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_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
76 #define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
82 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value"
85 * State while collecting all egos
87 #define ID_REST_STATE_INIT 0
90 * Done collecting egos
92 #define ID_REST_STATE_POST_INIT 1
96 * The configuration handle
98 const struct GNUNET_CONFIGURATION_Handle *cfg;
101 * HTTP methods allows for this plugin
103 static char* allow_methods;
106 * @brief struct returned by the initialization function of the plugin
110 const struct GNUNET_CONFIGURATION_Handle *cfg;
121 struct EgoEntry *next;
126 struct EgoEntry *prev;
141 struct GNUNET_IDENTITY_Ego *ego;
150 struct EgoEntry *ego_head;
155 struct EgoEntry *ego_tail;
160 struct EgoEntry *ego_entry;
163 * Ptr to current ego private key
165 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
168 * The processing state
173 * Handle to Identity service.
175 struct GNUNET_IDENTITY_Handle *identity_handle;
180 struct GNUNET_REST_RequestHandle *rest_handle;
186 struct GNUNET_IDENTITY_Operation *op;
191 struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
196 struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
201 struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it;
206 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it;
209 * Desired timeout for the lookup (default is no timeout).
211 struct GNUNET_TIME_Relative timeout;
214 * ID of a task associated with the resolution process.
216 struct GNUNET_SCHEDULER_Task *timeout_task;
219 * The plugin result processor
221 GNUNET_REST_ResultProcessor proc;
224 * The closure of the result processor
234 * Error response message
246 struct GNUNET_JSONAPI_Document *resp_object;
253 * Cleanup lookup handle
254 * @param handle Handle to clean up
257 cleanup_handle (struct RequestHandle *handle)
259 struct EgoEntry *ego_entry;
260 struct EgoEntry *ego_tmp;
261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
263 if (NULL != handle->resp_object)
264 GNUNET_JSONAPI_document_delete (handle->resp_object);
265 if (NULL != handle->timeout_task)
266 GNUNET_SCHEDULER_cancel (handle->timeout_task);
267 if (NULL != handle->identity_handle)
268 GNUNET_IDENTITY_disconnect (handle->identity_handle);
269 if (NULL != handle->attr_it)
270 GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it);
271 if (NULL != handle->ticket_it)
272 GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it);
273 if (NULL != handle->idp)
274 GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
275 if (NULL != handle->url)
276 GNUNET_free (handle->url);
277 if (NULL != handle->emsg)
278 GNUNET_free (handle->emsg);
279 for (ego_entry = handle->ego_head;
283 ego_entry = ego_entry->next;
284 GNUNET_free (ego_tmp->identifier);
285 GNUNET_free (ego_tmp->keystring);
286 GNUNET_free (ego_tmp);
288 GNUNET_free (handle);
292 cleanup_handle_delayed (void *cls)
294 cleanup_handle (cls);
299 * Task run on error, sends error message. Cleans up everything.
301 * @param cls the `struct RequestHandle`
306 struct RequestHandle *handle = cls;
307 struct MHD_Response *resp;
310 GNUNET_asprintf (&json_error,
311 "{Error while processing request: %s}",
313 resp = GNUNET_REST_create_response (json_error);
314 handle->proc (handle->proc_cls, resp, handle->response_code);
315 cleanup_handle (handle);
316 GNUNET_free (json_error);
320 * Task run on timeout, sends error message. Cleans up everything.
322 * @param cls the `struct RequestHandle`
325 do_timeout (void *cls)
327 struct RequestHandle *handle = cls;
329 handle->timeout_task = NULL;
335 collect_error_cb (void *cls)
337 struct RequestHandle *handle = cls;
343 finished_cont (void *cls,
347 struct RequestHandle *handle = cls;
348 struct MHD_Response *resp;
350 resp = GNUNET_REST_create_response (emsg);
351 if (GNUNET_OK != success)
353 GNUNET_SCHEDULER_add_now (&do_error, handle);
356 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
357 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
362 * Return attributes for identity
364 * @param cls the request handle
367 return_response (void *cls)
370 struct RequestHandle *handle = cls;
371 struct MHD_Response *resp;
373 GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
374 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
375 resp = GNUNET_REST_create_response (result_str);
376 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
377 GNUNET_free (result_str);
378 cleanup_handle (handle);
383 collect_finished_cb (void *cls)
385 struct RequestHandle *handle = cls;
387 handle->attr_it = NULL;
388 handle->ticket_it = NULL;
389 GNUNET_SCHEDULER_add_now (&return_response, handle);
394 * Collect all attributes for an ego
398 ticket_collect (void *cls,
399 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
401 struct GNUNET_JSONAPI_Resource *json_resource;
402 struct RequestHandle *handle = cls;
406 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
407 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
409 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
412 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
414 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
415 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
416 value = json_string (tmp);
417 GNUNET_JSONAPI_resource_add_attr (json_resource,
422 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
423 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
424 value = json_string (tmp);
425 GNUNET_JSONAPI_resource_add_attr (json_resource,
430 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
432 value = json_string (tmp);
433 GNUNET_JSONAPI_resource_add_attr (json_resource,
438 GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it);
444 * List tickets for identity request
446 * @param con_handle the connection handle
448 * @param cls the RequestHandle
451 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
455 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
456 struct RequestHandle *handle = cls;
457 struct EgoEntry *ego_entry;
460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
462 if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
463 strlen (handle->url))
465 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
466 GNUNET_SCHEDULER_add_now (&do_error, handle);
469 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
471 for (ego_entry = handle->ego_head;
473 ego_entry = ego_entry->next)
474 if (0 == strcmp (identity, ego_entry->identifier))
476 handle->resp_object = GNUNET_JSONAPI_document_new ();
478 if (NULL == ego_entry)
481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
483 GNUNET_SCHEDULER_add_now (&return_response, handle);
486 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
487 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
488 handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp,
494 &collect_finished_cb,
500 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
504 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
505 const char* identity;
506 const char* name_str;
507 const char* value_str;
509 struct RequestHandle *handle = cls;
510 struct EgoEntry *ego_entry;
511 struct MHD_Response *resp;
512 struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute;
513 struct GNUNET_JSONAPI_Document *json_obj;
514 struct GNUNET_JSONAPI_Resource *json_res;
515 char term_data[handle->rest_handle->data_size+1];
519 struct GNUNET_JSON_Specification docspec[] = {
520 GNUNET_JSON_spec_jsonapi_document (&json_obj),
521 GNUNET_JSON_spec_end()
524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
526 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
527 strlen (handle->url))
529 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
530 GNUNET_SCHEDULER_add_now (&do_error, handle);
533 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
535 for (ego_entry = handle->ego_head;
537 ego_entry = ego_entry->next)
538 if (0 == strcmp (identity, ego_entry->identifier))
541 if (NULL == ego_entry)
543 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
544 "Identity unknown (%s)\n", identity);
545 GNUNET_JSONAPI_document_delete (json_obj);
548 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
550 if (0 >= handle->rest_handle->data_size)
552 GNUNET_SCHEDULER_add_now (&do_error, handle);
556 term_data[handle->rest_handle->data_size] = '\0';
557 GNUNET_memcpy (term_data,
558 handle->rest_handle->data,
559 handle->rest_handle->data_size);
560 data_json = json_loads (term_data,
563 GNUNET_assert (GNUNET_OK ==
564 GNUNET_JSON_parse (data_json, docspec,
566 json_decref (data_json);
567 if (NULL == json_obj)
569 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
570 "Unable to parse JSONAPI Object from %s\n",
572 GNUNET_SCHEDULER_add_now (&do_error, handle);
575 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
577 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
578 "Cannot create more than 1 resource! (Got %d)\n",
579 GNUNET_JSONAPI_document_resource_count (json_obj));
580 GNUNET_JSONAPI_document_delete (json_obj);
581 GNUNET_SCHEDULER_add_now (&do_error, handle);
584 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
585 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
586 GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
588 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
589 "Unsupported JSON data type\n");
590 GNUNET_JSONAPI_document_delete (json_obj);
591 resp = GNUNET_REST_create_response (NULL);
592 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
593 cleanup_handle (handle);
596 name_str = GNUNET_JSONAPI_resource_get_id (json_res);
597 value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
599 value_str = json_string_value (value_json);
600 attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str,
601 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
603 strlen (value_str) + 1);
604 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
605 handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
610 GNUNET_free (attribute);
611 GNUNET_JSONAPI_document_delete (json_obj);
617 * Collect all attributes for an ego
621 attr_collect (void *cls,
622 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
623 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
625 struct GNUNET_JSONAPI_Resource *json_resource;
626 struct RequestHandle *handle = cls;
629 if ((NULL == attr->name) || (NULL == attr->data))
631 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
637 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
639 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
641 value = json_string (attr->data);
642 GNUNET_JSONAPI_resource_add_attr (json_resource,
646 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
652 * List attributes for identity request
654 * @param con_handle the connection handle
656 * @param cls the RequestHandle
659 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
663 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
664 struct RequestHandle *handle = cls;
665 struct EgoEntry *ego_entry;
668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
670 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
671 strlen (handle->url))
673 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
674 GNUNET_SCHEDULER_add_now (&do_error, handle);
677 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
679 for (ego_entry = handle->ego_head;
681 ego_entry = ego_entry->next)
682 if (0 == strcmp (identity, ego_entry->identifier))
684 handle->resp_object = GNUNET_JSONAPI_document_new ();
687 if (NULL == ego_entry)
690 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
692 GNUNET_SCHEDULER_add_now (&return_response, handle);
695 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
696 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
697 handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
703 &collect_finished_cb,
709 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
713 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
714 const char* identity_str;
715 const char* audience_str;
718 struct RequestHandle *handle = cls;
719 struct EgoEntry *ego_entry;
720 struct MHD_Response *resp;
721 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
722 struct GNUNET_JSONAPI_Document *json_obj;
723 struct GNUNET_JSONAPI_Resource *json_res;
724 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
725 char term_data[handle->rest_handle->data_size+1];
727 json_t *identity_json;
728 json_t *audience_json;
731 struct GNUNET_JSON_Specification docspec[] = {
732 GNUNET_JSON_spec_jsonapi_document (&json_obj),
733 GNUNET_JSON_spec_end()
736 if (0 >= handle->rest_handle->data_size)
738 GNUNET_SCHEDULER_add_now (&do_error, handle);
742 term_data[handle->rest_handle->data_size] = '\0';
743 GNUNET_memcpy (term_data,
744 handle->rest_handle->data,
745 handle->rest_handle->data_size);
746 data_json = json_loads (term_data,
749 GNUNET_assert (GNUNET_OK ==
750 GNUNET_JSON_parse (data_json, docspec,
752 json_decref (data_json);
753 if (NULL == json_obj)
755 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
756 "Unable to parse JSONAPI Object from %s\n",
758 GNUNET_SCHEDULER_add_now (&do_error, handle);
761 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
763 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
764 "Cannot create more than 1 resource! (Got %d)\n",
765 GNUNET_JSONAPI_document_resource_count (json_obj));
766 GNUNET_JSONAPI_document_delete (json_obj);
767 GNUNET_SCHEDULER_add_now (&do_error, handle);
770 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
771 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
772 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
774 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
775 "Unsupported JSON data type\n");
776 GNUNET_JSONAPI_document_delete (json_obj);
777 resp = GNUNET_REST_create_response (NULL);
778 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
779 cleanup_handle (handle);
782 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
784 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
786 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
788 rnd_str = json_string_value (rnd_json);
789 identity_str = json_string_value (identity_json);
790 audience_str = json_string_value (audience_json);
792 GNUNET_STRINGS_string_to_data (rnd_str,
796 GNUNET_STRINGS_string_to_data (identity_str,
797 strlen (identity_str),
799 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
800 GNUNET_STRINGS_string_to_data (audience_str,
801 strlen (audience_str),
803 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
805 for (ego_entry = handle->ego_head;
807 ego_entry = ego_entry->next)
809 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
811 if (0 == memcmp (&ticket.identity,
813 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
816 if (NULL == ego_entry)
818 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
819 "Identity unknown (%s)\n", identity_str);
820 GNUNET_JSONAPI_document_delete (json_obj);
823 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
825 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
826 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
831 GNUNET_JSONAPI_document_delete (json_obj);
835 consume_cont (void *cls,
836 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
837 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
839 struct RequestHandle *handle = cls;
840 struct GNUNET_JSONAPI_Resource *json_resource;
843 if (NULL == identity)
845 GNUNET_SCHEDULER_add_now (&return_response, handle);
849 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
851 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
853 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
855 value = json_string (attr->data);
856 GNUNET_JSONAPI_resource_add_attr (json_resource,
863 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
867 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
868 const char* identity_str;
869 const char* audience_str;
872 struct RequestHandle *handle = cls;
873 struct EgoEntry *ego_entry;
874 struct MHD_Response *resp;
875 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
876 struct GNUNET_JSONAPI_Document *json_obj;
877 struct GNUNET_JSONAPI_Resource *json_res;
878 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
879 char term_data[handle->rest_handle->data_size+1];
881 json_t *identity_json;
882 json_t *audience_json;
885 struct GNUNET_JSON_Specification docspec[] = {
886 GNUNET_JSON_spec_jsonapi_document (&json_obj),
887 GNUNET_JSON_spec_end()
890 if (0 >= handle->rest_handle->data_size)
892 GNUNET_SCHEDULER_add_now (&do_error, handle);
896 term_data[handle->rest_handle->data_size] = '\0';
897 GNUNET_memcpy (term_data,
898 handle->rest_handle->data,
899 handle->rest_handle->data_size);
900 data_json = json_loads (term_data,
903 GNUNET_assert (GNUNET_OK ==
904 GNUNET_JSON_parse (data_json, docspec,
906 json_decref (data_json);
907 if (NULL == json_obj)
909 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
910 "Unable to parse JSONAPI Object from %s\n",
912 GNUNET_SCHEDULER_add_now (&do_error, handle);
915 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
917 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
918 "Cannot create more than 1 resource! (Got %d)\n",
919 GNUNET_JSONAPI_document_resource_count (json_obj));
920 GNUNET_JSONAPI_document_delete (json_obj);
921 GNUNET_SCHEDULER_add_now (&do_error, handle);
924 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
925 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
926 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
928 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
929 "Unsupported JSON data type\n");
930 GNUNET_JSONAPI_document_delete (json_obj);
931 resp = GNUNET_REST_create_response (NULL);
932 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
933 cleanup_handle (handle);
936 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
938 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
940 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
942 rnd_str = json_string_value (rnd_json);
943 identity_str = json_string_value (identity_json);
944 audience_str = json_string_value (audience_json);
946 GNUNET_STRINGS_string_to_data (rnd_str,
950 GNUNET_STRINGS_string_to_data (identity_str,
951 strlen (identity_str),
953 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
954 GNUNET_STRINGS_string_to_data (audience_str,
955 strlen (audience_str),
957 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
959 for (ego_entry = handle->ego_head;
961 ego_entry = ego_entry->next)
963 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
965 if (0 == memcmp (&ticket.audience,
967 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
970 if (NULL == ego_entry)
972 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
973 "Identity unknown (%s)\n", identity_str);
974 GNUNET_JSONAPI_document_delete (json_obj);
977 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
978 handle->resp_object = GNUNET_JSONAPI_document_new ();
979 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
980 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
985 GNUNET_JSONAPI_document_delete (json_obj);
991 * Respond to OPTIONS request
993 * @param con_handle the connection handle
995 * @param cls the RequestHandle
998 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1002 struct MHD_Response *resp;
1003 struct RequestHandle *handle = cls;
1005 //For now, independent of path return all options
1006 resp = GNUNET_REST_create_response (NULL);
1007 MHD_add_response_header (resp,
1008 "Access-Control-Allow-Methods",
1010 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1011 cleanup_handle (handle);
1016 * Handle rest request
1018 * @param handle the request handle
1021 init_cont (struct RequestHandle *handle)
1023 struct GNUNET_REST_RequestHandlerError err;
1024 static const struct GNUNET_REST_RequestHandler handlers[] = {
1025 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
1026 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
1027 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
1028 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1029 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1030 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
1032 GNUNET_REST_HANDLER_END
1035 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1040 handle->response_code = err.error_code;
1041 GNUNET_SCHEDULER_add_now (&do_error, handle);
1046 * If listing is enabled, prints information about the egos.
1048 * This function is initially called for all egos and then again
1049 * whenever a ego's identifier changes or if it is deleted. At the
1050 * end of the initial pass over all egos, the function is once called
1051 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1052 * be invoked in the future or that there was an error.
1054 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1055 * this function is only called ONCE, and 'NULL' being passed in
1056 * 'ego' does indicate an error (i.e. name is taken or no default
1057 * value is known). If 'ego' is non-NULL and if '*ctx'
1058 * is set in those callbacks, the value WILL be passed to a subsequent
1059 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1060 * that one was not NULL).
1062 * When an identity is renamed, this function is called with the
1063 * (known) ego but the NEW identifier.
1065 * When an identity is deleted, this function is called with the
1066 * (known) ego and "NULL" for the 'identifier'. In this case,
1067 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1070 * @param cls closure
1071 * @param ego ego handle
1072 * @param ctx context for application to store data for this ego
1073 * (during the lifetime of this process, initially NULL)
1074 * @param identifier identifier assigned by the user for this ego,
1075 * NULL if the user just deleted the ego and it
1076 * must thus no longer be used
1079 list_ego (void *cls,
1080 struct GNUNET_IDENTITY_Ego *ego,
1082 const char *identifier)
1084 struct RequestHandle *handle = cls;
1085 struct EgoEntry *ego_entry;
1086 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1088 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1090 handle->state = ID_REST_STATE_POST_INIT;
1094 if (ID_REST_STATE_INIT == handle->state) {
1095 ego_entry = GNUNET_new (struct EgoEntry);
1096 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1097 ego_entry->keystring =
1098 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1099 ego_entry->ego = ego;
1100 ego_entry->identifier = GNUNET_strdup (identifier);
1101 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1107 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1108 GNUNET_REST_ResultProcessor proc,
1111 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1113 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1114 handle->proc_cls = proc_cls;
1115 handle->proc = proc;
1116 handle->state = ID_REST_STATE_INIT;
1117 handle->rest_handle = rest_handle;
1119 handle->url = GNUNET_strdup (rest_handle->url);
1120 if (handle->url[strlen (handle->url)-1] == '/')
1121 handle->url[strlen (handle->url)-1] = '\0';
1122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1124 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1127 handle->timeout_task =
1128 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1136 * Entry point for the plugin.
1138 * @param cls Config info
1139 * @return NULL on error, otherwise the plugin context
1142 libgnunet_plugin_rest_identity_provider_init (void *cls)
1144 static struct Plugin plugin;
1145 struct GNUNET_REST_Plugin *api;
1148 if (NULL != plugin.cfg)
1149 return NULL; /* can only initialize once! */
1150 memset (&plugin, 0, sizeof (struct Plugin));
1152 api = GNUNET_new (struct GNUNET_REST_Plugin);
1154 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1155 api->process_request = &rest_identity_process_request;
1156 GNUNET_asprintf (&allow_methods,
1157 "%s, %s, %s, %s, %s",
1158 MHD_HTTP_METHOD_GET,
1159 MHD_HTTP_METHOD_POST,
1160 MHD_HTTP_METHOD_PUT,
1161 MHD_HTTP_METHOD_DELETE,
1162 MHD_HTTP_METHOD_OPTIONS);
1164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1165 _("Identity Provider REST API initialized\n"));
1171 * Exit point from the plugin.
1173 * @param cls the plugin context (as returned by "init")
1174 * @return always NULL
1177 libgnunet_plugin_rest_identity_provider_done (void *cls)
1179 struct GNUNET_REST_Plugin *api = cls;
1180 struct Plugin *plugin = api->cls;
1183 GNUNET_free_non_null (allow_methods);
1185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1186 "Identity Provider REST plugin is finished\n");
1190 /* end of plugin_rest_identity_provider.c */