afb-auth: Increase and improve use of afb-auth
[src/app-framework-binder.git] / src / afb-auth.c
1 /*
2  * Copyright (C) 2016-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 <stdlib.h>
22
23 #include <json-c/json.h>
24 #include <afb/afb-auth.h>
25 #include <afb/afb-session-x2.h>
26 #if WITH_LEGACY_BINDING_V1
27 #include <afb/afb-session-x1.h>
28 #endif
29
30 #include "afb-auth.h"
31 #include "afb-context.h"
32 #include "afb-xreq.h"
33 #include "afb-cred.h"
34 #include "verbose.h"
35
36 int afb_auth_check(struct afb_xreq *xreq, const struct afb_auth *auth)
37 {
38         switch (auth->type) {
39         default:
40         case afb_auth_No:
41                 return 0;
42
43         case afb_auth_Token:
44                 return afb_context_check(&xreq->context);
45
46         case afb_auth_LOA:
47                 return afb_context_check_loa(&xreq->context, auth->loa);
48
49         case afb_auth_Permission:
50                 return afb_auth_has_permission(xreq, auth->text);
51
52         case afb_auth_Or:
53                 return afb_auth_check(xreq, auth->first) || afb_auth_check(xreq, auth->next);
54
55         case afb_auth_And:
56                 return afb_auth_check(xreq, auth->first) && afb_auth_check(xreq, auth->next);
57
58         case afb_auth_Not:
59                 return !afb_auth_check(xreq, auth->first);
60
61         case afb_auth_Yes:
62                 return 1;
63         }
64 }
65
66 int afb_auth_has_permission(struct afb_xreq *xreq, const char *permission)
67 {
68         return afb_cred_has_permission(xreq->cred, permission, &xreq->context);
69 }
70
71 #if WITH_LEGACY_BINDING_V1
72 int afb_auth_check_and_set_session_x1(struct afb_xreq *xreq, int sessionflags)
73 {
74         int loa;
75
76         if ((sessionflags & (AFB_SESSION_CLOSE_X1|AFB_SESSION_RENEW_X1|AFB_SESSION_CHECK_X1|AFB_SESSION_LOA_EQ_X1)) != 0) {
77                 if (!afb_context_check(&xreq->context)) {
78                         afb_context_close(&xreq->context);
79                         return afb_xreq_reply_invalid_token(xreq);
80                 }
81         }
82
83         if ((sessionflags & AFB_SESSION_LOA_GE_X1) != 0) {
84                 loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_X1) & AFB_SESSION_LOA_MASK_X1;
85                 if (!afb_context_check_loa(&xreq->context, loa))
86                         return afb_xreq_reply_insufficient_scope(xreq, "invalid LOA");
87         }
88
89         if ((sessionflags & AFB_SESSION_LOA_LE_X1) != 0) {
90                 loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_X1) & AFB_SESSION_LOA_MASK_X1;
91                 if (afb_context_check_loa(&xreq->context, loa + 1))
92                         return afb_xreq_reply_insufficient_scope(xreq, "invalid LOA");
93         }
94
95         if ((sessionflags & AFB_SESSION_CLOSE_X1) != 0) {
96                 afb_context_change_loa(&xreq->context, 0);
97                 afb_context_close(&xreq->context);
98         }
99
100         return 0;
101 }
102 #endif
103
104 int afb_auth_check_and_set_session_x2(struct afb_xreq *xreq, uint32_t sessionflags, const struct afb_auth *auth)
105 {
106         int loa;
107
108         if (sessionflags != 0) {
109                 if (!afb_context_check(&xreq->context)) {
110                         afb_context_close(&xreq->context);
111                         return afb_xreq_reply_invalid_token(xreq);
112                 }
113         }
114
115         loa = (int)(sessionflags & AFB_SESSION_LOA_MASK_X2);
116         if (loa && !afb_context_check_loa(&xreq->context, loa))
117                 return afb_xreq_reply_insufficient_scope(xreq, "invalid LOA");
118
119         if (auth && !afb_auth_check(xreq, auth))
120                 return afb_xreq_reply_insufficient_scope(xreq, NULL /* TODO */);
121
122         if ((sessionflags & AFB_SESSION_CLOSE_X2) != 0)
123                 afb_context_close(&xreq->context);
124
125         return 0;
126 }
127
128 /*********************************************************************************/
129
130 static struct json_object *addperm(struct json_object *o, struct json_object *x)
131 {
132         struct json_object *a;
133
134         if (!o)
135                 return x;
136
137         if (!json_object_object_get_ex(o, "allOf", &a)) {
138                 a = json_object_new_array();
139                 json_object_array_add(a, o);
140                 o = json_object_new_object();
141                 json_object_object_add(o, "allOf", a);
142         }
143         json_object_array_add(a, x);
144         return o;
145 }
146
147 static struct json_object *addperm_key_val(struct json_object *o, const char *key, struct json_object *val)
148 {
149         struct json_object *x = json_object_new_object();
150         json_object_object_add(x, key, val);
151         return addperm(o, x);
152 }
153
154 static struct json_object *addperm_key_valstr(struct json_object *o, const char *key, const char *val)
155 {
156         return addperm_key_val(o, key, json_object_new_string(val));
157 }
158
159 static struct json_object *addperm_key_valint(struct json_object *o, const char *key, int val)
160 {
161         return addperm_key_val(o, key, json_object_new_int(val));
162 }
163
164 static struct json_object *addauth_or_array(struct json_object *o, const struct afb_auth *auth);
165
166 static struct json_object *addauth(struct json_object *o, const struct afb_auth *auth)
167 {
168         switch(auth->type) {
169         case afb_auth_No: return addperm(o, json_object_new_boolean(0));
170         case afb_auth_Token: return addperm_key_valstr(o, "session", "check");
171         case afb_auth_LOA: return addperm_key_valint(o, "LOA", auth->loa);
172         case afb_auth_Permission: return addperm_key_valstr(o, "permission", auth->text);
173         case afb_auth_Or: return addperm_key_val(o, "anyOf", addauth_or_array(json_object_new_array(), auth));
174         case afb_auth_And: return addauth(addauth(o, auth->first), auth->next);
175         case afb_auth_Not: return addperm_key_val(o, "not", addauth(NULL, auth->first));
176         case afb_auth_Yes: return addperm(o, json_object_new_boolean(1));
177         }
178         return o;
179 }
180
181 static struct json_object *addauth_or_array(struct json_object *o, const struct afb_auth *auth)
182 {
183         if (auth->type != afb_auth_Or)
184                 json_object_array_add(o, addauth(NULL, auth));
185         else {
186                 addauth_or_array(o, auth->first);
187                 addauth_or_array(o, auth->next);
188         }
189
190         return o;
191 }
192
193 struct json_object *afb_auth_json_x2(const struct afb_auth *auth, uint32_t session)
194 {
195         struct json_object *result = NULL;
196
197         if (session & AFB_SESSION_CLOSE_X2)
198                 result = addperm_key_valstr(result, "session", "close");
199
200         if (session & AFB_SESSION_CHECK_X2)
201                 result = addperm_key_valstr(result, "session", "check");
202
203         if (session & AFB_SESSION_REFRESH_X2)
204                 result = addperm_key_valstr(result, "token", "refresh");
205
206         if (session & AFB_SESSION_LOA_MASK_X2)
207                 result = addperm_key_valint(result, "LOA", session & AFB_SESSION_LOA_MASK_X2);
208
209         if (auth)
210                 result = addauth(result, auth);
211
212         return result;
213 }
214
215  
216 #if WITH_LEGACY_BINDING_V1
217 struct json_object *afb_auth_json_x1(int session)
218 {
219         struct json_object *result = NULL;
220
221         if (session & AFB_SESSION_CLOSE_X1)
222                 result = addperm_key_valstr(result, "session", "close");
223         if (session & AFB_SESSION_CHECK_X1)
224                 result = addperm_key_valstr(result, "session", "check");
225         if (session & AFB_SESSION_RENEW_X1)
226                 result = addperm_key_valstr(result, "token", "refresh");
227         if (session & AFB_SESSION_LOA_MASK_X1)
228                 result = addperm_key_valint(result, "LOA", (session >> AFB_SESSION_LOA_SHIFT_X1) & AFB_SESSION_LOA_MASK_X1);
229
230         return result;
231 }
232 #endif