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_provider_service.h"
45 #define GNUNET_REST_API_NS_IDENTITY_PROVIDER "/idp"
50 #define GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES "/idp/attributes"
55 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/idp/tickets"
60 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/idp/revoke"
65 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume"
70 #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
101 * The configuration handle
103 const struct GNUNET_CONFIGURATION_Handle *cfg;
106 * HTTP methods allows for this plugin
108 static char* allow_methods;
111 * @brief struct returned by the initialization function of the plugin
115 const struct GNUNET_CONFIGURATION_Handle *cfg;
126 struct EgoEntry *next;
131 struct EgoEntry *prev;
146 struct GNUNET_IDENTITY_Ego *ego;
155 struct EgoEntry *ego_head;
160 struct EgoEntry *ego_tail;
165 struct EgoEntry *ego_entry;
168 * Ptr to current ego private key
170 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
173 * The processing state
178 * Handle to Identity service.
180 struct GNUNET_IDENTITY_Handle *identity_handle;
185 struct GNUNET_REST_RequestHandle *rest_handle;
191 struct GNUNET_IDENTITY_Operation *op;
196 struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
201 struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
206 struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it;
211 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it;
214 * Desired timeout for the lookup (default is no timeout).
216 struct GNUNET_TIME_Relative timeout;
219 * ID of a task associated with the resolution process.
221 struct GNUNET_SCHEDULER_Task *timeout_task;
224 * The plugin result processor
226 GNUNET_REST_ResultProcessor proc;
229 * The closure of the result processor
239 * Error response message
251 struct GNUNET_JSONAPI_Document *resp_object;
258 * Cleanup lookup handle
259 * @param handle Handle to clean up
262 cleanup_handle (struct RequestHandle *handle)
264 struct EgoEntry *ego_entry;
265 struct EgoEntry *ego_tmp;
266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
268 if (NULL != handle->resp_object)
269 GNUNET_JSONAPI_document_delete (handle->resp_object);
270 if (NULL != handle->timeout_task)
271 GNUNET_SCHEDULER_cancel (handle->timeout_task);
272 if (NULL != handle->identity_handle)
273 GNUNET_IDENTITY_disconnect (handle->identity_handle);
274 if (NULL != handle->attr_it)
275 GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it);
276 if (NULL != handle->ticket_it)
277 GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it);
278 if (NULL != handle->idp)
279 GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
280 if (NULL != handle->url)
281 GNUNET_free (handle->url);
282 if (NULL != handle->emsg)
283 GNUNET_free (handle->emsg);
284 for (ego_entry = handle->ego_head;
288 ego_entry = ego_entry->next;
289 GNUNET_free (ego_tmp->identifier);
290 GNUNET_free (ego_tmp->keystring);
291 GNUNET_free (ego_tmp);
293 GNUNET_free (handle);
297 cleanup_handle_delayed (void *cls)
299 cleanup_handle (cls);
304 * Task run on error, sends error message. Cleans up everything.
306 * @param cls the `struct RequestHandle`
311 struct RequestHandle *handle = cls;
312 struct MHD_Response *resp;
315 GNUNET_asprintf (&json_error,
318 resp = GNUNET_REST_create_response (json_error);
319 handle->proc (handle->proc_cls, resp, handle->response_code);
320 cleanup_handle (handle);
321 GNUNET_free (json_error);
325 * Task run on timeout, sends error message. Cleans up everything.
327 * @param cls the `struct RequestHandle`
330 do_timeout (void *cls)
332 struct RequestHandle *handle = cls;
334 handle->timeout_task = NULL;
340 collect_error_cb (void *cls)
342 struct RequestHandle *handle = cls;
348 finished_cont (void *cls,
352 struct RequestHandle *handle = cls;
353 struct MHD_Response *resp;
355 resp = GNUNET_REST_create_response (emsg);
356 if (GNUNET_OK != success)
358 GNUNET_SCHEDULER_add_now (&do_error, handle);
361 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
362 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
367 * Return attributes for identity
369 * @param cls the request handle
372 return_response (void *cls)
375 struct RequestHandle *handle = cls;
376 struct MHD_Response *resp;
378 GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
380 resp = GNUNET_REST_create_response (result_str);
381 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
382 GNUNET_free (result_str);
383 cleanup_handle (handle);
388 collect_finished_cb (void *cls)
390 struct RequestHandle *handle = cls;
392 handle->attr_it = NULL;
393 handle->ticket_it = NULL;
394 GNUNET_SCHEDULER_add_now (&return_response, handle);
399 * Collect all attributes for an ego
403 ticket_collect (void *cls,
404 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
406 struct GNUNET_JSONAPI_Resource *json_resource;
407 struct RequestHandle *handle = cls;
411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
412 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
414 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
417 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
419 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
420 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
421 value = json_string (tmp);
422 GNUNET_JSONAPI_resource_add_attr (json_resource,
427 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
428 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
429 value = json_string (tmp);
430 GNUNET_JSONAPI_resource_add_attr (json_resource,
435 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
437 value = json_string (tmp);
438 GNUNET_JSONAPI_resource_add_attr (json_resource,
443 GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it);
449 * List tickets for identity request
451 * @param con_handle the connection handle
453 * @param cls the RequestHandle
456 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
460 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
461 struct RequestHandle *handle = cls;
462 struct EgoEntry *ego_entry;
465 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
467 if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
468 strlen (handle->url))
470 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
471 GNUNET_SCHEDULER_add_now (&do_error, handle);
474 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
476 for (ego_entry = handle->ego_head;
478 ego_entry = ego_entry->next)
479 if (0 == strcmp (identity, ego_entry->identifier))
481 handle->resp_object = GNUNET_JSONAPI_document_new ();
483 if (NULL == ego_entry)
486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
488 GNUNET_SCHEDULER_add_now (&return_response, handle);
491 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
492 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
493 handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp,
499 &collect_finished_cb,
505 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
509 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
510 const char* identity;
511 const char* name_str;
512 const char* value_str;
514 struct RequestHandle *handle = cls;
515 struct EgoEntry *ego_entry;
516 struct MHD_Response *resp;
517 struct GNUNET_IDENTITY_PROVIDER_Attribute *attribute;
518 struct GNUNET_JSONAPI_Document *json_obj;
519 struct GNUNET_JSONAPI_Resource *json_res;
520 char term_data[handle->rest_handle->data_size+1];
524 struct GNUNET_JSON_Specification docspec[] = {
525 GNUNET_JSON_spec_jsonapi_document (&json_obj),
526 GNUNET_JSON_spec_end()
529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
531 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
532 strlen (handle->url))
534 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
535 GNUNET_SCHEDULER_add_now (&do_error, handle);
538 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
540 for (ego_entry = handle->ego_head;
542 ego_entry = ego_entry->next)
543 if (0 == strcmp (identity, ego_entry->identifier))
546 if (NULL == ego_entry)
548 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
549 "Identity unknown (%s)\n", identity);
550 GNUNET_JSONAPI_document_delete (json_obj);
553 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
555 if (0 >= handle->rest_handle->data_size)
557 GNUNET_SCHEDULER_add_now (&do_error, handle);
561 term_data[handle->rest_handle->data_size] = '\0';
562 GNUNET_memcpy (term_data,
563 handle->rest_handle->data,
564 handle->rest_handle->data_size);
565 data_json = json_loads (term_data,
568 GNUNET_assert (GNUNET_OK ==
569 GNUNET_JSON_parse (data_json, docspec,
571 json_decref (data_json);
572 if (NULL == json_obj)
574 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
575 "Unable to parse JSONAPI Object from %s\n",
577 GNUNET_SCHEDULER_add_now (&do_error, handle);
580 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
582 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
583 "Cannot create more than 1 resource! (Got %d)\n",
584 GNUNET_JSONAPI_document_resource_count (json_obj));
585 GNUNET_JSONAPI_document_delete (json_obj);
586 GNUNET_SCHEDULER_add_now (&do_error, handle);
589 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
590 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
591 GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
593 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
594 "Unsupported JSON data type\n");
595 GNUNET_JSONAPI_document_delete (json_obj);
596 resp = GNUNET_REST_create_response (NULL);
597 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
598 cleanup_handle (handle);
601 name_str = GNUNET_JSONAPI_resource_get_id (json_res);
602 value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
604 value_str = json_string_value (value_json);
605 attribute = GNUNET_IDENTITY_PROVIDER_attribute_new (name_str,
606 GNUNET_IDENTITY_PROVIDER_AT_STRING,
608 strlen (value_str) + 1);
609 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
610 handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
615 GNUNET_free (attribute);
616 GNUNET_JSONAPI_document_delete (json_obj);
622 * Collect all attributes for an ego
626 attr_collect (void *cls,
627 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
628 const struct GNUNET_IDENTITY_PROVIDER_Attribute *attr)
630 struct GNUNET_JSONAPI_Resource *json_resource;
631 struct RequestHandle *handle = cls;
634 if ((NULL == attr->name) || (NULL == attr->data))
636 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
642 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
644 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
646 value = json_string (attr->data);
647 GNUNET_JSONAPI_resource_add_attr (json_resource,
651 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
657 * List attributes for identity request
659 * @param con_handle the connection handle
661 * @param cls the RequestHandle
664 list_attribute_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 attributes for %s.\n",
675 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
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_ATTRIBUTES) + 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 ();
692 if (NULL == ego_entry)
695 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
697 GNUNET_SCHEDULER_add_now (&return_response, handle);
700 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
701 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
702 handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
708 &collect_finished_cb,
714 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
718 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
719 const char* identity_str;
720 const char* audience_str;
723 struct RequestHandle *handle = cls;
724 struct EgoEntry *ego_entry;
725 struct MHD_Response *resp;
726 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
727 struct GNUNET_JSONAPI_Document *json_obj;
728 struct GNUNET_JSONAPI_Resource *json_res;
729 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
730 char term_data[handle->rest_handle->data_size+1];
732 json_t *identity_json;
733 json_t *audience_json;
736 struct GNUNET_JSON_Specification docspec[] = {
737 GNUNET_JSON_spec_jsonapi_document (&json_obj),
738 GNUNET_JSON_spec_end()
741 if (0 >= handle->rest_handle->data_size)
743 GNUNET_SCHEDULER_add_now (&do_error, handle);
747 term_data[handle->rest_handle->data_size] = '\0';
748 GNUNET_memcpy (term_data,
749 handle->rest_handle->data,
750 handle->rest_handle->data_size);
751 data_json = json_loads (term_data,
754 GNUNET_assert (GNUNET_OK ==
755 GNUNET_JSON_parse (data_json, docspec,
757 json_decref (data_json);
758 if (NULL == json_obj)
760 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
761 "Unable to parse JSONAPI Object from %s\n",
763 GNUNET_SCHEDULER_add_now (&do_error, handle);
766 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
768 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
769 "Cannot create more than 1 resource! (Got %d)\n",
770 GNUNET_JSONAPI_document_resource_count (json_obj));
771 GNUNET_JSONAPI_document_delete (json_obj);
772 GNUNET_SCHEDULER_add_now (&do_error, handle);
775 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
776 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
777 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
779 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
780 "Unsupported JSON data type\n");
781 GNUNET_JSONAPI_document_delete (json_obj);
782 resp = GNUNET_REST_create_response (NULL);
783 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
784 cleanup_handle (handle);
787 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
789 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
791 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
793 rnd_str = json_string_value (rnd_json);
794 identity_str = json_string_value (identity_json);
795 audience_str = json_string_value (audience_json);
797 GNUNET_STRINGS_string_to_data (rnd_str,
801 GNUNET_STRINGS_string_to_data (identity_str,
802 strlen (identity_str),
804 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
805 GNUNET_STRINGS_string_to_data (audience_str,
806 strlen (audience_str),
808 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
810 for (ego_entry = handle->ego_head;
812 ego_entry = ego_entry->next)
814 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
816 if (0 == memcmp (&ticket.identity,
818 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
821 if (NULL == ego_entry)
823 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
824 "Identity unknown (%s)\n", identity_str);
825 GNUNET_JSONAPI_document_delete (json_obj);
828 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
830 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
831 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
836 GNUNET_JSONAPI_document_delete (json_obj);
840 consume_cont (void *cls,
841 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
842 const struct GNUNET_IDENTITY_PROVIDER_Attribute *attr)
844 struct RequestHandle *handle = cls;
845 struct GNUNET_JSONAPI_Resource *json_resource;
848 if (NULL == identity)
850 GNUNET_SCHEDULER_add_now (&return_response, handle);
854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
856 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
858 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
860 value = json_string (attr->data);
861 GNUNET_JSONAPI_resource_add_attr (json_resource,
868 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
872 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
873 const char* identity_str;
874 const char* audience_str;
877 struct RequestHandle *handle = cls;
878 struct EgoEntry *ego_entry;
879 struct MHD_Response *resp;
880 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
881 struct GNUNET_JSONAPI_Document *json_obj;
882 struct GNUNET_JSONAPI_Resource *json_res;
883 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
884 char term_data[handle->rest_handle->data_size+1];
886 json_t *identity_json;
887 json_t *audience_json;
890 struct GNUNET_JSON_Specification docspec[] = {
891 GNUNET_JSON_spec_jsonapi_document (&json_obj),
892 GNUNET_JSON_spec_end()
895 if (0 >= handle->rest_handle->data_size)
897 GNUNET_SCHEDULER_add_now (&do_error, handle);
901 term_data[handle->rest_handle->data_size] = '\0';
902 GNUNET_memcpy (term_data,
903 handle->rest_handle->data,
904 handle->rest_handle->data_size);
905 data_json = json_loads (term_data,
908 GNUNET_assert (GNUNET_OK ==
909 GNUNET_JSON_parse (data_json, docspec,
911 json_decref (data_json);
912 if (NULL == json_obj)
914 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
915 "Unable to parse JSONAPI Object from %s\n",
917 GNUNET_SCHEDULER_add_now (&do_error, handle);
920 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
922 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
923 "Cannot create more than 1 resource! (Got %d)\n",
924 GNUNET_JSONAPI_document_resource_count (json_obj));
925 GNUNET_JSONAPI_document_delete (json_obj);
926 GNUNET_SCHEDULER_add_now (&do_error, handle);
929 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
930 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
931 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
933 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
934 "Unsupported JSON data type\n");
935 GNUNET_JSONAPI_document_delete (json_obj);
936 resp = GNUNET_REST_create_response (NULL);
937 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
938 cleanup_handle (handle);
941 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
943 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
945 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
947 rnd_str = json_string_value (rnd_json);
948 identity_str = json_string_value (identity_json);
949 audience_str = json_string_value (audience_json);
951 GNUNET_STRINGS_string_to_data (rnd_str,
955 GNUNET_STRINGS_string_to_data (identity_str,
956 strlen (identity_str),
958 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
959 GNUNET_STRINGS_string_to_data (audience_str,
960 strlen (audience_str),
962 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
964 for (ego_entry = handle->ego_head;
966 ego_entry = ego_entry->next)
968 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
970 if (0 == memcmp (&ticket.audience,
972 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
975 if (NULL == ego_entry)
977 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
978 "Identity unknown (%s)\n", identity_str);
979 GNUNET_JSONAPI_document_delete (json_obj);
982 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
983 handle->resp_object = GNUNET_JSONAPI_document_new ();
984 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
985 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
990 GNUNET_JSONAPI_document_delete (json_obj);
996 * Respond to OPTIONS request
998 * @param con_handle the connection handle
1000 * @param cls the RequestHandle
1003 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1007 struct MHD_Response *resp;
1008 struct RequestHandle *handle = cls;
1010 //For now, independent of path return all options
1011 resp = GNUNET_REST_create_response (NULL);
1012 MHD_add_response_header (resp,
1013 "Access-Control-Allow-Methods",
1015 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1016 cleanup_handle (handle);
1021 * Respond to OPTIONS request
1023 * @param con_handle the connection handle
1024 * @param url the url
1025 * @param cls the RequestHandle
1028 authorize_cont (struct GNUNET_REST_RequestHandle *con_handle,
1033 //TODO clean up method
1036 // The Authorization Server MUST validate all the OAuth 2.0 parameters according to the OAuth 2.0 specification.
1037 // The Authorization Server MUST verify that all the REQUIRED parameters are present and their usage conforms to this specification.
1038 // If the sub (subject) Claim is requested with a specific value for the ID Token, the Authorization Server MUST only send a positive response if the End-User identified by that sub value has an active session with the Authorization Server or has been Authenticated as a result of the request. The Authorization Server MUST NOT reply with an ID Token or Access Token for a different user, even if they have an active session with the Authorization Server. Such a request can be made either using an id_token_hint parameter or by requesting a specific Claim Value as described in Section 5.5.1, if the claims parameter is supported by the implementation.
1042 struct MHD_Response *resp;
1043 struct RequestHandle *handle = cls;
1061 char* array[] = { "response_type", "client_id", "scope", "redirect_uri",
1062 "state", "nonce", "display", "prompt", "max_age", "ui_locales",
1063 "response_mode", "id_token_hint","login_hint", "acr_values" };
1065 int bool_array[array_size];
1067 struct GNUNET_HashCode cache_key;
1069 //iterates over each parameter and store used values in array array[]
1071 for( iterator = 0; iterator<array_size; iterator++){
1072 GNUNET_CRYPTO_hash (array[iterator], strlen (array[iterator]), &cache_key);
1073 char* cache=GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, &cache_key);
1074 bool_array[iterator]=0;
1076 size_t size=strlen(cache)+1;
1077 array[iterator]=(char*)malloc(size*sizeof(char));
1078 strncpy(array[iterator],cache,size);
1079 bool_array[iterator]=1;
1083 //MUST validate all the OAuth 2.0 parameters & that all the REQUIRED parameters are present and their usage conforms to this specification
1085 //required values: response_type, client_id, scope, redirect_uri
1086 if(!bool_array[0] || !bool_array[1] || !bool_array[2] || !bool_array[3]){
1087 handle->emsg=GNUNET_strdup("invalid_request");
1088 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1089 GNUNET_SCHEDULER_add_now (&do_error, handle);
1092 //response_type = code
1093 if(strcmp(array[0],"code")!=0){
1094 handle->emsg=GNUNET_strdup("invalid_response_type");
1095 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1096 GNUNET_SCHEDULER_add_now (&do_error, handle);
1099 //scope contains openid
1100 if(strstr(array[2],"openid")==NULL){
1101 handle->emsg=GNUNET_strdup("invalid_scope");
1102 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1103 GNUNET_SCHEDULER_add_now (&do_error, handle);
1107 //TODO check other values and use them accordingly
1110 char* redirect_url_to_login;
1117 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
1118 "identity-rest-plugin",
1120 &redirect_url_to_login)){
1122 char* build_array[] = { "response_type", "client_id", "scope", "redirect_uri",
1123 "state", "nonce", "display", "prompt", "max_age", "ui_locales",
1124 "response_mode", "id_token_hint","login_hint", "acr_values" };
1126 size_t redirect_parameter_size= strlen("?");
1127 for(iterator=0;iterator<array_size;iterator++){
1128 if(bool_array[iterator]){
1129 redirect_parameter_size += strlen(array[iterator]);
1130 redirect_parameter_size += strlen(build_array[iterator]);
1131 if(iterator==array_size-1)
1133 redirect_parameter_size += strlen("=");
1135 redirect_parameter_size += strlen("=&");
1140 char redirect_parameter[redirect_parameter_size+1];
1141 redirect_parameter_size = 0;
1142 redirect_parameter[redirect_parameter_size]='?';
1143 for(iterator=0;iterator<array_size;iterator++){
1144 if(bool_array[iterator]){
1145 //If not last parameter
1146 if(iterator!=array_size-1)
1148 char cache[strlen(array[iterator])+strlen(build_array[iterator])+2+1];
1149 snprintf(cache,sizeof(cache),"%s=%s&", build_array[iterator], array[iterator]);
1150 strncat(redirect_parameter, cache, strlen(array[iterator])+strlen(build_array[iterator])+2 );
1152 char cache[strlen(array[iterator])+strlen(build_array[iterator])+1+1];
1153 snprintf(cache,sizeof(cache),"%s=%s", build_array[iterator], array[iterator]);
1154 strncat(redirect_parameter, cache, strlen(array[iterator])+strlen(build_array[iterator])+1 );
1158 char redirect_component[strlen(redirect_url_to_login)+strlen(redirect_parameter)+1];
1159 snprintf(redirect_component, sizeof(redirect_component), "%s%s", redirect_url_to_login, redirect_parameter);
1160 resp = GNUNET_REST_create_response ("");
1161 MHD_add_response_header (resp, "Location", redirect_component);
1163 handle->emsg=GNUNET_strdup("No server on localhost:8000");
1164 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1165 GNUNET_SCHEDULER_add_now (&do_error, handle);
1167 // resp = GNUNET_REST_create_response ("");
1168 // MHD_add_response_header (resp, "Location", array[3]);
1171 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1172 cleanup_handle (handle);
1173 for(iterator=0; iterator<array_size; iterator++){
1174 if(bool_array[iterator]){
1175 free(array[iterator]);
1182 * Handle rest request
1184 * @param handle the request handle
1187 init_cont (struct RequestHandle *handle)
1189 struct GNUNET_REST_RequestHandlerError err;
1190 static const struct GNUNET_REST_RequestHandler handlers[] = {
1191 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
1192 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
1193 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
1194 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_cont},
1195 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_cont},
1196 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1197 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1198 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
1200 GNUNET_REST_HANDLER_END
1203 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1208 handle->response_code = err.error_code;
1209 GNUNET_SCHEDULER_add_now (&do_error, handle);
1214 * If listing is enabled, prints information about the egos.
1216 * This function is initially called for all egos and then again
1217 * whenever a ego's identifier changes or if it is deleted. At the
1218 * end of the initial pass over all egos, the function is once called
1219 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1220 * be invoked in the future or that there was an error.
1222 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1223 * this function is only called ONCE, and 'NULL' being passed in
1224 * 'ego' does indicate an error (i.e. name is taken or no default
1225 * value is known). If 'ego' is non-NULL and if '*ctx'
1226 * is set in those callbacks, the value WILL be passed to a subsequent
1227 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1228 * that one was not NULL).
1230 * When an identity is renamed, this function is called with the
1231 * (known) ego but the NEW identifier.
1233 * When an identity is deleted, this function is called with the
1234 * (known) ego and "NULL" for the 'identifier'. In this case,
1235 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1238 * @param cls closure
1239 * @param ego ego handle
1240 * @param ctx context for application to store data for this ego
1241 * (during the lifetime of this process, initially NULL)
1242 * @param identifier identifier assigned by the user for this ego,
1243 * NULL if the user just deleted the ego and it
1244 * must thus no longer be used
1247 list_ego (void *cls,
1248 struct GNUNET_IDENTITY_Ego *ego,
1250 const char *identifier)
1252 struct RequestHandle *handle = cls;
1253 struct EgoEntry *ego_entry;
1254 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1256 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1258 handle->state = ID_REST_STATE_POST_INIT;
1262 if (ID_REST_STATE_INIT == handle->state) {
1263 ego_entry = GNUNET_new (struct EgoEntry);
1264 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1265 ego_entry->keystring =
1266 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1267 ego_entry->ego = ego;
1268 ego_entry->identifier = GNUNET_strdup (identifier);
1269 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1275 * Function processing the REST call
1277 * @param method HTTP method
1278 * @param url URL of the HTTP request
1279 * @param data body of the HTTP request (optional)
1280 * @param data_size length of the body
1281 * @param proc callback function for the result
1282 * @param proc_cls closure for callback function
1283 * @return GNUNET_OK if request accepted
1286 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1287 GNUNET_REST_ResultProcessor proc,
1290 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1292 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1293 handle->proc_cls = proc_cls;
1294 handle->proc = proc;
1295 handle->state = ID_REST_STATE_INIT;
1296 handle->rest_handle = rest_handle;
1298 handle->url = GNUNET_strdup (rest_handle->url);
1299 if (handle->url[strlen (handle->url)-1] == '/')
1300 handle->url[strlen (handle->url)-1] = '\0';
1301 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1303 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1306 handle->timeout_task =
1307 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1315 * Entry point for the plugin.
1317 * @param cls Config info
1318 * @return NULL on error, otherwise the plugin context
1321 libgnunet_plugin_rest_identity_provider_init (void *cls)
1323 static struct Plugin plugin;
1324 struct GNUNET_REST_Plugin *api;
1327 if (NULL != plugin.cfg)
1328 return NULL; /* can only initialize once! */
1329 memset (&plugin, 0, sizeof (struct Plugin));
1331 api = GNUNET_new (struct GNUNET_REST_Plugin);
1333 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1334 api->process_request = &rest_identity_process_request;
1335 GNUNET_asprintf (&allow_methods,
1336 "%s, %s, %s, %s, %s",
1337 MHD_HTTP_METHOD_GET,
1338 MHD_HTTP_METHOD_POST,
1339 MHD_HTTP_METHOD_PUT,
1340 MHD_HTTP_METHOD_DELETE,
1341 MHD_HTTP_METHOD_OPTIONS);
1343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1344 _("Identity Provider REST API initialized\n"));
1350 * Exit point from the plugin.
1352 * @param cls the plugin context (as returned by "init")
1353 * @return always NULL
1356 libgnunet_plugin_rest_identity_provider_done (void *cls)
1358 struct GNUNET_REST_Plugin *api = cls;
1359 struct Plugin *plugin = api->cls;
1362 GNUNET_free_non_null (allow_methods);
1364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1365 "Identity Provider REST plugin is finished\n");
1369 /* end of plugin_rest_identity_provider.c */