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