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