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