diff options
Diffstat (limited to 'src/identity-provider/plugin_rest_identity_provider.c')
-rw-r--r-- | src/identity-provider/plugin_rest_identity_provider.c | 1593 |
1 files changed, 2 insertions, 1591 deletions
diff --git a/src/identity-provider/plugin_rest_identity_provider.c b/src/identity-provider/plugin_rest_identity_provider.c index 7b4ebf2fc..398d09cd2 100644 --- a/src/identity-provider/plugin_rest_identity_provider.c +++ b/src/identity-provider/plugin_rest_identity_provider.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #include "gnunet_signatures.h" | 40 | #include "gnunet_signatures.h" |
41 | #include "gnunet_identity_attribute_lib.h" | 41 | #include "gnunet_identity_attribute_lib.h" |
42 | #include "gnunet_identity_provider_service.h" | 42 | #include "gnunet_identity_provider_service.h" |
43 | #include "jwt.h" | ||
44 | 43 | ||
45 | /** | 44 | /** |
46 | * REST root namespace | 45 | * REST root namespace |
@@ -68,26 +67,6 @@ | |||
68 | #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume" | 67 | #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume" |
69 | 68 | ||
70 | /** | 69 | /** |
71 | * Authorize endpoint | ||
72 | */ | ||
73 | #define GNUNET_REST_API_NS_AUTHORIZE "/idp/authorize" | ||
74 | |||
75 | /** | ||
76 | * Token endpoint | ||
77 | */ | ||
78 | #define GNUNET_REST_API_NS_TOKEN "/idp/token" | ||
79 | |||
80 | /** | ||
81 | * UserInfo endpoint | ||
82 | */ | ||
83 | #define GNUNET_REST_API_NS_USERINFO "/idp/userinfo" | ||
84 | |||
85 | /** | ||
86 | * Login namespace | ||
87 | */ | ||
88 | #define GNUNET_REST_API_NS_LOGIN "/idp/login" | ||
89 | |||
90 | /** | ||
91 | * Attribute key | 70 | * Attribute key |
92 | */ | 71 | */ |
93 | #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute" | 72 | #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute" |
@@ -114,111 +93,6 @@ | |||
114 | #define ID_REST_STATE_POST_INIT 1 | 93 | #define ID_REST_STATE_POST_INIT 1 |
115 | 94 | ||
116 | /** | 95 | /** |
117 | * OIDC grant_type key | ||
118 | */ | ||
119 | #define OIDC_GRANT_TYPE_KEY "grant_type" | ||
120 | |||
121 | /** | ||
122 | * OIDC grant_type key | ||
123 | */ | ||
124 | #define OIDC_GRANT_TYPE_VALUE "authorization_code" | ||
125 | |||
126 | /** | ||
127 | * OIDC code key | ||
128 | */ | ||
129 | #define OIDC_CODE_KEY "code" | ||
130 | |||
131 | /** | ||
132 | * OIDC response_type key | ||
133 | */ | ||
134 | #define OIDC_RESPONSE_TYPE_KEY "response_type" | ||
135 | |||
136 | /** | ||
137 | * OIDC client_id key | ||
138 | */ | ||
139 | #define OIDC_CLIENT_ID_KEY "client_id" | ||
140 | |||
141 | /** | ||
142 | * OIDC scope key | ||
143 | */ | ||
144 | #define OIDC_SCOPE_KEY "scope" | ||
145 | |||
146 | /** | ||
147 | * OIDC redirect_uri key | ||
148 | */ | ||
149 | #define OIDC_REDIRECT_URI_KEY "redirect_uri" | ||
150 | |||
151 | /** | ||
152 | * OIDC state key | ||
153 | */ | ||
154 | #define OIDC_STATE_KEY "state" | ||
155 | |||
156 | /** | ||
157 | * OIDC nonce key | ||
158 | */ | ||
159 | #define OIDC_NONCE_KEY "nonce" | ||
160 | |||
161 | /** | ||
162 | * OIDC cookie header key | ||
163 | */ | ||
164 | #define OIDC_COOKIE_HEADER_KEY "Cookie" | ||
165 | |||
166 | /** | ||
167 | * OIDC cookie header information key | ||
168 | */ | ||
169 | #define OIDC_AUTHORIZATION_HEADER_KEY "Authorization" | ||
170 | |||
171 | /** | ||
172 | * OIDC cookie header information key | ||
173 | */ | ||
174 | #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity=" | ||
175 | |||
176 | /** | ||
177 | * OIDC expected response_type while authorizing | ||
178 | */ | ||
179 | #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code" | ||
180 | |||
181 | /** | ||
182 | * OIDC expected scope part while authorizing | ||
183 | */ | ||
184 | #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid" | ||
185 | |||
186 | /** | ||
187 | * OIDC ignored parameter array | ||
188 | */ | ||
189 | char* OIDC_ignored_parameter_array [] = | ||
190 | { | ||
191 | "display", | ||
192 | "prompt", | ||
193 | "max_age", | ||
194 | "ui_locales", | ||
195 | "response_mode", | ||
196 | "id_token_hint", | ||
197 | "login_hint", | ||
198 | "acr_values" | ||
199 | }; | ||
200 | |||
201 | /** | ||
202 | * OIDC authorized identities and times hashmap | ||
203 | */ | ||
204 | struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time; | ||
205 | |||
206 | /** | ||
207 | * OIDC authorized identities and times hashmap | ||
208 | */ | ||
209 | struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants; | ||
210 | |||
211 | /** | ||
212 | * OIDC ticket/code use only once | ||
213 | */ | ||
214 | struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once; | ||
215 | |||
216 | /** | ||
217 | * OIDC access_token to ticket and ego | ||
218 | */ | ||
219 | struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token; | ||
220 | |||
221 | /** | ||
222 | * The configuration handle | 96 | * The configuration handle |
223 | */ | 97 | */ |
224 | const struct GNUNET_CONFIGURATION_Handle *cfg; | 98 | const struct GNUNET_CONFIGURATION_Handle *cfg; |
@@ -237,34 +111,6 @@ struct Plugin | |||
237 | }; | 111 | }; |
238 | 112 | ||
239 | /** | 113 | /** |
240 | * OIDC needed variables | ||
241 | */ | ||
242 | struct OIDC_Variables | ||
243 | { | ||
244 | |||
245 | struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey; | ||
246 | |||
247 | char *client_id; | ||
248 | |||
249 | int is_client_trusted; | ||
250 | |||
251 | char *redirect_uri; | ||
252 | |||
253 | char *scope; | ||
254 | |||
255 | char *state; | ||
256 | |||
257 | char *nonce; | ||
258 | |||
259 | char *response_type; | ||
260 | |||
261 | char *login_identity; | ||
262 | |||
263 | json_t *response; | ||
264 | |||
265 | }; | ||
266 | |||
267 | /** | ||
268 | * The ego list | 114 | * The ego list |
269 | */ | 115 | */ |
270 | struct EgoEntry | 116 | struct EgoEntry |
@@ -319,11 +165,6 @@ struct RequestHandle | |||
319 | struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; | 165 | struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; |
320 | 166 | ||
321 | /** | 167 | /** |
322 | * OIDC variables | ||
323 | */ | ||
324 | struct OIDC_Variables *oidc; | ||
325 | |||
326 | /** | ||
327 | * The processing state | 168 | * The processing state |
328 | */ | 169 | */ |
329 | int state; | 170 | int state; |
@@ -409,21 +250,11 @@ struct RequestHandle | |||
409 | char *url; | 250 | char *url; |
410 | 251 | ||
411 | /** | 252 | /** |
412 | * The tld for redirect | ||
413 | */ | ||
414 | char *tld; | ||
415 | |||
416 | /** | ||
417 | * Error response message | 253 | * Error response message |
418 | */ | 254 | */ |
419 | char *emsg; | 255 | char *emsg; |
420 | 256 | ||
421 | /** | 257 | /** |
422 | * Error response description | ||
423 | */ | ||
424 | char *edesc; | ||
425 | |||
426 | /** | ||
427 | * Reponse code | 258 | * Reponse code |
428 | */ | 259 | */ |
429 | int response_code; | 260 | int response_code; |
@@ -462,34 +293,10 @@ cleanup_handle (struct RequestHandle *handle) | |||
462 | GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp); | 293 | GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp); |
463 | if (NULL != handle->url) | 294 | if (NULL != handle->url) |
464 | GNUNET_free (handle->url); | 295 | GNUNET_free (handle->url); |
465 | if (NULL != handle->tld) | ||
466 | GNUNET_free (handle->tld); | ||
467 | if (NULL != handle->emsg) | 296 | if (NULL != handle->emsg) |
468 | GNUNET_free (handle->emsg); | 297 | GNUNET_free (handle->emsg); |
469 | if (NULL != handle->edesc) | ||
470 | GNUNET_free (handle->edesc); | ||
471 | if (NULL != handle->namestore_handle) | 298 | if (NULL != handle->namestore_handle) |
472 | GNUNET_NAMESTORE_disconnect (handle->namestore_handle); | 299 | GNUNET_NAMESTORE_disconnect (handle->namestore_handle); |
473 | if (NULL != handle->oidc) | ||
474 | { | ||
475 | if (NULL != handle->oidc->client_id) | ||
476 | GNUNET_free(handle->oidc->client_id); | ||
477 | if (NULL != handle->oidc->login_identity) | ||
478 | GNUNET_free(handle->oidc->login_identity); | ||
479 | if (NULL != handle->oidc->nonce) | ||
480 | GNUNET_free(handle->oidc->nonce); | ||
481 | if (NULL != handle->oidc->redirect_uri) | ||
482 | GNUNET_free(handle->oidc->redirect_uri); | ||
483 | if (NULL != handle->oidc->response_type) | ||
484 | GNUNET_free(handle->oidc->response_type); | ||
485 | if (NULL != handle->oidc->scope) | ||
486 | GNUNET_free(handle->oidc->scope); | ||
487 | if (NULL != handle->oidc->state) | ||
488 | GNUNET_free(handle->oidc->state); | ||
489 | if (NULL != handle->oidc->response) | ||
490 | json_decref(handle->oidc->response); | ||
491 | GNUNET_free(handle->oidc); | ||
492 | } | ||
493 | if ( NULL != handle->attr_list ) | 300 | if ( NULL != handle->attr_list ) |
494 | { | 301 | { |
495 | for (claim_entry = handle->attr_list->list_head; | 302 | for (claim_entry = handle->attr_list->list_head; |
@@ -537,21 +344,13 @@ do_error (void *cls) | |||
537 | struct MHD_Response *resp; | 344 | struct MHD_Response *resp; |
538 | char *json_error; | 345 | char *json_error; |
539 | 346 | ||
540 | GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}", | 347 | GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", |
541 | handle->emsg, | 348 | handle->emsg); |
542 | (NULL != handle->edesc) ? handle->edesc : "", | ||
543 | (NULL != handle->oidc->state) ? ", \"state\":\"" : "", | ||
544 | (NULL != handle->oidc->state) ? handle->oidc->state : "", | ||
545 | (NULL != handle->oidc->state) ? "\"" : ""); | ||
546 | if ( 0 == handle->response_code ) | 349 | if ( 0 == handle->response_code ) |
547 | { | 350 | { |
548 | handle->response_code = MHD_HTTP_BAD_REQUEST; | 351 | handle->response_code = MHD_HTTP_BAD_REQUEST; |
549 | } | 352 | } |
550 | resp = GNUNET_REST_create_response (json_error); | 353 | resp = GNUNET_REST_create_response (json_error); |
551 | if (MHD_HTTP_UNAUTHORIZED == handle->response_code) | ||
552 | { | ||
553 | MHD_add_response_header(resp, "WWW-Authenticate", "Basic"); | ||
554 | } | ||
555 | MHD_add_response_header (resp, "Content-Type", "application/json"); | 354 | MHD_add_response_header (resp, "Content-Type", "application/json"); |
556 | handle->proc (handle->proc_cls, resp, handle->response_code); | 355 | handle->proc (handle->proc_cls, resp, handle->response_code); |
557 | GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); | 356 | GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); |
@@ -560,53 +359,6 @@ do_error (void *cls) | |||
560 | 359 | ||
561 | 360 | ||
562 | /** | 361 | /** |
563 | * Task run on error in userinfo endpoint, sends error header. Cleans up | ||
564 | * everything | ||
565 | * | ||
566 | * @param cls the `struct RequestHandle` | ||
567 | */ | ||
568 | static void | ||
569 | do_userinfo_error (void *cls) | ||
570 | { | ||
571 | struct RequestHandle *handle = cls; | ||
572 | struct MHD_Response *resp; | ||
573 | char *error; | ||
574 | |||
575 | GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"", | ||
576 | handle->emsg, | ||
577 | (NULL != handle->edesc) ? handle->edesc : ""); | ||
578 | resp = GNUNET_REST_create_response (""); | ||
579 | MHD_add_response_header(resp, "WWW-Authenticate", error); | ||
580 | handle->proc (handle->proc_cls, resp, handle->response_code); | ||
581 | GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); | ||
582 | GNUNET_free (error); | ||
583 | } | ||
584 | |||
585 | |||
586 | /** | ||
587 | * Task run on error, sends error message and redirects. Cleans up everything. | ||
588 | * | ||
589 | * @param cls the `struct RequestHandle` | ||
590 | */ | ||
591 | static void | ||
592 | do_redirect_error (void *cls) | ||
593 | { | ||
594 | struct RequestHandle *handle = cls; | ||
595 | struct MHD_Response *resp; | ||
596 | char* redirect; | ||
597 | GNUNET_asprintf (&redirect, | ||
598 | "%s?error=%s&error_description=%s%s%s", | ||
599 | handle->oidc->redirect_uri, handle->emsg, handle->edesc, | ||
600 | (NULL != handle->oidc->state) ? "&state=" : "", | ||
601 | (NULL != handle->oidc->state) ? handle->oidc->state : ""); | ||
602 | resp = GNUNET_REST_create_response (""); | ||
603 | MHD_add_response_header (resp, "Location", redirect); | ||
604 | handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); | ||
605 | GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); | ||
606 | GNUNET_free (redirect); | ||
607 | } | ||
608 | |||
609 | /** | ||
610 | * Task run on timeout, sends error message. Cleans up everything. | 362 | * Task run on timeout, sends error message. Cleans up everything. |
611 | * | 363 | * |
612 | * @param cls the `struct RequestHandle` | 364 | * @param cls the `struct RequestHandle` |
@@ -668,46 +420,6 @@ return_response (void *cls) | |||
668 | cleanup_handle (handle); | 420 | cleanup_handle (handle); |
669 | } | 421 | } |
670 | 422 | ||
671 | /** | ||
672 | * Return attributes for claim | ||
673 | * | ||
674 | * @param cls the request handle | ||
675 | */ | ||
676 | static void | ||
677 | return_userinfo_response (void *cls) | ||
678 | { | ||
679 | char* result_str; | ||
680 | struct RequestHandle *handle = cls; | ||
681 | struct MHD_Response *resp; | ||
682 | |||
683 | result_str = json_dumps (handle->oidc->response, 0); | ||
684 | |||
685 | resp = GNUNET_REST_create_response (result_str); | ||
686 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | ||
687 | GNUNET_free (result_str); | ||
688 | cleanup_handle (handle); | ||
689 | } | ||
690 | |||
691 | /** | ||
692 | * Returns base64 encoded string without padding | ||
693 | * | ||
694 | * @param string the string to encode | ||
695 | * @return base64 encoded string | ||
696 | */ | ||
697 | static char* | ||
698 | base_64_encode(char *string) | ||
699 | { | ||
700 | char *output; | ||
701 | GNUNET_STRINGS_base64_encode(string,strlen(string),&output); | ||
702 | int index = strlen(output)-1; | ||
703 | while ('=' == output[index]) | ||
704 | { | ||
705 | output[index] = '\0'; | ||
706 | index--; | ||
707 | } | ||
708 | return output; | ||
709 | } | ||
710 | |||
711 | static void | 423 | static void |
712 | collect_finished_cb (void *cls) | 424 | collect_finished_cb (void *cls) |
713 | { | 425 | { |
@@ -1349,1256 +1061,6 @@ options_cont (struct GNUNET_REST_RequestHandle *con_handle, | |||
1349 | } | 1061 | } |
1350 | 1062 | ||
1351 | /** | 1063 | /** |
1352 | * Interprets cookie header and pass its identity keystring to handle | ||
1353 | */ | ||
1354 | static void | ||
1355 | cookie_identity_interpretation (struct RequestHandle *handle) | ||
1356 | { | ||
1357 | struct GNUNET_HashCode cache_key; | ||
1358 | char *cookies; | ||
1359 | struct GNUNET_TIME_Absolute current_time, *relog_time; | ||
1360 | char delimiter[] = "; "; | ||
1361 | |||
1362 | //gets identity of login try with cookie | ||
1363 | GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY), | ||
1364 | &cache_key); | ||
1365 | if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map, | ||
1366 | &cache_key) ) | ||
1367 | { | ||
1368 | //splits cookies and find 'Identity' cookie | ||
1369 | cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key); | ||
1370 | handle->oidc->login_identity = strtok(cookies, delimiter); | ||
1371 | |||
1372 | while ( NULL != handle->oidc->login_identity ) | ||
1373 | { | ||
1374 | if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) ) | ||
1375 | { | ||
1376 | break; | ||
1377 | } | ||
1378 | handle->oidc->login_identity = strtok (NULL, delimiter); | ||
1379 | } | ||
1380 | GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity), | ||
1381 | &cache_key); | ||
1382 | if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) ) | ||
1383 | { | ||
1384 | relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time, | ||
1385 | &cache_key); | ||
1386 | current_time = GNUNET_TIME_absolute_get (); | ||
1387 | // 30 min after old login -> redirect to login | ||
1388 | if ( current_time.abs_value_us <= relog_time->abs_value_us ) | ||
1389 | { | ||
1390 | handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY); | ||
1391 | handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity); | ||
1392 | } | ||
1393 | } | ||
1394 | else | ||
1395 | { | ||
1396 | handle->oidc->login_identity = NULL; | ||
1397 | } | ||
1398 | } | ||
1399 | } | ||
1400 | |||
1401 | /** | ||
1402 | * Redirects to login page stored in configuration file | ||
1403 | */ | ||
1404 | static void | ||
1405 | login_redirection(void *cls) | ||
1406 | { | ||
1407 | char *login_base_url; | ||
1408 | char *new_redirect; | ||
1409 | struct MHD_Response *resp; | ||
1410 | struct RequestHandle *handle = cls; | ||
1411 | |||
1412 | if ( GNUNET_OK | ||
1413 | == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin", | ||
1414 | "address", &login_base_url) ) | ||
1415 | { | ||
1416 | GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s", | ||
1417 | login_base_url, | ||
1418 | OIDC_RESPONSE_TYPE_KEY, | ||
1419 | handle->oidc->response_type, | ||
1420 | OIDC_CLIENT_ID_KEY, | ||
1421 | handle->oidc->client_id, | ||
1422 | OIDC_REDIRECT_URI_KEY, | ||
1423 | handle->oidc->redirect_uri, | ||
1424 | OIDC_SCOPE_KEY, | ||
1425 | handle->oidc->scope, | ||
1426 | OIDC_STATE_KEY, | ||
1427 | (NULL != handle->oidc->state) ? handle->oidc->state : "", | ||
1428 | OIDC_NONCE_KEY, | ||
1429 | (NULL != handle->oidc->nonce) ? handle->oidc->nonce : ""); | ||
1430 | resp = GNUNET_REST_create_response (""); | ||
1431 | MHD_add_response_header (resp, "Location", new_redirect); | ||
1432 | GNUNET_free(login_base_url); | ||
1433 | } | ||
1434 | else | ||
1435 | { | ||
1436 | handle->emsg = GNUNET_strdup("server_error"); | ||
1437 | handle->edesc = GNUNET_strdup ("gnunet configuration failed"); | ||
1438 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
1439 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
1440 | return; | ||
1441 | } | ||
1442 | handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); | ||
1443 | GNUNET_free(new_redirect); | ||
1444 | GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); | ||
1445 | } | ||
1446 | |||
1447 | /** | ||
1448 | * Does internal server error when iteration failed. | ||
1449 | */ | ||
1450 | static void | ||
1451 | oidc_iteration_error (void *cls) | ||
1452 | { | ||
1453 | struct RequestHandle *handle = cls; | ||
1454 | handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR"); | ||
1455 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
1456 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
1457 | } | ||
1458 | |||
1459 | static void get_client_name_result (void *cls, | ||
1460 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, | ||
1461 | const char *label, | ||
1462 | unsigned int rd_count, | ||
1463 | const struct GNUNET_GNSRECORD_Data *rd) | ||
1464 | { | ||
1465 | struct RequestHandle *handle = cls; | ||
1466 | struct MHD_Response *resp; | ||
1467 | char *ticket_str; | ||
1468 | char *redirect_uri; | ||
1469 | char *code_json_string; | ||
1470 | char *code_base64_final_string; | ||
1471 | char *redirect_path; | ||
1472 | char *tmp; | ||
1473 | char *tmp_prefix; | ||
1474 | char *prefix; | ||
1475 | ticket_str = GNUNET_STRINGS_data_to_string_alloc (&handle->ticket, | ||
1476 | sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket)); | ||
1477 | //TODO change if more attributes are needed (see max_age) | ||
1478 | GNUNET_asprintf (&code_json_string, "{\"ticket\":\"%s\"%s%s%s}", | ||
1479 | ticket_str, | ||
1480 | (NULL != handle->oidc->nonce) ? ", \"nonce\":\"" : "", | ||
1481 | (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "", | ||
1482 | (NULL != handle->oidc->nonce) ? "\"" : ""); | ||
1483 | code_base64_final_string = base_64_encode(code_json_string); | ||
1484 | tmp = GNUNET_strdup (handle->oidc->redirect_uri); | ||
1485 | redirect_path = strtok (tmp, "/"); | ||
1486 | redirect_path = strtok (NULL, "/"); | ||
1487 | redirect_path = strtok (NULL, "/"); | ||
1488 | tmp_prefix = GNUNET_strdup (handle->oidc->redirect_uri); | ||
1489 | prefix = strrchr (tmp_prefix, | ||
1490 | (unsigned char) '.'); | ||
1491 | *prefix = '\0'; | ||
1492 | GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s", | ||
1493 | tmp_prefix, | ||
1494 | handle->tld, | ||
1495 | redirect_path, | ||
1496 | handle->oidc->response_type, | ||
1497 | code_base64_final_string, handle->oidc->state); | ||
1498 | resp = GNUNET_REST_create_response (""); | ||
1499 | MHD_add_response_header (resp, "Location", redirect_uri); | ||
1500 | handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND); | ||
1501 | GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); | ||
1502 | GNUNET_free (tmp); | ||
1503 | GNUNET_free (tmp_prefix); | ||
1504 | GNUNET_free (redirect_uri); | ||
1505 | GNUNET_free (ticket_str); | ||
1506 | GNUNET_free (code_json_string); | ||
1507 | GNUNET_free (code_base64_final_string); | ||
1508 | return; | ||
1509 | } | ||
1510 | |||
1511 | static void | ||
1512 | get_client_name_error (void *cls) | ||
1513 | { | ||
1514 | struct RequestHandle *handle = cls; | ||
1515 | |||
1516 | handle->emsg = GNUNET_strdup("server_error"); | ||
1517 | handle->edesc = GNUNET_strdup("Server cannot generate ticket, no name found for client."); | ||
1518 | GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); | ||
1519 | } | ||
1520 | |||
1521 | /** | ||
1522 | * Issues ticket and redirects to relying party with the authorization code as | ||
1523 | * parameter. Otherwise redirects with error | ||
1524 | */ | ||
1525 | static void | ||
1526 | oidc_ticket_issue_cb (void* cls, | ||
1527 | const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket) | ||
1528 | { | ||
1529 | struct RequestHandle *handle = cls; | ||
1530 | handle->idp_op = NULL; | ||
1531 | handle->ticket = *ticket; | ||
1532 | if (NULL != ticket) { | ||
1533 | GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle, | ||
1534 | &handle->priv_key, | ||
1535 | &handle->oidc->client_pkey, | ||
1536 | &get_client_name_error, | ||
1537 | handle, | ||
1538 | &get_client_name_result, | ||
1539 | handle); | ||
1540 | return; | ||
1541 | } | ||
1542 | handle->emsg = GNUNET_strdup("server_error"); | ||
1543 | handle->edesc = GNUNET_strdup("Server cannot generate ticket."); | ||
1544 | GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); | ||
1545 | } | ||
1546 | |||
1547 | static void | ||
1548 | oidc_collect_finished_cb (void *cls) | ||
1549 | { | ||
1550 | struct RequestHandle *handle = cls; | ||
1551 | handle->attr_it = NULL; | ||
1552 | handle->ticket_it = NULL; | ||
1553 | if (NULL == handle->attr_list->list_head) | ||
1554 | { | ||
1555 | handle->emsg = GNUNET_strdup("invalid_scope"); | ||
1556 | handle->edesc = GNUNET_strdup("The requested scope is not available."); | ||
1557 | GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); | ||
1558 | return; | ||
1559 | } | ||
1560 | handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_issue (handle->idp, | ||
1561 | &handle->priv_key, | ||
1562 | &handle->oidc->client_pkey, | ||
1563 | handle->attr_list, | ||
1564 | &oidc_ticket_issue_cb, | ||
1565 | handle); | ||
1566 | } | ||
1567 | |||
1568 | |||
1569 | /** | ||
1570 | * Collects all attributes for an ego if in scope parameter | ||
1571 | */ | ||
1572 | static void | ||
1573 | oidc_attr_collect (void *cls, | ||
1574 | const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, | ||
1575 | const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) | ||
1576 | { | ||
1577 | struct RequestHandle *handle = cls; | ||
1578 | struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; | ||
1579 | char* scope_variables; | ||
1580 | char* scope_variable; | ||
1581 | char delimiter[]=" "; | ||
1582 | |||
1583 | if ( (NULL == attr->name) || (NULL == attr->data) ) | ||
1584 | { | ||
1585 | GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it); | ||
1586 | return; | ||
1587 | } | ||
1588 | |||
1589 | scope_variables = GNUNET_strdup(handle->oidc->scope); | ||
1590 | scope_variable = strtok (scope_variables, delimiter); | ||
1591 | while (NULL != scope_variable) | ||
1592 | { | ||
1593 | if ( 0 == strcmp (attr->name, scope_variable) ) | ||
1594 | { | ||
1595 | break; | ||
1596 | } | ||
1597 | scope_variable = strtok (NULL, delimiter); | ||
1598 | } | ||
1599 | if ( NULL == scope_variable ) | ||
1600 | { | ||
1601 | GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it); | ||
1602 | GNUNET_free(scope_variables); | ||
1603 | return; | ||
1604 | } | ||
1605 | GNUNET_free(scope_variables); | ||
1606 | |||
1607 | le = GNUNET_new(struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry); | ||
1608 | le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr->name, attr->type, | ||
1609 | attr->data, attr->data_size); | ||
1610 | GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head, | ||
1611 | handle->attr_list->list_tail, le); | ||
1612 | GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it); | ||
1613 | } | ||
1614 | |||
1615 | |||
1616 | /** | ||
1617 | * Checks time and cookie and redirects accordingly | ||
1618 | */ | ||
1619 | static void | ||
1620 | login_check (void *cls) | ||
1621 | { | ||
1622 | struct RequestHandle *handle = cls; | ||
1623 | struct GNUNET_TIME_Absolute current_time, *relog_time; | ||
1624 | struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey; | ||
1625 | struct GNUNET_HashCode cache_key; | ||
1626 | char *identity_cookie; | ||
1627 | |||
1628 | GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity); | ||
1629 | GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key); | ||
1630 | GNUNET_free(identity_cookie); | ||
1631 | //No login time for identity -> redirect to login | ||
1632 | if ( GNUNET_YES | ||
1633 | == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, | ||
1634 | &cache_key) ) | ||
1635 | { | ||
1636 | relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time, | ||
1637 | &cache_key); | ||
1638 | current_time = GNUNET_TIME_absolute_get (); | ||
1639 | // 30 min after old login -> redirect to login | ||
1640 | if ( current_time.abs_value_us <= relog_time->abs_value_us ) | ||
1641 | { | ||
1642 | if ( GNUNET_OK | ||
1643 | != GNUNET_CRYPTO_ecdsa_public_key_from_string ( | ||
1644 | handle->oidc->login_identity, | ||
1645 | strlen (handle->oidc->login_identity), &pubkey) ) | ||
1646 | { | ||
1647 | handle->emsg = GNUNET_strdup("invalid_cookie"); | ||
1648 | handle->edesc = GNUNET_strdup( | ||
1649 | "The cookie of a login identity is not valid"); | ||
1650 | GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); | ||
1651 | return; | ||
1652 | } | ||
1653 | // iterate over egos and compare their public key | ||
1654 | for (handle->ego_entry = handle->ego_head; | ||
1655 | NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next) | ||
1656 | { | ||
1657 | GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey); | ||
1658 | if ( 0 | ||
1659 | == memcmp (&ego_pkey, &pubkey, | ||
1660 | sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) | ||
1661 | { | ||
1662 | handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key ( | ||
1663 | handle->ego_entry->ego); | ||
1664 | handle->resp_object = GNUNET_JSONAPI_document_new (); | ||
1665 | handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); | ||
1666 | handle->attr_list = GNUNET_new( | ||
1667 | struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); | ||
1668 | handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start ( | ||
1669 | handle->idp, &handle->priv_key, &oidc_iteration_error, handle, | ||
1670 | &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle); | ||
1671 | return; | ||
1672 | } | ||
1673 | } | ||
1674 | handle->emsg = GNUNET_strdup("invalid_cookie"); | ||
1675 | handle->edesc = GNUNET_strdup( | ||
1676 | "The cookie of the login identity is not valid"); | ||
1677 | GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); | ||
1678 | return; | ||
1679 | } | ||
1680 | } | ||
1681 | } | ||
1682 | |||
1683 | /** | ||
1684 | * Searches for client_id in namestore. If found trust status stored in handle | ||
1685 | * Else continues to search | ||
1686 | * | ||
1687 | * @param handle the RequestHandle | ||
1688 | */ | ||
1689 | static void | ||
1690 | namestore_iteration_callback ( | ||
1691 | void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, | ||
1692 | const char *rname, unsigned int rd_len, | ||
1693 | const struct GNUNET_GNSRECORD_Data *rd) | ||
1694 | { | ||
1695 | struct RequestHandle *handle = cls; | ||
1696 | struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey; | ||
1697 | struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey; | ||
1698 | int i; | ||
1699 | |||
1700 | for (i = 0; i < rd_len; i++) | ||
1701 | { | ||
1702 | if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type ) | ||
1703 | continue; | ||
1704 | |||
1705 | if ( NULL != handle->oidc->login_identity ) | ||
1706 | { | ||
1707 | GNUNET_CRYPTO_ecdsa_public_key_from_string ( | ||
1708 | handle->oidc->login_identity, | ||
1709 | strlen (handle->oidc->login_identity), | ||
1710 | &login_identity_pkey); | ||
1711 | GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, | ||
1712 | ¤t_zone_pkey); | ||
1713 | |||
1714 | if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey, | ||
1715 | sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) | ||
1716 | { | ||
1717 | if ( 0 == memcmp (&login_identity_pkey, ¤t_zone_pkey, | ||
1718 | sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) | ||
1719 | { | ||
1720 | handle->oidc->is_client_trusted = GNUNET_YES; | ||
1721 | } | ||
1722 | } | ||
1723 | } | ||
1724 | else | ||
1725 | { | ||
1726 | if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey, | ||
1727 | sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) | ||
1728 | { | ||
1729 | handle->oidc->is_client_trusted = GNUNET_YES; | ||
1730 | } | ||
1731 | } | ||
1732 | } | ||
1733 | |||
1734 | GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it); | ||
1735 | } | ||
1736 | |||
1737 | /** | ||
1738 | * Iteration over all results finished, build final | ||
1739 | * response. | ||
1740 | * | ||
1741 | * @param cls the `struct RequestHandle` | ||
1742 | */ | ||
1743 | static void namestore_iteration_finished (void *cls) | ||
1744 | { | ||
1745 | struct RequestHandle *handle = cls; | ||
1746 | struct GNUNET_HashCode cache_key; | ||
1747 | |||
1748 | char *expected_scope; | ||
1749 | char delimiter[]=" "; | ||
1750 | int number_of_ignored_parameter, iterator; | ||
1751 | |||
1752 | |||
1753 | handle->ego_entry = handle->ego_entry->next; | ||
1754 | |||
1755 | if(NULL != handle->ego_entry) | ||
1756 | { | ||
1757 | handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego); | ||
1758 | handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key, | ||
1759 | &oidc_iteration_error, handle, &namestore_iteration_callback, handle, | ||
1760 | &namestore_iteration_finished, handle); | ||
1761 | return; | ||
1762 | } | ||
1763 | if (GNUNET_NO == handle->oidc->is_client_trusted) | ||
1764 | { | ||
1765 | handle->emsg = GNUNET_strdup("unauthorized_client"); | ||
1766 | handle->edesc = GNUNET_strdup("The client is not authorized to request an " | ||
1767 | "authorization code using this method."); | ||
1768 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
1769 | return; | ||
1770 | } | ||
1771 | |||
1772 | // REQUIRED value: redirect_uri | ||
1773 | GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), | ||
1774 | &cache_key); | ||
1775 | if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, | ||
1776 | &cache_key)) | ||
1777 | { | ||
1778 | handle->emsg=GNUNET_strdup("invalid_request"); | ||
1779 | handle->edesc=GNUNET_strdup("missing parameter redirect_uri"); | ||
1780 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
1781 | return; | ||
1782 | } | ||
1783 | handle->oidc->redirect_uri = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, | ||
1784 | &cache_key)); | ||
1785 | |||
1786 | // REQUIRED value: response_type | ||
1787 | GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY), | ||
1788 | &cache_key); | ||
1789 | if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, | ||
1790 | &cache_key)) | ||
1791 | { | ||
1792 | handle->emsg=GNUNET_strdup("invalid_request"); | ||
1793 | handle->edesc=GNUNET_strdup("missing parameter response_type"); | ||
1794 | GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); | ||
1795 | return; | ||
1796 | } | ||
1797 | handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, | ||
1798 | &cache_key); | ||
1799 | handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type); | ||
1800 | |||
1801 | // REQUIRED value: scope | ||
1802 | GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key); | ||
1803 | if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, | ||
1804 | &cache_key)) | ||
1805 | { | ||
1806 | handle->emsg=GNUNET_strdup("invalid_request"); | ||
1807 | handle->edesc=GNUNET_strdup("missing parameter scope"); | ||
1808 | GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); | ||
1809 | return; | ||
1810 | } | ||
1811 | handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, | ||
1812 | &cache_key); | ||
1813 | handle->oidc->scope = GNUNET_strdup(handle->oidc->scope); | ||
1814 | |||
1815 | //OPTIONAL value: nonce | ||
1816 | GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key); | ||
1817 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, | ||
1818 | &cache_key)) | ||
1819 | { | ||
1820 | handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, | ||
1821 | &cache_key); | ||
1822 | handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce); | ||
1823 | } | ||
1824 | |||
1825 | //TODO check other values if needed | ||
1826 | number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *); | ||
1827 | for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ ) | ||
1828 | { | ||
1829 | GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator], | ||
1830 | strlen(OIDC_ignored_parameter_array[iterator]), | ||
1831 | &cache_key); | ||
1832 | if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map, | ||
1833 | &cache_key)) | ||
1834 | { | ||
1835 | handle->emsg=GNUNET_strdup("access_denied"); | ||
1836 | GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s", | ||
1837 | OIDC_ignored_parameter_array[iterator]); | ||
1838 | GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); | ||
1839 | return; | ||
1840 | } | ||
1841 | } | ||
1842 | |||
1843 | // Checks if response_type is 'code' | ||
1844 | if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) ) | ||
1845 | { | ||
1846 | handle->emsg=GNUNET_strdup("unsupported_response_type"); | ||
1847 | handle->edesc=GNUNET_strdup("The authorization server does not support " | ||
1848 | "obtaining this authorization code."); | ||
1849 | GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); | ||
1850 | return; | ||
1851 | } | ||
1852 | |||
1853 | // Checks if scope contains 'openid' | ||
1854 | expected_scope = GNUNET_strdup(handle->oidc->scope); | ||
1855 | char* test; | ||
1856 | test = strtok (expected_scope, delimiter); | ||
1857 | while (NULL != test) | ||
1858 | { | ||
1859 | if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) ) | ||
1860 | { | ||
1861 | break; | ||
1862 | } | ||
1863 | test = strtok (NULL, delimiter); | ||
1864 | } | ||
1865 | if (NULL == test) | ||
1866 | { | ||
1867 | handle->emsg = GNUNET_strdup("invalid_scope"); | ||
1868 | handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or " | ||
1869 | "malformed."); | ||
1870 | GNUNET_SCHEDULER_add_now (&do_redirect_error, handle); | ||
1871 | GNUNET_free(expected_scope); | ||
1872 | return; | ||
1873 | } | ||
1874 | |||
1875 | GNUNET_free(expected_scope); | ||
1876 | |||
1877 | if( NULL != handle->oidc->login_identity ) | ||
1878 | { | ||
1879 | GNUNET_SCHEDULER_add_now(&login_check,handle); | ||
1880 | return; | ||
1881 | } | ||
1882 | |||
1883 | GNUNET_SCHEDULER_add_now(&login_redirection,handle); | ||
1884 | } | ||
1885 | |||
1886 | /** | ||
1887 | * Responds to authorization GET and url-encoded POST request | ||
1888 | * | ||
1889 | * @param con_handle the connection handle | ||
1890 | * @param url the url | ||
1891 | * @param cls the RequestHandle | ||
1892 | */ | ||
1893 | static void | ||
1894 | authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | ||
1895 | const char* url, | ||
1896 | void *cls) | ||
1897 | { | ||
1898 | struct RequestHandle *handle = cls; | ||
1899 | struct GNUNET_HashCode cache_key; | ||
1900 | struct EgoEntry *tmp_ego; | ||
1901 | struct GNUNET_CRYPTO_EcdsaPublicKey pkey; | ||
1902 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; | ||
1903 | |||
1904 | cookie_identity_interpretation(handle); | ||
1905 | |||
1906 | //RECOMMENDED value: state - REQUIRED for answers | ||
1907 | GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key); | ||
1908 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, | ||
1909 | &cache_key)) | ||
1910 | { | ||
1911 | handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, | ||
1912 | &cache_key); | ||
1913 | handle->oidc->state = GNUNET_strdup (handle->oidc->state); | ||
1914 | } | ||
1915 | |||
1916 | // REQUIRED value: client_id | ||
1917 | GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY), | ||
1918 | &cache_key); | ||
1919 | if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, | ||
1920 | &cache_key)) | ||
1921 | { | ||
1922 | handle->emsg=GNUNET_strdup("invalid_request"); | ||
1923 | handle->edesc=GNUNET_strdup("missing parameter client_id"); | ||
1924 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
1925 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
1926 | return; | ||
1927 | } | ||
1928 | handle->oidc->client_id = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, | ||
1929 | &cache_key)); | ||
1930 | |||
1931 | if ( GNUNET_OK | ||
1932 | != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id, | ||
1933 | strlen (handle->oidc->client_id), | ||
1934 | &handle->oidc->client_pkey) ) | ||
1935 | { | ||
1936 | handle->emsg = GNUNET_strdup("unauthorized_client"); | ||
1937 | handle->edesc = GNUNET_strdup("The client is not authorized to request an " | ||
1938 | "authorization code using this method."); | ||
1939 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
1940 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
1941 | return; | ||
1942 | } | ||
1943 | |||
1944 | |||
1945 | if ( NULL == handle->ego_head ) | ||
1946 | { | ||
1947 | handle->emsg = GNUNET_strdup("server_error"); | ||
1948 | handle->edesc = GNUNET_strdup ("Egos are missing"); | ||
1949 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
1950 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
1951 | return; | ||
1952 | } | ||
1953 | |||
1954 | handle->ego_entry = handle->ego_head; | ||
1955 | handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego); | ||
1956 | handle->oidc->is_client_trusted = GNUNET_NO; | ||
1957 | |||
1958 | //First check if client_id is one of our egos; TODO: handle other TLD cases: Delegation, from config | ||
1959 | for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next) | ||
1960 | { | ||
1961 | priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego); | ||
1962 | GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, | ||
1963 | &pkey); | ||
1964 | if ( 0 == memcmp (&pkey, &handle->oidc->client_pkey, | ||
1965 | sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) ) | ||
1966 | { | ||
1967 | handle->tld = GNUNET_strdup (tmp_ego->identifier); | ||
1968 | handle->oidc->is_client_trusted = GNUNET_YES; | ||
1969 | handle->ego_entry = handle->ego_tail; | ||
1970 | } | ||
1971 | } | ||
1972 | |||
1973 | |||
1974 | // Checks if client_id is valid: | ||
1975 | handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start ( | ||
1976 | handle->namestore_handle, &handle->priv_key, &oidc_iteration_error, | ||
1977 | handle, &namestore_iteration_callback, handle, | ||
1978 | &namestore_iteration_finished, handle); | ||
1979 | } | ||
1980 | |||
1981 | /** | ||
1982 | * Combines an identity with a login time and responds OK to login request | ||
1983 | * | ||
1984 | * @param con_handle the connection handle | ||
1985 | * @param url the url | ||
1986 | * @param cls the RequestHandle | ||
1987 | */ | ||
1988 | static void | ||
1989 | login_cont (struct GNUNET_REST_RequestHandle *con_handle, | ||
1990 | const char* url, | ||
1991 | void *cls) | ||
1992 | { | ||
1993 | struct MHD_Response *resp = GNUNET_REST_create_response (""); | ||
1994 | struct RequestHandle *handle = cls; | ||
1995 | struct GNUNET_HashCode cache_key; | ||
1996 | struct GNUNET_TIME_Absolute *current_time; | ||
1997 | struct GNUNET_TIME_Absolute *last_time; | ||
1998 | char* cookie; | ||
1999 | json_t *root; | ||
2000 | json_error_t error; | ||
2001 | json_t *identity; | ||
2002 | char term_data[handle->rest_handle->data_size+1]; | ||
2003 | term_data[handle->rest_handle->data_size] = '\0'; | ||
2004 | GNUNET_memcpy (term_data, handle->rest_handle->data, handle->rest_handle->data_size); | ||
2005 | root = json_loads (term_data, JSON_DECODE_ANY, &error); | ||
2006 | identity = json_object_get (root, "identity"); | ||
2007 | if ( json_is_string(identity) ) | ||
2008 | { | ||
2009 | GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity)); | ||
2010 | MHD_add_response_header (resp, "Set-Cookie", cookie); | ||
2011 | MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST"); | ||
2012 | GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key); | ||
2013 | |||
2014 | current_time = GNUNET_new(struct GNUNET_TIME_Absolute); | ||
2015 | *current_time = GNUNET_TIME_relative_to_absolute ( | ||
2016 | GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_minute_ (), | ||
2017 | 30)); | ||
2018 | last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key); | ||
2019 | if (NULL != last_time) | ||
2020 | { | ||
2021 | GNUNET_free(last_time); | ||
2022 | } | ||
2023 | GNUNET_CONTAINER_multihashmap_put ( | ||
2024 | OIDC_identity_login_time, &cache_key, current_time, | ||
2025 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); | ||
2026 | |||
2027 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | ||
2028 | GNUNET_free(cookie); | ||
2029 | } | ||
2030 | else | ||
2031 | { | ||
2032 | handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); | ||
2033 | } | ||
2034 | json_decref (root); | ||
2035 | GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); | ||
2036 | return; | ||
2037 | } | ||
2038 | |||
2039 | /** | ||
2040 | * Responds to token url-encoded POST request | ||
2041 | * | ||
2042 | * @param con_handle the connection handle | ||
2043 | * @param url the url | ||
2044 | * @param cls the RequestHandle | ||
2045 | */ | ||
2046 | static void | ||
2047 | token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | ||
2048 | const char* url, | ||
2049 | void *cls) | ||
2050 | { | ||
2051 | //TODO static strings | ||
2052 | struct RequestHandle *handle = cls; | ||
2053 | struct GNUNET_HashCode cache_key; | ||
2054 | char *authorization, *credentials; | ||
2055 | char delimiter[]=" "; | ||
2056 | char delimiter_user_psw[]=":"; | ||
2057 | char *grant_type, *code, *redirect_uri, *expected_redirect_uri; | ||
2058 | char *user_psw = NULL, *client_id, *psw; | ||
2059 | char *expected_psw; | ||
2060 | int client_exists = GNUNET_NO; | ||
2061 | struct MHD_Response *resp; | ||
2062 | char* code_output; | ||
2063 | json_t *root, *ticket_string, *nonce, *max_age; | ||
2064 | json_error_t error; | ||
2065 | char *json_response; | ||
2066 | |||
2067 | /* | ||
2068 | * Check Authorization | ||
2069 | */ | ||
2070 | GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, | ||
2071 | strlen (OIDC_AUTHORIZATION_HEADER_KEY), | ||
2072 | &cache_key); | ||
2073 | if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map, | ||
2074 | &cache_key) ) | ||
2075 | { | ||
2076 | handle->emsg=GNUNET_strdup("invalid_client"); | ||
2077 | handle->edesc=GNUNET_strdup("missing authorization"); | ||
2078 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2079 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2080 | return; | ||
2081 | } | ||
2082 | authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key); | ||
2083 | |||
2084 | //split header in "Basic" and [content] | ||
2085 | credentials = strtok (authorization, delimiter); | ||
2086 | if (0 != strcmp ("Basic",credentials)) | ||
2087 | { | ||
2088 | handle->emsg=GNUNET_strdup("invalid_client"); | ||
2089 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2090 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2091 | return; | ||
2092 | } | ||
2093 | credentials = strtok(NULL, delimiter); | ||
2094 | if (NULL == credentials) | ||
2095 | { | ||
2096 | handle->emsg=GNUNET_strdup("invalid_client"); | ||
2097 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2098 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2099 | return; | ||
2100 | } | ||
2101 | GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), &user_psw); | ||
2102 | |||
2103 | if ( NULL == user_psw ) | ||
2104 | { | ||
2105 | handle->emsg=GNUNET_strdup("invalid_client"); | ||
2106 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2107 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2108 | return; | ||
2109 | } | ||
2110 | client_id = strtok (user_psw, delimiter_user_psw); | ||
2111 | if ( NULL == client_id ) | ||
2112 | { | ||
2113 | GNUNET_free_non_null(user_psw); | ||
2114 | handle->emsg=GNUNET_strdup("invalid_client"); | ||
2115 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2116 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2117 | return; | ||
2118 | } | ||
2119 | psw = strtok (NULL, delimiter_user_psw); | ||
2120 | if (NULL == psw) | ||
2121 | { | ||
2122 | GNUNET_free_non_null(user_psw); | ||
2123 | handle->emsg=GNUNET_strdup("invalid_client"); | ||
2124 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2125 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2126 | return; | ||
2127 | } | ||
2128 | |||
2129 | //check client password | ||
2130 | if ( GNUNET_OK | ||
2131 | == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin", | ||
2132 | "psw", &expected_psw) ) | ||
2133 | { | ||
2134 | if (0 != strcmp (expected_psw, psw)) | ||
2135 | { | ||
2136 | GNUNET_free_non_null(user_psw); | ||
2137 | GNUNET_free(expected_psw); | ||
2138 | handle->emsg=GNUNET_strdup("invalid_client"); | ||
2139 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2140 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2141 | return; | ||
2142 | } | ||
2143 | GNUNET_free(expected_psw); | ||
2144 | } | ||
2145 | else | ||
2146 | { | ||
2147 | GNUNET_free_non_null(user_psw); | ||
2148 | handle->emsg = GNUNET_strdup("server_error"); | ||
2149 | handle->edesc = GNUNET_strdup ("gnunet configuration failed"); | ||
2150 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
2151 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2152 | return; | ||
2153 | } | ||
2154 | |||
2155 | //check client_id | ||
2156 | for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; ) | ||
2157 | { | ||
2158 | if ( 0 == strcmp(handle->ego_entry->keystring, client_id)) | ||
2159 | { | ||
2160 | client_exists = GNUNET_YES; | ||
2161 | break; | ||
2162 | } | ||
2163 | handle->ego_entry = handle->ego_entry->next; | ||
2164 | } | ||
2165 | if (GNUNET_NO == client_exists) | ||
2166 | { | ||
2167 | GNUNET_free_non_null(user_psw); | ||
2168 | handle->emsg=GNUNET_strdup("invalid_client"); | ||
2169 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2170 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2171 | return; | ||
2172 | } | ||
2173 | |||
2174 | /* | ||
2175 | * Check parameter | ||
2176 | */ | ||
2177 | |||
2178 | //TODO Do not allow multiple equal parameter names | ||
2179 | //REQUIRED grant_type | ||
2180 | GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key); | ||
2181 | if ( GNUNET_NO | ||
2182 | == GNUNET_CONTAINER_multihashmap_contains ( | ||
2183 | handle->rest_handle->url_param_map, &cache_key) ) | ||
2184 | { | ||
2185 | GNUNET_free_non_null(user_psw); | ||
2186 | handle->emsg = GNUNET_strdup("invalid_request"); | ||
2187 | handle->edesc = GNUNET_strdup("missing parameter grant_type"); | ||
2188 | handle->response_code = MHD_HTTP_BAD_REQUEST; | ||
2189 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2190 | return; | ||
2191 | } | ||
2192 | grant_type = GNUNET_CONTAINER_multihashmap_get ( | ||
2193 | handle->rest_handle->url_param_map, &cache_key); | ||
2194 | |||
2195 | //REQUIRED code | ||
2196 | GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key); | ||
2197 | if ( GNUNET_NO | ||
2198 | == GNUNET_CONTAINER_multihashmap_contains ( | ||
2199 | handle->rest_handle->url_param_map, &cache_key) ) | ||
2200 | { | ||
2201 | GNUNET_free_non_null(user_psw); | ||
2202 | handle->emsg = GNUNET_strdup("invalid_request"); | ||
2203 | handle->edesc = GNUNET_strdup("missing parameter code"); | ||
2204 | handle->response_code = MHD_HTTP_BAD_REQUEST; | ||
2205 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2206 | return; | ||
2207 | } | ||
2208 | code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, | ||
2209 | &cache_key); | ||
2210 | |||
2211 | //REQUIRED redirect_uri | ||
2212 | GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY), | ||
2213 | &cache_key); | ||
2214 | if ( GNUNET_NO | ||
2215 | == GNUNET_CONTAINER_multihashmap_contains ( | ||
2216 | handle->rest_handle->url_param_map, &cache_key) ) | ||
2217 | { | ||
2218 | GNUNET_free_non_null(user_psw); | ||
2219 | handle->emsg = GNUNET_strdup("invalid_request"); | ||
2220 | handle->edesc = GNUNET_strdup("missing parameter redirect_uri"); | ||
2221 | handle->response_code = MHD_HTTP_BAD_REQUEST; | ||
2222 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2223 | return; | ||
2224 | } | ||
2225 | redirect_uri = GNUNET_CONTAINER_multihashmap_get ( | ||
2226 | handle->rest_handle->url_param_map, &cache_key); | ||
2227 | |||
2228 | |||
2229 | //Check parameter grant_type == "authorization_code" | ||
2230 | if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type)) | ||
2231 | { | ||
2232 | GNUNET_free_non_null(user_psw); | ||
2233 | handle->emsg=GNUNET_strdup("unsupported_grant_type"); | ||
2234 | handle->response_code = MHD_HTTP_BAD_REQUEST; | ||
2235 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2236 | return; | ||
2237 | } | ||
2238 | GNUNET_CRYPTO_hash (code, strlen (code), &cache_key); | ||
2239 | int i = 1; | ||
2240 | if ( GNUNET_SYSERR | ||
2241 | == GNUNET_CONTAINER_multihashmap_put (OIDC_ticket_once, | ||
2242 | &cache_key, | ||
2243 | &i, | ||
2244 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) ) | ||
2245 | { | ||
2246 | GNUNET_free_non_null(user_psw); | ||
2247 | handle->emsg = GNUNET_strdup("invalid_request"); | ||
2248 | handle->edesc = GNUNET_strdup("Cannot use the same code more than once"); | ||
2249 | handle->response_code = MHD_HTTP_BAD_REQUEST; | ||
2250 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2251 | return; | ||
2252 | } | ||
2253 | |||
2254 | //decode code | ||
2255 | GNUNET_STRINGS_base64_decode(code,strlen(code),&code_output); | ||
2256 | root = json_loads (code_output, 0, &error); | ||
2257 | GNUNET_free(code_output); | ||
2258 | ticket_string = json_object_get (root, "ticket"); | ||
2259 | nonce = json_object_get (root, "nonce"); | ||
2260 | max_age = json_object_get (root, "max_age"); | ||
2261 | |||
2262 | if(ticket_string == NULL && !json_is_string(ticket_string)) | ||
2263 | { | ||
2264 | GNUNET_free_non_null(user_psw); | ||
2265 | handle->emsg = GNUNET_strdup("invalid_request"); | ||
2266 | handle->edesc = GNUNET_strdup("invalid code"); | ||
2267 | handle->response_code = MHD_HTTP_BAD_REQUEST; | ||
2268 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2269 | return; | ||
2270 | } | ||
2271 | |||
2272 | struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket = GNUNET_new(struct GNUNET_IDENTITY_PROVIDER_Ticket); | ||
2273 | if ( GNUNET_OK | ||
2274 | != GNUNET_STRINGS_string_to_data (json_string_value(ticket_string), | ||
2275 | strlen (json_string_value(ticket_string)), | ||
2276 | ticket, | ||
2277 | sizeof(struct GNUNET_IDENTITY_PROVIDER_Ticket))) | ||
2278 | { | ||
2279 | GNUNET_free_non_null(user_psw); | ||
2280 | handle->emsg = GNUNET_strdup("invalid_request"); | ||
2281 | handle->edesc = GNUNET_strdup("invalid code"); | ||
2282 | handle->response_code = MHD_HTTP_BAD_REQUEST; | ||
2283 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2284 | GNUNET_free(ticket); | ||
2285 | return; | ||
2286 | } | ||
2287 | // this is the current client (relying party) | ||
2288 | struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; | ||
2289 | GNUNET_IDENTITY_ego_get_public_key(handle->ego_entry->ego,&pub_key); | ||
2290 | if (0 != memcmp(&pub_key,&ticket->audience,sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) | ||
2291 | { | ||
2292 | GNUNET_free_non_null(user_psw); | ||
2293 | handle->emsg = GNUNET_strdup("invalid_request"); | ||
2294 | handle->edesc = GNUNET_strdup("invalid code"); | ||
2295 | handle->response_code = MHD_HTTP_BAD_REQUEST; | ||
2296 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2297 | GNUNET_free(ticket); | ||
2298 | return; | ||
2299 | } | ||
2300 | |||
2301 | //create jwt | ||
2302 | unsigned long long int expiration_time; | ||
2303 | if ( GNUNET_OK | ||
2304 | != GNUNET_CONFIGURATION_get_value_number(cfg, "identity-rest-plugin", | ||
2305 | "expiration_time", &expiration_time) ) | ||
2306 | { | ||
2307 | GNUNET_free_non_null(user_psw); | ||
2308 | handle->emsg = GNUNET_strdup("server_error"); | ||
2309 | handle->edesc = GNUNET_strdup ("gnunet configuration failed"); | ||
2310 | handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
2311 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2312 | GNUNET_free(ticket); | ||
2313 | return; | ||
2314 | } | ||
2315 | |||
2316 | struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *cl = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); | ||
2317 | //aud REQUIRED public key client_id must be there | ||
2318 | GNUNET_IDENTITY_ATTRIBUTE_list_add(cl, | ||
2319 | "aud", | ||
2320 | GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING, | ||
2321 | client_id, | ||
2322 | strlen(client_id)); | ||
2323 | //exp REQUIRED time expired from config | ||
2324 | struct GNUNET_TIME_Absolute exp_time = GNUNET_TIME_relative_to_absolute ( | ||
2325 | GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (), | ||
2326 | expiration_time)); | ||
2327 | const char* exp_time_string = GNUNET_STRINGS_absolute_time_to_string(exp_time); | ||
2328 | GNUNET_IDENTITY_ATTRIBUTE_list_add (cl, | ||
2329 | "exp", | ||
2330 | GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING, | ||
2331 | exp_time_string, | ||
2332 | strlen(exp_time_string)); | ||
2333 | //iat REQUIRED time now | ||
2334 | struct GNUNET_TIME_Absolute time_now = GNUNET_TIME_absolute_get(); | ||
2335 | const char* time_now_string = GNUNET_STRINGS_absolute_time_to_string(time_now); | ||
2336 | GNUNET_IDENTITY_ATTRIBUTE_list_add (cl, | ||
2337 | "iat", | ||
2338 | GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING, | ||
2339 | time_now_string, | ||
2340 | strlen(time_now_string)); | ||
2341 | //nonce only if nonce is provided | ||
2342 | if ( NULL != nonce && json_is_string(nonce) ) | ||
2343 | { | ||
2344 | GNUNET_IDENTITY_ATTRIBUTE_list_add (cl, | ||
2345 | "nonce", | ||
2346 | GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING, | ||
2347 | json_string_value(nonce), | ||
2348 | strlen(json_string_value(nonce))); | ||
2349 | } | ||
2350 | //auth_time only if max_age is provided | ||
2351 | if ( NULL != max_age && json_is_string(max_age) ) | ||
2352 | { | ||
2353 | GNUNET_IDENTITY_ATTRIBUTE_list_add (cl, | ||
2354 | "auth_time", | ||
2355 | GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING, | ||
2356 | json_string_value(max_age), | ||
2357 | strlen(json_string_value(max_age))); | ||
2358 | } | ||
2359 | //TODO OPTIONAL acr,amr,azp | ||
2360 | |||
2361 | struct EgoEntry *ego_entry; | ||
2362 | for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) | ||
2363 | { | ||
2364 | GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key); | ||
2365 | if (0 == memcmp (&pub_key, &ticket->audience, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) | ||
2366 | { | ||
2367 | break; | ||
2368 | } | ||
2369 | } | ||
2370 | if ( NULL == ego_entry ) | ||
2371 | { | ||
2372 | GNUNET_free_non_null(user_psw); | ||
2373 | handle->emsg = GNUNET_strdup("invalid_request"); | ||
2374 | handle->edesc = GNUNET_strdup("invalid code...."); | ||
2375 | handle->response_code = MHD_HTTP_BAD_REQUEST; | ||
2376 | GNUNET_SCHEDULER_add_now (&do_error, handle); | ||
2377 | GNUNET_free(ticket); | ||
2378 | return; | ||
2379 | } | ||
2380 | char *id_token = jwt_create_from_list(&ticket->audience, | ||
2381 | cl, | ||
2382 | GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego)); | ||
2383 | |||
2384 | //Create random access_token | ||
2385 | char* access_token_number; | ||
2386 | char* access_token; | ||
2387 | uint64_t random_number; | ||
2388 | random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX); | ||
2389 | GNUNET_asprintf(&access_token_number, "%" PRIu64, random_number); | ||
2390 | GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token); | ||
2391 | |||
2392 | |||
2393 | |||
2394 | //TODO OPTIONAL add refresh_token and scope | ||
2395 | GNUNET_asprintf (&json_response, | ||
2396 | "{ \"access_token\" : \"%s\", " | ||
2397 | "\"token_type\" : \"Bearer\", " | ||
2398 | "\"expires_in\" : %d, " | ||
2399 | "\"id_token\" : \"%s\"}", | ||
2400 | access_token, | ||
2401 | expiration_time, | ||
2402 | id_token); | ||
2403 | GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key); | ||
2404 | char *id_ticket_combination; | ||
2405 | GNUNET_asprintf(&id_ticket_combination, | ||
2406 | "%s;%s", | ||
2407 | client_id, | ||
2408 | json_string_value(ticket_string)); | ||
2409 | GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token, | ||
2410 | &cache_key, | ||
2411 | id_ticket_combination, | ||
2412 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); | ||
2413 | |||
2414 | resp = GNUNET_REST_create_response (json_response); | ||
2415 | MHD_add_response_header (resp, "Cache-Control", "no-store"); | ||
2416 | MHD_add_response_header (resp, "Pragma", "no-cache"); | ||
2417 | MHD_add_response_header (resp, "Content-Type", "application/json"); | ||
2418 | handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); | ||
2419 | |||
2420 | GNUNET_IDENTITY_ATTRIBUTE_list_destroy(cl); | ||
2421 | GNUNET_free(access_token_number); | ||
2422 | GNUNET_free(access_token); | ||
2423 | GNUNET_free(user_psw); | ||
2424 | GNUNET_free(json_response); | ||
2425 | GNUNET_free(ticket); | ||
2426 | GNUNET_free(id_token); | ||
2427 | json_decref (root); | ||
2428 | GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle); | ||
2429 | } | ||
2430 | |||
2431 | /** | ||
2432 | * Collects claims and stores them in handle | ||
2433 | */ | ||
2434 | static void | ||
2435 | consume_ticket (void *cls, | ||
2436 | const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, | ||
2437 | const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) | ||
2438 | { | ||
2439 | struct RequestHandle *handle = cls; | ||
2440 | |||
2441 | if (NULL == identity) | ||
2442 | { | ||
2443 | GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle); | ||
2444 | return; | ||
2445 | } | ||
2446 | |||
2447 | json_object_set_new (handle->oidc->response, | ||
2448 | attr->name, | ||
2449 | json_string(attr->data)); | ||
2450 | } | ||
2451 | |||
2452 | /** | ||
2453 | * Responds to userinfo GET and url-encoded POST request | ||
2454 | * | ||
2455 | * @param con_handle the connection handle | ||
2456 | * @param url the url | ||
2457 | * @param cls the RequestHandle | ||
2458 | */ | ||
2459 | static void | ||
2460 | userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle, | ||
2461 | const char* url, void *cls) | ||
2462 | { | ||
2463 | //TODO expiration time | ||
2464 | struct RequestHandle *handle = cls; | ||
2465 | char delimiter[] = " "; | ||
2466 | char delimiter_db[] = ";"; | ||
2467 | struct GNUNET_HashCode cache_key; | ||
2468 | char *authorization, *authorization_type, *authorization_access_token; | ||
2469 | char *client_ticket, *client, *ticket_str; | ||
2470 | struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket; | ||
2471 | |||
2472 | GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY, | ||
2473 | strlen (OIDC_AUTHORIZATION_HEADER_KEY), | ||
2474 | &cache_key); | ||
2475 | if ( GNUNET_NO | ||
2476 | == GNUNET_CONTAINER_multihashmap_contains ( | ||
2477 | handle->rest_handle->header_param_map, &cache_key) ) | ||
2478 | { | ||
2479 | handle->emsg = GNUNET_strdup("invalid_token"); | ||
2480 | handle->edesc = GNUNET_strdup("No Access Token"); | ||
2481 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2482 | GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); | ||
2483 | return; | ||
2484 | } | ||
2485 | authorization = GNUNET_CONTAINER_multihashmap_get ( | ||
2486 | handle->rest_handle->header_param_map, &cache_key); | ||
2487 | |||
2488 | //split header in "Bearer" and access_token | ||
2489 | authorization = GNUNET_strdup(authorization); | ||
2490 | authorization_type = strtok (authorization, delimiter); | ||
2491 | if ( 0 != strcmp ("Bearer", authorization_type) ) | ||
2492 | { | ||
2493 | handle->emsg = GNUNET_strdup("invalid_token"); | ||
2494 | handle->edesc = GNUNET_strdup("No Access Token"); | ||
2495 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2496 | GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); | ||
2497 | GNUNET_free(authorization); | ||
2498 | return; | ||
2499 | } | ||
2500 | authorization_access_token = strtok (NULL, delimiter); | ||
2501 | if ( NULL == authorization_access_token ) | ||
2502 | { | ||
2503 | handle->emsg = GNUNET_strdup("invalid_token"); | ||
2504 | handle->edesc = GNUNET_strdup("No Access Token"); | ||
2505 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2506 | GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); | ||
2507 | GNUNET_free(authorization); | ||
2508 | return; | ||
2509 | } | ||
2510 | |||
2511 | GNUNET_CRYPTO_hash (authorization_access_token, | ||
2512 | strlen (authorization_access_token), | ||
2513 | &cache_key); | ||
2514 | if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token, | ||
2515 | &cache_key) ) | ||
2516 | { | ||
2517 | handle->emsg = GNUNET_strdup("invalid_token"); | ||
2518 | handle->edesc = GNUNET_strdup("The Access Token expired"); | ||
2519 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2520 | GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); | ||
2521 | GNUNET_free(authorization); | ||
2522 | return; | ||
2523 | } | ||
2524 | |||
2525 | client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token, | ||
2526 | &cache_key); | ||
2527 | client_ticket = GNUNET_strdup(client_ticket); | ||
2528 | client = strtok(client_ticket,delimiter_db); | ||
2529 | if (NULL == client) | ||
2530 | { | ||
2531 | handle->emsg = GNUNET_strdup("invalid_token"); | ||
2532 | handle->edesc = GNUNET_strdup("The Access Token expired"); | ||
2533 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2534 | GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); | ||
2535 | GNUNET_free(authorization); | ||
2536 | GNUNET_free(client_ticket); | ||
2537 | return; | ||
2538 | } | ||
2539 | handle->ego_entry = handle->ego_head; | ||
2540 | for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next) | ||
2541 | { | ||
2542 | if (0 == strcmp(handle->ego_entry->keystring,client)) | ||
2543 | { | ||
2544 | break; | ||
2545 | } | ||
2546 | } | ||
2547 | if (NULL == handle->ego_entry) | ||
2548 | { | ||
2549 | handle->emsg = GNUNET_strdup("invalid_token"); | ||
2550 | handle->edesc = GNUNET_strdup("The Access Token expired"); | ||
2551 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2552 | GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); | ||
2553 | GNUNET_free(authorization); | ||
2554 | GNUNET_free(client_ticket); | ||
2555 | return; | ||
2556 | } | ||
2557 | ticket_str = strtok(NULL, delimiter_db); | ||
2558 | if (NULL == ticket_str) | ||
2559 | { | ||
2560 | handle->emsg = GNUNET_strdup("invalid_token"); | ||
2561 | handle->edesc = GNUNET_strdup("The Access Token expired"); | ||
2562 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2563 | GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); | ||
2564 | GNUNET_free(authorization); | ||
2565 | GNUNET_free(client_ticket); | ||
2566 | return; | ||
2567 | } | ||
2568 | ticket = GNUNET_new(struct GNUNET_IDENTITY_PROVIDER_Ticket); | ||
2569 | if ( GNUNET_OK | ||
2570 | != GNUNET_STRINGS_string_to_data (ticket_str, | ||
2571 | strlen (ticket_str), | ||
2572 | ticket, | ||
2573 | sizeof(struct GNUNET_IDENTITY_PROVIDER_Ticket))) | ||
2574 | { | ||
2575 | handle->emsg = GNUNET_strdup("invalid_token"); | ||
2576 | handle->edesc = GNUNET_strdup("The Access Token expired"); | ||
2577 | handle->response_code = MHD_HTTP_UNAUTHORIZED; | ||
2578 | GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); | ||
2579 | GNUNET_free(ticket); | ||
2580 | GNUNET_free(authorization); | ||
2581 | GNUNET_free(client_ticket); | ||
2582 | return; | ||
2583 | } | ||
2584 | |||
2585 | handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); | ||
2586 | handle->oidc->response = json_object(); | ||
2587 | json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring)); | ||
2588 | handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume ( | ||
2589 | handle->idp, | ||
2590 | GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego), | ||
2591 | ticket, | ||
2592 | consume_ticket, | ||
2593 | handle); | ||
2594 | GNUNET_free(ticket); | ||
2595 | GNUNET_free(authorization); | ||
2596 | GNUNET_free(client_ticket); | ||
2597 | |||
2598 | } | ||
2599 | |||
2600 | |||
2601 | /** | ||
2602 | * Handle rest request | 1064 | * Handle rest request |
2603 | * | 1065 | * |
2604 | * @param handle the request handle | 1066 | * @param handle the request handle |
@@ -2611,12 +1073,6 @@ init_cont (struct RequestHandle *handle) | |||
2611 | {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont}, | 1073 | {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont}, |
2612 | {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont}, | 1074 | {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont}, |
2613 | {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont}, | 1075 | {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont}, |
2614 | {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, | ||
2615 | {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded | ||
2616 | {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont}, | ||
2617 | {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint }, | ||
2618 | {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, | ||
2619 | {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint }, | ||
2620 | {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont}, | 1076 | {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont}, |
2621 | {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont}, | 1077 | {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont}, |
2622 | {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER, | 1078 | {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER, |
@@ -2701,15 +1157,6 @@ rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, | |||
2701 | void *proc_cls) | 1157 | void *proc_cls) |
2702 | { | 1158 | { |
2703 | struct RequestHandle *handle = GNUNET_new (struct RequestHandle); | 1159 | struct RequestHandle *handle = GNUNET_new (struct RequestHandle); |
2704 | handle->oidc = GNUNET_new (struct OIDC_Variables); | ||
2705 | if ( NULL == OIDC_identity_login_time ) | ||
2706 | OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); | ||
2707 | if ( NULL == OIDC_identity_grants ) | ||
2708 | OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); | ||
2709 | if ( NULL == OIDC_ticket_once ) | ||
2710 | OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); | ||
2711 | if ( NULL == OIDC_interpret_access_token ) | ||
2712 | OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); | ||
2713 | handle->response_code = 0; | 1160 | handle->response_code = 0; |
2714 | handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; | 1161 | handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; |
2715 | handle->proc_cls = proc_cls; | 1162 | handle->proc_cls = proc_cls; |
@@ -2782,42 +1229,6 @@ libgnunet_plugin_rest_identity_provider_done (void *cls) | |||
2782 | struct Plugin *plugin = api->cls; | 1229 | struct Plugin *plugin = api->cls; |
2783 | plugin->cfg = NULL; | 1230 | plugin->cfg = NULL; |
2784 | 1231 | ||
2785 | struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it; | ||
2786 | void *value = NULL; | ||
2787 | hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create ( | ||
2788 | OIDC_identity_login_time); | ||
2789 | while (GNUNET_YES == | ||
2790 | GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) | ||
2791 | { | ||
2792 | if (NULL != value) | ||
2793 | GNUNET_free(value); | ||
2794 | } | ||
2795 | GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time); | ||
2796 | hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants); | ||
2797 | while (GNUNET_YES == | ||
2798 | GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) | ||
2799 | { | ||
2800 | if (NULL != value) | ||
2801 | GNUNET_free(value); | ||
2802 | } | ||
2803 | GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants); | ||
2804 | hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once); | ||
2805 | while (GNUNET_YES == | ||
2806 | GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) | ||
2807 | { | ||
2808 | if (NULL != value) | ||
2809 | GNUNET_free(value); | ||
2810 | } | ||
2811 | GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once); | ||
2812 | hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token); | ||
2813 | while (GNUNET_YES == | ||
2814 | GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value)) | ||
2815 | { | ||
2816 | if (NULL != value) | ||
2817 | GNUNET_free(value); | ||
2818 | } | ||
2819 | GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token); | ||
2820 | GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it); | ||
2821 | GNUNET_free_non_null (allow_methods); | 1232 | GNUNET_free_non_null (allow_methods); |
2822 | GNUNET_free (api); | 1233 | GNUNET_free (api); |
2823 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1234 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |