diff options
author | Martin Schanzenbach <schanzen@gnunet.org> | 2020-12-08 16:50:27 +0900 |
---|---|---|
committer | Martin Schanzenbach <schanzen@gnunet.org> | 2020-12-08 16:50:27 +0900 |
commit | 7ce054864a112f459a75ab542f844a8be0e6c47c (patch) | |
tree | 3b57538de1365180f540bf704d2909714a90d0c3 /src | |
parent | 61f7bf618b336c4d9349067ececdd7e5f051d67c (diff) | |
download | gnunet-7ce054864a112f459a75ab542f844a8be0e6c47c.tar.gz gnunet-7ce054864a112f459a75ab542f844a8be0e6c47c.zip |
RECLAIM: Return userinfo claims from cache
Diffstat (limited to 'src')
-rw-r--r-- | src/reclaim/oidc_helper.c | 78 | ||||
-rw-r--r-- | src/reclaim/oidc_helper.h | 38 | ||||
-rw-r--r-- | src/reclaim/plugin_rest_openid_connect.c | 151 |
3 files changed, 217 insertions, 50 deletions
diff --git a/src/reclaim/oidc_helper.c b/src/reclaim/oidc_helper.c index c6d56e02d..1dde7b673 100644 --- a/src/reclaim/oidc_helper.c +++ b/src/reclaim/oidc_helper.c | |||
@@ -567,6 +567,48 @@ OIDC_build_authz_code (const struct GNUNET_IDENTITY_PrivateKey *issuer, | |||
567 | } | 567 | } |
568 | 568 | ||
569 | 569 | ||
570 | enum GNUNET_GenericReturnValue | ||
571 | check_code_challenge (const char *code_challenge, | ||
572 | uint32_t code_challenge_len, | ||
573 | const char *code_verifier) | ||
574 | { | ||
575 | char *code_verifier_hash; | ||
576 | char *expected_code_challenge; | ||
577 | |||
578 | if (0 == code_challenge_len) /* Only check if this code requires a CV */ | ||
579 | return GNUNET_OK; | ||
580 | if (NULL == code_verifier) | ||
581 | { | ||
582 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
583 | "Expected code verifier!\n"); | ||
584 | return GNUNET_SYSERR; | ||
585 | } | ||
586 | code_verifier_hash = GNUNET_malloc (256 / 8); | ||
587 | // hash code verifier | ||
588 | gcry_md_hash_buffer (GCRY_MD_SHA256, | ||
589 | code_verifier_hash, | ||
590 | code_verifier, | ||
591 | strlen (code_verifier)); | ||
592 | // encode code verifier | ||
593 | GNUNET_STRINGS_base64url_encode (code_verifier_hash, 256 / 8, | ||
594 | &expected_code_challenge); | ||
595 | GNUNET_free (code_verifier_hash); | ||
596 | if (0 != | ||
597 | strncmp (expected_code_challenge, code_challenge, code_challenge_len)) | ||
598 | { | ||
599 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
600 | "Invalid code verifier! Expected: %s, Got: %.*s\n", | ||
601 | expected_code_challenge, | ||
602 | code_challenge_len, | ||
603 | code_challenge); | ||
604 | GNUNET_free (expected_code_challenge); | ||
605 | return GNUNET_SYSERR; | ||
606 | } | ||
607 | GNUNET_free (expected_code_challenge); | ||
608 | return GNUNET_OK; | ||
609 | } | ||
610 | |||
611 | |||
570 | /** | 612 | /** |
571 | * Parse reclaim ticket and nonce from | 613 | * Parse reclaim ticket and nonce from |
572 | * authorization code. | 614 | * authorization code. |
@@ -589,16 +631,15 @@ OIDC_parse_authz_code (const struct GNUNET_IDENTITY_PublicKey *audience, | |||
589 | struct GNUNET_RECLAIM_Ticket *ticket, | 631 | struct GNUNET_RECLAIM_Ticket *ticket, |
590 | struct GNUNET_RECLAIM_AttributeList **attrs, | 632 | struct GNUNET_RECLAIM_AttributeList **attrs, |
591 | struct GNUNET_RECLAIM_PresentationList **presentations, | 633 | struct GNUNET_RECLAIM_PresentationList **presentations, |
592 | char **nonce_str) | 634 | char **nonce_str, |
635 | enum OIDC_VerificationOptions opts) | ||
593 | { | 636 | { |
594 | char *code_payload; | 637 | char *code_payload; |
595 | char *ptr; | 638 | char *ptr; |
596 | char *plaintext; | 639 | char *plaintext; |
597 | char *attrs_ser; | 640 | char *attrs_ser; |
598 | char *presentations_ser; | 641 | char *presentations_ser; |
599 | char *expected_code_challenge; | ||
600 | char *code_challenge; | 642 | char *code_challenge; |
601 | char *code_verifier_hash; | ||
602 | struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; | 643 | struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; |
603 | struct GNUNET_IDENTITY_Signature *signature; | 644 | struct GNUNET_IDENTITY_Signature *signature; |
604 | uint32_t code_challenge_len; | 645 | uint32_t code_challenge_len; |
@@ -636,38 +677,15 @@ OIDC_parse_authz_code (const struct GNUNET_IDENTITY_PublicKey *audience, | |||
636 | // cmp code_challenge code_verifier | 677 | // cmp code_challenge code_verifier |
637 | code_challenge_len = ntohl (params->code_challenge_len); | 678 | code_challenge_len = ntohl (params->code_challenge_len); |
638 | code_challenge = ((char *) ¶ms[1]); | 679 | code_challenge = ((char *) ¶ms[1]); |
639 | if (0 != code_challenge_len) /* Only check if this code requires a CV */ | 680 | if (!(opts & OIDC_VERIFICATION_NO_CODE_VERIFIER)) |
640 | { | 681 | { |
641 | if (NULL == code_verifier) | 682 | if (GNUNET_OK != check_code_challenge (code_challenge, |
642 | { | 683 | code_challenge_len, |
643 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 684 | code_verifier)) |
644 | "Expected code verifier!\n"); | ||
645 | GNUNET_free (code_payload); | ||
646 | return GNUNET_SYSERR; | ||
647 | } | ||
648 | code_verifier_hash = GNUNET_malloc (256 / 8); | ||
649 | // hash code verifier | ||
650 | gcry_md_hash_buffer (GCRY_MD_SHA256, | ||
651 | code_verifier_hash, | ||
652 | code_verifier, | ||
653 | strlen (code_verifier)); | ||
654 | // encode code verifier | ||
655 | GNUNET_STRINGS_base64url_encode (code_verifier_hash, 256 / 8, | ||
656 | &expected_code_challenge); | ||
657 | GNUNET_free (code_verifier_hash); | ||
658 | if (0 != | ||
659 | strncmp (expected_code_challenge, code_challenge, code_challenge_len)) | ||
660 | { | 685 | { |
661 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
662 | "Invalid code verifier! Expected: %s, Got: %.*s\n", | ||
663 | expected_code_challenge, | ||
664 | code_challenge_len, | ||
665 | code_challenge); | ||
666 | GNUNET_free (code_payload); | 686 | GNUNET_free (code_payload); |
667 | GNUNET_free (expected_code_challenge); | ||
668 | return GNUNET_SYSERR; | 687 | return GNUNET_SYSERR; |
669 | } | 688 | } |
670 | GNUNET_free (expected_code_challenge); | ||
671 | } | 689 | } |
672 | nonce_len = ntohl (params->nonce_len); | 690 | nonce_len = ntohl (params->nonce_len); |
673 | if (0 != nonce_len) | 691 | if (0 != nonce_len) |
diff --git a/src/reclaim/oidc_helper.h b/src/reclaim/oidc_helper.h index eb1022423..2a8b7bbae 100644 --- a/src/reclaim/oidc_helper.h +++ b/src/reclaim/oidc_helper.h | |||
@@ -38,6 +38,19 @@ | |||
38 | 38 | ||
39 | #define SERVER_ADDRESS "https://api.reclaim" | 39 | #define SERVER_ADDRESS "https://api.reclaim" |
40 | 40 | ||
41 | enum OIDC_VerificationOptions | ||
42 | { | ||
43 | /** | ||
44 | * Strict verification | ||
45 | */ | ||
46 | OIDC_VERIFICATION_DEFAULT = 0, | ||
47 | |||
48 | /** | ||
49 | * Do not check code verifier even if expected | ||
50 | */ | ||
51 | OIDC_VERIFICATION_NO_CODE_VERIFIER = 1 | ||
52 | }; | ||
53 | |||
41 | /** | 54 | /** |
42 | * Create a JWT from attributes | 55 | * Create a JWT from attributes |
43 | * | 56 | * |
@@ -51,12 +64,13 @@ | |||
51 | */ | 64 | */ |
52 | char* | 65 | char* |
53 | OIDC_generate_id_token (const struct GNUNET_IDENTITY_PublicKey *aud_key, | 66 | OIDC_generate_id_token (const struct GNUNET_IDENTITY_PublicKey *aud_key, |
54 | const struct GNUNET_IDENTITY_PublicKey *sub_key, | 67 | const struct GNUNET_IDENTITY_PublicKey *sub_key, |
55 | const struct GNUNET_RECLAIM_AttributeList *attrs, | 68 | const struct GNUNET_RECLAIM_AttributeList *attrs, |
56 | const struct GNUNET_RECLAIM_PresentationList *presentations, | 69 | const struct |
57 | const struct GNUNET_TIME_Relative *expiration_time, | 70 | GNUNET_RECLAIM_PresentationList *presentations, |
58 | const char *nonce, | 71 | const struct GNUNET_TIME_Relative *expiration_time, |
59 | const char *secret_key); | 72 | const char *nonce, |
73 | const char *secret_key); | ||
60 | 74 | ||
61 | /** | 75 | /** |
62 | * Builds an OIDC authorization code including | 76 | * Builds an OIDC authorization code including |
@@ -68,13 +82,15 @@ OIDC_generate_id_token (const struct GNUNET_IDENTITY_PublicKey *aud_key, | |||
68 | * @param presentations credential presentation list | 82 | * @param presentations credential presentation list |
69 | * @param nonce the nonce to include in the code | 83 | * @param nonce the nonce to include in the code |
70 | * @param code_challenge PKCE code challenge | 84 | * @param code_challenge PKCE code challenge |
85 | * @param opts verification options | ||
71 | * @return a new authorization code (caller must free) | 86 | * @return a new authorization code (caller must free) |
72 | */ | 87 | */ |
73 | char* | 88 | char* |
74 | OIDC_build_authz_code (const struct GNUNET_IDENTITY_PrivateKey *issuer, | 89 | OIDC_build_authz_code (const struct GNUNET_IDENTITY_PrivateKey *issuer, |
75 | const struct GNUNET_RECLAIM_Ticket *ticket, | 90 | const struct GNUNET_RECLAIM_Ticket *ticket, |
76 | const struct GNUNET_RECLAIM_AttributeList *attrs, | 91 | const struct GNUNET_RECLAIM_AttributeList *attrs, |
77 | const struct GNUNET_RECLAIM_PresentationList *presentations, | 92 | const struct |
93 | GNUNET_RECLAIM_PresentationList *presentations, | ||
78 | const char *nonce, | 94 | const char *nonce, |
79 | const char *code_challenge); | 95 | const char *code_challenge); |
80 | 96 | ||
@@ -99,7 +115,8 @@ OIDC_parse_authz_code (const struct GNUNET_IDENTITY_PublicKey *ecdsa_pub, | |||
99 | struct GNUNET_RECLAIM_Ticket *ticket, | 115 | struct GNUNET_RECLAIM_Ticket *ticket, |
100 | struct GNUNET_RECLAIM_AttributeList **attrs, | 116 | struct GNUNET_RECLAIM_AttributeList **attrs, |
101 | struct GNUNET_RECLAIM_PresentationList **presentations, | 117 | struct GNUNET_RECLAIM_PresentationList **presentations, |
102 | char **nonce); | 118 | char **nonce, |
119 | enum OIDC_VerificationOptions opts); | ||
103 | 120 | ||
104 | /** | 121 | /** |
105 | * Build a token response for a token request | 122 | * Build a token response for a token request |
@@ -126,7 +143,7 @@ OIDC_access_token_new (const struct GNUNET_RECLAIM_Ticket *ticket); | |||
126 | * Parse an access token | 143 | * Parse an access token |
127 | */ | 144 | */ |
128 | int | 145 | int |
129 | OIDC_access_token_parse (const char* token, | 146 | OIDC_access_token_parse (const char*token, |
130 | struct GNUNET_RECLAIM_Ticket **ticket); | 147 | struct GNUNET_RECLAIM_Ticket **ticket); |
131 | 148 | ||
132 | 149 | ||
@@ -154,6 +171,7 @@ OIDC_check_scopes_for_claim_request (const char *scopes, | |||
154 | char * | 171 | char * |
155 | OIDC_generate_userinfo (const struct GNUNET_IDENTITY_PublicKey *sub_key, | 172 | OIDC_generate_userinfo (const struct GNUNET_IDENTITY_PublicKey *sub_key, |
156 | const struct GNUNET_RECLAIM_AttributeList *attrs, | 173 | const struct GNUNET_RECLAIM_AttributeList *attrs, |
157 | const struct GNUNET_RECLAIM_PresentationList *presentations); | 174 | const struct |
175 | GNUNET_RECLAIM_PresentationList *presentations); | ||
158 | 176 | ||
159 | #endif | 177 | #endif |
diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c index 7a8a886bd..8d21a5c99 100644 --- a/src/reclaim/plugin_rest_openid_connect.c +++ b/src/reclaim/plugin_rest_openid_connect.c | |||
@@ -227,6 +227,11 @@ | |||
227 | */ | 227 | */ |
228 | #define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied" | 228 | #define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied" |
229 | 229 | ||
230 | /** | ||
231 | * How long to wait for a consume in userinfo endpoint | ||
232 | */ | ||
233 | #define CONSUME_TIMEOUT GNUNET_TIME_relative_multiply ( \ | ||
234 | GNUNET_TIME_UNIT_SECONDS,2) | ||
230 | 235 | ||
231 | /** | 236 | /** |
232 | * OIDC ignored parameter array | 237 | * OIDC ignored parameter array |
@@ -240,7 +245,12 @@ static char *OIDC_ignored_parameter_array[] = { "display", | |||
240 | "acr_values" }; | 245 | "acr_values" }; |
241 | 246 | ||
242 | /** | 247 | /** |
243 | * OIDC Hash map that keeps track of issued cookies | 248 | * OIDC hashmap for cached access tokens and codes |
249 | */ | ||
250 | struct GNUNET_CONTAINER_MultiHashMap *oidc_code_cache; | ||
251 | |||
252 | /** | ||
253 | * OIDC hashmap that keeps track of issued cookies | ||
244 | */ | 254 | */ |
245 | struct GNUNET_CONTAINER_MultiHashMap *OIDC_cookie_jar_map; | 255 | struct GNUNET_CONTAINER_MultiHashMap *OIDC_cookie_jar_map; |
246 | 256 | ||
@@ -460,6 +470,11 @@ struct RequestHandle | |||
460 | struct GNUNET_RECLAIM_Operation *idp_op; | 470 | struct GNUNET_RECLAIM_Operation *idp_op; |
461 | 471 | ||
462 | /** | 472 | /** |
473 | * Timeout task for consume | ||
474 | */ | ||
475 | struct GNUNET_SCHEDULER_Task *consume_timeout_op; | ||
476 | |||
477 | /** | ||
463 | * Attribute iterator | 478 | * Attribute iterator |
464 | */ | 479 | */ |
465 | struct GNUNET_RECLAIM_AttributeIterator *attr_it; | 480 | struct GNUNET_RECLAIM_AttributeIterator *attr_it; |
@@ -506,6 +521,11 @@ struct RequestHandle | |||
506 | char *url; | 521 | char *url; |
507 | 522 | ||
508 | /** | 523 | /** |
524 | * The passed access token | ||
525 | */ | ||
526 | char *access_token; | ||
527 | |||
528 | /** | ||
509 | * The tld for redirect | 529 | * The tld for redirect |
510 | */ | 530 | */ |
511 | char *tld; | 531 | char *tld; |
@@ -571,6 +591,8 @@ cleanup_handle (struct RequestHandle *handle) | |||
571 | GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); | 591 | GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); |
572 | if (NULL != handle->idp_op) | 592 | if (NULL != handle->idp_op) |
573 | GNUNET_RECLAIM_cancel (handle->idp_op); | 593 | GNUNET_RECLAIM_cancel (handle->idp_op); |
594 | if (NULL != handle->consume_timeout_op) | ||
595 | GNUNET_SCHEDULER_cancel (handle->consume_timeout_op); | ||
574 | GNUNET_free (handle->url); | 596 | GNUNET_free (handle->url); |
575 | GNUNET_free (handle->tld); | 597 | GNUNET_free (handle->tld); |
576 | GNUNET_free (handle->redirect_prefix); | 598 | GNUNET_free (handle->redirect_prefix); |
@@ -601,6 +623,8 @@ cleanup_handle (struct RequestHandle *handle) | |||
601 | GNUNET_CONTAINER_DLL_remove (requests_head, | 623 | GNUNET_CONTAINER_DLL_remove (requests_head, |
602 | requests_tail, | 624 | requests_tail, |
603 | handle); | 625 | handle); |
626 | if (NULL != handle->access_token) | ||
627 | GNUNET_free (handle->access_token); | ||
604 | GNUNET_free (handle); | 628 | GNUNET_free (handle); |
605 | } | 629 | } |
606 | 630 | ||
@@ -1282,8 +1306,8 @@ code_redirect (void *cls) | |||
1282 | { | 1306 | { |
1283 | if (GNUNET_OK != | 1307 | if (GNUNET_OK != |
1284 | GNUNET_IDENTITY_public_key_from_string (handle->oidc | 1308 | GNUNET_IDENTITY_public_key_from_string (handle->oidc |
1285 | ->login_identity, | 1309 | ->login_identity, |
1286 | &pubkey)) | 1310 | &pubkey)) |
1287 | { | 1311 | { |
1288 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_COOKIE); | 1312 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_COOKIE); |
1289 | handle->edesc = | 1313 | handle->edesc = |
@@ -1662,7 +1686,7 @@ authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
1662 | 1686 | ||
1663 | if (GNUNET_OK != | 1687 | if (GNUNET_OK != |
1664 | GNUNET_IDENTITY_public_key_from_string (handle->oidc->client_id, | 1688 | GNUNET_IDENTITY_public_key_from_string (handle->oidc->client_id, |
1665 | &handle->oidc->client_pkey)) | 1689 | &handle->oidc->client_pkey)) |
1666 | { | 1690 | { |
1667 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT); | 1691 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT); |
1668 | handle->edesc = GNUNET_strdup ("The client is not authorized to request an " | 1692 | handle->edesc = GNUNET_strdup ("The client is not authorized to request an " |
@@ -2071,7 +2095,8 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
2071 | 2095 | ||
2072 | // decode code | 2096 | // decode code |
2073 | if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, code_verifier, &ticket, | 2097 | if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, code_verifier, &ticket, |
2074 | &cl, &pl, &nonce)) | 2098 | &cl, &pl, &nonce, |
2099 | OIDC_VERIFICATION_DEFAULT)) | ||
2075 | { | 2100 | { |
2076 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); | 2101 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); |
2077 | handle->edesc = GNUNET_strdup ("invalid code"); | 2102 | handle->edesc = GNUNET_strdup ("invalid code"); |
@@ -2080,7 +2105,6 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
2080 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 2105 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
2081 | return; | 2106 | return; |
2082 | } | 2107 | } |
2083 | GNUNET_free (code); | ||
2084 | 2108 | ||
2085 | // create jwt | 2109 | // create jwt |
2086 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, | 2110 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, |
@@ -2091,6 +2115,7 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
2091 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); | 2115 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); |
2092 | handle->edesc = GNUNET_strdup ("gnunet configuration failed"); | 2116 | handle->edesc = GNUNET_strdup ("gnunet configuration failed"); |
2093 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; | 2117 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; |
2118 | GNUNET_free (code); | ||
2094 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 2119 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
2095 | return; | 2120 | return; |
2096 | } | 2121 | } |
@@ -2105,6 +2130,7 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
2105 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); | 2130 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); |
2106 | handle->edesc = GNUNET_strdup ("No signing secret configured!"); | 2131 | handle->edesc = GNUNET_strdup ("No signing secret configured!"); |
2107 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; | 2132 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; |
2133 | GNUNET_free (code); | ||
2108 | GNUNET_SCHEDULER_add_now (&do_error, handle); | 2134 | GNUNET_SCHEDULER_add_now (&do_error, handle); |
2109 | return; | 2135 | return; |
2110 | } | 2136 | } |
@@ -2116,6 +2142,26 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
2116 | (NULL != nonce) ? nonce : NULL, | 2142 | (NULL != nonce) ? nonce : NULL, |
2117 | jwt_secret); | 2143 | jwt_secret); |
2118 | access_token = OIDC_access_token_new (&ticket); | 2144 | access_token = OIDC_access_token_new (&ticket); |
2145 | /* Store mapping from access token to code so we can later | ||
2146 | * fall back on the provided attributes in userinfo | ||
2147 | */ | ||
2148 | GNUNET_CRYPTO_hash (access_token, | ||
2149 | strlen (access_token), | ||
2150 | &cache_key); | ||
2151 | char *tmp_at = GNUNET_CONTAINER_multihashmap_get (oidc_code_cache, | ||
2152 | &cache_key); | ||
2153 | GNUNET_CONTAINER_multihashmap_put (oidc_code_cache, | ||
2154 | &cache_key, | ||
2155 | code, | ||
2156 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); | ||
2157 | /* If there was a previus code in there, free the old value */ | ||
2158 | if (NULL != tmp_at) | ||
2159 | { | ||
2160 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2161 | "OIDC access token already issued. Cleanup.\n"); | ||
2162 | GNUNET_free (tmp_at); | ||
2163 | } | ||
2164 | |||
2119 | OIDC_build_token_response (access_token, | 2165 | OIDC_build_token_response (access_token, |
2120 | id_token, | 2166 | id_token, |
2121 | &expiration_time, | 2167 | &expiration_time, |
@@ -2149,6 +2195,10 @@ consume_ticket (void *cls, | |||
2149 | struct GNUNET_RECLAIM_PresentationListEntry *atle; | 2195 | struct GNUNET_RECLAIM_PresentationListEntry *atle; |
2150 | struct MHD_Response *resp; | 2196 | struct MHD_Response *resp; |
2151 | char *result_str; | 2197 | char *result_str; |
2198 | |||
2199 | if (NULL != handle->consume_timeout_op) | ||
2200 | GNUNET_SCHEDULER_cancel (handle->consume_timeout_op); | ||
2201 | handle->consume_timeout_op = NULL; | ||
2152 | handle->idp_op = NULL; | 2202 | handle->idp_op = NULL; |
2153 | 2203 | ||
2154 | if (NULL == identity) | 2204 | if (NULL == identity) |
@@ -2180,8 +2230,9 @@ consume_ticket (void *cls, | |||
2180 | for (atle = handle->presentations->list_head; | 2230 | for (atle = handle->presentations->list_head; |
2181 | NULL != atle; atle = atle->next) | 2231 | NULL != atle; atle = atle->next) |
2182 | { | 2232 | { |
2183 | if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&atle->presentation->credential_id, | 2233 | if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal ( |
2184 | &pres->credential_id)) | 2234 | &atle->presentation->credential_id, |
2235 | &pres->credential_id)) | ||
2185 | continue; | 2236 | continue; |
2186 | break; /** already in list **/ | 2237 | break; /** already in list **/ |
2187 | } | 2238 | } |
@@ -2190,8 +2241,8 @@ consume_ticket (void *cls, | |||
2190 | /** Credential matches for attribute, add **/ | 2241 | /** Credential matches for attribute, add **/ |
2191 | atle = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry); | 2242 | atle = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry); |
2192 | atle->presentation = GNUNET_RECLAIM_presentation_new (pres->type, | 2243 | atle->presentation = GNUNET_RECLAIM_presentation_new (pres->type, |
2193 | pres->data, | 2244 | pres->data, |
2194 | pres->data_size); | 2245 | pres->data_size); |
2195 | GNUNET_CONTAINER_DLL_insert (handle->presentations->list_head, | 2246 | GNUNET_CONTAINER_DLL_insert (handle->presentations->list_head, |
2196 | handle->presentations->list_tail, | 2247 | handle->presentations->list_tail, |
2197 | atle); | 2248 | atle); |
@@ -2199,6 +2250,69 @@ consume_ticket (void *cls, | |||
2199 | } | 2250 | } |
2200 | 2251 | ||
2201 | 2252 | ||
2253 | static void | ||
2254 | consume_timeout (void*cls) | ||
2255 | { | ||
2256 | struct RequestHandle *handle = cls; | ||
2257 | struct GNUNET_HashCode cache_key; | ||
2258 | struct GNUNET_RECLAIM_AttributeList *cl = NULL; | ||
2259 | struct GNUNET_RECLAIM_PresentationList *pl = NULL; | ||
2260 | struct GNUNET_RECLAIM_Ticket ticket; | ||
2261 | char *nonce; | ||
2262 | char *cached_code; | ||
2263 | |||
2264 | handle->consume_timeout_op = NULL; | ||
2265 | if (NULL != handle->idp_op) | ||
2266 | GNUNET_RECLAIM_cancel (handle->idp_op); | ||
2267 | handle->idp_op = NULL; | ||
2268 | |||
2269 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2270 | "Ticket consumptioned timed out. Using cache...\n"); | ||
2271 | GNUNET_CRYPTO_hash (handle->access_token, | ||
2272 | strlen (handle->access_token), | ||
2273 | &cache_key); | ||
2274 | cached_code = GNUNET_CONTAINER_multihashmap_get (oidc_code_cache, | ||
2275 | &cache_key); | ||
2276 | if (NULL == cached_code) | ||
2277 | { | ||
2278 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); | ||
2279 | handle->edesc = GNUNET_strdup ("No Access Token in cache!"); | ||
2280 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2281 | GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); | ||
2282 | return; | ||
2283 | } | ||
2284 | |||
2285 | // decode code | ||
2286 | if (GNUNET_OK != OIDC_parse_authz_code (&handle->ticket.audience, | ||
2287 | cached_code, NULL, &ticket, | ||
2288 | &cl, &pl, &nonce, | ||
2289 | OIDC_VERIFICATION_NO_CODE_VERIFIER)) | ||
2290 | { | ||
2291 | handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); | ||
2292 | handle->edesc = GNUNET_strdup ("invalid code"); | ||
2293 | handle->response_code = MHD_HTTP_BAD_REQUEST; | ||
2294 | GNUNET_free (cached_code); | ||
2295 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2296 | return; | ||
2297 | } | ||
2298 | |||
2299 | struct MHD_Response *resp; | ||
2300 | char *result_str; | ||
2301 | |||
2302 | result_str = OIDC_generate_userinfo (&handle->ticket.identity, | ||
2303 | cl, | ||
2304 | pl); | ||
2305 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Userinfo: %s\n", result_str); | ||
2306 | resp = GNUNET_REST_create_response (result_str); | ||
2307 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | ||
2308 | GNUNET_free (result_str); | ||
2309 | GNUNET_free (nonce); | ||
2310 | GNUNET_RECLAIM_attribute_list_destroy (cl); | ||
2311 | GNUNET_RECLAIM_presentation_list_destroy (pl); | ||
2312 | cleanup_handle (handle); | ||
2313 | } | ||
2314 | |||
2315 | |||
2202 | /** | 2316 | /** |
2203 | * Responds to userinfo GET and url-encoded POST request | 2317 | * Responds to userinfo GET and url-encoded POST request |
2204 | * | 2318 | * |
@@ -2295,6 +2409,11 @@ userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | |||
2295 | handle->presentations = | 2409 | handle->presentations = |
2296 | GNUNET_new (struct GNUNET_RECLAIM_PresentationList); | 2410 | GNUNET_new (struct GNUNET_RECLAIM_PresentationList); |
2297 | 2411 | ||
2412 | /* If the consume takes too long, we use values from the cache */ | ||
2413 | handle->access_token = GNUNET_strdup (authorization_access_token); | ||
2414 | handle->consume_timeout_op = GNUNET_SCHEDULER_add_delayed (CONSUME_TIMEOUT, | ||
2415 | &consume_timeout, | ||
2416 | handle); | ||
2298 | handle->idp_op = GNUNET_RECLAIM_ticket_consume (idp, | 2417 | handle->idp_op = GNUNET_RECLAIM_ticket_consume (idp, |
2299 | privkey, | 2418 | privkey, |
2300 | &handle->ticket, | 2419 | &handle->ticket, |
@@ -2554,6 +2673,10 @@ rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle, | |||
2554 | if (NULL == OIDC_cookie_jar_map) | 2673 | if (NULL == OIDC_cookie_jar_map) |
2555 | OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10, | 2674 | OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10, |
2556 | GNUNET_NO); | 2675 | GNUNET_NO); |
2676 | if (NULL == oidc_code_cache) | ||
2677 | oidc_code_cache = GNUNET_CONTAINER_multihashmap_create (10, | ||
2678 | GNUNET_NO); | ||
2679 | |||
2557 | handle->response_code = 0; | 2680 | handle->response_code = 0; |
2558 | handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; | 2681 | handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; |
2559 | handle->proc_cls = proc_cls; | 2682 | handle->proc_cls = proc_cls; |
@@ -2646,6 +2769,14 @@ libgnunet_plugin_rest_openid_connect_done (void *cls) | |||
2646 | NULL); | 2769 | NULL); |
2647 | GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map); | 2770 | GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map); |
2648 | } | 2771 | } |
2772 | if (NULL != oidc_code_cache) | ||
2773 | { | ||
2774 | GNUNET_CONTAINER_multihashmap_iterate (oidc_code_cache, | ||
2775 | &cleanup_hashmap, | ||
2776 | NULL); | ||
2777 | GNUNET_CONTAINER_multihashmap_destroy (oidc_code_cache); | ||
2778 | } | ||
2779 | |||
2649 | GNUNET_free (allow_methods); | 2780 | GNUNET_free (allow_methods); |
2650 | if (NULL != gns_handle) | 2781 | if (NULL != gns_handle) |
2651 | GNUNET_GNS_disconnect (gns_handle); | 2782 | GNUNET_GNS_disconnect (gns_handle); |