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 if (NULL != handle->attr_list)
279 GNUNET_RECLAIM_attribute_list_destroy (handle->attr_list);
280 for (ego_entry = handle->ego_head; NULL != ego_entry;)
283 ego_entry = ego_entry->next;
284 GNUNET_free (ego_tmp->identifier);
285 GNUNET_free (ego_tmp->keystring);
286 GNUNET_free (ego_tmp);
288 GNUNET_free (handle);
293 cleanup_handle_delayed (void *cls)
295 cleanup_handle (cls);
300 * Task run on error, sends error message. Cleans up everything.
302 * @param cls the `struct RequestHandle`
307 struct RequestHandle *handle = cls;
308 struct MHD_Response *resp;
311 GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\" }", handle->emsg);
312 if (0 == handle->response_code)
314 handle->response_code = MHD_HTTP_BAD_REQUEST;
316 resp = GNUNET_REST_create_response (json_error);
317 MHD_add_response_header (resp, "Content-Type", "application/json");
318 handle->proc (handle->proc_cls, resp, handle->response_code);
319 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
320 GNUNET_free (json_error);
325 * Task run on timeout, sends error message. Cleans up everything.
327 * @param cls the `struct RequestHandle`
330 do_timeout (void *cls)
332 struct RequestHandle *handle = cls;
334 handle->timeout_task = NULL;
340 collect_error_cb (void *cls)
342 struct RequestHandle *handle = cls;
349 finished_cont (void *cls, int32_t success, const char *emsg)
351 struct RequestHandle *handle = cls;
352 struct MHD_Response *resp;
354 resp = GNUNET_REST_create_response (emsg);
355 if (GNUNET_OK != success)
357 GNUNET_SCHEDULER_add_now (&do_error, handle);
360 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
361 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
366 delete_finished_cb (void *cls, int32_t success, const char *emsg)
368 struct RequestHandle *handle = cls;
369 struct MHD_Response *resp;
371 resp = GNUNET_REST_create_response (emsg);
372 if (GNUNET_OK != success)
374 GNUNET_SCHEDULER_add_now (&do_error, handle);
377 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
378 GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
383 * Return attributes for identity
385 * @param cls the request handle
388 return_response (void *cls)
391 struct RequestHandle *handle = cls;
392 struct MHD_Response *resp;
394 result_str = json_dumps (handle->resp_object, 0);
395 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
396 resp = GNUNET_REST_create_response (result_str);
397 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
398 GNUNET_free (result_str);
399 cleanup_handle (handle);
404 collect_finished_cb (void *cls)
406 struct RequestHandle *handle = cls;
409 handle->attr_it = NULL;
410 handle->ticket_it = NULL;
411 GNUNET_SCHEDULER_add_now (&return_response, handle);
416 * Collect all attributes for an ego
420 ticket_collect (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
422 json_t *json_resource;
423 struct RequestHandle *handle = cls;
427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
428 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd));
429 json_resource = json_object ();
431 json_array_append (handle->resp_object, json_resource);
434 GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
436 GNUNET_CRYPTO_EcdsaPublicKey));
437 value = json_string (tmp);
438 json_object_set_new (json_resource, "issuer", value);
441 GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
443 GNUNET_CRYPTO_EcdsaPublicKey));
444 value = json_string (tmp);
445 json_object_set_new (json_resource, "audience", value);
447 tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd));
448 value = json_string (tmp);
449 json_object_set_new (json_resource, "rnd", value);
451 GNUNET_RECLAIM_ticket_iteration_next (handle->ticket_it);
456 parse_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
460 struct RequestHandle *handle = cls;
462 char term_data[handle->rest_handle->data_size + 1];
466 struct MHD_Response *resp;
467 char *val_str = NULL;
468 const char *type_str = NULL;
469 term_data[handle->rest_handle->data_size] = '\0';
470 GNUNET_memcpy (term_data,
471 handle->rest_handle->data,
472 handle->rest_handle->data_size);
473 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
474 GNUNET_assert (NULL != data_json);
475 if (! json_is_object (data_json))
477 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
478 "Error json is not array nor object!\n");
479 GNUNET_SCHEDULER_add_now (&do_error, handle);
482 unpack_state = json_unpack (data_json,
488 if ((0 != unpack_state) || (NULL == val_str) || (NULL == type_str))
490 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
491 "Error json object has a wrong format!\n");
492 GNUNET_SCHEDULER_add_now (&do_error, handle);
495 if (0 == strcmp (type_str, "JWT"))
497 // The value is a JWT
500 char *jwt_body = strtok (val_str, delim);
501 jwt_body = strtok (NULL, delim);
502 GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
503 (void **) &decoded_jwt);
504 resp = GNUNET_REST_create_response (decoded_jwt);
505 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
506 GNUNET_free (decoded_jwt);
510 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
511 "Error requested parsing type not supported!\n");
512 GNUNET_SCHEDULER_add_now (&do_error, handle);
515 cleanup_handle (handle);
516 json_decref (data_json);
521 add_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
525 struct RequestHandle *handle = cls;
526 /* Check for substring "parse"
528 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) < strlen (
531 if (strncmp ("parse", (handle->url + strlen (
532 GNUNET_REST_API_NS_RECLAIM_ATTESTATION)
536 parse_attestation_cont (con_handle,url,cls);
540 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
541 const char *identity;
542 struct EgoEntry *ego_entry;
543 struct GNUNET_RECLAIM_Attestation *attribute;
544 struct GNUNET_TIME_Relative exp;
545 char term_data[handle->rest_handle->data_size + 1];
548 struct GNUNET_JSON_Specification attrspec[] =
549 { GNUNET_RECLAIM_JSON_spec_claim_attest (&attribute),
550 GNUNET_JSON_spec_end () };
552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
553 "Adding an attestation for %s.\n",
555 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
558 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
559 GNUNET_SCHEDULER_add_now (&do_error, handle);
562 identity = handle->url + strlen (
563 GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1;
565 for (ego_entry = handle->ego_head; NULL != ego_entry;
566 ego_entry = ego_entry->next)
567 if (0 == strcmp (identity, ego_entry->identifier))
570 if (NULL == ego_entry)
572 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
575 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
577 if (0 >= handle->rest_handle->data_size)
579 GNUNET_SCHEDULER_add_now (&do_error, handle);
583 term_data[handle->rest_handle->data_size] = '\0';
584 GNUNET_memcpy (term_data,
585 handle->rest_handle->data,
586 handle->rest_handle->data_size);
587 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
588 GNUNET_assert (GNUNET_OK ==
589 GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
590 json_decref (data_json);
591 if (NULL == attribute)
593 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
594 "Unable to parse attestation from %s\n",
596 GNUNET_SCHEDULER_add_now (&do_error, handle);
600 * New ID for attribute
602 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
603 GNUNET_RECLAIM_id_generate (&attribute->id);
604 handle->idp = GNUNET_RECLAIM_connect (cfg);
605 exp = GNUNET_TIME_UNIT_HOURS;
606 handle->idp_op = GNUNET_RECLAIM_attestation_store (handle->idp,
612 GNUNET_JSON_parse_free (attrspec);
617 * Collect all attestations for an ego
621 attest_collect (void *cls,
622 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
623 const struct GNUNET_RECLAIM_Attestation *attest,
624 const struct GNUNET_RECLAIM_AttributeList *attrs)
626 struct RequestHandle *handle = cls;
635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
636 "Attestation Collection with empty Attestation\n");
637 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
641 if ((NULL == attest->name) || (NULL == attest->data))
643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
644 "Attestation Collection with empty Name/Value\n");
645 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attestation: %s\n",
652 tmp_value = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
655 attr_obj = json_object ();
656 json_object_set_new (attr_obj, "value", json_string (tmp_value));
657 json_object_set_new (attr_obj, "name", json_string (attest->name));
658 type = GNUNET_RECLAIM_attestation_number_to_typename (attest->type);
659 json_object_set_new (attr_obj, "type", json_string (type));
660 id_str = GNUNET_STRINGS_data_to_string_alloc (&attest->id,
662 json_object_set_new (attr_obj, "id", json_string (id_str));
663 json_array_append (handle->resp_object, attr_obj);
664 json_decref (attr_obj);
665 GNUNET_free (tmp_value);
666 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
671 * Lists attestation for identity request
673 * @param con_handle the connection handle
675 * @param cls the RequestHandle
678 list_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
682 struct RequestHandle *handle = cls;
683 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
684 struct EgoEntry *ego_entry;
687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
688 "Getting attestations for %s.\n",
690 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
693 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
694 GNUNET_SCHEDULER_add_now (&do_error, handle);
697 identity = handle->url + strlen (
698 GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1;
700 for (ego_entry = handle->ego_head; NULL != ego_entry;
701 ego_entry = ego_entry->next)
702 if (0 == strcmp (identity, ego_entry->identifier))
704 handle->resp_object = json_array ();
707 if (NULL == ego_entry)
710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
711 GNUNET_SCHEDULER_add_now (&return_response, handle);
714 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
715 handle->idp = GNUNET_RECLAIM_connect (cfg);
716 handle->attest_it = GNUNET_RECLAIM_get_attestations_start (handle->idp,
729 * Deletes attestation from an identity
731 * @param con_handle the connection handle
733 * @param cls the RequestHandle
736 delete_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
740 struct RequestHandle *handle = cls;
741 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
742 struct GNUNET_RECLAIM_Attestation attr;
743 struct EgoEntry *ego_entry;
744 char *identity_id_str;
748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attestation.\n");
749 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
752 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
753 GNUNET_SCHEDULER_add_now (&do_error, handle);
757 strdup (handle->url + strlen (
758 GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1);
759 identity = strtok (identity_id_str, "/");
760 id = strtok (NULL, "/");
761 if ((NULL == identity) || (NULL == id))
763 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
764 GNUNET_free (identity_id_str);
765 GNUNET_SCHEDULER_add_now (&do_error, handle);
769 for (ego_entry = handle->ego_head; NULL != ego_entry;
770 ego_entry = ego_entry->next)
771 if (0 == strcmp (identity, ego_entry->identifier))
773 handle->resp_object = json_array ();
774 if (NULL == ego_entry)
777 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
778 GNUNET_free (identity_id_str);
779 GNUNET_SCHEDULER_add_now (&return_response, handle);
782 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
783 handle->idp = GNUNET_RECLAIM_connect (cfg);
784 memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attestation));
785 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
787 handle->idp_op = GNUNET_RECLAIM_attestation_delete (handle->idp,
792 GNUNET_free (identity_id_str);
797 * List tickets for identity request
799 * @param con_handle the connection handle
801 * @param cls the RequestHandle
804 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
808 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
809 struct RequestHandle *handle = cls;
810 struct EgoEntry *ego_entry;
813 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
814 "Getting tickets for %s.\n",
816 if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url))
818 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
819 GNUNET_SCHEDULER_add_now (&do_error, handle);
822 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
824 for (ego_entry = handle->ego_head; NULL != ego_entry;
825 ego_entry = ego_entry->next)
826 if (0 == strcmp (identity, ego_entry->identifier))
828 handle->resp_object = json_array ();
830 if (NULL == ego_entry)
833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
834 GNUNET_SCHEDULER_add_now (&return_response, handle);
837 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
838 handle->idp = GNUNET_RECLAIM_connect (cfg);
840 GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
846 &collect_finished_cb,
852 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
856 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
857 const char *identity;
858 struct RequestHandle *handle = cls;
859 struct EgoEntry *ego_entry;
860 struct GNUNET_RECLAIM_Attribute *attribute;
861 struct GNUNET_TIME_Relative exp;
862 char term_data[handle->rest_handle->data_size + 1];
865 struct GNUNET_JSON_Specification attrspec[] =
866 { GNUNET_RECLAIM_JSON_spec_claim (&attribute), GNUNET_JSON_spec_end () };
868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
869 "Adding an attribute for %s.\n",
871 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
873 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
874 GNUNET_SCHEDULER_add_now (&do_error, handle);
877 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
879 for (ego_entry = handle->ego_head; NULL != ego_entry;
880 ego_entry = ego_entry->next)
881 if (0 == strcmp (identity, ego_entry->identifier))
884 if (NULL == ego_entry)
886 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
889 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
891 if (0 >= handle->rest_handle->data_size)
893 GNUNET_SCHEDULER_add_now (&do_error, handle);
897 term_data[handle->rest_handle->data_size] = '\0';
898 GNUNET_memcpy (term_data,
899 handle->rest_handle->data,
900 handle->rest_handle->data_size);
901 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
902 GNUNET_assert (GNUNET_OK ==
903 GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
904 json_decref (data_json);
905 if (NULL == attribute)
907 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
908 "Unable to parse attribute from %s\n",
910 GNUNET_SCHEDULER_add_now (&do_error, handle);
914 * New ID for attribute
916 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
917 GNUNET_RECLAIM_id_generate (&attribute->id);
918 handle->idp = GNUNET_RECLAIM_connect (cfg);
919 exp = GNUNET_TIME_UNIT_HOURS;
920 handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
926 GNUNET_JSON_parse_free (attrspec);
931 * Parse a JWT and return the respective claim value as Attribute
933 * @param attest the jwt attestation
934 * @param claim the name of the claim in the JWT
936 * @return a GNUNET_RECLAIM_Attribute, containing the new value
938 struct GNUNET_RECLAIM_Attribute *
939 parse_jwt (const struct GNUNET_RECLAIM_Attestation *attest,
943 struct GNUNET_RECLAIM_Attribute *attr;
945 const char *type_str = NULL;
946 const char *val_str = NULL;
950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n");
953 json_error_t *json_err = NULL;
955 jwt_string = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
958 char *jwt_body = strtok (jwt_string, delim);
959 jwt_body = strtok (NULL, delim);
960 GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
961 (void **) &decoded_jwt);
962 json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, json_err);
965 json_object_foreach (json_val, key, value) {
966 if (0 == strcasecmp (key,claim))
968 val_str = json_dumps (value, JSON_ENCODE_ANY);
972 type = GNUNET_RECLAIM_attribute_typename_to_number (type_str);
973 if (GNUNET_SYSERR == GNUNET_RECLAIM_attribute_string_to_value (type,val_str,
977 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
978 "Attribute value from JWT Parser invalid!\n");
979 GNUNET_RECLAIM_attribute_string_to_value (type,
980 "Error: Referenced Claim Name not Found",
983 attr = GNUNET_RECLAIM_attribute_new (claim, &attest->id,
984 type, data, data_size);
985 attr->id = attest->id;
990 attr = GNUNET_RECLAIM_attribute_new (claim, &attest->id,
991 type, data, data_size);
992 attr->id = attest->id;
1000 * Collect all attributes for an ego
1004 attr_collect (void *cls,
1005 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1006 const struct GNUNET_RECLAIM_Attribute *attr)
1008 struct RequestHandle *handle = cls;
1014 tmp_value = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1017 attr_obj = json_object ();
1018 json_object_set_new (attr_obj, "value", json_string (tmp_value));
1019 json_object_set_new (attr_obj, "name", json_string (attr->name));
1021 json_object_set_new (attr_obj, "flag", json_string ("1"));
1022 type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
1023 json_object_set_new (attr_obj, "type", json_string (type));
1024 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id,
1026 json_object_set_new (attr_obj, "id", json_string (id_str));
1027 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->attestation,
1028 sizeof(attr->attestation));
1029 json_object_set_new (attr_obj, "attestation", json_string (id_str));
1030 json_array_append (handle->resp_object, attr_obj);
1031 json_decref (attr_obj);
1032 GNUNET_free (tmp_value);
1033 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1038 * List attributes for identity request
1040 * @param con_handle the connection handle
1041 * @param url the url
1042 * @param cls the RequestHandle
1045 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1049 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1050 struct RequestHandle *handle = cls;
1051 struct EgoEntry *ego_entry;
1054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1055 "Getting attributes for %s.\n",
1057 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1059 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1060 GNUNET_SCHEDULER_add_now (&do_error, handle);
1063 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
1065 for (ego_entry = handle->ego_head; NULL != ego_entry;
1066 ego_entry = ego_entry->next)
1067 if (0 == strcmp (identity, ego_entry->identifier))
1069 handle->resp_object = json_array ();
1072 if (NULL == ego_entry)
1075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1076 GNUNET_SCHEDULER_add_now (&return_response, handle);
1079 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1080 handle->idp = GNUNET_RECLAIM_connect (cfg);
1081 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
1087 &collect_finished_cb,
1093 * List attributes for identity request
1095 * @param con_handle the connection handle
1096 * @param url the url
1097 * @param cls the RequestHandle
1100 delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1104 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1105 struct RequestHandle *handle = cls;
1106 struct GNUNET_RECLAIM_Attribute attr;
1107 struct EgoEntry *ego_entry;
1108 char *identity_id_str;
1112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
1113 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1115 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1116 GNUNET_SCHEDULER_add_now (&do_error, handle);
1120 strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
1121 identity = strtok (identity_id_str, "/");
1122 id = strtok (NULL, "/");
1123 if ((NULL == identity) || (NULL == id))
1125 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
1126 GNUNET_free (identity_id_str);
1127 GNUNET_SCHEDULER_add_now (&do_error, handle);
1131 for (ego_entry = handle->ego_head; NULL != ego_entry;
1132 ego_entry = ego_entry->next)
1133 if (0 == strcmp (identity, ego_entry->identifier))
1135 handle->resp_object = json_array ();
1136 if (NULL == ego_entry)
1139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1140 GNUNET_free (identity_id_str);
1141 GNUNET_SCHEDULER_add_now (&return_response, handle);
1144 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1145 handle->idp = GNUNET_RECLAIM_connect (cfg);
1146 memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attribute));
1147 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
1149 handle->idp_op = GNUNET_RECLAIM_attribute_delete (handle->idp,
1152 &delete_finished_cb,
1154 GNUNET_free (identity_id_str);
1159 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1163 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1164 struct RequestHandle *handle = cls;
1165 struct EgoEntry *ego_entry;
1166 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1167 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1168 char term_data[handle->rest_handle->data_size + 1];
1171 struct GNUNET_JSON_Specification tktspec[] =
1172 { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1174 if (0 >= handle->rest_handle->data_size)
1176 GNUNET_SCHEDULER_add_now (&do_error, handle);
1180 term_data[handle->rest_handle->data_size] = '\0';
1181 GNUNET_memcpy (term_data,
1182 handle->rest_handle->data,
1183 handle->rest_handle->data_size);
1184 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1185 if ((NULL == data_json) ||
1186 (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)))
1188 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1189 GNUNET_SCHEDULER_add_now (&do_error, handle);
1190 GNUNET_JSON_parse_free (tktspec);
1191 if (NULL != data_json)
1192 json_decref (data_json);
1195 json_decref (data_json);
1198 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1199 "Unable to parse ticket from %s\n",
1201 GNUNET_SCHEDULER_add_now (&do_error, handle);
1205 for (ego_entry = handle->ego_head; NULL != ego_entry;
1206 ego_entry = ego_entry->next)
1208 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1209 if (0 == memcmp (&ticket->identity,
1211 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1214 if (NULL == ego_entry)
1216 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1217 GNUNET_JSON_parse_free (tktspec);
1220 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1222 handle->idp = GNUNET_RECLAIM_connect (cfg);
1223 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
1228 GNUNET_JSON_parse_free (tktspec);
1233 consume_cont (void *cls,
1234 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1235 const struct GNUNET_RECLAIM_Attribute *attr,
1236 const struct GNUNET_RECLAIM_Attestation *attest)
1238 struct RequestHandle *handle = cls;
1242 if (NULL == identity)
1244 GNUNET_SCHEDULER_add_now (&return_response, handle);
1248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
1249 val_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1252 if (NULL == val_str)
1254 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1255 "Failed to parse value for: %s\n",
1259 value = json_string (val_str);
1260 json_object_set_new (handle->resp_object, attr->name, value);
1261 json_decref (value);
1262 GNUNET_free (val_str);
1267 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1271 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1272 struct RequestHandle *handle = cls;
1273 struct EgoEntry *ego_entry;
1274 struct GNUNET_RECLAIM_Ticket *ticket;
1275 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1276 char term_data[handle->rest_handle->data_size + 1];
1279 struct GNUNET_JSON_Specification tktspec[] =
1280 { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1282 if (0 >= handle->rest_handle->data_size)
1284 GNUNET_SCHEDULER_add_now (&do_error, handle);
1288 term_data[handle->rest_handle->data_size] = '\0';
1289 GNUNET_memcpy (term_data,
1290 handle->rest_handle->data,
1291 handle->rest_handle->data_size);
1292 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1293 if (NULL == data_json)
1295 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1296 "Unable to parse JSON Object from %s\n",
1298 GNUNET_SCHEDULER_add_now (&do_error, handle);
1301 if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL))
1303 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1304 GNUNET_SCHEDULER_add_now (&do_error, handle);
1305 GNUNET_JSON_parse_free (tktspec);
1306 json_decref (data_json);
1309 for (ego_entry = handle->ego_head; NULL != ego_entry;
1310 ego_entry = ego_entry->next)
1312 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1313 if (0 == memcmp (&ticket->audience,
1315 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1318 if (NULL == ego_entry)
1320 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1321 GNUNET_JSON_parse_free (tktspec);
1324 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1325 handle->resp_object = json_object ();
1326 handle->idp = GNUNET_RECLAIM_connect (cfg);
1327 handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
1332 GNUNET_JSON_parse_free (tktspec);
1337 * Respond to OPTIONS request
1339 * @param con_handle the connection handle
1340 * @param url the url
1341 * @param cls the RequestHandle
1344 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1348 struct MHD_Response *resp;
1349 struct RequestHandle *handle = cls;
1351 // For now, independent of path return all options
1352 resp = GNUNET_REST_create_response (NULL);
1353 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1354 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1355 cleanup_handle (handle);
1361 * Handle rest request
1363 * @param handle the request handle
1366 init_cont (struct RequestHandle *handle)
1368 struct GNUNET_REST_RequestHandlerError err;
1369 static const struct GNUNET_REST_RequestHandler handlers[] =
1370 { { MHD_HTTP_METHOD_GET,
1371 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1372 &list_attribute_cont },
1373 { MHD_HTTP_METHOD_POST,
1374 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1375 &add_attribute_cont },
1376 { MHD_HTTP_METHOD_DELETE,
1377 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1378 &delete_attribute_cont },
1379 { MHD_HTTP_METHOD_GET,
1380 GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1381 &list_attestation_cont },
1382 { MHD_HTTP_METHOD_POST,
1383 GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1384 &add_attestation_cont },
1385 { MHD_HTTP_METHOD_DELETE,
1386 GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1387 &delete_attestation_cont },
1388 { MHD_HTTP_METHOD_GET,
1389 GNUNET_REST_API_NS_IDENTITY_TICKETS,
1390 &list_tickets_cont },
1391 { MHD_HTTP_METHOD_POST,
1392 GNUNET_REST_API_NS_IDENTITY_REVOKE,
1393 &revoke_ticket_cont },
1394 { MHD_HTTP_METHOD_POST,
1395 GNUNET_REST_API_NS_IDENTITY_CONSUME,
1396 &consume_ticket_cont },
1397 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont },
1398 GNUNET_REST_HANDLER_END };
1401 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1403 handle->response_code = err.error_code;
1404 GNUNET_SCHEDULER_add_now (&do_error, handle);
1410 * If listing is enabled, prints information about the egos.
1412 * This function is initially called for all egos and then again
1413 * whenever a ego's identifier changes or if it is deleted. At the
1414 * end of the initial pass over all egos, the function is once called
1415 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1416 * be invoked in the future or that there was an error.
1418 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1419 * this function is only called ONCE, and 'NULL' being passed in
1420 * 'ego' does indicate an error (i.e. name is taken or no default
1421 * value is known). If 'ego' is non-NULL and if '*ctx'
1422 * is set in those callbacks, the value WILL be passed to a subsequent
1423 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1424 * that one was not NULL).
1426 * When an identity is renamed, this function is called with the
1427 * (known) ego but the NEW identifier.
1429 * When an identity is deleted, this function is called with the
1430 * (known) ego and "NULL" for the 'identifier'. In this case,
1431 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1434 * @param cls closure
1435 * @param ego ego handle
1436 * @param ctx context for application to store data for this ego
1437 * (during the lifetime of this process, initially NULL)
1438 * @param identifier identifier assigned by the user for this ego,
1439 * NULL if the user just deleted the ego and it
1440 * must thus no longer be used
1443 list_ego (void *cls,
1444 struct GNUNET_IDENTITY_Ego *ego,
1446 const char *identifier)
1448 struct RequestHandle *handle = cls;
1449 struct EgoEntry *ego_entry;
1450 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1452 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1454 handle->state = ID_REST_STATE_POST_INIT;
1458 if (ID_REST_STATE_INIT == handle->state)
1460 ego_entry = GNUNET_new (struct EgoEntry);
1461 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1462 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1463 ego_entry->ego = ego;
1464 ego_entry->identifier = GNUNET_strdup (identifier);
1465 GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1473 rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1474 GNUNET_REST_ResultProcessor proc,
1477 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1479 handle->response_code = 0;
1480 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1481 handle->proc_cls = proc_cls;
1482 handle->proc = proc;
1483 handle->state = ID_REST_STATE_INIT;
1484 handle->rest_handle = rest_handle;
1486 handle->url = GNUNET_strdup (rest_handle->url);
1487 if (handle->url[strlen (handle->url) - 1] == '/')
1488 handle->url[strlen (handle->url) - 1] = '\0';
1489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1490 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
1491 handle->timeout_task =
1492 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
1493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1498 * Entry point for the plugin.
1500 * @param cls Config info
1501 * @return NULL on error, otherwise the plugin context
1504 libgnunet_plugin_rest_reclaim_init (void *cls)
1506 static struct Plugin plugin;
1507 struct GNUNET_REST_Plugin *api;
1510 if (NULL != plugin.cfg)
1511 return NULL; /* can only initialize once! */
1512 memset (&plugin, 0, sizeof(struct Plugin));
1514 api = GNUNET_new (struct GNUNET_REST_Plugin);
1516 api->name = GNUNET_REST_API_NS_RECLAIM;
1517 api->process_request = &rest_identity_process_request;
1518 GNUNET_asprintf (&allow_methods,
1519 "%s, %s, %s, %s, %s",
1520 MHD_HTTP_METHOD_GET,
1521 MHD_HTTP_METHOD_POST,
1522 MHD_HTTP_METHOD_PUT,
1523 MHD_HTTP_METHOD_DELETE,
1524 MHD_HTTP_METHOD_OPTIONS);
1526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1527 _ ("Identity Provider REST API initialized\n"));
1533 * Exit point from the plugin.
1535 * @param cls the plugin context (as returned by "init")
1536 * @return always NULL
1539 libgnunet_plugin_rest_reclaim_done (void *cls)
1541 struct GNUNET_REST_Plugin *api = cls;
1542 struct Plugin *plugin = api->cls;
1546 GNUNET_free_non_null (allow_methods);
1548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1549 "Identity Provider REST plugin is finished\n");
1554 /* end of plugin_rest_reclaim.c */