-fix (C) notices
[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 "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 parameter name in which the ticket must be provided
61  */
62 #define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET "ticket"
63
64 /**
65  * The parameter name in which the ticket must be provided
66  */
67 #define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TOKEN "token"
68
69 /**
70  * The URL parameter name in which the nonce must be provided
71  */
72 #define GNUNET_IDENTITY_TOKEN_REQUEST_NONCE "nonce"
73
74 /**
75  * State while collecting all egos
76  */
77 #define ID_REST_STATE_INIT 0
78
79 /**
80  * Done collecting egos
81  */
82 #define ID_REST_STATE_POST_INIT 1
83
84 /**
85  * Resource type
86  */
87 #define GNUNET_REST_JSONAPI_IDENTITY_TOKEN "token"
88
89 /**
90  * URL parameter to create a GNUid token for a specific audience
91  */
92 #define GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST "audience"
93
94 /**
95  * URL parameter to create a GNUid token for a specific issuer (EGO)
96  */
97 #define GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST "issuer"
98
99 /**
100  * Attributes passed to issue request
101  */
102 #define GNUNET_IDENTITY_TOKEN_ATTR_LIST "requested_attrs"
103
104 /**
105  * Token expiration string
106  */
107 #define GNUNET_IDENTITY_TOKEN_EXP_STRING "expiration"
108
109 /**
110  * Error messages
111  */
112 #define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid"
113 #define GNUNET_REST_ERROR_NO_DATA "No data"
114
115 /**
116  * GNUid token lifetime
117  */
118 #define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000
119
120 /**
121  * The configuration handle
122  */
123 const struct GNUNET_CONFIGURATION_Handle *cfg;
124
125 /**
126  * HTTP methods allows for this plugin
127  */
128 static char* allow_methods;
129
130 /**
131  * @brief struct returned by the initialization function of the plugin
132  */
133 struct Plugin
134 {
135   const struct GNUNET_CONFIGURATION_Handle *cfg;
136 };
137
138 /**
139  * The ego list
140  */
141 struct EgoEntry
142 {
143   /**
144    * DLL
145    */
146   struct EgoEntry *next;
147   
148   /**
149    * DLL
150    */
151   struct EgoEntry *prev;
152   
153   /**
154    * Ego Identifier
155    */
156   char *identifier;
157
158   /**
159    * Public key string
160    */
161   char *keystring;
162   
163   /**
164    * The Ego
165    */
166   struct GNUNET_IDENTITY_Ego *ego;
167 };
168
169
170 struct RequestHandle
171 {
172   /**
173    * Ego list
174    */
175   struct EgoEntry *ego_head;
176
177   /**
178    * Ego list
179    */
180   struct EgoEntry *ego_tail;
181
182   /**
183    * Selected ego
184    */
185   struct EgoEntry *ego_entry;
186   
187   /**
188    * Ptr to current ego private key
189    */
190   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
191
192   /**
193    * Handle to the rest connection
194    */
195   struct RestConnectionDataHandle *conndata_handle;
196   
197   /**
198    * The processing state
199    */
200   int state;
201
202   /**
203    * Handle to Identity service.
204    */
205   struct GNUNET_IDENTITY_Handle *identity_handle;
206
207   /**
208    * IDENTITY Operation
209    */
210   struct GNUNET_IDENTITY_Operation *op;
211
212   /**
213    * Identity Provider
214    */
215   struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
216
217   /**
218    * Idp Operation
219    */
220   struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
221
222   /**
223    * Handle to NS service
224    */
225   struct GNUNET_NAMESTORE_Handle *ns_handle;
226
227   /**
228    * NS iterator
229    */
230   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
231
232   /**
233    * NS Handle
234    */
235   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
236
237   /**
238    * Desired timeout for the lookup (default is no timeout).
239    */
240   struct GNUNET_TIME_Relative timeout;
241
242   /**
243    * ID of a task associated with the resolution process.
244    */
245   struct GNUNET_SCHEDULER_Task * timeout_task;    
246   
247   /**
248    * The plugin result processor
249    */
250   GNUNET_REST_ResultProcessor proc;
251
252   /**
253    * The closure of the result processor
254    */
255   void *proc_cls;
256
257   /**
258    * The url
259    */
260   char *url;
261
262   /**
263    * Error response message
264    */
265   char *emsg;
266
267   /**
268    * Response object
269    */
270   struct JsonApiObject *resp_object;
271
272 };
273
274
275 /**
276  * Cleanup lookup handle
277  * @param handle Handle to clean up
278  */
279 static void
280 cleanup_handle (struct RequestHandle *handle)
281 {
282   struct EgoEntry *ego_entry;
283   struct EgoEntry *ego_tmp;
284   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
285               "Cleaning up\n");
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;
305        NULL != ego_entry;)
306   {
307     ego_tmp = ego_entry;
308     ego_entry = ego_entry->next;
309     GNUNET_free (ego_tmp->identifier);
310     GNUNET_free (ego_tmp->keystring);
311     GNUNET_free (ego_tmp);
312   }
313   GNUNET_free (handle);
314 }
315
316
317 /**
318  * Task run on shutdown.  Cleans up everything.
319  *
320  * @param cls unused
321  * @param tc scheduler context
322  */
323 static void
324 do_error (void *cls,
325           const struct GNUNET_SCHEDULER_TaskContext *tc)
326 {
327   struct RequestHandle *handle = cls;
328   struct MHD_Response *resp;
329   char *json_error;
330
331   GNUNET_asprintf (&json_error,
332                    "{Error while processing request: %s}",
333                    handle->emsg);
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);
338 }
339
340 /**
341  * Task run on shutdown.  Cleans up everything.
342  *
343  * @param cls unused
344  * @param tc scheduler context
345  */
346 static void
347 do_cleanup_handle_delayed (void *cls,
348           const struct GNUNET_SCHEDULER_TaskContext *tc)
349 {
350   struct RequestHandle *handle = cls;
351   cleanup_handle(handle);
352 }
353
354
355 /**
356  * Get a ticket for identity
357  * @param cls the handle
358  * @param ticket the ticket returned from the idp
359  */
360 static void
361 token_creat_cont (void *cls,
362                   const char *label,
363                   const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket,
364                   const struct GNUNET_IDENTITY_PROVIDER_Token *token)
365 {
366   struct JsonApiResource *json_resource;
367   struct RequestHandle *handle = cls;
368   struct MHD_Response *resp;
369   json_t *ticket_json;
370   json_t *token_json;
371   char *ticket_str;
372   char *token_str;
373   char *result_str;
374   
375   if (NULL == ticket)
376   {
377     handle->emsg = GNUNET_strdup ("Error in token issue");
378     GNUNET_SCHEDULER_add_now (&do_error, handle);
379     return;
380   }
381
382   handle->resp_object = GNUNET_REST_jsonapi_object_new ();
383   json_resource = GNUNET_REST_jsonapi_resource_new (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
384                                                     label);
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,
391                                          ticket_json);
392   GNUNET_REST_jsonapi_resource_add_attr (json_resource,
393                                          GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TOKEN,
394                                          token_json);
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);
400
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);
407
408
409 }
410
411 /**
412  * Continueationf for token issue request
413  *
414  * @param con the Rest handle
415  * @param url the requested url
416  * @param cls the request handle
417  */
418 static void
419 issue_token_cont (struct RestConnectionDataHandle *con,
420                   const char *url,
421                   void *cls)
422 {
423   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
424   const char *egoname;
425
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;
434   char *ego_val;
435   char *audience;
436   char *exp_str;
437   char *nonce_str;
438   char *scopes;
439   uint64_t time;
440   uint64_t nonce;
441
442   if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url,
443                                                 GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE))
444   {
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);
449     return;
450   }
451   egoname = NULL;
452   ego_entry = NULL;
453   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST,
454                       strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST),
455                       &key);
456   if ( GNUNET_YES !=
457        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
458                                                &key) )
459   {
460     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Issuer not found\n");
461     GNUNET_SCHEDULER_add_now (&do_error, handle);
462     return;
463   }
464   ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
465                                                &key);
466   if (NULL == ego_val)
467   {
468     GNUNET_SCHEDULER_add_now (&do_error, handle);
469     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego invalid: %s\n", ego_val);
470     return;
471   }
472   for (ego_entry = handle->ego_head;
473        NULL != ego_entry;
474        ego_entry = ego_entry->next)
475   {
476     if (0 != strcmp (ego_val, ego_entry->identifier))
477       continue;
478     egoname = ego_entry->identifier;
479     break;
480   }
481   if (NULL == egoname || NULL == ego_entry)
482   {
483     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Ego not found: %s\n", ego_val);
484     GNUNET_SCHEDULER_add_now (&do_error, handle);
485     return;
486   }
487   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego to issue token for: %s\n", egoname);
488
489
490   //Meta info
491   GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST,
492                       strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST),
493                       &key);
494
495   scopes = NULL;
496   if ( GNUNET_YES !=
497        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
498                                                &key) )
499   {
500     handle->emsg = GNUNET_strdup ("Scopes missing!\n");
501     GNUNET_SCHEDULER_add_now (&do_error, handle);
502     return;
503   }
504   scopes = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
505                                               &key);
506
507
508   //Token audience
509   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST,
510                       strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST),
511                       &key);
512   audience = NULL;
513   if ( GNUNET_YES !=
514        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
515                                                &key) )
516   {
517     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Audience missing!\n");
518     GNUNET_SCHEDULER_add_now (&do_error, handle);
519     return;
520   }
521   audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
522                                                 &key);
523   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Audience to issue token for: %s\n", audience);
524
525   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
526   GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
527                                       &pub_key);
528   GNUNET_STRINGS_string_to_data (audience,
529                                  strlen (audience),
530                                  &aud_key,
531                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
532
533   //Remote nonce 
534   nonce_str = NULL;
535   GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE,
536                       strlen (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE),
537                       &key);
538   if ( GNUNET_YES !=
539        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
540                                                &key) )
541   {
542     handle->emsg = GNUNET_strdup ("Request nonce missing!\n");
543     GNUNET_SCHEDULER_add_now (&do_error, handle);
544     return;
545   }
546   nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
547                                                  &key);
548   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
549   sscanf (nonce_str, "%lu", &nonce);
550
551   //Get expiration for token from URL parameter
552   GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_EXP_STRING,
553                       strlen (GNUNET_IDENTITY_TOKEN_EXP_STRING),
554                       &key);
555
556   exp_str = NULL;
557   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
558                                                             &key))
559   {
560     exp_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
561                                                  &key);
562   }
563   if (NULL == exp_str) {
564     handle->emsg = GNUNET_strdup ("No expiration given!\n");
565     GNUNET_SCHEDULER_add_now (&do_error, handle);
566     return;
567   }
568
569   if (GNUNET_OK !=
570       GNUNET_STRINGS_fancy_time_to_relative (exp_str,
571                                              &etime_rel))
572   {
573     handle->emsg = GNUNET_strdup ("Expiration invalid!\n");
574     GNUNET_SCHEDULER_add_now (&do_error, handle);
575     return;
576   }
577   time = GNUNET_TIME_absolute_get().abs_value_us;
578   exp_time.abs_value_us = time + etime_rel.rel_value_us;
579
580   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
581   handle->idp_op = GNUNET_IDENTITY_PROVIDER_issue_token (handle->idp,
582                                                          priv_key,
583                                                          &aud_key,
584                                                          scopes,
585                                                          exp_time,
586                                                          nonce,
587                                                          &token_creat_cont,
588                                                          handle);
589
590 }
591
592
593 /**
594  * Build a GNUid token for identity
595  *
596  * @param cls the request handle
597  * @param tc task context
598  */
599 static void
600 return_token_list (void *cls,
601                    const struct GNUNET_SCHEDULER_TaskContext *tc)
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 {
772   json_t *root;
773   struct RequestHandle *handle = cls;
774   struct MHD_Response *resp;
775   char* result;
776   char* token_str;
777
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);
783
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);
789   json_decref (root); 
790 }
791
792
793 /**
794  *
795  * Callback called when identity for token exchange has been found
796  *
797  * @param cls request handle
798  * @param ego the identity to use as issuer
799  * @param ctx user context
800  * @param name identity name
801  *
802  */
803 static void
804 exchange_token_ticket_cb (void *cls,
805                           struct GNUNET_IDENTITY_Ego *ego,
806                           void **ctx,
807                           const char *name)
808 {
809   struct RequestHandle *handle = cls;
810   struct GNUNET_HashCode key;
811   struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket;
812   char* ticket_str;
813
814   handle->op = NULL;
815
816   if (NULL == ego)
817   {
818     handle->emsg = GNUNET_strdup ("No identity found.");
819     GNUNET_SCHEDULER_add_now (&do_error, handle);
820     return;
821   }
822
823   GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET,
824                       strlen (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET),
825                       &key);
826
827   if ( GNUNET_NO ==
828        GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map,
829                                                &key) )
830   {
831     handle->emsg = GNUNET_strdup ("No ticket given.");
832     GNUNET_SCHEDULER_add_now (&do_error, handle);
833     return;
834   }
835   ticket_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map,
836                                                   &key);
837
838   handle->priv_key = GNUNET_IDENTITY_ego_get_private_key (ego);
839   GNUNET_IDENTITY_PROVIDER_string_to_ticket (ticket_str,
840                                              &ticket);
841
842   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
843   handle->idp_op = GNUNET_IDENTITY_PROVIDER_exchange_ticket (handle->idp,
844                                                              ticket,
845                                                              handle->priv_key,
846                                                              &exchange_cont,
847                                                              handle);
848   GNUNET_IDENTITY_PROVIDER_ticket_destroy (ticket);
849
850 }
851
852
853
854 /**
855  * Respond to issue request
856  *
857  * @param con_handle the connection handle
858  * @param url the url
859  * @param cls the RequestHandle
860  */
861 static void
862 exchange_token_ticket_cont (struct RestConnectionDataHandle *con_handle,
863                             const char* url,
864                             void *cls)
865 {
866   struct RequestHandle *handle = cls;
867
868   //Get token from GNS
869   handle->op = GNUNET_IDENTITY_get (handle->identity_handle,
870                                     "gns-master",
871                                     &exchange_token_ticket_cb,
872                                     handle);
873 }
874
875 /**
876  * Respond to OPTIONS request
877  *
878  * @param con_handle the connection handle
879  * @param url the url
880  * @param cls the RequestHandle
881  */
882 static void
883 options_cont (struct RestConnectionDataHandle *con_handle,
884               const char* url,
885               void *cls)
886 {
887   struct MHD_Response *resp;
888   struct RequestHandle *handle = cls;
889
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",
894                            allow_methods);
895   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
896   cleanup_handle (handle);
897   return;
898 }
899
900 /**
901  * Handle rest request
902  *
903  * @param handle the request handle
904  */
905 static void
906 init_cont (struct RequestHandle *handle)
907 {
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
915   };
916
917   if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, handlers, handle))
918   {
919     handle->emsg = GNUNET_strdup ("Request unsupported");
920     GNUNET_SCHEDULER_add_now (&do_error, handle);
921   }
922 }
923
924 /**
925  * If listing is enabled, prints information about the egos.
926  *
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.
932  *
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).
940  *
941  * When an identity is renamed, this function is called with the
942  * (known) ego but the NEW identifier.
943  *
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
947  * cleaned up).
948  *
949  * @param cls closure
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
956  */
957 static void
958 list_ego (void *cls,
959           struct GNUNET_IDENTITY_Ego *ego,
960           void **ctx,
961           const char *identifier)
962 {
963   struct RequestHandle *handle = cls;
964   struct EgoEntry *ego_entry;
965   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
966
967   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
968   {
969     handle->state = ID_REST_STATE_POST_INIT;
970     init_cont (handle);
971     return;
972   }
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);
981   }
982
983 }
984
985 /**
986  * Function processing the REST call
987  *
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
995  */
996 static void
997 rest_identity_process_request(struct RestConnectionDataHandle *conndata_handle,
998                               GNUNET_REST_ResultProcessor proc,
999                               void *proc_cls)
1000 {
1001   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1002
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;
1008
1009
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,
1014               "Connecting...\n");
1015   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1016                                                      &list_ego,
1017                                                      handle);
1018   handle->timeout_task =
1019     GNUNET_SCHEDULER_add_delayed (handle->timeout,
1020                                   &do_error,
1021                                   handle);
1022
1023
1024   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1025               "Connected\n");
1026 }
1027
1028 /**
1029  * Entry point for the plugin.
1030  *
1031  * @param cls Config info
1032  * @return NULL on error, otherwise the plugin context
1033  */
1034 void *
1035 libgnunet_plugin_rest_identity_provider_init (void *cls)
1036 {
1037   static struct Plugin plugin;
1038   struct GNUNET_REST_Plugin *api;
1039
1040   cfg = cls;
1041   if (NULL != plugin.cfg)
1042     return NULL;                /* can only initialize once! */
1043   memset (&plugin, 0, sizeof (struct Plugin));
1044   plugin.cfg = cfg;
1045   api = GNUNET_new (struct GNUNET_REST_Plugin);
1046   api->cls = &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);
1056
1057   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1058               _("Identity Token REST API initialized\n"));
1059   return api;
1060 }
1061
1062
1063 /**
1064  * Exit point from the plugin.
1065  *
1066  * @param cls the plugin context (as returned by "init")
1067  * @return always NULL
1068  */
1069 void *
1070 libgnunet_plugin_rest_identity_provider_done (void *cls)
1071 {
1072   struct GNUNET_REST_Plugin *api = cls;
1073   struct Plugin *plugin = api->cls;
1074
1075   plugin->cfg = NULL;
1076   GNUNET_free_non_null (allow_methods);
1077   GNUNET_free (api);
1078   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1079               "Identity Token REST plugin is finished\n");
1080   return NULL;
1081 }
1082
1083 /* end of plugin_rest_gns.c */