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