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