2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 * @author Martin Schanzenbach
22 * @file identity/plugin_rest_identity.c
23 * @brief GNUnet Namestore REST plugin
28 #include "gnunet_rest_plugin.h"
29 #include "gnunet_identity_service.h"
30 #include "gnunet_gnsrecord_lib.h"
31 #include "gnunet_namestore_service.h"
32 #include "gnunet_rest_lib.h"
33 #include "microhttpd.h"
35 #include "gnunet_signatures.h"
40 #define GNUNET_REST_API_NS_IDENTITY_TOKEN "/token"
45 #define GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE "/token/issue"
50 #define GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK "/token/check"
54 * State while collecting all egos
56 #define ID_REST_STATE_INIT 0
59 * Done collecting egos
61 #define ID_REST_STATE_POST_INIT 1
66 #define GNUNET_REST_JSONAPI_IDENTITY_TOKEN "token"
69 * URL parameter to create a GNUid token for a specific audience
71 #define GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST "audience"
74 * URL parameter to create a GNUid token for a specific issuer (EGO)
76 #define GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST "issuer"
79 * Attributes passed to issue request
81 #define GNUNET_IDENTITY_TOKEN_ATTR_LIST "requested_attrs"
84 * Token expiration string
86 #define GNUNET_IDENTITY_TOKEN_EXP_STRING "expiration"
89 * Renew token w/ relative expirations
91 #define GNUNET_IDENTITY_TOKEN_RENEW_TOKEN "renew_token"
96 #define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
97 #define GNUNET_REST_ERROR_NO_DATA "No data"
100 * GNUid token lifetime
102 #define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
105 * The configuration handle
107 const struct GNUNET_CONFIGURATION_Handle *cfg;
110 * HTTP methods allows for this plugin
112 static char* allow_methods;
115 * @brief struct returned by the initialization function of the plugin
119 const struct GNUNET_CONFIGURATION_Handle *cfg;
130 struct EgoEntry *next;
135 struct EgoEntry *prev;
150 struct GNUNET_IDENTITY_Ego *ego;
159 struct EgoEntry *ego_head;
164 struct EgoEntry *ego_tail;
169 struct EgoEntry *ego_entry;
172 * Handle to the rest connection
174 struct RestConnectionDataHandle *conndata_handle;
177 * The processing state
182 * Handle to Identity service.
184 struct GNUNET_IDENTITY_Handle *identity_handle;
189 struct GNUNET_IDENTITY_Operation *op;
192 * Handle to NS service
194 struct GNUNET_NAMESTORE_Handle *ns_handle;
199 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
204 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
207 * Desired timeout for the lookup (default is no timeout).
209 struct GNUNET_TIME_Relative timeout;
212 * ID of a task associated with the resolution process.
214 struct GNUNET_SCHEDULER_Task * timeout_task;
217 * The plugin result processor
219 GNUNET_REST_ResultProcessor proc;
222 * The closure of the result processor
227 * The name to look up
237 * The data from the REST request
242 * the length of the REST data
252 * Error response message
269 struct JsonApiObject *resp_object;
272 * ID Attribute list given
274 struct GNUNET_CONTAINER_MultiHashMap *attr_map;
281 * Cleanup lookup handle
282 * @param handle Handle to clean up
285 cleanup_handle (struct RequestHandle *handle)
287 struct EgoEntry *ego_entry;
288 struct EgoEntry *ego_tmp;
289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
291 if (NULL != handle->resp_object)
292 GNUNET_REST_jsonapi_object_delete (handle->resp_object);
293 if (NULL != handle->name)
294 GNUNET_free (handle->name);
295 if (NULL != handle->timeout_task)
296 GNUNET_SCHEDULER_cancel (handle->timeout_task);
297 if (NULL != handle->identity_handle)
298 GNUNET_IDENTITY_disconnect (handle->identity_handle);
299 if (NULL != handle->ns_it)
300 GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it);
301 if (NULL != handle->ns_qe)
302 GNUNET_NAMESTORE_cancel (handle->ns_qe);
303 if (NULL != handle->ns_handle)
304 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
305 if (NULL != handle->attr_map)
306 GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
308 if (NULL != handle->url)
309 GNUNET_free (handle->url);
310 if (NULL != handle->emsg)
311 GNUNET_free (handle->emsg);
312 for (ego_entry = handle->ego_head;
316 ego_entry = ego_entry->next;
317 GNUNET_free (ego_tmp->identifier);
318 GNUNET_free (ego_tmp->keystring);
319 GNUNET_free (ego_tmp);
321 GNUNET_free (handle);
326 * Task run on shutdown. Cleans up everything.
329 * @param tc scheduler context
333 const struct GNUNET_SCHEDULER_TaskContext *tc)
335 struct RequestHandle *handle = cls;
336 struct MHD_Response *resp;
339 GNUNET_asprintf (&json_error,
340 "{Error while processing request: %s}",
343 resp = GNUNET_REST_create_json_response (json_error);
344 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
345 cleanup_handle (handle);
346 GNUNET_free (json_error);
350 * Task run on shutdown. Cleans up everything.
353 * @param tc scheduler context
356 do_cleanup_handle_delayed (void *cls,
357 const struct GNUNET_SCHEDULER_TaskContext *tc)
359 struct RequestHandle *handle = cls;
360 cleanup_handle(handle);
364 store_token_cont (void *cls,
369 struct MHD_Response *resp;
370 struct RequestHandle *handle = cls;
372 handle->ns_qe = NULL;
373 if (GNUNET_SYSERR == success)
375 handle->emsg = GNUNET_strdup (emsg);
376 GNUNET_SCHEDULER_add_now (&do_error, handle);
379 GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
381 resp = GNUNET_REST_create_json_response (result_str);
382 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
383 GNUNET_free (result_str);
384 GNUNET_SCHEDULER_add_now (&do_cleanup_handle_delayed, handle);
389 * Build a GNUid token for identity
390 * @param handle the handle
391 * @param ego_entry the ego to build the token for
392 * @param name name of the ego
393 * @param token_aud token audience
394 * @param token the resulting gnuid token
395 * @return identifier string of token (label)
398 sign_and_return_token (void *cls,
399 const struct GNUNET_SCHEDULER_TaskContext *tc)
404 char *payload_base64;
415 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
416 struct GNUNET_CRYPTO_EcdsaSignature sig;
417 struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
418 struct JsonApiResource *json_resource;
419 struct RequestHandle *handle = cls;
420 struct GNUNET_GNSRECORD_Data token_record;
421 struct GNUNET_HashCode key;
422 struct GNUNET_TIME_Relative etime_rel;
423 int renew_token = GNUNET_NO;
425 time = GNUNET_TIME_absolute_get().abs_value_us;
426 lbl = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
427 GNUNET_STRINGS_base64_encode ((char*)&lbl, sizeof (uint64_t), &lbl_str);
429 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_EXP_STRING,
430 strlen (GNUNET_IDENTITY_TOKEN_EXP_STRING),
433 //Get expiration for token from URL parameter
435 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
438 exp_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
442 if (NULL == exp_str) {
443 handle->emsg = GNUNET_strdup ("No expiration given!\n");
444 GNUNET_SCHEDULER_add_now (&do_error, handle);
449 GNUNET_STRINGS_fancy_time_to_relative (exp_str,
452 handle->emsg = GNUNET_strdup ("Expiration invalid!\n");
453 GNUNET_SCHEDULER_add_now (&do_error, handle);
456 exp_time = time + etime_rel.rel_value_us;
458 //Get renewal policy for token
459 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_RENEW_TOKEN,
460 strlen (GNUNET_IDENTITY_TOKEN_RENEW_TOKEN),
464 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
467 renew_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
469 if (0 == strcmp (renew_str, "true"))
470 renew_token = GNUNET_YES;
473 //json_object_set_new (handle->payload, "lbl", json_string (lbl_str));
474 json_object_set_new (handle->payload, "sub", json_string (handle->ego_entry->identifier));
475 json_object_set_new (handle->payload, "nbf", json_integer (time));
476 json_object_set_new (handle->payload, "iat", json_integer (time));
477 json_object_set_new (handle->payload, "exp", json_integer (exp_time));
478 if (GNUNET_YES == renew_token)
480 json_object_set_new (handle->payload, "rnl", json_string ("yes"));
483 header_str = json_dumps (handle->header, JSON_COMPACT);
484 GNUNET_STRINGS_base64_encode (header_str,
487 char* padding = strtok(header_base64, "=");
488 while (NULL != padding)
489 padding = strtok(NULL, "=");
491 payload_str = json_dumps (handle->payload, JSON_COMPACT);
492 GNUNET_STRINGS_base64_encode (payload_str,
493 strlen (payload_str),
495 padding = strtok(payload_base64, "=");
496 while (NULL != padding)
497 padding = strtok(NULL, "=");
499 GNUNET_asprintf (&token, "%s,%s", header_base64, payload_base64);
500 priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
502 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
505 htonl (strlen (token) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose));
506 purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN);
507 memcpy (&purpose[1], token, strlen (token));
508 if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key,
513 sig_str = GNUNET_STRINGS_data_to_string_alloc (&sig,
514 sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
515 GNUNET_asprintf (&token, "%s.%s.%s",
516 header_base64, payload_base64, sig_str);
517 GNUNET_free (sig_str);
518 GNUNET_free (header_str);
519 GNUNET_free (header_base64);
520 GNUNET_free (payload_str);
521 GNUNET_free (payload_base64);
522 GNUNET_free (purpose);
523 json_decref (handle->header);
524 json_decref (handle->payload);
526 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
528 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
530 name_str = json_string (handle->ego_entry->identifier);
531 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
532 GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
534 json_decref (name_str);
538 token_str = json_string (token);
539 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
540 GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
542 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
543 token_record.data = token;
544 token_record.data_size = strlen (token);
545 token_record.expiration_time = exp_time;
546 token_record.record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
547 token_record.flags = GNUNET_GNSRECORD_RF_NONE;
548 if (GNUNET_YES == renew_token)
549 token_record.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
551 handle->ns_qe = GNUNET_NAMESTORE_records_store (handle->ns_handle,
558 GNUNET_free (lbl_str);
560 json_decref (token_str);
568 attr_collect (void *cls,
569 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
571 unsigned int rd_count,
572 const struct GNUNET_GNSRECORD_Data *rd)
577 struct RequestHandle *handle = cls;
578 struct GNUNET_HashCode key;
582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
583 handle->ns_it = NULL;
584 GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
588 GNUNET_CRYPTO_hash (label,
593 ( (NULL != handle->attr_map) &&
594 (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
599 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
607 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
609 data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
613 json_object_set_new (handle->payload, label, json_string (data));
616 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
621 attr_arr = json_array();
622 for (; i < rd_count; i++)
624 if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
626 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
630 json_array_append_new (attr_arr, json_string (data));
635 if (0 < json_array_size (attr_arr))
637 json_object_set (handle->payload, label, attr_arr);
639 json_decref (attr_arr);
640 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
645 * Create a response with requested ego(s)
647 * @param con the Rest handle
648 * @param url the requested url
649 * @param cls the request handle
652 issue_token_cont (struct RestConnectionDataHandle *con,
659 struct RequestHandle *handle = cls;
660 struct EgoEntry *ego_entry;
661 struct GNUNET_HashCode key;
662 struct MHD_Response *resp;
663 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
665 if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url,
666 GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE))
668 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "URL invalid: %s\n", handle->url);
669 resp = GNUNET_REST_create_json_response (NULL);
670 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
671 cleanup_handle (handle);
677 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
678 strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
681 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
684 ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
687 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego invalid: %s\n", ego_val);
690 for (ego_entry = handle->ego_head;
692 ego_entry = ego_entry->next)
694 if (0 != strcmp (ego_val, ego_entry->identifier))
696 egoname = ego_entry->identifier;
699 if (NULL == egoname || NULL == ego_entry)
701 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego not found: %s\n", ego_val);
702 resp = GNUNET_REST_create_json_response (NULL);
703 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
704 cleanup_handle (handle);
709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego to issue token for: %s\n", egoname);
710 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
711 strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST),
717 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
720 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Audience missing!\n");
721 resp = GNUNET_REST_create_json_response (NULL);
722 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
723 cleanup_handle (handle);
726 audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audience to issue token for: %s\n", audience);
729 handle->header = json_object ();
730 json_object_set_new (handle->header, "alg", json_string ("ED512"));
731 json_object_set_new (handle->header, "typ", json_string ("JWT"));
733 handle->payload = json_object ();
734 json_object_set_new (handle->payload, "iss", json_string (ego_entry->keystring));
735 json_object_set_new (handle->payload, "aud", json_string (audience));
738 //Get identity attributes
739 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
740 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
741 handle->ego_entry = ego_entry;
742 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
750 * Build a GNUid token for identity
751 * @param handle the handle
752 * @param ego_entry the ego to build the token for
753 * @param name name of the ego
754 * @param token_aud token audience
755 * @param token the resulting gnuid token
756 * @return identifier string of token (label)
759 return_token_list (void *cls,
760 const struct GNUNET_SCHEDULER_TaskContext *tc)
763 struct RequestHandle *handle = cls;
764 struct MHD_Response *resp;
766 GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
768 resp = GNUNET_REST_create_json_response (result_str);
769 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
770 GNUNET_free (result_str);
771 cleanup_handle (handle);
775 * Collect all tokens for ego
778 token_collect (void *cls,
779 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
781 unsigned int rd_count,
782 const struct GNUNET_GNSRECORD_Data *rd)
786 struct RequestHandle *handle = cls;
787 struct EgoEntry *ego_tmp;
788 struct JsonApiResource *json_resource;
789 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
795 ego_tmp = handle->ego_head;
796 GNUNET_CONTAINER_DLL_remove (handle->ego_head,
799 GNUNET_free (ego_tmp->identifier);
800 GNUNET_free (ego_tmp->keystring);
801 GNUNET_free (ego_tmp);
803 if (NULL == handle->ego_head)
806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token END\n");
807 handle->ns_it = NULL;
808 GNUNET_SCHEDULER_add_now (&return_token_list, handle);
812 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Next ego: %s\n", handle->ego_head->identifier);
813 priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
814 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
821 for (i = 0; i < rd_count; i++)
823 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
825 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token: %s\n", data);
829 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
831 issuer = json_string (handle->ego_head->identifier);
832 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
833 GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
835 json_decref (issuer);
836 token = json_string (data);
837 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
838 GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
842 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
847 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
853 * Respond to OPTIONS request
855 * @param con_handle the connection handle
857 * @param cls the RequestHandle
860 list_token_cont (struct RestConnectionDataHandle *con_handle,
865 struct GNUNET_HashCode key;
866 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
867 struct RequestHandle *handle = cls;
868 struct EgoEntry *ego_entry;
869 struct EgoEntry *ego_tmp;
871 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
872 strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
876 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
879 ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
881 //Remove non-matching egos
882 for (ego_entry = handle->ego_head;
886 ego_entry = ego_entry->next;
887 if (0 != strcmp (ego_val, ego_tmp->identifier))
889 GNUNET_CONTAINER_DLL_remove (handle->ego_head,
892 GNUNET_free (ego_tmp->identifier);
893 GNUNET_free (ego_tmp->keystring);
894 GNUNET_free (ego_tmp);
898 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
899 if (NULL == handle->ego_head)
902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No results.\n");
903 GNUNET_SCHEDULER_add_now (&return_token_list, handle);
906 priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
907 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
908 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
917 * Respond to OPTIONS request
919 * @param con_handle the connection handle
921 * @param cls the RequestHandle
924 options_cont (struct RestConnectionDataHandle *con_handle,
928 struct MHD_Response *resp;
929 struct RequestHandle *handle = cls;
931 //For now, independent of path return all options
932 resp = GNUNET_REST_create_json_response (NULL);
933 MHD_add_response_header (resp,
934 "Access-Control-Allow-Methods",
936 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
937 cleanup_handle (handle);
942 * Handle rest request
944 * @param handle the request handle
947 init_cont (struct RequestHandle *handle)
949 static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
950 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE, &issue_token_cont},
951 //{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK, &check_token_cont},
952 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN, &list_token_cont},
953 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_TOKEN, &options_cont},
954 GNUNET_REST_HANDLER_END
957 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
959 handle->emsg = GNUNET_strdup ("Request unsupported");
960 GNUNET_SCHEDULER_add_now (&do_error, handle);
965 * If listing is enabled, prints information about the egos.
967 * This function is initially called for all egos and then again
968 * whenever a ego's identifier changes or if it is deleted. At the
969 * end of the initial pass over all egos, the function is once called
970 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
971 * be invoked in the future or that there was an error.
973 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
974 * this function is only called ONCE, and 'NULL' being passed in
975 * 'ego' does indicate an error (i.e. name is taken or no default
976 * value is known). If 'ego' is non-NULL and if '*ctx'
977 * is set in those callbacks, the value WILL be passed to a subsequent
978 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
979 * that one was not NULL).
981 * When an identity is renamed, this function is called with the
982 * (known) ego but the NEW identifier.
984 * When an identity is deleted, this function is called with the
985 * (known) ego and "NULL" for the 'identifier'. In this case,
986 * the 'ego' is henceforth invalid (and the 'ctx' should also be
990 * @param ego ego handle
991 * @param ctx context for application to store data for this ego
992 * (during the lifetime of this process, initially NULL)
993 * @param identifier identifier assigned by the user for this ego,
994 * NULL if the user just deleted the ego and it
995 * must thus no longer be used
999 struct GNUNET_IDENTITY_Ego *ego,
1001 const char *identifier)
1003 struct RequestHandle *handle = cls;
1004 struct EgoEntry *ego_entry;
1005 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1007 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1009 handle->state = ID_REST_STATE_POST_INIT;
1013 if (ID_REST_STATE_INIT == handle->state) {
1014 ego_entry = GNUNET_new (struct EgoEntry);
1015 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1016 ego_entry->keystring =
1017 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1018 ego_entry->ego = ego;
1019 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
1020 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1026 * Function processing the REST call
1028 * @param method HTTP method
1029 * @param url URL of the HTTP request
1030 * @param data body of the HTTP request (optional)
1031 * @param data_size length of the body
1032 * @param proc callback function for the result
1033 * @param proc_cls closure for callback function
1034 * @return GNUNET_OK if request accepted
1037 rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
1038 GNUNET_REST_ResultProcessor proc,
1041 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1042 struct GNUNET_HashCode key;
1044 char* attr_list_tmp;
1047 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST,
1048 strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST),
1051 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1053 handle->proc_cls = proc_cls;
1054 handle->proc = proc;
1055 handle->state = ID_REST_STATE_INIT;
1056 handle->conndata_handle = conndata_handle;
1057 handle->data = conndata_handle->data;
1058 handle->data_size = conndata_handle->data_size;
1059 handle->method = conndata_handle->method;
1060 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
1063 handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1065 attr_list = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
1067 if (NULL != attr_list)
1069 attr_list_tmp = GNUNET_strdup (attr_list);
1070 attr = strtok(attr_list_tmp, ",");
1071 for (; NULL != attr; attr = strtok (NULL, ","))
1073 GNUNET_CRYPTO_hash (attr,
1076 GNUNET_CONTAINER_multihashmap_put (handle->attr_map,
1079 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1081 GNUNET_free (attr_list_tmp);
1086 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
1087 if (handle->url[strlen (handle->url)-1] == '/')
1088 handle->url[strlen (handle->url)-1] = '\0';
1089 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1091 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1094 handle->timeout_task =
1095 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1105 * Entry point for the plugin.
1107 * @param cls Config info
1108 * @return NULL on error, otherwise the plugin context
1111 libgnunet_plugin_rest_identity_token_init (void *cls)
1113 static struct Plugin plugin;
1114 struct GNUNET_REST_Plugin *api;
1117 if (NULL != plugin.cfg)
1118 return NULL; /* can only initialize once! */
1119 memset (&plugin, 0, sizeof (struct Plugin));
1121 api = GNUNET_new (struct GNUNET_REST_Plugin);
1123 api->name = GNUNET_REST_API_NS_IDENTITY_TOKEN;
1124 api->process_request = &rest_identity_process_request;
1125 GNUNET_asprintf (&allow_methods,
1126 "%s, %s, %s, %s, %s",
1127 MHD_HTTP_METHOD_GET,
1128 MHD_HTTP_METHOD_POST,
1129 MHD_HTTP_METHOD_PUT,
1130 MHD_HTTP_METHOD_DELETE,
1131 MHD_HTTP_METHOD_OPTIONS);
1133 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1134 _("Identity Token REST API initialized\n"));
1140 * Exit point from the plugin.
1142 * @param cls the plugin context (as returned by "init")
1143 * @return always NULL
1146 libgnunet_plugin_rest_identity_token_done (void *cls)
1148 struct GNUNET_REST_Plugin *api = cls;
1149 struct Plugin *plugin = api->cls;
1152 GNUNET_free_non_null (allow_methods);
1154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1155 "Identity Token REST plugin is finished\n");
1159 /* end of plugin_rest_gns.c */