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
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_gns_service.h"
31 #include "gnunet_gnsrecord_lib.h"
32 #include "gnunet_namestore_service.h"
33 #include "gnunet_rest_lib.h"
34 #include "gnunet_jsonapi_lib.h"
35 #include "gnunet_jsonapi_util.h"
36 #include "microhttpd.h"
39 #include "gnunet_signatures.h"
40 #include "gnunet_identity_provider_service.h"
45 #define GNUNET_REST_API_NS_IDENTITY_PROVIDER "/idp"
50 #define GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE "/idp/issue"
53 * Check namespace TODO
55 #define GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK "/idp/check"
60 #define GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN "/idp/token"
63 * The parameter name in which the ticket must be provided
65 #define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET "ticket"
68 * The parameter name in which the expected nonce must be provided
70 #define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_EXPECTED_NONCE "expected_nonce"
73 * The parameter name in which the ticket must be provided
75 #define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TOKEN "token"
78 * The URL parameter name in which the nonce must be provided
80 #define GNUNET_IDENTITY_TOKEN_REQUEST_NONCE "nonce"
83 * State while collecting all egos
85 #define ID_REST_STATE_INIT 0
88 * Done collecting egos
90 #define ID_REST_STATE_POST_INIT 1
95 #define GNUNET_REST_JSONAPI_IDENTITY_TOKEN "token"
98 * URL parameter to create a GNUid token for a specific audience
100 #define GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST "audience"
103 * URL parameter to create a GNUid token for a specific issuer (EGO)
105 #define GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST "issuer"
108 * Attributes passed to issue request
110 #define GNUNET_IDENTITY_TOKEN_ATTR_LIST "requested_attrs"
113 * Attributes passed to issue request
115 #define GNUNET_IDENTITY_TOKEN_V_ATTR_LIST "requested_verified_attrs"
119 * Token expiration string
121 #define GNUNET_IDENTITY_TOKEN_EXP_STRING "expiration"
126 #define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
127 #define GNUNET_REST_ERROR_NO_DATA "No data"
130 * GNUid token lifetime
132 #define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
135 * The configuration handle
137 const struct GNUNET_CONFIGURATION_Handle *cfg;
140 * HTTP methods allows for this plugin
142 static char* allow_methods;
145 * @brief struct returned by the initialization function of the plugin
149 const struct GNUNET_CONFIGURATION_Handle *cfg;
160 struct EgoEntry *next;
165 struct EgoEntry *prev;
180 struct GNUNET_IDENTITY_Ego *ego;
189 struct EgoEntry *ego_head;
194 struct EgoEntry *ego_tail;
199 struct EgoEntry *ego_entry;
202 * Ptr to current ego private key
204 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
207 * Handle to the rest connection
209 struct GNUNET_REST_RequestHandle *conndata_handle;
212 * The processing state
217 * Handle to Identity service.
219 struct GNUNET_IDENTITY_Handle *identity_handle;
224 struct GNUNET_IDENTITY_Operation *op;
229 struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
234 struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
237 * Handle to NS service
239 struct GNUNET_NAMESTORE_Handle *ns_handle;
244 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
249 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
252 * Desired timeout for the lookup (default is no timeout).
254 struct GNUNET_TIME_Relative timeout;
257 * ID of a task associated with the resolution process.
259 struct GNUNET_SCHEDULER_Task *timeout_task;
262 * The plugin result processor
264 GNUNET_REST_ResultProcessor proc;
267 * The closure of the result processor
277 * Error response message
289 struct GNUNET_JSONAPI_Document *resp_object;
295 * Cleanup lookup handle
296 * @param handle Handle to clean up
299 cleanup_handle (struct RequestHandle *handle)
301 struct EgoEntry *ego_entry;
302 struct EgoEntry *ego_tmp;
303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
305 if (NULL != handle->resp_object)
306 GNUNET_JSONAPI_document_delete (handle->resp_object);
307 if (NULL != handle->timeout_task)
308 GNUNET_SCHEDULER_cancel (handle->timeout_task);
309 if (NULL != handle->identity_handle)
310 GNUNET_IDENTITY_disconnect (handle->identity_handle);
311 if (NULL != handle->idp)
312 GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
313 if (NULL != handle->ns_it)
314 GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it);
315 if (NULL != handle->ns_qe)
316 GNUNET_NAMESTORE_cancel (handle->ns_qe);
317 if (NULL != handle->ns_handle)
318 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
319 if (NULL != handle->url)
320 GNUNET_free (handle->url);
321 if (NULL != handle->emsg)
322 GNUNET_free (handle->emsg);
323 for (ego_entry = handle->ego_head;
327 ego_entry = ego_entry->next;
328 GNUNET_free (ego_tmp->identifier);
329 GNUNET_free (ego_tmp->keystring);
330 GNUNET_free (ego_tmp);
332 GNUNET_free (handle);
337 * Task run on error, sends error message. Cleans up everything.
339 * @param cls the `struct RequestHandle`
344 struct RequestHandle *handle = cls;
345 struct MHD_Response *resp;
348 GNUNET_asprintf (&json_error,
349 "{Error while processing request: %s}",
351 resp = GNUNET_REST_create_response (json_error);
352 handle->proc (handle->proc_cls, resp, handle->response_code);
353 cleanup_handle (handle);
354 GNUNET_free (json_error);
358 * Task run on timeout, sends error message. Cleans up everything.
360 * @param cls the `struct RequestHandle`
363 do_timeout (void *cls)
365 struct RequestHandle *handle = cls;
367 handle->timeout_task = NULL;
373 * Task run on shutdown. Cleans up everything.
378 do_cleanup_handle_delayed (void *cls)
380 struct RequestHandle *handle = cls;
382 cleanup_handle (handle);
387 * Get a ticket for identity
388 * @param cls the handle
389 * @param ticket the ticket returned from the idp
392 token_creat_cont (void *cls,
394 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket,
395 const struct GNUNET_IDENTITY_PROVIDER_Token *token)
397 struct GNUNET_JSONAPI_Resource *json_resource;
398 struct RequestHandle *handle = cls;
399 struct MHD_Response *resp;
408 handle->emsg = GNUNET_strdup ("Error in token issue");
409 GNUNET_SCHEDULER_add_now (&do_error, handle);
413 handle->resp_object = GNUNET_JSONAPI_document_new ();
414 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
416 ticket_str = GNUNET_IDENTITY_PROVIDER_ticket_to_string (ticket);
417 token_str = GNUNET_IDENTITY_PROVIDER_token_to_string (token);
418 ticket_json = json_string (ticket_str);
419 token_json = json_string (token_str);
420 GNUNET_JSONAPI_resource_add_attr (json_resource,
421 GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
423 GNUNET_JSONAPI_resource_add_attr (json_resource,
424 GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TOKEN,
426 GNUNET_free (ticket_str);
427 GNUNET_free (token_str);
428 json_decref (ticket_json);
429 json_decref (token_json);
430 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
432 GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
434 resp = GNUNET_REST_create_response (result_str);
435 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
436 GNUNET_free (result_str);
437 GNUNET_SCHEDULER_add_now (&do_cleanup_handle_delayed, handle);
442 * Continueationf for token issue request
444 * @param con the Rest handle
445 * @param url the requested url
446 * @param cls the request handle
449 issue_token_cont (struct GNUNET_REST_RequestHandle *con,
453 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
456 struct RequestHandle *handle = cls;
457 struct EgoEntry *ego_entry;
458 struct GNUNET_HashCode key;
459 struct MHD_Response *resp;
460 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
461 struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
462 struct GNUNET_TIME_Relative etime_rel;
463 struct GNUNET_TIME_Absolute exp_time;
473 if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url,
474 GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE))
476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "URL invalid: %s\n", handle->url);
477 resp = GNUNET_REST_create_response (NULL);
478 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
479 cleanup_handle (handle);
484 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
485 strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
488 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
491 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
492 "Issuer not found\n");
493 GNUNET_SCHEDULER_add_now (&do_error, handle);
496 ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
500 GNUNET_SCHEDULER_add_now (&do_error, handle);
501 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
506 for (ego_entry = handle->ego_head;
508 ego_entry = ego_entry->next)
510 if (0 != strcmp (ego_val, ego_entry->identifier))
512 egoname = ego_entry->identifier;
515 if ( (NULL == egoname) ||
516 (NULL == ego_entry) )
518 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
519 "Ego not found: %s\n",
521 GNUNET_SCHEDULER_add_now (&do_error, handle);
524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525 "Ego to issue token for: %s\n",
530 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST,
531 strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST),
536 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
539 handle->emsg = GNUNET_strdup ("Scopes missing!\n");
540 GNUNET_SCHEDULER_add_now (&do_error, handle);
543 scopes = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
547 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_V_ATTR_LIST,
548 strlen (GNUNET_IDENTITY_TOKEN_V_ATTR_LIST),
553 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
556 vattrs = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
563 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
564 strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST),
568 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
571 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
572 "Audience missing!\n");
573 GNUNET_SCHEDULER_add_now (&do_error, handle);
576 audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
579 "Audience to issue token for: %s\n",
582 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
583 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
585 GNUNET_STRINGS_string_to_data (audience,
588 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
592 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE,
593 strlen (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE),
596 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
599 handle->emsg = GNUNET_strdup ("Request nonce missing!\n");
600 GNUNET_SCHEDULER_add_now (&do_error, handle);
603 nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
605 GNUNET_assert (NULL != nonce_str);
606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
607 "Request nonce: %s\n",
609 GNUNET_assert (1 == sscanf (nonce_str, "%"SCNu64, &nonce));
611 //Get expiration for token from URL parameter
612 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_EXP_STRING,
613 strlen (GNUNET_IDENTITY_TOKEN_EXP_STRING),
617 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
620 exp_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
623 if (NULL == exp_str) {
624 handle->emsg = GNUNET_strdup ("No expiration given!\n");
625 GNUNET_SCHEDULER_add_now (&do_error, handle);
630 GNUNET_STRINGS_fancy_time_to_relative (exp_str,
633 handle->emsg = GNUNET_strdup ("Expiration invalid!\n");
634 GNUNET_SCHEDULER_add_now (&do_error, handle);
637 time = GNUNET_TIME_absolute_get().abs_value_us;
638 exp_time.abs_value_us = time + etime_rel.rel_value_us;
640 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
641 handle->idp_op = GNUNET_IDENTITY_PROVIDER_issue_token (handle->idp,
655 * Build a GNUid token for identity
657 * @param cls the request handle
660 return_token_list (void *cls)
663 struct RequestHandle *handle = cls;
664 struct MHD_Response *resp;
666 GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
667 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
668 resp = GNUNET_REST_create_response (result_str);
669 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
670 GNUNET_free (result_str);
671 cleanup_handle (handle);
676 token_collect_error_cb (void *cls)
678 struct RequestHandle *handle = cls;
685 * Collect all tokens for an ego
687 * TODO move this into the identity-provider service
691 token_collect (void *cls,
692 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
694 unsigned int rd_count,
695 const struct GNUNET_GNSRECORD_Data *rd);
699 token_collect_finished_cb (void *cls)
701 struct RequestHandle *handle = cls;
702 struct EgoEntry *ego_tmp;
703 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
705 ego_tmp = handle->ego_head;
706 GNUNET_CONTAINER_DLL_remove (handle->ego_head,
709 GNUNET_free (ego_tmp->identifier);
710 GNUNET_free (ego_tmp->keystring);
711 GNUNET_free (ego_tmp);
713 if (NULL == handle->ego_head)
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token END\n");
717 handle->ns_it = NULL;
718 GNUNET_SCHEDULER_add_now (&return_token_list, handle);
722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
724 handle->ego_head->identifier);
725 priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
726 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
728 &token_collect_error_cb,
732 &token_collect_finished_cb,
738 * Collect all tokens for an ego
740 * TODO move this into the identity-provider service
744 token_collect (void *cls,
745 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
747 unsigned int rd_count,
748 const struct GNUNET_GNSRECORD_Data *rd)
750 struct RequestHandle *handle = cls;
753 struct GNUNET_JSONAPI_Resource *json_resource;
757 for (i = 0; i < rd_count; i++)
759 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
761 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token: %s\n", data);
765 json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
767 issuer = json_string (handle->ego_head->identifier);
768 GNUNET_JSONAPI_resource_add_attr (json_resource,
769 GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
771 json_decref (issuer);
772 token = json_string (data);
773 GNUNET_JSONAPI_resource_add_attr (json_resource,
774 GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
778 GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
783 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
789 * Respond to OPTIONS request
791 * @param con_handle the connection handle
793 * @param cls the RequestHandle
796 list_token_cont (struct GNUNET_REST_RequestHandle *con_handle,
801 struct GNUNET_HashCode key;
802 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
803 struct RequestHandle *handle = cls;
804 struct EgoEntry *ego_entry;
805 struct EgoEntry *ego_tmp;
807 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
808 strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
812 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
815 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No issuer given.\n");
816 GNUNET_SCHEDULER_add_now (&do_error, handle);
819 ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
821 GNUNET_assert (NULL != ego_val);
822 //Remove non-matching egos
823 for (ego_entry = handle->ego_head;
827 ego_entry = ego_entry->next;
828 if (0 != strcmp (ego_val, ego_tmp->identifier))
830 GNUNET_CONTAINER_DLL_remove (handle->ego_head,
833 GNUNET_free (ego_tmp->identifier);
834 GNUNET_free (ego_tmp->keystring);
835 GNUNET_free (ego_tmp);
838 handle->resp_object = GNUNET_JSONAPI_document_new ();
839 if (NULL == handle->ego_head)
842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No results.\n");
843 GNUNET_SCHEDULER_add_now (&return_token_list, handle);
846 priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
847 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
848 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
850 &token_collect_error_cb,
854 &token_collect_finished_cb,
860 * Return token to requestor
862 * @param cls request handle
863 * @param token the token
866 exchange_cont (void *cls,
867 const struct GNUNET_IDENTITY_PROVIDER_Token *token,
868 uint64_t ticket_nonce)
871 struct RequestHandle *handle = cls;
872 struct MHD_Response *resp;
873 struct GNUNET_HashCode key;
877 uint64_t expected_nonce;
880 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_EXPECTED_NONCE,
881 strlen (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_EXPECTED_NONCE),
885 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
888 handle->emsg = GNUNET_strdup ("No nonce given.");
889 GNUNET_SCHEDULER_add_now (&do_error, handle);
892 nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
894 GNUNET_assert (NULL != nonce_str);
895 GNUNET_assert (1 == sscanf (nonce_str, "%"SCNu64, &expected_nonce));
897 if (ticket_nonce != expected_nonce)
899 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
900 "Ticket nonce %"SCNu64" does not match expected nonce %"SCNu64"\n",
901 ticket_nonce, expected_nonce);
902 handle->emsg = GNUNET_strdup ("Ticket nonce does not match expected nonce\n");
903 GNUNET_SCHEDULER_add_now (&do_error, handle);
907 root = json_object ();
908 token_str = GNUNET_IDENTITY_PROVIDER_token_to_string (token);
909 json_object_set_new (root, "token", json_string (token_str));
910 json_object_set_new (root, "token_type", json_string ("jwt"));
911 GNUNET_free (token_str);
913 result = json_dumps (root, JSON_INDENT(1));
914 resp = GNUNET_REST_create_response (result);
915 GNUNET_free (result);
916 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
917 cleanup_handle (handle);
924 * Callback called when identity for token exchange has been found
926 * @param cls request handle
927 * @param ego the identity to use as issuer
928 * @param ctx user context
929 * @param name identity name
933 exchange_token_ticket_cb (void *cls,
934 struct GNUNET_IDENTITY_Ego *ego,
938 struct RequestHandle *handle = cls;
939 struct GNUNET_HashCode key;
940 struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket;
947 handle->emsg = GNUNET_strdup ("No identity found.");
948 GNUNET_SCHEDULER_add_now (&do_error, handle);
953 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
954 strlen (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET),
958 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
961 handle->emsg = GNUNET_strdup ("No ticket given.");
962 GNUNET_SCHEDULER_add_now (&do_error, handle);
965 ticket_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
967 handle->priv_key = GNUNET_IDENTITY_ego_get_private_key (ego);
968 GNUNET_IDENTITY_PROVIDER_string_to_ticket (ticket_str,
971 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
972 handle->idp_op = GNUNET_IDENTITY_PROVIDER_exchange_ticket (handle->idp,
977 GNUNET_IDENTITY_PROVIDER_ticket_destroy (ticket);
984 * Respond to issue request
986 * @param con_handle the connection handle
988 * @param cls the RequestHandle
991 exchange_token_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
995 struct RequestHandle *handle = cls;
998 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
1000 &exchange_token_ticket_cb,
1005 * Respond to OPTIONS request
1007 * @param con_handle the connection handle
1008 * @param url the url
1009 * @param cls the RequestHandle
1012 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1016 struct MHD_Response *resp;
1017 struct RequestHandle *handle = cls;
1019 //For now, independent of path return all options
1020 resp = GNUNET_REST_create_response (NULL);
1021 MHD_add_response_header (resp,
1022 "Access-Control-Allow-Methods",
1024 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1025 cleanup_handle (handle);
1030 * Handle rest request
1032 * @param handle the request handle
1035 init_cont (struct RequestHandle *handle)
1037 struct GNUNET_REST_RequestHandlerError err;
1038 static const struct GNUNET_REST_RequestHandler handlers[] = {
1039 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE, &issue_token_cont},
1040 //{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK, &check_token_cont},
1041 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PROVIDER, &list_token_cont},
1042 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER, &options_cont},
1043 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN, &exchange_token_ticket_cont},
1044 GNUNET_REST_HANDLER_END
1047 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle,
1052 handle->response_code = err.error_code;
1053 GNUNET_SCHEDULER_add_now (&do_error, handle);
1058 * If listing is enabled, prints information about the egos.
1060 * This function is initially called for all egos and then again
1061 * whenever a ego's identifier changes or if it is deleted. At the
1062 * end of the initial pass over all egos, the function is once called
1063 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1064 * be invoked in the future or that there was an error.
1066 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1067 * this function is only called ONCE, and 'NULL' being passed in
1068 * 'ego' does indicate an error (i.e. name is taken or no default
1069 * value is known). If 'ego' is non-NULL and if '*ctx'
1070 * is set in those callbacks, the value WILL be passed to a subsequent
1071 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1072 * that one was not NULL).
1074 * When an identity is renamed, this function is called with the
1075 * (known) ego but the NEW identifier.
1077 * When an identity is deleted, this function is called with the
1078 * (known) ego and "NULL" for the 'identifier'. In this case,
1079 * the 'ego' is henceforth invalid (and the 'ctx' should also be
1082 * @param cls closure
1083 * @param ego ego handle
1084 * @param ctx context for application to store data for this ego
1085 * (during the lifetime of this process, initially NULL)
1086 * @param identifier identifier assigned by the user for this ego,
1087 * NULL if the user just deleted the ego and it
1088 * must thus no longer be used
1091 list_ego (void *cls,
1092 struct GNUNET_IDENTITY_Ego *ego,
1094 const char *identifier)
1096 struct RequestHandle *handle = cls;
1097 struct EgoEntry *ego_entry;
1098 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1100 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1102 handle->state = ID_REST_STATE_POST_INIT;
1106 if (ID_REST_STATE_INIT == handle->state) {
1107 ego_entry = GNUNET_new (struct EgoEntry);
1108 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1109 ego_entry->keystring =
1110 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1111 ego_entry->ego = ego;
1112 ego_entry->identifier = GNUNET_strdup (identifier);
1113 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1119 * Function processing the REST call
1121 * @param method HTTP method
1122 * @param url URL of the HTTP request
1123 * @param data body of the HTTP request (optional)
1124 * @param data_size length of the body
1125 * @param proc callback function for the result
1126 * @param proc_cls closure for callback function
1127 * @return GNUNET_OK if request accepted
1130 rest_identity_process_request(struct GNUNET_REST_RequestHandle *conndata_handle,
1131 GNUNET_REST_ResultProcessor proc,
1134 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1136 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1137 handle->proc_cls = proc_cls;
1138 handle->proc = proc;
1139 handle->state = ID_REST_STATE_INIT;
1140 handle->conndata_handle = conndata_handle;
1143 handle->url = GNUNET_strdup (conndata_handle->url);
1144 if (handle->url[strlen (handle->url)-1] == '/')
1145 handle->url[strlen (handle->url)-1] = '\0';
1146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1148 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1151 handle->timeout_task =
1152 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1160 * Entry point for the plugin.
1162 * @param cls Config info
1163 * @return NULL on error, otherwise the plugin context
1166 libgnunet_plugin_rest_identity_provider_init (void *cls)
1168 static struct Plugin plugin;
1169 struct GNUNET_REST_Plugin *api;
1172 if (NULL != plugin.cfg)
1173 return NULL; /* can only initialize once! */
1174 memset (&plugin, 0, sizeof (struct Plugin));
1176 api = GNUNET_new (struct GNUNET_REST_Plugin);
1178 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1179 api->process_request = &rest_identity_process_request;
1180 GNUNET_asprintf (&allow_methods,
1181 "%s, %s, %s, %s, %s",
1182 MHD_HTTP_METHOD_GET,
1183 MHD_HTTP_METHOD_POST,
1184 MHD_HTTP_METHOD_PUT,
1185 MHD_HTTP_METHOD_DELETE,
1186 MHD_HTTP_METHOD_OPTIONS);
1188 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1189 _("Identity Token REST API initialized\n"));
1195 * Exit point from the plugin.
1197 * @param cls the plugin context (as returned by "init")
1198 * @return always NULL
1201 libgnunet_plugin_rest_identity_provider_done (void *cls)
1203 struct GNUNET_REST_Plugin *api = cls;
1204 struct Plugin *plugin = api->cls;
1207 GNUNET_free_non_null (allow_methods);
1209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1210 "Identity Token REST plugin is finished\n");
1214 /* end of plugin_rest_gns.c */