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