diff options
-rw-r--r-- | include/afb/afb-auth.h | 21 | ||||
-rw-r--r-- | include/afb/afb-binding-v2.h | 2 | ||||
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/afb-auth.c | 89 | ||||
-rw-r--r-- | src/afb-auth.h | 23 | ||||
-rw-r--r-- | src/afb-xreq.c | 19 |
6 files changed, 140 insertions, 15 deletions
diff --git a/include/afb/afb-auth.h b/include/afb/afb-auth.h index fe29adec..ee089e7f 100644 --- a/include/afb/afb-auth.h +++ b/include/afb/afb-auth.h @@ -22,19 +22,24 @@ */ enum afb_auth_type { - afb_auth_No = 0, - afb_auth_Permission, - afb_auth_Or, - afb_auth_And, - afb_auth_Yes + afb_auth_No = 0, /** never authorized, no data */ + afb_auth_Token, /** authorized if token valid, no data */ + afb_auth_LOA, /** authorized if LOA greater than data 'loa' */ + afb_auth_Permission, /** authorized if permission 'text' is granted */ + afb_auth_Or, /** authorized if 'first' or 'next' is authorized */ + afb_auth_And, /** authorized if 'first' and 'next' are authorized */ + afb_auth_Not, /** authorized if 'first' is not authorized */ + afb_auth_Yes /** always authorized, no data */ }; -struct afb_auth_desc +struct afb_auth { - enum afb_auth_type type; + const enum afb_auth_type type; union { const char *text; - struct afb_auth_desc *child[2]; + const unsigned loa; + const struct afb_auth *first; }; + const struct afb_auth *next; }; diff --git a/include/afb/afb-binding-v2.h b/include/afb/afb-binding-v2.h index 80e2385d..19bff05a 100644 --- a/include/afb/afb-binding-v2.h +++ b/include/afb/afb-binding-v2.h @@ -43,7 +43,7 @@ struct afb_verb_v2 { const char *verb; /* name of the verb */ void (*callback)(struct afb_req req); /* callback function implementing the verb */ - struct afb_auth *auth; /* required authorisation */ + const struct afb_auth *auth; /* required authorisation */ uint32_t session; /* authorisation and session requirements of the verb */ }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 877f7aaf..2f97fd1b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,6 +64,7 @@ ADD_LIBRARY(afb-lib STATIC afb-api-so-v2.c afb-api-ws.c afb-apiset.c + afb-auth.c afb-common.c afb-config.c afb-context.c diff --git a/src/afb-auth.c b/src/afb-auth.c new file mode 100644 index 00000000..fc62bd59 --- /dev/null +++ b/src/afb-auth.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2016, 2017 "IoT.bzh" + * Author "Fulup Ar Foll" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO + +#include <stdlib.h> + +#include <afb/afb-auth.h> + +#include "afb-auth.h" +#include "afb-context.h" +#include "afb-xreq.h" +#include "verbose.h" + +static int check_permission(const char *permission, struct afb_xreq *xreq); + +int afb_auth_check(const struct afb_auth *auth, struct afb_xreq *xreq) +{ + switch (auth->type) { + default: + case afb_auth_No: + return 0; + + case afb_auth_Token: + return afb_context_check(&xreq->context); + + case afb_auth_LOA: + return afb_context_check_loa(&xreq->context, auth->loa); + + case afb_auth_Permission: + return xreq->cred && auth->text && check_permission(auth->text, xreq); + + case afb_auth_Or: + return afb_auth_check(auth->first, xreq) || afb_auth_check(auth->next, xreq); + + case afb_auth_And: + return afb_auth_check(auth->first, xreq) && afb_auth_check(auth->next, xreq); + + case afb_auth_Not: + return !afb_auth_check(auth->first, xreq); + + case afb_auth_Yes: + return 1; + } +} + +#ifdef BACKEND_PERMISSION_IS_CYNARA +#include <cynara-client.h> +static int check_permission(const char *permission, struct afb_xreq *xreq) +{ + static cynara *cynara; + char uid[64]; + int rc; + + if (!cynara) { + rc = cynara_initialize(&cynara, NULL); + if (rc != CYNARA_API_SUCCESS) { + cynara = NULL; + ERROR("cynara initialisation failed with code %d", rc); + return 0; + } + } + rc = cynara_check(cynara, cred->label, afb_context_uuid(&xreq->context), xreq->cred->user, permission); + return rc == CYNARA_API_ACCESS_ALLOWED; +} +#else +static int check_permission(const char *permission, struct afb_xreq *xreq) +{ + WARNING("Granting permission %s by default", permission); + return 1; +} +#endif + diff --git a/src/afb-auth.h b/src/afb-auth.h new file mode 100644 index 00000000..75e5d56e --- /dev/null +++ b/src/afb-auth.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016, 2017 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +struct afb_auth; +struct afb_xreq; + +extern int afb_auth_check(const struct afb_auth *auth, struct afb_xreq *xreq); diff --git a/src/afb-xreq.c b/src/afb-xreq.c index 0aef608a..b964b104 100644 --- a/src/afb-xreq.c +++ b/src/afb-xreq.c @@ -33,6 +33,7 @@ #include "afb-hook.h" #include "afb-api.h" #include "afb-apiset.h" +#include "afb-auth.h" #include "jobs.h" #include "verbose.h" @@ -439,14 +440,14 @@ void afb_xreq_subcall(struct afb_xreq *xreq, const char *api, const char *verb, afb_req_subcall(to_req(xreq), api, verb, args, callback, cb_closure); } -static int xreq_session_check_apply(struct afb_xreq *xreq, int sessionflags) +static int xreq_session_check_apply(struct afb_xreq *xreq, int sessionflags, const struct afb_auth *auth) { int loa; if ((sessionflags & (AFB_SESSION_CLOSE|AFB_SESSION_RENEW|AFB_SESSION_CHECK|AFB_SESSION_LOA_EQ)) != 0) { if (!afb_context_check(&xreq->context)) { afb_context_close(&xreq->context); - afb_xreq_fail_f(xreq, "failed", "invalid token's identity"); + afb_xreq_fail_f(xreq, "denied", "invalid token's identity"); errno = EINVAL; return -1; } @@ -455,7 +456,7 @@ static int xreq_session_check_apply(struct afb_xreq *xreq, int sessionflags) if ((sessionflags & AFB_SESSION_LOA_GE) != 0) { loa = (sessionflags >> AFB_SESSION_LOA_SHIFT) & AFB_SESSION_LOA_MASK; if (!afb_context_check_loa(&xreq->context, loa)) { - afb_xreq_fail_f(xreq, "failed", "invalid LOA"); + afb_xreq_fail_f(xreq, "denied", "invalid LOA"); errno = EPERM; return -1; } @@ -464,12 +465,18 @@ static int xreq_session_check_apply(struct afb_xreq *xreq, int sessionflags) if ((sessionflags & AFB_SESSION_LOA_LE) != 0) { loa = (sessionflags >> AFB_SESSION_LOA_SHIFT) & AFB_SESSION_LOA_MASK; if (afb_context_check_loa(&xreq->context, loa + 1)) { - afb_xreq_fail_f(xreq, "failed", "invalid LOA"); + afb_xreq_fail_f(xreq, "denied", "invalid LOA"); errno = EPERM; return -1; } } + if (auth && !afb_auth_check(auth, xreq)) { + afb_xreq_fail_f(xreq, "denied", "authorisation refused"); + errno = EPERM; + return -1; + } + if ((sessionflags & AFB_SESSION_RENEW) != 0) { afb_context_refresh(&xreq->context); } @@ -486,7 +493,7 @@ void afb_xreq_call_verb_v1(struct afb_xreq *xreq, const struct afb_verb_desc_v1 if (!verb) afb_xreq_fail_unknown_verb(xreq); else - if (!xreq_session_check_apply(xreq, verb->session)) + if (!xreq_session_check_apply(xreq, verb->session, NULL)) verb->callback(to_req(xreq)); } @@ -495,7 +502,7 @@ void afb_xreq_call_verb_v2(struct afb_xreq *xreq, const struct afb_verb_v2 *verb if (!verb) afb_xreq_fail_unknown_verb(xreq); else - if (!xreq_session_check_apply(xreq, verb->session)) + if (!xreq_session_check_apply(xreq, verb->session, verb->auth)) verb->callback(to_req(xreq)); } |