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;
551 struct RequestHandle *handle = cls;
552 struct EgoEntry *ego_entry;
553 struct MHD_Response *resp;
554 struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute;
555 struct GNUNET_JSONAPI_Document *json_obj;
556 struct GNUNET_JSONAPI_Resource *json_res;
557 struct GNUNET_TIME_Relative exp;
558 char term_data[handle->rest_handle->data_size+1];
563 struct GNUNET_JSON_Specification docspec[] = {
564 GNUNET_JSON_spec_jsonapi_document (&json_obj),
565 GNUNET_JSON_spec_end()
568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
570 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
571 strlen (handle->url))
573 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
574 GNUNET_SCHEDULER_add_now (&do_error, handle);
577 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
579 for (ego_entry = handle->ego_head;
581 ego_entry = ego_entry->next)
582 if (0 == strcmp (identity, ego_entry->identifier))
585 if (NULL == ego_entry)
587 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
588 "Identity unknown (%s)\n", identity);
589 GNUNET_JSONAPI_document_delete (json_obj);
592 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
594 if (0 >= handle->rest_handle->data_size)
596 GNUNET_SCHEDULER_add_now (&do_error, handle);
600 term_data[handle->rest_handle->data_size] = '\0';
601 GNUNET_memcpy (term_data,
602 handle->rest_handle->data,
603 handle->rest_handle->data_size);
604 data_json = json_loads (term_data,
607 GNUNET_assert (GNUNET_OK ==
608 GNUNET_JSON_parse (data_json, docspec,
610 json_decref (data_json);
611 if (NULL == json_obj)
613 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
614 "Unable to parse JSONAPI Object from %s\n",
616 GNUNET_SCHEDULER_add_now (&do_error, handle);
619 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
621 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
622 "Cannot create more than 1 resource! (Got %d)\n",
623 GNUNET_JSONAPI_document_resource_count (json_obj));
624 GNUNET_JSONAPI_document_delete (json_obj);
625 GNUNET_SCHEDULER_add_now (&do_error, handle);
628 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
629 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
630 GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
632 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
633 "Unsupported JSON data type\n");
634 GNUNET_JSONAPI_document_delete (json_obj);
635 resp = GNUNET_REST_create_response (NULL);
636 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
637 cleanup_handle (handle);
640 name_str = GNUNET_JSONAPI_resource_get_id (json_res);
641 exp_json = GNUNET_JSONAPI_resource_read_attr (json_res,
643 exp_str = json_string_value (exp_json);
644 if (NULL == exp_str) {
645 exp = GNUNET_TIME_UNIT_HOURS;
647 if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (exp_str,
649 exp = GNUNET_TIME_UNIT_HOURS;
653 value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
655 value_str = json_string_value (value_json);
656 attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str,
657 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
659 strlen (value_str) + 1);
660 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
661 handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
667 GNUNET_free (attribute);
668 GNUNET_JSONAPI_document_delete (json_obj);
674 * Collect all attributes for an ego
678 attr_collect (void *cls,
679 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
680 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
682 struct GNUNET_JSONAPI_Resource *json_resource;
683 struct RequestHandle *handle = cls;
687 if ((NULL == attr->name) || (NULL == attr->data))
689 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
695 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
697 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
699 tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type,
703 value = json_string (tmp_value);
705 GNUNET_JSONAPI_resource_add_attr (json_resource,
709 GNUNET_free(tmp_value);
710 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
716 * List attributes for identity request
718 * @param con_handle the connection handle
720 * @param cls the RequestHandle
723 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
727 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
728 struct RequestHandle *handle = cls;
729 struct EgoEntry *ego_entry;
732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
734 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
735 strlen (handle->url))
737 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
738 GNUNET_SCHEDULER_add_now (&do_error, handle);
741 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
743 for (ego_entry = handle->ego_head;
745 ego_entry = ego_entry->next)
746 if (0 == strcmp (identity, ego_entry->identifier))
748 handle->resp_object = GNUNET_JSONAPI_document_new ();
751 if (NULL == ego_entry)
754 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
756 GNUNET_SCHEDULER_add_now (&return_response, handle);
759 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
760 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
761 handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
767 &collect_finished_cb,
773 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
777 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
778 const char* identity_str;
779 const char* audience_str;
782 struct RequestHandle *handle = cls;
783 struct EgoEntry *ego_entry;
784 struct MHD_Response *resp;
785 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
786 struct GNUNET_JSONAPI_Document *json_obj;
787 struct GNUNET_JSONAPI_Resource *json_res;
788 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
789 char term_data[handle->rest_handle->data_size+1];
791 json_t *identity_json;
792 json_t *audience_json;
795 struct GNUNET_JSON_Specification docspec[] = {
796 GNUNET_JSON_spec_jsonapi_document (&json_obj),
797 GNUNET_JSON_spec_end()
800 if (0 >= handle->rest_handle->data_size)
802 GNUNET_SCHEDULER_add_now (&do_error, handle);
806 term_data[handle->rest_handle->data_size] = '\0';
807 GNUNET_memcpy (term_data,
808 handle->rest_handle->data,
809 handle->rest_handle->data_size);
810 data_json = json_loads (term_data,
813 GNUNET_assert (GNUNET_OK ==
814 GNUNET_JSON_parse (data_json, docspec,
816 json_decref (data_json);
817 if (NULL == json_obj)
819 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
820 "Unable to parse JSONAPI Object from %s\n",
822 GNUNET_SCHEDULER_add_now (&do_error, handle);
825 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
827 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
828 "Cannot create more than 1 resource! (Got %d)\n",
829 GNUNET_JSONAPI_document_resource_count (json_obj));
830 GNUNET_JSONAPI_document_delete (json_obj);
831 GNUNET_SCHEDULER_add_now (&do_error, handle);
834 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
835 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
836 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
838 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
839 "Unsupported JSON data type\n");
840 GNUNET_JSONAPI_document_delete (json_obj);
841 resp = GNUNET_REST_create_response (NULL);
842 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
843 cleanup_handle (handle);
846 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
848 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
850 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
852 rnd_str = json_string_value (rnd_json);
853 identity_str = json_string_value (identity_json);
854 audience_str = json_string_value (audience_json);
856 GNUNET_STRINGS_string_to_data (rnd_str,
860 GNUNET_STRINGS_string_to_data (identity_str,
861 strlen (identity_str),
863 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
864 GNUNET_STRINGS_string_to_data (audience_str,
865 strlen (audience_str),
867 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
869 for (ego_entry = handle->ego_head;
871 ego_entry = ego_entry->next)
873 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
875 if (0 == memcmp (&ticket.identity,
877 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
880 if (NULL == ego_entry)
882 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
883 "Identity unknown (%s)\n", identity_str);
884 GNUNET_JSONAPI_document_delete (json_obj);
887 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
889 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
890 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
895 GNUNET_JSONAPI_document_delete (json_obj);
899 consume_cont (void *cls,
900 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
901 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
903 struct RequestHandle *handle = cls;
904 struct GNUNET_JSONAPI_Resource *json_resource;
907 if (NULL == identity)
909 GNUNET_SCHEDULER_add_now (&return_response, handle);
913 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
915 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
917 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
919 value = json_string (attr->data);
920 GNUNET_JSONAPI_resource_add_attr (json_resource,
927 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
931 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
932 const char* identity_str;
933 const char* audience_str;
936 struct RequestHandle *handle = cls;
937 struct EgoEntry *ego_entry;
938 struct MHD_Response *resp;
939 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
940 struct GNUNET_JSONAPI_Document *json_obj;
941 struct GNUNET_JSONAPI_Resource *json_res;
942 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
943 char term_data[handle->rest_handle->data_size+1];
945 json_t *identity_json;
946 json_t *audience_json;
949 struct GNUNET_JSON_Specification docspec[] = {
950 GNUNET_JSON_spec_jsonapi_document (&json_obj),
951 GNUNET_JSON_spec_end()
954 if (0 >= handle->rest_handle->data_size)
956 GNUNET_SCHEDULER_add_now (&do_error, handle);
960 term_data[handle->rest_handle->data_size] = '\0';
961 GNUNET_memcpy (term_data,
962 handle->rest_handle->data,
963 handle->rest_handle->data_size);
964 data_json = json_loads (term_data,
967 GNUNET_assert (GNUNET_OK ==
968 GNUNET_JSON_parse (data_json, docspec,
970 json_decref (data_json);
971 if (NULL == json_obj)
973 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
974 "Unable to parse JSONAPI Object from %s\n",
976 GNUNET_SCHEDULER_add_now (&do_error, handle);
979 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
981 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
982 "Cannot create more than 1 resource! (Got %d)\n",
983 GNUNET_JSONAPI_document_resource_count (json_obj));
984 GNUNET_JSONAPI_document_delete (json_obj);
985 GNUNET_SCHEDULER_add_now (&do_error, handle);
988 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
989 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
990 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
992 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
993 "Unsupported JSON data type\n");
994 GNUNET_JSONAPI_document_delete (json_obj);
995 resp = GNUNET_REST_create_response (NULL);
996 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
997 cleanup_handle (handle);
1000 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1002 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1004 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1006 rnd_str = json_string_value (rnd_json);
1007 identity_str = json_string_value (identity_json);
1008 audience_str = json_string_value (audience_json);
1010 GNUNET_STRINGS_string_to_data (rnd_str,
1014 GNUNET_STRINGS_string_to_data (identity_str,
1015 strlen (identity_str),
1017 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1018 GNUNET_STRINGS_string_to_data (audience_str,
1019 strlen (audience_str),
1021 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1023 for (ego_entry = handle->ego_head;
1025 ego_entry = ego_entry->next)
1027 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1029 if (0 == memcmp (&ticket.audience,
1031 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1034 if (NULL == ego_entry)
1036 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1037 "Identity unknown (%s)\n", identity_str);
1038 GNUNET_JSONAPI_document_delete (json_obj);
1041 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1042 handle->resp_object = GNUNET_JSONAPI_document_new ();
1043 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1044 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
1049 GNUNET_JSONAPI_document_delete (json_obj);
1055 * Respond to OPTIONS request
1057 * @param con_handle the connection handle
1058 * @param url the url
1059 * @param cls the RequestHandle
1062 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1066 struct MHD_Response *resp;
1067 struct RequestHandle *handle = cls;
1069 //For now, independent of path return all options
1070 resp = GNUNET_REST_create_response (NULL);
1071 MHD_add_response_header (resp,
1072 "Access-Control-Allow-Methods",
1074 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1075 cleanup_handle (handle);
1080 * Handle rest request
1082 * @param handle the request handle
1085 init_cont (struct RequestHandle *handle)
1087 struct GNUNET_REST_RequestHandlerError err;
1088 static const struct GNUNET_REST_RequestHandler handlers[] = {
1089 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
1090 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
1091 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
1092 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1093 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1094 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
1096 GNUNET_REST_HANDLER_END
1099 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1104 handle->response_code = err.error_code;
1105 GNUNET_SCHEDULER_add_now (&do_error, handle);
1110 * If listing is enabled, prints information about the egos.
1112 * This function is initially called for all egos and then again
1113 * whenever a ego's identifier changes or if it is deleted. At the
1114 * end of the initial pass over all egos, the function is once called
1115 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1116 * be invoked in the future or that there was an error.
1118 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1119 * this function is only called ONCE, and 'NULL' being passed in
1120 * 'ego' does indicate an error (i.e. name is taken or no default
1121 * value is known). If 'ego' is non-NULL and if '*ctx'
1122 * is set in those callbacks, the value WILL be passed to a subsequent
1123 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1124 * that one was not NULL).
1126 * When an identity is renamed, this function is called with the
1127 * (known) ego but the NEW identifier.
1129 * When an identity is deleted, this function is called with the
1130 * (known) ego and "NULL" for the 'identifier'. In this case,
1131 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1134 * @param cls closure
1135 * @param ego ego handle
1136 * @param ctx context for application to store data for this ego
1137 * (during the lifetime of this process, initially NULL)
1138 * @param identifier identifier assigned by the user for this ego,
1139 * NULL if the user just deleted the ego and it
1140 * must thus no longer be used
1143 list_ego (void *cls,
1144 struct GNUNET_IDENTITY_Ego *ego,
1146 const char *identifier)
1148 struct RequestHandle *handle = cls;
1149 struct EgoEntry *ego_entry;
1150 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1152 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1154 handle->state = ID_REST_STATE_POST_INIT;
1158 if (ID_REST_STATE_INIT == handle->state) {
1159 ego_entry = GNUNET_new (struct EgoEntry);
1160 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1161 ego_entry->keystring =
1162 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1163 ego_entry->ego = ego;
1164 ego_entry->identifier = GNUNET_strdup (identifier);
1165 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1171 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1172 GNUNET_REST_ResultProcessor proc,
1175 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1176 handle->response_code = 0;
1177 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1178 handle->proc_cls = proc_cls;
1179 handle->proc = proc;
1180 handle->state = ID_REST_STATE_INIT;
1181 handle->rest_handle = rest_handle;
1183 handle->url = GNUNET_strdup (rest_handle->url);
1184 if (handle->url[strlen (handle->url)-1] == '/')
1185 handle->url[strlen (handle->url)-1] = '\0';
1186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1188 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1191 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
1192 handle->timeout_task =
1193 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1201 * Entry point for the plugin.
1203 * @param cls Config info
1204 * @return NULL on error, otherwise the plugin context
1207 libgnunet_plugin_rest_identity_provider_init (void *cls)
1209 static struct Plugin plugin;
1210 struct GNUNET_REST_Plugin *api;
1213 if (NULL != plugin.cfg)
1214 return NULL; /* can only initialize once! */
1215 memset (&plugin, 0, sizeof (struct Plugin));
1217 api = GNUNET_new (struct GNUNET_REST_Plugin);
1219 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1220 api->process_request = &rest_identity_process_request;
1221 GNUNET_asprintf (&allow_methods,
1222 "%s, %s, %s, %s, %s",
1223 MHD_HTTP_METHOD_GET,
1224 MHD_HTTP_METHOD_POST,
1225 MHD_HTTP_METHOD_PUT,
1226 MHD_HTTP_METHOD_DELETE,
1227 MHD_HTTP_METHOD_OPTIONS);
1229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1230 _("Identity Provider REST API initialized\n"));
1236 * Exit point from the plugin.
1238 * @param cls the plugin context (as returned by "init")
1239 * @return always NULL
1242 libgnunet_plugin_rest_identity_provider_done (void *cls)
1244 struct GNUNET_REST_Plugin *api = cls;
1245 struct Plugin *plugin = api->cls;
1248 GNUNET_free_non_null (allow_methods);
1250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1251 "Identity Provider REST plugin is finished\n");
1255 /* end of plugin_rest_identity_provider.c */