b104950bab07bed9d677f0abc0acbd007a725a1b
[oweals/gnunet.git] / src / identity-provider / plugin_rest_identity_provider.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2012-2015 GNUnet e.V.
4
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.
9
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.
14
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.
19    */
20 /**
21  * @author Martin Schanzenbach
22  * @file identity/plugin_rest_identity.c
23  * @brief GNUnet Namestore REST plugin
24  *
25  */
26
27 #include "platform.h"
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"
35 #include <jansson.h>
36 #include <inttypes.h>
37 #include "gnunet_signatures.h"
38 #include "gnunet_identity_provider_service.h"
39
40 /**
41  * REST root namespace
42  */
43 #define GNUNET_REST_API_NS_IDENTITY_PROVIDER "/idp"
44
45 /**
46  * Issue namespace
47  */
48 #define GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE "/idp/issue"
49
50 /**
51  * Check namespace TODO
52  */
53 #define GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK "/idp/check"
54
55 /**
56  * Token namespace
57  */
58 #define GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN "/idp/token"
59
60 /**
61  * The parameter name in which the ticket must be provided
62  */
63 #define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET "ticket"
64
65 /**
66  * The parameter name in which the expected nonce must be provided
67  */
68 #define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_EXPECTED_NONCE "expected_nonce"
69
70 /**
71  * The parameter name in which the ticket must be provided
72  */
73 #define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TOKEN "token"
74
75 /**
76  * The URL parameter name in which the nonce must be provided
77  */
78 #define GNUNET_IDENTITY_TOKEN_REQUEST_NONCE "nonce"
79
80 /**
81  * State while collecting all egos
82  */
83 #define ID_REST_STATE_INIT 0
84
85 /**
86  * Done collecting egos
87  */
88 #define ID_REST_STATE_POST_INIT 1
89
90 /**
91  * Resource type
92  */
93 #define GNUNET_REST_JSONAPI_IDENTITY_TOKEN "token"
94
95 /**
96  * URL parameter to create a GNUid token for a specific audience
97  */
98 #define GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST "audience"
99
100 /**
101  * URL parameter to create a GNUid token for a specific issuer (EGO)
102  */
103 #define GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST "issuer"
104
105 /**
106  * Attributes passed to issue request
107  */
108 #define GNUNET_IDENTITY_TOKEN_ATTR_LIST "requested_attrs"
109
110 /**
111  * Token expiration string
112  */
113 #define GNUNET_IDENTITY_TOKEN_EXP_STRING "expiration"
114
115 /**
116  * Error messages
117  */
118 #define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
119 #define GNUNET_REST_ERROR_NO_DATA "No data"
120
121 /**
122  * GNUid token lifetime
123  */
124 #define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
125
126 /**
127  * The configuration handle
128  */
129 const struct GNUNET_CONFIGURATION_Handle *cfg;
130
131 /**
132  * HTTP methods allows for this plugin
133  */
134 static char* allow_methods;
135
136 /**
137  * @brief struct returned by the initialization function of the plugin
138  */
139 struct Plugin
140 {
141   const struct GNUNET_CONFIGURATION_Handle *cfg;
142 };
143
144 /**
145  * The ego list
146  */
147 struct EgoEntry
148 {
149   /**
150    * DLL
151    */
152   struct EgoEntry *next;
153
154   /**
155    * DLL
156    */
157   struct EgoEntry *prev;
158
159   /**
160    * Ego Identifier
161    */
162   char *identifier;
163
164   /**
165    * Public key string
166    */
167   char *keystring;
168
169   /**
170    * The Ego
171    */
172   struct GNUNET_IDENTITY_Ego *ego;
173 };
174
175
176 struct RequestHandle
177 {
178   /**
179    * Ego list
180    */
181   struct EgoEntry *ego_head;
182
183   /**
184    * Ego list
185    */
186   struct EgoEntry *ego_tail;
187
188   /**
189    * Selected ego
190    */
191   struct EgoEntry *ego_entry;
192
193   /**
194    * Ptr to current ego private key
195    */
196   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
197
198   /**
199    * Handle to the rest connection
200    */
201   struct RestConnectionDataHandle *conndata_handle;
202
203   /**
204    * The processing state
205    */
206   int state;
207
208   /**
209    * Handle to Identity service.
210    */
211   struct GNUNET_IDENTITY_Handle *identity_handle;
212
213   /**
214    * IDENTITY Operation
215    */
216   struct GNUNET_IDENTITY_Operation *op;
217
218   /**
219    * Identity Provider
220    */
221   struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
222
223   /**
224    * Idp Operation
225    */
226   struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
227
228   /**
229    * Handle to NS service
230    */
231   struct GNUNET_NAMESTORE_Handle *ns_handle;
232
233   /**
234    * NS iterator
235    */
236   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
237
238   /**
239    * NS Handle
240    */
241   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
242
243   /**
244    * Desired timeout for the lookup (default is no timeout).
245    */
246   struct GNUNET_TIME_Relative timeout;
247
248   /**
249    * ID of a task associated with the resolution process.
250    */
251   struct GNUNET_SCHEDULER_Task * timeout_task;
252
253   /**
254    * The plugin result processor
255    */
256   GNUNET_REST_ResultProcessor proc;
257
258   /**
259    * The closure of the result processor
260    */
261   void *proc_cls;
262
263   /**
264    * The url
265    */
266   char *url;
267
268   /**
269    * Error response message
270    */
271   char *emsg;
272
273   /**
274    * Response object
275    */
276   struct JsonApiObject *resp_object;
277
278 };
279
280
281 /**
282  * Cleanup lookup handle
283  * @param handle Handle to clean up
284  */
285 static void
286 cleanup_handle (struct RequestHandle *handle)
287 {
288   struct EgoEntry *ego_entry;
289   struct EgoEntry *ego_tmp;
290   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
291               "Cleaning up\n");
292   if (NULL != handle->resp_object)
293     GNUNET_REST_jsonapi_object_delete (handle->resp_object);
294   if (NULL != handle->timeout_task)
295     GNUNET_SCHEDULER_cancel (handle->timeout_task);
296   if (NULL != handle->identity_handle)
297     GNUNET_IDENTITY_disconnect (handle->identity_handle);
298   if (NULL != handle->idp)
299     GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
300   if (NULL != handle->ns_it)
301     GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it);
302   if (NULL != handle->ns_qe)
303     GNUNET_NAMESTORE_cancel (handle->ns_qe);
304   if (NULL != handle->ns_handle)
305     GNUNET_NAMESTORE_disconnect (handle->ns_handle);
306   if (NULL != handle->url)
307     GNUNET_free (handle->url);
308   if (NULL != handle->emsg)
309     GNUNET_free (handle->emsg);
310   for (ego_entry = handle->ego_head;
311        NULL != ego_entry;)
312   {
313     ego_tmp = ego_entry;
314     ego_entry = ego_entry->next;
315     GNUNET_free (ego_tmp->identifier);
316     GNUNET_free (ego_tmp->keystring);
317     GNUNET_free (ego_tmp);
318   }
319   GNUNET_free (handle);
320 }
321
322
323 /**
324  * Task run on shutdown.  Cleans up everything.
325  *
326  * @param cls unused
327  */
328 static void
329 do_error (void *cls)
330 {
331   struct RequestHandle *handle = cls;
332   struct MHD_Response *resp;
333   char *json_error;
334
335   GNUNET_asprintf (&json_error,
336                    "{Error while processing request: %s}",
337                    handle->emsg);
338   resp = GNUNET_REST_create_json_response (json_error);
339   handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
340   cleanup_handle (handle);
341   GNUNET_free (json_error);
342 }
343
344 /**
345  * Task run on shutdown.  Cleans up everything.
346  *
347  * @param cls unused
348  */
349 static void
350 do_cleanup_handle_delayed (void *cls)
351 {
352   struct RequestHandle *handle = cls;
353   cleanup_handle(handle);
354 }
355
356
357 /**
358  * Get a ticket for identity
359  * @param cls the handle
360  * @param ticket the ticket returned from the idp
361  */
362 static void
363 token_creat_cont (void *cls,
364                   const char *label,
365                   const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket,
366                   const struct GNUNET_IDENTITY_PROVIDER_Token *token)
367 {
368   struct JsonApiResource *json_resource;
369   struct RequestHandle *handle = cls;
370   struct MHD_Response *resp;
371   json_t *ticket_json;
372   json_t *token_json;
373   char *ticket_str;
374   char *token_str;
375   char *result_str;
376
377   if (NULL == ticket)
378   {
379     handle->emsg = GNUNET_strdup ("Error in token issue");
380     GNUNET_SCHEDULER_add_now (&do_error, handle);
381     return;
382   }
383
384   handle->resp_object = GNUNET_REST_jsonapi_object_new ();
385   json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
386                                                     label);
387   ticket_str = GNUNET_IDENTITY_PROVIDER_ticket_to_string (ticket);
388   token_str = GNUNET_IDENTITY_PROVIDER_token_to_string (token);
389   ticket_json = json_string (ticket_str);
390   token_json = json_string (token_str);
391   GNUNET_REST_jsonapi_resource_add_attr (json_resource,
392                                          GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
393                                          ticket_json);
394   GNUNET_REST_jsonapi_resource_add_attr (json_resource,
395                                          GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TOKEN,
396                                          token_json);
397   GNUNET_free (ticket_str);
398   GNUNET_free (token_str);
399   json_decref (ticket_json);
400   json_decref (token_json);
401   GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
402
403   GNUNET_REST_jsonapi_data_serialize (handle->resp_object, &result_str);
404   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
405   resp = GNUNET_REST_create_json_response (result_str);
406   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
407   GNUNET_free (result_str);
408   GNUNET_SCHEDULER_add_now (&do_cleanup_handle_delayed, handle);
409
410
411 }
412
413 /**
414  * Continueationf for token issue request
415  *
416  * @param con the Rest handle
417  * @param url the requested url
418  * @param cls the request handle
419  */
420 static void
421 issue_token_cont (struct RestConnectionDataHandle *con,
422                   const char *url,
423                   void *cls)
424 {
425   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
426   const char *egoname;
427
428   struct RequestHandle *handle = cls;
429   struct EgoEntry *ego_entry;
430   struct GNUNET_HashCode key;
431   struct MHD_Response *resp;
432   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
433   struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
434   struct GNUNET_TIME_Relative etime_rel;
435   struct GNUNET_TIME_Absolute exp_time;
436   char *ego_val;
437   char *audience;
438   char *exp_str;
439   char *nonce_str;
440   char *scopes;
441   uint64_t time;
442   uint64_t nonce;
443
444   if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url,
445                                                 GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE))
446   {
447     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "URL invalid: %s\n", handle->url);
448     resp = GNUNET_REST_create_json_response (NULL);
449     handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
450     cleanup_handle (handle);
451     return;
452   }
453   egoname = NULL;
454   ego_entry = NULL;
455   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
456                       strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
457                       &key);
458   if ( GNUNET_YES !=
459        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
460                                                &key) )
461   {
462     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Issuer not found\n");
463     GNUNET_SCHEDULER_add_now (&do_error, handle);
464     return;
465   }
466   ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
467                                                &key);
468   if (NULL == ego_val)
469   {
470     GNUNET_SCHEDULER_add_now (&do_error, handle);
471     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego invalid: %s\n", ego_val);
472     return;
473   }
474   for (ego_entry = handle->ego_head;
475        NULL != ego_entry;
476        ego_entry = ego_entry->next)
477   {
478     if (0 != strcmp (ego_val, ego_entry->identifier))
479       continue;
480     egoname = ego_entry->identifier;
481     break;
482   }
483   if (NULL == egoname || NULL == ego_entry)
484   {
485     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego not found: %s\n", ego_val);
486     GNUNET_SCHEDULER_add_now (&do_error, handle);
487     return;
488   }
489   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego to issue token for: %s\n", egoname);
490
491
492   //Meta info
493   GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST,
494                       strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST),
495                       &key);
496
497   scopes = NULL;
498   if ( GNUNET_YES !=
499        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
500                                                &key) )
501   {
502     handle->emsg = GNUNET_strdup ("Scopes missing!\n");
503     GNUNET_SCHEDULER_add_now (&do_error, handle);
504     return;
505   }
506   scopes = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
507                                               &key);
508
509
510   //Token audience
511   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
512                       strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST),
513                       &key);
514   audience = NULL;
515   if ( GNUNET_YES !=
516        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
517                                                &key) )
518   {
519     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Audience missing!\n");
520     GNUNET_SCHEDULER_add_now (&do_error, handle);
521     return;
522   }
523   audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
524                                                 &key);
525   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audience to issue token for: %s\n", audience);
526
527   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
528   GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
529                                       &pub_key);
530   GNUNET_STRINGS_string_to_data (audience,
531                                  strlen (audience),
532                                  &aud_key,
533                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
534
535   //Remote nonce
536   nonce_str = NULL;
537   GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE,
538                       strlen (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE),
539                       &key);
540   if ( GNUNET_YES !=
541        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
542                                                &key) )
543   {
544     handle->emsg = GNUNET_strdup ("Request nonce missing!\n");
545     GNUNET_SCHEDULER_add_now (&do_error, handle);
546     return;
547   }
548   nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
549                                                  &key);
550   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
551   sscanf (nonce_str, "%"SCNu64, &nonce);
552
553   //Get expiration for token from URL parameter
554   GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_EXP_STRING,
555                       strlen (GNUNET_IDENTITY_TOKEN_EXP_STRING),
556                       &key);
557
558   exp_str = NULL;
559   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
560                                                             &key))
561   {
562     exp_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
563                                                  &key);
564   }
565   if (NULL == exp_str) {
566     handle->emsg = GNUNET_strdup ("No expiration given!\n");
567     GNUNET_SCHEDULER_add_now (&do_error, handle);
568     return;
569   }
570
571   if (GNUNET_OK !=
572       GNUNET_STRINGS_fancy_time_to_relative (exp_str,
573                                              &etime_rel))
574   {
575     handle->emsg = GNUNET_strdup ("Expiration invalid!\n");
576     GNUNET_SCHEDULER_add_now (&do_error, handle);
577     return;
578   }
579   time = GNUNET_TIME_absolute_get().abs_value_us;
580   exp_time.abs_value_us = time + etime_rel.rel_value_us;
581
582   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
583   handle->idp_op = GNUNET_IDENTITY_PROVIDER_issue_token (handle->idp,
584                                                          priv_key,
585                                                          &aud_key,
586                                                          scopes,
587                                                          exp_time,
588                                                          nonce,
589                                                          &token_creat_cont,
590                                                          handle);
591
592 }
593
594
595 /**
596  * Build a GNUid token for identity
597  *
598  * @param cls the request handle
599  */
600 static void
601 return_token_list (void *cls)
602 {
603   char* result_str;
604   struct RequestHandle *handle = cls;
605   struct MHD_Response *resp;
606
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);
613 }
614
615 /**
616  * Collect all tokens for an ego
617  *
618  * TODO move this into the identity-provider service
619  *
620  */
621 static void
622 token_collect (void *cls,
623                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
624                const char *label,
625                unsigned int rd_count,
626                const struct GNUNET_GNSRECORD_Data *rd)
627 {
628   int i;
629   char* data;
630   struct RequestHandle *handle = cls;
631   struct EgoEntry *ego_tmp;
632   struct JsonApiResource *json_resource;
633   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
634   json_t *issuer;
635   json_t *token;
636
637   if (NULL == label)
638   {
639     ego_tmp = handle->ego_head;
640     GNUNET_CONTAINER_DLL_remove (handle->ego_head,
641                                  handle->ego_tail,
642                                  ego_tmp);
643     GNUNET_free (ego_tmp->identifier);
644     GNUNET_free (ego_tmp->keystring);
645     GNUNET_free (ego_tmp);
646
647     if (NULL == handle->ego_head)
648     {
649       //Done
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);
653       return;
654     }
655
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,
659                                                            priv_key,
660                                                            &token_collect,
661                                                            handle);
662     return;
663   }
664
665   for (i = 0; i < rd_count; i++)
666   {
667     if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
668     {
669       data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
670                                                rd[i].data,
671                                                rd[i].data_size);
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,
674                                                         label);
675       issuer = json_string (handle->ego_head->identifier);
676       GNUNET_REST_jsonapi_resource_add_attr (json_resource,
677                                              GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
678                                              issuer);
679       json_decref (issuer);
680       token = json_string (data);
681       GNUNET_REST_jsonapi_resource_add_attr (json_resource,
682                                              GNUNET_REST_JSONAPI_IDENTITY_TOKEN,
683                                              token);
684       json_decref (token);
685
686       GNUNET_REST_jsonapi_object_resource_add (handle->resp_object, json_resource);
687       GNUNET_free (data);
688     }
689   }
690
691   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
692 }
693
694
695
696 /**
697  * Respond to OPTIONS request
698  *
699  * @param con_handle the connection handle
700  * @param url the url
701  * @param cls the RequestHandle
702  */
703 static void
704 list_token_cont (struct RestConnectionDataHandle *con_handle,
705                  const char* url,
706                  void *cls)
707 {
708   char* ego_val;
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;
714
715   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
716                       strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
717                       &key);
718
719   if ( GNUNET_YES !=
720        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
721                                                &key) )
722   {
723     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No issuer given.\n");
724     GNUNET_SCHEDULER_add_now (&do_error, handle);
725     return;
726   }
727   ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
728                                                &key);
729   //Remove non-matching egos
730   for (ego_entry = handle->ego_head;
731        NULL != ego_entry;)
732   {
733     ego_tmp = ego_entry;
734     ego_entry = ego_entry->next;
735     if (0 != strcmp (ego_val, ego_tmp->identifier))
736     {
737       GNUNET_CONTAINER_DLL_remove (handle->ego_head,
738                                    handle->ego_tail,
739                                    ego_tmp);
740       GNUNET_free (ego_tmp->identifier);
741       GNUNET_free (ego_tmp->keystring);
742       GNUNET_free (ego_tmp);
743     }
744   }
745   handle->resp_object = GNUNET_REST_jsonapi_object_new ();
746   if (NULL == handle->ego_head)
747   {
748     //Done
749     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No results.\n");
750     GNUNET_SCHEDULER_add_now (&return_token_list, handle);
751     return;
752   }
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,
756                                                          priv_key,
757                                                          &token_collect,
758                                                          handle);
759
760 }
761
762 /**
763  * Return token to requestor
764  *
765  * @param cls request handle
766  * @param token the token
767  */
768 static void
769 exchange_cont (void *cls,
770                const struct GNUNET_IDENTITY_PROVIDER_Token *token,
771                uint64_t ticket_nonce)
772 {
773   json_t *root;
774   struct RequestHandle *handle = cls;
775   struct MHD_Response *resp;
776   struct GNUNET_HashCode key;
777   char* result;
778   char* token_str;
779   char* nonce_str;
780   uint64_t expected_nonce;
781
782   //Get nonce
783   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_EXPECTED_NONCE,
784                       strlen (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_EXPECTED_NONCE),
785                       &key);
786
787   if ( GNUNET_NO ==
788        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
789                                                &key) )
790   {
791     handle->emsg = GNUNET_strdup ("No nonce given.");
792     GNUNET_SCHEDULER_add_now (&do_error, handle);
793     return;
794   }
795   nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
796                                                   &key);
797   GNUNET_assert (1 == sscanf (nonce_str, "%"SCNu64, &expected_nonce));
798
799   if (ticket_nonce != expected_nonce)
800   {
801     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
802                 "Ticket nonce %lu does not match expected nonce %lu\n",
803                 ticket_nonce, expected_nonce);
804     handle->emsg = GNUNET_strdup ("Ticket nonce does not match expected nonce\n");
805     GNUNET_SCHEDULER_add_now (&do_error, handle);
806     return;
807   }
808
809   root = json_object ();
810   token_str = GNUNET_IDENTITY_PROVIDER_token_to_string (token);
811   json_object_set_new (root, "token", json_string (token_str));
812   json_object_set_new (root, "token_type", json_string ("jwt"));
813   GNUNET_free (token_str);
814
815   result = json_dumps (root, JSON_INDENT(1));
816   resp = GNUNET_REST_create_json_response (result);
817   GNUNET_free (result);
818   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
819   cleanup_handle (handle);
820   json_decref (root);
821 }
822
823
824 /**
825  *
826  * Callback called when identity for token exchange has been found
827  *
828  * @param cls request handle
829  * @param ego the identity to use as issuer
830  * @param ctx user context
831  * @param name identity name
832  *
833  */
834 static void
835 exchange_token_ticket_cb (void *cls,
836                           struct GNUNET_IDENTITY_Ego *ego,
837                           void **ctx,
838                           const char *name)
839 {
840   struct RequestHandle *handle = cls;
841   struct GNUNET_HashCode key;
842   struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket;
843   char* ticket_str;
844
845   handle->op = NULL;
846
847   if (NULL == ego)
848   {
849     handle->emsg = GNUNET_strdup ("No identity found.");
850     GNUNET_SCHEDULER_add_now (&do_error, handle);
851     return;
852   }
853
854   //Get ticket
855   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
856                       strlen (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET),
857                       &key);
858
859   if ( GNUNET_NO ==
860        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
861                                                &key) )
862   {
863     handle->emsg = GNUNET_strdup ("No ticket given.");
864     GNUNET_SCHEDULER_add_now (&do_error, handle);
865     return;
866   }
867   ticket_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
868                                                   &key);
869   handle->priv_key = GNUNET_IDENTITY_ego_get_private_key (ego);
870   GNUNET_IDENTITY_PROVIDER_string_to_ticket (ticket_str,
871                                              &ticket);
872
873   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
874   handle->idp_op = GNUNET_IDENTITY_PROVIDER_exchange_ticket (handle->idp,
875                                                              ticket,
876                                                              handle->priv_key,
877                                                              &exchange_cont,
878                                                              handle);
879   GNUNET_IDENTITY_PROVIDER_ticket_destroy (ticket);
880
881 }
882
883
884
885 /**
886  * Respond to issue request
887  *
888  * @param con_handle the connection handle
889  * @param url the url
890  * @param cls the RequestHandle
891  */
892 static void
893 exchange_token_ticket_cont (struct RestConnectionDataHandle *con_handle,
894                             const char* url,
895                             void *cls)
896 {
897   struct RequestHandle *handle = cls;
898
899   //Get token from GNS
900   handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
901                                     "gns-master",
902                                     &exchange_token_ticket_cb,
903                                     handle);
904 }
905
906 /**
907  * Respond to OPTIONS request
908  *
909  * @param con_handle the connection handle
910  * @param url the url
911  * @param cls the RequestHandle
912  */
913 static void
914 options_cont (struct RestConnectionDataHandle *con_handle,
915               const char* url,
916               void *cls)
917 {
918   struct MHD_Response *resp;
919   struct RequestHandle *handle = cls;
920
921   //For now, independent of path return all options
922   resp = GNUNET_REST_create_json_response (NULL);
923   MHD_add_response_header (resp,
924                            "Access-Control-Allow-Methods",
925                            allow_methods);
926   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
927   cleanup_handle (handle);
928   return;
929 }
930
931 /**
932  * Handle rest request
933  *
934  * @param handle the request handle
935  */
936 static void
937 init_cont (struct RequestHandle *handle)
938 {
939   static const struct GNUNET_REST_RestConnectionHandler handlers[] = {
940     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE, &issue_token_cont},
941     //{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK, &check_token_cont},
942     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PROVIDER, &list_token_cont},
943     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER, &options_cont},
944     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN, &exchange_token_ticket_cont},
945     GNUNET_REST_HANDLER_END
946   };
947
948   if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
949   {
950     handle->emsg = GNUNET_strdup ("Request unsupported");
951     GNUNET_SCHEDULER_add_now (&do_error, handle);
952   }
953 }
954
955 /**
956  * If listing is enabled, prints information about the egos.
957  *
958  * This function is initially called for all egos and then again
959  * whenever a ego's identifier changes or if it is deleted.  At the
960  * end of the initial pass over all egos, the function is once called
961  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
962  * be invoked in the future or that there was an error.
963  *
964  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
965  * this function is only called ONCE, and 'NULL' being passed in
966  * 'ego' does indicate an error (i.e. name is taken or no default
967  * value is known).  If 'ego' is non-NULL and if '*ctx'
968  * is set in those callbacks, the value WILL be passed to a subsequent
969  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
970  * that one was not NULL).
971  *
972  * When an identity is renamed, this function is called with the
973  * (known) ego but the NEW identifier.
974  *
975  * When an identity is deleted, this function is called with the
976  * (known) ego and "NULL" for the 'identifier'.  In this case,
977  * the 'ego' is henceforth invalid (and the 'ctx' should also be
978  * cleaned up).
979  *
980  * @param cls closure
981  * @param ego ego handle
982  * @param ctx context for application to store data for this ego
983  *                 (during the lifetime of this process, initially NULL)
984  * @param identifier identifier assigned by the user for this ego,
985  *                   NULL if the user just deleted the ego and it
986  *                   must thus no longer be used
987  */
988 static void
989 list_ego (void *cls,
990           struct GNUNET_IDENTITY_Ego *ego,
991           void **ctx,
992           const char *identifier)
993 {
994   struct RequestHandle *handle = cls;
995   struct EgoEntry *ego_entry;
996   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
997
998   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
999   {
1000     handle->state = ID_REST_STATE_POST_INIT;
1001     init_cont (handle);
1002     return;
1003   }
1004   if (ID_REST_STATE_INIT == handle->state) {
1005     ego_entry = GNUNET_new (struct EgoEntry);
1006     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1007     ego_entry->keystring =
1008       GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1009     ego_entry->ego = ego;
1010     GNUNET_asprintf (&ego_entry->identifier, "%s", identifier);
1011     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1012   }
1013
1014 }
1015
1016 /**
1017  * Function processing the REST call
1018  *
1019  * @param method HTTP method
1020  * @param url URL of the HTTP request
1021  * @param data body of the HTTP request (optional)
1022  * @param data_size length of the body
1023  * @param proc callback function for the result
1024  * @param proc_cls closure for callback function
1025  * @return GNUNET_OK if request accepted
1026  */
1027 static void
1028 rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
1029                               GNUNET_REST_ResultProcessor proc,
1030                               void *proc_cls)
1031 {
1032   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1033
1034   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1035   handle->proc_cls = proc_cls;
1036   handle->proc = proc;
1037   handle->state = ID_REST_STATE_INIT;
1038   handle->conndata_handle = conndata_handle;
1039
1040
1041   GNUNET_asprintf (&handle->url, "%s", conndata_handle->url);
1042   if (handle->url[strlen (handle->url)-1] == '/')
1043     handle->url[strlen (handle->url)-1] = '\0';
1044   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1045               "Connecting...\n");
1046   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1047                                                      &list_ego,
1048                                                      handle);
1049   handle->timeout_task =
1050     GNUNET_SCHEDULER_add_delayed (handle->timeout,
1051                                   &do_error,
1052                                   handle);
1053
1054
1055   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1056               "Connected\n");
1057 }
1058
1059 /**
1060  * Entry point for the plugin.
1061  *
1062  * @param cls Config info
1063  * @return NULL on error, otherwise the plugin context
1064  */
1065 void *
1066 libgnunet_plugin_rest_identity_provider_init (void *cls)
1067 {
1068   static struct Plugin plugin;
1069   struct GNUNET_REST_Plugin *api;
1070
1071   cfg = cls;
1072   if (NULL != plugin.cfg)
1073     return NULL;                /* can only initialize once! */
1074   memset (&plugin, 0, sizeof (struct Plugin));
1075   plugin.cfg = cfg;
1076   api = GNUNET_new (struct GNUNET_REST_Plugin);
1077   api->cls = &plugin;
1078   api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1079   api->process_request = &rest_identity_process_request;
1080   GNUNET_asprintf (&allow_methods,
1081                    "%s, %s, %s, %s, %s",
1082                    MHD_HTTP_METHOD_GET,
1083                    MHD_HTTP_METHOD_POST,
1084                    MHD_HTTP_METHOD_PUT,
1085                    MHD_HTTP_METHOD_DELETE,
1086                    MHD_HTTP_METHOD_OPTIONS);
1087
1088   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1089               _("Identity Token REST API initialized\n"));
1090   return api;
1091 }
1092
1093
1094 /**
1095  * Exit point from the plugin.
1096  *
1097  * @param cls the plugin context (as returned by "init")
1098  * @return always NULL
1099  */
1100 void *
1101 libgnunet_plugin_rest_identity_provider_done (void *cls)
1102 {
1103   struct GNUNET_REST_Plugin *api = cls;
1104   struct Plugin *plugin = api->cls;
1105
1106   plugin->cfg = NULL;
1107   GNUNET_free_non_null (allow_methods);
1108   GNUNET_free (api);
1109   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1110               "Identity Token REST plugin is finished\n");
1111   return NULL;
1112 }
1113
1114 /* end of plugin_rest_gns.c */