Update date of copyright notices
[src/app-framework-binder.git] / src / afb-auth.c
1 /*
2  * Copyright (C) 2016, 2017, 2018 "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-v2.h>
26
27 #include "afb-auth.h"
28 #include "afb-context.h"
29 #include "afb-xreq.h"
30 #include "afb-cred.h"
31 #include "verbose.h"
32
33 int afb_auth_check(struct afb_xreq *xreq, const struct afb_auth *auth)
34 {
35         switch (auth->type) {
36         default:
37         case afb_auth_No:
38                 return 0;
39
40         case afb_auth_Token:
41                 return afb_context_check(&xreq->context);
42
43         case afb_auth_LOA:
44                 return afb_context_check_loa(&xreq->context, auth->loa);
45
46         case afb_auth_Permission:
47                 return afb_auth_has_permission(xreq, auth->text);
48
49         case afb_auth_Or:
50                 return afb_auth_check(xreq, auth->first) || afb_auth_check(xreq, auth->next);
51
52         case afb_auth_And:
53                 return afb_auth_check(xreq, auth->first) && afb_auth_check(xreq, auth->next);
54
55         case afb_auth_Not:
56                 return !afb_auth_check(xreq, auth->first);
57
58         case afb_auth_Yes:
59                 return 1;
60         }
61 }
62
63 /*********************************************************************************/
64 #ifdef BACKEND_PERMISSION_IS_CYNARA
65
66 #include <pthread.h>
67 #include <cynara-client.h>
68
69 static cynara *handle;
70 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
71
72 int afb_auth_has_permission(struct afb_xreq *xreq, const char *permission)
73 {
74         int rc;
75
76         if (!xreq->cred) {
77                 /* case of permission for self */
78                 return 1;
79         }
80         if (!permission) {
81                 ERROR("Got a null permission!");
82                 return 0;
83         }
84
85         /* cynara isn't reentrant */
86         pthread_mutex_lock(&mutex);
87
88         /* lazy initialisation */
89         if (!handle) {
90                 rc = cynara_initialize(&handle, NULL);
91                 if (rc != CYNARA_API_SUCCESS) {
92                         handle = NULL;
93                         ERROR("cynara initialisation failed with code %d", rc);
94                         return 0;
95                 }
96         }
97
98         /* query cynara permission */
99         rc = cynara_check(handle, xreq->cred->label, afb_context_uuid(&xreq->context), xreq->cred->user, permission);
100
101         pthread_mutex_unlock(&mutex);
102         return rc == CYNARA_API_ACCESS_ALLOWED;
103 }
104
105 /*********************************************************************************/
106 #else
107 int afb_auth_has_permission(struct afb_xreq *xreq, const char *permission)
108 {
109         WARNING("Granting permission %s by default of backend", permission ?: "(null)");
110         return !!permission;
111 }
112 #endif
113
114 /*********************************************************************************/
115
116 static struct json_object *addperm(struct json_object *o, struct json_object *x)
117 {
118         struct json_object *a;
119
120         if (!o)
121                 return x;
122
123         if (!json_object_object_get_ex(o, "allOf", &a)) {
124                 a = json_object_new_array();
125                 json_object_array_add(a, o);
126                 o = json_object_new_object();
127                 json_object_object_add(o, "allOf", a);
128         }
129         json_object_array_add(a, x);
130         return o;
131 }
132
133 static struct json_object *addperm_key_val(struct json_object *o, const char *key, struct json_object *val)
134 {
135         struct json_object *x = json_object_new_object();
136         json_object_object_add(x, key, val);
137         return addperm(o, x);
138 }
139
140 static struct json_object *addperm_key_valstr(struct json_object *o, const char *key, const char *val)
141 {
142         return addperm_key_val(o, key, json_object_new_string(val));
143 }
144
145 static struct json_object *addperm_key_valint(struct json_object *o, const char *key, int val)
146 {
147         return addperm_key_val(o, key, json_object_new_int(val));
148 }
149
150 static struct json_object *addauth_or_array(struct json_object *o, const struct afb_auth *auth);
151
152 static struct json_object *addauth(struct json_object *o, const struct afb_auth *auth)
153 {
154         switch(auth->type) {
155         case afb_auth_No: return addperm(o, json_object_new_boolean(0));
156         case afb_auth_Token: return addperm_key_valstr(o, "session", "check");
157         case afb_auth_LOA: return addperm_key_valint(o, "LOA", auth->loa);
158         case afb_auth_Permission: return addperm_key_valstr(o, "permission", auth->text);
159         case afb_auth_Or: return addperm_key_val(o, "anyOf", addauth_or_array(json_object_new_array(), auth));
160         case afb_auth_And: return addauth(addauth(o, auth->first), auth->next);
161         case afb_auth_Not: return addperm_key_val(o, "not", addauth(NULL, auth->first));
162         case afb_auth_Yes: return addperm(o, json_object_new_boolean(1));
163         }
164         return o;
165 }
166
167 static struct json_object *addauth_or_array(struct json_object *o, const struct afb_auth *auth)
168 {
169         if (auth->type != afb_auth_Or)
170                 json_object_array_add(o, addauth(NULL, auth));
171         else {
172                 addauth_or_array(o, auth->first);
173                 addauth_or_array(o, auth->next);
174         }
175
176         return o;
177 }
178
179 struct json_object *afb_auth_json_v2(const struct afb_auth *auth, int session)
180 {
181         struct json_object *result = NULL;
182
183         if (session & AFB_SESSION_CLOSE_V2)
184                 result = addperm_key_valstr(result, "session", "close");
185
186         if (session & AFB_SESSION_CHECK_V2)
187                 result = addperm_key_valstr(result, "session", "check");
188
189         if (session & AFB_SESSION_REFRESH_V2)
190                 result = addperm_key_valstr(result, "token", "refresh");
191
192         if (session & AFB_SESSION_LOA_MASK_V2)
193                 result = addperm_key_valint(result, "LOA", session & AFB_SESSION_LOA_MASK_V2);
194
195         if (auth)
196                 result = addauth(result, auth);
197
198         return result;
199 }
200