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