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 "microhttpd.h"
36 #include "gnunet_signatures.h"
37 #include "gnunet_identity_provider_service.h"
42 #define GNUNET_REST_API_NS_IDENTITY_PROVIDER "/idp"
47 #define GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE "/idp/issue"
50 * Check namespace TODO
52 #define GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK "/idp/check"
57 #define GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN "/idp/token"
60 * The parameter name in which the ticket must be provided
62 #define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET "ticket"
65 * The parameter name in which the ticket must be provided
67 #define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TOKEN "token"
70 * The URL parameter name in which the nonce must be provided
72 #define GNUNET_IDENTITY_TOKEN_REQUEST_NONCE "nonce"
75 * State while collecting all egos
77 #define ID_REST_STATE_INIT 0
80 * Done collecting egos
82 #define ID_REST_STATE_POST_INIT 1
87 #define GNUNET_REST_JSONAPI_IDENTITY_TOKEN "token"
90 * URL parameter to create a GNUid token for a specific audience
92 #define GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST "audience"
95 * URL parameter to create a GNUid token for a specific issuer (EGO)
97 #define GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST "issuer"
100 * Attributes passed to issue request
102 #define GNUNET_IDENTITY_TOKEN_ATTR_LIST "requested_attrs"
105 * Token expiration string
107 #define GNUNET_IDENTITY_TOKEN_EXP_STRING "expiration"
112 #define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
113 #define GNUNET_REST_ERROR_NO_DATA "No data"
116 * GNUid token lifetime
118 #define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
121 * The configuration handle
123 const struct GNUNET_CONFIGURATION_Handle *cfg;
126 * HTTP methods allows for this plugin
128 static char* allow_methods;
131 * @brief struct returned by the initialization function of the plugin
135 const struct GNUNET_CONFIGURATION_Handle *cfg;
146 struct EgoEntry *next;
151 struct EgoEntry *prev;
166 struct GNUNET_IDENTITY_Ego *ego;
175 struct EgoEntry *ego_head;
180 struct EgoEntry *ego_tail;
185 struct EgoEntry *ego_entry;
188 * Ptr to current ego private key
190 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
193 * Handle to the rest connection
195 struct RestConnectionDataHandle *conndata_handle;
198 * The processing state
203 * Handle to Identity service.
205 struct GNUNET_IDENTITY_Handle *identity_handle;
210 struct GNUNET_IDENTITY_Operation *op;
215 struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
220 struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
223 * Handle to NS service
225 struct GNUNET_NAMESTORE_Handle *ns_handle;
230 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
235 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
238 * Desired timeout for the lookup (default is no timeout).
240 struct GNUNET_TIME_Relative timeout;
243 * ID of a task associated with the resolution process.
245 struct GNUNET_SCHEDULER_Task * timeout_task;
248 * The plugin result processor
250 GNUNET_REST_ResultProcessor proc;
253 * The closure of the result processor
263 * Error response message
270 struct JsonApiObject *resp_object;
276 * Cleanup lookup handle
277 * @param handle Handle to clean up
280 cleanup_handle (struct RequestHandle *handle)
282 struct EgoEntry *ego_entry;
283 struct EgoEntry *ego_tmp;
284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
286 if (NULL != handle->resp_object)
287 GNUNET_REST_jsonapi_object_delete (handle->resp_object);
288 if (NULL != handle->timeout_task)
289 GNUNET_SCHEDULER_cancel (handle->timeout_task);
290 if (NULL != handle->identity_handle)
291 GNUNET_IDENTITY_disconnect (handle->identity_handle);
292 if (NULL != handle->idp)
293 GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
294 if (NULL != handle->ns_it)
295 GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it);
296 if (NULL != handle->ns_qe)
297 GNUNET_NAMESTORE_cancel (handle->ns_qe);
298 if (NULL != handle->ns_handle)
299 GNUNET_NAMESTORE_disconnect (handle->ns_handle);
300 if (NULL != handle->url)
301 GNUNET_free (handle->url);
302 if (NULL != handle->emsg)
303 GNUNET_free (handle->emsg);
304 for (ego_entry = handle->ego_head;
308 ego_entry = ego_entry->next;
309 GNUNET_free (ego_tmp->identifier);
310 GNUNET_free (ego_tmp->keystring);
311 GNUNET_free (ego_tmp);
313 GNUNET_free (handle);
318 * Task run on shutdown. Cleans up everything.
321 * @param tc scheduler context
325 const struct GNUNET_SCHEDULER_TaskContext *tc)
327 struct RequestHandle *handle = cls;
328 struct MHD_Response *resp;
331 GNUNET_asprintf (&json_error,
332 "{Error while processing request: %s}",
334 resp = GNUNET_REST_create_json_response (json_error);
335 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
336 cleanup_handle (handle);
337 GNUNET_free (json_error);
341 * Task run on shutdown. Cleans up everything.
344 * @param tc scheduler context
347 do_cleanup_handle_delayed (void *cls,
348 const struct GNUNET_SCHEDULER_TaskContext *tc)
350 struct RequestHandle *handle = cls;
351 cleanup_handle(handle);
356 * Get a ticket for identity
357 * @param cls the handle
358 * @param ticket the ticket returned from the idp
361 token_creat_cont (void *cls,
363 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket,
364 const struct GNUNET_IDENTITY_PROVIDER_Token *token)
366 struct JsonApiResource *json_resource;
367 struct RequestHandle *handle = cls;
368 struct MHD_Response *resp;
377 handle->emsg = GNUNET_strdup ("Error in token issue");
378 GNUNET_SCHEDULER_add_now (&do_error, handle);
382 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
383 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
385 ticket_str = GNUNET_IDENTITY_PROVIDER_ticket_to_string (ticket);
386 token_str = GNUNET_IDENTITY_PROVIDER_token_to_string (token);
387 ticket_json = json_string (ticket_str);
388 token_json = json_string (token_str);
389 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
390 GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
392 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
393 GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TOKEN,
395 GNUNET_free (ticket_str);
396 GNUNET_free (token_str);
397 json_decref (ticket_json);
398 json_decref (token_json);
399 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
401 GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
403 resp = GNUNET_REST_create_json_response (result_str);
404 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
405 GNUNET_free (result_str);
406 GNUNET_SCHEDULER_add_now (&do_cleanup_handle_delayed, handle);
412 * Continueationf for token issue request
414 * @param con the Rest handle
415 * @param url the requested url
416 * @param cls the request handle
419 issue_token_cont (struct RestConnectionDataHandle *con,
423 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
426 struct RequestHandle *handle = cls;
427 struct EgoEntry *ego_entry;
428 struct GNUNET_HashCode key;
429 struct MHD_Response *resp;
430 struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
431 struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
432 struct GNUNET_TIME_Relative etime_rel;
433 struct GNUNET_TIME_Absolute exp_time;
442 if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url,
443 GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE))
445 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "URL invalid: %s\n", handle->url);
446 resp = GNUNET_REST_create_json_response (NULL);
447 handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
448 cleanup_handle (handle);
453 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
454 strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
457 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
460 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Issuer not found\n");
461 GNUNET_SCHEDULER_add_now (&do_error, handle);
464 ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
468 GNUNET_SCHEDULER_add_now (&do_error, handle);
469 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego invalid: %s\n", ego_val);
472 for (ego_entry = handle->ego_head;
474 ego_entry = ego_entry->next)
476 if (0 != strcmp (ego_val, ego_entry->identifier))
478 egoname = ego_entry->identifier;
481 if (NULL == egoname || NULL == ego_entry)
483 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego not found: %s\n", ego_val);
484 GNUNET_SCHEDULER_add_now (&do_error, handle);
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego to issue token for: %s\n", egoname);
491 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST,
492 strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST),
497 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
500 handle->emsg = GNUNET_strdup ("Scopes missing!\n");
501 GNUNET_SCHEDULER_add_now (&do_error, handle);
504 scopes = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
509 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
510 strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST),
514 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
517 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Audience missing!\n");
518 GNUNET_SCHEDULER_add_now (&do_error, handle);
521 audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
523 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audience to issue token for: %s\n", audience);
525 priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
526 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
528 GNUNET_STRINGS_string_to_data (audience,
531 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
535 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE,
536 strlen (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE),
539 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
542 handle->emsg = GNUNET_strdup ("Request nonce missing!\n");
543 GNUNET_SCHEDULER_add_now (&do_error, handle);
546 nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
549 sscanf (nonce_str, "%lu", &nonce);
551 //Get expiration for token from URL parameter
552 GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_EXP_STRING,
553 strlen (GNUNET_IDENTITY_TOKEN_EXP_STRING),
557 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
560 exp_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
563 if (NULL == exp_str) {
564 handle->emsg = GNUNET_strdup ("No expiration given!\n");
565 GNUNET_SCHEDULER_add_now (&do_error, handle);
570 GNUNET_STRINGS_fancy_time_to_relative (exp_str,
573 handle->emsg = GNUNET_strdup ("Expiration invalid!\n");
574 GNUNET_SCHEDULER_add_now (&do_error, handle);
577 time = GNUNET_TIME_absolute_get().abs_value_us;
578 exp_time.abs_value_us = time + etime_rel.rel_value_us;
580 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
581 handle->idp_op = GNUNET_IDENTITY_PROVIDER_issue_token (handle->idp,
594 * Build a GNUid token for identity
596 * @param cls the request handle
597 * @param tc task context
600 return_token_list (void *cls,
601 const struct GNUNET_SCHEDULER_TaskContext *tc)
604 struct RequestHandle *handle = cls;
605 struct MHD_Response *resp;
607 GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
609 resp = GNUNET_REST_create_json_response (result_str);
610 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
611 GNUNET_free (result_str);
612 cleanup_handle (handle);
616 * Collect all tokens for an ego
618 * TODO move this into the identity-provider service
622 token_collect (void *cls,
623 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
625 unsigned int rd_count,
626 const struct GNUNET_GNSRECORD_Data *rd)
630 struct RequestHandle *handle = cls;
631 struct EgoEntry *ego_tmp;
632 struct JsonApiResource *json_resource;
633 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
639 ego_tmp = handle->ego_head;
640 GNUNET_CONTAINER_DLL_remove (handle->ego_head,
643 GNUNET_free (ego_tmp->identifier);
644 GNUNET_free (ego_tmp->keystring);
645 GNUNET_free (ego_tmp);
647 if (NULL == handle->ego_head)
650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token END\n");
651 handle->ns_it = NULL;
652 GNUNET_SCHEDULER_add_now (&return_token_list, handle);
656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Next ego: %s\n", handle->ego_head->identifier);
657 priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
658 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
665 for (i = 0; i < rd_count; i++)
667 if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
669 data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token: %s\n", data);
673 json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
675 issuer = json_string (handle->ego_head->identifier);
676 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
677 GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
679 json_decref (issuer);
680 token = json_string (data);
681 GNUNET_REST_jsonapi_resource_add_attr (json_resource,
682 GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
686 GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
691 GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
697 * Respond to OPTIONS request
699 * @param con_handle the connection handle
701 * @param cls the RequestHandle
704 list_token_cont (struct RestConnectionDataHandle *con_handle,
709 struct GNUNET_HashCode key;
710 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
711 struct RequestHandle *handle = cls;
712 struct EgoEntry *ego_entry;
713 struct EgoEntry *ego_tmp;
715 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
716 strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
720 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
723 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No issuer given.\n");
724 GNUNET_SCHEDULER_add_now (&do_error, handle);
727 ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
729 //Remove non-matching egos
730 for (ego_entry = handle->ego_head;
734 ego_entry = ego_entry->next;
735 if (0 != strcmp (ego_val, ego_tmp->identifier))
737 GNUNET_CONTAINER_DLL_remove (handle->ego_head,
740 GNUNET_free (ego_tmp->identifier);
741 GNUNET_free (ego_tmp->keystring);
742 GNUNET_free (ego_tmp);
745 handle->resp_object = GNUNET_REST_jsonapi_object_new ();
746 if (NULL == handle->ego_head)
749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No results.\n");
750 GNUNET_SCHEDULER_add_now (&return_token_list, handle);
753 priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
754 handle->ns_handle = GNUNET_NAMESTORE_connect (cfg);
755 handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle,
763 * Return token to requestor
765 * @param cls request handle
766 * @param token the token
769 exchange_cont (void *cls,
770 const struct GNUNET_IDENTITY_PROVIDER_Token *token)
773 struct RequestHandle *handle = cls;
774 struct MHD_Response *resp;
778 root = json_object ();
779 token_str = GNUNET_IDENTITY_PROVIDER_token_to_string (token);
780 json_object_set_new (root, "token", json_string (token_str));
781 json_object_set_new (root, "token_type", json_string ("jwt"));
782 GNUNET_free (token_str);
784 result = json_dumps (root, JSON_INDENT(1));
785 resp = GNUNET_REST_create_json_response (result);
786 GNUNET_free (result);
787 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
788 cleanup_handle (handle);
795 * Callback called when identity for token exchange has been found
797 * @param cls request handle
798 * @param ego the identity to use as issuer
799 * @param ctx user context
800 * @param name identity name
804 exchange_token_ticket_cb (void *cls,
805 struct GNUNET_IDENTITY_Ego *ego,
809 struct RequestHandle *handle = cls;
810 struct GNUNET_HashCode key;
811 struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket;
818 handle->emsg = GNUNET_strdup ("No identity found.");
819 GNUNET_SCHEDULER_add_now (&do_error, handle);
823 GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
824 strlen (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET),
828 GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
831 handle->emsg = GNUNET_strdup ("No ticket given.");
832 GNUNET_SCHEDULER_add_now (&do_error, handle);
835 ticket_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
838 handle->priv_key = GNUNET_IDENTITY_ego_get_private_key (ego);
839 GNUNET_IDENTITY_PROVIDER_string_to_ticket (ticket_str,
842 handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
843 handle->idp_op = GNUNET_IDENTITY_PROVIDER_exchange_ticket (handle->idp,
848 GNUNET_IDENTITY_PROVIDER_ticket_destroy (ticket);
855 * Respond to issue request
857 * @param con_handle the connection handle
859 * @param cls the RequestHandle
862 exchange_token_ticket_cont (struct RestConnectionDataHandle *con_handle,
866 struct RequestHandle *handle = cls;
869 handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
871 &exchange_token_ticket_cb,
876 * Respond to OPTIONS request
878 * @param con_handle the connection handle
880 * @param cls the RequestHandle
883 options_cont (struct RestConnectionDataHandle *con_handle,
887 struct MHD_Response *resp;
888 struct RequestHandle *handle = cls;
890 //For now, independent of path return all options
891 resp = GNUNET_REST_create_json_response (NULL);
892 MHD_add_response_header (resp,
893 "Access-Control-Allow-Methods",
895 handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
896 cleanup_handle (handle);
901 * Handle rest request
903 * @param handle the request handle
906 init_cont (struct RequestHandle *handle)
908 static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
909 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE, &issue_token_cont},
910 //{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK, &check_token_cont},
911 {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PROVIDER, &list_token_cont},
912 {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER, &options_cont},
913 {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN, &exchange_token_ticket_cont},
914 GNUNET_REST_HANDLER_END
917 if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
919 handle->emsg = GNUNET_strdup ("Request unsupported");
920 GNUNET_SCHEDULER_add_now (&do_error, handle);
925 * If listing is enabled, prints information about the egos.
927 * This function is initially called for all egos and then again
928 * whenever a ego's identifier changes or if it is deleted. At the
929 * end of the initial pass over all egos, the function is once called
930 * with 'NULL' for 'ego'. That does NOT mean that the callback won't
931 * be invoked in the future or that there was an error.
933 * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
934 * this function is only called ONCE, and 'NULL' being passed in
935 * 'ego' does indicate an error (i.e. name is taken or no default
936 * value is known). If 'ego' is non-NULL and if '*ctx'
937 * is set in those callbacks, the value WILL be passed to a subsequent
938 * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
939 * that one was not NULL).
941 * When an identity is renamed, this function is called with the
942 * (known) ego but the NEW identifier.
944 * When an identity is deleted, this function is called with the
945 * (known) ego and "NULL" for the 'identifier'. In this case,
946 * the 'ego' is henceforth invalid (and the 'ctx' should also be
950 * @param ego ego handle
951 * @param ctx context for application to store data for this ego
952 * (during the lifetime of this process, initially NULL)
953 * @param identifier identifier assigned by the user for this ego,
954 * NULL if the user just deleted the ego and it
955 * must thus no longer be used
959 struct GNUNET_IDENTITY_Ego *ego,
961 const char *identifier)
963 struct RequestHandle *handle = cls;
964 struct EgoEntry *ego_entry;
965 struct GNUNET_CRYPTO_EcdsaPublicKey pk;
967 if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
969 handle->state = ID_REST_STATE_POST_INIT;
973 if (ID_REST_STATE_INIT == handle->state) {
974 ego_entry = GNUNET_new (struct EgoEntry);
975 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
976 ego_entry->keystring =
977 GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
978 ego_entry->ego = ego;
979 GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
980 GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
986 * Function processing the REST call
988 * @param method HTTP method
989 * @param url URL of the HTTP request
990 * @param data body of the HTTP request (optional)
991 * @param data_size length of the body
992 * @param proc callback function for the result
993 * @param proc_cls closure for callback function
994 * @return GNUNET_OK if request accepted
997 rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
998 GNUNET_REST_ResultProcessor proc,
1001 struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1003 handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1004 handle->proc_cls = proc_cls;
1005 handle->proc = proc;
1006 handle->state = ID_REST_STATE_INIT;
1007 handle->conndata_handle = conndata_handle;
1010 GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
1011 if (handle->url[strlen (handle->url)-1] == '/')
1012 handle->url[strlen (handle->url)-1] = '\0';
1013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1015 handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1018 handle->timeout_task =
1019 GNUNET_SCHEDULER_add_delayed (handle->timeout,
1024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1029 * Entry point for the plugin.
1031 * @param cls Config info
1032 * @return NULL on error, otherwise the plugin context
1035 libgnunet_plugin_rest_identity_provider_init (void *cls)
1037 static struct Plugin plugin;
1038 struct GNUNET_REST_Plugin *api;
1041 if (NULL != plugin.cfg)
1042 return NULL; /* can only initialize once! */
1043 memset (&plugin, 0, sizeof (struct Plugin));
1045 api = GNUNET_new (struct GNUNET_REST_Plugin);
1047 api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1048 api->process_request = &rest_identity_process_request;
1049 GNUNET_asprintf (&allow_methods,
1050 "%s, %s, %s, %s, %s",
1051 MHD_HTTP_METHOD_GET,
1052 MHD_HTTP_METHOD_POST,
1053 MHD_HTTP_METHOD_PUT,
1054 MHD_HTTP_METHOD_DELETE,
1055 MHD_HTTP_METHOD_OPTIONS);
1057 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1058 _("Identity Token REST API initialized\n"));
1064 * Exit point from the plugin.
1066 * @param cls the plugin context (as returned by "init")
1067 * @return always NULL
1070 libgnunet_plugin_rest_identity_provider_done (void *cls)
1072 struct GNUNET_REST_Plugin *api = cls;
1073 struct Plugin *plugin = api->cls;
1076 GNUNET_free_non_null (allow_methods);
1078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1079 "Identity Token REST plugin is finished\n");
1083 /* end of plugin_rest_gns.c */