X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Freclaim%2Fplugin_rest_openid_connect.c;h=09b3c8248a2de75894e3c494f51a292a09069f30;hb=0ecd5d693d2a7fa3e2897c77ed1f5f9566c9bebd;hp=1846df9010baa79743267d52ecf338f68931c882;hpb=6c4bd20776ce2dd060beee9abd7baaf7d38c4988;p=oweals%2Fgnunet.git diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c index 1846df901..09b3c8248 100644 --- a/src/reclaim/plugin_rest_openid_connect.c +++ b/src/reclaim/plugin_rest_openid_connect.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. + Copyright (C) 2012-2018 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published @@ -11,10 +11,12 @@ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . - */ + + SPDX-License-Identifier: AGPL3.0-or-later + */ /** * @author Martin Schanzenbach * @author Philippe Buschmann @@ -22,24 +24,21 @@ * @brief GNUnet Namestore REST plugin * */ - #include "platform.h" -#include "gnunet_rest_plugin.h" -#include "gnunet_identity_service.h" +#include +#include + #include "gnunet_gns_service.h" #include "gnunet_gnsrecord_lib.h" +#include "gnunet_identity_service.h" #include "gnunet_namestore_service.h" +#include "gnunet_reclaim_lib.h" +#include "gnunet_reclaim_service.h" #include "gnunet_rest_lib.h" -#include "gnunet_jsonapi_lib.h" -#include "gnunet_jsonapi_util.h" -#include "microhttpd.h" -#include -#include +#include "gnunet_rest_plugin.h" #include "gnunet_signatures.h" -#include "gnunet_reclaim_attribute_lib.h" -#include "gnunet_reclaim_service.h" +#include "microhttpd.h" #include "oidc_helper.h" - /** * REST root namespace */ @@ -65,22 +64,6 @@ */ #define GNUNET_REST_API_NS_LOGIN "/openid/login" -/** - * Attribute key - */ -#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE "attribute" - -/** - * Ticket key - */ -#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket" - - -/** - * Value key - */ -#define GNUNET_REST_JSONAPI_RECLAIM_ATTRIBUTE_VALUE "value" - /** * State while collecting all egos */ @@ -136,6 +119,26 @@ */ #define OIDC_NONCE_KEY "nonce" +/** + * OIDC claims key + */ +#define OIDC_CLAIMS_KEY "claims" + +/** + * OIDC PKCE code challenge + */ +#define OIDC_CODE_CHALLENGE_KEY "code_challenge" + +/** + * OIDC PKCE code verifier + */ +#define OIDC_CODE_VERIFIER_KEY "code_verifier" + +/** + * OIDC cookie expiration (in seconds) + */ +#define OIDC_COOKIE_EXPIRATION 3 + /** * OIDC cookie header key */ @@ -151,6 +154,11 @@ */ #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity=" +/** + * OIDC cookie header if user cancelled + */ +#define OIDC_COOKIE_HEADER_ACCESS_DENIED "Identity=Denied" + /** * OIDC expected response_type while authorizing */ @@ -162,38 +170,77 @@ #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid" /** - * OIDC ignored parameter array + * OIDC error key for invalid client */ -static char* OIDC_ignored_parameter_array [] = -{ - "display", - "prompt", - "ui_locales", - "response_mode", - "id_token_hint", - "login_hint", - "acr_values" -}; +#define OIDC_ERROR_KEY_INVALID_CLIENT "invalid_client" + +/** + * OIDC error key for invalid scopes + */ +#define OIDC_ERROR_KEY_INVALID_SCOPE "invalid_scope" + +/** + * OIDC error key for invalid requests + */ +#define OIDC_ERROR_KEY_INVALID_REQUEST "invalid_request" + +/** + * OIDC error key for invalid tokens + */ +#define OIDC_ERROR_KEY_INVALID_TOKEN "invalid_token" + +/** + * OIDC error key for invalid cookies + */ +#define OIDC_ERROR_KEY_INVALID_COOKIE "invalid_cookie" + +/** + * OIDC error key for generic server errors + */ +#define OIDC_ERROR_KEY_SERVER_ERROR "server_error" + +/** + * OIDC error key for unsupported grants + */ +#define OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE "unsupported_grant_type" /** - * OIDC authorized identities and times hashmap + * OIDC error key for unsupported response types */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time; +#define OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE "unsupported_response_type" /** - * OIDC authorized identities and times hashmap + * OIDC error key for unauthorized clients */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants; +#define OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT "unauthorized_client" /** - * OIDC ticket/code use only once + * OIDC error key for denied access */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once; +#define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied" + /** - * OIDC access_token to ticket and ego + * OIDC ignored parameter array */ -struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token; +static char *OIDC_ignored_parameter_array[] = { "display", + "prompt", + "ui_locales", + "response_mode", + "id_token_hint", + "login_hint", + "acr_values" }; + +/** + * OIDC Hash map that keeps track of issued cookies + */ +struct GNUNET_CONTAINER_MultiHashMap *OIDC_cookie_jar_map; + +/** + * Hash map that links the issued access token to the corresponding ticket and + * ego + */ +struct GNUNET_CONTAINER_MultiHashMap *OIDC_access_token_map; /** * The configuration handle @@ -203,7 +250,7 @@ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * HTTP methods allows for this plugin */ -static char* allow_methods; +static char *allow_methods; /** * @brief struct returned by the initialization function of the plugin @@ -248,6 +295,11 @@ struct OIDC_Variables */ char *nonce; + /** + * The OIDC claims + */ + char *claims; + /** * The OIDC response type */ @@ -258,11 +310,25 @@ struct OIDC_Variables */ char *login_identity; + /** + * User cancelled authorization/login + */ + int user_cancelled; + + /** + * The PKCE code_challenge + */ + char *code_challenge; + + /** + * The PKCE code_verifier + */ + char *code_verifier; + /** * The response JSON */ json_t *response; - }; /** @@ -362,7 +428,13 @@ struct RequestHandle /** * Attribute claim list */ - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list; + struct GNUNET_RECLAIM_AttributeList *attr_list; + + /** + * Attestation list + */ + struct GNUNET_RECLAIM_AttestationList *attests_list; + /** * IDENTITY Operation @@ -384,6 +456,12 @@ struct RequestHandle */ struct GNUNET_RECLAIM_AttributeIterator *attr_it; + /** + * Attestation iterator + */ + struct GNUNET_RECLAIM_AttestationIterator *attest_it; + + /** * Ticket iterator */ @@ -448,12 +526,6 @@ struct RequestHandle * Reponse code */ int response_code; - - /** - * Response object - */ - struct GNUNET_JSONAPI_Document *resp_object; - }; /** @@ -463,36 +535,29 @@ struct RequestHandle static void cleanup_handle (struct RequestHandle *handle) { - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry; - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp; struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Cleaning up\n"); - if (NULL != handle->resp_object) - GNUNET_JSONAPI_document_delete (handle->resp_object); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); if (NULL != handle->timeout_task) GNUNET_SCHEDULER_cancel (handle->timeout_task); if (NULL != handle->identity_handle) GNUNET_IDENTITY_disconnect (handle->identity_handle); if (NULL != handle->attr_it) GNUNET_RECLAIM_get_attributes_stop (handle->attr_it); + if (NULL != handle->attest_it) + GNUNET_RECLAIM_get_attestations_stop (handle->attest_it); if (NULL != handle->ticket_it) GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); + if (NULL != handle->idp_op) + GNUNET_RECLAIM_cancel (handle->idp_op); if (NULL != handle->idp) GNUNET_RECLAIM_disconnect (handle->idp); - if (NULL != handle->url) - GNUNET_free (handle->url); - if (NULL != handle->tld) - GNUNET_free (handle->tld); - if (NULL != handle->redirect_prefix) - GNUNET_free (handle->redirect_prefix); - if (NULL != handle->redirect_suffix) - GNUNET_free (handle->redirect_suffix); - if (NULL != handle->emsg) - GNUNET_free (handle->emsg); - if (NULL != handle->edesc) - GNUNET_free (handle->edesc); + GNUNET_free_non_null (handle->url); + GNUNET_free_non_null (handle->tld); + GNUNET_free_non_null (handle->redirect_prefix); + GNUNET_free_non_null (handle->redirect_suffix); + GNUNET_free_non_null (handle->emsg); + GNUNET_free_non_null (handle->edesc); if (NULL != handle->gns_op) GNUNET_GNS_lookup_cancel (handle->gns_op); if (NULL != handle->gns_handle) @@ -502,52 +567,34 @@ cleanup_handle (struct RequestHandle *handle) GNUNET_NAMESTORE_disconnect (handle->namestore_handle); if (NULL != handle->oidc) { - if (NULL != handle->oidc->client_id) - GNUNET_free(handle->oidc->client_id); - if (NULL != handle->oidc->login_identity) - GNUNET_free(handle->oidc->login_identity); - if (NULL != handle->oidc->nonce) - GNUNET_free(handle->oidc->nonce); - if (NULL != handle->oidc->redirect_uri) - GNUNET_free(handle->oidc->redirect_uri); - if (NULL != handle->oidc->response_type) - GNUNET_free(handle->oidc->response_type); - if (NULL != handle->oidc->scope) - GNUNET_free(handle->oidc->scope); - if (NULL != handle->oidc->state) - GNUNET_free(handle->oidc->state); - if (NULL != handle->oidc->response) - json_decref(handle->oidc->response); - GNUNET_free(handle->oidc); - } - if ( NULL != handle->attr_list ) - { - for (claim_entry = handle->attr_list->list_head; - NULL != claim_entry;) - { - claim_tmp = claim_entry; - claim_entry = claim_entry->next; - GNUNET_free(claim_tmp->claim); - GNUNET_free(claim_tmp); - } - GNUNET_free (handle->attr_list); - } - for (ego_entry = handle->ego_head; - NULL != ego_entry;) - { - ego_tmp = ego_entry; - ego_entry = ego_entry->next; - GNUNET_free (ego_tmp->identifier); - GNUNET_free (ego_tmp->keystring); - GNUNET_free (ego_tmp); - } - if (NULL != handle->attr_it) - { - GNUNET_free(handle->attr_it); + GNUNET_free_non_null (handle->oidc->client_id); + GNUNET_free_non_null (handle->oidc->login_identity); + GNUNET_free_non_null (handle->oidc->nonce); + GNUNET_free_non_null (handle->oidc->redirect_uri); + GNUNET_free_non_null (handle->oidc->response_type); + GNUNET_free_non_null (handle->oidc->scope); + GNUNET_free_non_null (handle->oidc->state); + json_decref (handle->oidc->response); + GNUNET_free (handle->oidc); + } + if (NULL!=handle->attr_list) + GNUNET_RECLAIM_attribute_list_destroy (handle->attr_list); + if (NULL!=handle->attests_list) + GNUNET_RECLAIM_attestation_list_destroy (handle->attests_list); + + while (NULL != (ego_entry = handle->ego_head)) + { + GNUNET_CONTAINER_DLL_remove (handle->ego_head, + handle->ego_tail, + ego_entry); + GNUNET_free_non_null (ego_entry->identifier); + GNUNET_free_non_null (ego_entry->keystring); + GNUNET_free (ego_entry); } GNUNET_free (handle); } + static void cleanup_handle_delayed (void *cls) { @@ -567,22 +614,21 @@ do_error (void *cls) struct MHD_Response *resp; char *json_error; - GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}", + GNUNET_asprintf (&json_error, + "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}", handle->emsg, (NULL != handle->edesc) ? handle->edesc : "", (NULL != handle->oidc->state) ? ", \"state\":\"" : "", (NULL != handle->oidc->state) ? handle->oidc->state : "", (NULL != handle->oidc->state) ? "\"" : ""); - if ( 0 == handle->response_code ) - { + if (0 == handle->response_code) handle->response_code = MHD_HTTP_BAD_REQUEST; - } resp = GNUNET_REST_create_response (json_error); if (MHD_HTTP_UNAUTHORIZED == handle->response_code) - { - MHD_add_response_header(resp, "WWW-Authenticate", "Basic"); - } - MHD_add_response_header (resp, "Content-Type", "application/json"); + MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Basic"); + MHD_add_response_header (resp, + MHD_HTTP_HEADER_CONTENT_TYPE, + "application/json"); handle->proc (handle->proc_cls, resp, handle->response_code); GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); GNUNET_free (json_error); @@ -602,11 +648,12 @@ do_userinfo_error (void *cls) struct MHD_Response *resp; char *error; - GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"", + GNUNET_asprintf (&error, + "error=\"%s\", error_description=\"%s\"", handle->emsg, (NULL != handle->edesc) ? handle->edesc : ""); resp = GNUNET_REST_create_response (""); - MHD_add_response_header(resp, "WWW-Authenticate", error); + MHD_add_response_header (resp, MHD_HTTP_HEADER_WWW_AUTHENTICATE, "Bearer"); handle->proc (handle->proc_cls, resp, handle->response_code); GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); GNUNET_free (error); @@ -623,10 +670,13 @@ do_redirect_error (void *cls) { struct RequestHandle *handle = cls; struct MHD_Response *resp; - char* redirect; + char *redirect; + GNUNET_asprintf (&redirect, "%s?error=%s&error_description=%s%s%s", - handle->oidc->redirect_uri, handle->emsg, handle->edesc, + handle->oidc->redirect_uri, + handle->emsg, + handle->edesc, (NULL != handle->oidc->state) ? "&state=" : "", (NULL != handle->oidc->state) ? handle->oidc->state : ""); resp = GNUNET_REST_create_response (""); @@ -636,6 +686,7 @@ do_redirect_error (void *cls) GNUNET_free (redirect); } + /** * Task run on timeout, sends error message. Cleans up everything. * @@ -650,6 +701,7 @@ do_timeout (void *cls) do_error (handle); } + /** * Return attributes for claim * @@ -658,35 +710,18 @@ do_timeout (void *cls) static void return_userinfo_response (void *cls) { - char* result_str; + char *result_str; struct RequestHandle *handle = cls; struct MHD_Response *resp; result_str = json_dumps (handle->oidc->response, 0); - + GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"ID-Token: %s\n",result_str); resp = GNUNET_REST_create_response (result_str); handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); GNUNET_free (result_str); cleanup_handle (handle); } -/** - * Returns base64 encoded string without padding - * - * @param string the string to encode - * @return base64 encoded string - */ -static char* -base_64_encode(const char *s) -{ - char *enc; - char *tmp; - - GNUNET_STRINGS_base64_encode(s, strlen(s), &enc); - tmp = strrchr (enc, '='); - *tmp = '\0'; - return enc; -} /** * Respond to OPTIONS request @@ -697,22 +732,21 @@ base_64_encode(const char *s) */ static void options_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, + const char *url, void *cls) { struct MHD_Response *resp; struct RequestHandle *handle = cls; - //For now, independent of path return all options + // For now, independent of path return all options resp = GNUNET_REST_create_response (NULL); - MHD_add_response_header (resp, - "Access-Control-Allow-Methods", - allow_methods); + MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods); handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); cleanup_handle (handle); return; } + /** * Interprets cookie header and pass its identity keystring to handle */ @@ -723,64 +757,106 @@ cookie_identity_interpretation (struct RequestHandle *handle) char *cookies; struct GNUNET_TIME_Absolute current_time, *relog_time; char delimiter[] = "; "; + char *tmp_cookies; + char *token; + char *value; - //gets identity of login try with cookie - GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY), + // gets identity of login try with cookie + GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, + strlen (OIDC_COOKIE_HEADER_KEY), &cache_key); - if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map, - &cache_key) ) + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle + ->header_param_map, + &cache_key)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No cookie found\n"); + return; + } + // splits cookies and find 'Identity' cookie + tmp_cookies = + GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map, + &cache_key); + cookies = GNUNET_strdup (tmp_cookies); + token = strtok (cookies, delimiter); + handle->oidc->user_cancelled = GNUNET_NO; + handle->oidc->login_identity = NULL; + if (NULL == token) { - //splits cookies and find 'Identity' cookie - cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key); - handle->oidc->login_identity = strtok(cookies, delimiter); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse cookie: %s\n", + cookies); + GNUNET_free (cookies); + return; + } - while ( NULL != handle->oidc->login_identity ) - { - if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) ) - { - break; - } - handle->oidc->login_identity = strtok (NULL, delimiter); - } - GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity), - &cache_key); - if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) ) - { - relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time, - &cache_key); - current_time = GNUNET_TIME_absolute_get (); - // 30 min after old login -> redirect to login - if ( current_time.abs_value_us <= relog_time->abs_value_us ) - { - handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY); - handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity); - } else { - handle->oidc->login_identity = NULL; - } - } - else + while (NULL != token) + { + if (0 == strcmp (token, OIDC_COOKIE_HEADER_ACCESS_DENIED)) { - handle->oidc->login_identity = NULL; + handle->oidc->user_cancelled = GNUNET_YES; + GNUNET_free (cookies); + return; } + if (NULL != strstr (token, OIDC_COOKIE_HEADER_INFORMATION_KEY)) + break; + token = strtok (NULL, delimiter); + } + if (NULL == token) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No cookie value to process: %s\n", + cookies); + GNUNET_free (cookies); + return; + } + GNUNET_CRYPTO_hash (token, strlen (token), &cache_key); + if (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key)) + { + GNUNET_log ( + GNUNET_ERROR_TYPE_WARNING, + "Found cookie `%s', but no corresponding expiration entry present...\n", + token); + GNUNET_free (cookies); + return; } + relog_time = + GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key); + current_time = GNUNET_TIME_absolute_get (); + // 30 min after old login -> redirect to login + if (current_time.abs_value_us > relog_time->abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Found cookie `%s', but it is expired.\n", + token); + GNUNET_free (cookies); + return; + } + value = strtok (token, OIDC_COOKIE_HEADER_INFORMATION_KEY); + GNUNET_assert (NULL != value); + handle->oidc->login_identity = GNUNET_strdup (value); + GNUNET_free (cookies); } + /** * Redirects to login page stored in configuration file */ static void -login_redirection(void *cls) +login_redirect (void *cls) { char *login_base_url; char *new_redirect; struct MHD_Response *resp; struct RequestHandle *handle = cls; - if ( GNUNET_OK - == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", - "address", &login_base_url) ) + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, + "reclaim-rest-plugin", + "address", + &login_base_url)) { - GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s", + GNUNET_asprintf (&new_redirect, + "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s", login_base_url, OIDC_RESPONSE_TYPE_KEY, handle->oidc->response_type, @@ -792,25 +868,32 @@ login_redirection(void *cls) handle->oidc->scope, OIDC_STATE_KEY, (NULL != handle->oidc->state) ? handle->oidc->state : "", + OIDC_CODE_CHALLENGE_KEY, + (NULL != handle->oidc->code_challenge) ? + handle->oidc->code_challenge : "", OIDC_NONCE_KEY, - (NULL != handle->oidc->nonce) ? handle->oidc->nonce : ""); + (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "", + OIDC_CLAIMS_KEY, + (NULL != handle->oidc->claims) ? handle->oidc->claims : + ""); resp = GNUNET_REST_create_response (""); MHD_add_response_header (resp, "Location", new_redirect); - GNUNET_free(login_base_url); + GNUNET_free (login_base_url); } else { - handle->emsg = GNUNET_strdup("server_error"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); handle->edesc = GNUNET_strdup ("gnunet configuration failed"); handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; GNUNET_SCHEDULER_add_now (&do_error, handle); return; } handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); - GNUNET_free(new_redirect); + GNUNET_free (new_redirect); GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); } + /** * Does internal server error when iteration failed. */ @@ -818,150 +901,146 @@ static void oidc_iteration_error (void *cls) { struct RequestHandle *handle = cls; - handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR"); + + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; GNUNET_SCHEDULER_add_now (&do_error, handle); } + +/** + * Issues ticket and redirects to relying party with the authorization code as + * parameter. Otherwise redirects with error + */ static void -get_client_name_result (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *label, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) +oidc_ticket_issue_cb (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket) { struct RequestHandle *handle = cls; struct MHD_Response *resp; char *ticket_str; char *redirect_uri; - char *code_json_string; - char *code_base64_final_string; - - ticket_str = GNUNET_STRINGS_data_to_string_alloc (&handle->ticket, - sizeof (struct GNUNET_RECLAIM_Ticket)); - //TODO change if more attributes are needed (see max_age) - code_json_string = OIDC_build_authz_code (&handle->priv_key, - &handle->ticket, - handle->oidc->nonce); - code_base64_final_string = base_64_encode(code_json_string); - GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s", - handle->redirect_prefix, - handle->tld, - handle->redirect_suffix, - handle->oidc->response_type, - code_base64_final_string, handle->oidc->state); + char *code_string; + + handle->idp_op = NULL; + if (NULL == ticket) + { + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); + handle->edesc = GNUNET_strdup ("Server cannot generate ticket."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + handle->ticket = *ticket; + ticket_str = + GNUNET_STRINGS_data_to_string_alloc (&handle->ticket, + sizeof(struct GNUNET_RECLAIM_Ticket)); + code_string = OIDC_build_authz_code (&handle->priv_key, + &handle->ticket, + handle->attr_list, + handle->attests_list, + handle->oidc->nonce, + handle->oidc->code_challenge); + if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) && + (NULL != handle->tld)) + { + GNUNET_asprintf (&redirect_uri, + "%s.%s/%s?%s=%s&state=%s", + handle->redirect_prefix, + handle->tld, + handle->redirect_suffix, + handle->oidc->response_type, + code_string, + handle->oidc->state); + } + else + { + GNUNET_asprintf (&redirect_uri, + "%s?%s=%s&state=%s", + handle->oidc->redirect_uri, + handle->oidc->response_type, + code_string, + handle->oidc->state); + } resp = GNUNET_REST_create_response (""); MHD_add_response_header (resp, "Location", redirect_uri); handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); GNUNET_free (redirect_uri); GNUNET_free (ticket_str); - GNUNET_free (code_json_string); - GNUNET_free (code_base64_final_string); - return; - + GNUNET_free (code_string); } static void -get_client_name_error (void *cls) +oidc_attest_collect_finished_cb (void *cls) { struct RequestHandle *handle = cls; - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup("Server cannot generate ticket, no name found for client."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + handle->attest_it = NULL; + handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp, + &handle->priv_key, + &handle->oidc->client_pkey, + handle->attr_list, + &oidc_ticket_issue_cb, + handle); } -static void -lookup_redirect_uri_result (void *cls, - uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - char *tmp; - char *tmp_key_str; - char *pos; - struct GNUNET_CRYPTO_EcdsaPublicKey redirect_zone; - - handle->gns_op = NULL; - if (1 != rd_count) - { - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup("Server cannot generate ticket, redirect uri not found."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; - } - tmp = GNUNET_strdup (rd->data); - pos = strrchr (tmp, - (unsigned char) '.'); - *pos = '\0'; - handle->redirect_prefix = GNUNET_strdup (tmp); - tmp_key_str = pos + 1; - pos = strchr (tmp_key_str, - (unsigned char) '/'); - *pos = '\0'; - handle->redirect_suffix = GNUNET_strdup (pos + 1); - - GNUNET_STRINGS_string_to_data (tmp_key_str, - strlen (tmp_key_str), - &redirect_zone, - sizeof (redirect_zone)); - - GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle, - &handle->priv_key, - &redirect_zone, - &get_client_name_error, - handle, - &get_client_name_result, - handle); - GNUNET_free (tmp); - -} - /** - * Issues ticket and redirects to relying party with the authorization code as - * parameter. Otherwise redirects with error + * Collects all attributes for an ego if in scope parameter */ static void -oidc_ticket_issue_cb (void* cls, - const struct GNUNET_RECLAIM_Ticket *ticket) +oidc_attest_collect (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_RECLAIM_Attestation *attest) { struct RequestHandle *handle = cls; + struct GNUNET_RECLAIM_AttributeListEntry *le; - handle->idp_op = NULL; - handle->ticket = *ticket; - if (NULL == ticket) + for (le = handle->attr_list->list_head; NULL != le; le = le->next) { - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup("Server cannot generate ticket."); - GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - return; + if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&le->attribute->attestation, + &attest->id)) + { + struct GNUNET_RECLAIM_AttestationListEntry *ale; + ale = GNUNET_new (struct GNUNET_RECLAIM_AttestationListEntry); + ale->attestation = GNUNET_RECLAIM_attestation_new (attest->name, + attest->type, + attest->data, + attest->data_size); + GNUNET_CONTAINER_DLL_insert (handle->attests_list->list_head, + handle->attests_list->list_tail, + ale); + } } - handle->gns_op = GNUNET_GNS_lookup (handle->gns_handle, - handle->oidc->redirect_uri, - &handle->oidc->client_pkey, - GNUNET_DNSPARSER_TYPE_TXT, - GNUNET_GNS_LO_DEFAULT, - &lookup_redirect_uri_result, - handle); - + GNUNET_RECLAIM_get_attestations_next (handle->attest_it); } + static void -oidc_collect_finished_cb (void *cls) +oidc_attr_collect_finished_cb (void *cls) { struct RequestHandle *handle = cls; + handle->attr_it = NULL; handle->ticket_it = NULL; if (NULL == handle->attr_list->list_head) { - handle->emsg = GNUNET_strdup("invalid_scope"); - handle->edesc = GNUNET_strdup("The requested scope is not available."); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE); + handle->edesc = GNUNET_strdup ("The requested scope is not available."); GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); return; } + handle->attests_list = GNUNET_new (struct GNUNET_RECLAIM_AttestationList); + handle->attest_it = + GNUNET_RECLAIM_get_attestations_start (handle->idp, + &handle->priv_key, + &oidc_iteration_error, + handle, + &oidc_attest_collect, + handle, + &oidc_attest_collect_finished_cb, + handle); + handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp, &handle->priv_key, &handle->oidc->client_pkey, @@ -977,43 +1056,42 @@ oidc_collect_finished_cb (void *cls) static void oidc_attr_collect (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) + const struct GNUNET_RECLAIM_Attribute *attr) { struct RequestHandle *handle = cls; - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le; - char* scope_variables; - char* scope_variable; - char delimiter[]=" "; - - if ( (NULL == attr->name) || (NULL == attr->data) ) - { - GNUNET_RECLAIM_get_attributes_next (handle->attr_it); - return; - } + struct GNUNET_RECLAIM_AttributeListEntry *le; + char *scope_variables; + char *scope_variable; + char delimiter[] = " "; - scope_variables = GNUNET_strdup(handle->oidc->scope); + scope_variables = GNUNET_strdup (handle->oidc->scope); scope_variable = strtok (scope_variables, delimiter); while (NULL != scope_variable) { - if ( 0 == strcmp (attr->name, scope_variable) ) - { + if (0 == strcmp (attr->name, scope_variable)) break; - } scope_variable = strtok (NULL, delimiter); } - if ( NULL == scope_variable ) + if (NULL == scope_variable) { GNUNET_RECLAIM_get_attributes_next (handle->attr_it); - GNUNET_free(scope_variables); + GNUNET_free (scope_variables); + // We can ignore this return; } - GNUNET_free(scope_variables); - - le = GNUNET_new(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry); - le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name, attr->type, - attr->data, attr->data_size); - GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head, - handle->attr_list->list_tail, le); + GNUNET_free (scope_variables); + le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry); + le->attribute = GNUNET_RECLAIM_attribute_new (attr->name, + &attr->attestation, + attr->type, + attr->data, + attr->data_size); + le->attribute->id = attr->id; + le->attribute->flag = attr->flag; + le->attribute->attestation = attr->attestation; + GNUNET_CONTAINER_DLL_insert (handle->attr_list->list_head, + handle->attr_list->list_tail, + le); GNUNET_RECLAIM_get_attributes_next (handle->attr_it); } @@ -1022,70 +1100,232 @@ oidc_attr_collect (void *cls, * Checks time and cookie and redirects accordingly */ static void -login_check (void *cls) +code_redirect (void *cls) { struct RequestHandle *handle = cls; - struct GNUNET_TIME_Absolute current_time, *relog_time; - struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey; + struct GNUNET_TIME_Absolute current_time; + struct GNUNET_TIME_Absolute *relog_time; + struct GNUNET_CRYPTO_EcdsaPublicKey pubkey; + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pkey; struct GNUNET_HashCode cache_key; char *identity_cookie; - GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity); + GNUNET_asprintf (&identity_cookie, + "Identity=%s", + handle->oidc->login_identity); GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key); - GNUNET_free(identity_cookie); - //No login time for identity -> redirect to login - if ( GNUNET_YES - == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, - &cache_key) ) - { - relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time, - &cache_key); + GNUNET_free (identity_cookie); + // No login time for identity -> redirect to login + if (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (OIDC_cookie_jar_map, &cache_key)) + { + relog_time = + GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key); current_time = GNUNET_TIME_absolute_get (); // 30 min after old login -> redirect to login - if ( current_time.abs_value_us <= relog_time->abs_value_us ) + if (current_time.abs_value_us <= relog_time->abs_value_us) { - if ( GNUNET_OK - != GNUNET_CRYPTO_ecdsa_public_key_from_string ( - handle->oidc->login_identity, - strlen (handle->oidc->login_identity), &pubkey) ) + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc + ->login_identity, + strlen ( + handle->oidc + ->login_identity), + &pubkey)) { - handle->emsg = GNUNET_strdup("invalid_cookie"); - handle->edesc = GNUNET_strdup( - "The cookie of a login identity is not valid"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_COOKIE); + handle->edesc = + GNUNET_strdup ("The cookie of a login identity is not valid"); GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); return; } // iterate over egos and compare their public key - for (handle->ego_entry = handle->ego_head; - NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next) + for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry; + handle->ego_entry = handle->ego_entry->next) { GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey); - if ( 0 - == memcmp (&ego_pkey, &pubkey, - sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) + if (0 == GNUNET_memcmp (&ego_pkey, &pubkey)) { - handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key ( - handle->ego_entry->ego); - handle->resp_object = GNUNET_JSONAPI_document_new (); + handle->priv_key = + *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego); handle->idp = GNUNET_RECLAIM_connect (cfg); - handle->attr_list = GNUNET_new( - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); - handle->attr_it = GNUNET_RECLAIM_get_attributes_start ( - handle->idp, &handle->priv_key, &oidc_iteration_error, handle, - &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle); + handle->attr_list = + GNUNET_new (struct GNUNET_RECLAIM_AttributeList); + handle->attr_it = + GNUNET_RECLAIM_get_attributes_start (handle->idp, + &handle->priv_key, + &oidc_iteration_error, + handle, + &oidc_attr_collect, + handle, + &oidc_attr_collect_finished_cb, + handle); return; } } - //handle->emsg = GNUNET_strdup("invalid_cookie"); - //handle->edesc = GNUNET_strdup( - // "The cookie of the login identity is not valid"); - //GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - GNUNET_SCHEDULER_add_now (&login_redirection,handle); + GNUNET_SCHEDULER_add_now (&login_redirect, handle); return; } } } + +static void +build_redirect (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + char *redirect_uri; + + if (GNUNET_YES == handle->oidc->user_cancelled) + { + if ((NULL != handle->redirect_prefix) && + (NULL != handle->redirect_suffix) && (NULL != handle->tld)) + { + GNUNET_asprintf (&redirect_uri, + "%s.%s/%s?error=%s&error_description=%s&state=%s", + handle->redirect_prefix, + handle->tld, + handle->redirect_suffix, + "access_denied", + "User denied access", + handle->oidc->state); + } + else + { + GNUNET_asprintf (&redirect_uri, + "%s?error=%s&error_description=%s&state=%s", + handle->oidc->redirect_uri, + "access_denied", + "User denied access", + handle->oidc->state); + } + resp = GNUNET_REST_create_response (""); + MHD_add_response_header (resp, "Location", redirect_uri); + handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + GNUNET_free (redirect_uri); + return; + } + GNUNET_SCHEDULER_add_now (&code_redirect, handle); +} + + +static void +lookup_redirect_uri_result (void *cls, + uint32_t rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct RequestHandle *handle = cls; + char *tmp; + char *tmp_key_str; + char *pos; + struct GNUNET_CRYPTO_EcdsaPublicKey redirect_zone; + + handle->gns_op = NULL; + if (0 == rd_count) + { + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); + handle->edesc = + GNUNET_strdup ("Server cannot generate ticket, redirect uri not found."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); + return; + } + for (int i = 0; i < rd_count; i++) + { + if (GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT != rd[i].record_type) + continue; + if (0 != strncmp (rd[i].data, handle->oidc->redirect_uri, rd[i].data_size)) + continue; + tmp = GNUNET_strndup (rd[i].data, rd[i].data_size); + if (NULL == strstr (tmp, handle->oidc->client_id)) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Redirect uri %s does not contain client_id %s\n", + tmp, + handle->oidc->client_id); + } + else + { + pos = strrchr (tmp, (unsigned char) '.'); + if (NULL == pos) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Redirect uri %s contains client_id but is malformed\n", + tmp); + GNUNET_free (tmp); + continue; + } + *pos = '\0'; + handle->redirect_prefix = GNUNET_strdup (tmp); + tmp_key_str = pos + 1; + pos = strchr (tmp_key_str, (unsigned char) '/'); + if (NULL == pos) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Redirect uri %s contains client_id but is malformed\n", + tmp); + GNUNET_free (tmp); + continue; + } + *pos = '\0'; + handle->redirect_suffix = GNUNET_strdup (pos + 1); + + GNUNET_STRINGS_string_to_data (tmp_key_str, + strlen (tmp_key_str), + &redirect_zone, + sizeof(redirect_zone)); + } + GNUNET_SCHEDULER_add_now (&build_redirect, handle); + GNUNET_free (tmp); + return; + } + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); + handle->edesc = + GNUNET_strdup ("Server cannot generate ticket, redirect uri not found."); + GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); +} + + +/** + * Initiate redirect back to client. + */ +static void +client_redirect (void *cls) +{ + struct RequestHandle *handle = cls; + + /* Lookup client redirect uri to verify request */ + handle->gns_op = + GNUNET_GNS_lookup (handle->gns_handle, + GNUNET_GNS_EMPTY_LABEL_AT, + &handle->oidc->client_pkey, + GNUNET_GNSRECORD_TYPE_RECLAIM_OIDC_REDIRECT, + GNUNET_GNS_LO_DEFAULT, + &lookup_redirect_uri_result, + handle); +} + + +static char * +get_url_parameter_copy (const struct RequestHandle *handle, const char *key) +{ + struct GNUNET_HashCode hc; + char *value; + + GNUNET_CRYPTO_hash (key, strlen (key), &hc); + if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle + ->url_param_map, + &hc)) + return NULL; + value = + GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, &hc); + if (NULL == value) + return NULL; + return GNUNET_strdup (value); +} + + /** * Iteration over all results finished, build final * response. @@ -1099,124 +1339,130 @@ build_authz_response (void *cls) struct GNUNET_HashCode cache_key; char *expected_scope; - char delimiter[]=" "; + char delimiter[] = " "; int number_of_ignored_parameter, iterator; // REQUIRED value: redirect_uri - GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) + handle->oidc->redirect_uri = + get_url_parameter_copy (handle, OIDC_REDIRECT_URI_KEY); + if (NULL == handle->oidc->redirect_uri) { - handle->emsg=GNUNET_strdup("invalid_request"); - handle->edesc=GNUNET_strdup("missing parameter redirect_uri"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); + handle->edesc = GNUNET_strdup ("missing parameter redirect_uri"); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - handle->oidc->redirect_uri = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key)); // REQUIRED value: response_type - GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) + handle->oidc->response_type = + get_url_parameter_copy (handle, OIDC_RESPONSE_TYPE_KEY); + if (NULL == handle->oidc->response_type) { - handle->emsg=GNUNET_strdup("invalid_request"); - handle->edesc=GNUNET_strdup("missing parameter response_type"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); + handle->edesc = GNUNET_strdup ("missing parameter response_type"); GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); return; } - handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key); - handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type); // REQUIRED value: scope - GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) + handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY); + if (NULL == handle->oidc->scope) { - handle->emsg=GNUNET_strdup("invalid_request"); - handle->edesc=GNUNET_strdup("missing parameter scope"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE); + handle->edesc = GNUNET_strdup ("missing parameter scope"); GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); return; } - handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key); - handle->oidc->scope = GNUNET_strdup(handle->oidc->scope); - //OPTIONAL value: nonce - GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key); - if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key); - handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce); - } + // OPTIONAL value: nonce + handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY); - //TODO check other values if needed - number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *); - for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ ) + // OPTIONAL value: claims + handle->oidc->claims = get_url_parameter_copy (handle, OIDC_CLAIMS_KEY); + + // TODO check other values if needed + number_of_ignored_parameter = + sizeof(OIDC_ignored_parameter_array) / sizeof(char *); + for (iterator = 0; iterator < number_of_ignored_parameter; iterator++) { GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator], - strlen(OIDC_ignored_parameter_array[iterator]), + strlen (OIDC_ignored_parameter_array[iterator]), &cache_key); - if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map, - &cache_key)) + if (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle + ->url_param_map, + &cache_key)) { - handle->emsg=GNUNET_strdup("access_denied"); - GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s", + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_ACCESS_DENIED); + GNUNET_asprintf (&handle->edesc, + "Server will not handle parameter: %s", OIDC_ignored_parameter_array[iterator]); GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); return; } } - // Checks if response_type is 'code' - if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) ) + // We only support authorization code flows. + if (0 != strcmp (handle->oidc->response_type, + OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE)) { - handle->emsg=GNUNET_strdup("unsupported_response_type"); - handle->edesc=GNUNET_strdup("The authorization server does not support " - "obtaining this authorization code."); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNSUPPORTED_RESPONSE_TYPE); + handle->edesc = GNUNET_strdup ("The authorization server does not support " + "obtaining this authorization code."); GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); return; } // Checks if scope contains 'openid' - expected_scope = GNUNET_strdup(handle->oidc->scope); - char* test; + expected_scope = GNUNET_strdup (handle->oidc->scope); + char *test; test = strtok (expected_scope, delimiter); while (NULL != test) { - if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) ) - { + if (0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope)) break; - } test = strtok (NULL, delimiter); } if (NULL == test) { - handle->emsg = GNUNET_strdup("invalid_scope"); - handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or " - "malformed."); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_SCOPE); + handle->edesc = + GNUNET_strdup ("The requested scope is invalid, unknown, or malformed."); GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); - GNUNET_free(expected_scope); + GNUNET_free (expected_scope); return; } - GNUNET_free(expected_scope); + GNUNET_free (expected_scope); + if ((NULL == handle->oidc->login_identity) && + (GNUNET_NO == handle->oidc->user_cancelled)) + GNUNET_SCHEDULER_add_now (&login_redirect, handle); + else + GNUNET_SCHEDULER_add_now (&client_redirect, handle); +} + + +/** + * Iterate over tlds in config + */ +static void +tld_iter (void *cls, const char *section, const char *option, const char *value) +{ + struct RequestHandle *handle = cls; + struct GNUNET_CRYPTO_EcdsaPublicKey pkey; - if( NULL != handle->oidc->login_identity ) + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_public_key_from_string (value, strlen (value), &pkey)) { - GNUNET_SCHEDULER_add_now(&login_check,handle); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping non key %s\n", value); return; } - - GNUNET_SCHEDULER_add_now(&login_redirection,handle); + if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey)) + handle->tld = GNUNET_strdup (option + 1); } + /** * Responds to authorization GET and url-encoded POST request * @@ -1226,84 +1472,75 @@ build_authz_response (void *cls) */ static void authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, + const char *url, void *cls) { struct RequestHandle *handle = cls; - struct GNUNET_HashCode cache_key; struct EgoEntry *tmp_ego; const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; struct GNUNET_CRYPTO_EcdsaPublicKey pkey; - cookie_identity_interpretation(handle); + cookie_identity_interpretation (handle); - //RECOMMENDED value: state - REQUIRED for answers - GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key); - if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) - { - handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key); - handle->oidc->state = GNUNET_strdup (handle->oidc->state); - } + // RECOMMENDED value: state - REQUIRED for answers + handle->oidc->state = get_url_parameter_copy (handle, OIDC_STATE_KEY); // REQUIRED value: client_id - GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY), - &cache_key); - if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) + handle->oidc->client_id = get_url_parameter_copy (handle, OIDC_CLIENT_ID_KEY); + if (NULL == handle->oidc->client_id) { - handle->emsg=GNUNET_strdup("invalid_request"); - handle->edesc=GNUNET_strdup("missing parameter client_id"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); + handle->edesc = GNUNET_strdup ("missing parameter client_id"); handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - handle->oidc->client_id = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, - &cache_key)); - if ( GNUNET_OK - != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id, - strlen (handle->oidc->client_id), - &handle->oidc->client_pkey) ) + // OPTIONAL value: code_challenge + handle->oidc->code_challenge = get_url_parameter_copy (handle, + OIDC_CODE_CHALLENGE_KEY); + if (NULL == handle->oidc->code_challenge) { - handle->emsg = GNUNET_strdup("unauthorized_client"); - handle->edesc = GNUNET_strdup("The client is not authorized to request an " - "authorization code using this method."); - handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "OAuth authorization request does not contain PKCE parameters!\n"); } - - if ( NULL == handle->ego_head ) - { - handle->emsg = GNUNET_strdup("server_error"); - handle->edesc = GNUNET_strdup ("Egos are missing"); + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id, + strlen ( + handle->oidc->client_id), + &handle->oidc->client_pkey)) + { + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT); + handle->edesc = GNUNET_strdup ("The client is not authorized to request an " + "authorization code using this method."); handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - handle->ego_entry = handle->ego_head; - handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego); - //If we know this identity, translated the corresponding TLD - //TODO: We might want to have a reverse lookup functionality for TLDs? + // If we know this identity, translated the corresponding TLD + // TODO: We might want to have a reverse lookup functionality for TLDs? for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next) { priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego); - GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, - &pkey); - if ( 0 == memcmp (&pkey, &handle->oidc->client_pkey, - sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) + GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &pkey); + if (0 == GNUNET_memcmp (&pkey, &handle->oidc->client_pkey)) { handle->tld = GNUNET_strdup (tmp_ego->identifier); handle->ego_entry = handle->ego_tail; } - } + } + handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scope: %s\n", handle->oidc->scope); + if (NULL == handle->tld) + GNUNET_CONFIGURATION_iterate_section_values (cfg, "gns", tld_iter, handle); + if (NULL == handle->tld) + handle->tld = GNUNET_strdup (handle->oidc->client_id); GNUNET_SCHEDULER_add_now (&build_authz_response, handle); } + /** * Combines an identity with a login time and responds OK to login request * @@ -1313,7 +1550,7 @@ authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle, */ static void login_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, + const char *url, void *cls) { struct MHD_Response *resp = GNUNET_REST_create_response (""); @@ -1321,48 +1558,61 @@ login_cont (struct GNUNET_REST_RequestHandle *con_handle, struct GNUNET_HashCode cache_key; struct GNUNET_TIME_Absolute *current_time; struct GNUNET_TIME_Absolute *last_time; - char* cookie; + char *cookie; + char *header_val; json_t *root; json_error_t error; json_t *identity; - char term_data[handle->rest_handle->data_size+1]; + char term_data[handle->rest_handle->data_size + 1]; + term_data[handle->rest_handle->data_size] = '\0'; - GNUNET_memcpy (term_data, handle->rest_handle->data, handle->rest_handle->data_size); + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); root = json_loads (term_data, JSON_DECODE_ANY, &error); identity = json_object_get (root, "identity"); - if ( json_is_string(identity) ) + if (! json_is_string (identity)) { - GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity)); - MHD_add_response_header (resp, "Set-Cookie", cookie); - MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST"); - GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error parsing json string from %s\n", + term_data); + handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); + json_decref (root); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); + return; + } + GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity)); + GNUNET_asprintf (&header_val, + "%s;Max-Age=%d", + cookie, + OIDC_COOKIE_EXPIRATION); + MHD_add_response_header (resp, "Set-Cookie", header_val); + MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST"); + GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key); - current_time = GNUNET_new(struct GNUNET_TIME_Absolute); + if (0 != strcmp (json_string_value (identity), "Denied")) + { + current_time = GNUNET_new (struct GNUNET_TIME_Absolute); *current_time = GNUNET_TIME_relative_to_absolute ( - GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (), - 5)); - last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key); - if (NULL != last_time) - { - GNUNET_free(last_time); - } - GNUNET_CONTAINER_multihashmap_put ( - OIDC_identity_login_time, &cache_key, current_time, + GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (), + OIDC_COOKIE_EXPIRATION)); + last_time = + GNUNET_CONTAINER_multihashmap_get (OIDC_cookie_jar_map, &cache_key); + GNUNET_free_non_null (last_time); + GNUNET_CONTAINER_multihashmap_put (OIDC_cookie_jar_map, + &cache_key, + current_time, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); - - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free(cookie); - } - else - { - handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); } + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free (cookie); + GNUNET_free (header_val); json_decref (root); GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); - return; } -static int + +static int check_authorization (struct RequestHandle *handle, struct GNUNET_CRYPTO_EcdsaPublicKey *cid) { @@ -1373,165 +1623,152 @@ check_authorization (struct RequestHandle *handle, char *client_id; char *pass; char *expected_pass; - int client_exists = GNUNET_NO; GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, strlen (OIDC_AUTHORIZATION_HEADER_KEY), &cache_key); - if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map, - &cache_key) ) + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle + ->header_param_map, + &cache_key)) { - handle->emsg=GNUNET_strdup("invalid_client"); - handle->edesc=GNUNET_strdup("missing authorization"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT); + handle->edesc = GNUNET_strdup ("missing authorization"); handle->response_code = MHD_HTTP_UNAUTHORIZED; return GNUNET_SYSERR; } - authorization = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map, - &cache_key); + authorization = + GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map, + &cache_key); - //split header in "Basic" and [content] + // split header in "Basic" and [content] credentials = strtok (authorization, " "); - if (0 != strcmp ("Basic", credentials)) + if ((NULL == credentials) || (0 != strcmp ("Basic", credentials))) { - handle->emsg=GNUNET_strdup("invalid_client"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT); handle->response_code = MHD_HTTP_UNAUTHORIZED; return GNUNET_SYSERR; } - credentials = strtok(NULL, " "); + credentials = strtok (NULL, " "); if (NULL == credentials) { - handle->emsg=GNUNET_strdup("invalid_client"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT); handle->response_code = MHD_HTTP_UNAUTHORIZED; return GNUNET_SYSERR; } GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), - (void**)&basic_authorization); + (void **) &basic_authorization); - if ( NULL == basic_authorization ) + if (NULL == basic_authorization) { - handle->emsg=GNUNET_strdup("invalid_client"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT); handle->response_code = MHD_HTTP_UNAUTHORIZED; return GNUNET_SYSERR; } client_id = strtok (basic_authorization, ":"); - if ( NULL == client_id ) + if (NULL == client_id) { - GNUNET_free_non_null(basic_authorization); - handle->emsg=GNUNET_strdup("invalid_client"); + GNUNET_free_non_null (basic_authorization); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT); handle->response_code = MHD_HTTP_UNAUTHORIZED; return GNUNET_SYSERR; } pass = strtok (NULL, ":"); if (NULL == pass) { - GNUNET_free_non_null(basic_authorization); - handle->emsg=GNUNET_strdup("invalid_client"); + GNUNET_free_non_null (basic_authorization); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT); handle->response_code = MHD_HTTP_UNAUTHORIZED; return GNUNET_SYSERR; } - //check client password - if ( GNUNET_OK - == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", - "psw", &expected_pass) ) + // check client password + if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, + "reclaim-rest-plugin", + "OIDC_CLIENT_SECRET", + &expected_pass)) { if (0 != strcmp (expected_pass, pass)) { - GNUNET_free_non_null(basic_authorization); - GNUNET_free(expected_pass); - handle->emsg=GNUNET_strdup("invalid_client"); + GNUNET_free_non_null (basic_authorization); + GNUNET_free (expected_pass); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT); handle->response_code = MHD_HTTP_UNAUTHORIZED; return GNUNET_SYSERR; } - GNUNET_free(expected_pass); + GNUNET_free (expected_pass); } else { - GNUNET_free_non_null(basic_authorization); - handle->emsg = GNUNET_strdup("server_error"); + GNUNET_free_non_null (basic_authorization); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); handle->edesc = GNUNET_strdup ("gnunet configuration failed"); handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; return GNUNET_SYSERR; } - //check client_id - for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; ) + // check client_id + for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry; + handle->ego_entry = handle->ego_entry->next) { - if ( 0 == strcmp(handle->ego_entry->keystring, client_id)) - { - client_exists = GNUNET_YES; + if (0 == strcmp (handle->ego_entry->keystring, client_id)) break; - } - handle->ego_entry = handle->ego_entry->next; } - if (GNUNET_NO == client_exists) + if (NULL == handle->ego_entry) { - GNUNET_free_non_null(basic_authorization); - handle->emsg=GNUNET_strdup("invalid_client"); + GNUNET_free_non_null (basic_authorization); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_CLIENT); handle->response_code = MHD_HTTP_UNAUTHORIZED; return GNUNET_SYSERR; } GNUNET_STRINGS_string_to_data (client_id, - strlen(client_id), + strlen (client_id), cid, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)); GNUNET_free (basic_authorization); return GNUNET_OK; } -static int -ego_exists (struct RequestHandle *handle, - struct GNUNET_CRYPTO_EcdsaPublicKey *test_key) + +const struct EgoEntry * +find_ego (struct RequestHandle *handle, + struct GNUNET_CRYPTO_EcdsaPublicKey *test_key) { struct EgoEntry *ego_entry; struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; - for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) + for (ego_entry = handle->ego_head; NULL != ego_entry; + ego_entry = ego_entry->next) { GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key); - if (0 == memcmp (&pub_key, - test_key, - sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) - { - break; - } + if (0 == GNUNET_memcmp (&pub_key, test_key)) + return ego_entry; } - if (NULL == ego_entry) - return GNUNET_NO; - return GNUNET_YES; + return NULL; } + static void -store_ticket_reference (const struct RequestHandle *handle, - const char* access_token, - const struct GNUNET_RECLAIM_Ticket *ticket, - const struct GNUNET_CRYPTO_EcdsaPublicKey *cid) +persist_access_token (const struct RequestHandle *handle, + const char *access_token, + const struct GNUNET_RECLAIM_Ticket *ticket) { - struct GNUNET_HashCode cache_key; - char *id_ticket_combination; - char *ticket_string; - char *client_id; - - GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key); - client_id = GNUNET_STRINGS_data_to_string_alloc (cid, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - ticket_string = GNUNET_STRINGS_data_to_string_alloc (ticket, - sizeof (struct GNUNET_RECLAIM_Ticket)); - GNUNET_asprintf(&id_ticket_combination, - "%s;%s", - client_id, - ticket_string); - GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token, - &cache_key, - id_ticket_combination, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); - - GNUNET_free (client_id); - GNUNET_free (ticket_string); + struct GNUNET_HashCode hc; + struct GNUNET_RECLAIM_Ticket *ticketbuf; + + GNUNET_CRYPTO_hash (access_token, strlen (access_token), &hc); + ticketbuf = GNUNET_new (struct GNUNET_RECLAIM_Ticket); + *ticketbuf = *ticket; + GNUNET_assert (GNUNET_SYSERR != + GNUNET_CONTAINER_multihashmap_put ( + OIDC_access_token_map, + &hc, + ticketbuf, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); } + /** * Responds to token url-encoded POST request * @@ -1541,14 +1778,17 @@ store_ticket_reference (const struct RequestHandle *handle, */ static void token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, + const char *url, void *cls) { struct RequestHandle *handle = cls; + const struct EgoEntry *ego_entry; struct GNUNET_TIME_Relative expiration_time; - struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *cl; - struct GNUNET_RECLAIM_Ticket *ticket; + struct GNUNET_RECLAIM_AttributeList *cl = NULL; + struct GNUNET_RECLAIM_AttestationList *al = NULL; + struct GNUNET_RECLAIM_Ticket ticket; struct GNUNET_CRYPTO_EcdsaPublicKey cid; + const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey; struct GNUNET_HashCode cache_key; struct MHD_Response *resp; char *grant_type; @@ -1558,13 +1798,12 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, char *access_token; char *jwt_secret; char *nonce; - int i = 1; + char *code_verifier; /* * Check Authorization */ - if (GNUNET_SYSERR == check_authorization (handle, - &cid)) + if (GNUNET_SYSERR == check_authorization (handle, &cid)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "OIDC authorization for token endpoint failed\n"); @@ -1576,185 +1815,219 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, * Check parameter */ - //TODO Do not allow multiple equal parameter names - //REQUIRED grant_type - GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key); - if (GNUNET_NO == - GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) + // TODO Do not allow multiple equal parameter names + // REQUIRED grant_type + GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, + strlen (OIDC_GRANT_TYPE_KEY), + &cache_key); + grant_type = get_url_parameter_copy (handle, OIDC_GRANT_TYPE_KEY); + if (NULL == grant_type) { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("missing parameter grant_type"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); + handle->edesc = GNUNET_strdup ("missing parameter grant_type"); handle->response_code = MHD_HTTP_BAD_REQUEST; GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - grant_type = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, - &cache_key); - //REQUIRED code - GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key); - if (GNUNET_NO == - GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key)) + // Check parameter grant_type == "authorization_code" + if (0 != strcmp (OIDC_GRANT_TYPE_VALUE, grant_type)) { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("missing parameter code"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNSUPPORTED_GRANT_TYPE); handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_free (grant_type); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, - &cache_key); - - //REQUIRED redirect_uri - GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), - &cache_key); - if (GNUNET_NO == - GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, - &cache_key) ) + GNUNET_free (grant_type); + // REQUIRED code + code = get_url_parameter_copy (handle, OIDC_CODE_KEY); + if (NULL == code) { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("missing parameter redirect_uri"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); + handle->edesc = GNUNET_strdup ("missing parameter code"); handle->response_code = MHD_HTTP_BAD_REQUEST; GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - - //Check parameter grant_type == "authorization_code" - if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type)) + ego_entry = find_ego (handle, &cid); + if (NULL == ego_entry) { - handle->emsg=GNUNET_strdup("unsupported_grant_type"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); + handle->edesc = GNUNET_strdup ("Unknown client"); handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_free (code); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - GNUNET_CRYPTO_hash (code, strlen (code), &cache_key); - if (GNUNET_SYSERR == - GNUNET_CONTAINER_multihashmap_put (OIDC_ticket_once, - &cache_key, - &i, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) ) + privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + + // REQUIRED code verifier + code_verifier = get_url_parameter_copy (handle, OIDC_CODE_VERIFIER_KEY); + if (NULL == code_verifier) { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("Cannot use the same code more than once"); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "OAuth authorization request does not contain PKCE parameters!\n"); + } - //decode code - if(GNUNET_OK != OIDC_parse_authz_code (&cid, - code, - &ticket, - &nonce)) + // decode code + if (GNUNET_OK != OIDC_parse_authz_code (privkey, code, code_verifier, &ticket, + &cl, &al, &nonce)) { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("invalid code"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); + handle->edesc = GNUNET_strdup ("invalid code"); handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_free (code); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } + GNUNET_free (code); - //create jwt - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time(cfg, - "reclaim-rest-plugin", - "expiration_time", - &expiration_time)) + // create jwt + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, + "reclaim-rest-plugin", + "expiration_time", + &expiration_time)) { - handle->emsg = GNUNET_strdup("server_error"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); handle->edesc = GNUNET_strdup ("gnunet configuration failed"); handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_free(ticket); return; } - //TODO OPTIONAL acr,amr,azp - if (GNUNET_NO == ego_exists (handle, - &ticket->audience)) - { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("invalid code..."); - handle->response_code = MHD_HTTP_BAD_REQUEST; - GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_free(ticket); - } - if ( GNUNET_OK - != GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin", - "jwt_secret", &jwt_secret) ) + // TODO OPTIONAL acr,amr,azp + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, + "reclaim-rest-plugin", + "jwt_secret", + &jwt_secret)) { - handle->emsg = GNUNET_strdup("invalid_request"); - handle->edesc = GNUNET_strdup("No signing secret configured!"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); + handle->edesc = GNUNET_strdup ("No signing secret configured!"); handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_free(ticket); return; } - //TODO We should collect the attributes here. cl always empty - cl = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList); - id_token = OIDC_id_token_new (&ticket->audience, - &ticket->identity, + id_token = OIDC_id_token_new (&ticket.audience, + &ticket.identity, cl, + al, &expiration_time, (NULL != nonce) ? nonce : NULL, jwt_secret); - access_token = OIDC_access_token_new (); + access_token = OIDC_access_token_new (); OIDC_build_token_response (access_token, id_token, &expiration_time, &json_response); - store_ticket_reference (handle, - access_token, - ticket, - &cid); + persist_access_token (handle, access_token, &ticket); resp = GNUNET_REST_create_response (json_response); MHD_add_response_header (resp, "Cache-Control", "no-store"); MHD_add_response_header (resp, "Pragma", "no-cache"); MHD_add_response_header (resp, "Content-Type", "application/json"); handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_RECLAIM_ATTRIBUTE_list_destroy(cl); - GNUNET_free(access_token); - GNUNET_free(json_response); - GNUNET_free(ticket); - GNUNET_free(id_token); - GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle); + GNUNET_RECLAIM_attribute_list_destroy (cl); + GNUNET_RECLAIM_attestation_list_destroy (al); + GNUNET_free (access_token); + GNUNET_free (json_response); + GNUNET_free (id_token); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); } + /** * Collects claims and stores them in handle */ static void consume_ticket (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, - const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr) + const struct GNUNET_RECLAIM_Attribute *attr, + const struct GNUNET_RECLAIM_Attestation *attest) { struct RequestHandle *handle = cls; - char *tmp_value; - json_t *value; + handle->idp_op = NULL; if (NULL == identity) { GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle); return; } - - tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, - attr->data, - attr->data_size); - - value = json_string (tmp_value); - - - json_object_set_new (handle->oidc->response, - attr->name, - value); - GNUNET_free (tmp_value); + if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attr->attestation)) + { + char *tmp_value; + json_t *value; + tmp_value = GNUNET_RECLAIM_attribute_value_to_string (attr->type, + attr->data, + attr->data_size); + value = json_string (tmp_value); + json_object_set_new (handle->oidc->response, attr->name, value); + GNUNET_free (tmp_value); + return; + } + json_t *claim_sources; + json_t *claim_sources_jwt; + json_t *claim_names; + char *attest_val_str; + claim_sources = json_object_get (handle->oidc->response,"_claim_sources"); + claim_names = json_object_get (handle->oidc->response,"_claim_names"); + attest_val_str = + GNUNET_RECLAIM_attestation_value_to_string (attest->type, + attest->data, + attest->data_size); + if ((NULL == claim_sources) && (NULL == claim_names) ) + { + claim_sources = json_object (); + claim_names = json_object (); + } + char *source_name; + int i = 0; + GNUNET_asprintf (&source_name, "src%d", i); + while (NULL != (claim_sources_jwt = json_object_get (claim_sources, + source_name))) + { + if (0 == strcmp (json_string_value (json_object_get (claim_sources_jwt, + "JWT")), + attest_val_str)) + { + // Adapt only the claim names + json_object_set_new (claim_names, attr->data, + json_string (source_name)); + json_object_set (handle->oidc->response, + "_claim_names", claim_names); + break; + } + i++; + GNUNET_free (source_name); + GNUNET_asprintf (&source_name, "src%d", i); + } + + // Create new one + if (NULL == claim_sources_jwt) + { + claim_sources_jwt = json_object (); + // Set the JWT for names + json_object_set_new (claim_names, attr->data, + json_string (source_name)); + // Set the JWT for the inner source + json_object_set_new (claim_sources_jwt, "JWT", + json_string (attest_val_str)); + // Set the JWT for the source + json_object_set_new (claim_sources, source_name, claim_sources_jwt); + // Set as claims + json_object_set (handle->oidc->response, "_claim_names", claim_names); + json_object_set (handle->oidc->response, "_claim_sources",claim_sources); + } + + json_decref (claim_sources); + json_decref (claim_names); + json_decref (claim_sources_jwt); + GNUNET_free (attest_val_str); } + /** * Responds to userinfo GET and url-encoded POST request * @@ -1764,143 +2037,101 @@ consume_ticket (void *cls, */ static void userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, void *cls) + const char *url, + void *cls) { - //TODO expiration time + // TODO expiration time struct RequestHandle *handle = cls; char delimiter[] = " "; - char delimiter_db[] = ";"; struct GNUNET_HashCode cache_key; - char *authorization, *authorization_type, *authorization_access_token; - char *client_ticket, *client, *ticket_str; + char *authorization; + char *authorization_type; + char *authorization_access_token; struct GNUNET_RECLAIM_Ticket *ticket; + const struct EgoEntry *ego_entry; + const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey; GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, strlen (OIDC_AUTHORIZATION_HEADER_KEY), &cache_key); - if ( GNUNET_NO - == GNUNET_CONTAINER_multihashmap_contains ( - handle->rest_handle->header_param_map, &cache_key) ) + if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle + ->header_param_map, + &cache_key)) { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("No Access Token"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); + handle->edesc = GNUNET_strdup ("No Access Token"); handle->response_code = MHD_HTTP_UNAUTHORIZED; GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); return; } - authorization = GNUNET_CONTAINER_multihashmap_get ( - handle->rest_handle->header_param_map, &cache_key); + authorization = + GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->header_param_map, + &cache_key); - //split header in "Bearer" and access_token - authorization = GNUNET_strdup(authorization); + // split header in "Bearer" and access_token + authorization = GNUNET_strdup (authorization); authorization_type = strtok (authorization, delimiter); - if ( 0 != strcmp ("Bearer", authorization_type) ) + if ((NULL == authorization_type) || + (0 != strcmp ("Bearer", authorization_type))) { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("No Access Token"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); + handle->edesc = GNUNET_strdup ("No Access Token"); handle->response_code = MHD_HTTP_UNAUTHORIZED; GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); + GNUNET_free (authorization); return; } authorization_access_token = strtok (NULL, delimiter); - if ( NULL == authorization_access_token ) + if (NULL == authorization_access_token) { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("No Access Token"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); + handle->edesc = GNUNET_strdup ("Access token missing"); handle->response_code = MHD_HTTP_UNAUTHORIZED; GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); + GNUNET_free (authorization); return; } GNUNET_CRYPTO_hash (authorization_access_token, strlen (authorization_access_token), &cache_key); - if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token, - &cache_key) ) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - return; - } - - client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token, - &cache_key); - client_ticket = GNUNET_strdup(client_ticket); - client = strtok(client_ticket,delimiter_db); - if (NULL == client) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - return; - } - handle->ego_entry = handle->ego_head; - for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next) - { - if (0 == strcmp(handle->ego_entry->keystring,client)) - { - break; - } - } - if (NULL == handle->ego_entry) - { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); - handle->response_code = MHD_HTTP_UNAUTHORIZED; - GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - return; - } - ticket_str = strtok(NULL, delimiter_db); - if (NULL == ticket_str) + if (GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (OIDC_access_token_map, + &cache_key)) { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); + handle->edesc = GNUNET_strdup ("The access token expired"); handle->response_code = MHD_HTTP_UNAUTHORIZED; GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(authorization); - GNUNET_free(client_ticket); + GNUNET_free (authorization); return; } - ticket = GNUNET_new(struct GNUNET_RECLAIM_Ticket); - if ( GNUNET_OK - != GNUNET_STRINGS_string_to_data (ticket_str, - strlen (ticket_str), - ticket, - sizeof(struct GNUNET_RECLAIM_Ticket))) + ticket = + GNUNET_CONTAINER_multihashmap_get (OIDC_access_token_map, &cache_key); + GNUNET_assert (NULL != ticket); + ego_entry = find_ego (handle, &ticket->audience); + if (NULL == ego_entry) { - handle->emsg = GNUNET_strdup("invalid_token"); - handle->edesc = GNUNET_strdup("The Access Token expired"); + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); + handle->edesc = GNUNET_strdup ("The access token expired"); handle->response_code = MHD_HTTP_UNAUTHORIZED; GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); - GNUNET_free(ticket); - GNUNET_free(authorization); - GNUNET_free(client_ticket); + GNUNET_free (authorization); return; } handle->idp = GNUNET_RECLAIM_connect (cfg); - handle->oidc->response = json_object(); - json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring)); - handle->idp_op = GNUNET_RECLAIM_ticket_consume ( - handle->idp, - GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego), + handle->oidc->response = json_object (); + json_object_set_new (handle->oidc->response, + "sub", + json_string (ego_entry->keystring)); + privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp, + privkey, ticket, consume_ticket, handle); - GNUNET_free(ticket); - GNUNET_free(authorization); - GNUNET_free(client_ticket); - + GNUNET_free (authorization); } @@ -1913,28 +2144,27 @@ static void init_cont (struct RequestHandle *handle) { struct GNUNET_REST_RequestHandlerError err; - static const struct GNUNET_REST_RequestHandler handlers[] = { - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint }, - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, - {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, - &options_cont}, - GNUNET_REST_HANDLER_END - }; - - if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, - handlers, - &err, - handle)) + static const struct GNUNET_REST_RequestHandler handlers[] = + { { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint }, + { MHD_HTTP_METHOD_POST, + GNUNET_REST_API_NS_AUTHORIZE, + &authorize_endpoint }, // url-encoded + { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont }, + { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint }, + { MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, + { MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, + { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC, &options_cont }, + GNUNET_REST_HANDLER_END }; + + if (GNUNET_NO == + GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle)) { handle->response_code = err.error_code; GNUNET_SCHEDULER_add_now (&do_error, handle); } } + /** * If listing is enabled, prints information about the egos. * @@ -1984,63 +2214,81 @@ list_ego (void *cls, init_cont (handle); return; } - if (ID_REST_STATE_INIT == handle->state) { + GNUNET_assert (NULL != ego); + if (ID_REST_STATE_INIT == handle->state) + + { ego_entry = GNUNET_new (struct EgoEntry); GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = - GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); + ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); ego_entry->ego = ego; ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); + GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head, + handle->ego_tail, + ego_entry); return; } /* Ego renamed or added */ - if (identifier != NULL) { - for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) { - if (ego_entry->ego == ego) { + if (identifier != NULL) + { + for (ego_entry = handle->ego_head; NULL != ego_entry; + ego_entry = ego_entry->next) + { + if (ego_entry->ego == ego) + { /* Rename */ GNUNET_free (ego_entry->identifier); ego_entry->identifier = GNUNET_strdup (identifier); break; } } - if (NULL == ego_entry) { + if (NULL == ego_entry) + { /* Add */ ego_entry = GNUNET_new (struct EgoEntry); GNUNET_IDENTITY_ego_get_public_key (ego, &pk); - ego_entry->keystring = - GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); + ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk); ego_entry->ego = ego; ego_entry->identifier = GNUNET_strdup (identifier); - GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry); + GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head, + handle->ego_tail, + ego_entry); } - } else { + } + else + { /* Delete */ - for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) { - if (ego_entry->ego == ego) - break; + for (ego_entry = handle->ego_head; NULL != ego_entry; + ego_entry = ego_entry->next) + { + if (ego_entry->ego != ego) + continue; + GNUNET_CONTAINER_DLL_remove (handle->ego_head, + handle->ego_tail, + ego_entry); + GNUNET_free (ego_entry->identifier); + GNUNET_free (ego_entry->keystring); + GNUNET_free (ego_entry); + return; } - if (NULL != ego_entry) - GNUNET_CONTAINER_DLL_remove(handle->ego_head,handle->ego_tail, ego_entry); } - } + static void -rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, - GNUNET_REST_ResultProcessor proc, - void *proc_cls) +rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls) { struct RequestHandle *handle = GNUNET_new (struct RequestHandle); + handle->oidc = GNUNET_new (struct OIDC_Variables); - if ( NULL == OIDC_identity_login_time ) - OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); - if ( NULL == OIDC_identity_grants ) - OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); - if ( NULL == OIDC_ticket_once ) - OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); - if ( NULL == OIDC_interpret_access_token ) - OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); + if (NULL == OIDC_cookie_jar_map) + OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10, + GNUNET_NO); + if (NULL == OIDC_access_token_map) + OIDC_access_token_map = + GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); handle->response_code = 0; handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; handle->proc_cls = proc_cls; @@ -2049,29 +2297,24 @@ rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, handle->rest_handle = rest_handle; handle->url = GNUNET_strdup (rest_handle->url); - if (handle->url[strlen (handle->url)-1] == '/') - handle->url[strlen (handle->url)-1] = '\0'; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connecting...\n"); - handle->identity_handle = GNUNET_IDENTITY_connect (cfg, - &list_ego, - handle); + if (handle->url[strlen (handle->url) - 1] == '/') + handle->url[strlen (handle->url) - 1] = '\0'; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n"); + handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle); handle->gns_handle = GNUNET_GNS_connect (cfg); handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg); handle->timeout_task = - GNUNET_SCHEDULER_add_delayed (handle->timeout, - &do_timeout, - handle); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connected\n"); + GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n"); } + /** - * Entry point for the plugin. - * - * @param cls Config info - * @return NULL on error, otherwise the plugin context - */ + * Entry point for the plugin. + * + * @param cls Config info + * @return NULL on error, otherwise the plugin context + */ void * libgnunet_plugin_rest_openid_connect_init (void *cls) { @@ -2080,8 +2323,8 @@ libgnunet_plugin_rest_openid_connect_init (void *cls) cfg = cls; if (NULL != plugin.cfg) - return NULL; /* can only initialize once! */ - memset (&plugin, 0, sizeof (struct Plugin)); + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof(struct Plugin)); plugin.cfg = cfg; api = GNUNET_new (struct GNUNET_REST_Plugin); api->cls = &plugin; @@ -2096,65 +2339,50 @@ libgnunet_plugin_rest_openid_connect_init (void *cls) MHD_HTTP_METHOD_OPTIONS); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Identity Provider REST API initialized\n")); + _ ("OpenID Connect REST API initialized\n")); return api; } /** - * Exit point from the plugin. - * - * @param cls the plugin context (as returned by "init") - * @return always NULL - */ + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ void * libgnunet_plugin_rest_openid_connect_done (void *cls) { struct GNUNET_REST_Plugin *api = cls; struct Plugin *plugin = api->cls; + plugin->cfg = NULL; struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it; void *value = NULL; - hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create ( - OIDC_identity_login_time); + hashmap_it = + GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_cookie_jar_map); while (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) - { - if (NULL != value) - GNUNET_free(value); - } - GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time); - hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants); + GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, + value)) + GNUNET_free_non_null (value); + GNUNET_CONTAINER_multihashmap_iterator_destroy (hashmap_it); + GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map); + + hashmap_it = + GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_access_token_map); while (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) - { - if (NULL != value) - GNUNET_free(value); - } - GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants); - hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once); - while (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) - { - if (NULL != value) - GNUNET_free(value); - } - GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once); - hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token); - while (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) - { - if (NULL != value) - GNUNET_free(value); - } - GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token); - GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it); + GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, + value)) + GNUNET_free_non_null (value); + GNUNET_CONTAINER_multihashmap_destroy (OIDC_access_token_map); + GNUNET_CONTAINER_multihashmap_iterator_destroy (hashmap_it); GNUNET_free_non_null (allow_methods); GNUNET_free (api); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Identity Provider REST plugin is finished\n"); + "OpenID Connect REST plugin is finished\n"); return NULL; } -/* end of plugin_rest_identity_provider.c */ + +/* end of plugin_rest_openid_connect.c */