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 it
6 under the terms of the GNU General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
16 * @author Martin Schanzenbach
17 * @author Philippe Buschmann
18 * @file identity/plugin_rest_identity.c
19 * @brief GNUnet Namestore REST plugin
24 #include "gnunet_rest_plugin.h"
25 #include "gnunet_identity_service.h"
26 #include "gnunet_gns_service.h"
27 #include "gnunet_gnsrecord_lib.h"
28 #include "gnunet_namestore_service.h"
29 #include "gnunet_rest_lib.h"
30 #include "gnunet_jsonapi_lib.h"
31 #include "gnunet_jsonapi_util.h"
32 #include "microhttpd.h"
35 #include "gnunet_signatures.h"
36 #include "gnunet_identity_attribute_lib.h"
37 #include "gnunet_identity_provider_service.h"
42 #define GNUNET_REST_API_NS_IDENTITY_PROVIDER "/idp"
47 #define GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES "/idp/attributes"
52 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/idp/tickets"
57 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/idp/revoke"
62 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume"
67 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
72 #define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
78 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value"
81 * State while collecting all egos
83 #define ID_REST_STATE_INIT 0
86 * Done collecting egos
88 #define ID_REST_STATE_POST_INIT 1
91 * The configuration handle
93 const struct GNUNET_CONFIGURATION_Handle *cfg;
96 * HTTP methods allows for this plugin
98 static char* allow_methods;
101 * @brief struct returned by the initialization function of the plugin
105 const struct GNUNET_CONFIGURATION_Handle *cfg;
116 struct EgoEntry *next;
121 struct EgoEntry *prev;
136 struct GNUNET_IDENTITY_Ego *ego;
145 struct EgoEntry *ego_head;
150 struct EgoEntry *ego_tail;
155 struct EgoEntry *ego_entry;
158 * Pointer to ego private key
160 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
163 * The processing state
168 * Handle to Identity service.
170 struct GNUNET_IDENTITY_Handle *identity_handle;
175 struct GNUNET_REST_RequestHandle *rest_handle;
178 * Handle to NAMESTORE
180 struct GNUNET_NAMESTORE_Handle *namestore_handle;
183 * Iterator for NAMESTORE
185 struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
188 * Attribute claim list
190 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list;
195 struct GNUNET_IDENTITY_Operation *op;
200 struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
205 struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
210 struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it;
215 struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it;
220 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
223 * Desired timeout for the lookup (default is no timeout).
225 struct GNUNET_TIME_Relative timeout;
228 * ID of a task associated with the resolution process.
230 struct GNUNET_SCHEDULER_Task *timeout_task;
233 * The plugin result processor
235 GNUNET_REST_ResultProcessor proc;
238 * The closure of the result processor
248 * Error response message
260 struct GNUNET_JSONAPI_Document *resp_object;
265 * Cleanup lookup handle
266 * @param handle Handle to clean up
269 cleanup_handle (struct RequestHandle *handle)
271 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_entry;
272 struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_tmp;
273 struct EgoEntry *ego_entry;
274 struct EgoEntry *ego_tmp;
275 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
277 if (NULL != handle->resp_object)
278 GNUNET_JSONAPI_document_delete (handle->resp_object);
279 if (NULL != handle->timeout_task)
280 GNUNET_SCHEDULER_cancel (handle->timeout_task);
281 if (NULL != handle->identity_handle)
282 GNUNET_IDENTITY_disconnect (handle->identity_handle);
283 if (NULL != handle->attr_it)
284 GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it);
285 if (NULL != handle->ticket_it)
286 GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it);
287 if (NULL != handle->idp)
288 GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
289 if (NULL != handle->url)
290 GNUNET_free (handle->url);
291 if (NULL != handle->emsg)
292 GNUNET_free (handle->emsg);
293 if (NULL != handle->namestore_handle)
294 GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
295 if ( NULL != handle->attr_list )
297 for (claim_entry = handle->attr_list->list_head;
298 NULL != claim_entry;)
300 claim_tmp = claim_entry;
301 claim_entry = claim_entry->next;
302 GNUNET_free(claim_tmp->claim);
303 GNUNET_free(claim_tmp);
305 GNUNET_free (handle->attr_list);
307 for (ego_entry = handle->ego_head;
311 ego_entry = ego_entry->next;
312 GNUNET_free (ego_tmp->identifier);
313 GNUNET_free (ego_tmp->keystring);
314 GNUNET_free (ego_tmp);
316 if (NULL != handle->attr_it)
318 GNUNET_free(handle->attr_it);
320 GNUNET_free (handle);
324 cleanup_handle_delayed (void *cls)
326 cleanup_handle (cls);
331 * Task run on error, sends error message. Cleans up everything.
333 * @param cls the `struct RequestHandle`
338 struct RequestHandle *handle = cls;
339 struct MHD_Response *resp;
342 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }",
344 if ( 0 == handle->response_code )
346 handle->response_code = MHD_HTTP_BAD_REQUEST;
348 resp = GNUNET_REST_create_response (json_error);
349 MHD_add_response_header (resp, "Content-Type", "application/json");
350 handle->proc (handle->proc_cls, resp, handle->response_code);
351 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
352 GNUNET_free (json_error);
357 * Task run on timeout, sends error message. Cleans up everything.
359 * @param cls the `struct RequestHandle`
362 do_timeout (void *cls)
364 struct RequestHandle *handle = cls;
366 handle->timeout_task = NULL;
372 collect_error_cb (void *cls)
374 struct RequestHandle *handle = cls;
380 finished_cont (void *cls,
384 struct RequestHandle *handle = cls;
385 struct MHD_Response *resp;
387 resp = GNUNET_REST_create_response (emsg);
388 if (GNUNET_OK != success)
390 GNUNET_SCHEDULER_add_now (&do_error, handle);
393 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
394 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
399 * Return attributes for identity
401 * @param cls the request handle
404 return_response (void *cls)
407 struct RequestHandle *handle = cls;
408 struct MHD_Response *resp;
410 GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
412 resp = GNUNET_REST_create_response (result_str);
413 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
414 GNUNET_free (result_str);
415 cleanup_handle (handle);
419 collect_finished_cb (void *cls)
421 struct RequestHandle *handle = cls;
423 handle->attr_it = NULL;
424 handle->ticket_it = NULL;
425 GNUNET_SCHEDULER_add_now (&return_response, handle);
430 * Collect all attributes for an ego
434 ticket_collect (void *cls,
435 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
437 struct GNUNET_JSONAPI_Resource *json_resource;
438 struct RequestHandle *handle = cls;
442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
443 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
445 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
448 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
450 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
451 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
452 value = json_string (tmp);
453 GNUNET_JSONAPI_resource_add_attr (json_resource,
458 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
459 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
460 value = json_string (tmp);
461 GNUNET_JSONAPI_resource_add_attr (json_resource,
466 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
468 value = json_string (tmp);
469 GNUNET_JSONAPI_resource_add_attr (json_resource,
474 GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it);
480 * List tickets for identity request
482 * @param con_handle the connection handle
484 * @param cls the RequestHandle
487 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
491 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
492 struct RequestHandle *handle = cls;
493 struct EgoEntry *ego_entry;
496 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
498 if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
499 strlen (handle->url))
501 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
502 GNUNET_SCHEDULER_add_now (&do_error, handle);
505 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
507 for (ego_entry = handle->ego_head;
509 ego_entry = ego_entry->next)
510 if (0 == strcmp (identity, ego_entry->identifier))
512 handle->resp_object = GNUNET_JSONAPI_document_new ();
514 if (NULL == ego_entry)
517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
519 GNUNET_SCHEDULER_add_now (&return_response, handle);
522 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
523 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
524 handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp,
530 &collect_finished_cb,
536 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
540 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
541 const char* identity;
542 const char* name_str;
543 const char* value_str;
546 struct RequestHandle *handle = cls;
547 struct EgoEntry *ego_entry;
548 struct MHD_Response *resp;
549 struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute;
550 struct GNUNET_JSONAPI_Document *json_obj;
551 struct GNUNET_JSONAPI_Resource *json_res;
552 struct GNUNET_TIME_Relative exp;
553 char term_data[handle->rest_handle->data_size+1];
558 struct GNUNET_JSON_Specification docspec[] = {
559 GNUNET_JSON_spec_jsonapi_document (&json_obj),
560 GNUNET_JSON_spec_end()
563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
565 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
566 strlen (handle->url))
568 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
569 GNUNET_SCHEDULER_add_now (&do_error, handle);
572 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
574 for (ego_entry = handle->ego_head;
576 ego_entry = ego_entry->next)
577 if (0 == strcmp (identity, ego_entry->identifier))
580 if (NULL == ego_entry)
582 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
583 "Identity unknown (%s)\n", identity);
584 GNUNET_JSONAPI_document_delete (json_obj);
587 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
589 if (0 >= handle->rest_handle->data_size)
591 GNUNET_SCHEDULER_add_now (&do_error, handle);
595 term_data[handle->rest_handle->data_size] = '\0';
596 GNUNET_memcpy (term_data,
597 handle->rest_handle->data,
598 handle->rest_handle->data_size);
599 data_json = json_loads (term_data,
602 GNUNET_assert (GNUNET_OK ==
603 GNUNET_JSON_parse (data_json, docspec,
605 json_decref (data_json);
606 if (NULL == json_obj)
608 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
609 "Unable to parse JSONAPI Object from %s\n",
611 GNUNET_SCHEDULER_add_now (&do_error, handle);
614 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
616 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
617 "Cannot create more than 1 resource! (Got %d)\n",
618 GNUNET_JSONAPI_document_resource_count (json_obj));
619 GNUNET_JSONAPI_document_delete (json_obj);
620 GNUNET_SCHEDULER_add_now (&do_error, handle);
623 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
624 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
625 GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
627 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
628 "Unsupported JSON data type\n");
629 GNUNET_JSONAPI_document_delete (json_obj);
630 resp = GNUNET_REST_create_response (NULL);
631 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
632 cleanup_handle (handle);
635 name_str = GNUNET_JSONAPI_resource_get_id (json_res);
636 exp_json = GNUNET_JSONAPI_resource_read_attr (json_res,
638 exp_str = json_string_value (exp_json);
639 if (NULL == exp_str) {
640 exp = GNUNET_TIME_UNIT_HOURS;
642 if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (exp_str,
644 exp = GNUNET_TIME_UNIT_HOURS;
648 value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
650 value_str = json_string_value (value_json);
651 attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str,
652 GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
654 strlen (value_str) + 1);
655 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
656 handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
662 GNUNET_free (attribute);
663 GNUNET_JSONAPI_document_delete (json_obj);
669 * Collect all attributes for an ego
673 attr_collect (void *cls,
674 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
675 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
677 struct GNUNET_JSONAPI_Resource *json_resource;
678 struct RequestHandle *handle = cls;
682 if ((NULL == attr->name) || (NULL == attr->data))
684 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
690 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
692 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
694 tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type,
698 value = json_string (tmp_value);
700 GNUNET_JSONAPI_resource_add_attr (json_resource,
704 GNUNET_free(tmp_value);
705 GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
711 * List attributes for identity request
713 * @param con_handle the connection handle
715 * @param cls the RequestHandle
718 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
722 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
723 struct RequestHandle *handle = cls;
724 struct EgoEntry *ego_entry;
727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
729 if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
730 strlen (handle->url))
732 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
733 GNUNET_SCHEDULER_add_now (&do_error, handle);
736 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
738 for (ego_entry = handle->ego_head;
740 ego_entry = ego_entry->next)
741 if (0 == strcmp (identity, ego_entry->identifier))
743 handle->resp_object = GNUNET_JSONAPI_document_new ();
746 if (NULL == ego_entry)
749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
751 GNUNET_SCHEDULER_add_now (&return_response, handle);
754 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
755 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
756 handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
762 &collect_finished_cb,
768 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
772 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
773 const char* identity_str;
774 const char* audience_str;
777 struct RequestHandle *handle = cls;
778 struct EgoEntry *ego_entry;
779 struct MHD_Response *resp;
780 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
781 struct GNUNET_JSONAPI_Document *json_obj;
782 struct GNUNET_JSONAPI_Resource *json_res;
783 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
784 char term_data[handle->rest_handle->data_size+1];
786 json_t *identity_json;
787 json_t *audience_json;
790 struct GNUNET_JSON_Specification docspec[] = {
791 GNUNET_JSON_spec_jsonapi_document (&json_obj),
792 GNUNET_JSON_spec_end()
795 if (0 >= handle->rest_handle->data_size)
797 GNUNET_SCHEDULER_add_now (&do_error, handle);
801 term_data[handle->rest_handle->data_size] = '\0';
802 GNUNET_memcpy (term_data,
803 handle->rest_handle->data,
804 handle->rest_handle->data_size);
805 data_json = json_loads (term_data,
808 GNUNET_assert (GNUNET_OK ==
809 GNUNET_JSON_parse (data_json, docspec,
811 json_decref (data_json);
812 if (NULL == json_obj)
814 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
815 "Unable to parse JSONAPI Object from %s\n",
817 GNUNET_SCHEDULER_add_now (&do_error, handle);
820 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
822 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
823 "Cannot create more than 1 resource! (Got %d)\n",
824 GNUNET_JSONAPI_document_resource_count (json_obj));
825 GNUNET_JSONAPI_document_delete (json_obj);
826 GNUNET_SCHEDULER_add_now (&do_error, handle);
829 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
830 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
831 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
833 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
834 "Unsupported JSON data type\n");
835 GNUNET_JSONAPI_document_delete (json_obj);
836 resp = GNUNET_REST_create_response (NULL);
837 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
838 cleanup_handle (handle);
841 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
843 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
845 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
847 rnd_str = json_string_value (rnd_json);
848 identity_str = json_string_value (identity_json);
849 audience_str = json_string_value (audience_json);
851 GNUNET_STRINGS_string_to_data (rnd_str,
855 GNUNET_STRINGS_string_to_data (identity_str,
856 strlen (identity_str),
858 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
859 GNUNET_STRINGS_string_to_data (audience_str,
860 strlen (audience_str),
862 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
864 for (ego_entry = handle->ego_head;
866 ego_entry = ego_entry->next)
868 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
870 if (0 == memcmp (&ticket.identity,
872 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
875 if (NULL == ego_entry)
877 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
878 "Identity unknown (%s)\n", identity_str);
879 GNUNET_JSONAPI_document_delete (json_obj);
882 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
884 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
885 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
890 GNUNET_JSONAPI_document_delete (json_obj);
894 consume_cont (void *cls,
895 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
896 const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
898 struct RequestHandle *handle = cls;
899 struct GNUNET_JSONAPI_Resource *json_resource;
902 if (NULL == identity)
904 GNUNET_SCHEDULER_add_now (&return_response, handle);
908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
910 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
912 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
914 value = json_string (attr->data);
915 GNUNET_JSONAPI_resource_add_attr (json_resource,
922 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
926 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
927 const char* identity_str;
928 const char* audience_str;
931 struct RequestHandle *handle = cls;
932 struct EgoEntry *ego_entry;
933 struct MHD_Response *resp;
934 struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
935 struct GNUNET_JSONAPI_Document *json_obj;
936 struct GNUNET_JSONAPI_Resource *json_res;
937 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
938 char term_data[handle->rest_handle->data_size+1];
940 json_t *identity_json;
941 json_t *audience_json;
944 struct GNUNET_JSON_Specification docspec[] = {
945 GNUNET_JSON_spec_jsonapi_document (&json_obj),
946 GNUNET_JSON_spec_end()
949 if (0 >= handle->rest_handle->data_size)
951 GNUNET_SCHEDULER_add_now (&do_error, handle);
955 term_data[handle->rest_handle->data_size] = '\0';
956 GNUNET_memcpy (term_data,
957 handle->rest_handle->data,
958 handle->rest_handle->data_size);
959 data_json = json_loads (term_data,
962 GNUNET_assert (GNUNET_OK ==
963 GNUNET_JSON_parse (data_json, docspec,
965 json_decref (data_json);
966 if (NULL == json_obj)
968 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
969 "Unable to parse JSONAPI Object from %s\n",
971 GNUNET_SCHEDULER_add_now (&do_error, handle);
974 if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
976 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
977 "Cannot create more than 1 resource! (Got %d)\n",
978 GNUNET_JSONAPI_document_resource_count (json_obj));
979 GNUNET_JSONAPI_document_delete (json_obj);
980 GNUNET_SCHEDULER_add_now (&do_error, handle);
983 json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
984 if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
985 GNUNET_REST_JSONAPI_IDENTITY_TICKET))
987 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
988 "Unsupported JSON data type\n");
989 GNUNET_JSONAPI_document_delete (json_obj);
990 resp = GNUNET_REST_create_response (NULL);
991 handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
992 cleanup_handle (handle);
995 rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
997 identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
999 audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1001 rnd_str = json_string_value (rnd_json);
1002 identity_str = json_string_value (identity_json);
1003 audience_str = json_string_value (audience_json);
1005 GNUNET_STRINGS_string_to_data (rnd_str,
1009 GNUNET_STRINGS_string_to_data (identity_str,
1010 strlen (identity_str),
1012 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1013 GNUNET_STRINGS_string_to_data (audience_str,
1014 strlen (audience_str),
1016 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1018 for (ego_entry = handle->ego_head;
1020 ego_entry = ego_entry->next)
1022 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1024 if (0 == memcmp (&ticket.audience,
1026 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1029 if (NULL == ego_entry)
1031 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1032 "Identity unknown (%s)\n", identity_str);
1033 GNUNET_JSONAPI_document_delete (json_obj);
1036 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1037 handle->resp_object = GNUNET_JSONAPI_document_new ();
1038 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1039 handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
1044 GNUNET_JSONAPI_document_delete (json_obj);
1050 * Respond to OPTIONS request
1052 * @param con_handle the connection handle
1053 * @param url the url
1054 * @param cls the RequestHandle
1057 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1061 struct MHD_Response *resp;
1062 struct RequestHandle *handle = cls;
1064 //For now, independent of path return all options
1065 resp = GNUNET_REST_create_response (NULL);
1066 MHD_add_response_header (resp,
1067 "Access-Control-Allow-Methods",
1069 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1070 cleanup_handle (handle);
1075 * Handle rest request
1077 * @param handle the request handle
1080 init_cont (struct RequestHandle *handle)
1082 struct GNUNET_REST_RequestHandlerError err;
1083 static const struct GNUNET_REST_RequestHandler handlers[] = {
1084 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
1085 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
1086 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
1087 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1088 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1089 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
1091 GNUNET_REST_HANDLER_END
1094 if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1099 handle->response_code = err.error_code;
1100 GNUNET_SCHEDULER_add_now (&do_error, handle);
1105 * If listing is enabled, prints information about the egos.
1107 * This function is initially called for all egos and then again
1108 * whenever a ego's identifier changes or if it is deleted. At the
1109 * end of the initial pass over all egos, the function is once called
1110 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1111 * be invoked in the future or that there was an error.
1113 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1114 * this function is only called ONCE, and 'NULL' being passed in
1115 * 'ego' does indicate an error (i.e. name is taken or no default
1116 * value is known). If 'ego' is non-NULL and if '*ctx'
1117 * is set in those callbacks, the value WILL be passed to a subsequent
1118 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1119 * that one was not NULL).
1121 * When an identity is renamed, this function is called with the
1122 * (known) ego but the NEW identifier.
1124 * When an identity is deleted, this function is called with the
1125 * (known) ego and "NULL" for the 'identifier'. In this case,
1126 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1129 * @param cls closure
1130 * @param ego ego handle
1131 * @param ctx context for application to store data for this ego
1132 * (during the lifetime of this process, initially NULL)
1133 * @param identifier identifier assigned by the user for this ego,
1134 * NULL if the user just deleted the ego and it
1135 * must thus no longer be used
1138 list_ego (void *cls,
1139 struct GNUNET_IDENTITY_Ego *ego,
1141 const char *identifier)
1143 struct RequestHandle *handle = cls;
1144 struct EgoEntry *ego_entry;
1145 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1147 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1149 handle->state = ID_REST_STATE_POST_INIT;
1153 if (ID_REST_STATE_INIT == handle->state) {
1154 ego_entry = GNUNET_new (struct EgoEntry);
1155 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1156 ego_entry->keystring =
1157 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1158 ego_entry->ego = ego;
1159 ego_entry->identifier = GNUNET_strdup (identifier);
1160 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1166 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1167 GNUNET_REST_ResultProcessor proc,
1170 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1171 handle->response_code = 0;
1172 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1173 handle->proc_cls = proc_cls;
1174 handle->proc = proc;
1175 handle->state = ID_REST_STATE_INIT;
1176 handle->rest_handle = rest_handle;
1178 handle->url = GNUNET_strdup (rest_handle->url);
1179 if (handle->url[strlen (handle->url)-1] == '/')
1180 handle->url[strlen (handle->url)-1] = '\0';
1181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1183 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1186 handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
1187 handle->timeout_task =
1188 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1196 * Entry point for the plugin.
1198 * @param cls Config info
1199 * @return NULL on error, otherwise the plugin context
1202 libgnunet_plugin_rest_identity_provider_init (void *cls)
1204 static struct Plugin plugin;
1205 struct GNUNET_REST_Plugin *api;
1208 if (NULL != plugin.cfg)
1209 return NULL; /* can only initialize once! */
1210 memset (&plugin, 0, sizeof (struct Plugin));
1212 api = GNUNET_new (struct GNUNET_REST_Plugin);
1214 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1215 api->process_request = &rest_identity_process_request;
1216 GNUNET_asprintf (&allow_methods,
1217 "%s, %s, %s, %s, %s",
1218 MHD_HTTP_METHOD_GET,
1219 MHD_HTTP_METHOD_POST,
1220 MHD_HTTP_METHOD_PUT,
1221 MHD_HTTP_METHOD_DELETE,
1222 MHD_HTTP_METHOD_OPTIONS);
1224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1225 _("Identity Provider REST API initialized\n"));
1231 * Exit point from the plugin.
1233 * @param cls the plugin context (as returned by "init")
1234 * @return always NULL
1237 libgnunet_plugin_rest_identity_provider_done (void *cls)
1239 struct GNUNET_REST_Plugin *api = cls;
1240 struct Plugin *plugin = api->cls;
1243 GNUNET_free_non_null (allow_methods);
1245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1246 "Identity Provider REST plugin is finished\n");
1250 /* end of plugin_rest_identity_provider.c */