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