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"
46 #define GNUNET_REST_API_NS_IDENTITY_PROVIDER "/idp"
51 #define GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES "/idp/attributes"
56 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/idp/tickets"
61 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/idp/revoke"
66 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume"
71 #define GNUNET_REST_API_NS_AUTHORIZE "/idp/authorize"
76 #define GNUNET_REST_API_NS_TOKEN "/idp/token"
81 #define GNUNET_REST_API_NS_LOGIN "/idp/login"
86 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
91 #define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
97 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value"
100 * State while collecting all egos
102 #define ID_REST_STATE_INIT 0
105 * Done collecting egos
107 #define ID_REST_STATE_POST_INIT 1
110 * OIDC response_type key
112 #define OIDC_RESPONSE_TYPE_KEY "response_type"
117 #define OIDC_CLIENT_ID_KEY "client_id"
122 #define OIDC_SCOPE_KEY "scope"
125 * OIDC redirect_uri key
127 #define OIDC_REDIRECT_URI_KEY "redirect_uri"
132 #define OIDC_STATE_KEY "state"
137 #define OIDC_NONCE_KEY "nonce"
140 * OIDC cookie header key
142 #define OIDC_COOKIE_HEADER_KEY "Cookie"
145 * OIDC cookie header information key
147 #define OIDC_AUTHORIZATION_HEADER_KEY "Authorization"
151 * OIDC cookie header information key
153 #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
156 * OIDC expected response_type while authorizing
158 #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
161 * OIDC expected scope part while authorizing
163 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
166 * OIDC ignored parameter array
168 char* OIDC_ignored_parameter_array [] =
181 * OIDC authorized identities and times hashmap
183 struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
186 * OIDC authorized identities and times hashmap
188 struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants;
191 * The configuration handle
193 const struct GNUNET_CONFIGURATION_Handle *cfg;
196 * HTTP methods allows for this plugin
198 static char* allow_methods;
201 * @brief struct returned by the initialization function of the plugin
205 const struct GNUNET_CONFIGURATION_Handle *cfg;
208 struct OIDC_Variables
211 struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
215 int is_client_trusted;
227 char *login_identity;
240 struct EgoEntry *next;
245 struct EgoEntry *prev;
260 struct GNUNET_IDENTITY_Ego *ego;
269 struct EgoEntry *ego_head;
274 struct EgoEntry *ego_tail;
279 struct EgoEntry *ego_entry;
282 * Pointer to ego private key
284 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
289 struct OIDC_Variables *oidc;
292 * The processing state
297 * Handle to Identity service.
299 struct GNUNET_IDENTITY_Handle *identity_handle;
304 struct GNUNET_REST_RequestHandle *rest_handle;
307 * Handle to NAMESTORE
309 struct GNUNET_NAMESTORE_Handle *namestore_handle;
312 * Iterator for NAMESTORE
314 struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
317 * Attribute claim list
319 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list;
324 struct GNUNET_IDENTITY_Operation *op;
329 struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
334 struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
339 struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it;
344 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it;
347 * Desired timeout for the lookup (default is no timeout).
349 struct GNUNET_TIME_Relative timeout;
352 * ID of a task associated with the resolution process.
354 struct GNUNET_SCHEDULER_Task *timeout_task;
357 * The plugin result processor
359 GNUNET_REST_ResultProcessor proc;
362 * The closure of the result processor
372 * Error response message
377 * Error response description
389 struct GNUNET_JSONAPI_Document *resp_object;
394 * Cleanup lookup handle
395 * @param handle Handle to clean up
398 cleanup_handle (struct RequestHandle *handle)
400 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_entry;
401 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_tmp;
402 struct EgoEntry *ego_entry;
403 struct EgoEntry *ego_tmp;
404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
406 if (NULL != handle->resp_object)
407 GNUNET_JSONAPI_document_delete (handle->resp_object);
408 if (NULL != handle->timeout_task)
409 GNUNET_SCHEDULER_cancel (handle->timeout_task);
410 if (NULL != handle->identity_handle)
411 GNUNET_IDENTITY_disconnect (handle->identity_handle);
412 if (NULL != handle->attr_it)
413 GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it);
414 if (NULL != handle->ticket_it)
415 GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it);
416 if (NULL != handle->idp)
417 GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
418 if (NULL != handle->url)
419 GNUNET_free (handle->url);
420 if (NULL != 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)
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);
446 if ( NULL != handle->attr_list )
448 for (claim_entry = handle->attr_list->list_head;
449 NULL != claim_entry;)
451 claim_tmp = claim_entry;
452 claim_entry = claim_entry->next;
453 GNUNET_free(claim_tmp->claim);
454 GNUNET_free(claim_tmp);
456 GNUNET_free (handle->attr_list);
458 for (ego_entry = handle->ego_head;
462 ego_entry = ego_entry->next;
463 GNUNET_free (ego_tmp->identifier);
464 GNUNET_free (ego_tmp->keystring);
465 GNUNET_free (ego_tmp);
467 if (NULL != handle->attr_it)
469 GNUNET_free(handle->attr_it);
471 GNUNET_free (handle);
475 cleanup_handle_delayed (void *cls)
477 cleanup_handle (cls);
482 * Task run on error, sends error message. Cleans up everything.
484 * @param cls the `struct RequestHandle`
489 struct RequestHandle *handle = cls;
490 struct MHD_Response *resp;
493 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
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 )
501 handle->response_code = MHD_HTTP_BAD_REQUEST;
503 resp = GNUNET_REST_create_response (json_error);
504 handle->proc (handle->proc_cls, resp, handle->response_code);
505 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
506 GNUNET_free (json_error);
510 * Task run on error, sends error message. Cleans up everything.
512 * @param cls the `struct RequestHandle`
515 do_redirect_error (void *cls)
517 struct RequestHandle *handle = cls;
518 struct MHD_Response *resp;
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);
533 * Task run on timeout, sends error message. Cleans up everything.
535 * @param cls the `struct RequestHandle`
538 do_timeout (void *cls)
540 struct RequestHandle *handle = cls;
542 handle->timeout_task = NULL;
548 collect_error_cb (void *cls)
550 struct RequestHandle *handle = cls;
556 finished_cont (void *cls,
560 struct RequestHandle *handle = cls;
561 struct MHD_Response *resp;
563 resp = GNUNET_REST_create_response (emsg);
564 if (GNUNET_OK != success)
566 GNUNET_SCHEDULER_add_now (&do_error, handle);
569 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
570 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
575 * Return attributes for identity
577 * @param cls the request handle
580 return_response (void *cls)
583 struct RequestHandle *handle = cls;
584 struct MHD_Response *resp;
586 GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
588 resp = GNUNET_REST_create_response (result_str);
589 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
590 GNUNET_free (result_str);
591 cleanup_handle (handle);
596 collect_finished_cb (void *cls)
598 struct RequestHandle *handle = cls;
600 handle->attr_it = NULL;
601 handle->ticket_it = NULL;
602 GNUNET_SCHEDULER_add_now (&return_response, handle);
607 * Collect all attributes for an ego
611 ticket_collect (void *cls,
612 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
614 struct GNUNET_JSONAPI_Resource *json_resource;
615 struct RequestHandle *handle = cls;
619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
620 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
622 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
625 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
627 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
628 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
629 value = json_string (tmp);
630 GNUNET_JSONAPI_resource_add_attr (json_resource,
635 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
636 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
637 value = json_string (tmp);
638 GNUNET_JSONAPI_resource_add_attr (json_resource,
643 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
645 value = json_string (tmp);
646 GNUNET_JSONAPI_resource_add_attr (json_resource,
651 GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it);
657 * List tickets for identity request
659 * @param con_handle the connection handle
661 * @param cls the RequestHandle
664 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
668 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
669 struct RequestHandle *handle = cls;
670 struct EgoEntry *ego_entry;
673 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
675 if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
676 strlen (handle->url))
678 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
679 GNUNET_SCHEDULER_add_now (&do_error, handle);
682 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
684 for (ego_entry = handle->ego_head;
686 ego_entry = ego_entry->next)
687 if (0 == strcmp (identity, ego_entry->identifier))
689 handle->resp_object = GNUNET_JSONAPI_document_new ();
691 if (NULL == ego_entry)
694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
696 GNUNET_SCHEDULER_add_now (&return_response, handle);
699 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
700 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
701 handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp,
707 &collect_finished_cb,
713 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
717 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
718 const char* identity;
719 const char* name_str;
720 const char* value_str;
722 struct RequestHandle *handle = cls;
723 struct EgoEntry *ego_entry;
724 struct MHD_Response *resp;
725 struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute;
726 struct GNUNET_JSONAPI_Document *json_obj;
727 struct GNUNET_JSONAPI_Resource *json_res;
728 char term_data[handle->rest_handle->data_size+1];
732 struct GNUNET_JSON_Specification docspec[] = {
733 GNUNET_JSON_spec_jsonapi_document (&json_obj),
734 GNUNET_JSON_spec_end()
737 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
739 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
740 strlen (handle->url))
742 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
743 GNUNET_SCHEDULER_add_now (&do_error, handle);
746 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
748 for (ego_entry = handle->ego_head;
750 ego_entry = ego_entry->next)
751 if (0 == strcmp (identity, ego_entry->identifier))
754 if (NULL == ego_entry)
756 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
757 "Identity unknown (%s)\n", identity);
758 GNUNET_JSONAPI_document_delete (json_obj);
761 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
763 if (0 >= handle->rest_handle->data_size)
765 GNUNET_SCHEDULER_add_now (&do_error, handle);
769 term_data[handle->rest_handle->data_size] = '\0';
770 GNUNET_memcpy (term_data,
771 handle->rest_handle->data,
772 handle->rest_handle->data_size);
773 data_json = json_loads (term_data,
776 GNUNET_assert (GNUNET_OK ==
777 GNUNET_JSON_parse (data_json, docspec,
779 json_decref (data_json);
780 if (NULL == json_obj)
782 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
783 "Unable to parse JSONAPI Object from %s\n",
785 GNUNET_SCHEDULER_add_now (&do_error, handle);
788 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
790 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
791 "Cannot create more than 1 resource! (Got %d)\n",
792 GNUNET_JSONAPI_document_resource_count (json_obj));
793 GNUNET_JSONAPI_document_delete (json_obj);
794 GNUNET_SCHEDULER_add_now (&do_error, handle);
797 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
798 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
799 GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
801 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
802 "Unsupported JSON data type\n");
803 GNUNET_JSONAPI_document_delete (json_obj);
804 resp = GNUNET_REST_create_response (NULL);
805 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
806 cleanup_handle (handle);
809 name_str = GNUNET_JSONAPI_resource_get_id (json_res);
810 value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
812 value_str = json_string_value (value_json);
813 attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str,
814 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
816 strlen (value_str) + 1);
817 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
818 handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
823 GNUNET_free (attribute);
824 GNUNET_JSONAPI_document_delete (json_obj);
830 * Collect all attributes for an ego
834 attr_collect (void *cls,
835 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
836 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
838 struct GNUNET_JSONAPI_Resource *json_resource;
839 struct RequestHandle *handle = cls;
843 if ((NULL == attr->name) || (NULL == attr->data))
845 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
849 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
851 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
853 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
855 tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type,
859 value = json_string (tmp_value);
861 GNUNET_JSONAPI_resource_add_attr (json_resource,
865 GNUNET_free(tmp_value);
866 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
872 * List attributes for identity request
874 * @param con_handle the connection handle
876 * @param cls the RequestHandle
879 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
883 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
884 struct RequestHandle *handle = cls;
885 struct EgoEntry *ego_entry;
888 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
890 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
891 strlen (handle->url))
893 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
894 GNUNET_SCHEDULER_add_now (&do_error, handle);
897 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
899 for (ego_entry = handle->ego_head;
901 ego_entry = ego_entry->next)
902 if (0 == strcmp (identity, ego_entry->identifier))
904 handle->resp_object = GNUNET_JSONAPI_document_new ();
907 if (NULL == ego_entry)
910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
912 GNUNET_SCHEDULER_add_now (&return_response, handle);
915 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
916 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
917 handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
923 &collect_finished_cb,
929 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
933 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
934 const char* identity_str;
935 const char* audience_str;
938 struct RequestHandle *handle = cls;
939 struct EgoEntry *ego_entry;
940 struct MHD_Response *resp;
941 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
942 struct GNUNET_JSONAPI_Document *json_obj;
943 struct GNUNET_JSONAPI_Resource *json_res;
944 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
945 char term_data[handle->rest_handle->data_size+1];
947 json_t *identity_json;
948 json_t *audience_json;
951 struct GNUNET_JSON_Specification docspec[] = {
952 GNUNET_JSON_spec_jsonapi_document (&json_obj),
953 GNUNET_JSON_spec_end()
956 if (0 >= handle->rest_handle->data_size)
958 GNUNET_SCHEDULER_add_now (&do_error, handle);
962 term_data[handle->rest_handle->data_size] = '\0';
963 GNUNET_memcpy (term_data,
964 handle->rest_handle->data,
965 handle->rest_handle->data_size);
966 data_json = json_loads (term_data,
969 GNUNET_assert (GNUNET_OK ==
970 GNUNET_JSON_parse (data_json, docspec,
972 json_decref (data_json);
973 if (NULL == json_obj)
975 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
976 "Unable to parse JSONAPI Object from %s\n",
978 GNUNET_SCHEDULER_add_now (&do_error, handle);
981 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
983 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
984 "Cannot create more than 1 resource! (Got %d)\n",
985 GNUNET_JSONAPI_document_resource_count (json_obj));
986 GNUNET_JSONAPI_document_delete (json_obj);
987 GNUNET_SCHEDULER_add_now (&do_error, handle);
990 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
991 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
992 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
994 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
995 "Unsupported JSON data type\n");
996 GNUNET_JSONAPI_document_delete (json_obj);
997 resp = GNUNET_REST_create_response (NULL);
998 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
999 cleanup_handle (handle);
1002 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1004 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1006 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1008 rnd_str = json_string_value (rnd_json);
1009 identity_str = json_string_value (identity_json);
1010 audience_str = json_string_value (audience_json);
1012 GNUNET_STRINGS_string_to_data (rnd_str,
1016 GNUNET_STRINGS_string_to_data (identity_str,
1017 strlen (identity_str),
1019 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1020 GNUNET_STRINGS_string_to_data (audience_str,
1021 strlen (audience_str),
1023 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1025 for (ego_entry = handle->ego_head;
1027 ego_entry = ego_entry->next)
1029 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1031 if (0 == memcmp (&ticket.identity,
1033 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1036 if (NULL == ego_entry)
1038 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1039 "Identity unknown (%s)\n", identity_str);
1040 GNUNET_JSONAPI_document_delete (json_obj);
1043 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1045 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1046 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
1051 GNUNET_JSONAPI_document_delete (json_obj);
1055 consume_cont (void *cls,
1056 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1057 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
1059 struct RequestHandle *handle = cls;
1060 struct GNUNET_JSONAPI_Resource *json_resource;
1063 if (NULL == identity)
1065 GNUNET_SCHEDULER_add_now (&return_response, handle);
1069 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
1071 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
1073 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
1075 value = json_string (attr->data);
1076 GNUNET_JSONAPI_resource_add_attr (json_resource,
1079 json_decref (value);
1083 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1087 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1088 const char* identity_str;
1089 const char* audience_str;
1090 const char* rnd_str;
1092 struct RequestHandle *handle = cls;
1093 struct EgoEntry *ego_entry;
1094 struct MHD_Response *resp;
1095 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
1096 struct GNUNET_JSONAPI_Document *json_obj;
1097 struct GNUNET_JSONAPI_Resource *json_res;
1098 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1099 char term_data[handle->rest_handle->data_size+1];
1101 json_t *identity_json;
1102 json_t *audience_json;
1105 struct GNUNET_JSON_Specification docspec[] = {
1106 GNUNET_JSON_spec_jsonapi_document (&json_obj),
1107 GNUNET_JSON_spec_end()
1110 if (0 >= handle->rest_handle->data_size)
1112 GNUNET_SCHEDULER_add_now (&do_error, handle);
1116 term_data[handle->rest_handle->data_size] = '\0';
1117 GNUNET_memcpy (term_data,
1118 handle->rest_handle->data,
1119 handle->rest_handle->data_size);
1120 data_json = json_loads (term_data,
1123 GNUNET_assert (GNUNET_OK ==
1124 GNUNET_JSON_parse (data_json, docspec,
1126 json_decref (data_json);
1127 if (NULL == json_obj)
1129 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1130 "Unable to parse JSONAPI Object from %s\n",
1132 GNUNET_SCHEDULER_add_now (&do_error, handle);
1135 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
1137 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1138 "Cannot create more than 1 resource! (Got %d)\n",
1139 GNUNET_JSONAPI_document_resource_count (json_obj));
1140 GNUNET_JSONAPI_document_delete (json_obj);
1141 GNUNET_SCHEDULER_add_now (&do_error, handle);
1144 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
1145 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
1146 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
1148 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1149 "Unsupported JSON data type\n");
1150 GNUNET_JSONAPI_document_delete (json_obj);
1151 resp = GNUNET_REST_create_response (NULL);
1152 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
1153 cleanup_handle (handle);
1156 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1158 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1160 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1162 rnd_str = json_string_value (rnd_json);
1163 identity_str = json_string_value (identity_json);
1164 audience_str = json_string_value (audience_json);
1166 GNUNET_STRINGS_string_to_data (rnd_str,
1170 GNUNET_STRINGS_string_to_data (identity_str,
1171 strlen (identity_str),
1173 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1174 GNUNET_STRINGS_string_to_data (audience_str,
1175 strlen (audience_str),
1177 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1179 for (ego_entry = handle->ego_head;
1181 ego_entry = ego_entry->next)
1183 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1185 if (0 == memcmp (&ticket.audience,
1187 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1190 if (NULL == ego_entry)
1192 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1193 "Identity unknown (%s)\n", identity_str);
1194 GNUNET_JSONAPI_document_delete (json_obj);
1197 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1198 handle->resp_object = GNUNET_JSONAPI_document_new ();
1199 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1200 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
1205 GNUNET_JSONAPI_document_delete (json_obj);
1211 * Respond to OPTIONS request
1213 * @param con_handle the connection handle
1214 * @param url the url
1215 * @param cls the RequestHandle
1218 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1222 struct MHD_Response *resp;
1223 struct RequestHandle *handle = cls;
1225 //For now, independent of path return all options
1226 resp = GNUNET_REST_create_response (NULL);
1227 MHD_add_response_header (resp,
1228 "Access-Control-Allow-Methods",
1230 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1231 cleanup_handle (handle);
1236 * Cookie interpretation
1239 cookie_identity_interpretation (struct RequestHandle *handle)
1241 struct GNUNET_HashCode cache_key;
1243 struct GNUNET_TIME_Absolute current_time, *relog_time;
1244 char delimiter[] = "; ";
1246 //gets identity of login try with cookie
1247 GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
1249 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
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);
1256 while ( NULL != handle->oidc->login_identity )
1258 if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
1262 handle->oidc->login_identity = strtok (NULL, delimiter);
1264 GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity),
1266 if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) )
1268 relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
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 )
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);
1280 handle->oidc->login_identity = NULL;
1289 login_redirection(void *cls)
1291 char *login_base_url;
1293 struct MHD_Response *resp;
1294 struct RequestHandle *handle = cls;
1297 == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
1298 "address", &login_base_url) )
1300 GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
1302 OIDC_RESPONSE_TYPE_KEY,
1303 handle->oidc->response_type,
1305 handle->oidc->client_id,
1306 OIDC_REDIRECT_URI_KEY,
1307 handle->oidc->redirect_uri,
1309 handle->oidc->scope,
1311 (NULL != handle->oidc->state) ? handle->oidc->state : "",
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);
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);
1326 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1327 GNUNET_free(new_redirect);
1328 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1332 * Function called if we had an error in zone-to-name mapping.
1335 oidc_iteration_error (void *cls)
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);
1344 oidc_ticket_issue_cb (void* cls,
1345 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
1347 struct RequestHandle *handle = cls;
1348 struct MHD_Response *resp;
1349 struct GNUNET_HashCode cache_key;
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));
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);
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);
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);
1388 oidc_collect_finished_cb (void *cls)
1390 struct RequestHandle *handle = cls;
1391 handle->attr_it = NULL;
1392 handle->ticket_it = NULL;
1393 if (NULL == handle->attr_list->list_head)
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);
1400 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_issue (handle->idp,
1402 &handle->oidc->client_pkey,
1404 &oidc_ticket_issue_cb,
1410 * Collect all attributes for an ego
1413 oidc_attr_collect (void *cls,
1414 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1415 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
1417 struct RequestHandle *handle = cls;
1418 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
1419 char* scope_variables;
1420 char* scope_variable;
1421 char delimiter[]=" ";
1423 if ( (NULL == attr->name) || (NULL == attr->data) )
1425 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1429 scope_variables = GNUNET_strdup(handle->oidc->scope);
1430 scope_variable = strtok (scope_variables, delimiter);
1431 while (NULL != scope_variable)
1433 if ( 0 == strcmp (attr->name, scope_variable) )
1437 scope_variable = strtok (NULL, delimiter);
1439 if ( NULL == scope_variable )
1441 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1444 GNUNET_free(scope_variables);
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);
1456 * Cookie and Time check
1459 login_check (void *cls)
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;
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
1472 == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time,
1475 relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
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 )
1482 != GNUNET_CRYPTO_ecdsa_public_key_from_string (
1483 handle->oidc->login_identity,
1484 strlen (handle->oidc->login_identity), &pubkey) )
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);
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)
1496 GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1498 == memcmp (&ego_pkey, &pubkey,
1499 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
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);
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);
1519 //GNUNET_free(relog_time);
1524 * Create a response with requested records
1526 * @param handle the RequestHandle
1529 namestore_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)
1534 struct RequestHandle *handle = cls;
1535 struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey;
1536 struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey;
1539 for (i = 0; i < rd_len; i++)
1541 if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type )
1544 if ( NULL != handle->oidc->login_identity )
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 ¤t_zone_pkey);
1553 if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1554 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1556 if ( 0 == memcmp (&login_identity_pkey, ¤t_zone_pkey,
1557 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1559 handle->oidc->is_client_trusted = GNUNET_YES;
1565 if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1566 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1568 handle->oidc->is_client_trusted = GNUNET_YES;
1573 GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it);
1577 * Iteration over all results finished, build final
1580 * @param cls the `struct RequestHandle`
1582 static void namestore_iteration_finished_GET (void *cls)
1584 struct RequestHandle *handle = cls;
1585 struct GNUNET_HashCode cache_key;
1587 char *expected_redirect_uri;
1588 char *expected_scope;
1589 char delimiter[]=" ";
1590 int number_of_ignored_parameter, iterator;
1593 handle->ego_entry = handle->ego_entry->next;
1595 if(NULL != handle->ego_entry)
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);
1603 if (GNUNET_NO == handle->oidc->is_client_trusted)
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);
1612 // REQUIRED value: redirect_uri
1613 GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1615 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1618 handle->emsg=GNUNET_strdup("invalid_request");
1619 handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
1620 GNUNET_SCHEDULER_add_now (&do_error, handle);
1623 handle->oidc->redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
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)) )
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);
1636 handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
1638 GNUNET_free(expected_redirect_uri);
1639 // REQUIRED value: response_type
1640 GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1642 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
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);
1650 handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1652 handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
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,
1659 handle->emsg=GNUNET_strdup("invalid_request");
1660 handle->edesc=GNUNET_strdup("missing parameter scope");
1661 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1664 handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1666 handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
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,
1673 handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1675 //TODO: what do we do with the nonce?
1676 handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
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++ )
1683 GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1684 strlen(OIDC_ignored_parameter_array[iterator]),
1686 if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
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);
1697 // Checks if response_type is 'code'
1698 if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
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);
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)
1712 if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1716 expected_scope = strtok (NULL, delimiter);
1718 if (NULL == expected_scope)
1720 handle->emsg = GNUNET_strdup("invalid_scope");
1721 handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1723 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1727 GNUNET_free(expected_scope);
1729 if( NULL != handle->oidc->login_identity )
1731 GNUNET_SCHEDULER_add_now(&login_check,handle);
1735 GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1739 * Responds to authorization GET request
1741 * @param con_handle the connection handle
1742 * @param url the url
1743 * @param cls the RequestHandle
1746 authorize_GET_cont (struct GNUNET_REST_RequestHandle *con_handle,
1750 struct RequestHandle *handle = cls;
1751 struct GNUNET_HashCode cache_key;
1753 cookie_identity_interpretation(handle);
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,
1760 handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1762 handle->oidc->state = GNUNET_strdup (handle->oidc->state);
1765 // REQUIRED value: client_id
1766 GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1768 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
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);
1777 handle->oidc->client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1779 handle->oidc->client_id = GNUNET_strdup (handle->oidc->client_id);
1782 != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
1783 strlen (handle->oidc->client_id),
1784 &handle->oidc->client_pkey) )
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);
1795 if ( NULL == handle->ego_head )
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);
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;
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);
1817 * Iteration over all results finished, build final
1820 * @param cls the `struct RequestHandle`
1822 static void namestore_iteration_finished_POST (void *cls)
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;
1832 handle->ego_entry = handle->ego_entry->next;
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);
1841 if (GNUNET_YES != handle->oidc->is_client_trusted)
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);
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) )
1854 handle->emsg=GNUNET_strdup("invalid_request");
1855 handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
1856 GNUNET_SCHEDULER_add_now (&do_error, handle);
1859 handle->oidc->redirect_uri = json_string_value (cache_object);
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)) )
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);
1871 handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
1872 GNUNET_free(expected_redirect_uri);
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) )
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);
1883 handle->oidc->response_type = json_string_value (cache_object);
1884 handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
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) )
1890 handle->emsg=GNUNET_strdup("invalid_request");
1891 handle->edesc=GNUNET_strdup("missing parameter scope");
1892 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1895 handle->oidc->scope = json_string_value (cache_object);
1896 handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
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) )
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);
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++ )
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) )
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);
1922 // Checks if response_type is 'code'
1923 if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
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);
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)
1937 if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1941 expected_scope = strtok (NULL, delimiter);
1943 if (NULL == expected_scope)
1945 handle->emsg = GNUNET_strdup("invalid_scope");
1946 handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1948 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1952 GNUNET_free(expected_scope);
1954 if( NULL != handle->oidc->login_identity )
1956 GNUNET_SCHEDULER_add_now(&login_check,handle);
1960 GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1965 * Responds to authorization POST request
1967 * @param con_handle the connection handle
1968 * @param url the url
1969 * @param cls the RequestHandle
1972 authorize_POST_cont (struct GNUNET_REST_RequestHandle *con_handle,
1976 struct RequestHandle *handle = cls;
1977 json_t *cache_object;
1979 handle->oidc->post_object = json_loads (handle->rest_handle->data, 0, &error);
1981 //gets identity of login try with cookie
1982 cookie_identity_interpretation(handle);
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) )
1988 handle->oidc->state = json_string_value (cache_object);
1989 handle->oidc->state = GNUNET_strdup(handle->oidc->state);
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) )
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);
2003 handle->oidc->client_id = json_string_value (cache_object);
2004 handle->oidc->client_id = GNUNET_strdup(handle->oidc->client_id);
2007 != GNUNET_CRYPTO_ecdsa_public_key_from_string (
2008 handle->oidc->client_id, strlen (handle->oidc->client_id),
2009 &handle->oidc->client_pkey) )
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);
2019 if ( NULL == handle->ego_head )
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);
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;
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);
2041 * Combines an identity with a login time and responds OK to login request
2043 * @param con_handle the connection handle
2044 * @param url the url
2045 * @param cls the RequestHandle
2048 login_cont (struct GNUNET_REST_RequestHandle *con_handle,
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;
2061 root = json_loads (handle->rest_handle->data, 0, &error);
2062 identity = json_object_get (root, "identity");
2063 if ( json_is_string(identity) )
2065 GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
2067 GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
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_ (),
2073 last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key);
2074 if (NULL != last_time)
2076 GNUNET_free(last_time);
2078 GNUNET_CONTAINER_multihashmap_put (
2079 OIDC_identity_login_time, &cache_key, current_time,
2080 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
2082 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2086 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
2088 GNUNET_free(cookie);
2090 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
2095 token_cont(struct GNUNET_REST_RequestHandle *con_handle,
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;
2106 char *grant_type, *code, *expected_jwt, *redirect_uri, *expected_redirect_uri;
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),
2112 if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
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);
2123 jwt = strtok(jwt, delimiter);
2124 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Test:%s\n", jwt);
2127 cache_object = json_object_get (handle->oidc->post_object, "grant_type");
2128 if ( NULL == cache_object || !json_is_string(cache_object) )
2130 handle->emsg=GNUNET_strdup("invalid_request");
2131 handle->edesc=GNUNET_strdup("missing parameter grant_type");
2132 GNUNET_SCHEDULER_add_now (&do_error, handle);
2135 grant_type = json_string_value (cache_object);
2137 //Check parameter grant_type == "authorization_code"
2138 if (0 != strcmp("authorization_code", grant_type))
2143 cache_object = json_object_get (handle->oidc->post_object, "code");
2144 if ( NULL == cache_object || !json_is_string(cache_object) )
2146 handle->emsg=GNUNET_strdup("invalid_request");
2147 handle->edesc=GNUNET_strdup("missing parameter code");
2148 GNUNET_SCHEDULER_add_now (&do_error, handle);
2151 code = json_string_value (cache_object);
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) )
2159 expected_jwt = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_grants, &cache_key);
2161 if (0 != strcmp(expected_jwt,jwt))
2166 cache_object = json_object_get (handle->oidc->post_object, "redirect_uri");
2167 if ( NULL == cache_object || !json_is_string(cache_object) )
2169 handle->emsg=GNUNET_strdup("invalid_request");
2170 handle->edesc=GNUNET_strdup("missing parameter code");
2171 GNUNET_SCHEDULER_add_now (&do_error, handle);
2174 redirect_uri = json_string_value (cache_object);
2176 // check redirect_uri
2177 // jwt breakdown to iss or sub
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)) )
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);
2189 // handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
2190 // GNUNET_free(expected_redirect_uri);
2193 //do we need the client_id?
2195 GNUNET_free(cache_authorization);
2196 decref(handle->oidc->post_object);
2200 * Handle rest request
2202 * @param handle the request handle
2205 init_cont (struct RequestHandle *handle)
2207 struct GNUNET_REST_RequestHandlerError err;
2208 static const struct GNUNET_REST_RequestHandler handlers[] = {
2209 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
2210 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_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},
2216 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
2217 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
2218 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
2220 GNUNET_REST_HANDLER_END
2223 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
2228 handle->response_code = err.error_code;
2229 GNUNET_SCHEDULER_add_now (&do_error, handle);
2234 * If listing is enabled, prints information about the egos.
2236 * This function is initially called for all egos and then again
2237 * whenever a ego's identifier changes or if it is deleted. At the
2238 * end of the initial pass over all egos, the function is once called
2239 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
2240 * be invoked in the future or that there was an error.
2242 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
2243 * this function is only called ONCE, and 'NULL' being passed in
2244 * 'ego' does indicate an error (i.e. name is taken or no default
2245 * value is known). If 'ego' is non-NULL and if '*ctx'
2246 * is set in those callbacks, the value WILL be passed to a subsequent
2247 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
2248 * that one was not NULL).
2250 * When an identity is renamed, this function is called with the
2251 * (known) ego but the NEW identifier.
2253 * When an identity is deleted, this function is called with the
2254 * (known) ego and "NULL" for the 'identifier'. In this case,
2255 * the 'ego' is henceforth invalid (and the 'ctx' should also be
2258 * @param cls closure
2259 * @param ego ego handle
2260 * @param ctx context for application to store data for this ego
2261 * (during the lifetime of this process, initially NULL)
2262 * @param identifier identifier assigned by the user for this ego,
2263 * NULL if the user just deleted the ego and it
2264 * must thus no longer be used
2267 list_ego (void *cls,
2268 struct GNUNET_IDENTITY_Ego *ego,
2270 const char *identifier)
2272 struct RequestHandle *handle = cls;
2273 struct EgoEntry *ego_entry;
2274 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
2276 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
2278 handle->state = ID_REST_STATE_POST_INIT;
2282 if (ID_REST_STATE_INIT == handle->state) {
2283 ego_entry = GNUNET_new (struct EgoEntry);
2284 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2285 ego_entry->keystring =
2286 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
2287 ego_entry->ego = ego;
2288 ego_entry->identifier = GNUNET_strdup (identifier);
2289 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
2295 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
2296 GNUNET_REST_ResultProcessor proc,
2299 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
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;
2306 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
2307 handle->proc_cls = proc_cls;
2308 handle->proc = proc;
2309 handle->state = ID_REST_STATE_INIT;
2310 handle->rest_handle = rest_handle;
2312 handle->url = GNUNET_strdup (rest_handle->url);
2313 if (handle->url[strlen (handle->url)-1] == '/')
2314 handle->url[strlen (handle->url)-1] = '\0';
2315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2317 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
2320 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
2321 handle->timeout_task =
2322 GNUNET_SCHEDULER_add_delayed (handle->timeout,
2325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2330 * Entry point for the plugin.
2332 * @param cls Config info
2333 * @return NULL on error, otherwise the plugin context
2336 libgnunet_plugin_rest_identity_provider_init (void *cls)
2338 static struct Plugin plugin;
2339 struct GNUNET_REST_Plugin *api;
2342 if (NULL != plugin.cfg)
2343 return NULL; /* can only initialize once! */
2344 memset (&plugin, 0, sizeof (struct Plugin));
2346 api = GNUNET_new (struct GNUNET_REST_Plugin);
2348 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
2349 api->process_request = &rest_identity_process_request;
2350 GNUNET_asprintf (&allow_methods,
2351 "%s, %s, %s, %s, %s",
2352 MHD_HTTP_METHOD_GET,
2353 MHD_HTTP_METHOD_POST,
2354 MHD_HTTP_METHOD_PUT,
2355 MHD_HTTP_METHOD_DELETE,
2356 MHD_HTTP_METHOD_OPTIONS);
2358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2359 _("Identity Provider REST API initialized\n"));
2365 * Exit point from the plugin.
2367 * @param cls the plugin context (as returned by "init")
2368 * @return always NULL
2371 libgnunet_plugin_rest_identity_provider_done (void *cls)
2373 struct GNUNET_REST_Plugin *api = cls;
2374 struct Plugin *plugin = api->cls;
2377 struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
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))
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))
2395 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
2396 GNUNET_free_non_null (allow_methods);
2398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2399 "Identity Provider REST plugin is finished\n");
2403 /* end of plugin_rest_identity_provider.c */