2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @author Martin Schanzenbach
22 * @file identity/plugin_rest_identity.c
23 * @brief GNUnet Namestore REST plugin
28 #include "gnunet_rest_plugin.h"
29 #include "gnunet_identity_service.h"
30 #include "gnunet_gns_service.h"
31 #include "gnunet_gnsrecord_lib.h"
32 #include "gnunet_namestore_service.h"
33 #include "gnunet_rest_lib.h"
34 #include "gnunet_jsonapi_lib.h"
35 #include "gnunet_jsonapi_util.h"
36 #include "microhttpd.h"
39 #include "gnunet_signatures.h"
40 #include "gnunet_identity_attribute_lib.h"
41 #include "gnunet_identity_provider_service.h"
47 #define GNUNET_REST_API_NS_IDENTITY_PROVIDER "/idp"
52 #define GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES "/idp/attributes"
57 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/idp/tickets"
62 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/idp/revoke"
67 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume"
72 #define GNUNET_REST_API_NS_AUTHORIZE "/idp/authorize"
77 #define GNUNET_REST_API_NS_TOKEN "/idp/token"
82 #define GNUNET_REST_API_NS_USERINFO "/idp/userinfo"
87 #define GNUNET_REST_API_NS_LOGIN "/idp/login"
92 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
97 #define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
103 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value"
106 * State while collecting all egos
108 #define ID_REST_STATE_INIT 0
111 * Done collecting egos
113 #define ID_REST_STATE_POST_INIT 1
116 * OIDC grant_type key
118 #define OIDC_GRANT_TYPE_KEY "grant_type"
121 * OIDC grant_type key
123 #define OIDC_GRANT_TYPE_VALUE "authorization_code"
128 #define OIDC_CODE_KEY "code"
131 * OIDC response_type key
133 #define OIDC_RESPONSE_TYPE_KEY "response_type"
138 #define OIDC_CLIENT_ID_KEY "client_id"
143 #define OIDC_SCOPE_KEY "scope"
146 * OIDC redirect_uri key
148 #define OIDC_REDIRECT_URI_KEY "redirect_uri"
153 #define OIDC_STATE_KEY "state"
158 #define OIDC_NONCE_KEY "nonce"
161 * OIDC cookie header key
163 #define OIDC_COOKIE_HEADER_KEY "Cookie"
166 * OIDC cookie header information key
168 #define OIDC_AUTHORIZATION_HEADER_KEY "Authorization"
171 * OIDC cookie header information key
173 #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
176 * OIDC expected response_type while authorizing
178 #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
181 * OIDC expected scope part while authorizing
183 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
186 * OIDC ignored parameter array
188 char* OIDC_ignored_parameter_array [] =
201 * OIDC authorized identities and times hashmap
203 struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
206 * OIDC authorized identities and times hashmap
208 struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants;
211 * OIDC ticket/code use only once
213 struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once;
216 * OIDC access_token to ticket and ego
218 struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token;
221 * The configuration handle
223 const struct GNUNET_CONFIGURATION_Handle *cfg;
226 * HTTP methods allows for this plugin
228 static char* allow_methods;
231 * @brief struct returned by the initialization function of the plugin
235 const struct GNUNET_CONFIGURATION_Handle *cfg;
238 * OIDC needed variables
240 struct OIDC_Variables
243 struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
247 int is_client_trusted;
259 char *login_identity;
273 struct EgoEntry *next;
278 struct EgoEntry *prev;
293 struct GNUNET_IDENTITY_Ego *ego;
302 struct EgoEntry *ego_head;
307 struct EgoEntry *ego_tail;
312 struct EgoEntry *ego_entry;
315 * Pointer to ego private key
317 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
322 struct OIDC_Variables *oidc;
325 * The processing state
330 * Handle to Identity service.
332 struct GNUNET_IDENTITY_Handle *identity_handle;
337 struct GNUNET_REST_RequestHandle *rest_handle;
340 * Handle to NAMESTORE
342 struct GNUNET_NAMESTORE_Handle *namestore_handle;
345 * Iterator for NAMESTORE
347 struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
350 * Attribute claim list
352 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list;
357 struct GNUNET_IDENTITY_Operation *op;
362 struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
367 struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
372 struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it;
377 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it;
380 * Desired timeout for the lookup (default is no timeout).
382 struct GNUNET_TIME_Relative timeout;
385 * ID of a task associated with the resolution process.
387 struct GNUNET_SCHEDULER_Task *timeout_task;
390 * The plugin result processor
392 GNUNET_REST_ResultProcessor proc;
395 * The closure of the result processor
405 * Error response message
410 * Error response description
422 struct GNUNET_JSONAPI_Document *resp_object;
427 * Cleanup lookup handle
428 * @param handle Handle to clean up
431 cleanup_handle (struct RequestHandle *handle)
433 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_entry;
434 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_tmp;
435 struct EgoEntry *ego_entry;
436 struct EgoEntry *ego_tmp;
437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
439 if (NULL != handle->resp_object)
440 GNUNET_JSONAPI_document_delete (handle->resp_object);
441 if (NULL != handle->timeout_task)
442 GNUNET_SCHEDULER_cancel (handle->timeout_task);
443 if (NULL != handle->identity_handle)
444 GNUNET_IDENTITY_disconnect (handle->identity_handle);
445 if (NULL != handle->attr_it)
446 GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it);
447 if (NULL != handle->ticket_it)
448 GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it);
449 if (NULL != handle->idp)
450 GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
451 if (NULL != handle->url)
452 GNUNET_free (handle->url);
453 if (NULL != handle->emsg)
454 GNUNET_free (handle->emsg);
455 if (NULL != handle->edesc)
456 GNUNET_free (handle->edesc);
457 if (NULL != handle->namestore_handle)
458 GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
459 if (NULL != handle->oidc)
461 if (NULL != handle->oidc->client_id)
462 GNUNET_free(handle->oidc->client_id);
463 if (NULL != handle->oidc->login_identity)
464 GNUNET_free(handle->oidc->login_identity);
465 if (NULL != handle->oidc->nonce)
466 GNUNET_free(handle->oidc->nonce);
467 if (NULL != handle->oidc->redirect_uri)
468 GNUNET_free(handle->oidc->redirect_uri);
469 if (NULL != handle->oidc->response_type)
470 GNUNET_free(handle->oidc->response_type);
471 if (NULL != handle->oidc->scope)
472 GNUNET_free(handle->oidc->scope);
473 if (NULL != handle->oidc->state)
474 GNUNET_free(handle->oidc->state);
475 if (NULL != handle->oidc->response)
476 json_decref(handle->oidc->response);
477 GNUNET_free(handle->oidc);
479 if ( NULL != handle->attr_list )
481 for (claim_entry = handle->attr_list->list_head;
482 NULL != claim_entry;)
484 claim_tmp = claim_entry;
485 claim_entry = claim_entry->next;
486 GNUNET_free(claim_tmp->claim);
487 GNUNET_free(claim_tmp);
489 GNUNET_free (handle->attr_list);
491 for (ego_entry = handle->ego_head;
495 ego_entry = ego_entry->next;
496 GNUNET_free (ego_tmp->identifier);
497 GNUNET_free (ego_tmp->keystring);
498 GNUNET_free (ego_tmp);
500 if (NULL != handle->attr_it)
502 GNUNET_free(handle->attr_it);
504 GNUNET_free (handle);
508 cleanup_handle_delayed (void *cls)
510 cleanup_handle (cls);
515 * Task run on error, sends error message. Cleans up everything.
517 * @param cls the `struct RequestHandle`
522 struct RequestHandle *handle = cls;
523 struct MHD_Response *resp;
526 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
528 (NULL != handle->edesc) ? handle->edesc : "",
529 (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
530 (NULL != handle->oidc->state) ? handle->oidc->state : "",
531 (NULL != handle->oidc->state) ? "\"" : "");
532 if ( 0 == handle->response_code )
534 handle->response_code = MHD_HTTP_BAD_REQUEST;
536 resp = GNUNET_REST_create_response (json_error);
537 if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
539 MHD_add_response_header(resp, "WWW-Authenticate", "Basic");
541 MHD_add_response_header (resp, "Content-Type", "application/json");
542 handle->proc (handle->proc_cls, resp, handle->response_code);
543 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
544 GNUNET_free (json_error);
549 * Task run on error, sends error message. Cleans up everything.
551 * @param cls the `struct RequestHandle`
554 do_userinfo_error (void *cls)
556 struct RequestHandle *handle = cls;
557 struct MHD_Response *resp;
560 GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"",
562 (NULL != handle->edesc) ? handle->edesc : "");
563 resp = GNUNET_REST_create_response ("");
564 MHD_add_response_header(resp, "WWW-Authenticate", error);
565 handle->proc (handle->proc_cls, resp, handle->response_code);
566 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
572 * Task run on error, sends error message. Cleans up everything.
574 * @param cls the `struct RequestHandle`
577 do_redirect_error (void *cls)
579 struct RequestHandle *handle = cls;
580 struct MHD_Response *resp;
582 GNUNET_asprintf (&redirect,
583 "%s?error=%s&error_description=%s%s%s",
584 handle->oidc->redirect_uri, handle->emsg, handle->edesc,
585 (NULL != handle->oidc->state) ? "&state=" : "",
586 (NULL != handle->oidc->state) ? handle->oidc->state : "");
587 resp = GNUNET_REST_create_response ("");
588 MHD_add_response_header (resp, "Location", redirect);
589 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
590 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
591 GNUNET_free (redirect);
595 * Task run on timeout, sends error message. Cleans up everything.
597 * @param cls the `struct RequestHandle`
600 do_timeout (void *cls)
602 struct RequestHandle *handle = cls;
604 handle->timeout_task = NULL;
610 collect_error_cb (void *cls)
612 struct RequestHandle *handle = cls;
618 finished_cont (void *cls,
622 struct RequestHandle *handle = cls;
623 struct MHD_Response *resp;
625 resp = GNUNET_REST_create_response (emsg);
626 if (GNUNET_OK != success)
628 GNUNET_SCHEDULER_add_now (&do_error, handle);
631 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
632 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
637 * Return attributes for identity
639 * @param cls the request handle
642 return_response (void *cls)
645 struct RequestHandle *handle = cls;
646 struct MHD_Response *resp;
648 GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
650 resp = GNUNET_REST_create_response (result_str);
651 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
652 GNUNET_free (result_str);
653 cleanup_handle (handle);
657 * Return attributes for claim
659 * @param cls the request handle
662 return_userinfo_response (void *cls)
665 struct RequestHandle *handle = cls;
666 struct MHD_Response *resp;
668 result_str = json_dumps (handle->oidc->response, 0);
670 resp = GNUNET_REST_create_response (result_str);
671 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
672 GNUNET_free (result_str);
673 cleanup_handle (handle);
677 base_64_encode(char *string)
680 GNUNET_STRINGS_base64_encode(string,strlen(string),&output);
681 int index = strlen(output)-1;
682 while ('=' == output[index])
684 output[index] = '\0';
691 collect_finished_cb (void *cls)
693 struct RequestHandle *handle = cls;
695 handle->attr_it = NULL;
696 handle->ticket_it = NULL;
697 GNUNET_SCHEDULER_add_now (&return_response, handle);
702 * Collect all attributes for an ego
706 ticket_collect (void *cls,
707 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
709 struct GNUNET_JSONAPI_Resource *json_resource;
710 struct RequestHandle *handle = cls;
714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
715 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
717 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
720 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
722 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
723 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
724 value = json_string (tmp);
725 GNUNET_JSONAPI_resource_add_attr (json_resource,
730 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
731 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
732 value = json_string (tmp);
733 GNUNET_JSONAPI_resource_add_attr (json_resource,
738 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
740 value = json_string (tmp);
741 GNUNET_JSONAPI_resource_add_attr (json_resource,
746 GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it);
752 * List tickets for identity request
754 * @param con_handle the connection handle
756 * @param cls the RequestHandle
759 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
763 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
764 struct RequestHandle *handle = cls;
765 struct EgoEntry *ego_entry;
768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
770 if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
771 strlen (handle->url))
773 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
774 GNUNET_SCHEDULER_add_now (&do_error, handle);
777 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
779 for (ego_entry = handle->ego_head;
781 ego_entry = ego_entry->next)
782 if (0 == strcmp (identity, ego_entry->identifier))
784 handle->resp_object = GNUNET_JSONAPI_document_new ();
786 if (NULL == ego_entry)
789 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
791 GNUNET_SCHEDULER_add_now (&return_response, handle);
794 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
795 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
796 handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp,
802 &collect_finished_cb,
808 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
812 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
813 const char* identity;
814 const char* name_str;
815 const char* value_str;
817 struct RequestHandle *handle = cls;
818 struct EgoEntry *ego_entry;
819 struct MHD_Response *resp;
820 struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute;
821 struct GNUNET_JSONAPI_Document *json_obj;
822 struct GNUNET_JSONAPI_Resource *json_res;
823 char term_data[handle->rest_handle->data_size+1];
827 struct GNUNET_JSON_Specification docspec[] = {
828 GNUNET_JSON_spec_jsonapi_document (&json_obj),
829 GNUNET_JSON_spec_end()
832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
834 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
835 strlen (handle->url))
837 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
838 GNUNET_SCHEDULER_add_now (&do_error, handle);
841 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
843 for (ego_entry = handle->ego_head;
845 ego_entry = ego_entry->next)
846 if (0 == strcmp (identity, ego_entry->identifier))
849 if (NULL == ego_entry)
851 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
852 "Identity unknown (%s)\n", identity);
853 GNUNET_JSONAPI_document_delete (json_obj);
856 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
858 if (0 >= handle->rest_handle->data_size)
860 GNUNET_SCHEDULER_add_now (&do_error, handle);
864 term_data[handle->rest_handle->data_size] = '\0';
865 GNUNET_memcpy (term_data,
866 handle->rest_handle->data,
867 handle->rest_handle->data_size);
868 data_json = json_loads (term_data,
871 GNUNET_assert (GNUNET_OK ==
872 GNUNET_JSON_parse (data_json, docspec,
874 json_decref (data_json);
875 if (NULL == json_obj)
877 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
878 "Unable to parse JSONAPI Object from %s\n",
880 GNUNET_SCHEDULER_add_now (&do_error, handle);
883 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
885 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
886 "Cannot create more than 1 resource! (Got %d)\n",
887 GNUNET_JSONAPI_document_resource_count (json_obj));
888 GNUNET_JSONAPI_document_delete (json_obj);
889 GNUNET_SCHEDULER_add_now (&do_error, handle);
892 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
893 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
894 GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
896 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
897 "Unsupported JSON data type\n");
898 GNUNET_JSONAPI_document_delete (json_obj);
899 resp = GNUNET_REST_create_response (NULL);
900 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
901 cleanup_handle (handle);
904 name_str = GNUNET_JSONAPI_resource_get_id (json_res);
905 value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
907 value_str = json_string_value (value_json);
908 attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str,
909 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
911 strlen (value_str) + 1);
912 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
913 handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
918 GNUNET_free (attribute);
919 GNUNET_JSONAPI_document_delete (json_obj);
925 * Collect all attributes for an ego
929 attr_collect (void *cls,
930 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
931 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
933 struct GNUNET_JSONAPI_Resource *json_resource;
934 struct RequestHandle *handle = cls;
938 if ((NULL == attr->name) || (NULL == attr->data))
940 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
944 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
946 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
948 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
950 tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type,
954 value = json_string (tmp_value);
956 GNUNET_JSONAPI_resource_add_attr (json_resource,
960 GNUNET_free(tmp_value);
961 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
967 * List attributes for identity request
969 * @param con_handle the connection handle
971 * @param cls the RequestHandle
974 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
978 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
979 struct RequestHandle *handle = cls;
980 struct EgoEntry *ego_entry;
983 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
985 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
986 strlen (handle->url))
988 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
989 GNUNET_SCHEDULER_add_now (&do_error, handle);
992 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
994 for (ego_entry = handle->ego_head;
996 ego_entry = ego_entry->next)
997 if (0 == strcmp (identity, ego_entry->identifier))
999 handle->resp_object = GNUNET_JSONAPI_document_new ();
1002 if (NULL == ego_entry)
1005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
1007 GNUNET_SCHEDULER_add_now (&return_response, handle);
1010 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1011 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1012 handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
1018 &collect_finished_cb,
1024 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1028 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1029 const char* identity_str;
1030 const char* audience_str;
1031 const char* rnd_str;
1033 struct RequestHandle *handle = cls;
1034 struct EgoEntry *ego_entry;
1035 struct MHD_Response *resp;
1036 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
1037 struct GNUNET_JSONAPI_Document *json_obj;
1038 struct GNUNET_JSONAPI_Resource *json_res;
1039 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1040 char term_data[handle->rest_handle->data_size+1];
1042 json_t *identity_json;
1043 json_t *audience_json;
1046 struct GNUNET_JSON_Specification docspec[] = {
1047 GNUNET_JSON_spec_jsonapi_document (&json_obj),
1048 GNUNET_JSON_spec_end()
1051 if (0 >= handle->rest_handle->data_size)
1053 GNUNET_SCHEDULER_add_now (&do_error, handle);
1057 term_data[handle->rest_handle->data_size] = '\0';
1058 GNUNET_memcpy (term_data,
1059 handle->rest_handle->data,
1060 handle->rest_handle->data_size);
1061 data_json = json_loads (term_data,
1064 GNUNET_assert (GNUNET_OK ==
1065 GNUNET_JSON_parse (data_json, docspec,
1067 json_decref (data_json);
1068 if (NULL == json_obj)
1070 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1071 "Unable to parse JSONAPI Object from %s\n",
1073 GNUNET_SCHEDULER_add_now (&do_error, handle);
1076 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
1078 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1079 "Cannot create more than 1 resource! (Got %d)\n",
1080 GNUNET_JSONAPI_document_resource_count (json_obj));
1081 GNUNET_JSONAPI_document_delete (json_obj);
1082 GNUNET_SCHEDULER_add_now (&do_error, handle);
1085 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
1086 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
1087 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
1089 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1090 "Unsupported JSON data type\n");
1091 GNUNET_JSONAPI_document_delete (json_obj);
1092 resp = GNUNET_REST_create_response (NULL);
1093 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
1094 cleanup_handle (handle);
1097 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1099 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1101 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1103 rnd_str = json_string_value (rnd_json);
1104 identity_str = json_string_value (identity_json);
1105 audience_str = json_string_value (audience_json);
1107 GNUNET_STRINGS_string_to_data (rnd_str,
1111 GNUNET_STRINGS_string_to_data (identity_str,
1112 strlen (identity_str),
1114 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1115 GNUNET_STRINGS_string_to_data (audience_str,
1116 strlen (audience_str),
1118 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1120 for (ego_entry = handle->ego_head;
1122 ego_entry = ego_entry->next)
1124 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1126 if (0 == memcmp (&ticket.identity,
1128 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1131 if (NULL == ego_entry)
1133 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1134 "Identity unknown (%s)\n", identity_str);
1135 GNUNET_JSONAPI_document_delete (json_obj);
1138 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1140 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1141 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
1146 GNUNET_JSONAPI_document_delete (json_obj);
1150 consume_cont (void *cls,
1151 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1152 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
1154 struct RequestHandle *handle = cls;
1155 struct GNUNET_JSONAPI_Resource *json_resource;
1158 if (NULL == identity)
1160 GNUNET_SCHEDULER_add_now (&return_response, handle);
1164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
1166 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
1168 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
1170 value = json_string (attr->data);
1171 GNUNET_JSONAPI_resource_add_attr (json_resource,
1174 json_decref (value);
1178 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1182 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1183 const char* identity_str;
1184 const char* audience_str;
1185 const char* rnd_str;
1187 struct RequestHandle *handle = cls;
1188 struct EgoEntry *ego_entry;
1189 struct MHD_Response *resp;
1190 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
1191 struct GNUNET_JSONAPI_Document *json_obj;
1192 struct GNUNET_JSONAPI_Resource *json_res;
1193 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1194 char term_data[handle->rest_handle->data_size+1];
1196 json_t *identity_json;
1197 json_t *audience_json;
1200 struct GNUNET_JSON_Specification docspec[] = {
1201 GNUNET_JSON_spec_jsonapi_document (&json_obj),
1202 GNUNET_JSON_spec_end()
1205 if (0 >= handle->rest_handle->data_size)
1207 GNUNET_SCHEDULER_add_now (&do_error, handle);
1211 term_data[handle->rest_handle->data_size] = '\0';
1212 GNUNET_memcpy (term_data,
1213 handle->rest_handle->data,
1214 handle->rest_handle->data_size);
1215 data_json = json_loads (term_data,
1218 GNUNET_assert (GNUNET_OK ==
1219 GNUNET_JSON_parse (data_json, docspec,
1221 json_decref (data_json);
1222 if (NULL == json_obj)
1224 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1225 "Unable to parse JSONAPI Object from %s\n",
1227 GNUNET_SCHEDULER_add_now (&do_error, handle);
1230 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
1232 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1233 "Cannot create more than 1 resource! (Got %d)\n",
1234 GNUNET_JSONAPI_document_resource_count (json_obj));
1235 GNUNET_JSONAPI_document_delete (json_obj);
1236 GNUNET_SCHEDULER_add_now (&do_error, handle);
1239 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
1240 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
1241 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
1243 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1244 "Unsupported JSON data type\n");
1245 GNUNET_JSONAPI_document_delete (json_obj);
1246 resp = GNUNET_REST_create_response (NULL);
1247 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
1248 cleanup_handle (handle);
1251 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1253 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1255 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1257 rnd_str = json_string_value (rnd_json);
1258 identity_str = json_string_value (identity_json);
1259 audience_str = json_string_value (audience_json);
1261 GNUNET_STRINGS_string_to_data (rnd_str,
1265 GNUNET_STRINGS_string_to_data (identity_str,
1266 strlen (identity_str),
1268 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1269 GNUNET_STRINGS_string_to_data (audience_str,
1270 strlen (audience_str),
1272 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1274 for (ego_entry = handle->ego_head;
1276 ego_entry = ego_entry->next)
1278 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1280 if (0 == memcmp (&ticket.audience,
1282 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1285 if (NULL == ego_entry)
1287 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1288 "Identity unknown (%s)\n", identity_str);
1289 GNUNET_JSONAPI_document_delete (json_obj);
1292 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1293 handle->resp_object = GNUNET_JSONAPI_document_new ();
1294 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1295 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
1300 GNUNET_JSONAPI_document_delete (json_obj);
1306 * Respond to OPTIONS request
1308 * @param con_handle the connection handle
1309 * @param url the url
1310 * @param cls the RequestHandle
1313 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1317 struct MHD_Response *resp;
1318 struct RequestHandle *handle = cls;
1320 //For now, independent of path return all options
1321 resp = GNUNET_REST_create_response (NULL);
1322 MHD_add_response_header (resp,
1323 "Access-Control-Allow-Methods",
1325 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1326 cleanup_handle (handle);
1331 * Cookie interpretation
1334 cookie_identity_interpretation (struct RequestHandle *handle)
1336 struct GNUNET_HashCode cache_key;
1338 struct GNUNET_TIME_Absolute current_time, *relog_time;
1339 char delimiter[] = "; ";
1341 //gets identity of login try with cookie
1342 GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
1344 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
1347 //splits cookies and find 'Identity' cookie
1348 cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
1349 handle->oidc->login_identity = strtok(cookies, delimiter);
1351 while ( NULL != handle->oidc->login_identity )
1353 if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
1357 handle->oidc->login_identity = strtok (NULL, delimiter);
1359 GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity),
1361 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) )
1363 relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
1365 current_time = GNUNET_TIME_absolute_get ();
1366 // 30 min after old login -> redirect to login
1367 if ( current_time.abs_value_us <= relog_time->abs_value_us )
1369 handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY);
1370 handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity);
1375 handle->oidc->login_identity = NULL;
1384 login_redirection(void *cls)
1386 char *login_base_url;
1388 struct MHD_Response *resp;
1389 struct RequestHandle *handle = cls;
1392 == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
1393 "address", &login_base_url) )
1395 GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
1397 OIDC_RESPONSE_TYPE_KEY,
1398 handle->oidc->response_type,
1400 handle->oidc->client_id,
1401 OIDC_REDIRECT_URI_KEY,
1402 handle->oidc->redirect_uri,
1404 handle->oidc->scope,
1406 (NULL != handle->oidc->state) ? handle->oidc->state : "",
1408 (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
1409 resp = GNUNET_REST_create_response ("");
1410 MHD_add_response_header (resp, "Location", new_redirect);
1411 GNUNET_free(login_base_url);
1415 handle->emsg = GNUNET_strdup("server_error");
1416 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1417 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1418 GNUNET_SCHEDULER_add_now (&do_error, handle);
1421 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1422 GNUNET_free(new_redirect);
1423 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1427 * Function called if we had an error in zone-to-name mapping.
1430 oidc_iteration_error (void *cls)
1432 struct RequestHandle *handle = cls;
1433 handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR");
1434 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1435 GNUNET_SCHEDULER_add_now (&do_error, handle);
1439 oidc_ticket_issue_cb (void* cls,
1440 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
1442 struct RequestHandle *handle = cls;
1443 struct MHD_Response *resp;
1446 char *code_json_string;
1447 char *code_base64_final_string;
1448 handle->idp_op = NULL;
1449 resp = GNUNET_REST_create_response ("");
1450 if (NULL != ticket) {
1451 ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket,
1452 sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket));
1453 //TODO change if more attributes are needed (see max_age)
1454 GNUNET_asprintf (&code_json_string, "{\"ticket\":\"%s\"%s%s%s}",
1456 (NULL != handle->oidc->nonce) ? ", \"nonce\":\"" : "",
1457 (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "",
1458 (NULL != handle->oidc->nonce) ? "\"" : "");
1459 code_base64_final_string = base_64_encode(code_json_string);
1460 GNUNET_asprintf (&redirect_uri, "%s?%s=%s&state=%s",
1461 handle->oidc->redirect_uri,
1462 handle->oidc->response_type,
1463 code_base64_final_string, handle->oidc->state);
1464 MHD_add_response_header (resp, "Location", redirect_uri);
1465 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1466 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1467 GNUNET_free (redirect_uri);
1468 GNUNET_free (ticket_str);
1469 GNUNET_free (code_json_string);
1470 GNUNET_free (code_base64_final_string);
1473 handle->emsg = GNUNET_strdup("server_error");
1474 handle->edesc = GNUNET_strdup("Server cannot generate ticket.");
1475 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1479 oidc_collect_finished_cb (void *cls)
1481 struct RequestHandle *handle = cls;
1482 handle->attr_it = NULL;
1483 handle->ticket_it = NULL;
1484 if (NULL == handle->attr_list->list_head)
1486 handle->emsg = GNUNET_strdup("invalid_scope");
1487 handle->edesc = GNUNET_strdup("The requested scope is not available.");
1488 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1491 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_issue (handle->idp,
1493 &handle->oidc->client_pkey,
1495 &oidc_ticket_issue_cb,
1501 * Collect all attributes for an ego
1504 oidc_attr_collect (void *cls,
1505 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1506 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
1508 struct RequestHandle *handle = cls;
1509 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
1510 char* scope_variables;
1511 char* scope_variable;
1512 char delimiter[]=" ";
1514 if ( (NULL == attr->name) || (NULL == attr->data) )
1516 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1520 scope_variables = GNUNET_strdup(handle->oidc->scope);
1521 scope_variable = strtok (scope_variables, delimiter);
1522 while (NULL != scope_variable)
1524 if ( 0 == strcmp (attr->name, scope_variable) )
1528 scope_variable = strtok (NULL, delimiter);
1530 if ( NULL == scope_variable )
1532 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1535 GNUNET_free(scope_variables);
1537 le = GNUNET_new(struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry);
1538 le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr->name, attr->type,
1539 attr->data, attr->data_size);
1540 GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head,
1541 handle->attr_list->list_tail, le);
1542 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1547 * Cookie and Time check
1550 login_check (void *cls)
1552 struct RequestHandle *handle = cls;
1553 struct GNUNET_TIME_Absolute current_time, *relog_time;
1554 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey;
1555 struct GNUNET_HashCode cache_key;
1556 char *identity_cookie;
1558 GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity);
1559 GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1560 GNUNET_free(identity_cookie);
1561 //No login time for identity -> redirect to login
1563 == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time,
1566 relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
1568 current_time = GNUNET_TIME_absolute_get ();
1569 // 30 min after old login -> redirect to login
1570 if ( current_time.abs_value_us <= relog_time->abs_value_us )
1573 != GNUNET_CRYPTO_ecdsa_public_key_from_string (
1574 handle->oidc->login_identity,
1575 strlen (handle->oidc->login_identity), &pubkey) )
1577 handle->emsg = GNUNET_strdup("invalid_cookie");
1578 handle->edesc = GNUNET_strdup(
1579 "The cookie of a login identity is not valid");
1580 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1583 // iterate over egos and compare their public key
1584 for (handle->ego_entry = handle->ego_head;
1585 NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
1587 GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1589 == memcmp (&ego_pkey, &pubkey,
1590 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1592 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (
1593 handle->ego_entry->ego);
1594 handle->resp_object = GNUNET_JSONAPI_document_new ();
1595 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1596 handle->attr_list = GNUNET_new(
1597 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList);
1598 handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (
1599 handle->idp, &handle->priv_key, &oidc_iteration_error, handle,
1600 &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle);
1604 handle->emsg = GNUNET_strdup("invalid_cookie");
1605 handle->edesc = GNUNET_strdup(
1606 "The cookie of the login identity is not valid");
1607 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1614 * Create a response with requested records
1616 * @param handle the RequestHandle
1619 namestore_iteration_callback (
1620 void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1621 const char *rname, unsigned int rd_len,
1622 const struct GNUNET_GNSRECORD_Data *rd)
1624 struct RequestHandle *handle = cls;
1625 struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey;
1626 struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey;
1629 for (i = 0; i < rd_len; i++)
1631 if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type )
1634 if ( NULL != handle->oidc->login_identity )
1636 GNUNET_CRYPTO_ecdsa_public_key_from_string (
1637 handle->oidc->login_identity,
1638 strlen (handle->oidc->login_identity),
1639 &login_identity_pkey);
1640 GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego,
1641 ¤t_zone_pkey);
1643 if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1644 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1646 if ( 0 == memcmp (&login_identity_pkey, ¤t_zone_pkey,
1647 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1649 handle->oidc->is_client_trusted = GNUNET_YES;
1655 if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1656 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1658 handle->oidc->is_client_trusted = GNUNET_YES;
1663 GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it);
1667 * Iteration over all results finished, build final
1670 * @param cls the `struct RequestHandle`
1672 static void namestore_iteration_finished (void *cls)
1674 struct RequestHandle *handle = cls;
1675 struct GNUNET_HashCode cache_key;
1677 char *expected_redirect_uri;
1678 char *expected_scope;
1679 char delimiter[]=" ";
1680 int number_of_ignored_parameter, iterator;
1683 handle->ego_entry = handle->ego_entry->next;
1685 if(NULL != handle->ego_entry)
1687 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1688 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
1689 &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
1690 &namestore_iteration_finished, handle);
1693 if (GNUNET_NO == handle->oidc->is_client_trusted)
1695 handle->emsg = GNUNET_strdup("unauthorized_client");
1696 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1697 "authorization code using this method.");
1698 GNUNET_SCHEDULER_add_now (&do_error, handle);
1702 // REQUIRED value: redirect_uri
1703 GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1705 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1708 handle->emsg=GNUNET_strdup("invalid_request");
1709 handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
1710 GNUNET_SCHEDULER_add_now (&do_error, handle);
1713 handle->oidc->redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1716 GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
1717 // verify the redirect uri matches https://<client_id>.zkey[/xyz]
1718 if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
1720 handle->emsg=GNUNET_strdup("invalid_request");
1721 handle->edesc=GNUNET_strdup("Invalid redirect_uri");
1722 GNUNET_SCHEDULER_add_now (&do_error, handle);
1723 GNUNET_free(expected_redirect_uri);
1726 handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
1728 GNUNET_free(expected_redirect_uri);
1729 // REQUIRED value: response_type
1730 GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1732 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1735 handle->emsg=GNUNET_strdup("invalid_request");
1736 handle->edesc=GNUNET_strdup("missing parameter response_type");
1737 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1740 handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1742 handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
1744 // REQUIRED value: scope
1745 GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
1746 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1749 handle->emsg=GNUNET_strdup("invalid_request");
1750 handle->edesc=GNUNET_strdup("missing parameter scope");
1751 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1754 handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1756 handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
1758 //OPTIONAL value: nonce
1759 GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
1760 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1763 handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1765 handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
1768 //TODO check other values if needed
1769 number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1770 for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1772 GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1773 strlen(OIDC_ignored_parameter_array[iterator]),
1775 if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
1778 handle->emsg=GNUNET_strdup("access_denied");
1779 GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1780 OIDC_ignored_parameter_array[iterator]);
1781 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1786 // Checks if response_type is 'code'
1787 if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1789 handle->emsg=GNUNET_strdup("unsupported_response_type");
1790 handle->edesc=GNUNET_strdup("The authorization server does not support "
1791 "obtaining this authorization code.");
1792 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1796 // Checks if scope contains 'openid'
1797 expected_scope = GNUNET_strdup(handle->oidc->scope);
1798 expected_scope = strtok (expected_scope, delimiter);
1799 while (NULL != expected_scope)
1801 if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1805 expected_scope = strtok (NULL, delimiter);
1807 if (NULL == expected_scope)
1809 handle->emsg = GNUNET_strdup("invalid_scope");
1810 handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1812 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1816 GNUNET_free(expected_scope);
1818 if( NULL != handle->oidc->login_identity )
1820 GNUNET_SCHEDULER_add_now(&login_check,handle);
1824 GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1828 * Responds to authorization GET and url-encoded POST request
1830 * @param con_handle the connection handle
1831 * @param url the url
1832 * @param cls the RequestHandle
1835 authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1839 struct RequestHandle *handle = cls;
1840 struct GNUNET_HashCode cache_key;
1842 cookie_identity_interpretation(handle);
1844 //RECOMMENDED value: state - REQUIRED for answers
1845 GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
1846 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1849 handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1851 handle->oidc->state = GNUNET_strdup (handle->oidc->state);
1854 // REQUIRED value: client_id
1855 GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1857 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1860 handle->emsg=GNUNET_strdup("invalid_request");
1861 handle->edesc=GNUNET_strdup("missing parameter client_id");
1862 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1863 GNUNET_SCHEDULER_add_now (&do_error, handle);
1866 handle->oidc->client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1868 handle->oidc->client_id = GNUNET_strdup (handle->oidc->client_id);
1871 != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
1872 strlen (handle->oidc->client_id),
1873 &handle->oidc->client_pkey) )
1875 handle->emsg = GNUNET_strdup("unauthorized_client");
1876 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1877 "authorization code using this method.");
1878 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1879 GNUNET_SCHEDULER_add_now (&do_error, handle);
1884 if ( NULL == handle->ego_head )
1886 handle->emsg = GNUNET_strdup("server_error");
1887 handle->edesc = GNUNET_strdup ("Egos are missing");
1888 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1889 GNUNET_SCHEDULER_add_now (&do_error, handle);
1893 handle->ego_entry = handle->ego_head;
1894 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
1895 handle->oidc->is_client_trusted = GNUNET_NO;
1897 // Checks if client_id is valid:
1898 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
1899 handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
1900 handle, &namestore_iteration_callback, handle,
1901 &namestore_iteration_finished, handle);
1905 * Combines an identity with a login time and responds OK to login request
1907 * @param con_handle the connection handle
1908 * @param url the url
1909 * @param cls the RequestHandle
1912 login_cont (struct GNUNET_REST_RequestHandle *con_handle,
1916 struct MHD_Response *resp = GNUNET_REST_create_response ("");
1917 struct RequestHandle *handle = cls;
1918 struct GNUNET_HashCode cache_key;
1919 struct GNUNET_TIME_Absolute *current_time;
1920 struct GNUNET_TIME_Absolute *last_time;
1925 root = json_loads (handle->rest_handle->data, 0, &error);
1926 identity = json_object_get (root, "identity");
1927 if ( json_is_string(identity) )
1929 GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1931 GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1933 current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
1934 *current_time = GNUNET_TIME_relative_to_absolute (
1935 GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_minute_ (),
1937 last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key);
1938 if (NULL != last_time)
1940 GNUNET_free(last_time);
1942 GNUNET_CONTAINER_multihashmap_put (
1943 OIDC_identity_login_time, &cache_key, current_time,
1944 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1946 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1950 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1952 GNUNET_free(cookie);
1954 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1959 token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1963 //TODO static strings
1965 struct RequestHandle *handle = cls;
1966 struct GNUNET_HashCode cache_key;
1967 char *authorization, *credentials;
1968 char delimiter[]=" ";
1969 char delimiter_user_psw[]=":";
1970 char *grant_type, *code, *redirect_uri, *expected_redirect_uri;
1971 char *user_psw = NULL, *client_id, *psw;
1973 int client_exists = GNUNET_NO;
1974 struct MHD_Response *resp;
1976 json_t *root, *ticket_string, *nonce, *max_age;
1978 char *json_response;
1981 * Check Authorization
1983 GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
1984 strlen (OIDC_AUTHORIZATION_HEADER_KEY),
1986 if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
1989 handle->emsg=GNUNET_strdup("invalid_client");
1990 handle->edesc=GNUNET_strdup("missing authorization");
1991 handle->response_code = MHD_HTTP_UNAUTHORIZED;
1992 GNUNET_SCHEDULER_add_now (&do_error, handle);
1995 authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
1997 //TODO authorization pointer will be moved as well
1998 //split header in "Basic" and [content]
1999 credentials = strtok (authorization, delimiter);
2000 if (0 != strcmp ("Basic",credentials))
2002 handle->emsg=GNUNET_strdup("invalid_client");
2003 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2004 GNUNET_SCHEDULER_add_now (&do_error, handle);
2007 credentials = strtok(NULL, delimiter);
2008 if (NULL == credentials)
2010 handle->emsg=GNUNET_strdup("invalid_client");
2011 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2012 GNUNET_SCHEDULER_add_now (&do_error, handle);
2015 GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), &user_psw);
2017 if ( NULL == user_psw )
2019 handle->emsg=GNUNET_strdup("invalid_client");
2020 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2021 GNUNET_SCHEDULER_add_now (&do_error, handle);
2024 client_id = strtok (user_psw, delimiter_user_psw);
2025 if ( NULL == client_id )
2027 GNUNET_free_non_null(user_psw);
2028 handle->emsg=GNUNET_strdup("invalid_client");
2029 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2030 GNUNET_SCHEDULER_add_now (&do_error, handle);
2033 psw = strtok (NULL, delimiter_user_psw);
2036 GNUNET_free_non_null(user_psw);
2037 handle->emsg=GNUNET_strdup("invalid_client");
2038 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2039 GNUNET_SCHEDULER_add_now (&do_error, handle);
2042 //check client password
2044 == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
2045 "psw", &expected_psw) )
2047 if (0 != strcmp (expected_psw, psw))
2049 handle->emsg=GNUNET_strdup("invalid_client");
2050 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2051 GNUNET_SCHEDULER_add_now (&do_error, handle);
2054 GNUNET_free(expected_psw);
2058 handle->emsg = GNUNET_strdup("server_error");
2059 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2060 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2061 GNUNET_SCHEDULER_add_now (&do_error, handle);
2065 for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; )
2067 if ( 0 == strcmp(handle->ego_entry->keystring, client_id))
2069 client_exists = GNUNET_YES;
2072 handle->ego_entry = handle->ego_entry->next;
2074 if (GNUNET_NO == client_exists)
2076 handle->emsg=GNUNET_strdup("invalid_client");
2077 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2078 GNUNET_SCHEDULER_add_now (&do_error, handle);
2086 //TODO Do not allow multiple equal parameter names
2087 //REQUIRED grant_type
2088 GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key);
2090 == GNUNET_CONTAINER_multihashmap_contains (
2091 handle->rest_handle->url_param_map, &cache_key) )
2093 handle->emsg = GNUNET_strdup("invalid_request");
2094 handle->edesc = GNUNET_strdup("missing parameter grant_type");
2095 handle->response_code = MHD_HTTP_BAD_REQUEST;
2096 GNUNET_SCHEDULER_add_now (&do_error, handle);
2099 grant_type = GNUNET_CONTAINER_multihashmap_get (
2100 handle->rest_handle->url_param_map, &cache_key);
2103 GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key);
2105 == GNUNET_CONTAINER_multihashmap_contains (
2106 handle->rest_handle->url_param_map, &cache_key) )
2108 handle->emsg = GNUNET_strdup("invalid_request");
2109 handle->edesc = GNUNET_strdup("missing parameter code");
2110 handle->response_code = MHD_HTTP_BAD_REQUEST;
2111 GNUNET_SCHEDULER_add_now (&do_error, handle);
2114 code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
2117 //REQUIRED redirect_uri
2118 GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
2121 == GNUNET_CONTAINER_multihashmap_contains (
2122 handle->rest_handle->url_param_map, &cache_key) )
2124 handle->emsg = GNUNET_strdup("invalid_request");
2125 handle->edesc = GNUNET_strdup("missing parameter redirect_uri");
2126 handle->response_code = MHD_HTTP_BAD_REQUEST;
2127 GNUNET_SCHEDULER_add_now (&do_error, handle);
2130 redirect_uri = GNUNET_CONTAINER_multihashmap_get (
2131 handle->rest_handle->url_param_map, &cache_key);
2134 //Check parameter grant_type == "authorization_code"
2135 if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type))
2137 handle->emsg=GNUNET_strdup("unsupported_grant_type");
2138 handle->response_code = MHD_HTTP_BAD_REQUEST;
2139 GNUNET_SCHEDULER_add_now (&do_error, handle);
2142 // check redirect_uri
2143 GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", client_id);
2144 // verify the redirect uri matches https://<client_id>.zkey[/xyz]
2145 if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
2147 handle->emsg=GNUNET_strdup("invalid_request");
2148 handle->edesc=GNUNET_strdup("Invalid redirect_uri");
2149 handle->response_code = MHD_HTTP_BAD_REQUEST;
2150 GNUNET_SCHEDULER_add_now (&do_error, handle);
2151 GNUNET_free(expected_redirect_uri);
2154 GNUNET_free(expected_redirect_uri);
2155 GNUNET_CRYPTO_hash(code, strlen(code), &cache_key);
2156 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(OIDC_ticket_once,&cache_key))
2158 handle->emsg = GNUNET_strdup("invalid_request");
2159 handle->edesc = GNUNET_strdup("Cannot use the same code more than once");
2160 handle->response_code = MHD_HTTP_BAD_REQUEST;
2161 GNUNET_SCHEDULER_add_now (&do_error, handle);
2165 GNUNET_CONTAINER_multihashmap_put(OIDC_ticket_once,&cache_key,&i,GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
2168 GNUNET_STRINGS_base64_decode(code,strlen(code),&code_output);
2169 root = json_loads (code_output, 0, &error);
2170 GNUNET_free(code_output);
2171 ticket_string = json_object_get (root, "ticket");
2172 nonce = json_object_get (root, "nonce");
2173 max_age = json_object_get (root, "max_age");
2175 if(ticket_string == NULL && !json_is_string(ticket_string))
2177 handle->emsg = GNUNET_strdup("invalid_request");
2178 handle->edesc = GNUNET_strdup("invalid code");
2179 handle->response_code = MHD_HTTP_BAD_REQUEST;
2180 GNUNET_SCHEDULER_add_now (&do_error, handle);
2184 struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket = GNUNET_new(struct GNUNET_IDENTITY_PROVIDER_Ticket);
2186 != GNUNET_STRINGS_string_to_data (json_string_value(ticket_string),
2187 strlen (json_string_value(ticket_string)),
2189 sizeof(struct GNUNET_IDENTITY_PROVIDER_Ticket)))
2191 handle->emsg = GNUNET_strdup("invalid_request");
2192 handle->edesc = GNUNET_strdup("invalid code");
2193 handle->response_code = MHD_HTTP_BAD_REQUEST;
2194 GNUNET_SCHEDULER_add_now (&do_error, handle);
2195 GNUNET_free(ticket);
2198 // this is the current client (relying party)
2199 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
2200 GNUNET_IDENTITY_ego_get_public_key(handle->ego_entry->ego,&pub_key);
2201 if (0 != memcmp(&pub_key,&ticket->audience,sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
2203 handle->emsg = GNUNET_strdup("invalid_request");
2204 handle->edesc = GNUNET_strdup("invalid code");
2205 handle->response_code = MHD_HTTP_BAD_REQUEST;
2206 GNUNET_SCHEDULER_add_now (&do_error, handle);
2207 GNUNET_free(ticket);
2212 unsigned long long int expiration_time;
2214 != GNUNET_CONFIGURATION_get_value_number(cfg, "identity-rest-plugin",
2215 "expiration_time", &expiration_time) )
2217 handle->emsg = GNUNET_strdup("server_error");
2218 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2219 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2220 GNUNET_SCHEDULER_add_now (&do_error, handle);
2221 GNUNET_free(ticket);
2225 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *cl = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList);
2226 //aud REQUIRED public key client_id must be there
2227 GNUNET_IDENTITY_ATTRIBUTE_list_add(cl,
2229 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2232 //exp REQUIRED time expired from config
2233 //TODO time as seconds
2234 struct GNUNET_TIME_Absolute exp_time = GNUNET_TIME_relative_to_absolute (
2235 GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
2237 const char* exp_time_string = GNUNET_STRINGS_absolute_time_to_string(exp_time);
2238 GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
2240 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2242 strlen(exp_time_string));
2243 //iat REQUIRED time now
2244 //TODO time as seconds
2245 struct GNUNET_TIME_Absolute time_now = GNUNET_TIME_absolute_get();
2246 const char* time_now_string = GNUNET_STRINGS_absolute_time_to_string(time_now);
2247 GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
2249 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2251 strlen(time_now_string));
2252 //nonce only if nonce is provided
2253 if ( NULL != nonce && json_is_string(nonce) )
2255 GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
2257 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2258 json_string_value(nonce),
2259 strlen(json_string_value(nonce)));
2261 //auth_time only if max_age is provided
2262 if ( NULL != max_age && json_is_string(max_age) )
2264 GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
2266 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2267 json_string_value(max_age),
2268 strlen(json_string_value(max_age)));
2270 //TODO OPTIONAL acr,amr,azp
2272 //TODO lookup client for client == audience of ticket
2273 struct EgoEntry *ego_entry;
2274 for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
2276 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
2277 if (0 == memcmp (&pub_key, &ticket->audience, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
2282 if ( NULL == ego_entry )
2284 handle->emsg = GNUNET_strdup("invalid_request");
2285 handle->edesc = GNUNET_strdup("invalid code....");
2286 handle->response_code = MHD_HTTP_BAD_REQUEST;
2287 GNUNET_SCHEDULER_add_now (&do_error, handle);
2288 GNUNET_free(ticket);
2291 char *id_token = jwt_create_from_list(&ticket->audience,
2293 GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego));
2295 //Create random access_token
2296 char* access_token_number;
2298 uint64_t random_number;
2299 random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
2300 GNUNET_asprintf(&access_token_number, "%" PRIu64, random_number);
2301 GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token);
2305 //TODO OPTIONAL add refresh_token and scope
2306 GNUNET_asprintf (&json_response,
2307 "{ \"access_token\" : \"%s\", "
2308 "\"token_type\" : \"Bearer\", "
2309 "\"expires_in\" : %d, "
2310 "\"id_token\" : \"%s\"}",
2314 GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key);
2315 char *id_ticket_combination;
2316 GNUNET_asprintf(&id_ticket_combination,
2319 json_string_value(ticket_string));
2320 GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token,
2322 id_ticket_combination,
2323 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
2325 resp = GNUNET_REST_create_response (json_response);
2326 MHD_add_response_header (resp, "Cache-Control", "no-store");
2327 MHD_add_response_header (resp, "Pragma", "no-cache");
2328 MHD_add_response_header (resp, "Content-Type", "application/json");
2329 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2331 //TODO one time ticket/code
2334 GNUNET_IDENTITY_ATTRIBUTE_list_destroy(cl);
2335 GNUNET_free(access_token_number);
2336 GNUNET_free(access_token);
2337 GNUNET_free(user_psw);
2338 GNUNET_free(json_response);
2339 GNUNET_free(ticket);
2340 GNUNET_free(id_token);
2342 GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle);
2347 consume_ticket (void *cls,
2348 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
2349 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
2351 struct RequestHandle *handle = cls;
2353 if (NULL == identity)
2355 GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle);
2359 json_object_set_new (handle->oidc->response,
2361 json_string(attr->data));
2365 userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
2366 const char* url, void *cls)
2368 struct RequestHandle *handle = cls;
2369 char delimiter[] = " ";
2370 char delimiter_db[] = ";";
2371 struct GNUNET_HashCode cache_key;
2372 char *authorization, *authorization_type, *authorization_access_token;
2373 char *client_ticket;
2374 struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket;
2376 GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
2377 strlen (OIDC_AUTHORIZATION_HEADER_KEY),
2380 == GNUNET_CONTAINER_multihashmap_contains (
2381 handle->rest_handle->header_param_map, &cache_key) )
2383 handle->emsg = GNUNET_strdup("invalid_token");
2384 handle->edesc = GNUNET_strdup("No Access Token");
2385 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2386 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2389 authorization = GNUNET_CONTAINER_multihashmap_get (
2390 handle->rest_handle->header_param_map, &cache_key);
2392 //TODO authorization pointer will be moved as well
2393 //split header in "Bearer" and access_token
2394 authorization_type = strtok (authorization, delimiter);
2395 if ( 0 != strcmp ("Bearer", authorization_type) )
2397 handle->emsg = GNUNET_strdup("invalid_token");
2398 handle->edesc = GNUNET_strdup("No Access Token");
2399 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2400 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2403 authorization_access_token = strtok (NULL, delimiter);
2404 if ( NULL == authorization_access_token )
2406 handle->emsg = GNUNET_strdup("invalid_token");
2407 handle->edesc = GNUNET_strdup("No Access Token");
2408 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2409 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2413 GNUNET_CRYPTO_hash (authorization_access_token,
2414 strlen (authorization_access_token),
2416 if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token,
2419 handle->emsg = GNUNET_strdup("invalid_token");
2420 handle->edesc = GNUNET_strdup("The Access Token expired");
2421 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2422 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2426 client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token,
2429 client_ticket = strtok(client_ticket,delimiter_db);
2430 if (NULL == client_ticket)
2432 handle->emsg = GNUNET_strdup("invalid_token");
2433 handle->edesc = GNUNET_strdup("The Access Token expired");
2434 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2435 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2438 handle->ego_entry = handle->ego_head;
2439 for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
2441 if (0 == strcmp(handle->ego_entry->keystring,client_ticket))
2446 if (NULL == handle->ego_entry)
2448 handle->emsg = GNUNET_strdup("invalid_token");
2449 handle->edesc = GNUNET_strdup("The Access Token expired");
2450 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2451 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2454 client_ticket = strtok(NULL, delimiter_db);
2455 if (NULL == client_ticket)
2457 handle->emsg = GNUNET_strdup("invalid_token");
2458 handle->edesc = GNUNET_strdup("The Access Token expired");
2459 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2460 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2463 ticket = GNUNET_new(struct GNUNET_IDENTITY_PROVIDER_Ticket);
2465 != GNUNET_STRINGS_string_to_data (client_ticket,
2466 strlen (client_ticket),
2468 sizeof(struct GNUNET_IDENTITY_PROVIDER_Ticket)))
2470 handle->emsg = GNUNET_strdup("invalid_token");
2471 handle->edesc = GNUNET_strdup("The Access Token expired");
2472 handle->response_code = MHD_HTTP_UNAUTHORIZED;
2473 GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2474 GNUNET_free(ticket);
2478 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
2479 handle->oidc->response = json_object();
2480 json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring));
2481 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (
2483 GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego),
2487 GNUNET_free(ticket);
2493 * Handle rest request
2495 * @param handle the request handle
2498 init_cont (struct RequestHandle *handle)
2500 struct GNUNET_REST_RequestHandlerError err;
2501 static const struct GNUNET_REST_RequestHandler handlers[] = {
2502 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
2503 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
2504 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
2505 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint},
2506 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded
2507 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
2508 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
2509 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2510 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2511 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
2512 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
2513 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
2515 GNUNET_REST_HANDLER_END
2518 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
2523 handle->response_code = err.error_code;
2524 GNUNET_SCHEDULER_add_now (&do_error, handle);
2529 * If listing is enabled, prints information about the egos.
2531 * This function is initially called for all egos and then again
2532 * whenever a ego's identifier changes or if it is deleted. At the
2533 * end of the initial pass over all egos, the function is once called
2534 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
2535 * be invoked in the future or that there was an error.
2537 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
2538 * this function is only called ONCE, and 'NULL' being passed in
2539 * 'ego' does indicate an error (i.e. name is taken or no default
2540 * value is known). If 'ego' is non-NULL and if '*ctx'
2541 * is set in those callbacks, the value WILL be passed to a subsequent
2542 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
2543 * that one was not NULL).
2545 * When an identity is renamed, this function is called with the
2546 * (known) ego but the NEW identifier.
2548 * When an identity is deleted, this function is called with the
2549 * (known) ego and "NULL" for the 'identifier'. In this case,
2550 * the 'ego' is henceforth invalid (and the 'ctx' should also be
2553 * @param cls closure
2554 * @param ego ego handle
2555 * @param ctx context for application to store data for this ego
2556 * (during the lifetime of this process, initially NULL)
2557 * @param identifier identifier assigned by the user for this ego,
2558 * NULL if the user just deleted the ego and it
2559 * must thus no longer be used
2562 list_ego (void *cls,
2563 struct GNUNET_IDENTITY_Ego *ego,
2565 const char *identifier)
2567 struct RequestHandle *handle = cls;
2568 struct EgoEntry *ego_entry;
2569 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
2571 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
2573 handle->state = ID_REST_STATE_POST_INIT;
2577 if (ID_REST_STATE_INIT == handle->state) {
2578 ego_entry = GNUNET_new (struct EgoEntry);
2579 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2580 ego_entry->keystring =
2581 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
2582 ego_entry->ego = ego;
2583 ego_entry->identifier = GNUNET_strdup (identifier);
2584 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
2590 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
2591 GNUNET_REST_ResultProcessor proc,
2594 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2595 handle->oidc = GNUNET_new (struct OIDC_Variables);
2596 if ( NULL == OIDC_identity_login_time )
2597 OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2598 if ( NULL == OIDC_identity_grants )
2599 OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2600 if ( NULL == OIDC_ticket_once )
2601 OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2602 if ( NULL == OIDC_interpret_access_token )
2603 OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2604 handle->response_code = 0;
2605 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
2606 handle->proc_cls = proc_cls;
2607 handle->proc = proc;
2608 handle->state = ID_REST_STATE_INIT;
2609 handle->rest_handle = rest_handle;
2611 handle->url = GNUNET_strdup (rest_handle->url);
2612 if (handle->url[strlen (handle->url)-1] == '/')
2613 handle->url[strlen (handle->url)-1] = '\0';
2614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2616 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
2619 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
2620 handle->timeout_task =
2621 GNUNET_SCHEDULER_add_delayed (handle->timeout,
2624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2629 * Entry point for the plugin.
2631 * @param cls Config info
2632 * @return NULL on error, otherwise the plugin context
2635 libgnunet_plugin_rest_identity_provider_init (void *cls)
2637 static struct Plugin plugin;
2638 struct GNUNET_REST_Plugin *api;
2641 if (NULL != plugin.cfg)
2642 return NULL; /* can only initialize once! */
2643 memset (&plugin, 0, sizeof (struct Plugin));
2645 api = GNUNET_new (struct GNUNET_REST_Plugin);
2647 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
2648 api->process_request = &rest_identity_process_request;
2649 GNUNET_asprintf (&allow_methods,
2650 "%s, %s, %s, %s, %s",
2651 MHD_HTTP_METHOD_GET,
2652 MHD_HTTP_METHOD_POST,
2653 MHD_HTTP_METHOD_PUT,
2654 MHD_HTTP_METHOD_DELETE,
2655 MHD_HTTP_METHOD_OPTIONS);
2657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2658 _("Identity Provider REST API initialized\n"));
2664 * Exit point from the plugin.
2666 * @param cls the plugin context (as returned by "init")
2667 * @return always NULL
2670 libgnunet_plugin_rest_identity_provider_done (void *cls)
2672 struct GNUNET_REST_Plugin *api = cls;
2673 struct Plugin *plugin = api->cls;
2676 struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2678 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
2679 OIDC_identity_login_time);
2680 while (GNUNET_YES ==
2681 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2686 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time);
2687 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants);
2688 while (GNUNET_YES ==
2689 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2694 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
2695 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once);
2696 while (GNUNET_YES ==
2697 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2702 GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once);
2703 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token);
2704 while (GNUNET_YES ==
2705 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2710 GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token);
2711 GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it);
2712 GNUNET_free_non_null (allow_methods);
2714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2715 "Identity Provider REST plugin is finished\n");
2719 /* end of plugin_rest_identity_provider.c */