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);
1523 * Create a response with requested records
1525 * @param handle the RequestHandle
1528 namestore_iteration_callback (
1529 void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1530 const char *rname, unsigned int rd_len,
1531 const struct GNUNET_GNSRECORD_Data *rd)
1533 struct RequestHandle *handle = cls;
1534 struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey;
1535 struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey;
1538 for (i = 0; i < rd_len; i++)
1540 if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type )
1543 if ( NULL != handle->oidc->login_identity )
1545 GNUNET_CRYPTO_ecdsa_public_key_from_string (
1546 handle->oidc->login_identity,
1547 strlen (handle->oidc->login_identity),
1548 &login_identity_pkey);
1549 GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego,
1550 ¤t_zone_pkey);
1552 if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1553 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1555 if ( 0 == memcmp (&login_identity_pkey, ¤t_zone_pkey,
1556 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1558 handle->oidc->is_client_trusted = GNUNET_YES;
1564 if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1565 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1567 handle->oidc->is_client_trusted = GNUNET_YES;
1572 GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it);
1576 * Iteration over all results finished, build final
1579 * @param cls the `struct RequestHandle`
1581 static void namestore_iteration_finished_GET (void *cls)
1583 struct RequestHandle *handle = cls;
1584 struct GNUNET_HashCode cache_key;
1586 char *expected_redirect_uri;
1587 char *expected_scope;
1588 char delimiter[]=" ";
1589 int number_of_ignored_parameter, iterator;
1592 handle->ego_entry = handle->ego_entry->next;
1594 if(NULL != handle->ego_entry)
1596 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1597 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
1598 &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
1599 &namestore_iteration_finished_GET, handle);
1602 if (GNUNET_NO == handle->oidc->is_client_trusted)
1604 handle->emsg = GNUNET_strdup("unauthorized_client");
1605 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1606 "authorization code using this method.");
1607 GNUNET_SCHEDULER_add_now (&do_error, handle);
1611 // REQUIRED value: redirect_uri
1612 GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1614 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1617 handle->emsg=GNUNET_strdup("invalid_request");
1618 handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
1619 GNUNET_SCHEDULER_add_now (&do_error, handle);
1622 handle->oidc->redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1625 GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
1626 // verify the redirect uri matches https://<client_id>.zkey[/xyz]
1627 if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
1629 handle->emsg=GNUNET_strdup("invalid_request");
1630 handle->edesc=GNUNET_strdup("Invalid redirect_uri");
1631 GNUNET_SCHEDULER_add_now (&do_error, handle);
1632 GNUNET_free(expected_redirect_uri);
1635 handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
1637 GNUNET_free(expected_redirect_uri);
1638 // REQUIRED value: response_type
1639 GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1641 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1644 handle->emsg=GNUNET_strdup("invalid_request");
1645 handle->edesc=GNUNET_strdup("missing parameter response_type");
1646 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1649 handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1651 handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
1653 // REQUIRED value: scope
1654 GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
1655 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1658 handle->emsg=GNUNET_strdup("invalid_request");
1659 handle->edesc=GNUNET_strdup("missing parameter scope");
1660 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1663 handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1665 handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
1667 //OPTIONAL value: nonce
1668 GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
1669 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1672 handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1674 //TODO: what do we do with the nonce? => token
1675 handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
1678 //TODO check other values and use them accordingly
1679 number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1680 for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1682 GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1683 strlen(OIDC_ignored_parameter_array[iterator]),
1685 if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
1688 handle->emsg=GNUNET_strdup("access_denied");
1689 GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1690 OIDC_ignored_parameter_array[iterator]);
1691 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1696 // Checks if response_type is 'code'
1697 if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1699 handle->emsg=GNUNET_strdup("unsupported_response_type");
1700 handle->edesc=GNUNET_strdup("The authorization server does not support "
1701 "obtaining this authorization code.");
1702 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1706 // Checks if scope contains 'openid'
1707 expected_scope = GNUNET_strdup(handle->oidc->scope);
1708 expected_scope = strtok (expected_scope, delimiter);
1709 while (NULL != expected_scope)
1711 if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1715 expected_scope = strtok (NULL, delimiter);
1717 if (NULL == expected_scope)
1719 handle->emsg = GNUNET_strdup("invalid_scope");
1720 handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1722 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1726 GNUNET_free(expected_scope);
1728 if( NULL != handle->oidc->login_identity )
1730 GNUNET_SCHEDULER_add_now(&login_check,handle);
1734 GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1738 * Responds to authorization GET request
1740 * @param con_handle the connection handle
1741 * @param url the url
1742 * @param cls the RequestHandle
1745 authorize_GET_cont (struct GNUNET_REST_RequestHandle *con_handle,
1749 struct RequestHandle *handle = cls;
1750 struct GNUNET_HashCode cache_key;
1752 cookie_identity_interpretation(handle);
1754 //RECOMMENDED value: state - REQUIRED for answers
1755 GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
1756 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1759 handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1761 handle->oidc->state = GNUNET_strdup (handle->oidc->state);
1764 // REQUIRED value: client_id
1765 GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1767 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1770 handle->emsg=GNUNET_strdup("invalid_request");
1771 handle->edesc=GNUNET_strdup("missing parameter client_id");
1772 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1773 GNUNET_SCHEDULER_add_now (&do_error, handle);
1776 handle->oidc->client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1778 handle->oidc->client_id = GNUNET_strdup (handle->oidc->client_id);
1781 != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
1782 strlen (handle->oidc->client_id),
1783 &handle->oidc->client_pkey) )
1785 handle->emsg = GNUNET_strdup("unauthorized_client");
1786 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1787 "authorization code using this method.");
1788 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1789 GNUNET_SCHEDULER_add_now (&do_error, handle);
1794 if ( NULL == handle->ego_head )
1796 handle->emsg = GNUNET_strdup("server_error");
1797 handle->edesc = GNUNET_strdup ("Egos are missing");
1798 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1799 GNUNET_SCHEDULER_add_now (&do_error, handle);
1803 handle->ego_entry = handle->ego_head;
1804 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
1805 handle->oidc->is_client_trusted = GNUNET_NO;
1807 // Checks if client_id is valid:
1808 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
1809 handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
1810 handle, &namestore_iteration_callback, handle,
1811 &namestore_iteration_finished_GET, handle);
1815 * Iteration over all results finished, build final
1818 * @param cls the `struct RequestHandle`
1820 static void namestore_iteration_finished_POST (void *cls)
1822 struct RequestHandle *handle = cls;
1823 json_t *cache_object;
1824 char *expected_redirect_uri;
1825 char *expected_scope;
1826 char delimiter[]=" ";
1827 int number_of_ignored_parameter, iterator;
1830 handle->ego_entry = handle->ego_entry->next;
1832 if(NULL != handle->ego_entry){
1833 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1834 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
1835 &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
1836 &namestore_iteration_finished_POST, handle);
1839 if (GNUNET_YES != handle->oidc->is_client_trusted)
1841 handle->emsg = GNUNET_strdup("unauthorized_client");
1842 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1843 "authorization code using this method.");
1844 GNUNET_SCHEDULER_add_now (&do_error, handle);
1848 // REQUIRED value: redirect_uri
1849 cache_object = json_object_get (handle->oidc->post_object, OIDC_REDIRECT_URI_KEY);
1850 if ( NULL == cache_object || !json_is_string(cache_object) )
1852 handle->emsg=GNUNET_strdup("invalid_request");
1853 handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
1854 GNUNET_SCHEDULER_add_now (&do_error, handle);
1857 handle->oidc->redirect_uri = json_string_value (cache_object);
1859 GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
1860 // verify the redirect uri matches https://<client_id>.zkey[/xyz]
1861 if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
1863 handle->emsg=GNUNET_strdup("invalid_request");
1864 handle->edesc=GNUNET_strdup("Invalid redirect_uri");
1865 GNUNET_SCHEDULER_add_now (&do_error, handle);
1866 GNUNET_free(expected_redirect_uri);
1869 handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
1870 GNUNET_free(expected_redirect_uri);
1872 // REQUIRED value: response_type
1873 cache_object = json_object_get (handle->oidc->post_object, OIDC_RESPONSE_TYPE_KEY);
1874 if ( NULL == cache_object || !json_is_string(cache_object) )
1876 handle->emsg=GNUNET_strdup("invalid_request");
1877 handle->edesc=GNUNET_strdup("missing parameter response_type");
1878 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1881 handle->oidc->response_type = json_string_value (cache_object);
1882 handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
1884 // REQUIRED value: scope
1885 cache_object = json_object_get (handle->oidc->post_object, OIDC_SCOPE_KEY);
1886 if ( NULL == cache_object || !json_is_string(cache_object) )
1888 handle->emsg=GNUNET_strdup("invalid_request");
1889 handle->edesc=GNUNET_strdup("missing parameter scope");
1890 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1893 handle->oidc->scope = json_string_value (cache_object);
1894 handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
1896 //OPTIONAL value: nonce
1897 cache_object = json_object_get (handle->oidc->post_object, OIDC_NONCE_KEY);
1898 if ( NULL != cache_object && json_is_string(cache_object) )
1900 handle->oidc->nonce = json_string_value (cache_object);
1901 //TODO: what do we do with the nonce?
1902 handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
1905 //TODO check other values and use them accordingly
1906 number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1907 for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1909 cache_object = json_object_get (handle->oidc->post_object, OIDC_ignored_parameter_array[iterator]);
1910 if( NULL != cache_object && json_is_string(cache_object) )
1912 handle->emsg=GNUNET_strdup("access_denied");
1913 GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1914 OIDC_ignored_parameter_array[iterator]);
1915 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1920 // Checks if response_type is 'code'
1921 if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1923 handle->emsg=GNUNET_strdup("unsupported_response_type");
1924 handle->edesc=GNUNET_strdup("The authorization server does not support "
1925 "obtaining this authorization code.");
1926 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1930 // Checks if scope contains 'openid'
1931 expected_scope = GNUNET_strdup(handle->oidc->scope);
1932 expected_scope = strtok (expected_scope, delimiter);
1933 while (NULL != expected_scope)
1935 if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1939 expected_scope = strtok (NULL, delimiter);
1941 if (NULL == expected_scope)
1943 handle->emsg = GNUNET_strdup("invalid_scope");
1944 handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1946 GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1950 GNUNET_free(expected_scope);
1952 if( NULL != handle->oidc->login_identity )
1954 GNUNET_SCHEDULER_add_now(&login_check,handle);
1958 GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1963 * Responds to authorization POST request
1965 * @param con_handle the connection handle
1966 * @param url the url
1967 * @param cls the RequestHandle
1970 authorize_POST_cont (struct GNUNET_REST_RequestHandle *con_handle,
1974 struct RequestHandle *handle = cls;
1975 json_t *cache_object;
1977 handle->oidc->post_object = json_loads (handle->rest_handle->data, 0, &error);
1979 //gets identity of login try with cookie
1980 cookie_identity_interpretation(handle);
1982 //RECOMMENDED value: state - REQUIRED for answers
1983 cache_object = json_object_get (handle->oidc->post_object, OIDC_STATE_KEY);
1984 if ( NULL != cache_object && json_is_string(cache_object) )
1986 handle->oidc->state = json_string_value (cache_object);
1987 handle->oidc->state = GNUNET_strdup(handle->oidc->state);
1990 // REQUIRED value: client_id
1991 cache_object = json_object_get (handle->oidc->post_object,
1992 OIDC_CLIENT_ID_KEY);
1993 if ( NULL == cache_object || !json_is_string(cache_object) )
1995 handle->emsg = GNUNET_strdup("invalid_request");
1996 handle->edesc = GNUNET_strdup("missing parameter client_id");
1997 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1998 GNUNET_SCHEDULER_add_now (&do_error, handle);
2001 handle->oidc->client_id = json_string_value (cache_object);
2002 handle->oidc->client_id = GNUNET_strdup(handle->oidc->client_id);
2005 != GNUNET_CRYPTO_ecdsa_public_key_from_string (
2006 handle->oidc->client_id, strlen (handle->oidc->client_id),
2007 &handle->oidc->client_pkey) )
2009 handle->emsg = GNUNET_strdup("unauthorized_client");
2010 handle->edesc = GNUNET_strdup("The client is not authorized to request an "
2011 "authorization code using this method.");
2012 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2013 GNUNET_SCHEDULER_add_now (&do_error, handle);
2017 if ( NULL == handle->ego_head )
2019 //TODO throw error or ignore if egos are missing?
2020 handle->emsg = GNUNET_strdup("server_error");
2021 handle->edesc = GNUNET_strdup ("Egos are missing");
2022 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2023 GNUNET_SCHEDULER_add_now (&do_error, handle);
2027 handle->ego_entry = handle->ego_head;
2028 handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
2029 handle->oidc->is_client_trusted = GNUNET_NO;
2031 // Checks if client_id is valid:
2032 handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
2033 handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
2034 handle, &namestore_iteration_callback, handle,
2035 &namestore_iteration_finished_POST, handle);
2039 * Combines an identity with a login time and responds OK to login request
2041 * @param con_handle the connection handle
2042 * @param url the url
2043 * @param cls the RequestHandle
2046 login_cont (struct GNUNET_REST_RequestHandle *con_handle,
2050 struct MHD_Response *resp = GNUNET_REST_create_response ("");
2051 struct RequestHandle *handle = cls;
2052 struct GNUNET_HashCode cache_key;
2053 struct GNUNET_TIME_Absolute *current_time;
2054 struct GNUNET_TIME_Absolute *last_time;
2059 root = json_loads (handle->rest_handle->data, 0, &error);
2060 identity = json_object_get (root, "identity");
2061 if ( json_is_string(identity) )
2063 GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
2065 GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
2067 current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
2068 *current_time = GNUNET_TIME_relative_to_absolute (
2069 GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_minute_ (),
2071 last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key);
2072 if (NULL != last_time)
2074 GNUNET_free(last_time);
2076 GNUNET_CONTAINER_multihashmap_put (
2077 OIDC_identity_login_time, &cache_key, current_time,
2078 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
2080 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2084 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
2086 GNUNET_free(cookie);
2088 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
2093 token_cont(struct GNUNET_REST_RequestHandle *con_handle,
2097 //TODO static strings
2098 struct RequestHandle *handle = cls;
2099 struct GNUNET_HashCode cache_key;
2100 char *authorization, *cache_authorization, *credentials;
2101 char delimiter[]=" ";
2102 char delimiter_user_psw[]=":";
2103 json_t *cache_object;
2105 char *grant_type, *code, *expected_jwt, *redirect_uri, *expected_redirect_uri;
2106 char *user_psw, *user, *psw;
2108 int client_exists = GNUNET_NO;
2110 handle->oidc->post_object = json_loads (handle->rest_handle->data, 0, &error);
2111 //Check Authorization Header
2112 GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
2114 if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
2119 authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
2120 //split JWT in "Basic" and [content]
2121 cache_authorization = GNUNET_strdup (authorization);
2122 credentials = strtok(cache_authorization,delimiter);
2123 if( NULL != credentials)
2125 credentials = strtok(credentials, delimiter);
2126 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Test:%s\n", credentials);
2128 if (NULL == credentials)
2132 GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), &user_psw);
2134 if ( NULL == user_psw )
2138 user = strtok (user_psw, delimiter_user_psw);
2144 psw = strtok (user, delimiter_user_psw);
2152 == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
2153 "psw", &expected_psw) )
2155 if (0 != strcmp (expected_psw, psw))
2159 GNUNET_free(expected_psw);
2163 handle->emsg = GNUNET_strdup("server_error");
2164 handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2165 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2166 GNUNET_SCHEDULER_add_now (&do_error, handle);
2171 for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; )
2173 if (handle->ego_entry->keystring == user)
2175 client_exists = GNUNET_YES;
2178 handle->ego_entry = handle->ego_entry->next;
2180 if (GNUNET_NO == client_exists)
2185 cache_object = json_object_get (handle->oidc->post_object, "grant_type");
2186 if ( NULL == cache_object || !json_is_string(cache_object) )
2188 handle->emsg=GNUNET_strdup("invalid_request");
2189 handle->edesc=GNUNET_strdup("missing parameter grant_type");
2190 GNUNET_SCHEDULER_add_now (&do_error, handle);
2193 grant_type = json_string_value (cache_object);
2195 //Check parameter grant_type == "authorization_code"
2196 if (0 != strcmp("authorization_code", grant_type))
2201 cache_object = json_object_get (handle->oidc->post_object, "code");
2202 if ( NULL == cache_object || !json_is_string(cache_object) )
2204 handle->emsg=GNUNET_strdup("invalid_request");
2205 handle->edesc=GNUNET_strdup("missing parameter code");
2206 GNUNET_SCHEDULER_add_now (&do_error, handle);
2209 code = json_string_value (cache_object);
2211 // lookup code in grants_hashmap and check if [content] is same
2213 cache_object = json_object_get (handle->oidc->post_object, "redirect_uri");
2214 if ( NULL == cache_object || !json_is_string(cache_object) )
2216 handle->emsg=GNUNET_strdup("invalid_request");
2217 handle->edesc=GNUNET_strdup("missing parameter code");
2218 GNUNET_SCHEDULER_add_now (&do_error, handle);
2221 redirect_uri = json_string_value (cache_object);
2223 // check redirect_uri
2224 GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", user);
2225 // verify the redirect uri matches https://<client_id>.zkey[/xyz]
2226 if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
2228 handle->emsg=GNUNET_strdup("invalid_request");
2229 handle->edesc=GNUNET_strdup("Invalid redirect_uri");
2230 GNUNET_SCHEDULER_add_now (&do_error, handle);
2231 GNUNET_free(expected_redirect_uri);
2234 handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
2235 GNUNET_free(expected_redirect_uri);
2239 GNUNET_free(cache_authorization);
2240 json_decref(handle->oidc->post_object);
2244 * Handle rest request
2246 * @param handle the request handle
2249 init_cont (struct RequestHandle *handle)
2251 struct GNUNET_REST_RequestHandlerError err;
2252 static const struct GNUNET_REST_RequestHandler handlers[] = {
2253 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
2254 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
2255 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
2256 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_GET_cont},
2257 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_GET_cont},
2258 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
2259 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_cont},
2260 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
2261 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
2262 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
2264 GNUNET_REST_HANDLER_END
2267 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
2272 handle->response_code = err.error_code;
2273 GNUNET_SCHEDULER_add_now (&do_error, handle);
2278 * If listing is enabled, prints information about the egos.
2280 * This function is initially called for all egos and then again
2281 * whenever a ego's identifier changes or if it is deleted. At the
2282 * end of the initial pass over all egos, the function is once called
2283 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
2284 * be invoked in the future or that there was an error.
2286 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
2287 * this function is only called ONCE, and 'NULL' being passed in
2288 * 'ego' does indicate an error (i.e. name is taken or no default
2289 * value is known). If 'ego' is non-NULL and if '*ctx'
2290 * is set in those callbacks, the value WILL be passed to a subsequent
2291 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
2292 * that one was not NULL).
2294 * When an identity is renamed, this function is called with the
2295 * (known) ego but the NEW identifier.
2297 * When an identity is deleted, this function is called with the
2298 * (known) ego and "NULL" for the 'identifier'. In this case,
2299 * the 'ego' is henceforth invalid (and the 'ctx' should also be
2302 * @param cls closure
2303 * @param ego ego handle
2304 * @param ctx context for application to store data for this ego
2305 * (during the lifetime of this process, initially NULL)
2306 * @param identifier identifier assigned by the user for this ego,
2307 * NULL if the user just deleted the ego and it
2308 * must thus no longer be used
2311 list_ego (void *cls,
2312 struct GNUNET_IDENTITY_Ego *ego,
2314 const char *identifier)
2316 struct RequestHandle *handle = cls;
2317 struct EgoEntry *ego_entry;
2318 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
2320 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
2322 handle->state = ID_REST_STATE_POST_INIT;
2326 if (ID_REST_STATE_INIT == handle->state) {
2327 ego_entry = GNUNET_new (struct EgoEntry);
2328 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2329 ego_entry->keystring =
2330 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
2331 ego_entry->ego = ego;
2332 ego_entry->identifier = GNUNET_strdup (identifier);
2333 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
2339 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
2340 GNUNET_REST_ResultProcessor proc,
2343 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2344 handle->oidc = GNUNET_new (struct OIDC_Variables);
2345 if ( NULL == OIDC_identity_login_time )
2346 OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2347 if ( NULL == OIDC_identity_grants )
2348 OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2349 handle->response_code = 0;
2350 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
2351 handle->proc_cls = proc_cls;
2352 handle->proc = proc;
2353 handle->state = ID_REST_STATE_INIT;
2354 handle->rest_handle = rest_handle;
2356 handle->url = GNUNET_strdup (rest_handle->url);
2357 if (handle->url[strlen (handle->url)-1] == '/')
2358 handle->url[strlen (handle->url)-1] = '\0';
2359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2361 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
2364 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
2365 handle->timeout_task =
2366 GNUNET_SCHEDULER_add_delayed (handle->timeout,
2369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2374 * Entry point for the plugin.
2376 * @param cls Config info
2377 * @return NULL on error, otherwise the plugin context
2380 libgnunet_plugin_rest_identity_provider_init (void *cls)
2382 static struct Plugin plugin;
2383 struct GNUNET_REST_Plugin *api;
2386 if (NULL != plugin.cfg)
2387 return NULL; /* can only initialize once! */
2388 memset (&plugin, 0, sizeof (struct Plugin));
2390 api = GNUNET_new (struct GNUNET_REST_Plugin);
2392 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
2393 api->process_request = &rest_identity_process_request;
2394 GNUNET_asprintf (&allow_methods,
2395 "%s, %s, %s, %s, %s",
2396 MHD_HTTP_METHOD_GET,
2397 MHD_HTTP_METHOD_POST,
2398 MHD_HTTP_METHOD_PUT,
2399 MHD_HTTP_METHOD_DELETE,
2400 MHD_HTTP_METHOD_OPTIONS);
2402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2403 _("Identity Provider REST API initialized\n"));
2409 * Exit point from the plugin.
2411 * @param cls the plugin context (as returned by "init")
2412 * @return always NULL
2415 libgnunet_plugin_rest_identity_provider_done (void *cls)
2417 struct GNUNET_REST_Plugin *api = cls;
2418 struct Plugin *plugin = api->cls;
2421 struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2423 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
2424 OIDC_identity_login_time);
2425 while (GNUNET_YES ==
2426 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2431 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time);
2432 hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants);
2433 while (GNUNET_YES ==
2434 GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2439 GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
2440 GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it);
2441 GNUNET_free_non_null (allow_methods);
2443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2444 "Identity Provider REST plugin is finished\n");
2448 /* end of plugin_rest_identity_provider.c */