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 * @author Philippe Buschmann
23 * @file identity/plugin_rest_identity.c
24 * @brief GNUnet Namestore REST plugin
29 #include "gnunet_rest_plugin.h"
30 #include "gnunet_identity_service.h"
31 #include "gnunet_gns_service.h"
32 #include "gnunet_gnsrecord_lib.h"
33 #include "gnunet_namestore_service.h"
34 #include "gnunet_rest_lib.h"
35 #include "gnunet_jsonapi_lib.h"
36 #include "gnunet_jsonapi_util.h"
37 #include "microhttpd.h"
40 #include "gnunet_signatures.h"
41 #include "gnunet_identity_attribute_lib.h"
42 #include "gnunet_identity_provider_service.h"
47 #define GNUNET_REST_API_NS_IDENTITY_PROVIDER "/idp"
52 #define GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES "/idp/attributes"
57 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/idp/tickets"
62 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/idp/revoke"
67 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume"
72 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
77 #define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
83 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value"
86 * State while collecting all egos
88 #define ID_REST_STATE_INIT 0
91 * Done collecting egos
93 #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 * Pointer to ego private key
165 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;
183 * Handle to NAMESTORE
185 struct GNUNET_NAMESTORE_Handle *namestore_handle;
188 * Iterator for NAMESTORE
190 struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
193 * Attribute claim list
195 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list;
200 struct GNUNET_IDENTITY_Operation *op;
205 struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
210 struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
215 struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it;
220 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it;
225 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
228 * Desired timeout for the lookup (default is no timeout).
230 struct GNUNET_TIME_Relative timeout;
233 * ID of a task associated with the resolution process.
235 struct GNUNET_SCHEDULER_Task *timeout_task;
238 * The plugin result processor
240 GNUNET_REST_ResultProcessor proc;
243 * The closure of the result processor
253 * Error response message
265 struct GNUNET_JSONAPI_Document *resp_object;
270 * Cleanup lookup handle
271 * @param handle Handle to clean up
274 cleanup_handle (struct RequestHandle *handle)
276 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_entry;
277 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_tmp;
278 struct EgoEntry *ego_entry;
279 struct EgoEntry *ego_tmp;
280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
282 if (NULL != handle->resp_object)
283 GNUNET_JSONAPI_document_delete (handle->resp_object);
284 if (NULL != handle->timeout_task)
285 GNUNET_SCHEDULER_cancel (handle->timeout_task);
286 if (NULL != handle->identity_handle)
287 GNUNET_IDENTITY_disconnect (handle->identity_handle);
288 if (NULL != handle->attr_it)
289 GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it);
290 if (NULL != handle->ticket_it)
291 GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it);
292 if (NULL != handle->idp)
293 GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
294 if (NULL != handle->url)
295 GNUNET_free (handle->url);
296 if (NULL != handle->emsg)
297 GNUNET_free (handle->emsg);
298 if (NULL != handle->namestore_handle)
299 GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
300 if ( NULL != handle->attr_list )
302 for (claim_entry = handle->attr_list->list_head;
303 NULL != claim_entry;)
305 claim_tmp = claim_entry;
306 claim_entry = claim_entry->next;
307 GNUNET_free(claim_tmp->claim);
308 GNUNET_free(claim_tmp);
310 GNUNET_free (handle->attr_list);
312 for (ego_entry = handle->ego_head;
316 ego_entry = ego_entry->next;
317 GNUNET_free (ego_tmp->identifier);
318 GNUNET_free (ego_tmp->keystring);
319 GNUNET_free (ego_tmp);
321 if (NULL != handle->attr_it)
323 GNUNET_free(handle->attr_it);
325 GNUNET_free (handle);
329 cleanup_handle_delayed (void *cls)
331 cleanup_handle (cls);
336 * Task run on error, sends error message. Cleans up everything.
338 * @param cls the `struct RequestHandle`
343 struct RequestHandle *handle = cls;
344 struct MHD_Response *resp;
347 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }",
349 if ( 0 == handle->response_code )
351 handle->response_code = MHD_HTTP_BAD_REQUEST;
353 resp = GNUNET_REST_create_response (json_error);
354 MHD_add_response_header (resp, "Content-Type", "application/json");
355 handle->proc (handle->proc_cls, resp, handle->response_code);
356 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
357 GNUNET_free (json_error);
362 * Task run on timeout, sends error message. Cleans up everything.
364 * @param cls the `struct RequestHandle`
367 do_timeout (void *cls)
369 struct RequestHandle *handle = cls;
371 handle->timeout_task = NULL;
377 collect_error_cb (void *cls)
379 struct RequestHandle *handle = cls;
385 finished_cont (void *cls,
389 struct RequestHandle *handle = cls;
390 struct MHD_Response *resp;
392 resp = GNUNET_REST_create_response (emsg);
393 if (GNUNET_OK != success)
395 GNUNET_SCHEDULER_add_now (&do_error, handle);
398 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
399 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
404 * Return attributes for identity
406 * @param cls the request handle
409 return_response (void *cls)
412 struct RequestHandle *handle = cls;
413 struct MHD_Response *resp;
415 GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
417 resp = GNUNET_REST_create_response (result_str);
418 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
419 GNUNET_free (result_str);
420 cleanup_handle (handle);
424 collect_finished_cb (void *cls)
426 struct RequestHandle *handle = cls;
428 handle->attr_it = NULL;
429 handle->ticket_it = NULL;
430 GNUNET_SCHEDULER_add_now (&return_response, handle);
435 * Collect all attributes for an ego
439 ticket_collect (void *cls,
440 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
442 struct GNUNET_JSONAPI_Resource *json_resource;
443 struct RequestHandle *handle = cls;
447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
448 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
450 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
453 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
455 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
456 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
457 value = json_string (tmp);
458 GNUNET_JSONAPI_resource_add_attr (json_resource,
463 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
464 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
465 value = json_string (tmp);
466 GNUNET_JSONAPI_resource_add_attr (json_resource,
471 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
473 value = json_string (tmp);
474 GNUNET_JSONAPI_resource_add_attr (json_resource,
479 GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it);
485 * List tickets for identity request
487 * @param con_handle the connection handle
489 * @param cls the RequestHandle
492 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
496 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
497 struct RequestHandle *handle = cls;
498 struct EgoEntry *ego_entry;
501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
503 if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
504 strlen (handle->url))
506 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
507 GNUNET_SCHEDULER_add_now (&do_error, handle);
510 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
512 for (ego_entry = handle->ego_head;
514 ego_entry = ego_entry->next)
515 if (0 == strcmp (identity, ego_entry->identifier))
517 handle->resp_object = GNUNET_JSONAPI_document_new ();
519 if (NULL == ego_entry)
522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
524 GNUNET_SCHEDULER_add_now (&return_response, handle);
527 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
528 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
529 handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp,
535 &collect_finished_cb,
541 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
545 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
546 const char* identity;
547 const char* name_str;
548 const char* value_str;
550 struct RequestHandle *handle = cls;
551 struct EgoEntry *ego_entry;
552 struct MHD_Response *resp;
553 struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute;
554 struct GNUNET_JSONAPI_Document *json_obj;
555 struct GNUNET_JSONAPI_Resource *json_res;
556 char term_data[handle->rest_handle->data_size+1];
560 struct GNUNET_JSON_Specification docspec[] = {
561 GNUNET_JSON_spec_jsonapi_document (&json_obj),
562 GNUNET_JSON_spec_end()
565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
567 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
568 strlen (handle->url))
570 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
571 GNUNET_SCHEDULER_add_now (&do_error, handle);
574 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
576 for (ego_entry = handle->ego_head;
578 ego_entry = ego_entry->next)
579 if (0 == strcmp (identity, ego_entry->identifier))
582 if (NULL == ego_entry)
584 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
585 "Identity unknown (%s)\n", identity);
586 GNUNET_JSONAPI_document_delete (json_obj);
589 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
591 if (0 >= handle->rest_handle->data_size)
593 GNUNET_SCHEDULER_add_now (&do_error, handle);
597 term_data[handle->rest_handle->data_size] = '\0';
598 GNUNET_memcpy (term_data,
599 handle->rest_handle->data,
600 handle->rest_handle->data_size);
601 data_json = json_loads (term_data,
604 GNUNET_assert (GNUNET_OK ==
605 GNUNET_JSON_parse (data_json, docspec,
607 json_decref (data_json);
608 if (NULL == json_obj)
610 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
611 "Unable to parse JSONAPI Object from %s\n",
613 GNUNET_SCHEDULER_add_now (&do_error, handle);
616 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
618 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
619 "Cannot create more than 1 resource! (Got %d)\n",
620 GNUNET_JSONAPI_document_resource_count (json_obj));
621 GNUNET_JSONAPI_document_delete (json_obj);
622 GNUNET_SCHEDULER_add_now (&do_error, handle);
625 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
626 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
627 GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
629 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
630 "Unsupported JSON data type\n");
631 GNUNET_JSONAPI_document_delete (json_obj);
632 resp = GNUNET_REST_create_response (NULL);
633 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
634 cleanup_handle (handle);
637 name_str = GNUNET_JSONAPI_resource_get_id (json_res);
638 value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
640 value_str = json_string_value (value_json);
641 attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str,
642 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
644 strlen (value_str) + 1);
645 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
646 handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
651 GNUNET_free (attribute);
652 GNUNET_JSONAPI_document_delete (json_obj);
658 * Collect all attributes for an ego
662 attr_collect (void *cls,
663 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
664 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
666 struct GNUNET_JSONAPI_Resource *json_resource;
667 struct RequestHandle *handle = cls;
671 if ((NULL == attr->name) || (NULL == attr->data))
673 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
679 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
681 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
683 tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type,
687 value = json_string (tmp_value);
689 GNUNET_JSONAPI_resource_add_attr (json_resource,
693 GNUNET_free(tmp_value);
694 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
700 * List attributes for identity request
702 * @param con_handle the connection handle
704 * @param cls the RequestHandle
707 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
711 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
712 struct RequestHandle *handle = cls;
713 struct EgoEntry *ego_entry;
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
718 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
719 strlen (handle->url))
721 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
722 GNUNET_SCHEDULER_add_now (&do_error, handle);
725 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
727 for (ego_entry = handle->ego_head;
729 ego_entry = ego_entry->next)
730 if (0 == strcmp (identity, ego_entry->identifier))
732 handle->resp_object = GNUNET_JSONAPI_document_new ();
735 if (NULL == ego_entry)
738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
740 GNUNET_SCHEDULER_add_now (&return_response, handle);
743 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
744 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
745 handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
751 &collect_finished_cb,
757 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
761 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
762 const char* identity_str;
763 const char* audience_str;
766 struct RequestHandle *handle = cls;
767 struct EgoEntry *ego_entry;
768 struct MHD_Response *resp;
769 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
770 struct GNUNET_JSONAPI_Document *json_obj;
771 struct GNUNET_JSONAPI_Resource *json_res;
772 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
773 char term_data[handle->rest_handle->data_size+1];
775 json_t *identity_json;
776 json_t *audience_json;
779 struct GNUNET_JSON_Specification docspec[] = {
780 GNUNET_JSON_spec_jsonapi_document (&json_obj),
781 GNUNET_JSON_spec_end()
784 if (0 >= handle->rest_handle->data_size)
786 GNUNET_SCHEDULER_add_now (&do_error, handle);
790 term_data[handle->rest_handle->data_size] = '\0';
791 GNUNET_memcpy (term_data,
792 handle->rest_handle->data,
793 handle->rest_handle->data_size);
794 data_json = json_loads (term_data,
797 GNUNET_assert (GNUNET_OK ==
798 GNUNET_JSON_parse (data_json, docspec,
800 json_decref (data_json);
801 if (NULL == json_obj)
803 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
804 "Unable to parse JSONAPI Object from %s\n",
806 GNUNET_SCHEDULER_add_now (&do_error, handle);
809 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
811 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
812 "Cannot create more than 1 resource! (Got %d)\n",
813 GNUNET_JSONAPI_document_resource_count (json_obj));
814 GNUNET_JSONAPI_document_delete (json_obj);
815 GNUNET_SCHEDULER_add_now (&do_error, handle);
818 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
819 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
820 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
822 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
823 "Unsupported JSON data type\n");
824 GNUNET_JSONAPI_document_delete (json_obj);
825 resp = GNUNET_REST_create_response (NULL);
826 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
827 cleanup_handle (handle);
830 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
832 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
834 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
836 rnd_str = json_string_value (rnd_json);
837 identity_str = json_string_value (identity_json);
838 audience_str = json_string_value (audience_json);
840 GNUNET_STRINGS_string_to_data (rnd_str,
844 GNUNET_STRINGS_string_to_data (identity_str,
845 strlen (identity_str),
847 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
848 GNUNET_STRINGS_string_to_data (audience_str,
849 strlen (audience_str),
851 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
853 for (ego_entry = handle->ego_head;
855 ego_entry = ego_entry->next)
857 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
859 if (0 == memcmp (&ticket.identity,
861 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
864 if (NULL == ego_entry)
866 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
867 "Identity unknown (%s)\n", identity_str);
868 GNUNET_JSONAPI_document_delete (json_obj);
871 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
873 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
874 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
879 GNUNET_JSONAPI_document_delete (json_obj);
883 consume_cont (void *cls,
884 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
885 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
887 struct RequestHandle *handle = cls;
888 struct GNUNET_JSONAPI_Resource *json_resource;
891 if (NULL == identity)
893 GNUNET_SCHEDULER_add_now (&return_response, handle);
897 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
899 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
901 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
903 value = json_string (attr->data);
904 GNUNET_JSONAPI_resource_add_attr (json_resource,
911 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
915 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
916 const char* identity_str;
917 const char* audience_str;
920 struct RequestHandle *handle = cls;
921 struct EgoEntry *ego_entry;
922 struct MHD_Response *resp;
923 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
924 struct GNUNET_JSONAPI_Document *json_obj;
925 struct GNUNET_JSONAPI_Resource *json_res;
926 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
927 char term_data[handle->rest_handle->data_size+1];
929 json_t *identity_json;
930 json_t *audience_json;
933 struct GNUNET_JSON_Specification docspec[] = {
934 GNUNET_JSON_spec_jsonapi_document (&json_obj),
935 GNUNET_JSON_spec_end()
938 if (0 >= handle->rest_handle->data_size)
940 GNUNET_SCHEDULER_add_now (&do_error, handle);
944 term_data[handle->rest_handle->data_size] = '\0';
945 GNUNET_memcpy (term_data,
946 handle->rest_handle->data,
947 handle->rest_handle->data_size);
948 data_json = json_loads (term_data,
951 GNUNET_assert (GNUNET_OK ==
952 GNUNET_JSON_parse (data_json, docspec,
954 json_decref (data_json);
955 if (NULL == json_obj)
957 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
958 "Unable to parse JSONAPI Object from %s\n",
960 GNUNET_SCHEDULER_add_now (&do_error, handle);
963 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
965 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
966 "Cannot create more than 1 resource! (Got %d)\n",
967 GNUNET_JSONAPI_document_resource_count (json_obj));
968 GNUNET_JSONAPI_document_delete (json_obj);
969 GNUNET_SCHEDULER_add_now (&do_error, handle);
972 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
973 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
974 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
976 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
977 "Unsupported JSON data type\n");
978 GNUNET_JSONAPI_document_delete (json_obj);
979 resp = GNUNET_REST_create_response (NULL);
980 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
981 cleanup_handle (handle);
984 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
986 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
988 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
990 rnd_str = json_string_value (rnd_json);
991 identity_str = json_string_value (identity_json);
992 audience_str = json_string_value (audience_json);
994 GNUNET_STRINGS_string_to_data (rnd_str,
998 GNUNET_STRINGS_string_to_data (identity_str,
999 strlen (identity_str),
1001 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1002 GNUNET_STRINGS_string_to_data (audience_str,
1003 strlen (audience_str),
1005 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1007 for (ego_entry = handle->ego_head;
1009 ego_entry = ego_entry->next)
1011 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1013 if (0 == memcmp (&ticket.audience,
1015 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1018 if (NULL == ego_entry)
1020 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1021 "Identity unknown (%s)\n", identity_str);
1022 GNUNET_JSONAPI_document_delete (json_obj);
1025 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1026 handle->resp_object = GNUNET_JSONAPI_document_new ();
1027 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1028 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
1033 GNUNET_JSONAPI_document_delete (json_obj);
1039 * Respond to OPTIONS request
1041 * @param con_handle the connection handle
1042 * @param url the url
1043 * @param cls the RequestHandle
1046 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1050 struct MHD_Response *resp;
1051 struct RequestHandle *handle = cls;
1053 //For now, independent of path return all options
1054 resp = GNUNET_REST_create_response (NULL);
1055 MHD_add_response_header (resp,
1056 "Access-Control-Allow-Methods",
1058 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1059 cleanup_handle (handle);
1064 * Handle rest request
1066 * @param handle the request handle
1069 init_cont (struct RequestHandle *handle)
1071 struct GNUNET_REST_RequestHandlerError err;
1072 static const struct GNUNET_REST_RequestHandler handlers[] = {
1073 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
1074 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
1075 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
1076 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1077 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1078 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
1080 GNUNET_REST_HANDLER_END
1083 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1088 handle->response_code = err.error_code;
1089 GNUNET_SCHEDULER_add_now (&do_error, handle);
1094 * If listing is enabled, prints information about the egos.
1096 * This function is initially called for all egos and then again
1097 * whenever a ego's identifier changes or if it is deleted. At the
1098 * end of the initial pass over all egos, the function is once called
1099 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1100 * be invoked in the future or that there was an error.
1102 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1103 * this function is only called ONCE, and 'NULL' being passed in
1104 * 'ego' does indicate an error (i.e. name is taken or no default
1105 * value is known). If 'ego' is non-NULL and if '*ctx'
1106 * is set in those callbacks, the value WILL be passed to a subsequent
1107 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1108 * that one was not NULL).
1110 * When an identity is renamed, this function is called with the
1111 * (known) ego but the NEW identifier.
1113 * When an identity is deleted, this function is called with the
1114 * (known) ego and "NULL" for the 'identifier'. In this case,
1115 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1118 * @param cls closure
1119 * @param ego ego handle
1120 * @param ctx context for application to store data for this ego
1121 * (during the lifetime of this process, initially NULL)
1122 * @param identifier identifier assigned by the user for this ego,
1123 * NULL if the user just deleted the ego and it
1124 * must thus no longer be used
1127 list_ego (void *cls,
1128 struct GNUNET_IDENTITY_Ego *ego,
1130 const char *identifier)
1132 struct RequestHandle *handle = cls;
1133 struct EgoEntry *ego_entry;
1134 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1136 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1138 handle->state = ID_REST_STATE_POST_INIT;
1142 if (ID_REST_STATE_INIT == handle->state) {
1143 ego_entry = GNUNET_new (struct EgoEntry);
1144 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1145 ego_entry->keystring =
1146 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1147 ego_entry->ego = ego;
1148 ego_entry->identifier = GNUNET_strdup (identifier);
1149 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1155 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1156 GNUNET_REST_ResultProcessor proc,
1159 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1160 handle->response_code = 0;
1161 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1162 handle->proc_cls = proc_cls;
1163 handle->proc = proc;
1164 handle->state = ID_REST_STATE_INIT;
1165 handle->rest_handle = rest_handle;
1167 handle->url = GNUNET_strdup (rest_handle->url);
1168 if (handle->url[strlen (handle->url)-1] == '/')
1169 handle->url[strlen (handle->url)-1] = '\0';
1170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1172 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1175 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
1176 handle->timeout_task =
1177 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1185 * Entry point for the plugin.
1187 * @param cls Config info
1188 * @return NULL on error, otherwise the plugin context
1191 libgnunet_plugin_rest_identity_provider_init (void *cls)
1193 static struct Plugin plugin;
1194 struct GNUNET_REST_Plugin *api;
1197 if (NULL != plugin.cfg)
1198 return NULL; /* can only initialize once! */
1199 memset (&plugin, 0, sizeof (struct Plugin));
1201 api = GNUNET_new (struct GNUNET_REST_Plugin);
1203 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1204 api->process_request = &rest_identity_process_request;
1205 GNUNET_asprintf (&allow_methods,
1206 "%s, %s, %s, %s, %s",
1207 MHD_HTTP_METHOD_GET,
1208 MHD_HTTP_METHOD_POST,
1209 MHD_HTTP_METHOD_PUT,
1210 MHD_HTTP_METHOD_DELETE,
1211 MHD_HTTP_METHOD_OPTIONS);
1213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1214 _("Identity Provider REST API initialized\n"));
1220 * Exit point from the plugin.
1222 * @param cls the plugin context (as returned by "init")
1223 * @return always NULL
1226 libgnunet_plugin_rest_identity_provider_done (void *cls)
1228 struct GNUNET_REST_Plugin *api = cls;
1229 struct Plugin *plugin = api->cls;
1232 GNUNET_free_non_null (allow_methods);
1234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1235 "Identity Provider REST plugin is finished\n");
1239 /* end of plugin_rest_identity_provider.c */