-fix
[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 #include "jwt.h"
43
44 /**
45  * REST root namespace
46  */
47 #define GNUNET_REST_API_NS_IDENTITY_PROVIDER "/idp"
48
49 /**
50  * Attribute namespace
51  */
52 #define GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES "/idp/attributes"
53
54 /**
55  * Ticket namespace
56  */
57 #define GNUNET_REST_API_NS_IDENTITY_TICKETS "/idp/tickets"
58
59 /**
60  * Revoke namespace
61  */
62 #define GNUNET_REST_API_NS_IDENTITY_REVOKE "/idp/revoke"
63
64 /**
65  * Revoke namespace
66  */
67 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume"
68
69 /**
70  * Authorize endpoint
71  */
72 #define GNUNET_REST_API_NS_AUTHORIZE "/idp/authorize"
73
74 /**
75  * Token endpoint
76  */
77 #define GNUNET_REST_API_NS_TOKEN "/idp/token"
78
79 /**
80  * UserInfo endpoint
81  */
82 #define GNUNET_REST_API_NS_USERINFO "/idp/userinfo"
83
84 /**
85  * Login namespace
86  */
87 #define GNUNET_REST_API_NS_LOGIN "/idp/login"
88
89 /**
90  * Attribute key
91  */
92 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
93
94 /**
95  * Ticket key
96  */
97 #define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
98
99
100 /**
101  * Value key
102  */
103 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value"
104
105 /**
106  * State while collecting all egos
107  */
108 #define ID_REST_STATE_INIT 0
109
110 /**
111  * Done collecting egos
112  */
113 #define ID_REST_STATE_POST_INIT 1
114
115 /**
116  * OIDC grant_type key
117  */
118 #define OIDC_GRANT_TYPE_KEY "grant_type"
119
120 /**
121  * OIDC grant_type key
122  */
123 #define OIDC_GRANT_TYPE_VALUE "authorization_code"
124
125 /**
126  * OIDC code key
127  */
128 #define OIDC_CODE_KEY "code"
129
130 /**
131  * OIDC response_type key
132  */
133 #define OIDC_RESPONSE_TYPE_KEY "response_type"
134
135 /**
136  * OIDC client_id key
137  */
138 #define OIDC_CLIENT_ID_KEY "client_id"
139
140 /**
141  * OIDC scope key
142  */
143 #define OIDC_SCOPE_KEY "scope"
144
145 /**
146  * OIDC redirect_uri key
147  */
148 #define OIDC_REDIRECT_URI_KEY "redirect_uri"
149
150 /**
151  * OIDC state key
152  */
153 #define OIDC_STATE_KEY "state"
154
155 /**
156  * OIDC nonce key
157  */
158 #define OIDC_NONCE_KEY "nonce"
159
160 /**
161  * OIDC cookie header key
162  */
163 #define OIDC_COOKIE_HEADER_KEY "Cookie"
164
165 /**
166  * OIDC cookie header information key
167  */
168 #define OIDC_AUTHORIZATION_HEADER_KEY "Authorization"
169
170 /**
171  * OIDC cookie header information key
172  */
173 #define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
174
175 /**
176  * OIDC expected response_type while authorizing
177  */
178 #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
179
180 /**
181  * OIDC expected scope part while authorizing
182  */
183 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
184
185 /**
186  * OIDC ignored parameter array
187  */
188 char* OIDC_ignored_parameter_array [] =
189 {
190   "display",
191   "prompt",
192   "max_age",
193   "ui_locales", 
194   "response_mode",
195   "id_token_hint",
196   "login_hint", 
197   "acr_values"
198 };
199
200 /**
201  * OIDC authorized identities and times hashmap
202  */
203 struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
204
205 /**
206  * OIDC authorized identities and times hashmap
207  */
208 struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants;
209
210 /**
211  * OIDC ticket/code use only once
212  */
213 struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once;
214
215 /**
216  * OIDC access_token to ticket and ego
217  */
218 struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token;
219
220 /**
221  * The configuration handle
222  */
223 const struct GNUNET_CONFIGURATION_Handle *cfg;
224
225 /**
226  * HTTP methods allows for this plugin
227  */
228 static char* allow_methods;
229
230 /**
231  * @brief struct returned by the initialization function of the plugin
232  */
233 struct Plugin
234 {
235   const struct GNUNET_CONFIGURATION_Handle *cfg;
236 };
237 /**
238  * OIDC needed variables
239  */
240 struct OIDC_Variables
241 {
242
243   struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
244
245   char *client_id;
246
247   int is_client_trusted;
248
249   char *redirect_uri;
250
251   char *scope;
252
253   char *state;
254
255   char *nonce;
256
257   char *response_type;
258
259   char *login_identity;
260
261   json_t *response;
262
263 };
264
265 /**
266  * The ego list
267  */
268 struct EgoEntry
269 {
270   /**
271    * DLL
272    */
273   struct EgoEntry *next;
274
275   /**
276    * DLL
277    */
278   struct EgoEntry *prev;
279
280   /**
281    * Ego Identifier
282    */
283   char *identifier;
284
285   /**
286    * Public key string
287    */
288   char *keystring;
289
290   /**
291    * The Ego
292    */
293   struct GNUNET_IDENTITY_Ego *ego;
294 };
295
296
297 struct RequestHandle
298 {
299   /**
300    * Ego list
301    */
302   struct EgoEntry *ego_head;
303
304   /**
305    * Ego list
306    */
307   struct EgoEntry *ego_tail;
308
309   /**
310    * Selected ego
311    */
312   struct EgoEntry *ego_entry;
313
314   /**
315    * Pointer to ego private key
316    */
317   struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
318
319   /**
320    * OIDC variables
321    */
322   struct OIDC_Variables *oidc;
323
324   /**
325    * The processing state
326    */
327   int state;
328
329   /**
330    * Handle to Identity service.
331    */
332   struct GNUNET_IDENTITY_Handle *identity_handle;
333
334   /**
335    * Rest connection
336    */
337   struct GNUNET_REST_RequestHandle *rest_handle;
338
339   /**
340    * Handle to NAMESTORE
341    */
342   struct GNUNET_NAMESTORE_Handle *namestore_handle;
343
344   /**
345    * Iterator for NAMESTORE
346    */
347   struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
348
349   /**
350    * Attribute claim list
351    */
352   struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list;
353
354   /**
355    * IDENTITY Operation
356    */
357   struct GNUNET_IDENTITY_Operation *op;
358
359   /**
360    * Identity Provider
361    */
362   struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
363
364   /**
365    * Idp Operation
366    */
367   struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
368
369   /**
370    * Attribute iterator
371    */
372   struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it;
373
374   /**
375    * Ticket iterator
376    */
377   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it;
378
379   /**
380    * Desired timeout for the lookup (default is no timeout).
381    */
382   struct GNUNET_TIME_Relative timeout;
383
384   /**
385    * ID of a task associated with the resolution process.
386    */
387   struct GNUNET_SCHEDULER_Task *timeout_task;
388
389   /**
390    * The plugin result processor
391    */
392   GNUNET_REST_ResultProcessor proc;
393
394   /**
395    * The closure of the result processor
396    */
397   void *proc_cls;
398
399   /**
400    * The url
401    */
402   char *url;
403
404   /**
405    * Error response message
406    */
407   char *emsg;
408
409   /**
410    * Error response description
411    */
412   char *edesc;
413
414   /**
415    * Reponse code
416    */
417   int response_code;
418
419   /**
420    * Response object
421    */
422   struct GNUNET_JSONAPI_Document *resp_object;
423
424 };
425
426 /**
427  * Cleanup lookup handle
428  * @param handle Handle to clean up
429  */
430 static void
431 cleanup_handle (struct RequestHandle *handle)
432 {
433   struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_entry;
434   struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_tmp;
435   struct EgoEntry *ego_entry;
436   struct EgoEntry *ego_tmp;
437   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
438               "Cleaning up\n");
439   if (NULL != handle->resp_object)
440     GNUNET_JSONAPI_document_delete (handle->resp_object);
441   if (NULL != handle->timeout_task)
442     GNUNET_SCHEDULER_cancel (handle->timeout_task);
443   if (NULL != handle->identity_handle)
444     GNUNET_IDENTITY_disconnect (handle->identity_handle);
445   if (NULL != handle->attr_it)
446     GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it);
447   if (NULL != handle->ticket_it)
448     GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it);
449   if (NULL != handle->idp)
450     GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
451   if (NULL != handle->url)
452     GNUNET_free (handle->url);
453   if (NULL != handle->emsg)
454     GNUNET_free (handle->emsg);
455   if (NULL != handle->edesc)
456     GNUNET_free (handle->edesc);
457   if (NULL != handle->namestore_handle)
458     GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
459   if (NULL != handle->oidc)
460   {
461     if (NULL != handle->oidc->client_id)
462       GNUNET_free(handle->oidc->client_id);
463     if (NULL != handle->oidc->login_identity)
464       GNUNET_free(handle->oidc->login_identity);
465     if (NULL != handle->oidc->nonce)
466       GNUNET_free(handle->oidc->nonce);
467     if (NULL != handle->oidc->redirect_uri)
468       GNUNET_free(handle->oidc->redirect_uri);
469     if (NULL != handle->oidc->response_type)
470       GNUNET_free(handle->oidc->response_type);
471     if (NULL != handle->oidc->scope)
472       GNUNET_free(handle->oidc->scope);
473     if (NULL != handle->oidc->state)
474       GNUNET_free(handle->oidc->state);
475     if (NULL != handle->oidc->response)
476       json_decref(handle->oidc->response);
477     GNUNET_free(handle->oidc);
478   }
479   if ( NULL != handle->attr_list )
480   {
481     for (claim_entry = handle->attr_list->list_head;
482     NULL != claim_entry;)
483     {
484       claim_tmp = claim_entry;
485       claim_entry = claim_entry->next;
486       GNUNET_free(claim_tmp->claim);
487       GNUNET_free(claim_tmp);
488     }
489     GNUNET_free (handle->attr_list);
490   }
491   for (ego_entry = handle->ego_head;
492        NULL != ego_entry;)
493   {
494     ego_tmp = ego_entry;
495     ego_entry = ego_entry->next;
496     GNUNET_free (ego_tmp->identifier);
497     GNUNET_free (ego_tmp->keystring);
498     GNUNET_free (ego_tmp);
499   }
500   if (NULL != handle->attr_it)
501   {
502     GNUNET_free(handle->attr_it);
503   }
504   GNUNET_free (handle);
505 }
506
507 static void
508 cleanup_handle_delayed (void *cls)
509 {
510   cleanup_handle (cls);
511 }
512
513
514 /**
515  * Task run on error, sends error message.  Cleans up everything.
516  *
517  * @param cls the `struct RequestHandle`
518  */
519 static void
520 do_error (void *cls)
521 {
522   struct RequestHandle *handle = cls;
523   struct MHD_Response *resp;
524   char *json_error;
525
526   GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : \"%s\"%s%s%s}",
527                    handle->emsg,
528                    (NULL != handle->edesc) ? handle->edesc : "",
529                    (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
530                    (NULL != handle->oidc->state) ? handle->oidc->state : "",
531                    (NULL != handle->oidc->state) ? "\"" : "");
532   if ( 0 == handle->response_code )
533   {
534     handle->response_code = MHD_HTTP_BAD_REQUEST;
535   }
536   resp = GNUNET_REST_create_response (json_error);
537   if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
538   {
539     MHD_add_response_header(resp, "WWW-Authenticate", "Basic");
540   }
541   MHD_add_response_header (resp, "Content-Type", "application/json");
542   handle->proc (handle->proc_cls, resp, handle->response_code);
543   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
544   GNUNET_free (json_error);
545 }
546
547
548 /**
549  * Task run on error, sends error message.  Cleans up everything.
550  *
551  * @param cls the `struct RequestHandle`
552  */
553 static void
554 do_userinfo_error (void *cls)
555 {
556   struct RequestHandle *handle = cls;
557   struct MHD_Response *resp;
558   char *error;
559
560   GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"",
561                    handle->emsg,
562                    (NULL != handle->edesc) ? handle->edesc : "");
563   resp = GNUNET_REST_create_response ("");
564   MHD_add_response_header(resp, "WWW-Authenticate", error);
565   handle->proc (handle->proc_cls, resp, handle->response_code);
566   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
567   GNUNET_free (error);
568 }
569
570
571 /**
572  * Task run on error, sends error message.  Cleans up everything.
573  *
574  * @param cls the `struct RequestHandle`
575  */
576 static void
577 do_redirect_error (void *cls)
578 {
579   struct RequestHandle *handle = cls;
580   struct MHD_Response *resp;
581   char* redirect;
582   GNUNET_asprintf (&redirect,
583                    "%s?error=%s&error_description=%s%s%s",
584                    handle->oidc->redirect_uri, handle->emsg, handle->edesc,
585                    (NULL != handle->oidc->state) ? "&state=" : "",
586                    (NULL != handle->oidc->state) ? handle->oidc->state : "");
587   resp = GNUNET_REST_create_response ("");
588   MHD_add_response_header (resp, "Location", redirect);
589   handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
590   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
591   GNUNET_free (redirect);
592 }
593
594 /**
595  * Task run on timeout, sends error message.  Cleans up everything.
596  *
597  * @param cls the `struct RequestHandle`
598  */
599 static void
600 do_timeout (void *cls)
601 {
602   struct RequestHandle *handle = cls;
603
604   handle->timeout_task = NULL;
605   do_error (handle);
606 }
607
608
609 static void
610 collect_error_cb (void *cls)
611 {
612   struct RequestHandle *handle = cls;
613
614   do_error (handle);
615 }
616
617 static void
618 finished_cont (void *cls,
619                int32_t success,
620                const char *emsg)
621 {
622   struct RequestHandle *handle = cls;
623   struct MHD_Response *resp;
624
625   resp = GNUNET_REST_create_response (emsg);
626   if (GNUNET_OK != success)
627   {
628     GNUNET_SCHEDULER_add_now (&do_error, handle);
629     return;
630   }
631   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
632   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
633 }
634
635
636 /**
637  * Return attributes for identity
638  *
639  * @param cls the request handle
640  */
641 static void
642 return_response (void *cls)
643 {
644   char* result_str;
645   struct RequestHandle *handle = cls;
646   struct MHD_Response *resp;
647
648   GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
649   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
650   resp = GNUNET_REST_create_response (result_str);
651   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
652   GNUNET_free (result_str);
653   cleanup_handle (handle);
654 }
655
656 /**
657  * Return attributes for claim
658  *
659  * @param cls the request handle
660  */
661 static void
662 return_userinfo_response (void *cls)
663 {
664   char* result_str;
665   struct RequestHandle *handle = cls;
666   struct MHD_Response *resp;
667
668   result_str = json_dumps (handle->oidc->response, 0);
669
670   resp = GNUNET_REST_create_response (result_str);
671   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
672   GNUNET_free (result_str);
673   cleanup_handle (handle);
674 }
675
676 static char*
677 base_64_encode(char *string)
678 {
679   char *output;
680   GNUNET_STRINGS_base64_encode(string,strlen(string),&output);
681   int index = strlen(output)-1;
682   while ('=' == output[index])
683   {
684     output[index] = '\0';
685     index--;
686   }
687   return output;
688 }
689
690 static void
691 collect_finished_cb (void *cls)
692 {
693   struct RequestHandle *handle = cls;
694   //Done
695   handle->attr_it = NULL;
696   handle->ticket_it = NULL;
697   GNUNET_SCHEDULER_add_now (&return_response, handle);
698 }
699
700
701 /**
702  * Collect all attributes for an ego
703  *
704  */
705 static void
706 ticket_collect (void *cls,
707                 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
708 {
709   struct GNUNET_JSONAPI_Resource *json_resource;
710   struct RequestHandle *handle = cls;
711   json_t *value;
712   char* tmp;
713
714   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
715   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
716                                              sizeof (uint64_t));
717   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
718                                                        tmp);
719   GNUNET_free (tmp);
720   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
721
722   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
723                                              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
724   value = json_string (tmp);
725   GNUNET_JSONAPI_resource_add_attr (json_resource,
726                                     "issuer",
727                                     value);
728   GNUNET_free (tmp);
729   json_decref (value);
730   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
731                                              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
732   value = json_string (tmp);
733   GNUNET_JSONAPI_resource_add_attr (json_resource,
734                                     "audience",
735                                     value);
736   GNUNET_free (tmp);
737   json_decref (value);
738   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
739                                              sizeof (uint64_t));
740   value = json_string (tmp);
741   GNUNET_JSONAPI_resource_add_attr (json_resource,
742                                     "rnd",
743                                     value);
744   GNUNET_free (tmp);
745   json_decref (value);
746   GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it);
747 }
748
749
750
751 /**
752  * List tickets for identity request
753  *
754  * @param con_handle the connection handle
755  * @param url the url
756  * @param cls the RequestHandle
757  */
758 static void
759 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
760                    const char* url,
761                    void *cls)
762 {
763   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
764   struct RequestHandle *handle = cls;
765   struct EgoEntry *ego_entry;
766   char *identity;
767
768   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
769               handle->url);
770   if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
771        strlen (handle->url))
772   {
773     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
774     GNUNET_SCHEDULER_add_now (&do_error, handle);
775     return;
776   }
777   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
778
779   for (ego_entry = handle->ego_head;
780        NULL != ego_entry;
781        ego_entry = ego_entry->next)
782     if (0 == strcmp (identity, ego_entry->identifier))
783       break;
784   handle->resp_object = GNUNET_JSONAPI_document_new ();
785
786   if (NULL == ego_entry)
787   {
788     //Done
789     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
790                 identity);
791     GNUNET_SCHEDULER_add_now (&return_response, handle);
792     return;
793   }
794   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
795   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
796   handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp,
797                                                                        priv_key,
798                                                                        &collect_error_cb,
799                                                                        handle,
800                                                                        &ticket_collect,
801                                                                        handle,
802                                                                        &collect_finished_cb,
803                                                                        handle);
804 }
805
806
807 static void
808 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
809                     const char* url,
810                     void *cls)
811 {
812   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
813   const char* identity;
814   const char* name_str;
815   const char* value_str;
816
817   struct RequestHandle *handle = cls;
818   struct EgoEntry *ego_entry;
819   struct MHD_Response *resp;
820   struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute;
821   struct GNUNET_JSONAPI_Document *json_obj;
822   struct GNUNET_JSONAPI_Resource *json_res;
823   char term_data[handle->rest_handle->data_size+1];
824   json_t *value_json;
825   json_t *data_json;
826   json_error_t err;
827   struct GNUNET_JSON_Specification docspec[] = {
828     GNUNET_JSON_spec_jsonapi_document (&json_obj),
829     GNUNET_JSON_spec_end()
830   };
831
832   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
833               handle->url);
834   if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
835        strlen (handle->url))
836   {
837     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
838     GNUNET_SCHEDULER_add_now (&do_error, handle);
839     return;
840   }
841   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
842
843   for (ego_entry = handle->ego_head;
844        NULL != ego_entry;
845        ego_entry = ego_entry->next)
846     if (0 == strcmp (identity, ego_entry->identifier))
847       break;
848
849   if (NULL == ego_entry)
850   {
851     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
852                 "Identity unknown (%s)\n", identity);
853     GNUNET_JSONAPI_document_delete (json_obj);
854     return;
855   }
856   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
857
858   if (0 >= handle->rest_handle->data_size)
859   {
860     GNUNET_SCHEDULER_add_now (&do_error, handle);
861     return;
862   }
863
864   term_data[handle->rest_handle->data_size] = '\0';
865   GNUNET_memcpy (term_data,
866                  handle->rest_handle->data,
867                  handle->rest_handle->data_size);
868   data_json = json_loads (term_data,
869                           JSON_DECODE_ANY,
870                           &err);
871   GNUNET_assert (GNUNET_OK ==
872                  GNUNET_JSON_parse (data_json, docspec,
873                                     NULL, NULL));
874   json_decref (data_json);
875   if (NULL == json_obj)
876   {
877     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
878                 "Unable to parse JSONAPI Object from %s\n",
879                 term_data);
880     GNUNET_SCHEDULER_add_now (&do_error, handle);
881     return;
882   }
883   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
884   {
885     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
886                 "Cannot create more than 1 resource! (Got %d)\n",
887                 GNUNET_JSONAPI_document_resource_count (json_obj));
888     GNUNET_JSONAPI_document_delete (json_obj);
889     GNUNET_SCHEDULER_add_now (&do_error, handle);
890     return;
891   }
892   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
893   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
894                                                        GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
895   {
896     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
897                 "Unsupported JSON data type\n");
898     GNUNET_JSONAPI_document_delete (json_obj);
899     resp = GNUNET_REST_create_response (NULL);
900     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
901     cleanup_handle (handle);
902     return;
903   }
904   name_str = GNUNET_JSONAPI_resource_get_id (json_res);
905   value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
906                                                   "value");
907   value_str = json_string_value (value_json);
908   attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str,
909                                                       GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
910                                                       value_str,
911                                                       strlen (value_str) + 1);
912   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
913   handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
914                                                              identity_priv,
915                                                              attribute,
916                                                              &finished_cont,
917                                                              handle);
918   GNUNET_free (attribute);
919   GNUNET_JSONAPI_document_delete (json_obj);
920 }
921
922
923
924 /**
925  * Collect all attributes for an ego
926  *
927  */
928 static void
929 attr_collect (void *cls,
930               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
931               const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
932 {
933   struct GNUNET_JSONAPI_Resource *json_resource;
934   struct RequestHandle *handle = cls;
935   json_t *value;
936   char* tmp_value;
937   
938   if ((NULL == attr->name) || (NULL == attr->data))
939   {
940     GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
941     return;
942   }
943
944   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
945               attr->name);
946   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
947                                                attr->name);
948   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
949
950   tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type,
951                                            attr->data,
952                                            attr->data_size);
953
954   value = json_string (tmp_value);
955
956   GNUNET_JSONAPI_resource_add_attr (json_resource,
957                                     "value",
958                                     value);
959   json_decref (value);
960   GNUNET_free(tmp_value);
961   GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
962 }
963
964
965
966 /**
967  * List attributes for identity request
968  *
969  * @param con_handle the connection handle
970  * @param url the url
971  * @param cls the RequestHandle
972  */
973 static void
974 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
975                      const char* url,
976                      void *cls)
977 {
978   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
979   struct RequestHandle *handle = cls;
980   struct EgoEntry *ego_entry;
981   char *identity;
982
983   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
984               handle->url);
985   if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
986        strlen (handle->url))
987   {
988     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
989     GNUNET_SCHEDULER_add_now (&do_error, handle);
990     return;
991   }
992   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
993
994   for (ego_entry = handle->ego_head;
995        NULL != ego_entry;
996        ego_entry = ego_entry->next)
997     if (0 == strcmp (identity, ego_entry->identifier))
998       break;
999   handle->resp_object = GNUNET_JSONAPI_document_new ();
1000
1001
1002   if (NULL == ego_entry)
1003   {
1004     //Done
1005     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
1006                 identity);
1007     GNUNET_SCHEDULER_add_now (&return_response, handle);
1008     return;
1009   }
1010   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1011   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1012   handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
1013                                                                    priv_key,
1014                                                                    &collect_error_cb,
1015                                                                    handle,
1016                                                                    &attr_collect,
1017                                                                    handle,
1018                                                                    &collect_finished_cb,
1019                                                                    handle);
1020 }
1021
1022
1023 static void
1024 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1025                     const char* url,
1026                     void *cls)
1027 {
1028   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1029   const char* identity_str;
1030   const char* audience_str;
1031   const char* rnd_str;
1032
1033   struct RequestHandle *handle = cls;
1034   struct EgoEntry *ego_entry;
1035   struct MHD_Response *resp;
1036   struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
1037   struct GNUNET_JSONAPI_Document *json_obj;
1038   struct GNUNET_JSONAPI_Resource *json_res;
1039   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1040   char term_data[handle->rest_handle->data_size+1];
1041   json_t *rnd_json;
1042   json_t *identity_json;
1043   json_t *audience_json;
1044   json_t *data_json;
1045   json_error_t err;
1046   struct GNUNET_JSON_Specification docspec[] = {
1047     GNUNET_JSON_spec_jsonapi_document (&json_obj),
1048     GNUNET_JSON_spec_end()
1049   };
1050
1051   if (0 >= handle->rest_handle->data_size)
1052   {
1053     GNUNET_SCHEDULER_add_now (&do_error, handle);
1054     return;
1055   }
1056
1057   term_data[handle->rest_handle->data_size] = '\0';
1058   GNUNET_memcpy (term_data,
1059                  handle->rest_handle->data,
1060                  handle->rest_handle->data_size);
1061   data_json = json_loads (term_data,
1062                           JSON_DECODE_ANY,
1063                           &err);
1064   GNUNET_assert (GNUNET_OK ==
1065                  GNUNET_JSON_parse (data_json, docspec,
1066                                     NULL, NULL));
1067   json_decref (data_json);
1068   if (NULL == json_obj)
1069   {
1070     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1071                 "Unable to parse JSONAPI Object from %s\n",
1072                 term_data);
1073     GNUNET_SCHEDULER_add_now (&do_error, handle);
1074     return;
1075   }
1076   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
1077   {
1078     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1079                 "Cannot create more than 1 resource! (Got %d)\n",
1080                 GNUNET_JSONAPI_document_resource_count (json_obj));
1081     GNUNET_JSONAPI_document_delete (json_obj);
1082     GNUNET_SCHEDULER_add_now (&do_error, handle);
1083     return;
1084   }
1085   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
1086   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
1087                                                        GNUNET_REST_JSONAPI_IDENTITY_TICKET))
1088   {
1089     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1090                 "Unsupported JSON data type\n");
1091     GNUNET_JSONAPI_document_delete (json_obj);
1092     resp = GNUNET_REST_create_response (NULL);
1093     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
1094     cleanup_handle (handle);
1095     return;
1096   }
1097   rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1098                                                 "rnd");
1099   identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1100                                                      "identity");
1101   audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1102                                                      "audience");
1103   rnd_str = json_string_value (rnd_json);
1104   identity_str = json_string_value (identity_json);
1105   audience_str = json_string_value (audience_json);
1106
1107   GNUNET_STRINGS_string_to_data (rnd_str,
1108                                  strlen (rnd_str),
1109                                  &ticket.rnd,
1110                                  sizeof (uint64_t));
1111   GNUNET_STRINGS_string_to_data (identity_str,
1112                                  strlen (identity_str),
1113                                  &ticket.identity,
1114                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1115   GNUNET_STRINGS_string_to_data (audience_str,
1116                                  strlen (audience_str),
1117                                  &ticket.audience,
1118                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1119
1120   for (ego_entry = handle->ego_head;
1121        NULL != ego_entry;
1122        ego_entry = ego_entry->next)
1123   {
1124     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1125                                         &tmp_pk);
1126     if (0 == memcmp (&ticket.identity,
1127                      &tmp_pk,
1128                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1129       break;
1130   }
1131   if (NULL == ego_entry)
1132   {
1133     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1134                 "Identity unknown (%s)\n", identity_str);
1135     GNUNET_JSONAPI_document_delete (json_obj);
1136     return;
1137   }
1138   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1139
1140   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1141   handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
1142                                                            identity_priv,
1143                                                            &ticket,
1144                                                            &finished_cont,
1145                                                            handle);
1146   GNUNET_JSONAPI_document_delete (json_obj);
1147 }
1148
1149 static void
1150 consume_cont (void *cls,
1151               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1152               const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
1153 {
1154   struct RequestHandle *handle = cls;
1155   struct GNUNET_JSONAPI_Resource *json_resource;
1156   json_t *value;
1157
1158   if (NULL == identity)
1159   {
1160     GNUNET_SCHEDULER_add_now (&return_response, handle);
1161     return;
1162   }
1163
1164   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
1165               attr->name);
1166   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
1167                                                attr->name);
1168   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
1169
1170   value = json_string (attr->data);
1171   GNUNET_JSONAPI_resource_add_attr (json_resource,
1172                                     "value",
1173                                     value);
1174   json_decref (value);
1175 }
1176
1177 static void
1178 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
1179                      const char* url,
1180                      void *cls)
1181 {
1182   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
1183   const char* identity_str;
1184   const char* audience_str;
1185   const char* rnd_str;
1186
1187   struct RequestHandle *handle = cls;
1188   struct EgoEntry *ego_entry;
1189   struct MHD_Response *resp;
1190   struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
1191   struct GNUNET_JSONAPI_Document *json_obj;
1192   struct GNUNET_JSONAPI_Resource *json_res;
1193   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
1194   char term_data[handle->rest_handle->data_size+1];
1195   json_t *rnd_json;
1196   json_t *identity_json;
1197   json_t *audience_json;
1198   json_t *data_json;
1199   json_error_t err;
1200   struct GNUNET_JSON_Specification docspec[] = {
1201     GNUNET_JSON_spec_jsonapi_document (&json_obj),
1202     GNUNET_JSON_spec_end()
1203   };
1204
1205   if (0 >= handle->rest_handle->data_size)
1206   {
1207     GNUNET_SCHEDULER_add_now (&do_error, handle);
1208     return;
1209   }
1210
1211   term_data[handle->rest_handle->data_size] = '\0';
1212   GNUNET_memcpy (term_data,
1213                  handle->rest_handle->data,
1214                  handle->rest_handle->data_size);
1215   data_json = json_loads (term_data,
1216                           JSON_DECODE_ANY,
1217                           &err);
1218   GNUNET_assert (GNUNET_OK ==
1219                  GNUNET_JSON_parse (data_json, docspec,
1220                                     NULL, NULL));
1221   json_decref (data_json);
1222   if (NULL == json_obj)
1223   {
1224     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1225                 "Unable to parse JSONAPI Object from %s\n",
1226                 term_data);
1227     GNUNET_SCHEDULER_add_now (&do_error, handle);
1228     return;
1229   }
1230   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
1231   {
1232     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1233                 "Cannot create more than 1 resource! (Got %d)\n",
1234                 GNUNET_JSONAPI_document_resource_count (json_obj));
1235     GNUNET_JSONAPI_document_delete (json_obj);
1236     GNUNET_SCHEDULER_add_now (&do_error, handle);
1237     return;
1238   }
1239   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
1240   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
1241                                                        GNUNET_REST_JSONAPI_IDENTITY_TICKET))
1242   {
1243     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1244                 "Unsupported JSON data type\n");
1245     GNUNET_JSONAPI_document_delete (json_obj);
1246     resp = GNUNET_REST_create_response (NULL);
1247     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
1248     cleanup_handle (handle);
1249     return;
1250   }
1251   rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1252                                                 "rnd");
1253   identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1254                                                      "identity");
1255   audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1256                                                      "audience");
1257   rnd_str = json_string_value (rnd_json);
1258   identity_str = json_string_value (identity_json);
1259   audience_str = json_string_value (audience_json);
1260
1261   GNUNET_STRINGS_string_to_data (rnd_str,
1262                                  strlen (rnd_str),
1263                                  &ticket.rnd,
1264                                  sizeof (uint64_t));
1265   GNUNET_STRINGS_string_to_data (identity_str,
1266                                  strlen (identity_str),
1267                                  &ticket.identity,
1268                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1269   GNUNET_STRINGS_string_to_data (audience_str,
1270                                  strlen (audience_str),
1271                                  &ticket.audience,
1272                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1273
1274   for (ego_entry = handle->ego_head;
1275        NULL != ego_entry;
1276        ego_entry = ego_entry->next)
1277   {
1278     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1279                                         &tmp_pk);
1280     if (0 == memcmp (&ticket.audience,
1281                      &tmp_pk,
1282                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1283       break;
1284   }
1285   if (NULL == ego_entry)
1286   {
1287     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1288                 "Identity unknown (%s)\n", identity_str);
1289     GNUNET_JSONAPI_document_delete (json_obj);
1290     return;
1291   }
1292   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1293   handle->resp_object = GNUNET_JSONAPI_document_new ();
1294   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1295   handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
1296                                                             identity_priv,
1297                                                             &ticket,
1298                                                             &consume_cont,
1299                                                             handle);
1300   GNUNET_JSONAPI_document_delete (json_obj);
1301 }
1302
1303
1304
1305 /**
1306  * Respond to OPTIONS request
1307  *
1308  * @param con_handle the connection handle
1309  * @param url the url
1310  * @param cls the RequestHandle
1311  */
1312 static void
1313 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1314               const char* url,
1315               void *cls)
1316 {
1317   struct MHD_Response *resp;
1318   struct RequestHandle *handle = cls;
1319
1320   //For now, independent of path return all options
1321   resp = GNUNET_REST_create_response (NULL);
1322   MHD_add_response_header (resp,
1323                            "Access-Control-Allow-Methods",
1324                            allow_methods);
1325   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1326   cleanup_handle (handle);
1327   return;
1328 }
1329
1330 /**
1331  * Cookie interpretation
1332  */
1333 static void
1334 cookie_identity_interpretation (struct RequestHandle *handle)
1335 {
1336   struct GNUNET_HashCode cache_key;
1337   char* cookies;
1338   struct GNUNET_TIME_Absolute current_time, *relog_time;
1339   char delimiter[] = "; ";
1340
1341   //gets identity of login try with cookie
1342   GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
1343                       &cache_key);
1344   if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
1345                                                              &cache_key) )
1346   {
1347     //splits cookies and find 'Identity' cookie
1348     cookies = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
1349     handle->oidc->login_identity = strtok(cookies, delimiter);
1350
1351     while ( NULL != handle->oidc->login_identity )
1352     {
1353       if ( NULL != strstr (handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY) )
1354       {
1355         break;
1356       }
1357       handle->oidc->login_identity = strtok (NULL, delimiter);
1358     }
1359     GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen (handle->oidc->login_identity),
1360                       &cache_key);
1361     if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time, &cache_key) )
1362     {
1363       relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
1364                                                     &cache_key);
1365       current_time = GNUNET_TIME_absolute_get ();
1366       // 30 min after old login -> redirect to login
1367       if ( current_time.abs_value_us <= relog_time->abs_value_us )
1368       {
1369         handle->oidc->login_identity = strtok(handle->oidc->login_identity, OIDC_COOKIE_HEADER_INFORMATION_KEY);
1370         handle->oidc->login_identity = GNUNET_strdup(handle->oidc->login_identity);
1371       }
1372     }
1373     else
1374     {
1375       handle->oidc->login_identity = NULL;
1376     }
1377   }
1378 }
1379
1380 /**
1381  * Login redirection
1382  */
1383 static void
1384 login_redirection(void *cls)
1385 {
1386   char *login_base_url;
1387   char *new_redirect;
1388   struct MHD_Response *resp;
1389   struct RequestHandle *handle = cls;
1390
1391   if ( GNUNET_OK
1392       == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
1393                                                 "address", &login_base_url) )
1394   {
1395     GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
1396                      login_base_url,
1397                      OIDC_RESPONSE_TYPE_KEY,
1398                      handle->oidc->response_type,
1399                      OIDC_CLIENT_ID_KEY,
1400                      handle->oidc->client_id,
1401                      OIDC_REDIRECT_URI_KEY,
1402                      handle->oidc->redirect_uri,
1403                      OIDC_SCOPE_KEY,
1404                      handle->oidc->scope,
1405                      OIDC_STATE_KEY,
1406                      (NULL != handle->oidc->state) ? handle->oidc->state : "",
1407                      OIDC_NONCE_KEY,
1408                      (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
1409     resp = GNUNET_REST_create_response ("");
1410     MHD_add_response_header (resp, "Location", new_redirect);
1411     GNUNET_free(login_base_url);
1412   }
1413   else
1414   {
1415     handle->emsg = GNUNET_strdup("server_error");
1416     handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1417     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1418     GNUNET_SCHEDULER_add_now (&do_error, handle);
1419     return;
1420   }
1421   handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1422   GNUNET_free(new_redirect);
1423   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1424 }
1425
1426 /**
1427  * Function called if we had an error in zone-to-name mapping.
1428  */
1429 static void
1430 oidc_iteration_error (void *cls)
1431 {
1432   struct RequestHandle *handle = cls;
1433   handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR");
1434   handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1435   GNUNET_SCHEDULER_add_now (&do_error, handle);
1436 }
1437
1438 static void
1439 oidc_ticket_issue_cb (void* cls,
1440                  const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
1441 {
1442   struct RequestHandle *handle = cls;
1443   struct MHD_Response *resp;
1444   char *ticket_str;
1445   char *redirect_uri;
1446   char *code_json_string;
1447   char *code_base64_final_string;
1448   handle->idp_op = NULL;
1449   resp = GNUNET_REST_create_response ("");
1450   if (NULL != ticket) {
1451     ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket,
1452                                                       sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket));
1453     //TODO change if more attributes are needed (see max_age)
1454     GNUNET_asprintf (&code_json_string, "{\"ticket\":\"%s\"%s%s%s}",
1455                      ticket_str,
1456                      (NULL != handle->oidc->nonce) ? ", \"nonce\":\"" : "",
1457                      (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "",
1458                      (NULL != handle->oidc->nonce) ? "\"" : "");
1459     code_base64_final_string = base_64_encode(code_json_string);
1460     GNUNET_asprintf (&redirect_uri, "%s?%s=%s&state=%s",
1461                      handle->oidc->redirect_uri,
1462                      handle->oidc->response_type,
1463                      code_base64_final_string, handle->oidc->state);
1464     MHD_add_response_header (resp, "Location", redirect_uri);
1465     handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1466     GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1467     GNUNET_free (redirect_uri);
1468     GNUNET_free (ticket_str);
1469     GNUNET_free (code_json_string);
1470     GNUNET_free (code_base64_final_string);
1471     return;
1472   }
1473   handle->emsg = GNUNET_strdup("server_error");
1474   handle->edesc = GNUNET_strdup("Server cannot generate ticket.");
1475   GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1476 }
1477
1478 static void
1479 oidc_collect_finished_cb (void *cls)
1480 {
1481   struct RequestHandle *handle = cls;
1482   handle->attr_it = NULL;
1483   handle->ticket_it = NULL;
1484   if (NULL == handle->attr_list->list_head)
1485   {
1486     handle->emsg = GNUNET_strdup("invalid_scope");
1487     handle->edesc = GNUNET_strdup("The requested scope is not available.");
1488     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1489     return;
1490   }
1491   handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_issue (handle->idp,
1492                                                     &handle->priv_key,
1493                                                     &handle->oidc->client_pkey,
1494                                                     handle->attr_list,
1495                                                     &oidc_ticket_issue_cb,
1496                                                     handle);
1497 }
1498
1499
1500 /**
1501  * Collect all attributes for an ego
1502  */
1503 static void
1504 oidc_attr_collect (void *cls,
1505               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1506               const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
1507 {
1508   struct RequestHandle *handle = cls;
1509   struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
1510   char* scope_variables;
1511   char* scope_variable;
1512   char delimiter[]=" ";
1513
1514   if ( (NULL == attr->name) || (NULL == attr->data) )
1515   {
1516     GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1517     return;
1518   }
1519
1520   scope_variables = GNUNET_strdup(handle->oidc->scope);
1521   scope_variable = strtok (scope_variables, delimiter);
1522   while (NULL != scope_variable)
1523   {
1524     if ( 0 == strcmp (attr->name, scope_variable) )
1525     {
1526       break;
1527     }
1528     scope_variable = strtok (NULL, delimiter);
1529   }
1530   if ( NULL == scope_variable )
1531   {
1532     GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1533     return;
1534   }
1535   GNUNET_free(scope_variables);
1536
1537   le = GNUNET_new(struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry);
1538   le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr->name, attr->type,
1539                                                    attr->data, attr->data_size);
1540   GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head,
1541                               handle->attr_list->list_tail, le);
1542   GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
1543 }
1544
1545
1546 /**
1547  * Cookie and Time check
1548  */
1549 static void
1550 login_check (void *cls)
1551 {
1552   struct RequestHandle *handle = cls;
1553   struct GNUNET_TIME_Absolute current_time, *relog_time;
1554   struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey;
1555   struct GNUNET_HashCode cache_key;
1556   char *identity_cookie;
1557
1558   GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity);
1559   GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1560   GNUNET_free(identity_cookie);
1561   //No login time for identity -> redirect to login
1562   if ( GNUNET_YES
1563       == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time,
1564                                                  &cache_key) )
1565   {
1566     relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
1567                                                     &cache_key);
1568     current_time = GNUNET_TIME_absolute_get ();
1569     // 30 min after old login -> redirect to login
1570     if ( current_time.abs_value_us <= relog_time->abs_value_us )
1571     {
1572       if ( GNUNET_OK
1573           != GNUNET_CRYPTO_ecdsa_public_key_from_string (
1574               handle->oidc->login_identity,
1575               strlen (handle->oidc->login_identity), &pubkey) )
1576       {
1577         handle->emsg = GNUNET_strdup("invalid_cookie");
1578         handle->edesc = GNUNET_strdup(
1579             "The cookie of a login identity is not valid");
1580         GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1581         return;
1582       }
1583       // iterate over egos and compare their public key
1584       for (handle->ego_entry = handle->ego_head;
1585       NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
1586       {
1587         GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1588         if ( 0
1589             == memcmp (&ego_pkey, &pubkey,
1590                        sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1591         {
1592           handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (
1593               handle->ego_entry->ego);
1594           handle->resp_object = GNUNET_JSONAPI_document_new ();
1595           handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1596           handle->attr_list = GNUNET_new(
1597               struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList);
1598           handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (
1599               handle->idp, &handle->priv_key, &oidc_iteration_error, handle,
1600               &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle);
1601           return;
1602         }
1603       }
1604       handle->emsg = GNUNET_strdup("invalid_cookie");
1605       handle->edesc = GNUNET_strdup(
1606           "The cookie of the login identity is not valid");
1607       GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1608       return;
1609     }
1610   }
1611 }
1612
1613 /**
1614  * Create a response with requested records
1615  *
1616  * @param handle the RequestHandle
1617  */
1618 static void
1619 namestore_iteration_callback (
1620     void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1621     const char *rname, unsigned int rd_len,
1622     const struct GNUNET_GNSRECORD_Data *rd)
1623 {
1624   struct RequestHandle *handle = cls;
1625   struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey;
1626   struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey;
1627   int i;
1628
1629   for (i = 0; i < rd_len; i++)
1630   {
1631     if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type )
1632       continue;
1633
1634     if ( NULL != handle->oidc->login_identity )
1635     {
1636       GNUNET_CRYPTO_ecdsa_public_key_from_string (
1637           handle->oidc->login_identity,
1638           strlen (handle->oidc->login_identity),
1639           &login_identity_pkey);
1640       GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego,
1641                                           &current_zone_pkey);
1642
1643       if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1644                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1645       {
1646         if ( 0 == memcmp (&login_identity_pkey, &current_zone_pkey,
1647                        sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1648         {
1649           handle->oidc->is_client_trusted = GNUNET_YES;
1650         }
1651       }
1652     }
1653     else
1654     {
1655       if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1656                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1657       {
1658         handle->oidc->is_client_trusted = GNUNET_YES;
1659       }
1660     }
1661   }
1662
1663   GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it);
1664 }
1665
1666 /**
1667  * Iteration over all results finished, build final
1668  * response.
1669  *
1670  * @param cls the `struct RequestHandle`
1671  */
1672 static void namestore_iteration_finished (void *cls)
1673 {
1674   struct RequestHandle *handle = cls;
1675   struct GNUNET_HashCode cache_key;
1676
1677   char *expected_redirect_uri;
1678   char *expected_scope;
1679   char delimiter[]=" ";
1680   int number_of_ignored_parameter, iterator;
1681
1682
1683   handle->ego_entry = handle->ego_entry->next;
1684
1685   if(NULL != handle->ego_entry)
1686   {
1687     handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1688     handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
1689                                            &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
1690                                            &namestore_iteration_finished, handle);
1691     return;
1692   }
1693   if (GNUNET_NO == handle->oidc->is_client_trusted)
1694   {
1695     handle->emsg = GNUNET_strdup("unauthorized_client");
1696     handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1697                                   "authorization code using this method.");
1698     GNUNET_SCHEDULER_add_now (&do_error, handle);
1699     return;
1700   }
1701
1702   // REQUIRED value: redirect_uri
1703   GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1704                       &cache_key);
1705   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1706                                                            &cache_key))
1707   {
1708     handle->emsg=GNUNET_strdup("invalid_request");
1709     handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
1710     GNUNET_SCHEDULER_add_now (&do_error, handle);
1711     return;
1712   }
1713   handle->oidc->redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1714                                                 &cache_key);
1715
1716   GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
1717   // verify the redirect uri matches https://<client_id>.zkey[/xyz]
1718   if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
1719   {
1720     handle->emsg=GNUNET_strdup("invalid_request");
1721     handle->edesc=GNUNET_strdup("Invalid redirect_uri");
1722     GNUNET_SCHEDULER_add_now (&do_error, handle);
1723     GNUNET_free(expected_redirect_uri);
1724     return;
1725   }
1726   handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
1727
1728   GNUNET_free(expected_redirect_uri);
1729   // REQUIRED value: response_type
1730   GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1731                       &cache_key);
1732   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1733                                                            &cache_key))
1734   {
1735     handle->emsg=GNUNET_strdup("invalid_request");
1736     handle->edesc=GNUNET_strdup("missing parameter response_type");
1737     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1738     return;
1739   }
1740   handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1741                                                     &cache_key);
1742   handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
1743
1744   // REQUIRED value: scope
1745   GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
1746   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1747                                                            &cache_key))
1748   {
1749     handle->emsg=GNUNET_strdup("invalid_request");
1750     handle->edesc=GNUNET_strdup("missing parameter scope");
1751     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1752     return;
1753   }
1754   handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1755                                             &cache_key);
1756   handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
1757
1758   //OPTIONAL value: nonce
1759   GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
1760   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1761                                                            &cache_key))
1762   {
1763     handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1764                                               &cache_key);
1765     handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
1766   }
1767
1768   //TODO check other values if needed
1769   number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1770   for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1771   {
1772     GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1773                         strlen(OIDC_ignored_parameter_array[iterator]),
1774                         &cache_key);
1775     if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
1776                                                             &cache_key))
1777     {
1778       handle->emsg=GNUNET_strdup("access_denied");
1779       GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1780                        OIDC_ignored_parameter_array[iterator]);
1781       GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1782       return;
1783     }
1784   }
1785
1786   // Checks if response_type is 'code'
1787   if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1788   {
1789     handle->emsg=GNUNET_strdup("unsupported_response_type");
1790     handle->edesc=GNUNET_strdup("The authorization server does not support "
1791                                 "obtaining this authorization code.");
1792     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1793     return;
1794   }
1795
1796   // Checks if scope contains 'openid'
1797   expected_scope = GNUNET_strdup(handle->oidc->scope);
1798   expected_scope = strtok (expected_scope, delimiter);
1799   while (NULL != expected_scope)
1800   {
1801     if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1802     {
1803       break;
1804     }
1805     expected_scope = strtok (NULL, delimiter);
1806   }
1807   if (NULL == expected_scope)
1808   {
1809     handle->emsg = GNUNET_strdup("invalid_scope");
1810     handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1811                                 "malformed.");
1812     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1813     return;
1814   }
1815
1816   GNUNET_free(expected_scope);
1817
1818   if( NULL != handle->oidc->login_identity )
1819   {
1820     GNUNET_SCHEDULER_add_now(&login_check,handle);
1821     return;
1822   }
1823
1824   GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1825 }
1826
1827 /**
1828  * Responds to authorization GET and url-encoded POST request
1829  *
1830  * @param con_handle the connection handle
1831  * @param url the url
1832  * @param cls the RequestHandle
1833  */
1834 static void
1835 authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1836                 const char* url,
1837                 void *cls)
1838 {
1839   struct RequestHandle *handle = cls;
1840   struct GNUNET_HashCode cache_key;
1841
1842   cookie_identity_interpretation(handle);
1843
1844   //RECOMMENDED value: state - REQUIRED for answers
1845   GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
1846   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1847                                                            &cache_key))
1848   {
1849     handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1850                                               &cache_key);
1851     handle->oidc->state = GNUNET_strdup (handle->oidc->state);
1852   }
1853
1854   // REQUIRED value: client_id
1855   GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1856                       &cache_key);
1857   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1858                                                            &cache_key))
1859   {
1860     handle->emsg=GNUNET_strdup("invalid_request");
1861     handle->edesc=GNUNET_strdup("missing parameter client_id");
1862     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1863     GNUNET_SCHEDULER_add_now (&do_error, handle);
1864     return;
1865   }
1866   handle->oidc->client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1867                                                 &cache_key);
1868   handle->oidc->client_id = GNUNET_strdup (handle->oidc->client_id);
1869
1870   if ( GNUNET_OK
1871       != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
1872                                                      strlen (handle->oidc->client_id),
1873                                                      &handle->oidc->client_pkey) )
1874   {
1875     handle->emsg = GNUNET_strdup("unauthorized_client");
1876     handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1877                                   "authorization code using this method.");
1878     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1879     GNUNET_SCHEDULER_add_now (&do_error, handle);
1880     return;
1881   }
1882
1883
1884   if ( NULL == handle->ego_head )
1885   {
1886     handle->emsg = GNUNET_strdup("server_error");
1887     handle->edesc = GNUNET_strdup ("Egos are missing");
1888     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1889     GNUNET_SCHEDULER_add_now (&do_error, handle);
1890     return;
1891   }
1892
1893   handle->ego_entry = handle->ego_head;
1894   handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
1895   handle->oidc->is_client_trusted = GNUNET_NO;
1896
1897   // Checks if client_id is valid:
1898   handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
1899       handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
1900       handle, &namestore_iteration_callback, handle,
1901       &namestore_iteration_finished, handle);
1902 }
1903
1904 /**
1905  * Combines an identity with a login time and responds OK to login request
1906  *
1907  * @param con_handle the connection handle
1908  * @param url the url
1909  * @param cls the RequestHandle
1910  */
1911 static void
1912 login_cont (struct GNUNET_REST_RequestHandle *con_handle,
1913             const char* url,
1914             void *cls)
1915 {
1916   struct MHD_Response *resp = GNUNET_REST_create_response ("");
1917   struct RequestHandle *handle = cls;
1918   struct GNUNET_HashCode cache_key;
1919   struct GNUNET_TIME_Absolute *current_time;
1920   struct GNUNET_TIME_Absolute *last_time;
1921   char* cookie;
1922   json_t *root;
1923   json_error_t error;
1924   json_t *identity;
1925   root = json_loads (handle->rest_handle->data, 0, &error);
1926   identity = json_object_get (root, "identity");
1927   if ( json_is_string(identity) )
1928   {
1929     GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1930
1931     GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1932
1933     current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
1934     *current_time = GNUNET_TIME_relative_to_absolute (
1935         GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_minute_ (),
1936                                        30));
1937     last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key);
1938     if (NULL != last_time)
1939     {
1940       GNUNET_free(last_time);
1941     }
1942     GNUNET_CONTAINER_multihashmap_put (
1943         OIDC_identity_login_time, &cache_key, current_time,
1944         GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1945
1946     handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1947   }
1948   else
1949   {
1950     handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1951   }
1952   GNUNET_free(cookie);
1953   json_decref (root);
1954   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1955   return;
1956 }
1957
1958 static void
1959 token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1960                 const char* url,
1961                 void *cls)
1962 {
1963   //TODO static strings
1964
1965   struct RequestHandle *handle = cls;
1966   struct GNUNET_HashCode cache_key;
1967   char *authorization, *credentials;
1968   char delimiter[]=" ";
1969   char delimiter_user_psw[]=":";
1970   char *grant_type, *code, *redirect_uri, *expected_redirect_uri;
1971   char *user_psw = NULL, *client_id, *psw;
1972   char *expected_psw;
1973   int client_exists = GNUNET_NO;
1974   struct MHD_Response *resp;
1975   char* code_output;
1976   json_t *root, *ticket_string, *nonce, *max_age;
1977   json_error_t error;
1978   char *json_response;
1979
1980   /*
1981    * Check Authorization
1982    */
1983   GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
1984                       strlen (OIDC_AUTHORIZATION_HEADER_KEY),
1985                       &cache_key);
1986   if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
1987                                                              &cache_key) )
1988   {
1989     handle->emsg=GNUNET_strdup("invalid_client");
1990     handle->edesc=GNUNET_strdup("missing authorization");
1991     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1992     GNUNET_SCHEDULER_add_now (&do_error, handle);
1993     return;
1994   }
1995   authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
1996
1997   //TODO authorization pointer will be moved as well
1998   //split header in "Basic" and [content]
1999   credentials = strtok (authorization, delimiter);
2000   if (0 != strcmp ("Basic",credentials))
2001   {
2002     handle->emsg=GNUNET_strdup("invalid_client");
2003     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2004     GNUNET_SCHEDULER_add_now (&do_error, handle);
2005     return;
2006   }
2007   credentials = strtok(NULL, delimiter);
2008   if (NULL == credentials)
2009   {
2010     handle->emsg=GNUNET_strdup("invalid_client");
2011     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2012     GNUNET_SCHEDULER_add_now (&do_error, handle);
2013     return;
2014   }
2015   GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), &user_psw);
2016
2017   if ( NULL == user_psw )
2018   {
2019     handle->emsg=GNUNET_strdup("invalid_client");
2020     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2021     GNUNET_SCHEDULER_add_now (&do_error, handle);
2022     return;
2023   }
2024   client_id = strtok (user_psw, delimiter_user_psw);
2025   if ( NULL == client_id )
2026   {
2027     GNUNET_free_non_null(user_psw);
2028     handle->emsg=GNUNET_strdup("invalid_client");
2029     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2030     GNUNET_SCHEDULER_add_now (&do_error, handle);
2031     return;
2032   }
2033   psw = strtok (NULL, delimiter_user_psw);
2034   if (NULL == psw)
2035   {
2036     GNUNET_free_non_null(user_psw);
2037     handle->emsg=GNUNET_strdup("invalid_client");
2038     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2039     GNUNET_SCHEDULER_add_now (&do_error, handle);
2040     return;
2041   }
2042   //check client password
2043   if ( GNUNET_OK
2044       == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
2045                                                 "psw", &expected_psw) )
2046   {
2047     if (0 != strcmp (expected_psw, psw))
2048     {
2049       handle->emsg=GNUNET_strdup("invalid_client");
2050       handle->response_code = MHD_HTTP_UNAUTHORIZED;
2051       GNUNET_SCHEDULER_add_now (&do_error, handle);
2052       return;
2053     }
2054     GNUNET_free(expected_psw);
2055   }
2056   else
2057   {
2058     handle->emsg = GNUNET_strdup("server_error");
2059     handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2060     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2061     GNUNET_SCHEDULER_add_now (&do_error, handle);
2062     return;
2063   }
2064   //check client_id
2065   for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; )
2066   {
2067     if ( 0 == strcmp(handle->ego_entry->keystring, client_id))
2068     {
2069       client_exists = GNUNET_YES;
2070       break;
2071     }
2072     handle->ego_entry = handle->ego_entry->next;
2073   }
2074   if (GNUNET_NO == client_exists)
2075   {
2076     handle->emsg=GNUNET_strdup("invalid_client");
2077     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2078     GNUNET_SCHEDULER_add_now (&do_error, handle);
2079     return;
2080   }
2081
2082   /*
2083    * Check parameter
2084    */
2085
2086   //TODO Do not allow multiple equal parameter names
2087   //REQUIRED grant_type
2088   GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key);
2089   if ( GNUNET_NO
2090       == GNUNET_CONTAINER_multihashmap_contains (
2091           handle->rest_handle->url_param_map, &cache_key) )
2092   {
2093     handle->emsg = GNUNET_strdup("invalid_request");
2094     handle->edesc = GNUNET_strdup("missing parameter grant_type");
2095     handle->response_code = MHD_HTTP_BAD_REQUEST;
2096     GNUNET_SCHEDULER_add_now (&do_error, handle);
2097     return;
2098   }
2099   grant_type = GNUNET_CONTAINER_multihashmap_get (
2100       handle->rest_handle->url_param_map, &cache_key);
2101
2102   //REQUIRED code
2103   GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key);
2104   if ( GNUNET_NO
2105       == GNUNET_CONTAINER_multihashmap_contains (
2106           handle->rest_handle->url_param_map, &cache_key) )
2107   {
2108     handle->emsg = GNUNET_strdup("invalid_request");
2109     handle->edesc = GNUNET_strdup("missing parameter code");
2110     handle->response_code = MHD_HTTP_BAD_REQUEST;
2111     GNUNET_SCHEDULER_add_now (&do_error, handle);
2112     return;
2113   }
2114   code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
2115                                             &cache_key);
2116
2117   //REQUIRED redirect_uri
2118   GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
2119                       &cache_key);
2120   if ( GNUNET_NO
2121       == GNUNET_CONTAINER_multihashmap_contains (
2122           handle->rest_handle->url_param_map, &cache_key) )
2123   {
2124     handle->emsg = GNUNET_strdup("invalid_request");
2125     handle->edesc = GNUNET_strdup("missing parameter redirect_uri");
2126     handle->response_code = MHD_HTTP_BAD_REQUEST;
2127     GNUNET_SCHEDULER_add_now (&do_error, handle);
2128     return;
2129   }
2130   redirect_uri = GNUNET_CONTAINER_multihashmap_get (
2131       handle->rest_handle->url_param_map, &cache_key);
2132
2133
2134   //Check parameter grant_type == "authorization_code"
2135   if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type))
2136   {
2137     handle->emsg=GNUNET_strdup("unsupported_grant_type");
2138     handle->response_code = MHD_HTTP_BAD_REQUEST;
2139     GNUNET_SCHEDULER_add_now (&do_error, handle);
2140     return;
2141   }
2142   // check redirect_uri
2143   GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", client_id);
2144   // verify the redirect uri matches https://<client_id>.zkey[/xyz]
2145   if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
2146   {
2147     handle->emsg=GNUNET_strdup("invalid_request");
2148     handle->edesc=GNUNET_strdup("Invalid redirect_uri");
2149     handle->response_code = MHD_HTTP_BAD_REQUEST;
2150     GNUNET_SCHEDULER_add_now (&do_error, handle);
2151     GNUNET_free(expected_redirect_uri);
2152     return;
2153   }
2154   GNUNET_free(expected_redirect_uri);
2155   GNUNET_CRYPTO_hash(code, strlen(code), &cache_key);
2156   if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(OIDC_ticket_once,&cache_key))
2157   {
2158     handle->emsg = GNUNET_strdup("invalid_request");
2159     handle->edesc = GNUNET_strdup("Cannot use the same code more than once");
2160     handle->response_code = MHD_HTTP_BAD_REQUEST;
2161     GNUNET_SCHEDULER_add_now (&do_error, handle);
2162     return;
2163   }
2164   int i=1;
2165   GNUNET_CONTAINER_multihashmap_put(OIDC_ticket_once,&cache_key,&i,GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
2166
2167   //decode code
2168   GNUNET_STRINGS_base64_decode(code,strlen(code),&code_output);
2169   root = json_loads (code_output, 0, &error);
2170   GNUNET_free(code_output);
2171   ticket_string = json_object_get (root, "ticket");
2172   nonce = json_object_get (root, "nonce");
2173   max_age = json_object_get (root, "max_age");
2174
2175   if(ticket_string == NULL && !json_is_string(ticket_string))
2176   {
2177     handle->emsg = GNUNET_strdup("invalid_request");
2178     handle->edesc = GNUNET_strdup("invalid code");
2179     handle->response_code = MHD_HTTP_BAD_REQUEST;
2180     GNUNET_SCHEDULER_add_now (&do_error, handle);
2181     return;
2182   }
2183
2184   struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket = GNUNET_new(struct GNUNET_IDENTITY_PROVIDER_Ticket);
2185   if ( GNUNET_OK
2186       != GNUNET_STRINGS_string_to_data (json_string_value(ticket_string),
2187                                         strlen (json_string_value(ticket_string)),
2188                                         ticket,
2189                                         sizeof(struct GNUNET_IDENTITY_PROVIDER_Ticket)))
2190   {
2191     handle->emsg = GNUNET_strdup("invalid_request");
2192     handle->edesc = GNUNET_strdup("invalid code");
2193     handle->response_code = MHD_HTTP_BAD_REQUEST;
2194     GNUNET_SCHEDULER_add_now (&do_error, handle);
2195     GNUNET_free(ticket);
2196     return;
2197   }
2198   // this is the current client (relying party)
2199   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
2200   GNUNET_IDENTITY_ego_get_public_key(handle->ego_entry->ego,&pub_key);
2201   if (0 != memcmp(&pub_key,&ticket->audience,sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
2202   {
2203     handle->emsg = GNUNET_strdup("invalid_request");
2204     handle->edesc = GNUNET_strdup("invalid code");
2205     handle->response_code = MHD_HTTP_BAD_REQUEST;
2206     GNUNET_SCHEDULER_add_now (&do_error, handle);
2207     GNUNET_free(ticket);
2208     return;
2209   }
2210
2211   //create jwt
2212   unsigned long long int expiration_time;
2213   if ( GNUNET_OK
2214       != GNUNET_CONFIGURATION_get_value_number(cfg, "identity-rest-plugin",
2215                                                 "expiration_time", &expiration_time) )
2216   {
2217     handle->emsg = GNUNET_strdup("server_error");
2218     handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2219     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2220     GNUNET_SCHEDULER_add_now (&do_error, handle);
2221     GNUNET_free(ticket);
2222     return;
2223   }
2224
2225   struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *cl = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList);
2226   //aud REQUIRED public key client_id must be there
2227   GNUNET_IDENTITY_ATTRIBUTE_list_add(cl,
2228                                      "aud",
2229                                      GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2230                                      client_id,
2231                                      strlen(client_id));
2232   //exp REQUIRED time expired from config
2233   //TODO time as seconds
2234   struct GNUNET_TIME_Absolute exp_time = GNUNET_TIME_relative_to_absolute (
2235       GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
2236                                      expiration_time));
2237   const char* exp_time_string = GNUNET_STRINGS_absolute_time_to_string(exp_time);
2238   GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
2239                                       "exp",
2240                                       GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2241                                       exp_time_string,
2242                                       strlen(exp_time_string));
2243   //iat REQUIRED time now
2244   //TODO time as seconds
2245   struct GNUNET_TIME_Absolute time_now = GNUNET_TIME_absolute_get();
2246   const char* time_now_string = GNUNET_STRINGS_absolute_time_to_string(time_now);
2247   GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
2248                                       "iat",
2249                                       GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2250                                       time_now_string,
2251                                       strlen(time_now_string));
2252   //nonce only if nonce is provided
2253   if ( NULL != nonce && json_is_string(nonce) )
2254   {
2255     GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
2256                                         "nonce",
2257                                         GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2258                                         json_string_value(nonce),
2259                                         strlen(json_string_value(nonce)));
2260   }
2261   //auth_time only if max_age is provided
2262   if ( NULL != max_age && json_is_string(max_age) )
2263   {
2264     GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
2265                                         "auth_time",
2266                                         GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
2267                                         json_string_value(max_age),
2268                                         strlen(json_string_value(max_age)));
2269   }
2270   //TODO OPTIONAL acr,amr,azp
2271
2272   //TODO lookup client for client == audience of ticket
2273   struct EgoEntry *ego_entry;
2274   for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
2275   {
2276     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
2277     if (0 == memcmp (&pub_key, &ticket->audience, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
2278     {
2279       break;
2280     }
2281   }
2282   if ( NULL == ego_entry )
2283   {
2284     handle->emsg = GNUNET_strdup("invalid_request");
2285     handle->edesc = GNUNET_strdup("invalid code....");
2286     handle->response_code = MHD_HTTP_BAD_REQUEST;
2287     GNUNET_SCHEDULER_add_now (&do_error, handle);
2288     GNUNET_free(ticket);
2289     return;
2290   }
2291   char *id_token = jwt_create_from_list(&ticket->audience,
2292                                          cl,
2293                                          GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego));
2294
2295   //Create random access_token
2296   char* access_token_number;
2297   char* access_token;
2298   uint64_t random_number;
2299   random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
2300   GNUNET_asprintf(&access_token_number, "%" PRIu64, random_number);
2301   GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token);
2302
2303
2304   
2305   //TODO OPTIONAL add refresh_token and scope
2306   GNUNET_asprintf (&json_response,
2307                    "{ \"access_token\" : \"%s\", "
2308                    "\"token_type\" : \"Bearer\", "
2309                    "\"expires_in\" : %d, "
2310                    "\"id_token\" : \"%s\"}",
2311                    access_token,
2312                    expiration_time,
2313                    id_token);
2314   GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key);
2315   char *id_ticket_combination;
2316   GNUNET_asprintf(&id_ticket_combination,
2317                   "%s;%s",
2318                   client_id,
2319                   json_string_value(ticket_string));
2320   GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token,
2321                                     &cache_key,
2322                                     id_ticket_combination,
2323                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
2324
2325   resp = GNUNET_REST_create_response (json_response);
2326   MHD_add_response_header (resp, "Cache-Control", "no-store");
2327   MHD_add_response_header (resp, "Pragma", "no-cache");
2328   MHD_add_response_header (resp, "Content-Type", "application/json");
2329   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2330
2331   //TODO one time ticket/code
2332
2333   //TODO free
2334   GNUNET_IDENTITY_ATTRIBUTE_list_destroy(cl);
2335   GNUNET_free(access_token_number);
2336   GNUNET_free(access_token);
2337   GNUNET_free(user_psw);
2338   GNUNET_free(json_response);
2339   GNUNET_free(ticket);
2340   GNUNET_free(id_token);
2341   json_decref (root);
2342   GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle);
2343 }
2344
2345
2346 static void
2347 consume_ticket (void *cls,
2348               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
2349               const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
2350 {
2351   struct RequestHandle *handle = cls;
2352
2353   if (NULL == identity)
2354   {
2355     GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle);
2356     return;
2357   }
2358
2359   json_object_set_new (handle->oidc->response,
2360                        attr->name,
2361                        json_string(attr->data));
2362 }
2363
2364 static void
2365 userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
2366                    const char* url, void *cls)
2367 {
2368   struct RequestHandle *handle = cls;
2369   char delimiter[] = " ";
2370   char delimiter_db[] = ";";
2371   struct GNUNET_HashCode cache_key;
2372   char *authorization, *authorization_type, *authorization_access_token;
2373   char *client_ticket;
2374   struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket;
2375
2376   GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
2377                       strlen (OIDC_AUTHORIZATION_HEADER_KEY),
2378                       &cache_key);
2379   if ( GNUNET_NO
2380       == GNUNET_CONTAINER_multihashmap_contains (
2381           handle->rest_handle->header_param_map, &cache_key) )
2382   {
2383     handle->emsg = GNUNET_strdup("invalid_token");
2384     handle->edesc = GNUNET_strdup("No Access Token");
2385     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2386     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2387     return;
2388   }
2389   authorization = GNUNET_CONTAINER_multihashmap_get (
2390       handle->rest_handle->header_param_map, &cache_key);
2391
2392   //TODO authorization pointer will be moved as well
2393   //split header in "Bearer" and access_token
2394   authorization_type = strtok (authorization, delimiter);
2395   if ( 0 != strcmp ("Bearer", authorization_type) )
2396   {
2397     handle->emsg = GNUNET_strdup("invalid_token");
2398     handle->edesc = GNUNET_strdup("No Access Token");
2399     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2400     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2401     return;
2402   }
2403   authorization_access_token = strtok (NULL, delimiter);
2404   if ( NULL == authorization_access_token )
2405   {
2406     handle->emsg = GNUNET_strdup("invalid_token");
2407     handle->edesc = GNUNET_strdup("No Access Token");
2408     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2409     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2410     return;
2411   }
2412
2413   GNUNET_CRYPTO_hash (authorization_access_token,
2414                       strlen (authorization_access_token),
2415                       &cache_key);
2416   if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token,
2417                                                             &cache_key) )
2418   {
2419     handle->emsg = GNUNET_strdup("invalid_token");
2420     handle->edesc = GNUNET_strdup("The Access Token expired");
2421     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2422     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2423     return;
2424   }
2425
2426   client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token,
2427                                                     &cache_key);
2428
2429   client_ticket = strtok(client_ticket,delimiter_db);
2430   if (NULL == client_ticket)
2431   {
2432     handle->emsg = GNUNET_strdup("invalid_token");
2433     handle->edesc = GNUNET_strdup("The Access Token expired");
2434     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2435     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2436     return;
2437   }
2438   handle->ego_entry = handle->ego_head;
2439   for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
2440   {
2441     if (0 == strcmp(handle->ego_entry->keystring,client_ticket))
2442     {
2443       break;
2444     }
2445   }
2446   if (NULL == handle->ego_entry)
2447   {
2448     handle->emsg = GNUNET_strdup("invalid_token");
2449     handle->edesc = GNUNET_strdup("The Access Token expired");
2450     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2451     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2452     return;
2453   }
2454   client_ticket = strtok(NULL, delimiter_db);
2455   if (NULL == client_ticket)
2456   {
2457     handle->emsg = GNUNET_strdup("invalid_token");
2458     handle->edesc = GNUNET_strdup("The Access Token expired");
2459     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2460     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2461     return;
2462   }
2463   ticket = GNUNET_new(struct GNUNET_IDENTITY_PROVIDER_Ticket);
2464   if ( GNUNET_OK
2465       != GNUNET_STRINGS_string_to_data (client_ticket,
2466                                         strlen (client_ticket),
2467                                         ticket,
2468                                         sizeof(struct GNUNET_IDENTITY_PROVIDER_Ticket)))
2469   {
2470     handle->emsg = GNUNET_strdup("invalid_token");
2471     handle->edesc = GNUNET_strdup("The Access Token expired");
2472     handle->response_code = MHD_HTTP_UNAUTHORIZED;
2473     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
2474     GNUNET_free(ticket);
2475     return;
2476   }
2477
2478   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
2479   handle->oidc->response = json_object();
2480   json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring));
2481   handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (
2482       handle->idp,
2483       GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego),
2484       ticket,
2485       consume_ticket,
2486       handle);
2487   GNUNET_free(ticket);
2488
2489 }
2490
2491
2492 /**
2493  * Handle rest request
2494  *
2495  * @param handle the request handle
2496  */
2497 static void
2498 init_cont (struct RequestHandle *handle)
2499 {
2500   struct GNUNET_REST_RequestHandlerError err;
2501   static const struct GNUNET_REST_RequestHandler handlers[] = {
2502     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
2503     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
2504     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
2505     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint},
2506     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded
2507     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
2508     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
2509     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2510     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2511     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
2512     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
2513     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
2514       &options_cont},
2515     GNUNET_REST_HANDLER_END
2516   };
2517
2518   if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
2519                                                handlers,
2520                                                &err,
2521                                                handle))
2522   {
2523     handle->response_code = err.error_code;
2524     GNUNET_SCHEDULER_add_now (&do_error, handle);
2525   }
2526 }
2527
2528 /**
2529  * If listing is enabled, prints information about the egos.
2530  *
2531  * This function is initially called for all egos and then again
2532  * whenever a ego's identifier changes or if it is deleted.  At the
2533  * end of the initial pass over all egos, the function is once called
2534  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
2535  * be invoked in the future or that there was an error.
2536  *
2537  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
2538  * this function is only called ONCE, and 'NULL' being passed in
2539  * 'ego' does indicate an error (i.e. name is taken or no default
2540  * value is known).  If 'ego' is non-NULL and if '*ctx'
2541  * is set in those callbacks, the value WILL be passed to a subsequent
2542  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
2543  * that one was not NULL).
2544  *
2545  * When an identity is renamed, this function is called with the
2546  * (known) ego but the NEW identifier.
2547  *
2548  * When an identity is deleted, this function is called with the
2549  * (known) ego and "NULL" for the 'identifier'.  In this case,
2550  * the 'ego' is henceforth invalid (and the 'ctx' should also be
2551  * cleaned up).
2552  *
2553  * @param cls closure
2554  * @param ego ego handle
2555  * @param ctx context for application to store data for this ego
2556  *                 (during the lifetime of this process, initially NULL)
2557  * @param identifier identifier assigned by the user for this ego,
2558  *                   NULL if the user just deleted the ego and it
2559  *                   must thus no longer be used
2560  */
2561 static void
2562 list_ego (void *cls,
2563           struct GNUNET_IDENTITY_Ego *ego,
2564           void **ctx,
2565           const char *identifier)
2566 {
2567   struct RequestHandle *handle = cls;
2568   struct EgoEntry *ego_entry;
2569   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
2570
2571   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
2572   {
2573     handle->state = ID_REST_STATE_POST_INIT;
2574     init_cont (handle);
2575     return;
2576   }
2577   if (ID_REST_STATE_INIT == handle->state) {
2578     ego_entry = GNUNET_new (struct EgoEntry);
2579     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2580     ego_entry->keystring =
2581       GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
2582     ego_entry->ego = ego;
2583     ego_entry->identifier = GNUNET_strdup (identifier);
2584     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
2585   }
2586
2587 }
2588
2589 static void
2590 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
2591                               GNUNET_REST_ResultProcessor proc,
2592                               void *proc_cls)
2593 {
2594   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2595   handle->oidc = GNUNET_new (struct OIDC_Variables);
2596   if ( NULL == OIDC_identity_login_time )
2597     OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2598   if ( NULL == OIDC_identity_grants )
2599     OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2600   if ( NULL == OIDC_ticket_once )
2601     OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2602   if ( NULL == OIDC_interpret_access_token )
2603     OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2604   handle->response_code = 0;
2605   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
2606   handle->proc_cls = proc_cls;
2607   handle->proc = proc;
2608   handle->state = ID_REST_STATE_INIT;
2609   handle->rest_handle = rest_handle;
2610
2611   handle->url = GNUNET_strdup (rest_handle->url);
2612   if (handle->url[strlen (handle->url)-1] == '/')
2613     handle->url[strlen (handle->url)-1] = '\0';
2614   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2615               "Connecting...\n");
2616   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
2617                                                      &list_ego,
2618                                                      handle);
2619   handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
2620   handle->timeout_task =
2621     GNUNET_SCHEDULER_add_delayed (handle->timeout,
2622                                   &do_timeout,
2623                                   handle);
2624   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2625               "Connected\n");
2626 }
2627
2628 /**
2629  * Entry point for the plugin.
2630  *
2631  * @param cls Config info
2632  * @return NULL on error, otherwise the plugin context
2633  */
2634 void *
2635 libgnunet_plugin_rest_identity_provider_init (void *cls)
2636 {
2637   static struct Plugin plugin;
2638   struct GNUNET_REST_Plugin *api;
2639
2640   cfg = cls;
2641   if (NULL != plugin.cfg)
2642     return NULL;                /* can only initialize once! */
2643   memset (&plugin, 0, sizeof (struct Plugin));
2644   plugin.cfg = cfg;
2645   api = GNUNET_new (struct GNUNET_REST_Plugin);
2646   api->cls = &plugin;
2647   api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
2648   api->process_request = &rest_identity_process_request;
2649   GNUNET_asprintf (&allow_methods,
2650                    "%s, %s, %s, %s, %s",
2651                    MHD_HTTP_METHOD_GET,
2652                    MHD_HTTP_METHOD_POST,
2653                    MHD_HTTP_METHOD_PUT,
2654                    MHD_HTTP_METHOD_DELETE,
2655                    MHD_HTTP_METHOD_OPTIONS);
2656
2657   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2658               _("Identity Provider REST API initialized\n"));
2659   return api;
2660 }
2661
2662
2663 /**
2664  * Exit point from the plugin.
2665  *
2666  * @param cls the plugin context (as returned by "init")
2667  * @return always NULL
2668  */
2669 void *
2670 libgnunet_plugin_rest_identity_provider_done (void *cls)
2671 {
2672   struct GNUNET_REST_Plugin *api = cls;
2673   struct Plugin *plugin = api->cls;
2674   plugin->cfg = NULL;
2675
2676   struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2677   void *value = NULL;
2678   hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
2679       OIDC_identity_login_time);
2680   while (GNUNET_YES ==
2681          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2682   {
2683     if (NULL != value)
2684       GNUNET_free(value);
2685   }
2686   GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time);
2687   hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants);
2688   while (GNUNET_YES ==
2689          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2690   {
2691     if (NULL != value)
2692       GNUNET_free(value);
2693   }
2694   GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
2695   hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once);
2696   while (GNUNET_YES ==
2697          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2698   {
2699     if (NULL != value)
2700       GNUNET_free(value);
2701   }
2702   GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once);
2703   hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token);
2704   while (GNUNET_YES ==
2705          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2706   {
2707     if (NULL != value)
2708       GNUNET_free(value);
2709   }
2710   GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token);
2711   GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it);
2712   GNUNET_free_non_null (allow_methods);
2713   GNUNET_free (api);
2714   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2715               "Identity Provider REST plugin is finished\n");
2716   return NULL;
2717 }
2718
2719 /* end of plugin_rest_identity_provider.c */