-wip post request testing required and namestore handle fix required
[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  * Login namespace
75  */
76 #define GNUNET_REST_API_NS_LOGIN "/idp/login"
77
78 /**
79  * Attribute key
80  */
81 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
82
83 /**
84  * Ticket key
85  */
86 #define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
87
88
89 /**
90  * Value key
91  */
92 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value"
93
94 /**
95  * State while collecting all egos
96  */
97 #define ID_REST_STATE_INIT 0
98
99 /**
100  * Done collecting egos
101  */
102 #define ID_REST_STATE_POST_INIT 1
103
104 /**
105  * OIDC response_type key
106  */
107 #define OIDC_RESPONSE_TYPE_KEY "response_type"
108
109 /**
110  * OIDC client_id key
111  */
112 #define OIDC_CLIENT_ID_KEY "client_id"
113
114 /**
115  * OIDC scope key
116  */
117 #define OIDC_SCOPE_KEY "scope"
118
119 /**
120  * OIDC redirect_uri key
121  */
122 #define OIDC_REDIRECT_URI_KEY "redirect_uri"
123
124 /**
125  * OIDC state key
126  */
127 #define OIDC_STATE_KEY "state"
128
129 /**
130  * OIDC nonce key
131  */
132 #define OIDC_NONCE_KEY "nonce"
133
134 /**
135  * OIDC cookie header key
136  */
137 #define OIDC_COOKIE_HEADER_KEY "Cookie"
138
139 /**
140  * OIDC cookie header information key
141  */
142 #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
143
144 /**
145  * OIDC expected response_type while authorizing
146  */
147 #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
148
149 /**
150  * OIDC expected scope part while authorizing
151  */
152 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
153 /**
154  * OIDC ignored parameter array
155  */
156 char* OIDC_ignored_parameter_array [] =
157 {
158   "display",
159   "prompt",
160   "max_age",
161   "ui_locales", 
162   "response_mode",
163   "id_token_hint",
164   "login_hint", 
165   "acr_values"
166 };
167
168 /**
169  * OIDC authorized identities and times hashmap
170  */
171 struct GNUNET_CONTAINER_MultiHashMap *OIDC_authorized_identities;
172
173 /**
174  * The configuration handle
175  */
176 const struct GNUNET_CONFIGURATION_Handle *cfg;
177
178 /**
179  * HTTP methods allows for this plugin
180  */
181 static char* allow_methods;
182
183 /**
184  * @brief struct returned by the initialization function of the plugin
185  */
186 struct Plugin
187 {
188   const struct GNUNET_CONFIGURATION_Handle *cfg;
189 };
190
191 /**
192  * The ego list
193  */
194 struct EgoEntry
195 {
196   /**
197    * DLL
198    */
199   struct EgoEntry *next;
200
201   /**
202    * DLL
203    */
204   struct EgoEntry *prev;
205
206   /**
207    * Ego Identifier
208    */
209   char *identifier;
210
211   /**
212    * Public key string
213    */
214   char *keystring;
215
216   /**
217    * The Ego
218    */
219   struct GNUNET_IDENTITY_Ego *ego;
220 };
221
222
223 struct RequestHandle
224 {
225   /**
226    * Ego list
227    */
228   struct EgoEntry *ego_head;
229
230   /**
231    * Ego list
232    */
233   struct EgoEntry *ego_tail;
234
235   /**
236    * Selected ego
237    */
238   struct EgoEntry *ego_entry;
239
240   /**
241    * Ptr to current ego private key
242    */
243   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
244
245   /**
246    * The processing state
247    */
248   int state;
249
250   /**
251    * Handle to Identity service.
252    */
253   struct GNUNET_IDENTITY_Handle *identity_handle;
254
255   /**
256    * Rest connection
257    */
258   struct GNUNET_REST_RequestHandle *rest_handle;
259
260   /**
261    * Zone connection
262    */
263   struct GNUNET_NAMESTORE_Handle *namestore_handle;
264
265   /**
266    * IDENTITY Operation
267    */
268   struct GNUNET_IDENTITY_Operation *op;
269
270   /**
271    * Identity Provider
272    */
273   struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
274
275   /**
276    * Idp Operation
277    */
278   struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
279
280   /**
281    * Attribute iterator
282    */
283   struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it;
284
285   /**
286    * Ticket iterator
287    */
288   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it;
289
290   /**
291    * Desired timeout for the lookup (default is no timeout).
292    */
293   struct GNUNET_TIME_Relative timeout;
294
295   /**
296    * ID of a task associated with the resolution process.
297    */
298   struct GNUNET_SCHEDULER_Task *timeout_task;
299
300   /**
301    * The plugin result processor
302    */
303   GNUNET_REST_ResultProcessor proc;
304
305   /**
306    * The closure of the result processor
307    */
308   void *proc_cls;
309
310   /**
311    * The url
312    */
313   char *url;
314
315   /**
316    * Error response message
317    */
318   char *emsg;
319
320   /**
321    * Error response uri
322    */
323   char *eredirect;
324
325   /**
326    * Error response description
327    */
328   char *edesc;
329
330   /**
331    * Reponse code
332    */
333   int response_code;
334
335   /**
336    * Response object
337    */
338   struct GNUNET_JSONAPI_Document *resp_object;
339
340 };
341
342
343
344 /**
345  * Cleanup lookup handle
346  * @param handle Handle to clean up
347  */
348 static void
349 cleanup_handle (struct RequestHandle *handle)
350 {
351   struct EgoEntry *ego_entry;
352   struct EgoEntry *ego_tmp;
353   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
354               "Cleaning up\n");
355   if (NULL != handle->resp_object)
356     GNUNET_JSONAPI_document_delete (handle->resp_object);
357   if (NULL != handle->timeout_task)
358     GNUNET_SCHEDULER_cancel (handle->timeout_task);
359   if (NULL != handle->identity_handle)
360     GNUNET_IDENTITY_disconnect (handle->identity_handle);
361   if (NULL != handle->attr_it)
362     GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it);
363   if (NULL != handle->ticket_it)
364     GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it);
365   if (NULL != handle->idp)
366     GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
367   if (NULL != handle->url)
368     GNUNET_free (handle->url);
369   if (NULL != handle->emsg)
370     GNUNET_free (handle->emsg);
371   if (NULL != handle->edesc)
372     GNUNET_free (handle->edesc);
373   if (NULL != handle->eredirect)
374     GNUNET_free (handle->eredirect);
375   for (ego_entry = handle->ego_head;
376        NULL != ego_entry;)
377   {
378     ego_tmp = ego_entry;
379     ego_entry = ego_entry->next;
380     GNUNET_free (ego_tmp->identifier);
381     GNUNET_free (ego_tmp->keystring);
382     GNUNET_free (ego_tmp);
383   }
384   GNUNET_free (handle);
385 }
386
387 static void
388 cleanup_handle_delayed (void *cls)
389 {
390   cleanup_handle (cls);
391 }
392
393
394 /**
395  * Task run on error, sends error message.  Cleans up everything.
396  *
397  * @param cls the `struct RequestHandle`
398  */
399 static void
400 do_error (void *cls)
401 {
402   struct RequestHandle *handle = cls;
403   struct MHD_Response *resp;
404   char *json_error;
405
406   GNUNET_asprintf (&json_error,
407                    "{error : %s}",
408                    handle->emsg);
409   resp = GNUNET_REST_create_response (json_error);
410   handle->proc (handle->proc_cls, resp, handle->response_code);
411   cleanup_handle (handle);
412   GNUNET_free (json_error);
413 }
414
415 /**
416  * Task run on error, sends error message.  Cleans up everything.
417  *
418  * @param cls the `struct RequestHandle`
419  */
420 static void
421 do_redirect_error (void *cls)
422 {
423   struct RequestHandle *handle = cls;
424   struct MHD_Response *resp;
425   char* redirect;
426   //TODO handle->url is wrong
427   GNUNET_asprintf (&redirect,
428                    "%s?error=%s&error_description=%s",
429                    handle->eredirect, handle->emsg, handle->edesc );
430   resp = GNUNET_REST_create_response ("");
431   MHD_add_response_header (resp, "Location", redirect);
432   handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
433   cleanup_handle (handle);
434   GNUNET_free (redirect);
435 }
436
437 /**
438  * Task run on timeout, sends error message.  Cleans up everything.
439  *
440  * @param cls the `struct RequestHandle`
441  */
442 static void
443 do_timeout (void *cls)
444 {
445   struct RequestHandle *handle = cls;
446
447   handle->timeout_task = NULL;
448   do_error (handle);
449 }
450
451
452 static void
453 collect_error_cb (void *cls)
454 {
455   struct RequestHandle *handle = cls;
456
457   do_error (handle);
458 }
459
460 static void
461 finished_cont (void *cls,
462                int32_t success,
463                const char *emsg)
464 {
465   struct RequestHandle *handle = cls;
466   struct MHD_Response *resp;
467
468   resp = GNUNET_REST_create_response (emsg);
469   if (GNUNET_OK != success)
470   {
471     GNUNET_SCHEDULER_add_now (&do_error, handle);
472     return;
473   }
474   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
475   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
476 }
477
478
479 /**
480  * Return attributes for identity
481  *
482  * @param cls the request handle
483  */
484 static void
485 return_response (void *cls)
486 {
487   char* result_str;
488   struct RequestHandle *handle = cls;
489   struct MHD_Response *resp;
490
491   GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
492   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
493   resp = GNUNET_REST_create_response (result_str);
494   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
495   GNUNET_free (result_str);
496   cleanup_handle (handle);
497 }
498
499
500 static void
501 collect_finished_cb (void *cls)
502 {
503   struct RequestHandle *handle = cls;
504   //Done
505   handle->attr_it = NULL;
506   handle->ticket_it = NULL;
507   GNUNET_SCHEDULER_add_now (&return_response, handle);
508 }
509
510
511 /**
512  * Collect all attributes for an ego
513  *
514  */
515 static void
516 ticket_collect (void *cls,
517                 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
518 {
519   struct GNUNET_JSONAPI_Resource *json_resource;
520   struct RequestHandle *handle = cls;
521   json_t *value;
522   char* tmp;
523
524   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
525   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
526                                              sizeof (uint64_t));
527   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
528                                                        tmp);
529   GNUNET_free (tmp);
530   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
531
532   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
533                                              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
534   value = json_string (tmp);
535   GNUNET_JSONAPI_resource_add_attr (json_resource,
536                                     "issuer",
537                                     value);
538   GNUNET_free (tmp);
539   json_decref (value);
540   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
541                                              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
542   value = json_string (tmp);
543   GNUNET_JSONAPI_resource_add_attr (json_resource,
544                                     "audience",
545                                     value);
546   GNUNET_free (tmp);
547   json_decref (value);
548   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
549                                              sizeof (uint64_t));
550   value = json_string (tmp);
551   GNUNET_JSONAPI_resource_add_attr (json_resource,
552                                     "rnd",
553                                     value);
554   GNUNET_free (tmp);
555   json_decref (value);
556   GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it);
557 }
558
559
560
561 /**
562  * List tickets for identity request
563  *
564  * @param con_handle the connection handle
565  * @param url the url
566  * @param cls the RequestHandle
567  */
568 static void
569 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
570                    const char* url,
571                    void *cls)
572 {
573   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
574   struct RequestHandle *handle = cls;
575   struct EgoEntry *ego_entry;
576   char *identity;
577
578   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
579               handle->url);
580   if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
581        strlen (handle->url))
582   {
583     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
584     GNUNET_SCHEDULER_add_now (&do_error, handle);
585     return;
586   }
587   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
588
589   for (ego_entry = handle->ego_head;
590        NULL != ego_entry;
591        ego_entry = ego_entry->next)
592     if (0 == strcmp (identity, ego_entry->identifier))
593       break;
594   handle->resp_object = GNUNET_JSONAPI_document_new ();
595
596   if (NULL == ego_entry)
597   {
598     //Done
599     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
600                 identity);
601     GNUNET_SCHEDULER_add_now (&return_response, handle);
602     return;
603   }
604   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
605   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
606   handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp,
607                                                                        priv_key,
608                                                                        &collect_error_cb,
609                                                                        handle,
610                                                                        &ticket_collect,
611                                                                        handle,
612                                                                        &collect_finished_cb,
613                                                                        handle);
614 }
615
616
617 static void
618 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
619                     const char* url,
620                     void *cls)
621 {
622   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
623   const char* identity;
624   const char* name_str;
625   const char* value_str;
626
627   struct RequestHandle *handle = cls;
628   struct EgoEntry *ego_entry;
629   struct MHD_Response *resp;
630   struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute;
631   struct GNUNET_JSONAPI_Document *json_obj;
632   struct GNUNET_JSONAPI_Resource *json_res;
633   char term_data[handle->rest_handle->data_size+1];
634   json_t *value_json;
635   json_t *data_json;
636   json_error_t err;
637   struct GNUNET_JSON_Specification docspec[] = {
638     GNUNET_JSON_spec_jsonapi_document (&json_obj),
639     GNUNET_JSON_spec_end()
640   };
641
642   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
643               handle->url);
644   if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
645        strlen (handle->url))
646   {
647     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
648     GNUNET_SCHEDULER_add_now (&do_error, handle);
649     return;
650   }
651   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
652
653   for (ego_entry = handle->ego_head;
654        NULL != ego_entry;
655        ego_entry = ego_entry->next)
656     if (0 == strcmp (identity, ego_entry->identifier))
657       break;
658
659   if (NULL == ego_entry)
660   {
661     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
662                 "Identity unknown (%s)\n", identity);
663     GNUNET_JSONAPI_document_delete (json_obj);
664     return;
665   }
666   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
667
668   if (0 >= handle->rest_handle->data_size)
669   {
670     GNUNET_SCHEDULER_add_now (&do_error, handle);
671     return;
672   }
673
674   term_data[handle->rest_handle->data_size] = '\0';
675   GNUNET_memcpy (term_data,
676                  handle->rest_handle->data,
677                  handle->rest_handle->data_size);
678   data_json = json_loads (term_data,
679                           JSON_DECODE_ANY,
680                           &err);
681   GNUNET_assert (GNUNET_OK ==
682                  GNUNET_JSON_parse (data_json, docspec,
683                                     NULL, NULL));
684   json_decref (data_json);
685   if (NULL == json_obj)
686   {
687     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
688                 "Unable to parse JSONAPI Object from %s\n",
689                 term_data);
690     GNUNET_SCHEDULER_add_now (&do_error, handle);
691     return;
692   }
693   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
694   {
695     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
696                 "Cannot create more than 1 resource! (Got %d)\n",
697                 GNUNET_JSONAPI_document_resource_count (json_obj));
698     GNUNET_JSONAPI_document_delete (json_obj);
699     GNUNET_SCHEDULER_add_now (&do_error, handle);
700     return;
701   }
702   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
703   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
704                                                        GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
705   {
706     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
707                 "Unsupported JSON data type\n");
708     GNUNET_JSONAPI_document_delete (json_obj);
709     resp = GNUNET_REST_create_response (NULL);
710     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
711     cleanup_handle (handle);
712     return;
713   }
714   name_str = GNUNET_JSONAPI_resource_get_id (json_res);
715   value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
716                                                   "value");
717   value_str = json_string_value (value_json);
718   attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str,
719                                                       GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
720                                                       value_str,
721                                                       strlen (value_str) + 1);
722   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
723   handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
724                                                              identity_priv,
725                                                              attribute,
726                                                              &finished_cont,
727                                                              handle);
728   GNUNET_free (attribute);
729   GNUNET_JSONAPI_document_delete (json_obj);
730 }
731
732
733
734 /**
735  * Collect all attributes for an ego
736  *
737  */
738 static void
739 attr_collect (void *cls,
740               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
741               const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
742 {
743   struct GNUNET_JSONAPI_Resource *json_resource;
744   struct RequestHandle *handle = cls;
745   json_t *value;
746   
747   if ((NULL == attr->name) || (NULL == attr->data))
748   {
749     GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
750     return;
751   }
752
753   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
754               attr->name);
755   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
756                                                attr->name);
757   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
758
759   value = json_string (attr->data);
760   GNUNET_JSONAPI_resource_add_attr (json_resource,
761                                     "value",
762                                     value);
763   json_decref (value);
764   GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
765 }
766
767
768
769 /**
770  * List attributes for identity request
771  *
772  * @param con_handle the connection handle
773  * @param url the url
774  * @param cls the RequestHandle
775  */
776 static void
777 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
778                      const char* url,
779                      void *cls)
780 {
781   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
782   struct RequestHandle *handle = cls;
783   struct EgoEntry *ego_entry;
784   char *identity;
785
786   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
787               handle->url);
788   if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
789        strlen (handle->url))
790   {
791     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
792     GNUNET_SCHEDULER_add_now (&do_error, handle);
793     return;
794   }
795   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
796
797   for (ego_entry = handle->ego_head;
798        NULL != ego_entry;
799        ego_entry = ego_entry->next)
800     if (0 == strcmp (identity, ego_entry->identifier))
801       break;
802   handle->resp_object = GNUNET_JSONAPI_document_new ();
803
804
805   if (NULL == ego_entry)
806   {
807     //Done
808     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
809                 identity);
810     GNUNET_SCHEDULER_add_now (&return_response, handle);
811     return;
812   }
813   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
814   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
815   handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
816                                                                    priv_key,
817                                                                    &collect_error_cb,
818                                                                    handle,
819                                                                    &attr_collect,
820                                                                    handle,
821                                                                    &collect_finished_cb,
822                                                                    handle);
823 }
824
825
826 static void
827 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
828                     const char* url,
829                     void *cls)
830 {
831   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
832   const char* identity_str;
833   const char* audience_str;
834   const char* rnd_str;
835
836   struct RequestHandle *handle = cls;
837   struct EgoEntry *ego_entry;
838   struct MHD_Response *resp;
839   struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
840   struct GNUNET_JSONAPI_Document *json_obj;
841   struct GNUNET_JSONAPI_Resource *json_res;
842   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
843   char term_data[handle->rest_handle->data_size+1];
844   json_t *rnd_json;
845   json_t *identity_json;
846   json_t *audience_json;
847   json_t *data_json;
848   json_error_t err;
849   struct GNUNET_JSON_Specification docspec[] = {
850     GNUNET_JSON_spec_jsonapi_document (&json_obj),
851     GNUNET_JSON_spec_end()
852   };
853
854   if (0 >= handle->rest_handle->data_size)
855   {
856     GNUNET_SCHEDULER_add_now (&do_error, handle);
857     return;
858   }
859
860   term_data[handle->rest_handle->data_size] = '\0';
861   GNUNET_memcpy (term_data,
862                  handle->rest_handle->data,
863                  handle->rest_handle->data_size);
864   data_json = json_loads (term_data,
865                           JSON_DECODE_ANY,
866                           &err);
867   GNUNET_assert (GNUNET_OK ==
868                  GNUNET_JSON_parse (data_json, docspec,
869                                     NULL, NULL));
870   json_decref (data_json);
871   if (NULL == json_obj)
872   {
873     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
874                 "Unable to parse JSONAPI Object from %s\n",
875                 term_data);
876     GNUNET_SCHEDULER_add_now (&do_error, handle);
877     return;
878   }
879   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
880   {
881     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
882                 "Cannot create more than 1 resource! (Got %d)\n",
883                 GNUNET_JSONAPI_document_resource_count (json_obj));
884     GNUNET_JSONAPI_document_delete (json_obj);
885     GNUNET_SCHEDULER_add_now (&do_error, handle);
886     return;
887   }
888   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
889   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
890                                                        GNUNET_REST_JSONAPI_IDENTITY_TICKET))
891   {
892     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
893                 "Unsupported JSON data type\n");
894     GNUNET_JSONAPI_document_delete (json_obj);
895     resp = GNUNET_REST_create_response (NULL);
896     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
897     cleanup_handle (handle);
898     return;
899   }
900   rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
901                                                 "rnd");
902   identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
903                                                      "identity");
904   audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
905                                                      "audience");
906   rnd_str = json_string_value (rnd_json);
907   identity_str = json_string_value (identity_json);
908   audience_str = json_string_value (audience_json);
909
910   GNUNET_STRINGS_string_to_data (rnd_str,
911                                  strlen (rnd_str),
912                                  &ticket.rnd,
913                                  sizeof (uint64_t));
914 //  GNUNET_STRINGS_string_to_data (identity_str,
915 //                                 strlen (identity_str),
916 //                                 &ticket.identity,type filter text
917 //                                 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
918   GNUNET_STRINGS_string_to_data (audience_str,
919                                  strlen (audience_str),
920                                  &ticket.audience,
921                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
922
923   for (ego_entry = handle->ego_head;
924        NULL != ego_entry;
925        ego_entry = ego_entry->next)
926   {
927     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
928                                         &tmp_pk);
929     if (0 == memcmp (&ticket.identity,
930                      &tmp_pk,
931                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
932       break;
933   }
934   if (NULL == ego_entry)
935   {
936     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
937                 "Identity unknown (%s)\n", identity_str);
938     GNUNET_JSONAPI_document_delete (json_obj);
939     return;
940   }
941   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
942
943   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
944   handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
945                                                            identity_priv,
946                                                            &ticket,
947                                                            &finished_cont,
948                                                            handle);
949   GNUNET_JSONAPI_document_delete (json_obj);
950 }
951
952 static void
953 consume_cont (void *cls,
954               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
955               const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
956 {
957   struct RequestHandle *handle = cls;
958   struct GNUNET_JSONAPI_Resource *json_resource;
959   json_t *value;
960
961   if (NULL == identity)
962   {
963     GNUNET_SCHEDULER_add_now (&return_response, handle);
964     return;
965   }
966
967   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
968               attr->name);
969   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
970                                                attr->name);
971   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
972
973   value = json_string (attr->data);
974   GNUNET_JSONAPI_resource_add_attr (json_resource,
975                                     "value",
976                                     value);
977   json_decref (value);
978 }
979
980 static void
981 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
982                      const char* url,
983                      void *cls)
984 {
985   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
986   const char* identity_str;
987   const char* audience_str;
988   const char* rnd_str;
989
990   struct RequestHandle *handle = cls;
991   struct EgoEntry *ego_entry;
992   struct MHD_Response *resp;
993   struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
994   struct GNUNET_JSONAPI_Document *json_obj;
995   struct GNUNET_JSONAPI_Resource *json_res;
996   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
997   char term_data[handle->rest_handle->data_size+1];
998   json_t *rnd_json;
999   json_t *identity_json;
1000   json_t *audience_json;
1001   json_t *data_json;
1002   json_error_t err;
1003   struct GNUNET_JSON_Specification docspec[] = {
1004     GNUNET_JSON_spec_jsonapi_document (&json_obj),
1005     GNUNET_JSON_spec_end()
1006   };
1007
1008   if (0 >= handle->rest_handle->data_size)
1009   {
1010     GNUNET_SCHEDULER_add_now (&do_error, handle);
1011     return;
1012   }
1013
1014   term_data[handle->rest_handle->data_size] = '\0';
1015   GNUNET_memcpy (term_data,
1016                  handle->rest_handle->data,
1017                  handle->rest_handle->data_size);
1018   data_json = json_loads (term_data,
1019                           JSON_DECODE_ANY,
1020                           &err);
1021   GNUNET_assert (GNUNET_OK ==
1022                  GNUNET_JSON_parse (data_json, docspec,
1023                                     NULL, NULL));
1024   json_decref (data_json);
1025   if (NULL == json_obj)
1026   {
1027     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1028                 "Unable to parse JSONAPI Object from %s\n",
1029                 term_data);
1030     GNUNET_SCHEDULER_add_now (&do_error, handle);
1031     return;
1032   }
1033   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
1034   {
1035     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1036                 "Cannot create more than 1 resource! (Got %d)\n",
1037                 GNUNET_JSONAPI_document_resource_count (json_obj));
1038     GNUNET_JSONAPI_document_delete (json_obj);
1039     GNUNET_SCHEDULER_add_now (&do_error, handle);
1040     return;
1041   }
1042   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
1043   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
1044                                                        GNUNET_REST_JSONAPI_IDENTITY_TICKET))
1045   {
1046     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1047                 "Unsupported JSON data type\n");
1048     GNUNET_JSONAPI_document_delete (json_obj);
1049     resp = GNUNET_REST_create_response (NULL);
1050     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
1051     cleanup_handle (handle);
1052     return;
1053   }
1054   rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1055                                                 "rnd");
1056   identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1057                                                      "identity");
1058   audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1059                                                      "audience");
1060   rnd_str = json_string_value (rnd_json);
1061   identity_str = json_string_value (identity_json);
1062   audience_str = json_string_value (audience_json);
1063
1064   GNUNET_STRINGS_string_to_data (rnd_str,
1065                                  strlen (rnd_str),
1066                                  &ticket.rnd,
1067                                  sizeof (uint64_t));
1068   GNUNET_STRINGS_string_to_data (identity_str,
1069                                  strlen (identity_str),
1070                                  &ticket.identity,
1071                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1072   GNUNET_STRINGS_string_to_data (audience_str,
1073                                  strlen (audience_str),
1074                                  &ticket.audience,
1075                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1076
1077   for (ego_entry = handle->ego_head;
1078        NULL != ego_entry;
1079        ego_entry = ego_entry->next)
1080   {
1081     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1082                                         &tmp_pk);
1083     if (0 == memcmp (&ticket.audience,
1084                      &tmp_pk,
1085                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1086       break;
1087   }
1088   if (NULL == ego_entry)
1089   {
1090     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1091                 "Identity unknown (%s)\n", identity_str);
1092     GNUNET_JSONAPI_document_delete (json_obj);
1093     return;
1094   }
1095   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1096   handle->resp_object = GNUNET_JSONAPI_document_new ();
1097   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1098   handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
1099                                                             identity_priv,
1100                                                             &ticket,
1101                                                             &consume_cont,
1102                                                             handle);
1103   GNUNET_JSONAPI_document_delete (json_obj);
1104 }
1105
1106
1107
1108 /**
1109  * Respond to OPTIONS request
1110  *
1111  * @param con_handle the connection handle
1112  * @param url the url
1113  * @param cls the RequestHandle
1114  */
1115 static void
1116 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1117               const char* url,
1118               void *cls)
1119 {
1120   struct MHD_Response *resp;
1121   struct RequestHandle *handle = cls;
1122
1123   //For now, independent of path return all options
1124   resp = GNUNET_REST_create_response (NULL);
1125   MHD_add_response_header (resp,
1126                            "Access-Control-Allow-Methods",
1127                            allow_methods);
1128   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1129   cleanup_handle (handle);
1130   return;
1131 }
1132
1133 /**
1134  * Function called if we had an error in zone-to-name mapping.
1135  */
1136 static void
1137 zone_to_name_error (void *cls)
1138 {
1139   struct RequestHandle *handle = cls;
1140
1141   handle->emsg = GNUNET_strdup("unauthorized_client");
1142   handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1143
1144   GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
1145   handle->namestore_handle = NULL;
1146   GNUNET_SCHEDULER_add_now (&do_error, handle);
1147 }
1148
1149 /**
1150  * Test if a name mapping was found, if so, continue, else, throw error
1151  *
1152  * @param cls closure
1153  * @param zone_key public key of the zone
1154  * @param name name that is being mapped (at most 255 characters long)
1155  * @param rd_count number of entries in @a rd array
1156  * @param rd array of records with data to store
1157  */
1158 static void
1159 zone_to_name_get_cb (void *cls,
1160                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1161                  const char *name,
1162                  unsigned int rd_count,
1163                  const struct GNUNET_GNSRECORD_Data *rd)
1164 {
1165   struct RequestHandle *handle = cls;
1166
1167
1168   if (0 == rd_count)
1169   {
1170     handle->emsg = GNUNET_strdup("unauthorized_client");
1171     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1172
1173     GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
1174     handle->namestore_handle = NULL;
1175     GNUNET_SCHEDULER_add_now (&do_error, handle);
1176     return;
1177   }
1178 }
1179
1180 /**
1181  * Respond to authorization GET request
1182  *
1183  * @param con_handle the connection handle
1184  * @param url the url
1185  * @param cls the RequestHandle
1186  */
1187 static void
1188 authorize_get_cont (struct GNUNET_REST_RequestHandle *con_handle,
1189                 const char* url,
1190                 void *cls)
1191 {
1192     /** The Authorization Server MUST validate all the OAuth 2.0 parameters
1193    *    according to the OAuth 2.0 specification.
1194    */
1195   /**
1196    *    If the sub (subject) Claim is requested with a specific value for the
1197    *    ID Token, the Authorization Server MUST only send a positive response
1198    *    if the End-User identified by that sub value has an active session with
1199    *    the Authorization Server or has been Authenticated as a result of the
1200    *    request. The Authorization Server MUST NOT reply with an ID Token or
1201    *    Access Token for a different user, even if they have an active session
1202    *    with the Authorization Server. Such a request can be made either using
1203    *    an id_token_hint parameter or by requesting a specific Claim Value as
1204    *    described in Section 5.5.1, if the claims parameter is supported by
1205    *    the implementation.
1206    */
1207
1208   struct MHD_Response *resp;
1209   struct RequestHandle *handle = cls;
1210   char *response_type;
1211   char *client_id;
1212   char *scope;
1213   char *redirect_uri;
1214   char *expected_redirect_uri;
1215   char *state = NULL;
1216   char *nonce = NULL;
1217   struct GNUNET_TIME_Absolute current_time, *relog_time;
1218   char *login_base_url, *new_redirect;
1219   struct GNUNET_HashCode cache_key;
1220   const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey;
1221   struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
1222   int number_of_ignored_parameter, iterator;
1223
1224   // REQUIRED value: client_id
1225   GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1226                       &cache_key);
1227   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1228                                                            &cache_key))
1229   {
1230     handle->emsg=GNUNET_strdup("invalid_request");
1231     handle->edesc=GNUNET_strdup("Missing parameter: client_id");
1232     GNUNET_SCHEDULER_add_now (&do_error, handle);
1233     return;
1234   }
1235   client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1236                                                 &cache_key);
1237   if ( GNUNET_OK
1238       != GNUNET_CRYPTO_ecdsa_public_key_from_string (client_id,
1239                                                      strlen (client_id),
1240                                                      &pubkey) )
1241   {
1242     handle->emsg=GNUNET_strdup("unauthorized_client");
1243     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1244     GNUNET_SCHEDULER_add_now (&do_error, handle);
1245   }
1246
1247   // Checks if client_id is valid:
1248   handle->namestore_handle = GNUNET_NAMESTORE_connect(cfg);
1249   zone_pkey = GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1250   GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle, zone_pkey, &pubkey,
1251                                  zone_to_name_error, handle, zone_to_name_get_cb,
1252                                  handle);
1253   return;
1254
1255   // REQUIRED value: redirect_uri
1256   GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1257                       &cache_key);
1258   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1259                                                            &cache_key))
1260   {
1261     handle->emsg=GNUNET_strdup("invalid_request");
1262     handle->edesc=GNUNET_strdup("Missing parameter: redirect_uri");
1263     GNUNET_SCHEDULER_add_now (&do_error, handle);
1264     return;
1265   }
1266   redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1267                                                 &cache_key);
1268
1269   GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", client_id);
1270
1271   // verify the redirect uri matches https://<client_id>.zkey[/xyz]
1272   if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
1273   {
1274     handle->emsg=GNUNET_strdup("invalid_request");
1275     handle->edesc=GNUNET_strdup("Invalid redirect_uri");
1276     GNUNET_free(expected_redirect_uri);
1277     GNUNET_SCHEDULER_add_now (&do_error, handle);
1278     return;
1279   }
1280   handle->eredirect = GNUNET_strdup(redirect_uri);
1281
1282   // REQUIRED value: response_type
1283   GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1284                       &cache_key);
1285   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1286                                                            &cache_key))
1287   {
1288     handle->emsg=GNUNET_strdup("invalid_request");
1289     handle->edesc=GNUNET_strdup("Missing parameter: response_type");
1290     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1291     return;
1292   }
1293   response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1294                                                     &cache_key);
1295
1296   // REQUIRED value: scope
1297   GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
1298   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1299                                                            &cache_key))
1300   {
1301     handle->emsg=GNUNET_strdup("invalid_request");
1302     handle->edesc=GNUNET_strdup("Missing parameter: scope");
1303     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1304     return;
1305   }
1306   scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1307                                             &cache_key);
1308
1309   //RECOMMENDED value: state
1310   GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
1311   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1312                                                            &cache_key))
1313   {
1314     state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1315                                               &cache_key);
1316   }
1317
1318   //OPTIONAL value: nonce
1319   GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
1320   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1321                                                            &cache_key))
1322   {
1323     nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1324                                               &cache_key);
1325   }
1326
1327   number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1328   for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1329   {
1330     GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1331                         strlen(OIDC_ignored_parameter_array[iterator]),
1332                         &cache_key);
1333     if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
1334                                                             &cache_key))
1335     {
1336       handle->emsg=GNUNET_strdup("access_denied");
1337       GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1338                        OIDC_ignored_parameter_array[iterator]);
1339       GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1340       return;
1341     }
1342   }
1343
1344   // Checks if response_type is 'code'
1345   if( 0 != strcmp( response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1346   {
1347     handle->emsg=GNUNET_strdup("unsupported_response_type");
1348     handle->edesc=GNUNET_strdup("The authorization server does not support "
1349                                 "obtaining this authorization code.");
1350     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1351     return;
1352   }
1353   // Checks if scope contains 'openid'
1354   if( NULL == strstr( scope, OIDC_EXPECTED_AUTHORIZATION_SCOPE ) )
1355   {
1356     handle->emsg=GNUNET_strdup("invalid_scope");
1357     handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1358                                 "malformed.");
1359     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1360     return;
1361   }
1362
1363   //TODO check other values and use them accordingly
1364
1365   GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
1366                       &cache_key);
1367   //No identity-cookie -> redirect to login
1368   if ( GNUNET_YES
1369       == GNUNET_CONTAINER_multihashmap_contains (con_handle->header_param_map,
1370                                                  &cache_key) )
1371   {
1372     //split cookies and find 'Identity' cookie
1373     char* cookies = GNUNET_CONTAINER_multihashmap_get (
1374         con_handle->header_param_map, &cache_key);
1375     char delimiter[] = "; ";
1376     char *identity_cookie;
1377     identity_cookie = strtok(cookies, delimiter);
1378
1379     while ( NULL != identity_cookie )
1380     {
1381       if ( NULL != strstr (identity_cookie, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
1382       {
1383         break;
1384       }
1385       identity_cookie = strtok (NULL, delimiter);
1386     }
1387     GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1388
1389     //No login time for identity -> redirect to login
1390     if ( GNUNET_YES
1391         == GNUNET_CONTAINER_multihashmap_contains (OIDC_authorized_identities,
1392                                                    &cache_key) )
1393     {
1394       relog_time = GNUNET_CONTAINER_multihashmap_get (
1395               OIDC_authorized_identities, &cache_key);
1396
1397       current_time = GNUNET_TIME_absolute_get();
1398
1399       GNUNET_CONTAINER_multihashmap_remove_all(OIDC_authorized_identities, &cache_key);
1400       // 30 min after old login -> redirect to login
1401       if ( current_time.abs_value_us <= relog_time->abs_value_us )
1402       {
1403         resp = GNUNET_REST_create_response ("");
1404
1405         GNUNET_CRYPTO_ecdsa_public_key_from_string (identity_cookie,
1406                                                     strlen (identity_cookie),
1407                                                     &pubkey);
1408
1409         // iterate over egos and compare their public key
1410 //      GNUNET_IDENTITY_PROVIDER_get_attributes_start
1411         // iterate over scope variables
1412         char delimiter[] = " ";
1413         char *scope_attribute;
1414         scope_attribute = strtok(scope, delimiter);
1415
1416         while ( NULL != scope_attribute )
1417         {
1418           if ( NULL == strstr (scope_attribute, OIDC_EXPECTED_AUTHORIZATION_SCOPE) )
1419           {
1420             // claim attribute from ego
1421             scope_attribute = strtok (NULL, delimiter);
1422           }
1423         }
1424         // create an authorization code
1425
1426 //      GNUNET_IDENTITY_PROVIDER_t
1427
1428         MHD_add_response_header (resp, "Location", redirect_uri);
1429         handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1430         cleanup_handle (handle);
1431         GNUNET_free(relog_time);
1432         return;
1433       }
1434       GNUNET_free(relog_time);
1435     }
1436   }
1437
1438
1439   // login redirection
1440   if ( GNUNET_OK
1441       == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
1442                                                 "address", &login_base_url) )
1443   {
1444     GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
1445                      login_base_url,
1446                      OIDC_RESPONSE_TYPE_KEY,
1447                      response_type,
1448                      OIDC_CLIENT_ID_KEY,
1449                      client_id,
1450                      OIDC_REDIRECT_URI_KEY,
1451                      redirect_uri,
1452                      OIDC_SCOPE_KEY,
1453                      scope,
1454                      OIDC_STATE_KEY,
1455                      (NULL == state) ? state : "",
1456                      OIDC_NONCE_KEY,
1457                      (NULL == nonce) ? nonce : "");
1458     resp = GNUNET_REST_create_response ("");
1459     MHD_add_response_header (resp, "Location", new_redirect);
1460   }
1461   else
1462   {
1463     handle->emsg = GNUNET_strdup("No server configuration");
1464     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1465     GNUNET_SCHEDULER_add_now (&do_error, handle);
1466     return;
1467   }
1468   handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1469   cleanup_handle (handle);
1470   GNUNET_free(new_redirect);
1471   return;
1472 }
1473
1474 /**
1475  * Respond to authorization POST request
1476  *
1477  * @param con_handle the connection handle
1478  * @param url the url
1479  * @param cls the RequestHandle
1480  */
1481 static void
1482 authorize_post_cont (struct GNUNET_REST_RequestHandle *con_handle,
1483                 const char* url,
1484                 void *cls)
1485 {
1486     /** The Authorization Server MUST validate all the OAuth 2.0 parameters
1487    *    according to the OAuth 2.0 specification.
1488    */
1489   /**
1490    *    If the sub (subject) Claim is requested with a specific value for the
1491    *    ID Token, the Authorization Server MUST only send a positive response
1492    *    if the End-User identified by that sub value has an active session with
1493    *    the Authorization Server or has been Authenticated as a result of the
1494    *    request. The Authorization Server MUST NOT reply with an ID Token or
1495    *    Access Token for a different user, even if they have an active session
1496    *    with the Authorization Server. Such a request can be made either using
1497    *    an id_token_hint parameter or by requesting a specific Claim Value as
1498    *    described in Section 5.5.1, if the claims parameter is supported by
1499    *    the implementation.
1500    */
1501
1502   struct MHD_Response *resp;
1503   struct RequestHandle *handle = cls;
1504   const char *response_type;
1505   const char *client_id;
1506   char *scope;
1507   const char *redirect_uri;
1508   const char *state = NULL;
1509   const char *nonce = NULL;
1510   struct GNUNET_TIME_Absolute current_time, *relog_time;
1511   char *login_base_url;
1512   char *new_redirect;
1513   char *expected_redirect_uri;
1514   json_t *cache_object;
1515   const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_pkey;
1516   struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
1517   struct GNUNET_HashCode cache_key;
1518   int number_of_ignored_parameter, iterator;
1519
1520   json_t *root;
1521   json_error_t error;
1522   root = json_loads (handle->rest_handle->data, 0, &error);
1523
1524   // REQUIRED value: client_id
1525   cache_object = json_object_get (root, OIDC_CLIENT_ID_KEY);
1526   if( NULL==cache_object || !json_is_string(cache_object))
1527   {
1528     handle->emsg=GNUNET_strdup("invalid_request");
1529     handle->edesc=GNUNET_strdup("Missing parameter: client_id");
1530     GNUNET_SCHEDULER_add_now (&do_error, handle);
1531     return;
1532   }
1533   client_id = json_string_value(cache_object);
1534   if ( GNUNET_OK
1535       != GNUNET_CRYPTO_ecdsa_public_key_from_string (client_id,
1536                                                      strlen (client_id),
1537                                                      &pubkey) )
1538   {
1539     handle->emsg=GNUNET_strdup("unauthorized_client");
1540     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1541     GNUNET_SCHEDULER_add_now (&do_error, handle);
1542   }
1543
1544   // Checks if client_id is valid:
1545   handle->namestore_handle = GNUNET_NAMESTORE_connect(cfg);
1546   zone_pkey = GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1547   //TODO: fix
1548 //  GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle, zone_pkey, &pubkey,
1549 //                               zone_to_name_error, handle, zone_to_name_cb,
1550 //                               handle);
1551
1552   // REQUIRED value: redirect_uri
1553   cache_object = json_object_get (root, OIDC_REDIRECT_URI_KEY);
1554   if( NULL==cache_object || !json_is_string(cache_object))
1555   {
1556     handle->emsg=GNUNET_strdup("invalid_request");
1557     handle->edesc=GNUNET_strdup("Missing parameter: redirect_uri");
1558     GNUNET_SCHEDULER_add_now (&do_error, handle);
1559     return;
1560   }
1561   redirect_uri = json_string_value(cache_object);
1562
1563   GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", client_id);
1564
1565   // verify the redirect uri matches https://<client_id>.zkey[/xyz]
1566   if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
1567   {
1568     handle->emsg=GNUNET_strdup("invalid_request");
1569     handle->edesc=GNUNET_strdup("Invalid redirect_uri");
1570     GNUNET_free(expected_redirect_uri);
1571     GNUNET_SCHEDULER_add_now (&do_error, handle);
1572     return;
1573   }
1574   handle->eredirect = GNUNET_strdup(redirect_uri);
1575
1576   // REQUIRED value: response_type
1577   cache_object = json_object_get (root, OIDC_RESPONSE_TYPE_KEY);
1578   if( NULL==cache_object || !json_is_string(cache_object))
1579   {
1580     handle->emsg=GNUNET_strdup("invalid_request");
1581     handle->edesc=GNUNET_strdup("Missing parameter: response_type");
1582     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1583     return;
1584   }
1585   response_type = json_string_value(cache_object);
1586
1587   // REQUIRED value: scope
1588   cache_object = json_object_get (root, OIDC_SCOPE_KEY);
1589   if( NULL==cache_object || !json_is_string(cache_object))
1590   {
1591     handle->emsg=GNUNET_strdup("invalid_request");
1592     handle->edesc=GNUNET_strdup("Missing parameter: scope");
1593     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1594     return;
1595   }
1596   scope = json_string_value(cache_object);
1597
1598   //RECOMMENDED value: state
1599   cache_object = json_object_get (root, OIDC_STATE_KEY);
1600   if( NULL!=cache_object || json_is_string(cache_object))
1601   {
1602     state = json_string_value(cache_object);
1603   }
1604
1605   //OPTIONAL value: nonce
1606   cache_object = json_object_get (root, OIDC_NONCE_KEY);
1607   if( NULL!=cache_object || json_is_string(cache_object))
1608   {
1609     nonce = json_string_value(cache_object);
1610   }
1611
1612   //TODO check other values and use them accordingly
1613   number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1614   for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1615   {
1616     cache_object = json_object_get (root, OIDC_ignored_parameter_array[iterator]);
1617     if(json_is_string(cache_object))
1618     {
1619       handle->emsg=GNUNET_strdup("access_denied");
1620       GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1621                        OIDC_ignored_parameter_array[iterator]);
1622       GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1623       return;
1624     }
1625   }
1626
1627   // Checks if response_type is 'code'
1628   if( 0 != strcmp( response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1629   {
1630     handle->emsg=GNUNET_strdup("unsupported_response_type");
1631     handle->edesc=GNUNET_strdup("The authorization server does not support "
1632                                 "obtaining this authorization code.");
1633     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1634     return;
1635   }
1636   // Checks if scope contains 'openid'
1637   if( NULL == strstr( scope, OIDC_EXPECTED_AUTHORIZATION_SCOPE ) )
1638   {
1639     handle->emsg=GNUNET_strdup("invalid_scope");
1640     handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1641                                 "malformed.");
1642     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1643     return;
1644   }
1645
1646
1647   GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
1648                       &cache_key);
1649   //No identity-cookie -> redirect to login
1650   if ( GNUNET_YES
1651       == GNUNET_CONTAINER_multihashmap_contains (con_handle->header_param_map,
1652                                                  &cache_key) )
1653   {
1654     //split cookies and find 'Identity' cookie
1655     char* cookies = GNUNET_CONTAINER_multihashmap_get (
1656         con_handle->header_param_map, &cache_key);
1657     char delimiter[] = "; ";
1658     char *identity_cookie;
1659     identity_cookie = strtok(cookies, delimiter);
1660
1661     while ( NULL != identity_cookie )
1662     {
1663       if ( NULL != strstr (identity_cookie, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
1664       {
1665         break;
1666       }
1667       identity_cookie = strtok (NULL, delimiter);
1668     }
1669     GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1670
1671     //No login time for identity -> redirect to login
1672     if ( GNUNET_YES
1673         == GNUNET_CONTAINER_multihashmap_contains (OIDC_authorized_identities,
1674                                                    &cache_key) )
1675     {
1676       relog_time = GNUNET_CONTAINER_multihashmap_get (
1677               OIDC_authorized_identities, &cache_key);
1678
1679       current_time = GNUNET_TIME_absolute_get();
1680
1681       GNUNET_CONTAINER_multihashmap_remove_all(OIDC_authorized_identities, &cache_key);
1682       // 30 min after old login -> redirect to login
1683       if ( current_time.abs_value_us <= relog_time->abs_value_us )
1684       {
1685         resp = GNUNET_REST_create_response ("");
1686
1687         GNUNET_CRYPTO_ecdsa_public_key_from_string (identity_cookie,
1688                                                     strlen (identity_cookie),
1689                                                     &pubkey);
1690
1691         // iterate over egos and compare their public key
1692 //      GNUNET_IDENTITY_PROVIDER_get_attributes_start
1693         // iterate over scope variables
1694         char delimiter[] = " ";
1695         char *scope_attribute;
1696         scope_attribute = strtok(scope, delimiter);
1697
1698         while ( NULL != scope_attribute )
1699         {
1700           if ( NULL == strstr (scope_attribute, OIDC_EXPECTED_AUTHORIZATION_SCOPE) )
1701           {
1702             // claim attribute from ego
1703             scope_attribute = strtok (NULL, delimiter);
1704           }
1705         }
1706         // create an authorization code
1707
1708 //      GNUNET_IDENTITY_PROVIDER_t
1709
1710         MHD_add_response_header (resp, "Location", redirect_uri);
1711         handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1712         cleanup_handle (handle);
1713         GNUNET_free(relog_time);
1714         return;
1715       }
1716       GNUNET_free(relog_time);
1717     }
1718   }
1719
1720
1721   // login redirection
1722   if ( GNUNET_OK
1723       == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
1724                                                 "address", &login_base_url) )
1725   {
1726     GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
1727                      login_base_url,
1728                      OIDC_RESPONSE_TYPE_KEY,
1729                      response_type,
1730                      OIDC_CLIENT_ID_KEY,
1731                      client_id,
1732                      OIDC_REDIRECT_URI_KEY,
1733                      redirect_uri,
1734                      OIDC_SCOPE_KEY,
1735                      scope,
1736                      OIDC_STATE_KEY,
1737                      (NULL == state) ? state : "",
1738                      OIDC_NONCE_KEY,
1739                      (NULL == nonce) ? nonce : "");
1740     resp = GNUNET_REST_create_response ("");
1741     MHD_add_response_header (resp, "Location", new_redirect);
1742   }
1743   else
1744   {
1745     handle->emsg = GNUNET_strdup("No server configuration");
1746     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1747     GNUNET_SCHEDULER_add_now (&do_error, handle);
1748     return;
1749   }
1750   handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1751   cleanup_handle (handle);
1752   GNUNET_free(new_redirect);
1753   return;
1754 }
1755
1756
1757 /**
1758  * Combines an identity with a login time and responds OK to login request
1759  *
1760  * @param con_handle the connection handle
1761  * @param url the url
1762  * @param cls the RequestHandle
1763  */
1764 static void
1765 login_cont (struct GNUNET_REST_RequestHandle *con_handle,
1766             const char* url,
1767             void *cls)
1768 {
1769
1770
1771   struct MHD_Response *resp = GNUNET_REST_create_response ("");
1772   struct RequestHandle *handle = cls;
1773   struct GNUNET_HashCode cache_key;
1774   struct GNUNET_TIME_Absolute *current_time;
1775   char* cookie;
1776   json_t *root;
1777   json_error_t error;
1778   json_t *identity;
1779   root = json_loads (handle->rest_handle->data, 0, &error);
1780   identity = json_object_get (root, "identity");
1781   if ( json_is_string(identity) )
1782   {
1783     GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1784
1785     GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1786     current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
1787     *current_time = GNUNET_TIME_relative_to_absolute (
1788         GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_minute_ (),
1789                                        30));
1790     GNUNET_CONTAINER_multihashmap_put (
1791         OIDC_authorized_identities, &cache_key, current_time,
1792         GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1793
1794     handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1795   }
1796   else
1797   {
1798     handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1799   }
1800   GNUNET_free(cookie);
1801   json_decref (root);
1802   cleanup_handle (handle);
1803   return;
1804 }
1805
1806 /**
1807  * Handle rest request
1808  *
1809  * @param handle the request handle
1810  */
1811 static void
1812 init_cont (struct RequestHandle *handle)
1813 {
1814   struct GNUNET_REST_RequestHandlerError err;
1815   static const struct GNUNET_REST_RequestHandler handlers[] = {
1816     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
1817     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
1818     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
1819     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_get_cont},
1820     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
1821     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_post_cont},
1822     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1823     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1824     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
1825       &options_cont},
1826     GNUNET_REST_HANDLER_END
1827   };
1828
1829   if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1830                                                handlers,
1831                                                &err,
1832                                                handle))
1833   {
1834     handle->response_code = err.error_code;
1835     GNUNET_SCHEDULER_add_now (&do_error, handle);
1836   }
1837 }
1838
1839 /**
1840  * If listing is enabled, prints information about the egos.
1841  *
1842  * This function is initially called for all egos and then again
1843  * whenever a ego's identifier changes or if it is deleted.  At the
1844  * end of the initial pass over all egos, the function is once called
1845  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1846  * be invoked in the future or that there was an error.
1847  *
1848  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1849  * this function is only called ONCE, and 'NULL' being passed in
1850  * 'ego' does indicate an error (i.e. name is taken or no default
1851  * value is known).  If 'ego' is non-NULL and if '*ctx'
1852  * is set in those callbacks, the value WILL be passed to a subsequent
1853  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1854  * that one was not NULL).
1855  *
1856  * When an identity is renamed, this function is called with the
1857  * (known) ego but the NEW identifier.
1858  *
1859  * When an identity is deleted, this function is called with the
1860  * (known) ego and "NULL" for the 'identifier'.  In this case,
1861  * the 'ego' is henceforth invalid (and the 'ctx' should also be
1862  * cleaned up).
1863  *
1864  * @param cls closure
1865  * @param ego ego handle
1866  * @param ctx context for application to store data for this ego
1867  *                 (during the lifetime of this process, initially NULL)
1868  * @param identifier identifier assigned by the user for this ego,
1869  *                   NULL if the user just deleted the ego and it
1870  *                   must thus no longer be used
1871  */
1872 static void
1873 list_ego (void *cls,
1874           struct GNUNET_IDENTITY_Ego *ego,
1875           void **ctx,
1876           const char *identifier)
1877 {
1878   struct RequestHandle *handle = cls;
1879   struct EgoEntry *ego_entry;
1880   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1881
1882   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1883   {
1884     handle->state = ID_REST_STATE_POST_INIT;
1885     init_cont (handle);
1886     return;
1887   }
1888   if (ID_REST_STATE_INIT == handle->state) {
1889     ego_entry = GNUNET_new (struct EgoEntry);
1890     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1891     ego_entry->keystring =
1892       GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1893     ego_entry->ego = ego;
1894     ego_entry->identifier = GNUNET_strdup (identifier);
1895     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1896   }
1897
1898 }
1899
1900 static void
1901 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1902                               GNUNET_REST_ResultProcessor proc,
1903                               void *proc_cls)
1904 {
1905   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1906   if ( NULL == OIDC_authorized_identities )
1907   {
1908     OIDC_authorized_identities = GNUNET_CONTAINER_multihashmap_create (10,
1909                                                                      GNUNET_NO);
1910   }
1911   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1912   handle->proc_cls = proc_cls;
1913   handle->proc = proc;
1914   handle->state = ID_REST_STATE_INIT;
1915   handle->rest_handle = rest_handle;
1916
1917   handle->url = GNUNET_strdup (rest_handle->url);
1918   if (handle->url[strlen (handle->url)-1] == '/')
1919     handle->url[strlen (handle->url)-1] = '\0';
1920   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1921               "Connecting...\n");
1922   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1923                                                      &list_ego,
1924                                                      handle);
1925   handle->timeout_task =
1926     GNUNET_SCHEDULER_add_delayed (handle->timeout,
1927                                   &do_timeout,
1928                                   handle);
1929   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1930               "Connected\n");
1931 }
1932
1933 /**
1934  * Entry point for the plugin.
1935  *
1936  * @param cls Config info
1937  * @return NULL on error, otherwise the plugin context
1938  */
1939 void *
1940 libgnunet_plugin_rest_identity_provider_init (void *cls)
1941 {
1942   static struct Plugin plugin;
1943   struct GNUNET_REST_Plugin *api;
1944
1945   cfg = cls;
1946   if (NULL != plugin.cfg)
1947     return NULL;                /* can only initialize once! */
1948   memset (&plugin, 0, sizeof (struct Plugin));
1949   plugin.cfg = cfg;
1950   api = GNUNET_new (struct GNUNET_REST_Plugin);
1951   api->cls = &plugin;
1952   api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1953   api->process_request = &rest_identity_process_request;
1954   GNUNET_asprintf (&allow_methods,
1955                    "%s, %s, %s, %s, %s",
1956                    MHD_HTTP_METHOD_GET,
1957                    MHD_HTTP_METHOD_POST,
1958                    MHD_HTTP_METHOD_PUT,
1959                    MHD_HTTP_METHOD_DELETE,
1960                    MHD_HTTP_METHOD_OPTIONS);
1961
1962   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1963               _("Identity Provider REST API initialized\n"));
1964   return api;
1965 }
1966
1967
1968 /**
1969  * Exit point from the plugin.
1970  *
1971  * @param cls the plugin context (as returned by "init")
1972  * @return always NULL
1973  */
1974 void *
1975 libgnunet_plugin_rest_identity_provider_done (void *cls)
1976 {
1977   struct GNUNET_REST_Plugin *api = cls;
1978   struct Plugin *plugin = api->cls;
1979
1980   plugin->cfg = NULL;
1981   GNUNET_free_non_null (allow_methods);
1982   GNUNET_free (api);
1983   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1984               "Identity Provider REST plugin is finished\n");
1985   return NULL;
1986 }
1987
1988 /* end of plugin_rest_identity_provider.c */