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