afb-context: Move credentials to context
[src/app-framework-binder.git] / src / afb-context.c
1 /*
2  * Copyright (C) 2015-2019 "IoT.bzh"
3  * Author "Fulup Ar Foll"
4  * Author José Bollo <jose.bollo@iot.bzh>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #define _GNU_SOURCE
20
21 #include <assert.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <errno.h>
25
26 #include "afb-session.h"
27 #include "afb-context.h"
28 #include "afb-token.h"
29 #include "afb-cred.h"
30 #include "afb-permission-text.h"
31 #include "verbose.h"
32
33 static void init_context(struct afb_context *context, struct afb_session *session, struct afb_token *token, struct afb_cred *cred)
34 {
35         assert(session != NULL);
36
37         /* reset the context for the session */
38         context->session = session;
39         context->flags = 0;
40         context->super = NULL;
41         context->api_key = NULL;
42         context->token = afb_token_addref(token);
43         context->credentials = afb_cred_addref(cred);
44
45         /* check the token */
46         if (token != NULL) {
47                 if (afb_token_check(token))
48                         context->validated = 1;
49                 else
50                         context->invalidated = 1;
51         }
52 }
53
54 void afb_context_init(struct afb_context *context, struct afb_session *session, struct afb_token *token, struct afb_cred *cred)
55 {
56         init_context(context, afb_session_addref(session), token, cred);
57 }
58
59 void afb_context_init_validated(struct afb_context *context, struct afb_session *session, struct afb_token *token, struct afb_cred *cred)
60 {
61         afb_context_init(context, session, token, cred);
62         context->validated = 1;
63 }
64
65 void afb_context_subinit(struct afb_context *context, struct afb_context *super)
66 {
67         context->session = afb_session_addref(super->session);
68         context->flags = 0;
69         context->super = super;
70         context->api_key = NULL;
71         context->token = afb_token_addref(super->token);
72         context->credentials = afb_cred_addref(super->credentials);
73 }
74
75 int afb_context_connect(struct afb_context *context, const char *uuid, struct afb_token *token, struct afb_cred *cred)
76 {
77         int created;
78         struct afb_session *session;
79
80         session = afb_session_get (uuid, AFB_SESSION_TIMEOUT_DEFAULT, &created);
81         if (session == NULL)
82                 return -1;
83         init_context(context, session, token, cred);
84         if (created) {
85                 context->created = 1;
86         }
87         return 0;
88 }
89
90 int afb_context_connect_validated(struct afb_context *context, const char *uuid, struct afb_token *token, struct afb_cred *cred)
91 {
92         int rc = afb_context_connect(context, uuid, token, cred);
93         if (!rc)
94                 context->validated = 1;
95         return rc;
96 }
97
98 void afb_context_disconnect(struct afb_context *context)
99 {
100         if (context->session && !context->super && context->closing && !context->closed) {
101                 afb_context_change_loa(context, 0);
102                 afb_context_set(context, NULL, NULL);
103                 context->closed = 1;
104         }
105         afb_session_unref(context->session);
106         context->session = NULL;
107         afb_cred_unref(context->credentials);
108         context->credentials = NULL;
109         afb_token_unref(context->token);
110         context->token = NULL;
111 }
112
113 void afb_context_change_cred(struct afb_context *context, struct afb_cred *cred)
114 {
115         struct afb_cred *ocred = context->credentials;
116         if (ocred != cred) {
117                 context->credentials = afb_cred_addref(cred);
118                 afb_cred_unref(ocred);
119         }
120 }
121
122 void afb_context_change_token(struct afb_context *context, struct afb_token *token)
123 {
124         struct afb_token *otoken = context->token;
125         if (otoken != token) {
126                 context->validated = 0;
127                 context->invalidated = 0;
128                 context->token = afb_token_addref(token);
129                 afb_token_unref(otoken);
130         }
131 }
132
133 const char *afb_context_on_behalf_export(struct afb_context *context)
134 {
135         return context->credentials ? afb_cred_export(context->credentials) : NULL;
136 }
137
138 int afb_context_on_behalf_import(struct afb_context *context, const char *exported)
139 {
140         int rc;
141         struct afb_cred *imported, *ocred;
142
143         if (!exported || !*exported)
144                 rc = 0;
145         else {
146                 if (afb_context_has_permission(context, afb_permission_on_behalf_credential)) {
147                         imported = afb_cred_import(exported);
148                         if (!imported) {
149                                 ERROR("Can't import on behalf credentials: %m");
150                                 rc = -1;
151                         } else {
152                                 ocred = context->credentials;
153                                 context->credentials = imported;
154                                 afb_cred_unref(ocred);
155                                 rc = 0;
156                         }
157                 } else {
158                         ERROR("On behalf credentials refused");
159                         rc = -1;
160                 }
161         }
162         return rc;
163 }
164
165 void afb_context_on_behalf_other_context(struct afb_context *context, struct afb_context *other)
166 {
167         afb_context_change_cred(context, other->credentials);
168         afb_context_change_token(context, other->token);
169 }
170
171 int afb_context_has_permission(struct afb_context *context, const char *permission)
172 {
173         return afb_cred_has_permission(context->credentials, permission, context);
174 }
175
176 const char *afb_context_uuid(struct afb_context *context)
177 {
178         return context->session ? afb_session_uuid(context->session) : NULL;
179 }
180
181 void *afb_context_make(struct afb_context *context, int replace, void *(*make_value)(void *closure), void (*free_value)(void *item), void *closure)
182 {
183         assert(context->session != NULL);
184         return afb_session_cookie(context->session, context->api_key, make_value, free_value, closure, replace);
185 }
186
187 void *afb_context_get(struct afb_context *context)
188 {
189         assert(context->session != NULL);
190         return afb_session_get_cookie(context->session, context->api_key);
191 }
192
193 int afb_context_set(struct afb_context *context, void *value, void (*free_value)(void*))
194 {
195         assert(context->session != NULL);
196         return afb_session_set_cookie(context->session, context->api_key, value, free_value);
197 }
198
199 void afb_context_close(struct afb_context *context)
200 {
201         context->closing = 1;
202 }
203
204 int afb_context_check(struct afb_context *context)
205 {
206         if (context->super)
207                 return afb_context_check(context);
208         return context->validated;
209 }
210
211 int afb_context_check_loa(struct afb_context *context, unsigned loa)
212 {
213         return afb_context_get_loa(context) >= loa;
214 }
215
216 static inline const void *loa_key(struct afb_context *context)
217 {
218         return (const void*)(1+(intptr_t)(context->api_key));
219 }
220
221 static inline void *loa2ptr(unsigned loa)
222 {
223         return (void*)(intptr_t)loa;
224 }
225
226 static inline unsigned ptr2loa(void *ptr)
227 {
228         return (unsigned)(intptr_t)ptr;
229 }
230
231 int afb_context_change_loa(struct afb_context *context, unsigned loa)
232 {
233         if (!context->validated || loa > 7) {
234                 errno = EINVAL;
235                 return -1;
236         }
237
238         return afb_session_set_cookie(context->session, loa_key(context), loa2ptr(loa), NULL);
239 }
240
241 unsigned afb_context_get_loa(struct afb_context *context)
242 {
243         assert(context->session != NULL);
244         return ptr2loa(afb_session_get_cookie(context->session, loa_key(context)));
245 }