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