summaryrefslogtreecommitdiffstats
path: root/agl-identity-service/src/oidc-agent.c
diff options
context:
space:
mode:
Diffstat (limited to 'agl-identity-service/src/oidc-agent.c')
-rw-r--r--agl-identity-service/src/oidc-agent.c812
1 files changed, 0 insertions, 812 deletions
diff --git a/agl-identity-service/src/oidc-agent.c b/agl-identity-service/src/oidc-agent.c
deleted file mode 100644
index 1f09e7a..0000000
--- a/agl-identity-service/src/oidc-agent.c
+++ /dev/null
@@ -1,812 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#define _GNU_SOURCE
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <pthread.h>
-
-#include <json-c/json.h>
-
-#include "oidc-agent.h"
-#include "escape.h"
-#include "curl-wrap.h"
-
-/***************** utilities *************************/
-
-static const char string_empty[] = "";
-static const char string_authorization_endpoint[] = "authorization_endpoint";
-static const char string_token_endpoint[] = "token_endpoint";
-#if 0
-static const char string_issuer[] = "issuer";
-static const char string_userinfo_endpoint[] = "userinfo_endpoint";
-static const char string_revocation_endpoint[] = "revocation_endpoint";
-static const char string_jwks_uri[] = "jwks_uri";
-#endif
-
-#define MAX_IDP_COUNT 20
-#define MAX_APPLI_COUNT 100
-
-static struct json_object *idps;
-static struct json_object *applis;
-
-static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
-
-/***************** utilities *************************/
-
-/*
- * Get the object of 'name' in the 'container' and return it.
- * Creates the result if needed and add it to the container.
- * When 'maxcount' isn't zero the final count will not exceed 'maxcount'.
- */
-static struct json_object *j_container_item(struct json_object *container, const char *name, int maxcount)
-{
- struct json_object *result;
-
- /* ensure object of 'name' exists */
- if (!json_object_object_get_ex(container, name, &result)) {
- if (maxcount && json_object_object_length(container) >= maxcount)
- return NULL;
- result = json_object_new_object();
- if (!result)
- return NULL;
- json_object_object_add (container, name, result);
- }
- return result;
-}
-
-/*
- * Like 'j_container_item' but also creates the 'container' if needed.
- */
-static struct json_object *j_container_item_make(struct json_object **container, const char *name, int maxcount)
-{
- struct json_object *cont;
-
- /* ensure container exists */
- cont = *container;
- if (!cont) {
- cont = json_object_new_object();
- if (!cont)
- return NULL;
- *container = cont;
- }
- return j_container_item(cont, name, maxcount);
-}
-
-/*
- * Adds in 'dest' the fields of 'src'
- * Also when the value of a field of 'src' is null, delete the field of 'dst'
- */
-static void j_merge(struct json_object *dest, struct json_object *src)
-{
- struct json_object_iter i;
- json_object_object_foreachC(src, i) {
- if (json_object_is_type(i.val, json_type_null))
- json_object_object_del(dest, i.key);
- else
- json_object_object_add(dest, i.key, json_object_get(i.val));
- }
-}
-
-/***************** IDP **************************/
-
-/*
- * Set the values of 'desc' for the idp of 'name'.
- * Return 0 on error or 1 on success.
- */
-int oidc_idp_set(const char *name, struct json_object *desc)
-{
- struct json_object *idp;
- int result = 0;
-
- pthread_rwlock_wrlock(&rwlock);
- idp = j_container_item_make(&idps, name, MAX_IDP_COUNT);
- if (idp) {
- j_merge(idp, desc);
- result = 1;
- }
- pthread_rwlock_unlock(&rwlock);
- return result;
-}
-
-/*
- * Return 1 if idp of 'name' exists or 0 otherwise.
- */
-int oidc_idp_exists(const char *name)
-{
- int result;
-
- pthread_rwlock_rdlock(&rwlock);
- result = json_object_object_get_ex(idps, name, NULL);
- pthread_rwlock_unlock(&rwlock);
-
- return result;
-}
-
-/*
- * Deletes the idp of 'name'.
- */
-void oidc_idp_delete(const char *name)
-{
- pthread_rwlock_wrlock(&rwlock);
- json_object_object_del(idps, name);
- pthread_rwlock_unlock(&rwlock);
-}
-
-/***************** APPLI **************************/
-
-/*
- * Returns the name of the idp of the 'appli'.
- * Returns NULL when appli isn't set or default idp isn't set.
- */
-static const char *get_default_idp(const char *appli)
-{
- struct json_object *a, *i;
-
- if (!json_object_object_get_ex(applis, appli, &a))
- return NULL;
- if (!json_object_object_get_ex(a, string_empty, &i))
- return NULL;
- return json_object_get_string(i);
-}
-
-/*
- * Returns the application data related to the 'appli' for the 'idp'.
- * If 'ja' isn't null, returns in it the object for the application 'appli'.
- * Returns NULL in case of error.
- */
-static struct json_object *get_appli_idp(const char *appli, const char *idp, struct json_object **ja)
-{
- struct json_object *a, *i;
-
- if (!json_object_object_get_ex(applis, appli, &a) || !json_object_object_get_ex(a, idp, &i))
- return NULL;
- if (ja)
- *ja = a;
- return i;
-}
-
-/*
- * Set the description 'desc' for the application of 'name' and
- * the 'idp'. When 'make_default' is set it, make it the default idp
- * for the application.
- * Return 0 on error or 1 on success.
- */
-int oidc_appli_set(const char *name, const char *idp, struct json_object *desc, int make_default)
-{
- struct json_object *a, *ai;
- int result = 0;
-
- pthread_rwlock_wrlock(&rwlock);
- a = j_container_item_make(&applis, name, MAX_APPLI_COUNT);
- if (a) {
- ai = j_container_item(a, idp, 0);
- if (ai) {
- j_merge(ai, desc);
- if (make_default || !json_object_object_get_ex(a, string_empty, NULL))
- json_object_object_add(a, string_empty, json_object_new_string(idp));
- result = 1;
- }
- }
- pthread_rwlock_unlock(&rwlock);
- return result;
-}
-
-/*
- * Is the appli of 'name' defined?
- * Return 1 if answer is yes or 0 for no.
- */
-int oidc_appli_exists(const char *name)
-{
- int result;
-
- pthread_rwlock_rdlock(&rwlock);
- result = json_object_object_get_ex(applis, name, NULL);
- pthread_rwlock_unlock(&rwlock);
-
- return result;
-}
-
-/*
- * Does the appli of 'name' has the 'idp' defined?
- * Return 1 if answer is yes or 0 for no.
- */
-int oidc_appli_has_idp(const char *name, const char *idp)
-{
- int result;
-
- pthread_rwlock_rdlock(&rwlock);
- result = !!get_appli_idp(name, idp, NULL);
- pthread_rwlock_unlock(&rwlock);
-
- return result;
-}
-
-/*
- * Set 'idp' as default for the application of 'name'.
- * Returns 0 on error (appli or idp for appli not existing)
- * or 1 in case of success.
- */
-int oidc_appli_set_default_idp(const char *name, const char *idp)
-{
- struct json_object *a, *i;
-
- pthread_rwlock_wrlock(&rwlock);
- i = get_appli_idp(name, idp, &a);
- if (i)
- json_object_object_add(a, string_empty, json_object_new_string(idp));
- pthread_rwlock_unlock(&rwlock);
-
- return !!i;
-}
-
-/*
- * Deletes the application of 'name'
- */
-void oidc_appli_delete(const char *name)
-{
- pthread_rwlock_wrlock(&rwlock);
- json_object_object_del(applis, name);
- pthread_rwlock_unlock(&rwlock);
-}
-
-/***************** AUTHORISATION **************************/
-
-/* parameters */
-enum param
-{
- Param_Access_Token,
- Param_Acr_Values,
- Param_Authorization,
- Param_Client_Id,
- Param_Client_Secret,
- Param_Code,
- Param_Display,
- Param_Error,
- Param_Error_Description,
- Param_Error_Uri,
- Param_Expires_In,
- Param_Grant_Type,
- Param_Id_Token,
- Param_Id_Token_Hint,
- Param_Login_Hint,
- Param_Max_Age,
- Param_Nonce,
- Param_Password,
- Param_Prompt,
- Param_Redirect_Uri,
- Param_Refresh_Token,
- Param_Response_Type,
- Param_Scope,
- Param_State,
- Param_Token_Type,
- Param_Ui_Locales,
- Param_Username,
- PARAM_COUNT
-};
-
-#if PARAM_COUNT > 30
-# error "Too much parameters"
-#endif
-#define PARAM(p) ((uint32_t)((uint32_t)1 << (Param_##p)))
-
-/* args of authorization requests */
-struct args
-{
- struct json_object *appli;
- struct json_object *idp;
- struct json_object *args;
- struct oidc_grant_cb cb;
- int locked;
- int refresh;
- uint32_t mandatory;
- uint32_t all;
- struct json_object *header;
- struct json_object *query;
-};
-
-/* Release the lock if needed */
-static void args_unlock(struct args *args)
-{
- if (!args->locked) {
- pthread_rwlock_unlock(&rwlock);
- args->locked = 0;
- }
-}
-
-/* Release the memory needed by args */
-static void args_destroy(struct args *args)
-{
- json_object_put(args->appli);
- json_object_put(args->idp);
- json_object_put(args->header);
- json_object_put(args->query);
- free(args);
-}
-
-/* Send the success event with the gained tokens */
-static void args_send_success(struct args *args, struct json_object *result)
-{
- args_unlock(args);
- args->cb.success(args->cb.closure, result);
- args_destroy(args);
-}
-
-/* Sends the error event with the indice to the client of args */
-static void args_send_error(struct args *args, const char *message, const char *indice)
-{
- args_unlock(args);
- args->cb.error(args->cb.closure, message, indice);
- args_destroy(args);
-}
-
-/* Send the error and also return NULL */
-static inline struct args *args_send_error_null(struct args *args, const char *message, const char *indice)
-{
- args_send_error(args, message, indice);
- return NULL;
-}
-
-/* creates a struct args from the arguments, returns NULL on error */
-struct args *mkargs(const char *appli, const char *idp, struct json_object *args, const struct oidc_grant_cb *cb)
-{
- struct args *result;
- struct json_object *obj;
-
- /* allocates the args */
- result = calloc(1, sizeof *result);
- if (!result) {
- cb->error(cb->closure, "Out of memory", NULL);
- return NULL;
- }
-
- /* init of the structure */
- result->cb = *cb;
- result->args = args;
- result->header = json_object_new_object();
- result->query = json_object_new_object();
-
- /* lock in read */
- pthread_rwlock_rdlock(&rwlock);
- result->locked = 1;
-
- /* check previous allocations */
- if (!result->query || !result->header) {
- return args_send_error_null(result, "Out of memory", NULL);
- }
-
- /* check whether default idp */
- if (!idp) {
- idp = get_default_idp(appli);
- if (!idp)
- return args_send_error_null(result, "No default IDP", NULL);
- }
-
- /* get the IDP */
- if (!json_object_object_get_ex(idps, idp, &obj))
- return args_send_error_null(result, "Unknown IDP", idp);
- result->idp = json_object_get(obj);
-
- /* get the appli */
- obj = get_appli_idp(appli, idp, NULL);
- if (!obj)
- return args_send_error_null(result, "Unknown APPLI for IDP", appli);
- result->appli = json_object_get(obj);
-
- return result;
-}
-
-/* get a value for a struct args */
-static struct json_object *args_object(struct args *args, const char *name)
-{
- struct json_object *result;
-
- if (!json_object_object_get_ex(args->appli, name, &result)
- && !json_object_object_get_ex(args->idp, name, &result)
- && !json_object_object_get_ex(args->args, name, &result))
- result = NULL;
- return result;
-}
-
-/* get a string value for a struct args */
-static const char *args_string(struct args *args, const char *name)
-{
- struct json_object *object = args_object(args, name);
- return object ? json_object_get_string(object) : NULL;
-}
-
-/* add a data */
-static int args_add(struct args *args, uint32_t val, const char *name, int query)
-{
- struct json_object *obj, *dest;
-
- if (val & args->all) {
- obj = args_object(args, name);
- if (obj) {
- dest = query ? args->query : args->header;
- json_object_object_add(dest, name, json_object_get(obj));
- }
- else if (val & args->mandatory) {
- args_send_error(args, "Mandatory field missing", name);
- return 0;
- }
- }
-
- return 1;
-}
-
-/*
- * Makes the CURL object for the given 'url' for either GET or POST depending
- * on 'post' with the added 'header' fields and the given query parameters.
- * Returns NULL on error.
- * Ex:
- *
- * curl_json("http://iot.bzh/api", 0, {"X-Index": "no"}, {"fast":true,"item":"2345-hellfest"})
- *
- * produces the query:
- *
- * GET /api?fast=true&item=2345-hellfest HTTP/1.1
- * Host: iot.bzh
- * X-Index: no
- *
- * while the same but with post not null produces:
- *
- * POST /api HTTP/1.1
- * Host: iot.bzh
- * X-Index: no
- * Content-Type: application/x-www-form-urlencoded
- *
- * fast=true&item=2345-hellfest
- *
- */
-static CURL *curl_json(const char *url, int post, struct json_object *header, struct json_object *query)
-{
- const char **args, *str;
- struct json_object_iter i;
- int idx;
- CURL *result;
-
- /* create args array */
- idx = 1 + (json_object_object_length(query) << 1);
- args = malloc((unsigned)idx * sizeof *args);
- if (!args)
- return NULL;
-
- /* fill the args array */
- args[--idx] = NULL;
- json_object_object_foreachC(query, i) {
- str = json_object_get_string(i.val);
- args[--idx] = str;
- args[--idx] = i.key;
- }
-
- /* prepare the query */
- if (post)
- result = curl_wrap_prepare_post(url, NULL, args);
- else
- result = curl_wrap_prepare_get(url, NULL, args);
- free(args);
- if(!result)
- return NULL;
-
- /* add headers */
- if (header) {
- json_object_object_foreachC(header, i) {
- str = json_object_get_string(i.val);
- if (!curl_wrap_add_header_value(result, i.key, str)) {
- curl_easy_cleanup(result);
- return NULL;
- }
- }
- }
- return result;
-}
-
-/*
- * Extract from the answer of 'curl' whose 'content' has 'size' bytes the
- * embeded JSON object (if any).
- * Returns it or returns NULL if the answer can't be interpreted.
- */
-static struct json_object *decode_perform_result(CURL *curl, const char *content, size_t size)
-{
- int i;
- const char **args;
- struct json_object *result;
-
- /* is it an url encoded answer? */
- if (curl_wrap_content_type_is(curl, "application/x-www-form-urlencoded")) {
- /* yes, unescape as an array of strings */
- args = unescape_args(content);
- if (!args)
- result = NULL;
- else {
- /* wrap the key=value pairs in an object */
- result = json_object_new_object();
- if (result) {
- for (i = 0 ; args[i] ; i += 2)
- json_object_object_add(result, args[i],
- json_object_new_string(args[i+1]));
- }
- free(args);
- }
- } else if (curl_wrap_content_type_is(curl, "application/json")) {
- /* interpret the json */
- result = json_tokener_parse (content);
- } else {
- /* by default, still try to interpret the answer as if json */
- result = json_tokener_parse (content);
- }
- return result;
-}
-
-/*
- * Treats the result of the query 'curl' of 'content' of 'size' bytes for the 'args'
- */
-static void perform_result(struct args *args, CURL *curl, const char *content, size_t size)
-{
- struct json_object *obj, *at, *tt;
- char *txt;
-
- /* get answer */
- obj = decode_perform_result(curl, content, size);
- if (!obj)
- return args_send_error(args, "unable to extract answer", content);
-
- /* process the answer */
- if (json_object_object_get_ex(obj, "access_token", &at) && json_object_object_get_ex(obj, "token_type", &tt)) {
- if (!strcmp(json_object_get_string(tt), "bearer")) {
- if (asprintf(&txt, "Bearer %s", json_object_get_string(at)) > 0) {
- json_object_object_add(obj, "authorization", json_object_new_string(txt));
- free(txt);
- }
- }
- }
-
- /* merge the answer to the token args in case of refresh */
- if (args->refresh)
- j_merge(args->args, obj);
-
- /* send the answer */
- args_send_success(args, obj);
-}
-
-/*
- * Treats the redirect answer of the query 'curl' of 'content' of 'size' bytes for the 'args'
- */
-static void perform_redirect(struct args *args, CURL *curl, const char *content, size_t size)
-{
- /* TODO: handle redirection for the normal flow */
- return args_send_error(args, "unhandled redirection", content);
-}
-
-/*
- * Handle the result of the query 'curl' of 'status'. If a data is returned, it is available in
- * 'content' of 'size' bytes.
- * When 'status' is 0, an error occured. Otherwise, 'statu' isn't zero.
- */
-static void perform_callback(void *closure, int status, CURL *curl, const char *content, size_t size)
-{
- long code;
- struct args *args = closure;
-
- /* query error ? */
- if (!status
- || curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code) != CURLE_OK)
- return args_send_error(args, "query error", NULL); /* TODO: IMPROVE? */
-
- /* get the returned code */
- switch (code) {
- case 200:
- return perform_result(args, curl, content, size);
- case 302:
- return perform_redirect(args, curl, content, size);
- case 400:
- case 401:
- return args_send_error(args, content ? : "returned code error", content ? "returned code error" : content);
- default:
- return args_send_error(args, content ? : "unexpected code error", content ? "unexpected code error" : content);
- }
-}
-
-/*
- * Main function for performing OAuth2/OpenId Connect transactions.
- * The structure 'args' is filled with the needed values:
- * Application data as json object, IDP data as json object
- * Contextual arguments for the transaction.
- * 'endpoint' must be the name of an endpoint in the context of 'args'.
- * 'operation' is the value that will get either response_type or grant_type,
- * depending on the nature of the required parameters 'mandatory'.
- * 'mandatory' designates the mandatory parameters.
- * 'optional' designate the optional parameters.
- */
-static void perform(struct args *args, const char *endpoint, const char *operation, uint32_t mandatory, uint32_t optional)
-{
- int post;
- const char *url, *type;
- CURL *curl;
-
- /* set the flags */
- args->mandatory = mandatory;
- args->all = mandatory | optional;
-
- /* get the endpoint */
- url = args_string(args, endpoint);
- if (!url)
- return args_send_error(args, "No endpoint", endpoint);
-
- /* get the operation type */
- if ((mandatory & PARAM(Response_Type)) == PARAM(Response_Type)) {
- type = "response_type";
- post = 0; /* can be 1 sometimes so not risk here */
- } else if ((mandatory & PARAM(Grant_Type)) == PARAM(Grant_Type)) {
- type = "grant_type";
- post = 1; /* must be 1 */
- } else
- return args_send_error(args, "Unexpected operation Type", NULL);
-
- json_object_object_add(args->query, type, json_object_new_string(operation));
-
- /* get the arguments */
- if (1
- && args_add(args, PARAM(Access_Token), "access_token", 1)
- && args_add(args, PARAM(Acr_Values), "acr_values", 1)
- && args_add(args, PARAM(Authorization), "authorization", 0)
- && args_add(args, PARAM(Client_Id), "client_id", 1)
- && args_add(args, PARAM(Client_Secret), "client_secret", 1)
- && args_add(args, PARAM(Code), "code", 1)
- && args_add(args, PARAM(Display), "display", 1)
- && args_add(args, PARAM(Expires_In), "expires_in", 1)
- && args_add(args, PARAM(Id_Token_Hint), "id_token_hint", 1)
- && args_add(args, PARAM(Login_Hint), "login_hint", 1)
- && args_add(args, PARAM(Max_Age), "max_age", 1)
- && args_add(args, PARAM(Nonce), "nonce", 1)
- && args_add(args, PARAM(Password), "password", 1)
- && args_add(args, PARAM(Prompt), "prompt", 1)
- && args_add(args, PARAM(Redirect_Uri), "redirect_uri", 1)
- && args_add(args, PARAM(Refresh_Token), "refresh_token", 1)
- && args_add(args, PARAM(Scope), "scope", 1)
- && args_add(args, PARAM(State), "state", 1)
- && args_add(args, PARAM(Token_Type), "token_type", 1)
- && args_add(args, PARAM(Ui_Locales), "ui_locales", 1)
- && args_add(args, PARAM(Username), "username", 1)
- ) {
- /* creates the curl query */
- curl = curl_json(url, post, args->header, args->query);
- if (!curl)
- return args_send_error(args, "out of memory", NULL);
-
- /* release data */
- args_unlock(args);
-
- /* perform the request to the server */
- curl_wrap_do(curl, perform_callback, args);
- }
-}
-
-/* perform a grant of flow Flow_Resource_Owner_Password_Credentials_Grant */
-static void grant_owner_password(struct args *args)
-{
- perform(args, string_token_endpoint, "password",
- PARAM(Grant_Type) | PARAM(Username) | PARAM(Password),
- PARAM(Scope) | PARAM(Authorization)
- );
-}
-
-/* perform a grant of flow Flow_Client_Credentials_Grant */
-static void grant_client_credentials(struct args *args)
-{
- perform(args, string_token_endpoint, "client_credentials",
- PARAM(Grant_Type),
- PARAM(Scope) | PARAM(Authorization)
- );
-}
-
-/* switches the requests depending on 'flow' */
-static void grant(struct args *args, enum oidc_grant_flow flow)
-{
- /* ensure args is valid */
- if (!args)
- return;
-
- /* process for flow */
- switch(flow) {
-
- case Flow_Resource_Owner_Password_Credentials_Grant:
- grant_owner_password(args);
- break;
-
- case Flow_Client_Credentials_Grant:
- grant_client_credentials(args);
- break;
-
- case Flow_Authorization_Code_Grant:
- case Flow_Implicit_Grant:
- case Flow_Extension_Grant:
- args_send_error(args, "Unsupported flow", NULL);
- break;
-
- case Flow_Invalid:
- default:
- args_send_error(args, "Invalid flow", NULL);
- break;
- }
-}
-
-/*
- * Initiates a grant with the given 'flow'.
- * 'appli' and 'idp' designates the appli and the idp that have been recorded.
- * when idp == NULL or idp == "", the default idp of 'appli' is used.
- * 'args' contains parameters expected in plus for the grant transaction.
- * 'cb' describes the callback actions that are called before
- * the function returns.
- */
-void oidc_grant(const char *appli, const char *idp, struct json_object *args, const struct oidc_grant_cb *cb, enum oidc_grant_flow flow)
-{
- grant(mkargs(appli, idp, args, cb), flow);
-}
-
-/*
- * Like oidc_grant for flow Flow_Resource_Owner_Password_Credentials_Grant
- */
-void oidc_grant_owner_password(const char *appli, const char *idp, struct json_object *args, const struct oidc_grant_cb *cb)
-{
- grant(mkargs(appli, idp, args, cb), Flow_Resource_Owner_Password_Credentials_Grant);
-}
-
-/*
- * Like oidc_grant for flow Flow_Client_Credentials_Grant
- */
-void oidc_grant_client_credentials(const char *appli, const char *idp, struct json_object *args, const struct oidc_grant_cb *cb)
-{
- grant(mkargs(appli, idp, args, cb), Flow_Client_Credentials_Grant);
-}
-
-/*
- * Refreshes the 'token' for the 'appli' and the 'idp'.
- * 'cb' describes the callback actions that are called before
- * the function returns.
- */
-void oidc_token_refresh(const char *appli, const char *idp, struct json_object *token, const struct oidc_grant_cb *cb)
-{
- struct args *args;
-
- args = mkargs(appli, idp, token, cb);
- if (!args)
- return;
- args->refresh = 1;
- perform(args, string_token_endpoint, "refresh_token",
- PARAM(Grant_Type) | PARAM(Refresh_Token),
- PARAM(Scope) | PARAM(Authorization)
- );
-}
-
-/*
- * Adds the header "authorisation" with the bearer access_token of 'token'.
- * Return 1 on case of success or 0 otherwise.
- */
-int oidc_add_bearer(CURL *curl, struct json_object *token)
-{
- struct json_object *bearer;
-
- return json_object_object_get_ex(token, "authorization", &bearer)
- && curl_wrap_add_header_value(curl, "authorization", json_object_get_string(bearer));
-}
-
-