aboutsummaryrefslogtreecommitdiff
path: root/src/identity-provider
diff options
context:
space:
mode:
Diffstat (limited to 'src/identity-provider')
-rw-r--r--src/identity-provider/plugin_rest_identity_provider.c1235
-rw-r--r--src/identity-provider/test_idp.conf5
2 files changed, 1228 insertions, 12 deletions
diff --git a/src/identity-provider/plugin_rest_identity_provider.c b/src/identity-provider/plugin_rest_identity_provider.c
index 6eb856435..ca42cc50c 100644
--- a/src/identity-provider/plugin_rest_identity_provider.c
+++ b/src/identity-provider/plugin_rest_identity_provider.c
@@ -66,6 +66,21 @@
66#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume" 66#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume"
67 67
68/** 68/**
69 * Authorize endpoint
70 */
71#define GNUNET_REST_API_NS_AUTHORIZE "/idp/authorize"
72
73/**
74 * Token endpoint
75 */
76#define GNUNET_REST_API_NS_TOKEN "/idp/token"
77
78/**
79 * Login namespace
80 */
81#define GNUNET_REST_API_NS_LOGIN "/idp/login"
82
83/**
69 * Attribute key 84 * Attribute key
70 */ 85 */
71#define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute" 86#define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
@@ -91,6 +106,86 @@
91 */ 106 */
92#define ID_REST_STATE_POST_INIT 1 107#define ID_REST_STATE_POST_INIT 1
93 108
109/**
110 * OIDC response_type key
111 */
112#define OIDC_RESPONSE_TYPE_KEY "response_type"
113
114/**
115 * OIDC client_id key
116 */
117#define OIDC_CLIENT_ID_KEY "client_id"
118
119/**
120 * OIDC scope key
121 */
122#define OIDC_SCOPE_KEY "scope"
123
124/**
125 * OIDC redirect_uri key
126 */
127#define OIDC_REDIRECT_URI_KEY "redirect_uri"
128
129/**
130 * OIDC state key
131 */
132#define OIDC_STATE_KEY "state"
133
134/**
135 * OIDC nonce key
136 */
137#define OIDC_NONCE_KEY "nonce"
138
139/**
140 * OIDC cookie header key
141 */
142#define OIDC_COOKIE_HEADER_KEY "Cookie"
143
144/**
145 * OIDC cookie header information key
146 */
147#define OIDC_AUTHORIZATION_HEADER_KEY "Authorization"
148
149
150/**
151 * OIDC cookie header information key
152 */
153#define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
154
155/**
156 * OIDC expected response_type while authorizing
157 */
158#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
159
160/**
161 * OIDC expected scope part while authorizing
162 */
163#define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
164
165/**
166 * OIDC ignored parameter array
167 */
168char* OIDC_ignored_parameter_array [] =
169{
170 "display",
171 "prompt",
172 "max_age",
173 "ui_locales",
174 "response_mode",
175 "id_token_hint",
176 "login_hint",
177 "acr_values"
178};
179
180/**
181 * OIDC authorized identities and times hashmap
182 */
183struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
184
185/**
186 * OIDC authorized identities and times hashmap
187 */
188struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants;
94 189
95/** 190/**
96 * The configuration handle 191 * The configuration handle
@@ -110,6 +205,30 @@ struct Plugin
110 const struct GNUNET_CONFIGURATION_Handle *cfg; 205 const struct GNUNET_CONFIGURATION_Handle *cfg;
111}; 206};
112 207
208struct OIDC_Variables
209{
210
211 struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
212
213 char *client_id;
214
215 int is_client_trusted;
216
217 char *redirect_uri;
218
219 char *scope;
220
221 char *state;
222
223 char *nonce;
224
225 char *response_type;
226
227 char *login_identity;
228
229 json_t *post_object;
230};
231
113/** 232/**
114 * The ego list 233 * The ego list
115 */ 234 */
@@ -160,9 +279,14 @@ struct RequestHandle
160 struct EgoEntry *ego_entry; 279 struct EgoEntry *ego_entry;
161 280
162 /** 281 /**
163 * Ptr to current ego private key 282 * Pointer to ego private key
164 */ 283 */
165 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; 284 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
285
286 /**
287 * OIDC variables
288 */
289 struct OIDC_Variables *oidc;
166 290
167 /** 291 /**
168 * The processing state 292 * The processing state
@@ -179,6 +303,20 @@ struct RequestHandle
179 */ 303 */
180 struct GNUNET_REST_RequestHandle *rest_handle; 304 struct GNUNET_REST_RequestHandle *rest_handle;
181 305
306 /**
307 * Handle to NAMESTORE
308 */
309 struct GNUNET_NAMESTORE_Handle *namestore_handle;
310
311 /**
312 * Iterator for NAMESTORE
313 */
314 struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
315
316 /**
317 * Attribute claim list
318 */
319 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list;
182 320
183 /** 321 /**
184 * IDENTITY Operation 322 * IDENTITY Operation
@@ -236,6 +374,11 @@ struct RequestHandle
236 char *emsg; 374 char *emsg;
237 375
238 /** 376 /**
377 * Error response description
378 */
379 char *edesc;
380
381 /**
239 * Reponse code 382 * Reponse code
240 */ 383 */
241 int response_code; 384 int response_code;
@@ -247,8 +390,6 @@ struct RequestHandle
247 390
248}; 391};
249 392
250
251
252/** 393/**
253 * Cleanup lookup handle 394 * Cleanup lookup handle
254 * @param handle Handle to clean up 395 * @param handle Handle to clean up
@@ -256,6 +397,8 @@ struct RequestHandle
256static void 397static void
257cleanup_handle (struct RequestHandle *handle) 398cleanup_handle (struct RequestHandle *handle)
258{ 399{
400 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_entry;
401 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_tmp;
259 struct EgoEntry *ego_entry; 402 struct EgoEntry *ego_entry;
260 struct EgoEntry *ego_tmp; 403 struct EgoEntry *ego_tmp;
261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -276,6 +419,42 @@ cleanup_handle (struct RequestHandle *handle)
276 GNUNET_free (handle->url); 419 GNUNET_free (handle->url);
277 if (NULL != handle->emsg) 420 if (NULL != handle->emsg)
278 GNUNET_free (handle->emsg); 421 GNUNET_free (handle->emsg);
422 if (NULL != handle->edesc)
423 GNUNET_free (handle->edesc);
424 if (NULL != handle->namestore_handle)
425 GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
426 if (NULL != handle->oidc)
427 {
428 if (NULL != handle->oidc->client_id)
429 GNUNET_free(handle->oidc->client_id);
430 if (NULL != handle->oidc->login_identity)
431 GNUNET_free(handle->oidc->login_identity);
432 if (NULL != handle->oidc->nonce)
433 GNUNET_free(handle->oidc->nonce);
434 if (NULL != handle->oidc->redirect_uri)
435 GNUNET_free(handle->oidc->redirect_uri);
436 if (NULL != handle->oidc->response_type)
437 GNUNET_free(handle->oidc->response_type);
438 if (NULL != handle->oidc->scope)
439 GNUNET_free(handle->oidc->scope);
440 if (NULL != handle->oidc->state)
441 GNUNET_free(handle->oidc->state);
442 if (NULL != handle->oidc->post_object)
443 json_decref(handle->oidc->post_object);
444 GNUNET_free(handle->oidc);
445 }
446 if ( NULL != handle->attr_list )
447 {
448 for (claim_entry = handle->attr_list->list_head;
449 NULL != claim_entry;)
450 {
451 claim_tmp = claim_entry;
452 claim_entry = claim_entry->next;
453 GNUNET_free(claim_tmp->claim);
454 GNUNET_free(claim_tmp);
455 }
456 GNUNET_free (handle->attr_list);
457 }
279 for (ego_entry = handle->ego_head; 458 for (ego_entry = handle->ego_head;
280 NULL != ego_entry;) 459 NULL != ego_entry;)
281 { 460 {
@@ -285,6 +464,10 @@ cleanup_handle (struct RequestHandle *handle)
285 GNUNET_free (ego_tmp->keystring); 464 GNUNET_free (ego_tmp->keystring);
286 GNUNET_free (ego_tmp); 465 GNUNET_free (ego_tmp);
287 } 466 }
467 if (NULL != handle->attr_it)
468 {
469 GNUNET_free(handle->attr_it);
470 }
288 GNUNET_free (handle); 471 GNUNET_free (handle);
289} 472}
290 473
@@ -307,16 +490,46 @@ do_error (void *cls)
307 struct MHD_Response *resp; 490 struct MHD_Response *resp;
308 char *json_error; 491 char *json_error;
309 492
310 GNUNET_asprintf (&json_error, 493 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
311 "{Error while processing request: %s}", 494 handle->emsg,
312 handle->emsg); 495 (NULL != handle->edesc) ? handle->edesc : "",
496 (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
497 (NULL != handle->oidc->state) ? handle->oidc->state : "",
498 (NULL != handle->oidc->state) ? "\"" : "");
499 if ( 0 == handle->response_code )
500 {
501 handle->response_code = MHD_HTTP_BAD_REQUEST;
502 }
313 resp = GNUNET_REST_create_response (json_error); 503 resp = GNUNET_REST_create_response (json_error);
314 handle->proc (handle->proc_cls, resp, handle->response_code); 504 handle->proc (handle->proc_cls, resp, handle->response_code);
315 cleanup_handle (handle); 505 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
316 GNUNET_free (json_error); 506 GNUNET_free (json_error);
317} 507}
318 508
319/** 509/**
510 * Task run on error, sends error message. Cleans up everything.
511 *
512 * @param cls the `struct RequestHandle`
513 */
514static void
515do_redirect_error (void *cls)
516{
517 struct RequestHandle *handle = cls;
518 struct MHD_Response *resp;
519 char* redirect;
520 GNUNET_asprintf (&redirect,
521 "%s?error=%s&error_description=%s%s%s",
522 handle->oidc->redirect_uri, handle->emsg, handle->edesc,
523 (NULL != handle->oidc->state) ? "&state=" : "",
524 (NULL != handle->oidc->state) ? handle->oidc->state : "");
525 resp = GNUNET_REST_create_response ("");
526 MHD_add_response_header (resp, "Location", redirect);
527 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
528 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
529 GNUNET_free (redirect);
530}
531
532/**
320 * Task run on timeout, sends error message. Cleans up everything. 533 * Task run on timeout, sends error message. Cleans up everything.
321 * 534 *
322 * @param cls the `struct RequestHandle` 535 * @param cls the `struct RequestHandle`
@@ -625,6 +838,7 @@ attr_collect (void *cls,
625 struct GNUNET_JSONAPI_Resource *json_resource; 838 struct GNUNET_JSONAPI_Resource *json_resource;
626 struct RequestHandle *handle = cls; 839 struct RequestHandle *handle = cls;
627 json_t *value; 840 json_t *value;
841 char* tmp_value;
628 842
629 if ((NULL == attr->name) || (NULL == attr->data)) 843 if ((NULL == attr->name) || (NULL == attr->data))
630 { 844 {
@@ -638,11 +852,17 @@ attr_collect (void *cls,
638 attr->name); 852 attr->name);
639 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); 853 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
640 854
641 value = json_string (attr->data); 855 tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type,
856 attr->data,
857 attr->data_size);
858
859 value = json_string (tmp_value);
860
642 GNUNET_JSONAPI_resource_add_attr (json_resource, 861 GNUNET_JSONAPI_resource_add_attr (json_resource,
643 "value", 862 "value",
644 value); 863 value);
645 json_decref (value); 864 json_decref (value);
865 GNUNET_free(tmp_value);
646 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it); 866 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
647} 867}
648 868
@@ -1013,6 +1233,970 @@ options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1013} 1233}
1014 1234
1015/** 1235/**
1236 * Cookie interpretation
1237 */
1238static void
1239cookie_identity_interpretation (struct RequestHandle *handle)
1240{
1241 struct GNUNET_HashCode cache_key;
1242 char* cookies;
1243 struct GNUNET_TIME_Absolute current_time, *relog_time;
1244 char delimiter[] = "; ";
1245
1246 //gets identity of login try with cookie
1247 GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
1248 &cache_key);
1249 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
1250 &cache_key) )
1251 {
1252 //splits cookies and find 'Identity' cookie
1253 cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
1254 handle->oidc->login_identity = strtok(cookies, delimiter);
1255
1256 while ( NULL != handle->oidc->login_identity )
1257 {
1258 if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
1259 {
1260 break;
1261 }
1262 handle->oidc->login_identity = strtok (NULL, delimiter);
1263 }
1264 GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity),
1265 &cache_key);
1266 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) )
1267 {
1268 relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
1269 &cache_key);
1270 current_time = GNUNET_TIME_absolute_get ();
1271 // 30 min after old login -> redirect to login
1272 if ( current_time.abs_value_us <= relog_time->abs_value_us )
1273 {
1274 handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY);
1275 handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity);
1276 }
1277 }
1278 else
1279 {
1280 handle->oidc->login_identity = NULL;
1281 }
1282 }
1283}
1284
1285/**
1286 * Login redirection
1287 */
1288static void
1289login_redirection(void *cls)
1290{
1291 char *login_base_url;
1292 char *new_redirect;
1293 struct MHD_Response *resp;
1294 struct RequestHandle *handle = cls;
1295
1296 if ( GNUNET_OK
1297 == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
1298 "address", &login_base_url) )
1299 {
1300 GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
1301 login_base_url,
1302 OIDC_RESPONSE_TYPE_KEY,
1303 handle->oidc->response_type,
1304 OIDC_CLIENT_ID_KEY,
1305 handle->oidc->client_id,
1306 OIDC_REDIRECT_URI_KEY,
1307 handle->oidc->redirect_uri,
1308 OIDC_SCOPE_KEY,
1309 handle->oidc->scope,
1310 OIDC_STATE_KEY,
1311 (NULL != handle->oidc->state) ? handle->oidc->state : "",
1312 OIDC_NONCE_KEY,
1313 (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
1314 resp = GNUNET_REST_create_response ("");
1315 MHD_add_response_header (resp, "Location", new_redirect);
1316 GNUNET_free(login_base_url);
1317 }
1318 else
1319 {
1320 handle->emsg = GNUNET_strdup("server_error");
1321 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1322 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1323 GNUNET_SCHEDULER_add_now (&do_error, handle);
1324 return;
1325 }
1326 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1327 GNUNET_free(new_redirect);
1328 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1329}
1330
1331/**
1332 * Function called if we had an error in zone-to-name mapping.
1333 */
1334static void
1335oidc_iteration_error (void *cls)
1336{
1337 struct RequestHandle *handle = cls;
1338 handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR");
1339 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1340 GNUNET_SCHEDULER_add_now (&do_error, handle);
1341}
1342
1343static void
1344oidc_ticket_issue_cb (void* cls,
1345 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
1346{
1347 struct RequestHandle *handle = cls;
1348 struct MHD_Response *resp;
1349 struct GNUNET_HashCode cache_key;
1350 char* ticket_str;
1351 char* redirect_uri;
1352 char* jwt;
1353 handle->idp_op = NULL;
1354 resp = GNUNET_REST_create_response ("");
1355 if (NULL != ticket) {
1356 ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket,
1357 sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket));
1358
1359
1360 //TODO Check if this is right:
1361// GNUNET_CRYPTO_hash (ticket_str, strlen (ticket_str), &cache_key);
1362// jwt = jwt_create_from_list (handle->oidc->client_pkey,
1363// handle->attr_list,
1364// handle->priv_key);
1365// //TODO Check success of function
1366// GNUNET_CONTAINER_multihashmap_put (
1367// OIDC_identity_grants, &cache_key, jwt,
1368// GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1369
1370
1371 GNUNET_asprintf (&redirect_uri, "%s?%s=%s&state=%s",
1372 handle->oidc->redirect_uri,
1373 handle->oidc->response_type,
1374 ticket_str, handle->oidc->state);
1375 MHD_add_response_header (resp, "Location", redirect_uri);
1376 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1377 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1378 GNUNET_free (redirect_uri);
1379 GNUNET_free (ticket_str);
1380 return;
1381 }
1382 handle->emsg = GNUNET_strdup("server_error");
1383 handle->edesc = GNUNET_strdup("Server cannot generate ticket.");
1384 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1385}
1386
1387static void
1388oidc_collect_finished_cb (void *cls)
1389{
1390 struct RequestHandle *handle = cls;
1391 handle->attr_it = NULL;
1392 handle->ticket_it = NULL;
1393 if (NULL == handle->attr_list->list_head)
1394 {
1395 handle->emsg = GNUNET_strdup("invalid_scope");
1396 handle->edesc = GNUNET_strdup("The requested scope is not available.");
1397 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1398 return;
1399 }
1400 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_issue (handle->idp,
1401 &handle->priv_key,
1402 &handle->oidc->client_pkey,
1403 handle->attr_list,
1404 &oidc_ticket_issue_cb,
1405 handle);
1406}
1407
1408
1409/**
1410 * Collect all attributes for an ego
1411 */
1412static void
1413oidc_attr_collect (void *cls,
1414 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1415 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
1416{
1417 struct RequestHandle *handle = cls;
1418 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
1419 char* scope_variables;
1420 char* scope_variable;
1421 char delimiter[]=" ";
1422
1423 if ( (NULL == attr->name) || (NULL == attr->data) )
1424 {
1425 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1426 return;
1427 }
1428
1429 scope_variables = GNUNET_strdup(handle->oidc->scope);
1430 scope_variable = strtok (scope_variables, delimiter);
1431 while (NULL != scope_variable)
1432 {
1433 if ( 0 == strcmp (attr->name, scope_variable) )
1434 {
1435 break;
1436 }
1437 scope_variable = strtok (NULL, delimiter);
1438 }
1439 if ( NULL == scope_variable )
1440 {
1441 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1442 return;
1443 }
1444 GNUNET_free(scope_variables);
1445
1446 le = GNUNET_new(struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry);
1447 le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr->name, attr->type,
1448 attr->data, attr->data_size);
1449 GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head,
1450 handle->attr_list->list_tail, le);
1451 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1452}
1453
1454
1455/**
1456 * Cookie and Time check
1457 */
1458static void
1459login_check (void *cls)
1460{
1461 struct RequestHandle *handle = cls;
1462 struct GNUNET_TIME_Absolute current_time, *relog_time;
1463 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey;
1464 struct GNUNET_HashCode cache_key;
1465 char *identity_cookie;
1466
1467 GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity);
1468 GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1469 GNUNET_free(identity_cookie);
1470 //No login time for identity -> redirect to login
1471 if ( GNUNET_YES
1472 == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time,
1473 &cache_key) )
1474 {
1475 relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
1476 &cache_key);
1477 current_time = GNUNET_TIME_absolute_get ();
1478 // 30 min after old login -> redirect to login
1479 if ( current_time.abs_value_us <= relog_time->abs_value_us )
1480 {
1481 if ( GNUNET_OK
1482 != GNUNET_CRYPTO_ecdsa_public_key_from_string (
1483 handle->oidc->login_identity,
1484 strlen (handle->oidc->login_identity), &pubkey) )
1485 {
1486 handle->emsg = GNUNET_strdup("invalid_cookie");
1487 handle->edesc = GNUNET_strdup(
1488 "The cookie of a login identity is not valid");
1489 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1490 return;
1491 }
1492 // iterate over egos and compare their public key
1493 for (handle->ego_entry = handle->ego_head;
1494 NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
1495 {
1496 GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1497 if ( 0
1498 == memcmp (&ego_pkey, &pubkey,
1499 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1500 {
1501 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (
1502 handle->ego_entry->ego);
1503 handle->resp_object = GNUNET_JSONAPI_document_new ();
1504 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1505 handle->attr_list = GNUNET_new(
1506 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList);
1507 handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (
1508 handle->idp, &handle->priv_key, &oidc_iteration_error, handle,
1509 &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle);
1510 return;
1511 }
1512 }
1513 handle->emsg = GNUNET_strdup("invalid_cookie");
1514 handle->edesc = GNUNET_strdup(
1515 "The cookie of the login identity is not valid");
1516 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1517 return;
1518 }
1519 //GNUNET_free(relog_time);
1520 }
1521}
1522
1523/**
1524 * Create a response with requested records
1525 *
1526 * @param handle the RequestHandle
1527 */
1528static void
1529namestore_iteration_callback (
1530 void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1531 const char *rname, unsigned int rd_len,
1532 const struct GNUNET_GNSRECORD_Data *rd)
1533{
1534 struct RequestHandle *handle = cls;
1535 struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey;
1536 struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey;
1537 int i;
1538
1539 for (i = 0; i < rd_len; i++)
1540 {
1541 if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type )
1542 continue;
1543
1544 if ( NULL != handle->oidc->login_identity )
1545 {
1546 GNUNET_CRYPTO_ecdsa_public_key_from_string (
1547 handle->oidc->login_identity,
1548 strlen (handle->oidc->login_identity),
1549 &login_identity_pkey);
1550 GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego,
1551 &current_zone_pkey);
1552
1553 if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1554 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1555 {
1556 if ( 0 == memcmp (&login_identity_pkey, &current_zone_pkey,
1557 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1558 {
1559 handle->oidc->is_client_trusted = GNUNET_YES;
1560 }
1561 }
1562 }
1563 else
1564 {
1565 if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1566 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1567 {
1568 handle->oidc->is_client_trusted = GNUNET_YES;
1569 }
1570 }
1571 }
1572
1573 GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it);
1574}
1575
1576/**
1577 * Iteration over all results finished, build final
1578 * response.
1579 *
1580 * @param cls the `struct RequestHandle`
1581 */
1582static void namestore_iteration_finished_GET (void *cls)
1583{
1584 struct RequestHandle *handle = cls;
1585 struct GNUNET_HashCode cache_key;
1586
1587 char *expected_redirect_uri;
1588 char *expected_scope;
1589 char delimiter[]=" ";
1590 int number_of_ignored_parameter, iterator;
1591
1592
1593 handle->ego_entry = handle->ego_entry->next;
1594
1595 if(NULL != handle->ego_entry)
1596 {
1597 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1598 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
1599 &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
1600 &namestore_iteration_finished_GET, handle);
1601 return;
1602 }
1603 if (GNUNET_NO == handle->oidc->is_client_trusted)
1604 {
1605 handle->emsg = GNUNET_strdup("unauthorized_client");
1606 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1607 "authorization code using this method.");
1608 GNUNET_SCHEDULER_add_now (&do_error, handle);
1609 return;
1610 }
1611
1612 // REQUIRED value: redirect_uri
1613 GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1614 &cache_key);
1615 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1616 &cache_key))
1617 {
1618 handle->emsg=GNUNET_strdup("invalid_request");
1619 handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
1620 GNUNET_SCHEDULER_add_now (&do_error, handle);
1621 return;
1622 }
1623 handle->oidc->redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1624 &cache_key);
1625
1626 GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
1627 // verify the redirect uri matches https://<client_id>.zkey[/xyz]
1628 if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
1629 {
1630 handle->emsg=GNUNET_strdup("invalid_request");
1631 handle->edesc=GNUNET_strdup("Invalid redirect_uri");
1632 GNUNET_SCHEDULER_add_now (&do_error, handle);
1633 GNUNET_free(expected_redirect_uri);
1634 return;
1635 }
1636 handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
1637
1638 GNUNET_free(expected_redirect_uri);
1639 // REQUIRED value: response_type
1640 GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1641 &cache_key);
1642 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1643 &cache_key))
1644 {
1645 handle->emsg=GNUNET_strdup("invalid_request");
1646 handle->edesc=GNUNET_strdup("missing parameter response_type");
1647 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1648 return;
1649 }
1650 handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1651 &cache_key);
1652 handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
1653
1654 // REQUIRED value: scope
1655 GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
1656 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1657 &cache_key))
1658 {
1659 handle->emsg=GNUNET_strdup("invalid_request");
1660 handle->edesc=GNUNET_strdup("missing parameter scope");
1661 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1662 return;
1663 }
1664 handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1665 &cache_key);
1666 handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
1667
1668 //OPTIONAL value: nonce
1669 GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
1670 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1671 &cache_key))
1672 {
1673 handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1674 &cache_key);
1675 //TODO: what do we do with the nonce?
1676 handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
1677 }
1678
1679 //TODO check other values and use them accordingly
1680 number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1681 for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1682 {
1683 GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1684 strlen(OIDC_ignored_parameter_array[iterator]),
1685 &cache_key);
1686 if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
1687 &cache_key))
1688 {
1689 handle->emsg=GNUNET_strdup("access_denied");
1690 GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1691 OIDC_ignored_parameter_array[iterator]);
1692 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1693 return;
1694 }
1695 }
1696
1697 // Checks if response_type is 'code'
1698 if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1699 {
1700 handle->emsg=GNUNET_strdup("unsupported_response_type");
1701 handle->edesc=GNUNET_strdup("The authorization server does not support "
1702 "obtaining this authorization code.");
1703 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1704 return;
1705 }
1706
1707 // Checks if scope contains 'openid'
1708 expected_scope = GNUNET_strdup(handle->oidc->scope);
1709 expected_scope = strtok (expected_scope, delimiter);
1710 while (NULL != expected_scope)
1711 {
1712 if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1713 {
1714 break;
1715 }
1716 expected_scope = strtok (NULL, delimiter);
1717 }
1718 if (NULL == expected_scope)
1719 {
1720 handle->emsg = GNUNET_strdup("invalid_scope");
1721 handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1722 "malformed.");
1723 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1724 return;
1725 }
1726
1727 GNUNET_free(expected_scope);
1728
1729 if( NULL != handle->oidc->login_identity )
1730 {
1731 GNUNET_SCHEDULER_add_now(&login_check,handle);
1732 return;
1733 }
1734
1735 GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1736}
1737
1738/**
1739 * Responds to authorization GET request
1740 *
1741 * @param con_handle the connection handle
1742 * @param url the url
1743 * @param cls the RequestHandle
1744 */
1745static void
1746authorize_GET_cont (struct GNUNET_REST_RequestHandle *con_handle,
1747 const char* url,
1748 void *cls)
1749{
1750 struct RequestHandle *handle = cls;
1751 struct GNUNET_HashCode cache_key;
1752
1753 cookie_identity_interpretation(handle);
1754
1755 //RECOMMENDED value: state - REQUIRED for answers
1756 GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
1757 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1758 &cache_key))
1759 {
1760 handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1761 &cache_key);
1762 handle->oidc->state = GNUNET_strdup (handle->oidc->state);
1763 }
1764
1765 // REQUIRED value: client_id
1766 GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1767 &cache_key);
1768 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1769 &cache_key))
1770 {
1771 handle->emsg=GNUNET_strdup("invalid_request");
1772 handle->edesc=GNUNET_strdup("missing parameter client_id");
1773 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1774 GNUNET_SCHEDULER_add_now (&do_error, handle);
1775 return;
1776 }
1777 handle->oidc->client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1778 &cache_key);
1779 handle->oidc->client_id = GNUNET_strdup (handle->oidc->client_id);
1780
1781 if ( GNUNET_OK
1782 != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
1783 strlen (handle->oidc->client_id),
1784 &handle->oidc->client_pkey) )
1785 {
1786 handle->emsg = GNUNET_strdup("unauthorized_client");
1787 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1788 "authorization code using this method.");
1789 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1790 GNUNET_SCHEDULER_add_now (&do_error, handle);
1791 return;
1792 }
1793
1794
1795 if ( NULL == handle->ego_head )
1796 {
1797 //TODO throw error or ignore if egos are missing?
1798 handle->emsg = GNUNET_strdup("server_error");
1799 handle->edesc = GNUNET_strdup ("Egos are missing");
1800 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1801 GNUNET_SCHEDULER_add_now (&do_error, handle);
1802 return;
1803 }
1804
1805 handle->ego_entry = handle->ego_head;
1806 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
1807 handle->oidc->is_client_trusted = GNUNET_NO;
1808
1809 // Checks if client_id is valid:
1810 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
1811 handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
1812 handle, &namestore_iteration_callback, handle,
1813 &namestore_iteration_finished_GET, handle);
1814}
1815
1816/**
1817 * Iteration over all results finished, build final
1818 * response.
1819 *
1820 * @param cls the `struct RequestHandle`
1821 */
1822static void namestore_iteration_finished_POST (void *cls)
1823{
1824 struct RequestHandle *handle = cls;
1825 json_t *cache_object;
1826 char *expected_redirect_uri;
1827 char *expected_scope;
1828 char delimiter[]=" ";
1829 int number_of_ignored_parameter, iterator;
1830
1831
1832 handle->ego_entry = handle->ego_entry->next;
1833
1834 if(NULL != handle->ego_entry){
1835 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1836 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
1837 &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
1838 &namestore_iteration_finished_POST, handle);
1839 return;
1840 }
1841 if (GNUNET_YES != handle->oidc->is_client_trusted)
1842 {
1843 handle->emsg = GNUNET_strdup("unauthorized_client");
1844 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1845 "authorization code using this method.");
1846 GNUNET_SCHEDULER_add_now (&do_error, handle);
1847 return;
1848 }
1849
1850 // REQUIRED value: redirect_uri
1851 cache_object = json_object_get (handle->oidc->post_object, OIDC_REDIRECT_URI_KEY);
1852 if ( NULL == cache_object || !json_is_string(cache_object) )
1853 {
1854 handle->emsg=GNUNET_strdup("invalid_request");
1855 handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
1856 GNUNET_SCHEDULER_add_now (&do_error, handle);
1857 return;
1858 }
1859 handle->oidc->redirect_uri = json_string_value (cache_object);
1860
1861 GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
1862 // verify the redirect uri matches https://<client_id>.zkey[/xyz]
1863 if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
1864 {
1865 handle->emsg=GNUNET_strdup("invalid_request");
1866 handle->edesc=GNUNET_strdup("Invalid redirect_uri");
1867 GNUNET_SCHEDULER_add_now (&do_error, handle);
1868 GNUNET_free(expected_redirect_uri);
1869 return;
1870 }
1871 handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
1872 GNUNET_free(expected_redirect_uri);
1873
1874 // REQUIRED value: response_type
1875 cache_object = json_object_get (handle->oidc->post_object, OIDC_RESPONSE_TYPE_KEY);
1876 if ( NULL == cache_object || !json_is_string(cache_object) )
1877 {
1878 handle->emsg=GNUNET_strdup("invalid_request");
1879 handle->edesc=GNUNET_strdup("missing parameter response_type");
1880 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1881 return;
1882 }
1883 handle->oidc->response_type = json_string_value (cache_object);
1884 handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
1885
1886 // REQUIRED value: scope
1887 cache_object = json_object_get (handle->oidc->post_object, OIDC_SCOPE_KEY);
1888 if ( NULL == cache_object || !json_is_string(cache_object) )
1889 {
1890 handle->emsg=GNUNET_strdup("invalid_request");
1891 handle->edesc=GNUNET_strdup("missing parameter scope");
1892 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1893 return;
1894 }
1895 handle->oidc->scope = json_string_value (cache_object);
1896 handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
1897
1898 //OPTIONAL value: nonce
1899 cache_object = json_object_get (handle->oidc->post_object, OIDC_NONCE_KEY);
1900 if ( NULL != cache_object && json_is_string(cache_object) )
1901 {
1902 handle->oidc->nonce = json_string_value (cache_object);
1903 //TODO: what do we do with the nonce?
1904 handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
1905 }
1906
1907 //TODO check other values and use them accordingly
1908 number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1909 for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1910 {
1911 cache_object = json_object_get (handle->oidc->post_object, OIDC_ignored_parameter_array[iterator]);
1912 if( NULL != cache_object && json_is_string(cache_object) )
1913 {
1914 handle->emsg=GNUNET_strdup("access_denied");
1915 GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1916 OIDC_ignored_parameter_array[iterator]);
1917 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1918 return;
1919 }
1920 }
1921
1922 // Checks if response_type is 'code'
1923 if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1924 {
1925 handle->emsg=GNUNET_strdup("unsupported_response_type");
1926 handle->edesc=GNUNET_strdup("The authorization server does not support "
1927 "obtaining this authorization code.");
1928 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1929 return;
1930 }
1931
1932 // Checks if scope contains 'openid'
1933 expected_scope = GNUNET_strdup(handle->oidc->scope);
1934 expected_scope = strtok (expected_scope, delimiter);
1935 while (NULL != expected_scope)
1936 {
1937 if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1938 {
1939 break;
1940 }
1941 expected_scope = strtok (NULL, delimiter);
1942 }
1943 if (NULL == expected_scope)
1944 {
1945 handle->emsg = GNUNET_strdup("invalid_scope");
1946 handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1947 "malformed.");
1948 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1949 return;
1950 }
1951
1952 GNUNET_free(expected_scope);
1953
1954 if( NULL != handle->oidc->login_identity )
1955 {
1956 GNUNET_SCHEDULER_add_now(&login_check,handle);
1957 return;
1958 }
1959
1960 GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1961}
1962
1963
1964/**
1965 * Responds to authorization POST request
1966 *
1967 * @param con_handle the connection handle
1968 * @param url the url
1969 * @param cls the RequestHandle
1970 */
1971static void
1972authorize_POST_cont (struct GNUNET_REST_RequestHandle *con_handle,
1973 const char* url,
1974 void *cls)
1975{
1976 struct RequestHandle *handle = cls;
1977 json_t *cache_object;
1978 json_error_t error;
1979 handle->oidc->post_object = json_loads (handle->rest_handle->data, 0, &error);
1980
1981 //gets identity of login try with cookie
1982 cookie_identity_interpretation(handle);
1983
1984 //RECOMMENDED value: state - REQUIRED for answers
1985 cache_object = json_object_get (handle->oidc->post_object, OIDC_STATE_KEY);
1986 if ( NULL != cache_object && json_is_string(cache_object) )
1987 {
1988 handle->oidc->state = json_string_value (cache_object);
1989 handle->oidc->state = GNUNET_strdup(handle->oidc->state);
1990 }
1991
1992 // REQUIRED value: client_id
1993 cache_object = json_object_get (handle->oidc->post_object,
1994 OIDC_CLIENT_ID_KEY);
1995 if ( NULL == cache_object || !json_is_string(cache_object) )
1996 {
1997 handle->emsg = GNUNET_strdup("invalid_request");
1998 handle->edesc = GNUNET_strdup("missing parameter client_id");
1999 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2000 GNUNET_SCHEDULER_add_now (&do_error, handle);
2001 return;
2002 }
2003 handle->oidc->client_id = json_string_value (cache_object);
2004 handle->oidc->client_id = GNUNET_strdup(handle->oidc->client_id);
2005
2006 if ( GNUNET_OK
2007 != GNUNET_CRYPTO_ecdsa_public_key_from_string (
2008 handle->oidc->client_id, strlen (handle->oidc->client_id),
2009 &handle->oidc->client_pkey) )
2010 {
2011 handle->emsg = GNUNET_strdup("unauthorized_client");
2012 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
2013 "authorization code using this method.");
2014 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2015 GNUNET_SCHEDULER_add_now (&do_error, handle);
2016 return;
2017 }
2018
2019 if ( NULL == handle->ego_head )
2020 {
2021 //TODO throw error or ignore if egos are missing?
2022 handle->emsg = GNUNET_strdup("server_error");
2023 handle->edesc = GNUNET_strdup ("Egos are missing");
2024 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2025 GNUNET_SCHEDULER_add_now (&do_error, handle);
2026 return;
2027 }
2028
2029 handle->ego_entry = handle->ego_head;
2030 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
2031 handle->oidc->is_client_trusted = GNUNET_NO;
2032
2033 // Checks if client_id is valid:
2034 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
2035 handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
2036 handle, &namestore_iteration_callback, handle,
2037 &namestore_iteration_finished_POST, handle);
2038}
2039
2040/**
2041 * Combines an identity with a login time and responds OK to login request
2042 *
2043 * @param con_handle the connection handle
2044 * @param url the url
2045 * @param cls the RequestHandle
2046 */
2047static void
2048login_cont (struct GNUNET_REST_RequestHandle *con_handle,
2049 const char* url,
2050 void *cls)
2051{
2052 struct MHD_Response *resp = GNUNET_REST_create_response ("");
2053 struct RequestHandle *handle = cls;
2054 struct GNUNET_HashCode cache_key;
2055 struct GNUNET_TIME_Absolute *current_time;
2056 struct GNUNET_TIME_Absolute *last_time;
2057 char* cookie;
2058 json_t *root;
2059 json_error_t error;
2060 json_t *identity;
2061 root = json_loads (handle->rest_handle->data, 0, &error);
2062 identity = json_object_get (root, "identity");
2063 if ( json_is_string(identity) )
2064 {
2065 GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
2066
2067 GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
2068
2069 current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
2070 *current_time = GNUNET_TIME_relative_to_absolute (
2071 GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_minute_ (),
2072 30));
2073 last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key);
2074 if (NULL != last_time)
2075 {
2076 GNUNET_free(last_time);
2077 }
2078 GNUNET_CONTAINER_multihashmap_put (
2079 OIDC_identity_login_time, &cache_key, current_time,
2080 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
2081
2082 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2083 }
2084 else
2085 {
2086 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
2087 }
2088 GNUNET_free(cookie);
2089 json_decref (root);
2090 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
2091 return;
2092}
2093
2094static void
2095token_cont(struct GNUNET_REST_RequestHandle *con_handle,
2096 const char* url,
2097 void *cls)
2098{
2099 //TODO static strings
2100 struct RequestHandle *handle = cls;
2101 struct GNUNET_HashCode cache_key;
2102 char *authorization, *cache_authorization, *jwt;
2103 char delimiter[]=" ";
2104 json_t *cache_object;
2105 json_error_t error;
2106 char *grant_type, *code, *expected_jwt, *redirect_uri, *expected_redirect_uri;
2107
2108 handle->oidc->post_object = json_loads (handle->rest_handle->data, 0, &error);
2109 //Check Authorization Header
2110 GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
2111 &cache_key);
2112 if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
2113 &cache_key) )
2114 {
2115 //error
2116 }
2117 authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
2118 //split JWT in "Base" and [content]
2119 cache_authorization = GNUNET_strdup (authorization);
2120 jwt = strtok(cache_authorization,delimiter);
2121 if( NULL != jwt)
2122 {
2123 jwt = strtok(jwt, delimiter);
2124 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Test:%s\n", jwt);
2125 }
2126
2127 cache_object = json_object_get (handle->oidc->post_object, "grant_type");
2128 if ( NULL == cache_object || !json_is_string(cache_object) )
2129 {
2130 handle->emsg=GNUNET_strdup("invalid_request");
2131 handle->edesc=GNUNET_strdup("missing parameter grant_type");
2132 GNUNET_SCHEDULER_add_now (&do_error, handle);
2133 return;
2134 }
2135 grant_type = json_string_value (cache_object);
2136
2137 //Check parameter grant_type == "authorization_code"
2138 if (0 != strcmp("authorization_code", grant_type))
2139 {
2140 //error
2141 }
2142
2143 cache_object = json_object_get (handle->oidc->post_object, "code");
2144 if ( NULL == cache_object || !json_is_string(cache_object) )
2145 {
2146 handle->emsg=GNUNET_strdup("invalid_request");
2147 handle->edesc=GNUNET_strdup("missing parameter code");
2148 GNUNET_SCHEDULER_add_now (&do_error, handle);
2149 return;
2150 }
2151 code = json_string_value (cache_object);
2152
2153 // lookup code in grants_hashmap and check if [content] is same
2154 GNUNET_CRYPTO_hash(code, strlen(code), &cache_key);
2155 if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_grants, &cache_key) )
2156 {
2157 //error
2158 }
2159 expected_jwt = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_grants, &cache_key);
2160
2161 if (0 != strcmp(expected_jwt,jwt))
2162 {
2163 //error
2164 }
2165
2166 cache_object = json_object_get (handle->oidc->post_object, "redirect_uri");
2167 if ( NULL == cache_object || !json_is_string(cache_object) )
2168 {
2169 handle->emsg=GNUNET_strdup("invalid_request");
2170 handle->edesc=GNUNET_strdup("missing parameter code");
2171 GNUNET_SCHEDULER_add_now (&do_error, handle);
2172 return;
2173 }
2174 redirect_uri = json_string_value (cache_object);
2175
2176 // check redirect_uri
2177 // jwt breakdown to iss or sub
2178
2179// GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", iss);
2180// // verify the redirect uri matches https://<client_id>.zkey[/xyz]
2181// if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
2182// {
2183// handle->emsg=GNUNET_strdup("invalid_request");
2184// handle->edesc=GNUNET_strdup("Invalid redirect_uri");
2185// GNUNET_SCHEDULER_add_now (&do_error, handle);
2186// GNUNET_free(expected_redirect_uri);
2187// return;
2188// }
2189// handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
2190// GNUNET_free(expected_redirect_uri);
2191
2192
2193 //do we need the client_id?
2194
2195 GNUNET_free(cache_authorization);
2196 decref(handle->oidc->post_object);
2197}
2198
2199/**
1016 * Handle rest request 2200 * Handle rest request
1017 * 2201 *
1018 * @param handle the request handle 2202 * @param handle the request handle
@@ -1025,6 +2209,10 @@ init_cont (struct RequestHandle *handle)
1025 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont}, 2209 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
1026 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont}, 2210 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
1027 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont}, 2211 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
2212 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_GET_cont},
2213 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_POST_cont},
2214 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
2215 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_cont},
1028 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont}, 2216 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1029 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont}, 2217 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1030 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER, 2218 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
@@ -1109,7 +2297,12 @@ rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1109 void *proc_cls) 2297 void *proc_cls)
1110{ 2298{
1111 struct RequestHandle *handle = GNUNET_new (struct RequestHandle); 2299 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1112 2300 handle->oidc = GNUNET_new (struct OIDC_Variables);
2301 if ( NULL == OIDC_identity_login_time )
2302 OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2303 if ( NULL == OIDC_identity_grants )
2304 OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2305 handle->response_code = 0;
1113 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; 2306 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1114 handle->proc_cls = proc_cls; 2307 handle->proc_cls = proc_cls;
1115 handle->proc = proc; 2308 handle->proc = proc;
@@ -1124,6 +2317,7 @@ rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1124 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, 2317 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1125 &list_ego, 2318 &list_ego,
1126 handle); 2319 handle);
2320 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
1127 handle->timeout_task = 2321 handle->timeout_task =
1128 GNUNET_SCHEDULER_add_delayed (handle->timeout, 2322 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1129 &do_timeout, 2323 &do_timeout,
@@ -1178,8 +2372,27 @@ libgnunet_plugin_rest_identity_provider_done (void *cls)
1178{ 2372{
1179 struct GNUNET_REST_Plugin *api = cls; 2373 struct GNUNET_REST_Plugin *api = cls;
1180 struct Plugin *plugin = api->cls; 2374 struct Plugin *plugin = api->cls;
1181
1182 plugin->cfg = NULL; 2375 plugin->cfg = NULL;
2376
2377 struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2378 void *value = NULL;
2379 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
2380 OIDC_identity_login_time);
2381 while (GNUNET_YES ==
2382 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2383 {
2384 if (NULL != value)
2385 GNUNET_free(value);
2386 }
2387 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time);
2388 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants);
2389 while (GNUNET_YES ==
2390 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2391 {
2392 if (NULL != value)
2393 GNUNET_free(value);
2394 }
2395 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
1183 GNUNET_free_non_null (allow_methods); 2396 GNUNET_free_non_null (allow_methods);
1184 GNUNET_free (api); 2397 GNUNET_free (api);
1185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
diff --git a/src/identity-provider/test_idp.conf b/src/identity-provider/test_idp.conf
index 2b76c7bf2..95111df3e 100644
--- a/src/identity-provider/test_idp.conf
+++ b/src/identity-provider/test_idp.conf
@@ -8,7 +8,7 @@ AUTOSTART = YES
8 8
9[rest] 9[rest]
10AUTOSTART = YES 10AUTOSTART = YES
11#PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/restlog 11PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/restlog
12 12
13[transport] 13[transport]
14PLUGINS = 14PLUGINS =
@@ -26,3 +26,6 @@ DEFAULT_LOOKUP_TIMEOUT = 15 s
26RECORD_PUT_INTERVAL = 1 h 26RECORD_PUT_INTERVAL = 1 h
27ZONE_PUBLISH_TIME_WINDOW = 1 h 27ZONE_PUBLISH_TIME_WINDOW = 1 h
28DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0 28DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
29
30[identity-rest-plugin]
31address = http://localhost:8000/#/identities \ No newline at end of file