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