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)
624 struct RequestHandle *handle = cls;
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634 "Attestation Collection with empty Attestation\n");
635 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
639 if ((NULL == attest->name) || (NULL == attest->data))
641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
642 "Attestation Collection with empty Name/Value\n");
643 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
647 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attestation: %s\n",
650 tmp_value = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
653 attr_obj = json_object ();
654 json_object_set_new (attr_obj, "value", json_string (tmp_value));
655 json_object_set_new (attr_obj, "name", json_string (attest->name));
656 type = GNUNET_RECLAIM_attestation_number_to_typename (attest->type);
657 json_object_set_new (attr_obj, "type", json_string (type));
658 id_str = GNUNET_STRINGS_data_to_string_alloc (&attest->id,
660 json_object_set_new (attr_obj, "id", json_string (id_str));
661 json_array_append (handle->resp_object, attr_obj);
662 json_decref (attr_obj);
663 GNUNET_free (tmp_value);
664 GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
669 * Lists attestation for identity request
671 * @param con_handle the connection handle
673 * @param cls the RequestHandle
676 list_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
680 struct RequestHandle *handle = cls;
681 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
682 struct EgoEntry *ego_entry;
685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
686 "Getting attestations for %s.\n",
688 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
691 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
692 GNUNET_SCHEDULER_add_now (&do_error, handle);
695 identity = handle->url + strlen (
696 GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1;
698 for (ego_entry = handle->ego_head; NULL != ego_entry;
699 ego_entry = ego_entry->next)
700 if (0 == strcmp (identity, ego_entry->identifier))
702 handle->resp_object = json_array ();
705 if (NULL == ego_entry)
708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
709 GNUNET_SCHEDULER_add_now (&return_response, handle);
712 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
713 handle->idp = GNUNET_RECLAIM_connect (cfg);
714 handle->attest_it = GNUNET_RECLAIM_get_attestations_start (handle->idp,
727 * Deletes attestation from an identity
729 * @param con_handle the connection handle
731 * @param cls the RequestHandle
734 delete_attestation_cont (struct GNUNET_REST_RequestHandle *con_handle,
738 struct RequestHandle *handle = cls;
739 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
740 struct GNUNET_RECLAIM_Attestation attr;
741 struct EgoEntry *ego_entry;
742 char *identity_id_str;
746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attestation.\n");
747 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTESTATION) >= strlen (
750 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
751 GNUNET_SCHEDULER_add_now (&do_error, handle);
755 strdup (handle->url + strlen (
756 GNUNET_REST_API_NS_RECLAIM_ATTESTATION) + 1);
757 identity = strtok (identity_id_str, "/");
758 id = strtok (NULL, "/");
759 if ((NULL == identity) || (NULL == id))
761 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
762 GNUNET_free (identity_id_str);
763 GNUNET_SCHEDULER_add_now (&do_error, handle);
767 for (ego_entry = handle->ego_head; NULL != ego_entry;
768 ego_entry = ego_entry->next)
769 if (0 == strcmp (identity, ego_entry->identifier))
771 handle->resp_object = json_array ();
772 if (NULL == ego_entry)
775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
776 GNUNET_free (identity_id_str);
777 GNUNET_SCHEDULER_add_now (&return_response, handle);
780 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
781 handle->idp = GNUNET_RECLAIM_connect (cfg);
782 memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attestation));
783 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
785 handle->idp_op = GNUNET_RECLAIM_attestation_delete (handle->idp,
790 GNUNET_free (identity_id_str);
795 * List tickets for identity request
797 * @param con_handle the connection handle
799 * @param cls the RequestHandle
802 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
806 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
807 struct RequestHandle *handle = cls;
808 struct EgoEntry *ego_entry;
811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
812 "Getting tickets for %s.\n",
814 if (strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= strlen (handle->url))
816 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
817 GNUNET_SCHEDULER_add_now (&do_error, handle);
820 identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
822 for (ego_entry = handle->ego_head; NULL != ego_entry;
823 ego_entry = ego_entry->next)
824 if (0 == strcmp (identity, ego_entry->identifier))
826 handle->resp_object = json_array ();
828 if (NULL == ego_entry)
831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
832 GNUNET_SCHEDULER_add_now (&return_response, handle);
835 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
836 handle->idp = GNUNET_RECLAIM_connect (cfg);
838 GNUNET_RECLAIM_ticket_iteration_start (handle->idp,
844 &collect_finished_cb,
850 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
854 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
855 const char *identity;
856 struct RequestHandle *handle = cls;
857 struct EgoEntry *ego_entry;
858 struct GNUNET_RECLAIM_Attribute *attribute;
859 struct GNUNET_TIME_Relative exp;
860 char term_data[handle->rest_handle->data_size + 1];
863 struct GNUNET_JSON_Specification attrspec[] =
864 { GNUNET_RECLAIM_JSON_spec_claim (&attribute), GNUNET_JSON_spec_end () };
866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
867 "Adding an attribute for %s.\n",
869 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
871 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
872 GNUNET_SCHEDULER_add_now (&do_error, handle);
875 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
877 for (ego_entry = handle->ego_head; NULL != ego_entry;
878 ego_entry = ego_entry->next)
879 if (0 == strcmp (identity, ego_entry->identifier))
882 if (NULL == ego_entry)
884 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown (%s)\n", identity);
887 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
889 if (0 >= handle->rest_handle->data_size)
891 GNUNET_SCHEDULER_add_now (&do_error, handle);
895 term_data[handle->rest_handle->data_size] = '\0';
896 GNUNET_memcpy (term_data,
897 handle->rest_handle->data,
898 handle->rest_handle->data_size);
899 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
900 GNUNET_assert (GNUNET_OK ==
901 GNUNET_JSON_parse (data_json, attrspec, NULL, NULL));
902 json_decref (data_json);
903 if (NULL == attribute)
905 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
906 "Unable to parse attribute from %s\n",
908 GNUNET_SCHEDULER_add_now (&do_error, handle);
912 * New ID for attribute
914 if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attribute->id))
915 GNUNET_RECLAIM_id_generate (&attribute->id);
916 handle->idp = GNUNET_RECLAIM_connect (cfg);
917 exp = GNUNET_TIME_UNIT_HOURS;
918 handle->idp_op = GNUNET_RECLAIM_attribute_store (handle->idp,
924 GNUNET_JSON_parse_free (attrspec);
929 * Parse a JWT and return the respective claim value as Attribute
931 * @param attest the jwt attestation
932 * @param claim the name of the claim in the JWT
934 * @return a GNUNET_RECLAIM_Attribute, containing the new value
936 struct GNUNET_RECLAIM_Attribute *
937 parse_jwt (const struct GNUNET_RECLAIM_Attestation *attest,
941 struct GNUNET_RECLAIM_Attribute *attr;
943 const char *type_str = NULL;
944 const char *val_str = NULL;
948 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing JWT attributes.\n");
951 json_error_t *json_err = NULL;
953 jwt_string = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
956 char *jwt_body = strtok (jwt_string, delim);
957 jwt_body = strtok (NULL, delim);
958 GNUNET_STRINGS_base64_decode (jwt_body, strlen (jwt_body),
959 (void **) &decoded_jwt);
960 json_val = json_loads (decoded_jwt, JSON_DECODE_ANY, json_err);
963 json_object_foreach (json_val, key, value) {
964 if (0 == strcasecmp (key,claim))
966 val_str = json_dumps (value, JSON_ENCODE_ANY);
970 type = GNUNET_RECLAIM_attribute_typename_to_number (type_str);
971 if (GNUNET_SYSERR == GNUNET_RECLAIM_attribute_string_to_value (type,val_str,
975 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
976 "Attribute value from JWT Parser invalid!\n");
977 GNUNET_RECLAIM_attribute_string_to_value (type,
978 "Error: Referenced Claim Name not Found",
981 attr = GNUNET_RECLAIM_attribute_new (claim, &attest->id,
982 type, data, data_size);
983 attr->id = attest->id;
988 attr = GNUNET_RECLAIM_attribute_new (claim, &attest->id,
989 type, data, data_size);
990 attr->id = attest->id;
998 * Collect all attributes for an ego
1002 attr_collect (void *cls,
1003 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1004 const struct GNUNET_RECLAIM_Attribute *attr)
1006 struct RequestHandle *handle = cls;
1012 tmp_value = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1015 attr_obj = json_object ();
1016 json_object_set_new (attr_obj, "value", json_string (tmp_value));
1017 json_object_set_new (attr_obj, "name", json_string (attr->name));
1019 json_object_set_new (attr_obj, "flag", json_string ("1"));
1020 type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
1021 json_object_set_new (attr_obj, "type", json_string (type));
1022 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->id,
1024 json_object_set_new (attr_obj, "id", json_string (id_str));
1025 id_str = GNUNET_STRINGS_data_to_string_alloc (&attr->attestation,
1026 sizeof(attr->attestation));
1027 json_object_set_new (attr_obj, "attestation", json_string (id_str));
1028 json_array_append (handle->resp_object, attr_obj);
1029 json_decref (attr_obj);
1030 GNUNET_free (tmp_value);
1035 * List attributes for identity request
1037 * @param con_handle the connection handle
1038 * @param url the url
1039 * @param cls the RequestHandle
1042 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1046 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1047 struct RequestHandle *handle = cls;
1048 struct EgoEntry *ego_entry;
1051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1052 "Getting attributes for %s.\n",
1054 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1056 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1057 GNUNET_SCHEDULER_add_now (&do_error, handle);
1060 identity = handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1;
1062 for (ego_entry = handle->ego_head; NULL != ego_entry;
1063 ego_entry = ego_entry->next)
1064 if (0 == strcmp (identity, ego_entry->identifier))
1066 handle->resp_object = json_array ();
1069 if (NULL == ego_entry)
1072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1073 GNUNET_SCHEDULER_add_now (&return_response, handle);
1076 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1077 handle->idp = GNUNET_RECLAIM_connect (cfg);
1078 handle->attr_it = GNUNET_RECLAIM_get_attributes_start (handle->idp,
1084 &collect_finished_cb,
1090 * List attributes for identity request
1092 * @param con_handle the connection handle
1093 * @param url the url
1094 * @param cls the RequestHandle
1097 delete_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
1101 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1102 struct RequestHandle *handle = cls;
1103 struct GNUNET_RECLAIM_Attribute attr;
1104 struct EgoEntry *ego_entry;
1105 char *identity_id_str;
1109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting attributes.\n");
1110 if (strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) >= strlen (handle->url))
1112 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
1113 GNUNET_SCHEDULER_add_now (&do_error, handle);
1117 strdup (handle->url + strlen (GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES) + 1);
1118 identity = strtok (identity_id_str, "/");
1119 id = strtok (NULL, "/");
1120 if ((NULL == identity) || (NULL == id))
1122 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed request.\n");
1123 GNUNET_free (identity_id_str);
1124 GNUNET_SCHEDULER_add_now (&do_error, handle);
1128 for (ego_entry = handle->ego_head; NULL != ego_entry;
1129 ego_entry = ego_entry->next)
1130 if (0 == strcmp (identity, ego_entry->identifier))
1132 handle->resp_object = json_array ();
1133 if (NULL == ego_entry)
1136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", identity);
1137 GNUNET_free (identity_id_str);
1138 GNUNET_SCHEDULER_add_now (&return_response, handle);
1141 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1142 handle->idp = GNUNET_RECLAIM_connect (cfg);
1143 memset (&attr, 0, sizeof(struct GNUNET_RECLAIM_Attribute));
1144 GNUNET_STRINGS_string_to_data (id, strlen (id), &attr.id, sizeof(attr.id));
1146 handle->idp_op = GNUNET_RECLAIM_attribute_delete (handle->idp,
1149 &delete_finished_cb,
1151 GNUNET_free (identity_id_str);
1156 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1160 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1161 struct RequestHandle *handle = cls;
1162 struct EgoEntry *ego_entry;
1163 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1164 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1165 char term_data[handle->rest_handle->data_size + 1];
1168 struct GNUNET_JSON_Specification tktspec[] =
1169 { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1171 if (0 >= handle->rest_handle->data_size)
1173 GNUNET_SCHEDULER_add_now (&do_error, handle);
1177 term_data[handle->rest_handle->data_size] = '\0';
1178 GNUNET_memcpy (term_data,
1179 handle->rest_handle->data,
1180 handle->rest_handle->data_size);
1181 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1182 if ((NULL == data_json) ||
1183 (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL)))
1185 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1186 GNUNET_SCHEDULER_add_now (&do_error, handle);
1187 GNUNET_JSON_parse_free (tktspec);
1188 if (NULL != data_json)
1189 json_decref (data_json);
1192 json_decref (data_json);
1195 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1196 "Unable to parse ticket from %s\n",
1198 GNUNET_SCHEDULER_add_now (&do_error, handle);
1202 for (ego_entry = handle->ego_head; NULL != ego_entry;
1203 ego_entry = ego_entry->next)
1205 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1206 if (0 == memcmp (&ticket->identity,
1208 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1211 if (NULL == ego_entry)
1213 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1214 GNUNET_JSON_parse_free (tktspec);
1217 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1219 handle->idp = GNUNET_RECLAIM_connect (cfg);
1220 handle->idp_op = GNUNET_RECLAIM_ticket_revoke (handle->idp,
1225 GNUNET_JSON_parse_free (tktspec);
1230 consume_cont (void *cls,
1231 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1232 const struct GNUNET_RECLAIM_Attribute *attr,
1233 const struct GNUNET_RECLAIM_Attestation *attest)
1235 struct RequestHandle *handle = cls;
1239 if (NULL == identity)
1241 GNUNET_SCHEDULER_add_now (&return_response, handle);
1245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", attr->name);
1246 val_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
1249 if (NULL == val_str)
1251 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1252 "Failed to parse value for: %s\n",
1256 value = json_string (val_str);
1257 json_object_set_new (handle->resp_object, attr->name, value);
1258 json_decref (value);
1259 GNUNET_free (val_str);
1264 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1268 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1269 struct RequestHandle *handle = cls;
1270 struct EgoEntry *ego_entry;
1271 struct GNUNET_RECLAIM_Ticket *ticket;
1272 struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1273 char term_data[handle->rest_handle->data_size + 1];
1276 struct GNUNET_JSON_Specification tktspec[] =
1277 { GNUNET_RECLAIM_JSON_spec_ticket (&ticket), GNUNET_JSON_spec_end () };
1279 if (0 >= handle->rest_handle->data_size)
1281 GNUNET_SCHEDULER_add_now (&do_error, handle);
1285 term_data[handle->rest_handle->data_size] = '\0';
1286 GNUNET_memcpy (term_data,
1287 handle->rest_handle->data,
1288 handle->rest_handle->data_size);
1289 data_json = json_loads (term_data, JSON_DECODE_ANY, &err);
1290 if (NULL == data_json)
1292 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1293 "Unable to parse JSON Object from %s\n",
1295 GNUNET_SCHEDULER_add_now (&do_error, handle);
1298 if (GNUNET_OK != GNUNET_JSON_parse (data_json, tktspec, NULL, NULL))
1300 handle->emsg = GNUNET_strdup ("Not a ticket!\n");
1301 GNUNET_SCHEDULER_add_now (&do_error, handle);
1302 GNUNET_JSON_parse_free (tktspec);
1303 json_decref (data_json);
1306 for (ego_entry = handle->ego_head; NULL != ego_entry;
1307 ego_entry = ego_entry->next)
1309 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &tmp_pk);
1310 if (0 == memcmp (&ticket->audience,
1312 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1315 if (NULL == ego_entry)
1317 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Identity unknown\n");
1318 GNUNET_JSON_parse_free (tktspec);
1321 identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1322 handle->resp_object = json_object ();
1323 handle->idp = GNUNET_RECLAIM_connect (cfg);
1324 handle->idp_op = GNUNET_RECLAIM_ticket_consume (handle->idp,
1329 GNUNET_JSON_parse_free (tktspec);
1334 * Respond to OPTIONS request
1336 * @param con_handle the connection handle
1337 * @param url the url
1338 * @param cls the RequestHandle
1341 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1345 struct MHD_Response *resp;
1346 struct RequestHandle *handle = cls;
1348 // For now, independent of path return all options
1349 resp = GNUNET_REST_create_response (NULL);
1350 MHD_add_response_header (resp, "Access-Control-Allow-Methods", allow_methods);
1351 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1352 cleanup_handle (handle);
1358 * Handle rest request
1360 * @param handle the request handle
1363 init_cont (struct RequestHandle *handle)
1365 struct GNUNET_REST_RequestHandlerError err;
1366 static const struct GNUNET_REST_RequestHandler handlers[] =
1367 { { MHD_HTTP_METHOD_GET,
1368 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1369 &list_attribute_cont },
1370 { MHD_HTTP_METHOD_POST,
1371 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1372 &add_attribute_cont },
1373 { MHD_HTTP_METHOD_DELETE,
1374 GNUNET_REST_API_NS_RECLAIM_ATTRIBUTES,
1375 &delete_attribute_cont },
1376 { MHD_HTTP_METHOD_GET,
1377 GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1378 &list_attestation_cont },
1379 { MHD_HTTP_METHOD_POST,
1380 GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1381 &add_attestation_cont },
1382 { MHD_HTTP_METHOD_DELETE,
1383 GNUNET_REST_API_NS_RECLAIM_ATTESTATION,
1384 &delete_attestation_cont },
1385 { MHD_HTTP_METHOD_GET,
1386 GNUNET_REST_API_NS_IDENTITY_TICKETS,
1387 &list_tickets_cont },
1388 { MHD_HTTP_METHOD_POST,
1389 GNUNET_REST_API_NS_IDENTITY_REVOKE,
1390 &revoke_ticket_cont },
1391 { MHD_HTTP_METHOD_POST,
1392 GNUNET_REST_API_NS_IDENTITY_CONSUME,
1393 &consume_ticket_cont },
1394 { MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_RECLAIM, &options_cont },
1395 GNUNET_REST_HANDLER_END };
1398 GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle))
1400 handle->response_code = err.error_code;
1401 GNUNET_SCHEDULER_add_now (&do_error, handle);
1407 * If listing is enabled, prints information about the egos.
1409 * This function is initially called for all egos and then again
1410 * whenever a ego's identifier changes or if it is deleted. At the
1411 * end of the initial pass over all egos, the function is once called
1412 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1413 * be invoked in the future or that there was an error.
1415 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1416 * this function is only called ONCE, and 'NULL' being passed in
1417 * 'ego' does indicate an error (i.e. name is taken or no default
1418 * value is known). If 'ego' is non-NULL and if '*ctx'
1419 * is set in those callbacks, the value WILL be passed to a subsequent
1420 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1421 * that one was not NULL).
1423 * When an identity is renamed, this function is called with the
1424 * (known) ego but the NEW identifier.
1426 * When an identity is deleted, this function is called with the
1427 * (known) ego and "NULL" for the 'identifier'. In this case,
1428 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1431 * @param cls closure
1432 * @param ego ego handle
1433 * @param ctx context for application to store data for this ego
1434 * (during the lifetime of this process, initially NULL)
1435 * @param identifier identifier assigned by the user for this ego,
1436 * NULL if the user just deleted the ego and it
1437 * must thus no longer be used
1440 list_ego (void *cls,
1441 struct GNUNET_IDENTITY_Ego *ego,
1443 const char *identifier)
1445 struct RequestHandle *handle = cls;
1446 struct EgoEntry *ego_entry;
1447 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1449 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1451 handle->state = ID_REST_STATE_POST_INIT;
1455 if (ID_REST_STATE_INIT == handle->state)
1457 ego_entry = GNUNET_new (struct EgoEntry);
1458 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1459 ego_entry->keystring = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1460 ego_entry->ego = ego;
1461 ego_entry->identifier = GNUNET_strdup (identifier);
1462 GNUNET_CONTAINER_DLL_insert_tail (handle->ego_head,
1470 rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
1471 GNUNET_REST_ResultProcessor proc,
1474 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1476 handle->response_code = 0;
1477 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1478 handle->proc_cls = proc_cls;
1479 handle->proc = proc;
1480 handle->state = ID_REST_STATE_INIT;
1481 handle->rest_handle = rest_handle;
1483 handle->url = GNUNET_strdup (rest_handle->url);
1484 if (handle->url[strlen (handle->url) - 1] == '/')
1485 handle->url[strlen (handle->url) - 1] = '\0';
1486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting...\n");
1487 handle->identity_handle = GNUNET_IDENTITY_connect (cfg, &list_ego, handle);
1488 handle->timeout_task =
1489 GNUNET_SCHEDULER_add_delayed (handle->timeout, &do_timeout, handle);
1490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected\n");
1495 * Entry point for the plugin.
1497 * @param cls Config info
1498 * @return NULL on error, otherwise the plugin context
1501 libgnunet_plugin_rest_reclaim_init (void *cls)
1503 static struct Plugin plugin;
1504 struct GNUNET_REST_Plugin *api;
1507 if (NULL != plugin.cfg)
1508 return NULL; /* can only initialize once! */
1509 memset (&plugin, 0, sizeof(struct Plugin));
1511 api = GNUNET_new (struct GNUNET_REST_Plugin);
1513 api->name = GNUNET_REST_API_NS_RECLAIM;
1514 api->process_request = &rest_identity_process_request;
1515 GNUNET_asprintf (&allow_methods,
1516 "%s, %s, %s, %s, %s",
1517 MHD_HTTP_METHOD_GET,
1518 MHD_HTTP_METHOD_POST,
1519 MHD_HTTP_METHOD_PUT,
1520 MHD_HTTP_METHOD_DELETE,
1521 MHD_HTTP_METHOD_OPTIONS);
1523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1524 _ ("Identity Provider REST API initialized\n"));
1530 * Exit point from the plugin.
1532 * @param cls the plugin context (as returned by "init")
1533 * @return always NULL
1536 libgnunet_plugin_rest_reclaim_done (void *cls)
1538 struct GNUNET_REST_Plugin *api = cls;
1539 struct Plugin *plugin = api->cls;
1543 GNUNET_free_non_null (allow_methods);
1545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1546 "Identity Provider REST plugin is finished\n");
1551 /* end of plugin_rest_reclaim.c */