Merge branch 'master' of gnunet.org:gnunet
[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   const char* exp_str;
550
551   struct RequestHandle *handle = cls;
552   struct EgoEntry *ego_entry;
553   struct MHD_Response *resp;
554   struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute;
555   struct GNUNET_JSONAPI_Document *json_obj;
556   struct GNUNET_JSONAPI_Resource *json_res;
557   struct GNUNET_TIME_Relative exp;
558   char term_data[handle->rest_handle->data_size+1];
559   json_t *value_json;
560   json_t *data_json;
561   json_t *exp_json;
562   json_error_t err;
563   struct GNUNET_JSON_Specification docspec[] = {
564     GNUNET_JSON_spec_jsonapi_document (&json_obj),
565     GNUNET_JSON_spec_end()
566   };
567
568   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
569               handle->url);
570   if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
571        strlen (handle->url))
572   {
573     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
574     GNUNET_SCHEDULER_add_now (&do_error, handle);
575     return;
576   }
577   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
578
579   for (ego_entry = handle->ego_head;
580        NULL != ego_entry;
581        ego_entry = ego_entry->next)
582     if (0 == strcmp (identity, ego_entry->identifier))
583       break;
584
585   if (NULL == ego_entry)
586   {
587     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
588                 "Identity unknown (%s)\n", identity);
589     GNUNET_JSONAPI_document_delete (json_obj);
590     return;
591   }
592   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
593
594   if (0 >= handle->rest_handle->data_size)
595   {
596     GNUNET_SCHEDULER_add_now (&do_error, handle);
597     return;
598   }
599
600   term_data[handle->rest_handle->data_size] = '\0';
601   GNUNET_memcpy (term_data,
602                  handle->rest_handle->data,
603                  handle->rest_handle->data_size);
604   data_json = json_loads (term_data,
605                           JSON_DECODE_ANY,
606                           &err);
607   GNUNET_assert (GNUNET_OK ==
608                  GNUNET_JSON_parse (data_json, docspec,
609                                     NULL, NULL));
610   json_decref (data_json);
611   if (NULL == json_obj)
612   {
613     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
614                 "Unable to parse JSONAPI Object from %s\n",
615                 term_data);
616     GNUNET_SCHEDULER_add_now (&do_error, handle);
617     return;
618   }
619   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
620   {
621     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
622                 "Cannot create more than 1 resource! (Got %d)\n",
623                 GNUNET_JSONAPI_document_resource_count (json_obj));
624     GNUNET_JSONAPI_document_delete (json_obj);
625     GNUNET_SCHEDULER_add_now (&do_error, handle);
626     return;
627   }
628   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
629   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
630                                                        GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
631   {
632     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
633                 "Unsupported JSON data type\n");
634     GNUNET_JSONAPI_document_delete (json_obj);
635     resp = GNUNET_REST_create_response (NULL);
636     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
637     cleanup_handle (handle);
638     return;
639   }
640   name_str = GNUNET_JSONAPI_resource_get_id (json_res);
641   exp_json = GNUNET_JSONAPI_resource_read_attr (json_res,
642                                                 "exp");
643   exp_str = json_string_value (exp_json);
644   if (NULL == exp_str) {
645     exp = GNUNET_TIME_UNIT_HOURS;
646   } else {
647     if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_relative (exp_str,
648                                            &exp)) {
649       exp = GNUNET_TIME_UNIT_HOURS;
650     }
651   }
652
653   value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
654                                                   "value");
655   value_str = json_string_value (value_json);
656   attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str,
657                                                       GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
658                                                       value_str,
659                                                       strlen (value_str) + 1);
660   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
661   handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
662                                                              identity_priv,
663                                                              attribute,
664                                                              &exp,
665                                                              &finished_cont,
666                                                              handle);
667   GNUNET_free (attribute);
668   GNUNET_JSONAPI_document_delete (json_obj);
669 }
670
671
672
673 /**
674  * Collect all attributes for an ego
675  *
676  */
677 static void
678 attr_collect (void *cls,
679               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
680               const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
681 {
682   struct GNUNET_JSONAPI_Resource *json_resource;
683   struct RequestHandle *handle = cls;
684   json_t *value;
685   char* tmp_value;
686   
687   if ((NULL == attr->name) || (NULL == attr->data))
688   {
689     GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
690     return;
691   }
692
693   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
694               attr->name);
695   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
696                                                attr->name);
697   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
698
699   tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type,
700                                            attr->data,
701                                            attr->data_size);
702
703   value = json_string (tmp_value);
704
705   GNUNET_JSONAPI_resource_add_attr (json_resource,
706                                     "value",
707                                     value);
708   json_decref (value);
709   GNUNET_free(tmp_value);
710   GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
711 }
712
713
714
715 /**
716  * List attributes for identity request
717  *
718  * @param con_handle the connection handle
719  * @param url the url
720  * @param cls the RequestHandle
721  */
722 static void
723 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
724                      const char* url,
725                      void *cls)
726 {
727   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
728   struct RequestHandle *handle = cls;
729   struct EgoEntry *ego_entry;
730   char *identity;
731
732   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
733               handle->url);
734   if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
735        strlen (handle->url))
736   {
737     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
738     GNUNET_SCHEDULER_add_now (&do_error, handle);
739     return;
740   }
741   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
742
743   for (ego_entry = handle->ego_head;
744        NULL != ego_entry;
745        ego_entry = ego_entry->next)
746     if (0 == strcmp (identity, ego_entry->identifier))
747       break;
748   handle->resp_object = GNUNET_JSONAPI_document_new ();
749
750
751   if (NULL == ego_entry)
752   {
753     //Done
754     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
755                 identity);
756     GNUNET_SCHEDULER_add_now (&return_response, handle);
757     return;
758   }
759   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
760   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
761   handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
762                                                                    priv_key,
763                                                                    &collect_error_cb,
764                                                                    handle,
765                                                                    &attr_collect,
766                                                                    handle,
767                                                                    &collect_finished_cb,
768                                                                    handle);
769 }
770
771
772 static void
773 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
774                     const char* url,
775                     void *cls)
776 {
777   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
778   const char* identity_str;
779   const char* audience_str;
780   const char* rnd_str;
781
782   struct RequestHandle *handle = cls;
783   struct EgoEntry *ego_entry;
784   struct MHD_Response *resp;
785   struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
786   struct GNUNET_JSONAPI_Document *json_obj;
787   struct GNUNET_JSONAPI_Resource *json_res;
788   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
789   char term_data[handle->rest_handle->data_size+1];
790   json_t *rnd_json;
791   json_t *identity_json;
792   json_t *audience_json;
793   json_t *data_json;
794   json_error_t err;
795   struct GNUNET_JSON_Specification docspec[] = {
796     GNUNET_JSON_spec_jsonapi_document (&json_obj),
797     GNUNET_JSON_spec_end()
798   };
799
800   if (0 >= handle->rest_handle->data_size)
801   {
802     GNUNET_SCHEDULER_add_now (&do_error, handle);
803     return;
804   }
805
806   term_data[handle->rest_handle->data_size] = '\0';
807   GNUNET_memcpy (term_data,
808                  handle->rest_handle->data,
809                  handle->rest_handle->data_size);
810   data_json = json_loads (term_data,
811                           JSON_DECODE_ANY,
812                           &err);
813   GNUNET_assert (GNUNET_OK ==
814                  GNUNET_JSON_parse (data_json, docspec,
815                                     NULL, NULL));
816   json_decref (data_json);
817   if (NULL == json_obj)
818   {
819     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
820                 "Unable to parse JSONAPI Object from %s\n",
821                 term_data);
822     GNUNET_SCHEDULER_add_now (&do_error, handle);
823     return;
824   }
825   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
826   {
827     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
828                 "Cannot create more than 1 resource! (Got %d)\n",
829                 GNUNET_JSONAPI_document_resource_count (json_obj));
830     GNUNET_JSONAPI_document_delete (json_obj);
831     GNUNET_SCHEDULER_add_now (&do_error, handle);
832     return;
833   }
834   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
835   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
836                                                        GNUNET_REST_JSONAPI_IDENTITY_TICKET))
837   {
838     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
839                 "Unsupported JSON data type\n");
840     GNUNET_JSONAPI_document_delete (json_obj);
841     resp = GNUNET_REST_create_response (NULL);
842     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
843     cleanup_handle (handle);
844     return;
845   }
846   rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
847                                                 "rnd");
848   identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
849                                                      "identity");
850   audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
851                                                      "audience");
852   rnd_str = json_string_value (rnd_json);
853   identity_str = json_string_value (identity_json);
854   audience_str = json_string_value (audience_json);
855
856   GNUNET_STRINGS_string_to_data (rnd_str,
857                                  strlen (rnd_str),
858                                  &ticket.rnd,
859                                  sizeof (uint64_t));
860   GNUNET_STRINGS_string_to_data (identity_str,
861                                  strlen (identity_str),
862                                  &ticket.identity,
863                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
864   GNUNET_STRINGS_string_to_data (audience_str,
865                                  strlen (audience_str),
866                                  &ticket.audience,
867                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
868
869   for (ego_entry = handle->ego_head;
870        NULL != ego_entry;
871        ego_entry = ego_entry->next)
872   {
873     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
874                                         &tmp_pk);
875     if (0 == memcmp (&ticket.identity,
876                      &tmp_pk,
877                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
878       break;
879   }
880   if (NULL == ego_entry)
881   {
882     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
883                 "Identity unknown (%s)\n", identity_str);
884     GNUNET_JSONAPI_document_delete (json_obj);
885     return;
886   }
887   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
888
889   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
890   handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
891                                                            identity_priv,
892                                                            &ticket,
893                                                            &finished_cont,
894                                                            handle);
895   GNUNET_JSONAPI_document_delete (json_obj);
896 }
897
898 static void
899 consume_cont (void *cls,
900               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
901               const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
902 {
903   struct RequestHandle *handle = cls;
904   struct GNUNET_JSONAPI_Resource *json_resource;
905   json_t *value;
906
907   if (NULL == identity)
908   {
909     GNUNET_SCHEDULER_add_now (&return_response, handle);
910     return;
911   }
912
913   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
914               attr->name);
915   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
916                                                attr->name);
917   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
918
919   value = json_string (attr->data);
920   GNUNET_JSONAPI_resource_add_attr (json_resource,
921                                     "value",
922                                     value);
923   json_decref (value);
924 }
925
926 static void
927 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
928                      const char* url,
929                      void *cls)
930 {
931   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
932   const char* identity_str;
933   const char* audience_str;
934   const char* rnd_str;
935
936   struct RequestHandle *handle = cls;
937   struct EgoEntry *ego_entry;
938   struct MHD_Response *resp;
939   struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
940   struct GNUNET_JSONAPI_Document *json_obj;
941   struct GNUNET_JSONAPI_Resource *json_res;
942   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
943   char term_data[handle->rest_handle->data_size+1];
944   json_t *rnd_json;
945   json_t *identity_json;
946   json_t *audience_json;
947   json_t *data_json;
948   json_error_t err;
949   struct GNUNET_JSON_Specification docspec[] = {
950     GNUNET_JSON_spec_jsonapi_document (&json_obj),
951     GNUNET_JSON_spec_end()
952   };
953
954   if (0 >= handle->rest_handle->data_size)
955   {
956     GNUNET_SCHEDULER_add_now (&do_error, handle);
957     return;
958   }
959
960   term_data[handle->rest_handle->data_size] = '\0';
961   GNUNET_memcpy (term_data,
962                  handle->rest_handle->data,
963                  handle->rest_handle->data_size);
964   data_json = json_loads (term_data,
965                           JSON_DECODE_ANY,
966                           &err);
967   GNUNET_assert (GNUNET_OK ==
968                  GNUNET_JSON_parse (data_json, docspec,
969                                     NULL, NULL));
970   json_decref (data_json);
971   if (NULL == json_obj)
972   {
973     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
974                 "Unable to parse JSONAPI Object from %s\n",
975                 term_data);
976     GNUNET_SCHEDULER_add_now (&do_error, handle);
977     return;
978   }
979   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
980   {
981     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
982                 "Cannot create more than 1 resource! (Got %d)\n",
983                 GNUNET_JSONAPI_document_resource_count (json_obj));
984     GNUNET_JSONAPI_document_delete (json_obj);
985     GNUNET_SCHEDULER_add_now (&do_error, handle);
986     return;
987   }
988   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
989   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
990                                                        GNUNET_REST_JSONAPI_IDENTITY_TICKET))
991   {
992     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
993                 "Unsupported JSON data type\n");
994     GNUNET_JSONAPI_document_delete (json_obj);
995     resp = GNUNET_REST_create_response (NULL);
996     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
997     cleanup_handle (handle);
998     return;
999   }
1000   rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1001                                                 "rnd");
1002   identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1003                                                      "identity");
1004   audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1005                                                      "audience");
1006   rnd_str = json_string_value (rnd_json);
1007   identity_str = json_string_value (identity_json);
1008   audience_str = json_string_value (audience_json);
1009
1010   GNUNET_STRINGS_string_to_data (rnd_str,
1011                                  strlen (rnd_str),
1012                                  &ticket.rnd,
1013                                  sizeof (uint64_t));
1014   GNUNET_STRINGS_string_to_data (identity_str,
1015                                  strlen (identity_str),
1016                                  &ticket.identity,
1017                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1018   GNUNET_STRINGS_string_to_data (audience_str,
1019                                  strlen (audience_str),
1020                                  &ticket.audience,
1021                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1022
1023   for (ego_entry = handle->ego_head;
1024        NULL != ego_entry;
1025        ego_entry = ego_entry->next)
1026   {
1027     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1028                                         &tmp_pk);
1029     if (0 == memcmp (&ticket.audience,
1030                      &tmp_pk,
1031                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1032       break;
1033   }
1034   if (NULL == ego_entry)
1035   {
1036     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1037                 "Identity unknown (%s)\n", identity_str);
1038     GNUNET_JSONAPI_document_delete (json_obj);
1039     return;
1040   }
1041   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1042   handle->resp_object = GNUNET_JSONAPI_document_new ();
1043   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1044   handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
1045                                                             identity_priv,
1046                                                             &ticket,
1047                                                             &consume_cont,
1048                                                             handle);
1049   GNUNET_JSONAPI_document_delete (json_obj);
1050 }
1051
1052
1053
1054 /**
1055  * Respond to OPTIONS request
1056  *
1057  * @param con_handle the connection handle
1058  * @param url the url
1059  * @param cls the RequestHandle
1060  */
1061 static void
1062 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1063               const char* url,
1064               void *cls)
1065 {
1066   struct MHD_Response *resp;
1067   struct RequestHandle *handle = cls;
1068
1069   //For now, independent of path return all options
1070   resp = GNUNET_REST_create_response (NULL);
1071   MHD_add_response_header (resp,
1072                            "Access-Control-Allow-Methods",
1073                            allow_methods);
1074   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1075   cleanup_handle (handle);
1076   return;
1077 }
1078
1079 /**
1080  * Handle rest request
1081  *
1082  * @param handle the request handle
1083  */
1084 static void
1085 init_cont (struct RequestHandle *handle)
1086 {
1087   struct GNUNET_REST_RequestHandlerError err;
1088   static const struct GNUNET_REST_RequestHandler handlers[] = {
1089     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
1090     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
1091     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
1092     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1093     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1094     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
1095       &options_cont},
1096     GNUNET_REST_HANDLER_END
1097   };
1098
1099   if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1100                                                handlers,
1101                                                &err,
1102                                                handle))
1103   {
1104     handle->response_code = err.error_code;
1105     GNUNET_SCHEDULER_add_now (&do_error, handle);
1106   }
1107 }
1108
1109 /**
1110  * If listing is enabled, prints information about the egos.
1111  *
1112  * This function is initially called for all egos and then again
1113  * whenever a ego's identifier changes or if it is deleted.  At the
1114  * end of the initial pass over all egos, the function is once called
1115  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1116  * be invoked in the future or that there was an error.
1117  *
1118  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1119  * this function is only called ONCE, and 'NULL' being passed in
1120  * 'ego' does indicate an error (i.e. name is taken or no default
1121  * value is known).  If 'ego' is non-NULL and if '*ctx'
1122  * is set in those callbacks, the value WILL be passed to a subsequent
1123  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1124  * that one was not NULL).
1125  *
1126  * When an identity is renamed, this function is called with the
1127  * (known) ego but the NEW identifier.
1128  *
1129  * When an identity is deleted, this function is called with the
1130  * (known) ego and "NULL" for the 'identifier'.  In this case,
1131  * the 'ego' is henceforth invalid (and the 'ctx' should also be
1132  * cleaned up).
1133  *
1134  * @param cls closure
1135  * @param ego ego handle
1136  * @param ctx context for application to store data for this ego
1137  *                 (during the lifetime of this process, initially NULL)
1138  * @param identifier identifier assigned by the user for this ego,
1139  *                   NULL if the user just deleted the ego and it
1140  *                   must thus no longer be used
1141  */
1142 static void
1143 list_ego (void *cls,
1144           struct GNUNET_IDENTITY_Ego *ego,
1145           void **ctx,
1146           const char *identifier)
1147 {
1148   struct RequestHandle *handle = cls;
1149   struct EgoEntry *ego_entry;
1150   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1151
1152   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1153   {
1154     handle->state = ID_REST_STATE_POST_INIT;
1155     init_cont (handle);
1156     return;
1157   }
1158   if (ID_REST_STATE_INIT == handle->state) {
1159     ego_entry = GNUNET_new (struct EgoEntry);
1160     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1161     ego_entry->keystring =
1162       GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1163     ego_entry->ego = ego;
1164     ego_entry->identifier = GNUNET_strdup (identifier);
1165     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1166   }
1167
1168 }
1169
1170 static void
1171 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1172                               GNUNET_REST_ResultProcessor proc,
1173                               void *proc_cls)
1174 {
1175   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1176   handle->response_code = 0;
1177   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1178   handle->proc_cls = proc_cls;
1179   handle->proc = proc;
1180   handle->state = ID_REST_STATE_INIT;
1181   handle->rest_handle = rest_handle;
1182
1183   handle->url = GNUNET_strdup (rest_handle->url);
1184   if (handle->url[strlen (handle->url)-1] == '/')
1185     handle->url[strlen (handle->url)-1] = '\0';
1186   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1187               "Connecting...\n");
1188   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1189                                                      &list_ego,
1190                                                      handle);
1191   handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
1192   handle->timeout_task =
1193     GNUNET_SCHEDULER_add_delayed (handle->timeout,
1194                                   &do_timeout,
1195                                   handle);
1196   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1197               "Connected\n");
1198 }
1199
1200 /**
1201  * Entry point for the plugin.
1202  *
1203  * @param cls Config info
1204  * @return NULL on error, otherwise the plugin context
1205  */
1206 void *
1207 libgnunet_plugin_rest_identity_provider_init (void *cls)
1208 {
1209   static struct Plugin plugin;
1210   struct GNUNET_REST_Plugin *api;
1211
1212   cfg = cls;
1213   if (NULL != plugin.cfg)
1214     return NULL;                /* can only initialize once! */
1215   memset (&plugin, 0, sizeof (struct Plugin));
1216   plugin.cfg = cfg;
1217   api = GNUNET_new (struct GNUNET_REST_Plugin);
1218   api->cls = &plugin;
1219   api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1220   api->process_request = &rest_identity_process_request;
1221   GNUNET_asprintf (&allow_methods,
1222                    "%s, %s, %s, %s, %s",
1223                    MHD_HTTP_METHOD_GET,
1224                    MHD_HTTP_METHOD_POST,
1225                    MHD_HTTP_METHOD_PUT,
1226                    MHD_HTTP_METHOD_DELETE,
1227                    MHD_HTTP_METHOD_OPTIONS);
1228
1229   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1230               _("Identity Provider REST API initialized\n"));
1231   return api;
1232 }
1233
1234
1235 /**
1236  * Exit point from the plugin.
1237  *
1238  * @param cls the plugin context (as returned by "init")
1239  * @return always NULL
1240  */
1241 void *
1242 libgnunet_plugin_rest_identity_provider_done (void *cls)
1243 {
1244   struct GNUNET_REST_Plugin *api = cls;
1245   struct Plugin *plugin = api->cls;
1246   plugin->cfg = NULL;
1247
1248   GNUNET_free_non_null (allow_methods);
1249   GNUNET_free (api);
1250   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1251               "Identity Provider REST plugin is finished\n");
1252   return NULL;
1253 }
1254
1255 /* end of plugin_rest_identity_provider.c */