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