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 Affero 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.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @author Martin Schanzenbach
22 * @author Philippe Buschmann
23 * @file reclaim/plugin_rest_reclaim.c
24 * @brief GNUnet reclaim REST plugin
28 #include "microhttpd.h"
31 #include "gnunet_gns_service.h"
32 #include "gnunet_gnsrecord_lib.h"
33 #include "gnunet_identity_service.h"
34 #include "gnunet_reclaim_attribute_lib.h"
35 #include "gnunet_reclaim_service.h"
36 #include "gnunet_rest_lib.h"
37 #include "gnunet_rest_plugin.h"
38 #include "gnunet_signatures.h"
39 #include "json_reclaim.h"
43 #define GNUNET_REST_API_NS_RECLAIM "/reclaim"
48 #define GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES "/reclaim/attributes"
51 * Attestation namespace
53 #define GNUNET_REST_API_NS_RECLAIM_ATTESTATION "/reclaim/attestation"
58 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/reclaim/tickets"
63 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/reclaim/revoke"
68 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/reclaim/consume"
71 * State while collecting all egos
73 #define ID_REST_STATE_INIT 0
76 * Done collecting egos
78 #define ID_REST_STATE_POST_INIT 1
81 * The configuration handle
83 const struct GNUNET_CONFIGURATION_Handle *cfg;
86 * HTTP methods allows for this plugin
88 static char *allow_methods;
91 * @brief struct returned by the initialization function of the plugin
95 const struct GNUNET_CONFIGURATION_Handle *cfg;
106 struct EgoEntry *next;
111 struct EgoEntry *prev;
126 struct GNUNET_IDENTITY_Ego *ego;
135 struct EgoEntry *ego_head;
140 struct EgoEntry *ego_tail;
145 struct EgoEntry *ego_entry;
148 * Pointer to ego private key
150 struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
153 * The processing state
158 * Handle to Identity service.
160 struct GNUNET_IDENTITY_Handle *identity_handle;
165 struct GNUNET_REST_RequestHandle *rest_handle;
168 * Attribute claim list
170 struct GNUNET_RECLAIM_AttributeList *attr_list;
175 struct GNUNET_IDENTITY_Operation *op;
180 struct GNUNET_RECLAIM_Handle *idp;
185 struct GNUNET_RECLAIM_Operation *idp_op;
190 struct GNUNET_RECLAIM_AttributeIterator *attr_it;
195 struct GNUNET_RECLAIM_AttestationIterator *attest_it;
201 struct GNUNET_RECLAIM_TicketIterator *ticket_it;
206 struct GNUNET_RECLAIM_Ticket ticket;
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
250 * Cleanup lookup handle
251 * @param handle Handle to clean up
254 cleanup_handle (struct RequestHandle *handle)
256 struct EgoEntry *ego_entry;
257 struct EgoEntry *ego_tmp;
259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
260 if (NULL != handle->resp_object)
261 json_decref (handle->resp_object);
262 if (NULL != handle->timeout_task)
263 GNUNET_SCHEDULER_cancel (handle->timeout_task);
264 if (NULL != handle->identity_handle)
265 GNUNET_IDENTITY_disconnect (handle->identity_handle);
266 if (NULL != handle->attr_it)
267 GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
268 if (NULL != handle->attest_it)
269 GNUNET_RECLAIM_get_attestations_stop (handle->attest_it);
270 if (NULL != handle->ticket_it)
271 GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
272 if (NULL != handle->idp)
273 GNUNET_RECLAIM_disconnect (handle->idp);
274 if (NULL != handle->url)
275 GNUNET_free (handle->url);
276 if (NULL != handle->emsg)
277 GNUNET_free (handle->emsg);
278 GNUNET_RECLAIM_attribute_list_destroy (handle->attr_list);
279 for (ego_entry = handle->ego_head; NULL != ego_entry;)
282 ego_entry = ego_entry->next;
283 GNUNET_free (ego_tmp->identifier);
284 GNUNET_free (ego_tmp->keystring);
285 GNUNET_free (ego_tmp);
287 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, "{ \"error\" : \"%s\" }", handle->emsg);
311 if (0 == handle->response_code)
313 handle->response_code = MHD_HTTP_BAD_REQUEST;
315 resp = GNUNET_REST_create_response (json_error);
316 MHD_add_response_header (resp, "Content-Type", "application/json");
317 handle->proc (handle->proc_cls, resp, handle->response_code);
318 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
319 GNUNET_free (json_error);
324 * Task run on timeout, sends error message. Cleans up everything.
326 * @param cls the `struct RequestHandle`
329 do_timeout (void *cls)
331 struct RequestHandle *handle = cls;
333 handle->timeout_task = NULL;
339 collect_error_cb (void *cls)
341 struct RequestHandle *handle = cls;
348 finished_cont (void *cls, int32_t success, const char *emsg)
350 struct RequestHandle *handle = cls;
351 struct MHD_Response *resp;
353 resp = GNUNET_REST_create_response (emsg);
354 if (GNUNET_OK != success)
356 GNUNET_SCHEDULER_add_now (&do_error, handle);
359 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
360 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
365 delete_finished_cb (void *cls, int32_t success, const char *emsg)
367 struct RequestHandle *handle = cls;
368 struct MHD_Response *resp;
370 resp = GNUNET_REST_create_response (emsg);
371 if (GNUNET_OK != success)
373 GNUNET_SCHEDULER_add_now (&do_error, handle);
376 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
377 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
382 * Return attributes for identity
384 * @param cls the request handle
387 return_response (void *cls)
390 struct RequestHandle *handle = cls;
391 struct MHD_Response *resp;
393 result_str = json_dumps (handle->resp_object, 0);
394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
395 resp = GNUNET_REST_create_response (result_str);
396 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
397 GNUNET_free (result_str);
398 cleanup_handle (handle);
403 collect_finished_cb (void *cls)
405 struct RequestHandle *handle = cls;
408 handle->attr_it = NULL;
409 handle->ticket_it = NULL;
410 GNUNET_SCHEDULER_add_now (&return_response, handle);
415 * Collect all attributes for an ego
419 ticket_collect (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
421 json_t *json_resource;
422 struct RequestHandle *handle = cls;
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
427 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd));
428 json_resource = json_object ();
430 json_array_append (handle->resp_object, json_resource);
433 GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
435 GNUNET_CRYPTO_EcdsaPublicKey));
436 value = json_string (tmp);
437 json_object_set_new (json_resource, "issuer", value);
440 GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
442 GNUNET_CRYPTO_EcdsaPublicKey));
443 value = json_string (tmp);
444 json_object_set_new (json_resource, "audience", value);
446 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd));
447 value = json_string (tmp);
448 json_object_set_new (json_resource, "rnd", value);
450 GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
455 parse_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
459 struct RequestHandle *handle = cls;
461 char term_data[handle->rest_handle->data_size + 1];
465 struct MHD_Response *resp;
466 char *val_str = NULL;
467 const char *type_str = NULL;
468 term_data[handle->rest_handle->data_size] = '\0';
469 GNUNET_memcpy (term_data,
470 handle->rest_handle->data,
471 handle->rest_handle->data_size);
472 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
473 GNUNET_assert (NULL != data_json);
474 if (! json_is_object (data_json))
476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
477 "Error json is not array nor object!\n");
478 GNUNET_SCHEDULER_add_now (&do_error, handle);
481 unpack_state = json_unpack (data_json,
487 if ((0 != unpack_state) || (NULL == val_str) || (NULL == type_str))
489 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
490 "Error json object has a wrong format!\n");
491 GNUNET_SCHEDULER_add_now (&do_error, handle);
494 if (0 == strcmp (type_str, "JWT"))
496 // The value is a JWT
499 char *jwt_body = strtok (val_str, delim);
500 jwt_body = strtok (NULL, delim);
501 GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
502 (void **) &decoded_jwt);
503 resp = GNUNET_REST_create_response (decoded_jwt);
504 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
505 GNUNET_free (decoded_jwt);
509 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
510 "Error requested parsing type not supported!\n");
511 GNUNET_SCHEDULER_add_now (&do_error, handle);
514 cleanup_handle (handle);
515 json_decref (data_json);
520 add_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
524 struct RequestHandle *handle = cls;
525 /* Check for substring "parse"
527 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) < strlen (
530 if (strncmp ("parse", (handle->url + strlen (
531 GNUNET_REST_API_NS_RECLAIM_ATTESTATION)
535 parse_attestation_cont (con_handle,url,cls);
539 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
540 const char *identity;
541 struct EgoEntry *ego_entry;
542 struct GNUNET_RECLAIM_Attestation *attribute;
543 struct GNUNET_TIME_Relative exp;
544 char term_data[handle->rest_handle->data_size + 1];
547 struct GNUNET_JSON_Specification attrspec[] =
548 { GNUNET_RECLAIM_JSON_spec_claim_attest (&attribute),
549 GNUNET_JSON_spec_end () };
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552 "Adding an attestation for %s.\n",
554 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
557 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
558 GNUNET_SCHEDULER_add_now (&do_error, handle);
561 identity = handle->url + strlen (
562 GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1;
564 for (ego_entry = handle->ego_head; NULL != ego_entry;
565 ego_entry = ego_entry->next)
566 if (0 == strcmp (identity, ego_entry->identifier))
569 if (NULL == ego_entry)
571 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
574 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
576 if (0 >= handle->rest_handle->data_size)
578 GNUNET_SCHEDULER_add_now (&do_error, handle);
582 term_data[handle->rest_handle->data_size] = '\0';
583 GNUNET_memcpy (term_data,
584 handle->rest_handle->data,
585 handle->rest_handle->data_size);
586 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
587 GNUNET_assert (GNUNET_OK ==
588 GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
589 json_decref (data_json);
590 if (NULL == attribute)
592 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
593 "Unable to parse attestation from %s\n",
595 GNUNET_SCHEDULER_add_now (&do_error, handle);
599 * New ID for attribute
601 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
602 GNUNET_RECLAIM_id_generate (&attribute->id);
603 handle->idp = GNUNET_RECLAIM_connect (cfg);
604 exp = GNUNET_TIME_UNIT_HOURS;
605 handle->idp_op = GNUNET_RECLAIM_attestation_store (handle->idp,
611 GNUNET_JSON_parse_free (attrspec);
616 * Collect all attestations for an ego
620 attest_collect (void *cls,
621 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
622 const struct GNUNET_RECLAIM_Attestation *attest,
623 const struct GNUNET_RECLAIM_AttributeList *attrs)
625 struct RequestHandle *handle = cls;
634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
635 "Attestation Collection with empty Attestation\n");
636 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
640 if ((NULL == attest->name) || (NULL == attest->data))
642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
643 "Attestation Collection with empty Name/Value\n");
644 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
648 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attestation: %s\n",
651 tmp_value = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
654 attr_obj = json_object ();
655 json_object_set_new (attr_obj, "value", json_string (tmp_value));
656 json_object_set_new (attr_obj, "name", json_string (attest->name));
657 type = GNUNET_RECLAIM_attestation_number_to_typename (attest->type);
658 json_object_set_new (attr_obj, "type", json_string (type));
659 id_str = GNUNET_STRINGS_data_to_string_alloc (&attest->id,
661 json_object_set_new (attr_obj, "id", json_string (id_str));
662 json_array_append (handle->resp_object, attr_obj);
663 json_decref (attr_obj);
664 GNUNET_free (tmp_value);
665 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
670 * Lists attestation for identity request
672 * @param con_handle the connection handle
674 * @param cls the RequestHandle
677 list_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
681 struct RequestHandle *handle = cls;
682 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
683 struct EgoEntry *ego_entry;
686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
687 "Getting attestations for %s.\n",
689 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
692 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
693 GNUNET_SCHEDULER_add_now (&do_error, handle);
696 identity = handle->url + strlen (
697 GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1;
699 for (ego_entry = handle->ego_head; NULL != ego_entry;
700 ego_entry = ego_entry->next)
701 if (0 == strcmp (identity, ego_entry->identifier))
703 handle->resp_object = json_array ();
706 if (NULL == ego_entry)
709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
710 GNUNET_SCHEDULER_add_now (&return_response, handle);
713 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
714 handle->idp = GNUNET_RECLAIM_connect (cfg);
715 handle->attest_it = GNUNET_RECLAIM_get_attestations_start (handle->idp,
728 * Deletes attestation from an identity
730 * @param con_handle the connection handle
732 * @param cls the RequestHandle
735 delete_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
739 struct RequestHandle *handle = cls;
740 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
741 struct GNUNET_RECLAIM_Attestation attr;
742 struct EgoEntry *ego_entry;
743 char *identity_id_str;
747 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attestation.\n");
748 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
751 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
752 GNUNET_SCHEDULER_add_now (&do_error, handle);
756 strdup (handle->url + strlen (
757 GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1);
758 identity = strtok (identity_id_str, "/");
759 id = strtok (NULL, "/");
760 if ((NULL == identity) || (NULL == id))
762 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
763 GNUNET_free (identity_id_str);
764 GNUNET_SCHEDULER_add_now (&do_error, handle);
768 for (ego_entry = handle->ego_head; NULL != ego_entry;
769 ego_entry = ego_entry->next)
770 if (0 == strcmp (identity, ego_entry->identifier))
772 handle->resp_object = json_array ();
773 if (NULL == ego_entry)
776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
777 GNUNET_free (identity_id_str);
778 GNUNET_SCHEDULER_add_now (&return_response, handle);
781 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
782 handle->idp = GNUNET_RECLAIM_connect (cfg);
783 memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attestation));
784 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
786 handle->idp_op = GNUNET_RECLAIM_attestation_delete (handle->idp,
791 GNUNET_free (identity_id_str);
796 * List tickets for identity request
798 * @param con_handle the connection handle
800 * @param cls the RequestHandle
803 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
807 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
808 struct RequestHandle *handle = cls;
809 struct EgoEntry *ego_entry;
812 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
813 "Getting tickets for %s.\n",
815 if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url))
817 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
818 GNUNET_SCHEDULER_add_now (&do_error, handle);
821 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
823 for (ego_entry = handle->ego_head; NULL != ego_entry;
824 ego_entry = ego_entry->next)
825 if (0 == strcmp (identity, ego_entry->identifier))
827 handle->resp_object = json_array ();
829 if (NULL == ego_entry)
832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
833 GNUNET_SCHEDULER_add_now (&return_response, handle);
836 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
837 handle->idp = GNUNET_RECLAIM_connect (cfg);
839 GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
845 &collect_finished_cb,
851 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
855 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
856 const char *identity;
857 struct RequestHandle *handle = cls;
858 struct EgoEntry *ego_entry;
859 struct GNUNET_RECLAIM_Attribute *attribute;
860 struct GNUNET_TIME_Relative exp;
861 char term_data[handle->rest_handle->data_size + 1];
864 struct GNUNET_JSON_Specification attrspec[] =
865 { GNUNET_RECLAIM_JSON_spec_claim (&attribute), GNUNET_JSON_spec_end () };
867 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
868 "Adding an attribute for %s.\n",
870 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
872 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
873 GNUNET_SCHEDULER_add_now (&do_error, handle);
876 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
878 for (ego_entry = handle->ego_head; NULL != ego_entry;
879 ego_entry = ego_entry->next)
880 if (0 == strcmp (identity, ego_entry->identifier))
883 if (NULL == ego_entry)
885 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
888 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
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, JSON_DECODE_ANY, &err);
901 GNUNET_assert (GNUNET_OK ==
902 GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
903 json_decref (data_json);
904 if (NULL == attribute)
906 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
907 "Unable to parse attribute from %s\n",
909 GNUNET_SCHEDULER_add_now (&do_error, handle);
913 * New ID for attribute
915 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
916 GNUNET_RECLAIM_id_generate (&attribute->id);
917 handle->idp = GNUNET_RECLAIM_connect (cfg);
918 exp = GNUNET_TIME_UNIT_HOURS;
919 handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
925 GNUNET_JSON_parse_free (attrspec);
930 * Parse a JWT and return the respective claim value as Attribute
932 * @param attest the jwt attestation
933 * @param claim the name of the claim in the JWT
935 * @return a GNUNET_RECLAIM_Attribute, containing the new value
937 struct GNUNET_RECLAIM_Attribute *
938 parse_jwt (const struct GNUNET_RECLAIM_Attestation *attest,
942 struct GNUNET_RECLAIM_Attribute *attr;
944 const char *type_str = NULL;
945 const char *val_str = NULL;
949 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n");
952 json_error_t *json_err = NULL;
954 jwt_string = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
957 char *jwt_body = strtok (jwt_string, delim);
958 jwt_body = strtok (NULL, delim);
959 GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
960 (void **) &decoded_jwt);
961 json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, json_err);
964 json_object_foreach (json_val, key, value) {
965 if (0 == strcasecmp (key,claim))
967 val_str = json_dumps (value, JSON_ENCODE_ANY);
971 type = GNUNET_RECLAIM_attribute_typename_to_number (type_str);
972 if (GNUNET_SYSERR == GNUNET_RECLAIM_attribute_string_to_value (type,val_str,
976 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
977 "Attribute value from JWT Parser invalid!\n");
978 GNUNET_RECLAIM_attribute_string_to_value (type,
979 "Error: Referenced Claim Name not Found",
982 attr = GNUNET_RECLAIM_attribute_new (claim, &attest->id,
983 type, data, data_size);
984 attr->id = attest->id;
989 attr = GNUNET_RECLAIM_attribute_new (claim, &attest->id,
990 type, data, data_size);
991 attr->id = attest->id;
999 * Collect all attributes for an ego
1003 attr_collect (void *cls,
1004 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1005 const struct GNUNET_RECLAIM_Attribute *attr)
1007 struct RequestHandle *handle = cls;
1013 tmp_value = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1016 attr_obj = json_object ();
1017 json_object_set_new (attr_obj, "value", json_string (tmp_value));
1018 json_object_set_new (attr_obj, "name", json_string (attr->name));
1020 json_object_set_new (attr_obj, "flag", json_string ("1"));
1021 type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
1022 json_object_set_new (attr_obj, "type", json_string (type));
1023 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id,
1025 json_object_set_new (attr_obj, "id", json_string (id_str));
1026 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->attestation,
1027 sizeof(attr->attestation));
1028 json_object_set_new (attr_obj, "attestation", json_string (id_str));
1029 json_array_append (handle->resp_object, attr_obj);
1030 json_decref (attr_obj);
1031 GNUNET_free (tmp_value);
1036 * List attributes for identity request
1038 * @param con_handle the connection handle
1039 * @param url the url
1040 * @param cls the RequestHandle
1043 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1047 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1048 struct RequestHandle *handle = cls;
1049 struct EgoEntry *ego_entry;
1052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1053 "Getting attributes for %s.\n",
1055 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1057 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1058 GNUNET_SCHEDULER_add_now (&do_error, handle);
1061 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
1063 for (ego_entry = handle->ego_head; NULL != ego_entry;
1064 ego_entry = ego_entry->next)
1065 if (0 == strcmp (identity, ego_entry->identifier))
1067 handle->resp_object = json_array ();
1070 if (NULL == ego_entry)
1073 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1074 GNUNET_SCHEDULER_add_now (&return_response, handle);
1077 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1078 handle->idp = GNUNET_RECLAIM_connect (cfg);
1079 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
1085 &collect_finished_cb,
1091 * List attributes for identity request
1093 * @param con_handle the connection handle
1094 * @param url the url
1095 * @param cls the RequestHandle
1098 delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1102 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1103 struct RequestHandle *handle = cls;
1104 struct GNUNET_RECLAIM_Attribute attr;
1105 struct EgoEntry *ego_entry;
1106 char *identity_id_str;
1110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
1111 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1113 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1114 GNUNET_SCHEDULER_add_now (&do_error, handle);
1118 strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
1119 identity = strtok (identity_id_str, "/");
1120 id = strtok (NULL, "/");
1121 if ((NULL == identity) || (NULL == id))
1123 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
1124 GNUNET_free (identity_id_str);
1125 GNUNET_SCHEDULER_add_now (&do_error, handle);
1129 for (ego_entry = handle->ego_head; NULL != ego_entry;
1130 ego_entry = ego_entry->next)
1131 if (0 == strcmp (identity, ego_entry->identifier))
1133 handle->resp_object = json_array ();
1134 if (NULL == ego_entry)
1137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1138 GNUNET_free (identity_id_str);
1139 GNUNET_SCHEDULER_add_now (&return_response, handle);
1142 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1143 handle->idp = GNUNET_RECLAIM_connect (cfg);
1144 memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attribute));
1145 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
1147 handle->idp_op = GNUNET_RECLAIM_attribute_delete (handle->idp,
1150 &delete_finished_cb,
1152 GNUNET_free (identity_id_str);
1157 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1161 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1162 struct RequestHandle *handle = cls;
1163 struct EgoEntry *ego_entry;
1164 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1165 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1166 char term_data[handle->rest_handle->data_size + 1];
1169 struct GNUNET_JSON_Specification tktspec[] =
1170 { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1172 if (0 >= handle->rest_handle->data_size)
1174 GNUNET_SCHEDULER_add_now (&do_error, handle);
1178 term_data[handle->rest_handle->data_size] = '\0';
1179 GNUNET_memcpy (term_data,
1180 handle->rest_handle->data,
1181 handle->rest_handle->data_size);
1182 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1183 if ((NULL == data_json) ||
1184 (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)))
1186 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1187 GNUNET_SCHEDULER_add_now (&do_error, handle);
1188 GNUNET_JSON_parse_free (tktspec);
1189 if (NULL != data_json)
1190 json_decref (data_json);
1193 json_decref (data_json);
1196 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1197 "Unable to parse ticket from %s\n",
1199 GNUNET_SCHEDULER_add_now (&do_error, handle);
1203 for (ego_entry = handle->ego_head; NULL != ego_entry;
1204 ego_entry = ego_entry->next)
1206 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1207 if (0 == memcmp (&ticket->identity,
1209 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1212 if (NULL == ego_entry)
1214 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1215 GNUNET_JSON_parse_free (tktspec);
1218 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1220 handle->idp = GNUNET_RECLAIM_connect (cfg);
1221 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
1226 GNUNET_JSON_parse_free (tktspec);
1231 consume_cont (void *cls,
1232 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1233 const struct GNUNET_RECLAIM_Attribute *attr,
1234 const struct GNUNET_RECLAIM_Attestation *attest)
1236 struct RequestHandle *handle = cls;
1240 if (NULL == identity)
1242 GNUNET_SCHEDULER_add_now (&return_response, handle);
1246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
1247 val_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1250 if (NULL == val_str)
1252 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1253 "Failed to parse value for: %s\n",
1257 value = json_string (val_str);
1258 json_object_set_new (handle->resp_object, attr->name, value);
1259 json_decref (value);
1260 GNUNET_free (val_str);
1265 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1269 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1270 struct RequestHandle *handle = cls;
1271 struct EgoEntry *ego_entry;
1272 struct GNUNET_RECLAIM_Ticket *ticket;
1273 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1274 char term_data[handle->rest_handle->data_size + 1];
1277 struct GNUNET_JSON_Specification tktspec[] =
1278 { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1280 if (0 >= handle->rest_handle->data_size)
1282 GNUNET_SCHEDULER_add_now (&do_error, handle);
1286 term_data[handle->rest_handle->data_size] = '\0';
1287 GNUNET_memcpy (term_data,
1288 handle->rest_handle->data,
1289 handle->rest_handle->data_size);
1290 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1291 if (NULL == data_json)
1293 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1294 "Unable to parse JSON Object from %s\n",
1296 GNUNET_SCHEDULER_add_now (&do_error, handle);
1299 if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL))
1301 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1302 GNUNET_SCHEDULER_add_now (&do_error, handle);
1303 GNUNET_JSON_parse_free (tktspec);
1304 json_decref (data_json);
1307 for (ego_entry = handle->ego_head; NULL != ego_entry;
1308 ego_entry = ego_entry->next)
1310 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1311 if (0 == memcmp (&ticket->audience,
1313 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1316 if (NULL == ego_entry)
1318 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1319 GNUNET_JSON_parse_free (tktspec);
1322 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1323 handle->resp_object = json_object ();
1324 handle->idp = GNUNET_RECLAIM_connect (cfg);
1325 handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
1330 GNUNET_JSON_parse_free (tktspec);
1335 * Respond to OPTIONS request
1337 * @param con_handle the connection handle
1338 * @param url the url
1339 * @param cls the RequestHandle
1342 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1346 struct MHD_Response *resp;
1347 struct RequestHandle *handle = cls;
1349 // For now, independent of path return all options
1350 resp = GNUNET_REST_create_response (NULL);
1351 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1352 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1353 cleanup_handle (handle);
1359 * Handle rest request
1361 * @param handle the request handle
1364 init_cont (struct RequestHandle *handle)
1366 struct GNUNET_REST_RequestHandlerError err;
1367 static const struct GNUNET_REST_RequestHandler handlers[] =
1368 { { MHD_HTTP_METHOD_GET,
1369 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1370 &list_attribute_cont },
1371 { MHD_HTTP_METHOD_POST,
1372 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1373 &add_attribute_cont },
1374 { MHD_HTTP_METHOD_DELETE,
1375 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1376 &delete_attribute_cont },
1377 { MHD_HTTP_METHOD_GET,
1378 GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1379 &list_attestation_cont },
1380 { MHD_HTTP_METHOD_POST,
1381 GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1382 &add_attestation_cont },
1383 { MHD_HTTP_METHOD_DELETE,
1384 GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1385 &delete_attestation_cont },
1386 { MHD_HTTP_METHOD_GET,
1387 GNUNET_REST_API_NS_IDENTITY_TICKETS,
1388 &list_tickets_cont },
1389 { MHD_HTTP_METHOD_POST,
1390 GNUNET_REST_API_NS_IDENTITY_REVOKE,
1391 &revoke_ticket_cont },
1392 { MHD_HTTP_METHOD_POST,
1393 GNUNET_REST_API_NS_IDENTITY_CONSUME,
1394 &consume_ticket_cont },
1395 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont },
1396 GNUNET_REST_HANDLER_END };
1399 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1401 handle->response_code = err.error_code;
1402 GNUNET_SCHEDULER_add_now (&do_error, handle);
1408 * If listing is enabled, prints information about the egos.
1410 * This function is initially called for all egos and then again
1411 * whenever a ego's identifier changes or if it is deleted. At the
1412 * end of the initial pass over all egos, the function is once called
1413 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1414 * be invoked in the future or that there was an error.
1416 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1417 * this function is only called ONCE, and 'NULL' being passed in
1418 * 'ego' does indicate an error (i.e. name is taken or no default
1419 * value is known). If 'ego' is non-NULL and if '*ctx'
1420 * is set in those callbacks, the value WILL be passed to a subsequent
1421 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1422 * that one was not NULL).
1424 * When an identity is renamed, this function is called with the
1425 * (known) ego but the NEW identifier.
1427 * When an identity is deleted, this function is called with the
1428 * (known) ego and "NULL" for the 'identifier'. In this case,
1429 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1432 * @param cls closure
1433 * @param ego ego handle
1434 * @param ctx context for application to store data for this ego
1435 * (during the lifetime of this process, initially NULL)
1436 * @param identifier identifier assigned by the user for this ego,
1437 * NULL if the user just deleted the ego and it
1438 * must thus no longer be used
1441 list_ego (void *cls,
1442 struct GNUNET_IDENTITY_Ego *ego,
1444 const char *identifier)
1446 struct RequestHandle *handle = cls;
1447 struct EgoEntry *ego_entry;
1448 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1450 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1452 handle->state = ID_REST_STATE_POST_INIT;
1456 if (ID_REST_STATE_INIT == handle->state)
1458 ego_entry = GNUNET_new (struct EgoEntry);
1459 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1460 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1461 ego_entry->ego = ego;
1462 ego_entry->identifier = GNUNET_strdup (identifier);
1463 GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1471 rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1472 GNUNET_REST_ResultProcessor proc,
1475 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1477 handle->response_code = 0;
1478 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1479 handle->proc_cls = proc_cls;
1480 handle->proc = proc;
1481 handle->state = ID_REST_STATE_INIT;
1482 handle->rest_handle = rest_handle;
1484 handle->url = GNUNET_strdup (rest_handle->url);
1485 if (handle->url[strlen (handle->url) - 1] == '/')
1486 handle->url[strlen (handle->url) - 1] = '\0';
1487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1488 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
1489 handle->timeout_task =
1490 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
1491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1496 * Entry point for the plugin.
1498 * @param cls Config info
1499 * @return NULL on error, otherwise the plugin context
1502 libgnunet_plugin_rest_reclaim_init (void *cls)
1504 static struct Plugin plugin;
1505 struct GNUNET_REST_Plugin *api;
1508 if (NULL != plugin.cfg)
1509 return NULL; /* can only initialize once! */
1510 memset (&plugin, 0, sizeof(struct Plugin));
1512 api = GNUNET_new (struct GNUNET_REST_Plugin);
1514 api->name = GNUNET_REST_API_NS_RECLAIM;
1515 api->process_request = &rest_identity_process_request;
1516 GNUNET_asprintf (&allow_methods,
1517 "%s, %s, %s, %s, %s",
1518 MHD_HTTP_METHOD_GET,
1519 MHD_HTTP_METHOD_POST,
1520 MHD_HTTP_METHOD_PUT,
1521 MHD_HTTP_METHOD_DELETE,
1522 MHD_HTTP_METHOD_OPTIONS);
1524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1525 _ ("Identity Provider REST API initialized\n"));
1531 * Exit point from the plugin.
1533 * @param cls the plugin context (as returned by "init")
1534 * @return always NULL
1537 libgnunet_plugin_rest_reclaim_done (void *cls)
1539 struct GNUNET_REST_Plugin *api = cls;
1540 struct Plugin *plugin = api->cls;
1544 GNUNET_free_non_null (allow_methods);
1546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1547 "Identity Provider REST plugin is finished\n");
1552 /* end of plugin_rest_reclaim.c */