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"
77 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
82 #define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
88 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value"
91 * State while collecting all egos
93 #define ID_REST_STATE_INIT 0
96 * Done collecting egos
98 #define ID_REST_STATE_POST_INIT 1
102 * The configuration handle
104 const struct GNUNET_CONFIGURATION_Handle *cfg;
107 * HTTP methods allows for this plugin
109 static char* allow_methods;
112 * @brief struct returned by the initialization function of the plugin
116 const struct GNUNET_CONFIGURATION_Handle *cfg;
127 struct EgoEntry *next;
132 struct EgoEntry *prev;
147 struct GNUNET_IDENTITY_Ego *ego;
156 struct EgoEntry *ego_head;
161 struct EgoEntry *ego_tail;
166 struct EgoEntry *ego_entry;
169 * Ptr to current ego private key
171 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
174 * The processing state
179 * Handle to Identity service.
181 struct GNUNET_IDENTITY_Handle *identity_handle;
186 struct GNUNET_REST_RequestHandle *rest_handle;
192 struct GNUNET_IDENTITY_Operation *op;
197 struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
202 struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
207 struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it;
212 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it;
215 * Desired timeout for the lookup (default is no timeout).
217 struct GNUNET_TIME_Relative timeout;
220 * ID of a task associated with the resolution process.
222 struct GNUNET_SCHEDULER_Task *timeout_task;
225 * The plugin result processor
227 GNUNET_REST_ResultProcessor proc;
230 * The closure of the result processor
240 * Error response message
252 struct GNUNET_JSONAPI_Document *resp_object;
259 * Cleanup lookup handle
260 * @param handle Handle to clean up
263 cleanup_handle (struct RequestHandle *handle)
265 struct EgoEntry *ego_entry;
266 struct EgoEntry *ego_tmp;
267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
269 if (NULL != handle->resp_object)
270 GNUNET_JSONAPI_document_delete (handle->resp_object);
271 if (NULL != handle->timeout_task)
272 GNUNET_SCHEDULER_cancel (handle->timeout_task);
273 if (NULL != handle->identity_handle)
274 GNUNET_IDENTITY_disconnect (handle->identity_handle);
275 if (NULL != handle->attr_it)
276 GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it);
277 if (NULL != handle->ticket_it)
278 GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it);
279 if (NULL != handle->idp)
280 GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
281 if (NULL != handle->url)
282 GNUNET_free (handle->url);
283 if (NULL != handle->emsg)
284 GNUNET_free (handle->emsg);
285 for (ego_entry = handle->ego_head;
289 ego_entry = ego_entry->next;
290 GNUNET_free (ego_tmp->identifier);
291 GNUNET_free (ego_tmp->keystring);
292 GNUNET_free (ego_tmp);
294 GNUNET_free (handle);
298 cleanup_handle_delayed (void *cls)
300 cleanup_handle (cls);
305 * Task run on error, sends error message. Cleans up everything.
307 * @param cls the `struct RequestHandle`
312 struct RequestHandle *handle = cls;
313 struct MHD_Response *resp;
316 GNUNET_asprintf (&json_error,
319 resp = GNUNET_REST_create_response (json_error);
320 handle->proc (handle->proc_cls, resp, handle->response_code);
321 cleanup_handle (handle);
322 GNUNET_free (json_error);
326 * Task run on timeout, sends error message. Cleans up everything.
328 * @param cls the `struct RequestHandle`
331 do_timeout (void *cls)
333 struct RequestHandle *handle = cls;
335 handle->timeout_task = NULL;
341 collect_error_cb (void *cls)
343 struct RequestHandle *handle = cls;
349 finished_cont (void *cls,
353 struct RequestHandle *handle = cls;
354 struct MHD_Response *resp;
356 resp = GNUNET_REST_create_response (emsg);
357 if (GNUNET_OK != success)
359 GNUNET_SCHEDULER_add_now (&do_error, handle);
362 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
363 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
368 * Return attributes for identity
370 * @param cls the request handle
373 return_response (void *cls)
376 struct RequestHandle *handle = cls;
377 struct MHD_Response *resp;
379 GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
381 resp = GNUNET_REST_create_response (result_str);
382 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
383 GNUNET_free (result_str);
384 cleanup_handle (handle);
389 collect_finished_cb (void *cls)
391 struct RequestHandle *handle = cls;
393 handle->attr_it = NULL;
394 handle->ticket_it = NULL;
395 GNUNET_SCHEDULER_add_now (&return_response, handle);
400 * Collect all attributes for an ego
404 ticket_collect (void *cls,
405 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
407 struct GNUNET_JSONAPI_Resource *json_resource;
408 struct RequestHandle *handle = cls;
412 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
413 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
415 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
418 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
420 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
421 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
422 value = json_string (tmp);
423 GNUNET_JSONAPI_resource_add_attr (json_resource,
428 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
429 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
430 value = json_string (tmp);
431 GNUNET_JSONAPI_resource_add_attr (json_resource,
436 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
438 value = json_string (tmp);
439 GNUNET_JSONAPI_resource_add_attr (json_resource,
444 GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it);
450 * List tickets for identity request
452 * @param con_handle the connection handle
454 * @param cls the RequestHandle
457 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
461 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
462 struct RequestHandle *handle = cls;
463 struct EgoEntry *ego_entry;
466 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
468 if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
469 strlen (handle->url))
471 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
472 GNUNET_SCHEDULER_add_now (&do_error, handle);
475 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
477 for (ego_entry = handle->ego_head;
479 ego_entry = ego_entry->next)
480 if (0 == strcmp (identity, ego_entry->identifier))
482 handle->resp_object = GNUNET_JSONAPI_document_new ();
484 if (NULL == ego_entry)
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
489 GNUNET_SCHEDULER_add_now (&return_response, handle);
492 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
493 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
494 handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp,
500 &collect_finished_cb,
506 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
510 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
511 const char* identity;
512 const char* name_str;
513 const char* value_str;
515 struct RequestHandle *handle = cls;
516 struct EgoEntry *ego_entry;
517 struct MHD_Response *resp;
518 struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute;
519 struct GNUNET_JSONAPI_Document *json_obj;
520 struct GNUNET_JSONAPI_Resource *json_res;
521 char term_data[handle->rest_handle->data_size+1];
525 struct GNUNET_JSON_Specification docspec[] = {
526 GNUNET_JSON_spec_jsonapi_document (&json_obj),
527 GNUNET_JSON_spec_end()
530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
532 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
533 strlen (handle->url))
535 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
536 GNUNET_SCHEDULER_add_now (&do_error, handle);
539 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
541 for (ego_entry = handle->ego_head;
543 ego_entry = ego_entry->next)
544 if (0 == strcmp (identity, ego_entry->identifier))
547 if (NULL == ego_entry)
549 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
550 "Identity unknown (%s)\n", identity);
551 GNUNET_JSONAPI_document_delete (json_obj);
554 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
556 if (0 >= handle->rest_handle->data_size)
558 GNUNET_SCHEDULER_add_now (&do_error, handle);
562 term_data[handle->rest_handle->data_size] = '\0';
563 GNUNET_memcpy (term_data,
564 handle->rest_handle->data,
565 handle->rest_handle->data_size);
566 data_json = json_loads (term_data,
569 GNUNET_assert (GNUNET_OK ==
570 GNUNET_JSON_parse (data_json, docspec,
572 json_decref (data_json);
573 if (NULL == json_obj)
575 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
576 "Unable to parse JSONAPI Object from %s\n",
578 GNUNET_SCHEDULER_add_now (&do_error, handle);
581 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
583 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
584 "Cannot create more than 1 resource! (Got %d)\n",
585 GNUNET_JSONAPI_document_resource_count (json_obj));
586 GNUNET_JSONAPI_document_delete (json_obj);
587 GNUNET_SCHEDULER_add_now (&do_error, handle);
590 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
591 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
592 GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
594 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
595 "Unsupported JSON data type\n");
596 GNUNET_JSONAPI_document_delete (json_obj);
597 resp = GNUNET_REST_create_response (NULL);
598 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
599 cleanup_handle (handle);
602 name_str = GNUNET_JSONAPI_resource_get_id (json_res);
603 value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
605 value_str = json_string_value (value_json);
606 attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str,
607 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
609 strlen (value_str) + 1);
610 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
611 handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
616 GNUNET_free (attribute);
617 GNUNET_JSONAPI_document_delete (json_obj);
623 * Collect all attributes for an ego
627 attr_collect (void *cls,
628 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
629 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
631 struct GNUNET_JSONAPI_Resource *json_resource;
632 struct RequestHandle *handle = cls;
635 if ((NULL == attr->name) || (NULL == attr->data))
637 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
643 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
645 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
647 value = json_string (attr->data);
648 GNUNET_JSONAPI_resource_add_attr (json_resource,
652 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
658 * List attributes for identity request
660 * @param con_handle the connection handle
662 * @param cls the RequestHandle
665 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
669 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
670 struct RequestHandle *handle = cls;
671 struct EgoEntry *ego_entry;
674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
676 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
677 strlen (handle->url))
679 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
680 GNUNET_SCHEDULER_add_now (&do_error, handle);
683 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
685 for (ego_entry = handle->ego_head;
687 ego_entry = ego_entry->next)
688 if (0 == strcmp (identity, ego_entry->identifier))
690 handle->resp_object = GNUNET_JSONAPI_document_new ();
693 if (NULL == ego_entry)
696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
698 GNUNET_SCHEDULER_add_now (&return_response, handle);
701 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
702 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
703 handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
709 &collect_finished_cb,
715 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
719 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
720 const char* identity_str;
721 const char* audience_str;
724 struct RequestHandle *handle = cls;
725 struct EgoEntry *ego_entry;
726 struct MHD_Response *resp;
727 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
728 struct GNUNET_JSONAPI_Document *json_obj;
729 struct GNUNET_JSONAPI_Resource *json_res;
730 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
731 char term_data[handle->rest_handle->data_size+1];
733 json_t *identity_json;
734 json_t *audience_json;
737 struct GNUNET_JSON_Specification docspec[] = {
738 GNUNET_JSON_spec_jsonapi_document (&json_obj),
739 GNUNET_JSON_spec_end()
742 if (0 >= handle->rest_handle->data_size)
744 GNUNET_SCHEDULER_add_now (&do_error, handle);
748 term_data[handle->rest_handle->data_size] = '\0';
749 GNUNET_memcpy (term_data,
750 handle->rest_handle->data,
751 handle->rest_handle->data_size);
752 data_json = json_loads (term_data,
755 GNUNET_assert (GNUNET_OK ==
756 GNUNET_JSON_parse (data_json, docspec,
758 json_decref (data_json);
759 if (NULL == json_obj)
761 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
762 "Unable to parse JSONAPI Object from %s\n",
764 GNUNET_SCHEDULER_add_now (&do_error, handle);
767 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
769 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
770 "Cannot create more than 1 resource! (Got %d)\n",
771 GNUNET_JSONAPI_document_resource_count (json_obj));
772 GNUNET_JSONAPI_document_delete (json_obj);
773 GNUNET_SCHEDULER_add_now (&do_error, handle);
776 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
777 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
778 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
780 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
781 "Unsupported JSON data type\n");
782 GNUNET_JSONAPI_document_delete (json_obj);
783 resp = GNUNET_REST_create_response (NULL);
784 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
785 cleanup_handle (handle);
788 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
790 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
792 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
794 rnd_str = json_string_value (rnd_json);
795 identity_str = json_string_value (identity_json);
796 audience_str = json_string_value (audience_json);
798 GNUNET_STRINGS_string_to_data (rnd_str,
802 GNUNET_STRINGS_string_to_data (identity_str,
803 strlen (identity_str),
805 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
806 GNUNET_STRINGS_string_to_data (audience_str,
807 strlen (audience_str),
809 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
811 for (ego_entry = handle->ego_head;
813 ego_entry = ego_entry->next)
815 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
817 if (0 == memcmp (&ticket.identity,
819 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
822 if (NULL == ego_entry)
824 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
825 "Identity unknown (%s)\n", identity_str);
826 GNUNET_JSONAPI_document_delete (json_obj);
829 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
831 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
832 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
837 GNUNET_JSONAPI_document_delete (json_obj);
841 consume_cont (void *cls,
842 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
843 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
845 struct RequestHandle *handle = cls;
846 struct GNUNET_JSONAPI_Resource *json_resource;
849 if (NULL == identity)
851 GNUNET_SCHEDULER_add_now (&return_response, handle);
855 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
857 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
859 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
861 value = json_string (attr->data);
862 GNUNET_JSONAPI_resource_add_attr (json_resource,
869 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
873 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
874 const char* identity_str;
875 const char* audience_str;
878 struct RequestHandle *handle = cls;
879 struct EgoEntry *ego_entry;
880 struct MHD_Response *resp;
881 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
882 struct GNUNET_JSONAPI_Document *json_obj;
883 struct GNUNET_JSONAPI_Resource *json_res;
884 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
885 char term_data[handle->rest_handle->data_size+1];
887 json_t *identity_json;
888 json_t *audience_json;
891 struct GNUNET_JSON_Specification docspec[] = {
892 GNUNET_JSON_spec_jsonapi_document (&json_obj),
893 GNUNET_JSON_spec_end()
896 if (0 >= handle->rest_handle->data_size)
898 GNUNET_SCHEDULER_add_now (&do_error, handle);
902 term_data[handle->rest_handle->data_size] = '\0';
903 GNUNET_memcpy (term_data,
904 handle->rest_handle->data,
905 handle->rest_handle->data_size);
906 data_json = json_loads (term_data,
909 GNUNET_assert (GNUNET_OK ==
910 GNUNET_JSON_parse (data_json, docspec,
912 json_decref (data_json);
913 if (NULL == json_obj)
915 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
916 "Unable to parse JSONAPI Object from %s\n",
918 GNUNET_SCHEDULER_add_now (&do_error, handle);
921 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
923 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
924 "Cannot create more than 1 resource! (Got %d)\n",
925 GNUNET_JSONAPI_document_resource_count (json_obj));
926 GNUNET_JSONAPI_document_delete (json_obj);
927 GNUNET_SCHEDULER_add_now (&do_error, handle);
930 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
931 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
932 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
934 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
935 "Unsupported JSON data type\n");
936 GNUNET_JSONAPI_document_delete (json_obj);
937 resp = GNUNET_REST_create_response (NULL);
938 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
939 cleanup_handle (handle);
942 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
944 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
946 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
948 rnd_str = json_string_value (rnd_json);
949 identity_str = json_string_value (identity_json);
950 audience_str = json_string_value (audience_json);
952 GNUNET_STRINGS_string_to_data (rnd_str,
956 GNUNET_STRINGS_string_to_data (identity_str,
957 strlen (identity_str),
959 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
960 GNUNET_STRINGS_string_to_data (audience_str,
961 strlen (audience_str),
963 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
965 for (ego_entry = handle->ego_head;
967 ego_entry = ego_entry->next)
969 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
971 if (0 == memcmp (&ticket.audience,
973 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
976 if (NULL == ego_entry)
978 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
979 "Identity unknown (%s)\n", identity_str);
980 GNUNET_JSONAPI_document_delete (json_obj);
983 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
984 handle->resp_object = GNUNET_JSONAPI_document_new ();
985 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
986 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
991 GNUNET_JSONAPI_document_delete (json_obj);
997 * Respond to OPTIONS request
999 * @param con_handle the connection handle
1000 * @param url the url
1001 * @param cls the RequestHandle
1004 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1008 struct MHD_Response *resp;
1009 struct RequestHandle *handle = cls;
1011 //For now, independent of path return all options
1012 resp = GNUNET_REST_create_response (NULL);
1013 MHD_add_response_header (resp,
1014 "Access-Control-Allow-Methods",
1016 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1017 cleanup_handle (handle);
1022 * Respond to OPTIONS request
1024 * @param con_handle the connection handle
1025 * @param url the url
1026 * @param cls the RequestHandle
1029 authorize_cont (struct GNUNET_REST_RequestHandle *con_handle,
1034 //TODO clean up method
1037 // The Authorization Server MUST validate all the OAuth 2.0 parameters according to the OAuth 2.0 specification.
1038 // The Authorization Server MUST verify that all the REQUIRED parameters are present and their usage conforms to this specification.
1039 // 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.
1043 struct MHD_Response *resp;
1044 struct RequestHandle *handle = cls;
1062 char* array[] = { "response_type", "client_id", "scope", "redirect_uri",
1063 "state", "nonce", "display", "prompt", "max_age", "ui_locales",
1064 "response_mode", "id_token_hint","login_hint", "acr_values" };
1066 int bool_array[array_size];
1068 struct GNUNET_HashCode cache_key;
1070 //iterates over each parameter and store used values in array array[]
1072 for( iterator = 0; iterator<array_size; iterator++){
1073 GNUNET_CRYPTO_hash (array[iterator], strlen (array[iterator]), &cache_key);
1074 char* cache=GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map, &cache_key);
1075 bool_array[iterator]=0;
1077 size_t size=strlen(cache)+1;
1078 array[iterator]=(char*)malloc(size*sizeof(char));
1079 strncpy(array[iterator],cache,size);
1080 bool_array[iterator]=1;
1084 //MUST validate all the OAuth 2.0 parameters & that all the REQUIRED parameters are present and their usage conforms to this specification
1086 //required values: response_type, client_id, scope, redirect_uri
1087 if(!bool_array[0] || !bool_array[1] || !bool_array[2] || !bool_array[3]){
1088 handle->emsg=GNUNET_strdup("invalid_request");
1089 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1090 GNUNET_SCHEDULER_add_now (&do_error, handle);
1093 //response_type = code
1094 if(strcmp(array[0],"code")!=0){
1095 handle->emsg=GNUNET_strdup("invalid_response_type");
1096 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1097 GNUNET_SCHEDULER_add_now (&do_error, handle);
1100 //scope contains openid
1101 if(strstr(array[2],"openid")==NULL){
1102 handle->emsg=GNUNET_strdup("invalid_scope");
1103 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1104 GNUNET_SCHEDULER_add_now (&do_error, handle);
1108 //TODO check other values and use them accordingly
1111 char* redirect_url_to_login;
1118 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg,
1119 "identity-rest-plugin",
1121 &redirect_url_to_login)){
1123 char* build_array[] = { "response_type", "client_id", "scope", "redirect_uri",
1124 "state", "nonce", "display", "prompt", "max_age", "ui_locales",
1125 "response_mode", "id_token_hint","login_hint", "acr_values" };
1127 size_t redirect_parameter_size= strlen("?");
1128 for(iterator=0;iterator<array_size;iterator++){
1129 if(bool_array[iterator]){
1130 redirect_parameter_size += strlen(array[iterator]);
1131 redirect_parameter_size += strlen(build_array[iterator]);
1132 if(iterator==array_size-1)
1134 redirect_parameter_size += strlen("=");
1136 redirect_parameter_size += strlen("=&");
1141 char redirect_parameter[redirect_parameter_size+1];
1142 redirect_parameter_size = 0;
1143 redirect_parameter[redirect_parameter_size]='?';
1144 for(iterator=0;iterator<array_size;iterator++){
1145 if(bool_array[iterator]){
1146 //If not last parameter
1147 if(iterator!=array_size-1)
1149 char cache[strlen(array[iterator])+strlen(build_array[iterator])+2+1];
1150 snprintf(cache,sizeof(cache),"%s=%s&", build_array[iterator], array[iterator]);
1151 strncat(redirect_parameter, cache, strlen(array[iterator])+strlen(build_array[iterator])+2 );
1153 char cache[strlen(array[iterator])+strlen(build_array[iterator])+1+1];
1154 snprintf(cache,sizeof(cache),"%s=%s", build_array[iterator], array[iterator]);
1155 strncat(redirect_parameter, cache, strlen(array[iterator])+strlen(build_array[iterator])+1 );
1159 char redirect_component[strlen(redirect_url_to_login)+strlen(redirect_parameter)+1];
1160 snprintf(redirect_component, sizeof(redirect_component), "%s%s", redirect_url_to_login, redirect_parameter);
1161 resp = GNUNET_REST_create_response ("");
1162 MHD_add_response_header (resp, "Location", redirect_component);
1164 handle->emsg=GNUNET_strdup("No server on localhost:8000");
1165 handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1166 GNUNET_SCHEDULER_add_now (&do_error, handle);
1168 // resp = GNUNET_REST_create_response ("");
1169 // MHD_add_response_header (resp, "Location", array[3]);
1172 handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1173 cleanup_handle (handle);
1174 for(iterator=0; iterator<array_size; iterator++){
1175 if(bool_array[iterator]){
1176 free(array[iterator]);
1183 * Handle rest request
1185 * @param handle the request handle
1188 init_cont (struct RequestHandle *handle)
1190 struct GNUNET_REST_RequestHandlerError err;
1191 static const struct GNUNET_REST_RequestHandler handlers[] = {
1192 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
1193 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
1194 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
1195 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_cont},
1196 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_cont},
1197 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1198 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1199 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
1201 GNUNET_REST_HANDLER_END
1204 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1209 handle->response_code = err.error_code;
1210 GNUNET_SCHEDULER_add_now (&do_error, handle);
1215 * If listing is enabled, prints information about the egos.
1217 * This function is initially called for all egos and then again
1218 * whenever a ego's identifier changes or if it is deleted. At the
1219 * end of the initial pass over all egos, the function is once called
1220 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1221 * be invoked in the future or that there was an error.
1223 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1224 * this function is only called ONCE, and 'NULL' being passed in
1225 * 'ego' does indicate an error (i.e. name is taken or no default
1226 * value is known). If 'ego' is non-NULL and if '*ctx'
1227 * is set in those callbacks, the value WILL be passed to a subsequent
1228 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1229 * that one was not NULL).
1231 * When an identity is renamed, this function is called with the
1232 * (known) ego but the NEW identifier.
1234 * When an identity is deleted, this function is called with the
1235 * (known) ego and "NULL" for the 'identifier'. In this case,
1236 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1239 * @param cls closure
1240 * @param ego ego handle
1241 * @param ctx context for application to store data for this ego
1242 * (during the lifetime of this process, initially NULL)
1243 * @param identifier identifier assigned by the user for this ego,
1244 * NULL if the user just deleted the ego and it
1245 * must thus no longer be used
1248 list_ego (void *cls,
1249 struct GNUNET_IDENTITY_Ego *ego,
1251 const char *identifier)
1253 struct RequestHandle *handle = cls;
1254 struct EgoEntry *ego_entry;
1255 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1257 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1259 handle->state = ID_REST_STATE_POST_INIT;
1263 if (ID_REST_STATE_INIT == handle->state) {
1264 ego_entry = GNUNET_new (struct EgoEntry);
1265 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1266 ego_entry->keystring =
1267 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1268 ego_entry->ego = ego;
1269 ego_entry->identifier = GNUNET_strdup (identifier);
1270 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1276 * Function processing the REST call
1278 * @param method HTTP method
1279 * @param url URL of the HTTP request
1280 * @param data body of the HTTP request (optional)
1281 * @param data_size length of the body
1282 * @param proc callback function for the result
1283 * @param proc_cls closure for callback function
1284 * @return GNUNET_OK if request accepted
1287 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1288 GNUNET_REST_ResultProcessor proc,
1291 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1293 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1294 handle->proc_cls = proc_cls;
1295 handle->proc = proc;
1296 handle->state = ID_REST_STATE_INIT;
1297 handle->rest_handle = rest_handle;
1299 handle->url = GNUNET_strdup (rest_handle->url);
1300 if (handle->url[strlen (handle->url)-1] == '/')
1301 handle->url[strlen (handle->url)-1] = '\0';
1302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1304 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1307 handle->timeout_task =
1308 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1316 * Entry point for the plugin.
1318 * @param cls Config info
1319 * @return NULL on error, otherwise the plugin context
1322 libgnunet_plugin_rest_identity_provider_init (void *cls)
1324 static struct Plugin plugin;
1325 struct GNUNET_REST_Plugin *api;
1328 if (NULL != plugin.cfg)
1329 return NULL; /* can only initialize once! */
1330 memset (&plugin, 0, sizeof (struct Plugin));
1332 api = GNUNET_new (struct GNUNET_REST_Plugin);
1334 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1335 api->process_request = &rest_identity_process_request;
1336 GNUNET_asprintf (&allow_methods,
1337 "%s, %s, %s, %s, %s",
1338 MHD_HTTP_METHOD_GET,
1339 MHD_HTTP_METHOD_POST,
1340 MHD_HTTP_METHOD_PUT,
1341 MHD_HTTP_METHOD_DELETE,
1342 MHD_HTTP_METHOD_OPTIONS);
1344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1345 _("Identity Provider REST API initialized\n"));
1351 * Exit point from the plugin.
1353 * @param cls the plugin context (as returned by "init")
1354 * @return always NULL
1357 libgnunet_plugin_rest_identity_provider_done (void *cls)
1359 struct GNUNET_REST_Plugin *api = cls;
1360 struct Plugin *plugin = api->cls;
1363 GNUNET_free_non_null (allow_methods);
1365 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1366 "Identity Provider REST plugin is finished\n");
1370 /* end of plugin_rest_identity_provider.c */