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_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
81 #define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
87 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value"
90 * State while collecting all egos
92 #define ID_REST_STATE_INIT 0
95 * Done collecting egos
97 #define ID_REST_STATE_POST_INIT 1
100 * OIDC response_type key
102 #define OIDC_RESPONSE_TYPE_KEY "response_type"
107 #define OIDC_CLIENT_ID_KEY "client_id"
112 #define OIDC_SCOPE_KEY "scope"
115 * OIDC redirect_uri key
117 #define OIDC_REDIRECT_URI_KEY "redirect_uri"
122 #define OIDC_STATE_KEY "state"
127 #define OIDC_NONCE_KEY "nonce"
130 * OIDC expected response_type while authorizing
132 #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
135 * OIDC expected scope part while authorizing
137 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
141 * OIDC ignored parameter array
143 char* OIDC_ignored_parameter_array [] =
156 * The configuration handle
158 const struct GNUNET_CONFIGURATION_Handle *cfg;
161 * HTTP methods allows for this plugin
163 static char* allow_methods;
166 * @brief struct returned by the initialization function of the plugin
170 const struct GNUNET_CONFIGURATION_Handle *cfg;
181 struct EgoEntry *next;
186 struct EgoEntry *prev;
201 struct GNUNET_IDENTITY_Ego *ego;
210 struct EgoEntry *ego_head;
215 struct EgoEntry *ego_tail;
220 struct EgoEntry *ego_entry;
223 * Ptr to current ego private key
225 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
228 * The processing state
233 * Handle to Identity service.
235 struct GNUNET_IDENTITY_Handle *identity_handle;
240 struct GNUNET_REST_RequestHandle *rest_handle;
246 struct GNUNET_IDENTITY_Operation *op;
251 struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
256 struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
261 struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it;
266 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it;
269 * Desired timeout for the lookup (default is no timeout).
271 struct GNUNET_TIME_Relative timeout;
274 * ID of a task associated with the resolution process.
276 struct GNUNET_SCHEDULER_Task *timeout_task;
279 * The plugin result processor
281 GNUNET_REST_ResultProcessor proc;
284 * The closure of the result processor
294 * Error response message
306 struct GNUNET_JSONAPI_Document *resp_object;
313 * Cleanup lookup handle
314 * @param handle Handle to clean up
317 cleanup_handle (struct RequestHandle *handle)
319 struct EgoEntry *ego_entry;
320 struct EgoEntry *ego_tmp;
321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
323 if (NULL != handle->resp_object)
324 GNUNET_JSONAPI_document_delete (handle->resp_object);
325 if (NULL != handle->timeout_task)
326 GNUNET_SCHEDULER_cancel (handle->timeout_task);
327 if (NULL != handle->identity_handle)
328 GNUNET_IDENTITY_disconnect (handle->identity_handle);
329 if (NULL != handle->attr_it)
330 GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it);
331 if (NULL != handle->ticket_it)
332 GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it);
333 if (NULL != handle->idp)
334 GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
335 if (NULL != handle->url)
336 GNUNET_free (handle->url);
337 if (NULL != handle->emsg)
338 GNUNET_free (handle->emsg);
339 for (ego_entry = handle->ego_head;
343 ego_entry = ego_entry->next;
344 GNUNET_free (ego_tmp->identifier);
345 GNUNET_free (ego_tmp->keystring);
346 GNUNET_free (ego_tmp);
348 GNUNET_free (handle);
352 cleanup_handle_delayed (void *cls)
354 cleanup_handle (cls);
359 * Task run on error, sends error message. Cleans up everything.
361 * @param cls the `struct RequestHandle`
366 struct RequestHandle *handle = cls;
367 struct MHD_Response *resp;
370 GNUNET_asprintf (&json_error,
373 resp = GNUNET_REST_create_response (json_error);
374 handle->proc (handle->proc_cls, resp, handle->response_code);
375 cleanup_handle (handle);
376 GNUNET_free (json_error);
380 * Task run on timeout, sends error message. Cleans up everything.
382 * @param cls the `struct RequestHandle`
385 do_timeout (void *cls)
387 struct RequestHandle *handle = cls;
389 handle->timeout_task = NULL;
395 collect_error_cb (void *cls)
397 struct RequestHandle *handle = cls;
403 finished_cont (void *cls,
407 struct RequestHandle *handle = cls;
408 struct MHD_Response *resp;
410 resp = GNUNET_REST_create_response (emsg);
411 if (GNUNET_OK != success)
413 GNUNET_SCHEDULER_add_now (&do_error, handle);
416 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
417 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
422 * Return attributes for identity
424 * @param cls the request handle
427 return_response (void *cls)
430 struct RequestHandle *handle = cls;
431 struct MHD_Response *resp;
433 GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
435 resp = GNUNET_REST_create_response (result_str);
436 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
437 GNUNET_free (result_str);
438 cleanup_handle (handle);
443 collect_finished_cb (void *cls)
445 struct RequestHandle *handle = cls;
447 handle->attr_it = NULL;
448 handle->ticket_it = NULL;
449 GNUNET_SCHEDULER_add_now (&return_response, handle);
454 * Collect all attributes for an ego
458 ticket_collect (void *cls,
459 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
461 struct GNUNET_JSONAPI_Resource *json_resource;
462 struct RequestHandle *handle = cls;
466 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
467 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
469 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
472 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
474 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
475 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
476 value = json_string (tmp);
477 GNUNET_JSONAPI_resource_add_attr (json_resource,
482 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
483 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
484 value = json_string (tmp);
485 GNUNET_JSONAPI_resource_add_attr (json_resource,
490 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
492 value = json_string (tmp);
493 GNUNET_JSONAPI_resource_add_attr (json_resource,
498 GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it);
504 * List tickets for identity request
506 * @param con_handle the connection handle
508 * @param cls the RequestHandle
511 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
515 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
516 struct RequestHandle *handle = cls;
517 struct EgoEntry *ego_entry;
520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
522 if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
523 strlen (handle->url))
525 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
526 GNUNET_SCHEDULER_add_now (&do_error, handle);
529 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
531 for (ego_entry = handle->ego_head;
533 ego_entry = ego_entry->next)
534 if (0 == strcmp (identity, ego_entry->identifier))
536 handle->resp_object = GNUNET_JSONAPI_document_new ();
538 if (NULL == ego_entry)
541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
543 GNUNET_SCHEDULER_add_now (&return_response, handle);
546 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
547 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
548 handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp,
554 &collect_finished_cb,
560 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
564 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
565 const char* identity;
566 const char* name_str;
567 const char* value_str;
569 struct RequestHandle *handle = cls;
570 struct EgoEntry *ego_entry;
571 struct MHD_Response *resp;
572 struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute;
573 struct GNUNET_JSONAPI_Document *json_obj;
574 struct GNUNET_JSONAPI_Resource *json_res;
575 char term_data[handle->rest_handle->data_size+1];
579 struct GNUNET_JSON_Specification docspec[] = {
580 GNUNET_JSON_spec_jsonapi_document (&json_obj),
581 GNUNET_JSON_spec_end()
584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
586 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
587 strlen (handle->url))
589 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
590 GNUNET_SCHEDULER_add_now (&do_error, handle);
593 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
595 for (ego_entry = handle->ego_head;
597 ego_entry = ego_entry->next)
598 if (0 == strcmp (identity, ego_entry->identifier))
601 if (NULL == ego_entry)
603 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
604 "Identity unknown (%s)\n", identity);
605 GNUNET_JSONAPI_document_delete (json_obj);
608 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
610 if (0 >= handle->rest_handle->data_size)
612 GNUNET_SCHEDULER_add_now (&do_error, handle);
616 term_data[handle->rest_handle->data_size] = '\0';
617 GNUNET_memcpy (term_data,
618 handle->rest_handle->data,
619 handle->rest_handle->data_size);
620 data_json = json_loads (term_data,
623 GNUNET_assert (GNUNET_OK ==
624 GNUNET_JSON_parse (data_json, docspec,
626 json_decref (data_json);
627 if (NULL == json_obj)
629 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
630 "Unable to parse JSONAPI Object from %s\n",
632 GNUNET_SCHEDULER_add_now (&do_error, handle);
635 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
637 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
638 "Cannot create more than 1 resource! (Got %d)\n",
639 GNUNET_JSONAPI_document_resource_count (json_obj));
640 GNUNET_JSONAPI_document_delete (json_obj);
641 GNUNET_SCHEDULER_add_now (&do_error, handle);
644 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
645 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
646 GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
648 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
649 "Unsupported JSON data type\n");
650 GNUNET_JSONAPI_document_delete (json_obj);
651 resp = GNUNET_REST_create_response (NULL);
652 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
653 cleanup_handle (handle);
656 name_str = GNUNET_JSONAPI_resource_get_id (json_res);
657 value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
659 value_str = json_string_value (value_json);
660 attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str,
661 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
663 strlen (value_str) + 1);
664 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
665 handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
670 GNUNET_free (attribute);
671 GNUNET_JSONAPI_document_delete (json_obj);
677 * Collect all attributes for an ego
681 attr_collect (void *cls,
682 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
683 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
685 struct GNUNET_JSONAPI_Resource *json_resource;
686 struct RequestHandle *handle = cls;
689 if ((NULL == attr->name) || (NULL == attr->data))
691 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
695 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
697 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
699 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
701 value = json_string (attr->data);
702 GNUNET_JSONAPI_resource_add_attr (json_resource,
706 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
712 * List attributes for identity request
714 * @param con_handle the connection handle
716 * @param cls the RequestHandle
719 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
723 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
724 struct RequestHandle *handle = cls;
725 struct EgoEntry *ego_entry;
728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
730 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
731 strlen (handle->url))
733 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
734 GNUNET_SCHEDULER_add_now (&do_error, handle);
737 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
739 for (ego_entry = handle->ego_head;
741 ego_entry = ego_entry->next)
742 if (0 == strcmp (identity, ego_entry->identifier))
744 handle->resp_object = GNUNET_JSONAPI_document_new ();
747 if (NULL == ego_entry)
750 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
752 GNUNET_SCHEDULER_add_now (&return_response, handle);
755 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
756 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
757 handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
763 &collect_finished_cb,
769 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
773 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
774 const char* identity_str;
775 const char* audience_str;
778 struct RequestHandle *handle = cls;
779 struct EgoEntry *ego_entry;
780 struct MHD_Response *resp;
781 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
782 struct GNUNET_JSONAPI_Document *json_obj;
783 struct GNUNET_JSONAPI_Resource *json_res;
784 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
785 char term_data[handle->rest_handle->data_size+1];
787 json_t *identity_json;
788 json_t *audience_json;
791 struct GNUNET_JSON_Specification docspec[] = {
792 GNUNET_JSON_spec_jsonapi_document (&json_obj),
793 GNUNET_JSON_spec_end()
796 if (0 >= handle->rest_handle->data_size)
798 GNUNET_SCHEDULER_add_now (&do_error, handle);
802 term_data[handle->rest_handle->data_size] = '\0';
803 GNUNET_memcpy (term_data,
804 handle->rest_handle->data,
805 handle->rest_handle->data_size);
806 data_json = json_loads (term_data,
809 GNUNET_assert (GNUNET_OK ==
810 GNUNET_JSON_parse (data_json, docspec,
812 json_decref (data_json);
813 if (NULL == json_obj)
815 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
816 "Unable to parse JSONAPI Object from %s\n",
818 GNUNET_SCHEDULER_add_now (&do_error, handle);
821 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
823 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
824 "Cannot create more than 1 resource! (Got %d)\n",
825 GNUNET_JSONAPI_document_resource_count (json_obj));
826 GNUNET_JSONAPI_document_delete (json_obj);
827 GNUNET_SCHEDULER_add_now (&do_error, handle);
830 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
831 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
832 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
834 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
835 "Unsupported JSON data type\n");
836 GNUNET_JSONAPI_document_delete (json_obj);
837 resp = GNUNET_REST_create_response (NULL);
838 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
839 cleanup_handle (handle);
842 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
844 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
846 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
848 rnd_str = json_string_value (rnd_json);
849 identity_str = json_string_value (identity_json);
850 audience_str = json_string_value (audience_json);
852 GNUNET_STRINGS_string_to_data (rnd_str,
856 // GNUNET_STRINGS_string_to_data (identity_str,
857 // strlen (identity_str),
858 // &ticket.identity,type filter text
859 // sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
860 GNUNET_STRINGS_string_to_data (audience_str,
861 strlen (audience_str),
863 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
865 for (ego_entry = handle->ego_head;
867 ego_entry = ego_entry->next)
869 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
871 if (0 == memcmp (&ticket.identity,
873 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
876 if (NULL == ego_entry)
878 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
879 "Identity unknown (%s)\n", identity_str);
880 GNUNET_JSONAPI_document_delete (json_obj);
883 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
885 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
886 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
891 GNUNET_JSONAPI_document_delete (json_obj);
895 consume_cont (void *cls,
896 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
897 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
899 struct RequestHandle *handle = cls;
900 struct GNUNET_JSONAPI_Resource *json_resource;
903 if (NULL == identity)
905 GNUNET_SCHEDULER_add_now (&return_response, handle);
909 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
911 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
913 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
915 value = json_string (attr->data);
916 GNUNET_JSONAPI_resource_add_attr (json_resource,
923 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
927 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
928 const char* identity_str;
929 const char* audience_str;
932 struct RequestHandle *handle = cls;
933 struct EgoEntry *ego_entry;
934 struct MHD_Response *resp;
935 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
936 struct GNUNET_JSONAPI_Document *json_obj;
937 struct GNUNET_JSONAPI_Resource *json_res;
938 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
939 char term_data[handle->rest_handle->data_size+1];
941 json_t *identity_json;
942 json_t *audience_json;
945 struct GNUNET_JSON_Specification docspec[] = {
946 GNUNET_JSON_spec_jsonapi_document (&json_obj),
947 GNUNET_JSON_spec_end()
950 if (0 >= handle->rest_handle->data_size)
952 GNUNET_SCHEDULER_add_now (&do_error, handle);
956 term_data[handle->rest_handle->data_size] = '\0';
957 GNUNET_memcpy (term_data,
958 handle->rest_handle->data,
959 handle->rest_handle->data_size);
960 data_json = json_loads (term_data,
963 GNUNET_assert (GNUNET_OK ==
964 GNUNET_JSON_parse (data_json, docspec,
966 json_decref (data_json);
967 if (NULL == json_obj)
969 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
970 "Unable to parse JSONAPI Object from %s\n",
972 GNUNET_SCHEDULER_add_now (&do_error, handle);
975 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
977 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
978 "Cannot create more than 1 resource! (Got %d)\n",
979 GNUNET_JSONAPI_document_resource_count (json_obj));
980 GNUNET_JSONAPI_document_delete (json_obj);
981 GNUNET_SCHEDULER_add_now (&do_error, handle);
984 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
985 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
986 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
988 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
989 "Unsupported JSON data type\n");
990 GNUNET_JSONAPI_document_delete (json_obj);
991 resp = GNUNET_REST_create_response (NULL);
992 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
993 cleanup_handle (handle);
996 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
998 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1000 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1002 rnd_str = json_string_value (rnd_json);
1003 identity_str = json_string_value (identity_json);
1004 audience_str = json_string_value (audience_json);
1006 GNUNET_STRINGS_string_to_data (rnd_str,
1010 GNUNET_STRINGS_string_to_data (identity_str,
1011 strlen (identity_str),
1013 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1014 GNUNET_STRINGS_string_to_data (audience_str,
1015 strlen (audience_str),
1017 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1019 for (ego_entry = handle->ego_head;
1021 ego_entry = ego_entry->next)
1023 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1025 if (0 == memcmp (&ticket.audience,
1027 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1030 if (NULL == ego_entry)
1032 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1033 "Identity unknown (%s)\n", identity_str);
1034 GNUNET_JSONAPI_document_delete (json_obj);
1037 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1038 handle->resp_object = GNUNET_JSONAPI_document_new ();
1039 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1040 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
1045 GNUNET_JSONAPI_document_delete (json_obj);
1051 * Respond to OPTIONS request
1053 * @param con_handle the connection handle
1054 * @param url the url
1055 * @param cls the RequestHandle
1058 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1062 struct MHD_Response *resp;
1063 struct RequestHandle *handle = cls;
1065 //For now, independent of path return all options
1066 resp = GNUNET_REST_create_response (NULL);
1067 MHD_add_response_header (resp,
1068 "Access-Control-Allow-Methods",
1070 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1071 cleanup_handle (handle);
1076 * Respond to OPTIONS request
1078 * @param con_handle the connection handle
1079 * @param url the url
1080 * @param cls the RequestHandle
1083 authorize_cont (struct GNUNET_REST_RequestHandle *con_handle,
1087 struct MHD_Response *resp;
1088 struct RequestHandle *handle = cls;
1089 char *response_type;
1096 //TODO clean up method
1098 /** The Authorization Server MUST validate all the OAuth 2.0 parameters
1099 * according to the OAuth 2.0 specification.
1101 /** The Authorization Server MUST verify that all the REQUIRED parameters
1102 * are present and their usage conforms to this specification.
1105 * If the sub (subject) Claim is requested with a specific value for the
1106 * ID Token, the Authorization Server MUST only send a positive response
1107 * if the End-User identified by that sub value has an active session with
1108 * the Authorization Server or has been Authenticated as a result of the
1109 * request. The Authorization Server MUST NOT reply with an ID Token or
1110 * Access Token for a different user, even if they have an active session
1111 * with the Authorization Server. Such a request can be made either using
1112 * an id_token_hint parameter or by requesting a specific Claim Value as
1113 * described in Section 5.5.1, if the claims parameter is supported by
1114 * the implementation.
1118 int size=sizeof(OIDC_ignored_parameter_array)/sizeof(char *);
1120 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Size %i = 8\n", size);
1122 struct GNUNET_HashCode cache_key;
1124 GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1126 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1132 response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1136 GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1138 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1143 client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1146 //TODO verify if client_id is in delegation from selected identity, i.e. use GNUNET_NAMESTORE_zone_to_name() to verify
1147 GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
1148 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1153 scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1156 GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1158 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1163 redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1166 GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
1167 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1172 state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1175 GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
1176 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1181 nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1185 for( iterator = 0; iterator < size; iterator++ )
1187 GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1188 strlen(OIDC_ignored_parameter_array[iterator]),
1190 if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
1198 //response_type = code
1199 if( strcmp( response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) != 0 )
1203 //scope contains openid
1204 if( strstr( scope, OIDC_EXPECTED_AUTHORIZATION_SCOPE ) == NULL )
1206 handle->emsg=GNUNET_strdup("invalid_scope");
1207 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1208 GNUNET_SCHEDULER_add_now (&do_error, handle);
1212 //TODO check other values and use them accordingly
1215 char* login_base_url;
1222 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
1223 "identity-rest-plugin",
1228 GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
1230 OIDC_RESPONSE_TYPE_KEY, response_type,
1231 OIDC_CLIENT_ID_KEY, client_id,
1232 OIDC_REDIRECT_URI_KEY, redirect_uri,
1233 OIDC_SCOPE_KEY, scope,
1234 OIDC_STATE_KEY, state,
1235 OIDC_NONCE_KEY, nonce
1237 resp = GNUNET_REST_create_response ("");
1238 MHD_add_response_header (resp, "Location", new_redirect);
1240 handle->emsg=GNUNET_strdup("No server on localhost:8000");
1241 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1242 GNUNET_SCHEDULER_add_now (&do_error, handle);
1246 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1247 cleanup_handle (handle);
1252 * Handle rest request
1254 * @param handle the request handle
1257 init_cont (struct RequestHandle *handle)
1259 struct GNUNET_REST_RequestHandlerError err;
1260 static const struct GNUNET_REST_RequestHandler handlers[] = {
1261 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
1262 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
1263 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
1264 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_cont},
1265 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_cont},
1266 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1267 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1268 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
1270 GNUNET_REST_HANDLER_END
1273 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1278 handle->response_code = err.error_code;
1279 GNUNET_SCHEDULER_add_now (&do_error, handle);
1284 * If listing is enabled, prints information about the egos.
1286 * This function is initially called for all egos and then again
1287 * whenever a ego's identifier changes or if it is deleted. At the
1288 * end of the initial pass over all egos, the function is once called
1289 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1290 * be invoked in the future or that there was an error.
1292 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1293 * this function is only called ONCE, and 'NULL' being passed in
1294 * 'ego' does indicate an error (i.e. name is taken or no default
1295 * value is known). If 'ego' is non-NULL and if '*ctx'
1296 * is set in those callbacks, the value WILL be passed to a subsequent
1297 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1298 * that one was not NULL).
1300 * When an identity is renamed, this function is called with the
1301 * (known) ego but the NEW identifier.
1303 * When an identity is deleted, this function is called with the
1304 * (known) ego and "NULL" for the 'identifier'. In this case,
1305 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1308 * @param cls closure
1309 * @param ego ego handle
1310 * @param ctx context for application to store data for this ego
1311 * (during the lifetime of this process, initially NULL)
1312 * @param identifier identifier assigned by the user for this ego,
1313 * NULL if the user just deleted the ego and it
1314 * must thus no longer be used
1317 list_ego (void *cls,
1318 struct GNUNET_IDENTITY_Ego *ego,
1320 const char *identifier)
1322 struct RequestHandle *handle = cls;
1323 struct EgoEntry *ego_entry;
1324 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1326 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1328 handle->state = ID_REST_STATE_POST_INIT;
1332 if (ID_REST_STATE_INIT == handle->state) {
1333 ego_entry = GNUNET_new (struct EgoEntry);
1334 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1335 ego_entry->keystring =
1336 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1337 ego_entry->ego = ego;
1338 ego_entry->identifier = GNUNET_strdup (identifier);
1339 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1345 * Function processing the REST call
1347 * @param method HTTP method
1348 * @param url URL of the HTTP request
1349 * @param data body of the HTTP request (optional)
1350 * @param data_size length of the body
1351 * @param proc callback function for the result
1352 * @param proc_cls closure for callback function
1353 * @return GNUNET_OK if request accepted
1356 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1357 GNUNET_REST_ResultProcessor proc,
1360 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1362 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1363 handle->proc_cls = proc_cls;
1364 handle->proc = proc;
1365 handle->state = ID_REST_STATE_INIT;
1366 handle->rest_handle = rest_handle;
1368 handle->url = GNUNET_strdup (rest_handle->url);
1369 if (handle->url[strlen (handle->url)-1] == '/')
1370 handle->url[strlen (handle->url)-1] = '\0';
1371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1373 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1376 handle->timeout_task =
1377 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1385 * Entry point for the plugin.
1387 * @param cls Config info
1388 * @return NULL on error, otherwise the plugin context
1391 libgnunet_plugin_rest_identity_provider_init (void *cls)
1393 static struct Plugin plugin;
1394 struct GNUNET_REST_Plugin *api;
1397 if (NULL != plugin.cfg)
1398 return NULL; /* can only initialize once! */
1399 memset (&plugin, 0, sizeof (struct Plugin));
1401 api = GNUNET_new (struct GNUNET_REST_Plugin);
1403 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1404 api->process_request = &rest_identity_process_request;
1405 GNUNET_asprintf (&allow_methods,
1406 "%s, %s, %s, %s, %s",
1407 MHD_HTTP_METHOD_GET,
1408 MHD_HTTP_METHOD_POST,
1409 MHD_HTTP_METHOD_PUT,
1410 MHD_HTTP_METHOD_DELETE,
1411 MHD_HTTP_METHOD_OPTIONS);
1413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1414 _("Identity Provider REST API initialized\n"));
1420 * Exit point from the plugin.
1422 * @param cls the plugin context (as returned by "init")
1423 * @return always NULL
1426 libgnunet_plugin_rest_identity_provider_done (void *cls)
1428 struct GNUNET_REST_Plugin *api = cls;
1429 struct Plugin *plugin = api->cls;
1432 GNUNET_free_non_null (allow_methods);
1434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1435 "Identity Provider REST plugin is finished\n");
1439 /* end of plugin_rest_identity_provider.c */