afb-context & afb-token: rework token validation
[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
46 void afb_context_subinit(struct afb_context *context, struct afb_context *super)
47 {
48         context->session = afb_session_addref(super->session);
49         context->flags = 0;
50         context->super = super;
51         context->api_key = NULL;
52         context->token = afb_token_addref(super->token);
53         context->credentials = afb_cred_addref(super->credentials);
54 }
55
56 void afb_context_init(struct afb_context *context, struct afb_session *session, struct afb_token *token, struct afb_cred *cred)
57 {
58         init_context(context, afb_session_addref(session), token, cred);
59 }
60
61 int afb_context_connect(struct afb_context *context, const char *uuid, struct afb_token *token, struct afb_cred *cred)
62 {
63         int created;
64         struct afb_session *session;
65
66         session = afb_session_get (uuid, AFB_SESSION_TIMEOUT_DEFAULT, &created);
67         if (session == NULL)
68                 return -1;
69         init_context(context, session, token, cred);
70         if (created) {
71                 context->created = 1;
72         }
73         return 0;
74 }
75
76 int afb_context_connect_validated(struct afb_context *context, const char *uuid, struct afb_token *token, struct afb_cred *cred)
77 {
78         int rc = afb_context_connect(context, uuid, token, cred);
79         if (!rc)
80                 context->validated = 1;
81         return rc;
82 }
83
84 void afb_context_init_validated(struct afb_context *context, struct afb_session *session, struct afb_token *token, struct afb_cred *cred)
85 {
86         afb_context_init(context, session, token, cred);
87         context->validated = 1;
88 }
89
90 void afb_context_disconnect(struct afb_context *context)
91 {
92         if (context->session && !context->super && context->closing && !context->closed) {
93                 afb_context_change_loa(context, 0);
94                 afb_context_set(context, NULL, NULL);
95                 context->closed = 1;
96         }
97         afb_session_unref(context->session);
98         context->session = NULL;
99         afb_cred_unref(context->credentials);
100         context->credentials = NULL;
101         afb_token_unref(context->token);
102         context->token = NULL;
103 }
104
105 void afb_context_change_cred(struct afb_context *context, struct afb_cred *cred)
106 {
107         struct afb_cred *ocred = context->credentials;
108         if (ocred != cred) {
109                 context->credentials = afb_cred_addref(cred);
110                 afb_cred_unref(ocred);
111         }
112 }
113
114 void afb_context_change_token(struct afb_context *context, struct afb_token *token)
115 {
116         struct afb_token *otoken = context->token;
117         if (otoken != token) {
118                 context->token = afb_token_addref(token);
119                 afb_token_unref(otoken);
120         }
121 }
122
123 const char *afb_context_on_behalf_export(struct afb_context *context)
124 {
125         return context->credentials ? afb_cred_export(context->credentials) : NULL;
126 }
127
128 int afb_context_on_behalf_import(struct afb_context *context, const char *exported)
129 {
130         int rc;
131         struct afb_cred *imported, *ocred;
132
133         if (!exported || !*exported)
134                 rc = 0;
135         else {
136                 if (afb_context_has_permission(context, afb_permission_on_behalf_credential)) {
137                         imported = afb_cred_import(exported);
138                         if (!imported) {
139                                 ERROR("Can't import on behalf credentials: %m");
140                                 rc = -1;
141                         } else {
142                                 ocred = context->credentials;
143                                 context->credentials = imported;
144                                 afb_cred_unref(ocred);
145                                 rc = 0;
146                         }
147                 } else {
148                         ERROR("On behalf credentials refused");
149                         rc = -1;
150                 }
151         }
152         return rc;
153 }
154
155 void afb_context_on_behalf_other_context(struct afb_context *context, struct afb_context *other)
156 {
157         afb_context_change_cred(context, other->credentials);
158         afb_context_change_token(context, other->token);
159 }
160
161 int afb_context_has_permission(struct afb_context *context, const char *permission)
162 {
163         return afb_cred_has_permission(context->credentials, permission, context);
164 }
165
166 const char *afb_context_uuid(struct afb_context *context)
167 {
168         return context->session ? afb_session_uuid(context->session) : NULL;
169 }
170
171 void *afb_context_make(struct afb_context *context, int replace, void *(*make_value)(void *closure), void (*free_value)(void *item), void *closure)
172 {
173         assert(context->session != NULL);
174         return afb_session_cookie(context->session, context->api_key, make_value, free_value, closure, replace);
175 }
176
177 void *afb_context_get(struct afb_context *context)
178 {
179         assert(context->session != NULL);
180         return afb_session_get_cookie(context->session, context->api_key);
181 }
182
183 int afb_context_set(struct afb_context *context, void *value, void (*free_value)(void*))
184 {
185         assert(context->session != NULL);
186         return afb_session_set_cookie(context->session, context->api_key, value, free_value);
187 }
188
189 void afb_context_close(struct afb_context *context)
190 {
191         context->closing = 1;
192 }
193
194 int afb_context_check(struct afb_context *context)
195 {
196         int r;
197
198         if (context->validated)
199                 r = 1;
200         else if (context->invalidated)
201                 r = 0;
202         else {
203                 if (context->super)
204                         r = afb_context_check(context->super);
205                 else
206                         r = afb_context_has_permission(context, afb_permission_token_valid);
207                 if (r)
208                         context->validated = 1;
209                 else
210                         context->invalidated = 1;
211         }
212         return r;
213 }
214
215 static inline const void *loa_key(struct afb_context *context)
216 {
217         return (const void*)(1+(intptr_t)(context->api_key));
218 }
219
220 static inline void *loa2ptr(unsigned loa)
221 {
222         return (void*)(intptr_t)loa;
223 }
224
225 static inline unsigned ptr2loa(void *ptr)
226 {
227         return (unsigned)(intptr_t)ptr;
228 }
229
230 int afb_context_change_loa(struct afb_context *context, unsigned loa)
231 {
232         if (loa > 7) {
233                 errno = EINVAL;
234                 return -1;
235         }
236         if (!afb_context_check(context)) {
237                 errno = EPERM;
238                 return -1;
239         }
240
241         return afb_session_set_cookie(context->session, loa_key(context), loa2ptr(loa), NULL);
242 }
243
244 unsigned afb_context_get_loa(struct afb_context *context)
245 {
246         assert(context->session != NULL);
247         return ptr2loa(afb_session_get_cookie(context->session, loa_key(context)));
248 }
249
250 int afb_context_check_loa(struct afb_context *context, unsigned loa)
251 {
252         return afb_context_get_loa(context) >= loa;
253 }