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