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