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