ensure ticket contains client id
[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 struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
799                   const char* code,
800                   struct GNUNET_RECLAIM_Ticket **ticket,
801                   char **nonce)
802 {
803   json_error_t error;
804   json_t *code_json;
805   json_t *ticket_json;
806   json_t *nonce_json;
807   json_t *signature_json;
808   const char *ticket_str;
809   const char *signature_str;
810   const char *nonce_str;
811   char *code_output;
812   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
813   struct GNUNET_CRYPTO_EcdsaSignature signature;
814   size_t signature_payload_len;
815   
816   code_output = NULL; 
817   GNUNET_STRINGS_base64_decode (code,
818                                 strlen(code),
819                                 (void**)&code_output);
820   code_json = json_loads (code_output, 0 , &error);
821   GNUNET_free (code_output);
822   ticket_json = json_object_get (code_json, "ticket");
823   nonce_json = json_object_get (code_json, "nonce");
824   signature_json = json_object_get (code_json, "signature");
825   *ticket = NULL;
826   *nonce = NULL;
827
828   if ((NULL == ticket_json || !json_is_string (ticket_json)) ||
829       (NULL == signature_json || !json_is_string (signature_json)))
830   {
831     json_decref (code_json);
832     return GNUNET_SYSERR;
833   }
834   ticket_str = json_string_value (ticket_json);
835   signature_str = json_string_value (signature_json);
836   nonce_str = NULL;
837   if (NULL != nonce_json)
838     nonce_str = json_string_value (nonce_json);
839   signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket);
840   if (NULL != nonce_str)
841     signature_payload_len += strlen (nonce_str);
842   purpose = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
843                            signature_payload_len);
844   purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len);
845   purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN);
846   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (ticket_str,
847                                                   strlen (ticket_str),
848                                                   &purpose[1],
849                                                   sizeof (struct GNUNET_RECLAIM_Ticket)))
850   {
851     GNUNET_free (purpose);
852     json_decref (code_json);
853     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
854                 "Cannot parse ticket!\n");
855     return GNUNET_SYSERR;
856   }
857   if (GNUNET_OK != GNUNET_STRINGS_string_to_data (signature_str,
858                                                   strlen (signature_str),
859                                                   &signature,
860                                                   sizeof (struct GNUNET_CRYPTO_EcdsaSignature)))
861   {
862     GNUNET_free (purpose);
863     json_decref (code_json);
864     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
865                 "Cannot parse signature!\n");
866     return GNUNET_SYSERR;
867   }
868   *ticket = GNUNET_new (struct GNUNET_RECLAIM_Ticket);
869   memcpy (*ticket,
870           &purpose[1],
871           sizeof (struct GNUNET_RECLAIM_Ticket));
872   if (0 != memcmp (audience,
873                    &(*ticket)->audience,
874                    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
875   {
876     GNUNET_free (purpose);
877     GNUNET_free (*ticket);
878     json_decref (code_json);
879     *ticket = NULL;
880     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
881                 "Audience in ticket does not match client!\n");
882     return GNUNET_SYSERR;
883
884   }
885   if (NULL != nonce_str)
886     memcpy (&purpose[1] + sizeof (struct GNUNET_RECLAIM_Ticket),
887             nonce_str,
888             strlen (nonce_str));
889   if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN,
890                                                purpose,
891                                                &signature,
892                                                &(*ticket)->identity))
893   {
894     GNUNET_free (purpose);
895     GNUNET_free (*ticket);
896     json_decref (code_json);
897     *ticket = NULL;
898     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
899                 "Signature of authZ code invalid!\n");
900     return GNUNET_SYSERR;
901   }
902   *nonce = GNUNET_strdup (nonce_str);
903   return GNUNET_OK;
904 }
905
906 static char*
907 build_authz_code (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer,
908                   const struct GNUNET_RECLAIM_Ticket *ticket,
909                   const char* nonce)
910 {
911   char *ticket_str;
912   json_t *code_json;
913   char *signature_payload;
914   char *signature_str;
915   char *authz_code;
916   size_t signature_payload_len;
917   struct GNUNET_CRYPTO_EcdsaSignature signature;
918   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
919
920   signature_payload_len = sizeof (struct GNUNET_RECLAIM_Ticket);
921   if (NULL != nonce)
922     signature_payload_len += strlen (nonce);
923
924   signature_payload = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len);
925   purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *)signature_payload;
926   purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + signature_payload_len);
927   purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_RECLAIM_CODE_SIGN);
928   memcpy (&purpose[1],
929           ticket,
930           sizeof (struct GNUNET_RECLAIM_Ticket));
931   if (NULL != nonce)
932     memcpy (&purpose[1] + sizeof (struct GNUNET_RECLAIM_Ticket),
933             nonce,
934             strlen (nonce));
935   if (GNUNET_SYSERR == GNUNET_CRYPTO_ecdsa_sign (issuer,
936                                                  purpose,
937                                                  &signature))
938   {
939     GNUNET_free (signature_payload);
940     return NULL;
941   }
942   signature_str = GNUNET_STRINGS_data_to_string_alloc (&signature,
943                                                        sizeof (signature));
944   ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket,
945                                                     sizeof (struct GNUNET_RECLAIM_Ticket));
946
947   code_json = json_object ();
948   json_object_set_new (code_json,
949                        "ticket",
950                        json_string (ticket_str));
951   if (NULL != nonce)
952     json_object_set_new (code_json,
953                          "nonce",
954                          json_string (nonce));
955   json_object_set_new (code_json,
956                        "signature",
957                        json_string (signature_str));
958   authz_code = json_dumps (code_json,
959                            JSON_INDENT(0) | JSON_COMPACT);
960   GNUNET_free (signature_payload);
961   GNUNET_free (signature_str);
962   GNUNET_free (ticket_str);
963   json_decref (code_json);
964   return authz_code;
965 }
966
967
968 static void
969 get_client_name_result (void *cls,
970                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
971                         const char *label,
972                         unsigned int rd_count,
973                         const struct GNUNET_GNSRECORD_Data *rd)
974 {
975   struct RequestHandle *handle = cls;
976   struct MHD_Response *resp;
977   char *ticket_str;
978   char *redirect_uri;
979   char *code_json_string;
980   char *code_base64_final_string;
981   char *redirect_path;
982   char *tmp;
983   char *tmp_prefix;
984   char *prefix;
985   ticket_str = GNUNET_STRINGS_data_to_string_alloc (&handle->ticket,
986                                                     sizeof (struct GNUNET_RECLAIM_Ticket));
987   //TODO add signature to code payload over nonce and ticket _and_ use jansson here!
988   //TODO change if more attributes are needed (see max_age)
989   code_json_string = build_authz_code (&handle->priv_key,
990                                        &handle->ticket,
991                                        handle->oidc->nonce);
992   /*GNUNET_asprintf (&code_json_string, "{\"ticket\":\"%s\"%s%s%s}",
993     ticket_str,
994     (NULL != handle->oidc->nonce) ? ", \"nonce\":\"" : "",
995     (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "",
996     (NULL != handle->oidc->nonce) ? "\"" : "");*/
997   code_base64_final_string = base_64_encode(code_json_string);
998   tmp = GNUNET_strdup (handle->oidc->redirect_uri);
999   redirect_path = strtok (tmp, "/");
1000   redirect_path = strtok (NULL, "/");
1001   redirect_path = strtok (NULL, "/");
1002   tmp_prefix = GNUNET_strdup (handle->oidc->redirect_uri);
1003   prefix = strrchr (tmp_prefix,
1004                     (unsigned char) '.');
1005   *prefix = '\0';
1006   GNUNET_asprintf (&redirect_uri, "%s.%s/%s?%s=%s&state=%s",
1007                    tmp_prefix,
1008                    handle->tld,
1009                    redirect_path,
1010                    handle->oidc->response_type,
1011                    code_base64_final_string, handle->oidc->state);
1012   resp = GNUNET_REST_create_response ("");
1013   MHD_add_response_header (resp, "Location", redirect_uri);
1014   handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1015   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1016   GNUNET_free (tmp);
1017   GNUNET_free (tmp_prefix);
1018   GNUNET_free (redirect_uri);
1019   GNUNET_free (ticket_str);
1020   GNUNET_free (code_json_string);
1021   GNUNET_free (code_base64_final_string);
1022   return;
1023 }
1024
1025 static void
1026 get_client_name_error (void *cls)
1027 {
1028   struct RequestHandle *handle = cls;
1029
1030   handle->emsg = GNUNET_strdup("server_error");
1031   handle->edesc = GNUNET_strdup("Server cannot generate ticket, no name found for client.");
1032   GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1033 }
1034
1035 /**
1036  * Issues ticket and redirects to relying party with the authorization code as
1037  * parameter. Otherwise redirects with error
1038  */
1039 static void
1040 oidc_ticket_issue_cb (void* cls,
1041                       const struct GNUNET_RECLAIM_Ticket *ticket)
1042 {
1043   struct RequestHandle *handle = cls;
1044   handle->idp_op = NULL;
1045   handle->ticket = *ticket;
1046   if (NULL != ticket) {
1047     GNUNET_NAMESTORE_zone_to_name (handle->namestore_handle,
1048                                    &handle->priv_key,
1049                                    &handle->oidc->client_pkey,
1050                                    &get_client_name_error,
1051                                    handle,
1052                                    &get_client_name_result,
1053                                    handle);
1054     return;
1055   }
1056   handle->emsg = GNUNET_strdup("server_error");
1057   handle->edesc = GNUNET_strdup("Server cannot generate ticket.");
1058   GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1059 }
1060
1061 static void
1062 oidc_collect_finished_cb (void *cls)
1063 {
1064   struct RequestHandle *handle = cls;
1065   handle->attr_it = NULL;
1066   handle->ticket_it = NULL;
1067   if (NULL == handle->attr_list->list_head)
1068   {
1069     handle->emsg = GNUNET_strdup("invalid_scope");
1070     handle->edesc = GNUNET_strdup("The requested scope is not available.");
1071     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1072     return;
1073   }
1074   handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp,
1075                                                 &handle->priv_key,
1076                                                 &handle->oidc->client_pkey,
1077                                                 handle->attr_list,
1078                                                 &oidc_ticket_issue_cb,
1079                                                 handle);
1080 }
1081
1082
1083 /**
1084  * Collects all attributes for an ego if in scope parameter
1085  */
1086 static void
1087 oidc_attr_collect (void *cls,
1088                    const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1089                    const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
1090 {
1091   struct RequestHandle *handle = cls;
1092   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1093   char* scope_variables;
1094   char* scope_variable;
1095   char delimiter[]=" ";
1096
1097   if ( (NULL == attr->name) || (NULL == attr->data) )
1098   {
1099     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1100     return;
1101   }
1102
1103   scope_variables = GNUNET_strdup(handle->oidc->scope);
1104   scope_variable = strtok (scope_variables, delimiter);
1105   while (NULL != scope_variable)
1106   {
1107     if ( 0 == strcmp (attr->name, scope_variable) )
1108     {
1109       break;
1110     }
1111     scope_variable = strtok (NULL, delimiter);
1112   }
1113   if ( NULL == scope_variable )
1114   {
1115     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1116     GNUNET_free(scope_variables);
1117     return;
1118   }
1119   GNUNET_free(scope_variables);
1120
1121   le = GNUNET_new(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
1122   le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name, attr->type,
1123                                                   attr->data, attr->data_size);
1124   GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head,
1125                               handle->attr_list->list_tail, le);
1126   GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
1127 }
1128
1129
1130 /**
1131  * Checks time and cookie and redirects accordingly
1132  */
1133 static void
1134 login_check (void *cls)
1135 {
1136   struct RequestHandle *handle = cls;
1137   struct GNUNET_TIME_Absolute current_time, *relog_time;
1138   struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey;
1139   struct GNUNET_HashCode cache_key;
1140   char *identity_cookie;
1141
1142   GNUNET_asprintf (&identity_cookie, "Identity=%s", handle->oidc->login_identity);
1143   GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
1144   GNUNET_free(identity_cookie);
1145   //No login time for identity -> redirect to login
1146   if ( GNUNET_YES
1147        == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time,
1148                                                   &cache_key) )
1149   {
1150     relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
1151                                                     &cache_key);
1152     current_time = GNUNET_TIME_absolute_get ();
1153     // 30 min after old login -> redirect to login
1154     if ( current_time.abs_value_us <= relog_time->abs_value_us )
1155     {
1156       if ( GNUNET_OK
1157            != GNUNET_CRYPTO_ecdsa_public_key_from_string (
1158                                                           handle->oidc->login_identity,
1159                                                           strlen (handle->oidc->login_identity), &pubkey) )
1160       {
1161         handle->emsg = GNUNET_strdup("invalid_cookie");
1162         handle->edesc = GNUNET_strdup(
1163                                       "The cookie of a login identity is not valid");
1164         GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1165         return;
1166       }
1167       // iterate over egos and compare their public key
1168       for (handle->ego_entry = handle->ego_head;
1169            NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
1170       {
1171         GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
1172         if ( 0
1173              == memcmp (&ego_pkey, &pubkey,
1174                         sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1175         {
1176           handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (
1177                                                                    handle->ego_entry->ego);
1178           handle->resp_object = GNUNET_JSONAPI_document_new ();
1179           handle->idp = GNUNET_RECLAIM_connect (cfg);
1180           handle->attr_list = GNUNET_new(
1181                                          struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1182           handle->attr_it = GNUNET_RECLAIM_get_attributes_start (
1183                                                                  handle->idp, &handle->priv_key, &oidc_iteration_error, handle,
1184                                                                  &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle);
1185           return;
1186         }
1187       }
1188       //handle->emsg = GNUNET_strdup("invalid_cookie");
1189       //handle->edesc = GNUNET_strdup(
1190       //                              "The cookie of the login identity is not valid");
1191       //GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1192       GNUNET_SCHEDULER_add_now (&login_redirection,handle);
1193       return;
1194     }
1195   }
1196 }
1197
1198 /**
1199  * Iteration over all results finished, build final
1200  * response.
1201  *
1202  * @param cls the `struct RequestHandle`
1203  */
1204 static void
1205 build_authz_response (void *cls)
1206 {
1207   struct RequestHandle *handle = cls;
1208   struct GNUNET_HashCode cache_key;
1209
1210   char *expected_scope;
1211   char delimiter[]=" ";
1212   int number_of_ignored_parameter, iterator;
1213
1214
1215   // REQUIRED value: redirect_uri
1216   GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_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 redirect_uri");
1223     GNUNET_SCHEDULER_add_now (&do_error, handle);
1224     return;
1225   }
1226   handle->oidc->redirect_uri = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1227                                                                                 &cache_key));
1228
1229   // REQUIRED value: response_type
1230   GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1231                       &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 response_type");
1237     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1238     return;
1239   }
1240   handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1241                                                                   &cache_key);
1242   handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
1243
1244   // REQUIRED value: scope
1245   GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
1246   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1247                                                            &cache_key))
1248   {
1249     handle->emsg=GNUNET_strdup("invalid_request");
1250     handle->edesc=GNUNET_strdup("missing parameter scope");
1251     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1252     return;
1253   }
1254   handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1255                                                           &cache_key);
1256   handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
1257
1258   //OPTIONAL value: nonce
1259   GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
1260   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1261                                                             &cache_key))
1262   {
1263     handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1264                                                             &cache_key);
1265     handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
1266   }
1267
1268   //TODO check other values if needed
1269   number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1270   for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1271   {
1272     GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1273                         strlen(OIDC_ignored_parameter_array[iterator]),
1274                         &cache_key);
1275     if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
1276                                                             &cache_key))
1277     {
1278       handle->emsg=GNUNET_strdup("access_denied");
1279       GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1280                        OIDC_ignored_parameter_array[iterator]);
1281       GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1282       return;
1283     }
1284   }
1285
1286   // Checks if response_type is 'code'
1287   if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1288   {
1289     handle->emsg=GNUNET_strdup("unsupported_response_type");
1290     handle->edesc=GNUNET_strdup("The authorization server does not support "
1291                                 "obtaining this authorization code.");
1292     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1293     return;
1294   }
1295
1296   // Checks if scope contains 'openid'
1297   expected_scope = GNUNET_strdup(handle->oidc->scope);
1298   char* test;
1299   test = strtok (expected_scope, delimiter);
1300   while (NULL != test)
1301   {
1302     if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1303     {
1304       break;
1305     }
1306     test = strtok (NULL, delimiter);
1307   }
1308   if (NULL == test)
1309   {
1310     handle->emsg = GNUNET_strdup("invalid_scope");
1311     handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1312                                 "malformed.");
1313     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1314     GNUNET_free(expected_scope);
1315     return;
1316   }
1317
1318   GNUNET_free(expected_scope);
1319
1320   if( NULL != handle->oidc->login_identity )
1321   {
1322     GNUNET_SCHEDULER_add_now(&login_check,handle);
1323     return;
1324   }
1325
1326   GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1327 }
1328
1329 /**
1330  * Responds to authorization GET and url-encoded POST request
1331  *
1332  * @param con_handle the connection handle
1333  * @param url the url
1334  * @param cls the RequestHandle
1335  */
1336 static void
1337 authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1338                     const char* url,
1339                     void *cls)
1340 {
1341   struct RequestHandle *handle = cls;
1342   struct GNUNET_HashCode cache_key;
1343   struct EgoEntry *tmp_ego;
1344   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
1345   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1346
1347   cookie_identity_interpretation(handle);
1348
1349   //RECOMMENDED value: state - REQUIRED for answers
1350   GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
1351   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1352                                                             &cache_key))
1353   {
1354     handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1355                                                             &cache_key);
1356     handle->oidc->state = GNUNET_strdup (handle->oidc->state);
1357   }
1358
1359   // REQUIRED value: client_id
1360   GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1361                       &cache_key);
1362   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1363                                                            &cache_key))
1364   {
1365     handle->emsg=GNUNET_strdup("invalid_request");
1366     handle->edesc=GNUNET_strdup("missing parameter client_id");
1367     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1368     GNUNET_SCHEDULER_add_now (&do_error, handle);
1369     return;
1370   }
1371   handle->oidc->client_id = GNUNET_strdup (GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1372                                                                              &cache_key));
1373
1374   if ( GNUNET_OK
1375        != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
1376                                                       strlen (handle->oidc->client_id),
1377                                                       &handle->oidc->client_pkey) )
1378   {
1379     handle->emsg = GNUNET_strdup("unauthorized_client");
1380     handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1381                                   "authorization code using this method.");
1382     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1383     GNUNET_SCHEDULER_add_now (&do_error, handle);
1384     return;
1385   }
1386
1387
1388   if ( NULL == handle->ego_head )
1389   {
1390     handle->emsg = GNUNET_strdup("server_error");
1391     handle->edesc = GNUNET_strdup ("Egos are missing");
1392     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1393     GNUNET_SCHEDULER_add_now (&do_error, handle);
1394     return;
1395   }
1396
1397   handle->ego_entry = handle->ego_head;
1398   handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
1399   //If we know this identity, translated the corresponding TLD
1400   //TODO: We might want to have a reverse lookup functionality for TLDs?
1401   for (tmp_ego = handle->ego_head; NULL != tmp_ego; tmp_ego = tmp_ego->next)
1402   {
1403     priv_key = GNUNET_IDENTITY_ego_get_private_key (tmp_ego->ego);
1404     GNUNET_CRYPTO_ecdsa_key_get_public (priv_key,
1405                                         &pkey);
1406     if ( 0 == memcmp (&pkey, &handle->oidc->client_pkey,
1407                       sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1408     {
1409       handle->tld = GNUNET_strdup (tmp_ego->identifier);
1410       handle->ego_entry = handle->ego_tail;
1411     }
1412   } 
1413   GNUNET_SCHEDULER_add_now (&build_authz_response, handle);
1414 }
1415
1416 /**
1417  * Combines an identity with a login time and responds OK to login request
1418  *
1419  * @param con_handle the connection handle
1420  * @param url the url
1421  * @param cls the RequestHandle
1422  */
1423 static void
1424 login_cont (struct GNUNET_REST_RequestHandle *con_handle,
1425             const char* url,
1426             void *cls)
1427 {
1428   struct MHD_Response *resp = GNUNET_REST_create_response ("");
1429   struct RequestHandle *handle = cls;
1430   struct GNUNET_HashCode cache_key;
1431   struct GNUNET_TIME_Absolute *current_time;
1432   struct GNUNET_TIME_Absolute *last_time;
1433   char* cookie;
1434   json_t *root;
1435   json_error_t error;
1436   json_t *identity;
1437   char term_data[handle->rest_handle->data_size+1];
1438   term_data[handle->rest_handle->data_size] = '\0';
1439   GNUNET_memcpy (term_data, handle->rest_handle->data, handle->rest_handle->data_size);
1440   root = json_loads (term_data, JSON_DECODE_ANY, &error);
1441   identity = json_object_get (root, "identity");
1442   if ( json_is_string(identity) )
1443   {
1444     GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
1445     MHD_add_response_header (resp, "Set-Cookie", cookie);
1446     MHD_add_response_header (resp, "Access-Control-Allow-Methods", "POST");
1447     GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
1448
1449     current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
1450     *current_time = GNUNET_TIME_relative_to_absolute (
1451                                                       GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
1452                                                                                      5));
1453     last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key);
1454     if (NULL != last_time)
1455     {
1456       GNUNET_free(last_time);
1457     }
1458     GNUNET_CONTAINER_multihashmap_put (
1459                                        OIDC_identity_login_time, &cache_key, current_time,
1460                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1461
1462     handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1463     GNUNET_free(cookie);
1464   }
1465   else
1466   {
1467     handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1468   }
1469   json_decref (root);
1470   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
1471   return;
1472 }
1473
1474 /**
1475  * Responds to token url-encoded POST request
1476  *
1477  * @param con_handle the connection handle
1478  * @param url the url
1479  * @param cls the RequestHandle
1480  */
1481 static void
1482 token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1483                 const char* url,
1484                 void *cls)
1485 {
1486   //TODO static strings
1487   struct RequestHandle *handle = cls;
1488   struct GNUNET_HashCode cache_key;
1489   char *authorization, *credentials;
1490   char delimiter[]=" ";
1491   char delimiter_user_psw[]=":";
1492   char *grant_type, *code;
1493   char *user_psw = NULL, *client_id, *psw;
1494   char *expected_psw;
1495   int client_exists = GNUNET_NO;
1496   struct MHD_Response *resp;
1497   char *json_response;
1498   char *jwt_secret;
1499   char *nonce;
1500
1501   /*
1502    * Check Authorization
1503    */
1504   GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
1505                       strlen (OIDC_AUTHORIZATION_HEADER_KEY),
1506                       &cache_key);
1507   if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
1508                                                             &cache_key) )
1509   {
1510     handle->emsg=GNUNET_strdup("invalid_client");
1511     handle->edesc=GNUNET_strdup("missing authorization");
1512     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1513     GNUNET_SCHEDULER_add_now (&do_error, handle);
1514     return;
1515   }
1516   authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
1517
1518   //split header in "Basic" and [content]
1519   credentials = strtok (authorization, delimiter);
1520   if (0 != strcmp ("Basic",credentials))
1521   {
1522     handle->emsg=GNUNET_strdup("invalid_client");
1523     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1524     GNUNET_SCHEDULER_add_now (&do_error, handle);
1525     return;
1526   }
1527   credentials = strtok(NULL, delimiter);
1528   if (NULL == credentials)
1529   {
1530     handle->emsg=GNUNET_strdup("invalid_client");
1531     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1532     GNUNET_SCHEDULER_add_now (&do_error, handle);
1533     return;
1534   }
1535   GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), (void**)&user_psw);
1536
1537   if ( NULL == user_psw )
1538   {
1539     handle->emsg=GNUNET_strdup("invalid_client");
1540     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1541     GNUNET_SCHEDULER_add_now (&do_error, handle);
1542     return;
1543   }
1544   client_id = strtok (user_psw, delimiter_user_psw);
1545   if ( NULL == client_id )
1546   {
1547     GNUNET_free_non_null(user_psw);
1548     handle->emsg=GNUNET_strdup("invalid_client");
1549     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1550     GNUNET_SCHEDULER_add_now (&do_error, handle);
1551     return;
1552   }
1553   psw = strtok (NULL, delimiter_user_psw);
1554   if (NULL == psw)
1555   {
1556     GNUNET_free_non_null(user_psw);
1557     handle->emsg=GNUNET_strdup("invalid_client");
1558     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1559     GNUNET_SCHEDULER_add_now (&do_error, handle);
1560     return;
1561   }
1562
1563   //check client password
1564   if ( GNUNET_OK
1565        == GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin",
1566                                                  "psw", &expected_psw) )
1567   {
1568     if (0 != strcmp (expected_psw, psw))
1569     {
1570       GNUNET_free_non_null(user_psw);
1571       GNUNET_free(expected_psw);
1572       handle->emsg=GNUNET_strdup("invalid_client");
1573       handle->response_code = MHD_HTTP_UNAUTHORIZED;
1574       GNUNET_SCHEDULER_add_now (&do_error, handle);
1575       return;
1576     }
1577     GNUNET_free(expected_psw);
1578   }
1579   else
1580   {
1581     GNUNET_free_non_null(user_psw);
1582     handle->emsg = GNUNET_strdup("server_error");
1583     handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1584     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1585     GNUNET_SCHEDULER_add_now (&do_error, handle);
1586     return;
1587   }
1588
1589   //check client_id
1590   for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; )
1591   {
1592     if ( 0 == strcmp(handle->ego_entry->keystring, client_id))
1593     {
1594       client_exists = GNUNET_YES;
1595       break;
1596     }
1597     handle->ego_entry = handle->ego_entry->next;
1598   }
1599   if (GNUNET_NO == client_exists)
1600   {
1601     GNUNET_free_non_null(user_psw);
1602     handle->emsg=GNUNET_strdup("invalid_client");
1603     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1604     GNUNET_SCHEDULER_add_now (&do_error, handle);
1605     return;
1606   }
1607
1608   /*
1609    * Check parameter
1610    */
1611
1612   //TODO Do not allow multiple equal parameter names
1613   //REQUIRED grant_type
1614   GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), &cache_key);
1615   if ( GNUNET_NO
1616        == GNUNET_CONTAINER_multihashmap_contains (
1617                                                   handle->rest_handle->url_param_map, &cache_key) )
1618   {
1619     GNUNET_free_non_null(user_psw);
1620     handle->emsg = GNUNET_strdup("invalid_request");
1621     handle->edesc = GNUNET_strdup("missing parameter grant_type");
1622     handle->response_code = MHD_HTTP_BAD_REQUEST;
1623     GNUNET_SCHEDULER_add_now (&do_error, handle);
1624     return;
1625   }
1626   grant_type = GNUNET_CONTAINER_multihashmap_get (
1627                                                   handle->rest_handle->url_param_map, &cache_key);
1628
1629   //REQUIRED code
1630   GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key);
1631   if ( GNUNET_NO
1632        == GNUNET_CONTAINER_multihashmap_contains (
1633                                                   handle->rest_handle->url_param_map, &cache_key) )
1634   {
1635     GNUNET_free_non_null(user_psw);
1636     handle->emsg = GNUNET_strdup("invalid_request");
1637     handle->edesc = GNUNET_strdup("missing parameter code");
1638     handle->response_code = MHD_HTTP_BAD_REQUEST;
1639     GNUNET_SCHEDULER_add_now (&do_error, handle);
1640     return;
1641   }
1642   code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
1643                                             &cache_key);
1644
1645   //REQUIRED redirect_uri
1646   GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1647                       &cache_key);
1648   if ( GNUNET_NO
1649        == GNUNET_CONTAINER_multihashmap_contains (
1650                                                   handle->rest_handle->url_param_map, &cache_key) )
1651   {
1652     GNUNET_free_non_null(user_psw);
1653     handle->emsg = GNUNET_strdup("invalid_request");
1654     handle->edesc = GNUNET_strdup("missing parameter redirect_uri");
1655     handle->response_code = MHD_HTTP_BAD_REQUEST;
1656     GNUNET_SCHEDULER_add_now (&do_error, handle);
1657     return;
1658   }
1659
1660   //Check parameter grant_type == "authorization_code"
1661   if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type))
1662   {
1663     GNUNET_free_non_null(user_psw);
1664     handle->emsg=GNUNET_strdup("unsupported_grant_type");
1665     handle->response_code = MHD_HTTP_BAD_REQUEST;
1666     GNUNET_SCHEDULER_add_now (&do_error, handle);
1667     return;
1668   }
1669   GNUNET_CRYPTO_hash (code, strlen (code), &cache_key);
1670   int i = 1;
1671   if ( GNUNET_SYSERR
1672        == GNUNET_CONTAINER_multihashmap_put (OIDC_ticket_once,
1673                                              &cache_key,
1674                                              &i,
1675                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) )
1676   {
1677     GNUNET_free_non_null(user_psw);
1678     handle->emsg = GNUNET_strdup("invalid_request");
1679     handle->edesc = GNUNET_strdup("Cannot use the same code more than once");
1680     handle->response_code = MHD_HTTP_BAD_REQUEST;
1681     GNUNET_SCHEDULER_add_now (&do_error, handle);
1682     return;
1683   }
1684
1685   //decode code
1686   struct GNUNET_CRYPTO_EcdsaPublicKey cid;
1687   GNUNET_STRINGS_string_to_data (client_id,
1688                                  strlen(client_id),
1689                                  &cid,
1690                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1691   struct GNUNET_RECLAIM_Ticket *ticket;
1692   if(GNUNET_OK != parse_authz_code (&cid,
1693                                     code,
1694                                     &ticket,
1695                                     &nonce))
1696   {
1697     GNUNET_free_non_null(user_psw);
1698     handle->emsg = GNUNET_strdup("invalid_request");
1699     handle->edesc = GNUNET_strdup("invalid code");
1700     handle->response_code = MHD_HTTP_BAD_REQUEST;
1701     GNUNET_SCHEDULER_add_now (&do_error, handle);
1702     return;
1703   }
1704
1705   // this is the current client (relying party)
1706   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1707   GNUNET_IDENTITY_ego_get_public_key(handle->ego_entry->ego,&pub_key);
1708   if (0 != memcmp(&pub_key,&ticket->audience,sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1709   {
1710     GNUNET_free_non_null(user_psw);
1711     handle->emsg = GNUNET_strdup("invalid_request");
1712     handle->edesc = GNUNET_strdup("invalid code");
1713     handle->response_code = MHD_HTTP_BAD_REQUEST;
1714     GNUNET_SCHEDULER_add_now (&do_error, handle);
1715     GNUNET_free(ticket);
1716     return;
1717   }
1718
1719   //create jwt
1720   struct GNUNET_TIME_Relative expiration_time;
1721   if ( GNUNET_OK
1722        != GNUNET_CONFIGURATION_get_value_time(cfg, "reclaim-rest-plugin",
1723                                               "expiration_time", &expiration_time) )
1724   {
1725     GNUNET_free_non_null(user_psw);
1726     handle->emsg = GNUNET_strdup("server_error");
1727     handle->edesc = GNUNET_strdup ("gnunet configuration failed");
1728     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1729     GNUNET_SCHEDULER_add_now (&do_error, handle);
1730     GNUNET_free(ticket);
1731     return;
1732   }
1733
1734   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *cl = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1735
1736   //TODO OPTIONAL acr,amr,azp
1737
1738   struct EgoEntry *ego_entry;
1739   for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
1740   {
1741     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
1742     if (0 == memcmp (&pub_key, &ticket->audience, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1743     {
1744       break;
1745     }
1746   }
1747   if ( NULL == ego_entry )
1748   {
1749     GNUNET_free_non_null(user_psw);
1750     handle->emsg = GNUNET_strdup("invalid_request");
1751     handle->edesc = GNUNET_strdup("invalid code...");
1752     handle->response_code = MHD_HTTP_BAD_REQUEST;
1753     GNUNET_SCHEDULER_add_now (&do_error, handle);
1754     GNUNET_free(ticket);
1755     return;
1756   }
1757   if ( GNUNET_OK
1758        != GNUNET_CONFIGURATION_get_value_string (cfg, "reclaim-rest-plugin",
1759                                                  "jwt_secret", &jwt_secret) )
1760   {
1761     GNUNET_free_non_null(user_psw);
1762     handle->emsg = GNUNET_strdup("invalid_request");
1763     handle->edesc = GNUNET_strdup("No signing secret configured!");
1764     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1765     GNUNET_SCHEDULER_add_now (&do_error, handle);
1766     GNUNET_free(ticket);
1767     return;
1768   }
1769   char *id_token = jwt_create_from_list(&ticket->audience,
1770                                         &ticket->identity,
1771                                         cl,
1772                                         &expiration_time,
1773                                         (NULL != nonce) ? nonce : NULL,
1774                                         jwt_secret);
1775
1776   //Create random access_token
1777   char* access_token_number;
1778   char* access_token;
1779   uint64_t random_number;
1780   random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, UINT64_MAX);
1781   GNUNET_asprintf(&access_token_number, "%" PRIu64, random_number);
1782   GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token);
1783
1784
1785
1786   //TODO OPTIONAL add refresh_token and scope
1787   GNUNET_asprintf (&json_response,
1788                    "{ \"access_token\" : \"%s\", "
1789                    "\"token_type\" : \"Bearer\", "
1790                    "\"expires_in\" : %d, "
1791                    "\"id_token\" : \"%s\"}",
1792                    access_token,
1793                    expiration_time,
1794                    id_token);
1795   GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key);
1796   char *id_ticket_combination;
1797   char *ticket_string;
1798   ticket_string = GNUNET_STRINGS_data_to_string_alloc (ticket,
1799                                                        sizeof (struct GNUNET_RECLAIM_Ticket));
1800   GNUNET_asprintf(&id_ticket_combination,
1801                   "%s;%s",
1802                   client_id,
1803                   ticket_string);
1804   GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token,
1805                                     &cache_key,
1806                                     id_ticket_combination,
1807                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1808
1809   resp = GNUNET_REST_create_response (json_response);
1810   MHD_add_response_header (resp, "Cache-Control", "no-store");
1811   MHD_add_response_header (resp, "Pragma", "no-cache");
1812   MHD_add_response_header (resp, "Content-Type", "application/json");
1813   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1814
1815   GNUNET_RECLAIM_ATTRIBUTE_list_destroy(cl);
1816   GNUNET_free(access_token_number);
1817   GNUNET_free(access_token);
1818   GNUNET_free(user_psw);
1819   GNUNET_free(json_response);
1820   GNUNET_free(ticket);
1821   GNUNET_free(id_token);
1822   GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle);
1823 }
1824
1825 /**
1826  * Collects claims and stores them in handle
1827  */
1828 static void
1829 consume_ticket (void *cls,
1830                 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1831                 const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
1832 {
1833   struct RequestHandle *handle = cls;
1834   char *tmp_value;
1835   json_t *value;
1836
1837   if (NULL == identity)
1838   {
1839     GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle);
1840     return;
1841   }
1842
1843   tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
1844                                                         attr->data,
1845                                                         attr->data_size);
1846
1847   value = json_string (tmp_value);
1848
1849
1850   json_object_set_new (handle->oidc->response,
1851                        attr->name,
1852                        value);
1853   GNUNET_free (tmp_value);
1854 }
1855
1856 /**
1857  * Responds to userinfo GET and url-encoded POST request
1858  *
1859  * @param con_handle the connection handle
1860  * @param url the url
1861  * @param cls the RequestHandle
1862  */
1863 static void
1864 userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
1865                    const char* url, void *cls)
1866 {
1867   //TODO expiration time
1868   struct RequestHandle *handle = cls;
1869   char delimiter[] = " ";
1870   char delimiter_db[] = ";";
1871   struct GNUNET_HashCode cache_key;
1872   char *authorization, *authorization_type, *authorization_access_token;
1873   char *client_ticket, *client, *ticket_str;
1874   struct GNUNET_RECLAIM_Ticket *ticket;
1875
1876   GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
1877                       strlen (OIDC_AUTHORIZATION_HEADER_KEY),
1878                       &cache_key);
1879   if ( GNUNET_NO
1880        == GNUNET_CONTAINER_multihashmap_contains (
1881                                                   handle->rest_handle->header_param_map, &cache_key) )
1882   {
1883     handle->emsg = GNUNET_strdup("invalid_token");
1884     handle->edesc = GNUNET_strdup("No Access Token");
1885     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1886     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1887     return;
1888   }
1889   authorization = GNUNET_CONTAINER_multihashmap_get (
1890                                                      handle->rest_handle->header_param_map, &cache_key);
1891
1892   //split header in "Bearer" and access_token
1893   authorization = GNUNET_strdup(authorization);
1894   authorization_type = strtok (authorization, delimiter);
1895   if ( 0 != strcmp ("Bearer", authorization_type) )
1896   {
1897     handle->emsg = GNUNET_strdup("invalid_token");
1898     handle->edesc = GNUNET_strdup("No Access Token");
1899     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1900     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1901     GNUNET_free(authorization);
1902     return;
1903   }
1904   authorization_access_token = strtok (NULL, delimiter);
1905   if ( NULL == authorization_access_token )
1906   {
1907     handle->emsg = GNUNET_strdup("invalid_token");
1908     handle->edesc = GNUNET_strdup("No Access Token");
1909     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1910     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1911     GNUNET_free(authorization);
1912     return;
1913   }
1914
1915   GNUNET_CRYPTO_hash (authorization_access_token,
1916                       strlen (authorization_access_token),
1917                       &cache_key);
1918   if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (OIDC_interpret_access_token,
1919                                                             &cache_key) )
1920   {
1921     handle->emsg = GNUNET_strdup("invalid_token");
1922     handle->edesc = GNUNET_strdup("The Access Token expired");
1923     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1924     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1925     GNUNET_free(authorization);
1926     return;
1927   }
1928
1929   client_ticket = GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token,
1930                                                     &cache_key);
1931   client_ticket = GNUNET_strdup(client_ticket);
1932   client = strtok(client_ticket,delimiter_db);
1933   if (NULL == client)
1934   {
1935     handle->emsg = GNUNET_strdup("invalid_token");
1936     handle->edesc = GNUNET_strdup("The Access Token expired");
1937     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1938     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1939     GNUNET_free(authorization);
1940     GNUNET_free(client_ticket);
1941     return;
1942   }
1943   handle->ego_entry = handle->ego_head;
1944   for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
1945   {
1946     if (0 == strcmp(handle->ego_entry->keystring,client))
1947     {
1948       break;
1949     }
1950   }
1951   if (NULL == handle->ego_entry)
1952   {
1953     handle->emsg = GNUNET_strdup("invalid_token");
1954     handle->edesc = GNUNET_strdup("The Access Token expired");
1955     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1956     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1957     GNUNET_free(authorization);
1958     GNUNET_free(client_ticket);
1959     return;
1960   }
1961   ticket_str = strtok(NULL, delimiter_db);
1962   if (NULL == ticket_str)
1963   {
1964     handle->emsg = GNUNET_strdup("invalid_token");
1965     handle->edesc = GNUNET_strdup("The Access Token expired");
1966     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1967     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1968     GNUNET_free(authorization);
1969     GNUNET_free(client_ticket);
1970     return;
1971   }
1972   ticket = GNUNET_new(struct GNUNET_RECLAIM_Ticket);
1973   if ( GNUNET_OK
1974        != GNUNET_STRINGS_string_to_data (ticket_str,
1975                                          strlen (ticket_str),
1976                                          ticket,
1977                                          sizeof(struct GNUNET_RECLAIM_Ticket)))
1978   {
1979     handle->emsg = GNUNET_strdup("invalid_token");
1980     handle->edesc = GNUNET_strdup("The Access Token expired");
1981     handle->response_code = MHD_HTTP_UNAUTHORIZED;
1982     GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
1983     GNUNET_free(ticket);
1984     GNUNET_free(authorization);
1985     GNUNET_free(client_ticket);
1986     return;
1987   }
1988
1989   handle->idp = GNUNET_RECLAIM_connect (cfg);
1990   handle->oidc->response = json_object();
1991   json_object_set_new( handle->oidc->response, "sub", json_string( handle->ego_entry->keystring));
1992   handle->idp_op = GNUNET_RECLAIM_ticket_consume (
1993                                                   handle->idp,
1994                                                   GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego),
1995                                                   ticket,
1996                                                   consume_ticket,
1997                                                   handle);
1998   GNUNET_free(ticket);
1999   GNUNET_free(authorization);
2000   GNUNET_free(client_ticket);
2001
2002 }
2003
2004
2005 /**
2006  * Handle rest request
2007  *
2008  * @param handle the request handle
2009  */
2010 static void
2011 init_cont (struct RequestHandle *handle)
2012 {
2013   struct GNUNET_REST_RequestHandlerError err;
2014   static const struct GNUNET_REST_RequestHandler handlers[] = {
2015     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint},
2016     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, //url-encoded
2017     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
2018     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
2019     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2020     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
2021     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_OIDC,
2022       &options_cont},
2023     GNUNET_REST_HANDLER_END
2024   };
2025
2026   if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
2027                                                handlers,
2028                                                &err,
2029                                                handle))
2030   {
2031     handle->response_code = err.error_code;
2032     GNUNET_SCHEDULER_add_now (&do_error, handle);
2033   }
2034 }
2035
2036 /**
2037  * If listing is enabled, prints information about the egos.
2038  *
2039  * This function is initially called for all egos and then again
2040  * whenever a ego's identifier changes or if it is deleted.  At the
2041  * end of the initial pass over all egos, the function is once called
2042  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
2043  * be invoked in the future or that there was an error.
2044  *
2045  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
2046  * this function is only called ONCE, and 'NULL' being passed in
2047  * 'ego' does indicate an error (i.e. name is taken or no default
2048  * value is known).  If 'ego' is non-NULL and if '*ctx'
2049  * is set in those callbacks, the value WILL be passed to a subsequent
2050  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
2051  * that one was not NULL).
2052  *
2053  * When an identity is renamed, this function is called with the
2054  * (known) ego but the NEW identifier.
2055  *
2056  * When an identity is deleted, this function is called with the
2057  * (known) ego and "NULL" for the 'identifier'.  In this case,
2058  * the 'ego' is henceforth invalid (and the 'ctx' should also be
2059  * cleaned up).
2060  *
2061  * @param cls closure
2062  * @param ego ego handle
2063  * @param ctx context for application to store data for this ego
2064  *                 (during the lifetime of this process, initially NULL)
2065  * @param identifier identifier assigned by the user for this ego,
2066  *                   NULL if the user just deleted the ego and it
2067  *                   must thus no longer be used
2068  */
2069 static void
2070 list_ego (void *cls,
2071           struct GNUNET_IDENTITY_Ego *ego,
2072           void **ctx,
2073           const char *identifier)
2074 {
2075   struct RequestHandle *handle = cls;
2076   struct EgoEntry *ego_entry;
2077   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
2078
2079   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
2080   {
2081     handle->state = ID_REST_STATE_POST_INIT;
2082     init_cont (handle);
2083     return;
2084   }
2085   if (ID_REST_STATE_INIT == handle->state) {
2086     ego_entry = GNUNET_new (struct EgoEntry);
2087     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2088     ego_entry->keystring =
2089       GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
2090     ego_entry->ego = ego;
2091     ego_entry->identifier = GNUNET_strdup (identifier);
2092     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
2093     return;
2094   }
2095   /* Ego renamed or added */
2096   if (identifier != NULL) {
2097     for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) {
2098       if (ego_entry->ego == ego) {
2099         /* Rename */
2100         GNUNET_free (ego_entry->identifier);
2101         ego_entry->identifier = GNUNET_strdup (identifier);
2102         break;
2103       }
2104     }
2105     if (NULL == ego_entry) {
2106       /* Add */
2107       ego_entry = GNUNET_new (struct EgoEntry);
2108       GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2109       ego_entry->keystring =
2110         GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
2111       ego_entry->ego = ego;
2112       ego_entry->identifier = GNUNET_strdup (identifier);
2113       GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
2114     }
2115   } else {
2116     /* Delete */
2117     for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) {
2118       if (ego_entry->ego == ego)
2119         break;
2120     }
2121     if (NULL != ego_entry)
2122       GNUNET_CONTAINER_DLL_remove(handle->ego_head,handle->ego_tail, ego_entry);
2123   }
2124
2125 }
2126
2127 static void
2128 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
2129                               GNUNET_REST_ResultProcessor proc,
2130                               void *proc_cls)
2131 {
2132   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2133   handle->oidc = GNUNET_new (struct OIDC_Variables);
2134   if ( NULL == OIDC_identity_login_time )
2135     OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2136   if ( NULL == OIDC_identity_grants )
2137     OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2138   if ( NULL == OIDC_ticket_once )
2139     OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2140   if ( NULL == OIDC_interpret_access_token )
2141     OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2142   handle->response_code = 0;
2143   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
2144   handle->proc_cls = proc_cls;
2145   handle->proc = proc;
2146   handle->state = ID_REST_STATE_INIT;
2147   handle->rest_handle = rest_handle;
2148
2149   handle->url = GNUNET_strdup (rest_handle->url);
2150   if (handle->url[strlen (handle->url)-1] == '/')
2151     handle->url[strlen (handle->url)-1] = '\0';
2152   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2153               "Connecting...\n");
2154   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
2155                                                      &list_ego,
2156                                                      handle);
2157   handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
2158   handle->timeout_task =
2159     GNUNET_SCHEDULER_add_delayed (handle->timeout,
2160                                   &do_timeout,
2161                                   handle);
2162   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2163               "Connected\n");
2164 }
2165
2166 /**
2167  * Entry point for the plugin.
2168  *
2169  * @param cls Config info
2170  * @return NULL on error, otherwise the plugin context
2171  */
2172 void *
2173 libgnunet_plugin_rest_openid_connect_init (void *cls)
2174 {
2175   static struct Plugin plugin;
2176   struct GNUNET_REST_Plugin *api;
2177
2178   cfg = cls;
2179   if (NULL != plugin.cfg)
2180     return NULL;                /* can only initialize once! */
2181   memset (&plugin, 0, sizeof (struct Plugin));
2182   plugin.cfg = cfg;
2183   api = GNUNET_new (struct GNUNET_REST_Plugin);
2184   api->cls = &plugin;
2185   api->name = GNUNET_REST_API_NS_OIDC;
2186   api->process_request = &rest_identity_process_request;
2187   GNUNET_asprintf (&allow_methods,
2188                    "%s, %s, %s, %s, %s",
2189                    MHD_HTTP_METHOD_GET,
2190                    MHD_HTTP_METHOD_POST,
2191                    MHD_HTTP_METHOD_PUT,
2192                    MHD_HTTP_METHOD_DELETE,
2193                    MHD_HTTP_METHOD_OPTIONS);
2194
2195   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2196               _("Identity Provider REST API initialized\n"));
2197   return api;
2198 }
2199
2200
2201 /**
2202  * Exit point from the plugin.
2203  *
2204  * @param cls the plugin context (as returned by "init")
2205  * @return always NULL
2206  */
2207 void *
2208 libgnunet_plugin_rest_openid_connect_done (void *cls)
2209 {
2210   struct GNUNET_REST_Plugin *api = cls;
2211   struct Plugin *plugin = api->cls;
2212   plugin->cfg = NULL;
2213
2214   struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2215   void *value = NULL;
2216   hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
2217                                                               OIDC_identity_login_time);
2218   while (GNUNET_YES ==
2219          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2220   {
2221     if (NULL != value)
2222       GNUNET_free(value);
2223   }
2224   GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time);
2225   hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants);
2226   while (GNUNET_YES ==
2227          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2228   {
2229     if (NULL != value)
2230       GNUNET_free(value);
2231   }
2232   GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
2233   hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_ticket_once);
2234   while (GNUNET_YES ==
2235          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2236   {
2237     if (NULL != value)
2238       GNUNET_free(value);
2239   }
2240   GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once);
2241   hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_interpret_access_token);
2242   while (GNUNET_YES ==
2243          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2244   {
2245     if (NULL != value)
2246       GNUNET_free(value);
2247   }
2248   GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token);
2249   GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it);
2250   GNUNET_free_non_null (allow_methods);
2251   GNUNET_free (api);
2252   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2253               "Identity Provider REST plugin is finished\n");
2254   return NULL;
2255 }
2256
2257 /* end of plugin_rest_identity_provider.c */