aboutsummaryrefslogtreecommitdiff
path: root/src/identity-provider/plugin_rest_identity_provider.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/identity-provider/plugin_rest_identity_provider.c')
-rw-r--r--src/identity-provider/plugin_rest_identity_provider.c1593
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 */
189char* 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 */
204struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
205
206/**
207 * OIDC authorized identities and times hashmap
208 */
209struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants;
210
211/**
212 * OIDC ticket/code use only once
213 */
214struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once;
215
216/**
217 * OIDC access_token to ticket and ego
218 */
219struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token;
220
221/**
222 * The configuration handle 96 * The configuration handle
223 */ 97 */
224const struct GNUNET_CONFIGURATION_Handle *cfg; 98const struct GNUNET_CONFIGURATION_Handle *cfg;
@@ -237,34 +111,6 @@ struct Plugin
237}; 111};
238 112
239/** 113/**
240 * OIDC needed variables
241 */
242struct 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 */
270struct EgoEntry 116struct 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 */
568static void
569do_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 */
591static void
592do_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 */
676static void
677return_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 */
697static char*
698base_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
711static void 423static void
712collect_finished_cb (void *cls) 424collect_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 */
1354static void
1355cookie_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 */
1404static void
1405login_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 */
1450static void
1451oidc_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
1459static 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
1511static void
1512get_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 */
1525static void
1526oidc_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
1547static void
1548oidc_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 */
1572static void
1573oidc_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 */
1619static void
1620login_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 */
1689static void
1690namestore_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 &current_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, &current_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 */
1743static 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 */
1893static void
1894authorize_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 */
1988static void
1989login_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 */
2046static void
2047token_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 */
2434static void
2435consume_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 */
2459static void
2460userinfo_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,