-Merge branch 'master' into identity_oidc
[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   }
1520 }
1521
1522 /**
1523  * Create a response with requested records
1524  *
1525  * @param handle the RequestHandle
1526  */
1527 static void
1528 namestore_iteration_callback (
1529     void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1530     const char *rname, unsigned int rd_len,
1531     const struct GNUNET_GNSRECORD_Data *rd)
1532 {
1533   struct RequestHandle *handle = cls;
1534   struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey;
1535   struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey;
1536   int i;
1537
1538   for (i = 0; i < rd_len; i++)
1539   {
1540     if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type )
1541       continue;
1542
1543     if ( NULL != handle->oidc->login_identity )
1544     {
1545       GNUNET_CRYPTO_ecdsa_public_key_from_string (
1546           handle->oidc->login_identity,
1547           strlen (handle->oidc->login_identity),
1548           &login_identity_pkey);
1549       GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego,
1550                                           &current_zone_pkey);
1551
1552       if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1553                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1554       {
1555         if ( 0 == memcmp (&login_identity_pkey, &current_zone_pkey,
1556                        sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1557         {
1558           handle->oidc->is_client_trusted = GNUNET_YES;
1559         }
1560       }
1561     }
1562     else
1563     {
1564       if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
1565                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
1566       {
1567         handle->oidc->is_client_trusted = GNUNET_YES;
1568       }
1569     }
1570   }
1571
1572   GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it);
1573 }
1574
1575 /**
1576  * Iteration over all results finished, build final
1577  * response.
1578  *
1579  * @param cls the `struct RequestHandle`
1580  */
1581 static void namestore_iteration_finished_GET (void *cls)
1582 {
1583   struct RequestHandle *handle = cls;
1584   struct GNUNET_HashCode cache_key;
1585
1586   char *expected_redirect_uri;
1587   char *expected_scope;
1588   char delimiter[]=" ";
1589   int number_of_ignored_parameter, iterator;
1590
1591
1592   handle->ego_entry = handle->ego_entry->next;
1593
1594   if(NULL != handle->ego_entry)
1595   {
1596     handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1597     handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
1598                                            &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
1599                                            &namestore_iteration_finished_GET, handle);
1600     return;
1601   }
1602   if (GNUNET_NO == handle->oidc->is_client_trusted)
1603   {
1604     handle->emsg = GNUNET_strdup("unauthorized_client");
1605     handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1606                                   "authorization code using this method.");
1607     GNUNET_SCHEDULER_add_now (&do_error, handle);
1608     return;
1609   }
1610
1611   // REQUIRED value: redirect_uri
1612   GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1613                       &cache_key);
1614   if (GNUNET_NO == 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     GNUNET_SCHEDULER_add_now (&do_error, handle);
1620     return;
1621   }
1622   handle->oidc->redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1623                                                 &cache_key);
1624
1625   GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
1626   // verify the redirect uri matches https://<client_id>.zkey[/xyz]
1627   if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
1628   {
1629     handle->emsg=GNUNET_strdup("invalid_request");
1630     handle->edesc=GNUNET_strdup("Invalid redirect_uri");
1631     GNUNET_SCHEDULER_add_now (&do_error, handle);
1632     GNUNET_free(expected_redirect_uri);
1633     return;
1634   }
1635   handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
1636
1637   GNUNET_free(expected_redirect_uri);
1638   // REQUIRED value: response_type
1639   GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1640                       &cache_key);
1641   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1642                                                            &cache_key))
1643   {
1644     handle->emsg=GNUNET_strdup("invalid_request");
1645     handle->edesc=GNUNET_strdup("missing parameter response_type");
1646     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1647     return;
1648   }
1649   handle->oidc->response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1650                                                     &cache_key);
1651   handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
1652
1653   // REQUIRED value: scope
1654   GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
1655   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1656                                                            &cache_key))
1657   {
1658     handle->emsg=GNUNET_strdup("invalid_request");
1659     handle->edesc=GNUNET_strdup("missing parameter scope");
1660     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1661     return;
1662   }
1663   handle->oidc->scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1664                                             &cache_key);
1665   handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
1666
1667   //OPTIONAL value: nonce
1668   GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
1669   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1670                                                            &cache_key))
1671   {
1672     handle->oidc->nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1673                                               &cache_key);
1674     //TODO: what do we do with the nonce? => token
1675     handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
1676   }
1677
1678   //TODO check other values and use them accordingly
1679   number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1680   for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1681   {
1682     GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1683                         strlen(OIDC_ignored_parameter_array[iterator]),
1684                         &cache_key);
1685     if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
1686                                                             &cache_key))
1687     {
1688       handle->emsg=GNUNET_strdup("access_denied");
1689       GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1690                        OIDC_ignored_parameter_array[iterator]);
1691       GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1692       return;
1693     }
1694   }
1695
1696   // Checks if response_type is 'code'
1697   if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1698   {
1699     handle->emsg=GNUNET_strdup("unsupported_response_type");
1700     handle->edesc=GNUNET_strdup("The authorization server does not support "
1701                                 "obtaining this authorization code.");
1702     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1703     return;
1704   }
1705
1706   // Checks if scope contains 'openid'
1707   expected_scope = GNUNET_strdup(handle->oidc->scope);
1708   expected_scope = strtok (expected_scope, delimiter);
1709   while (NULL != expected_scope)
1710   {
1711     if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1712     {
1713       break;
1714     }
1715     expected_scope = strtok (NULL, delimiter);
1716   }
1717   if (NULL == expected_scope)
1718   {
1719     handle->emsg = GNUNET_strdup("invalid_scope");
1720     handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1721                                 "malformed.");
1722     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1723     return;
1724   }
1725
1726   GNUNET_free(expected_scope);
1727
1728   if( NULL != handle->oidc->login_identity )
1729   {
1730     GNUNET_SCHEDULER_add_now(&login_check,handle);
1731     return;
1732   }
1733
1734   GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1735 }
1736
1737 /**
1738  * Responds to authorization GET request
1739  *
1740  * @param con_handle the connection handle
1741  * @param url the url
1742  * @param cls the RequestHandle
1743  */
1744 static void
1745 authorize_GET_cont (struct GNUNET_REST_RequestHandle *con_handle,
1746                 const char* url,
1747                 void *cls)
1748 {
1749   struct RequestHandle *handle = cls;
1750   struct GNUNET_HashCode cache_key;
1751
1752   cookie_identity_interpretation(handle);
1753
1754   //RECOMMENDED value: state - REQUIRED for answers
1755   GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
1756   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1757                                                            &cache_key))
1758   {
1759     handle->oidc->state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1760                                               &cache_key);
1761     handle->oidc->state = GNUNET_strdup (handle->oidc->state);
1762   }
1763
1764   // REQUIRED value: client_id
1765   GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1766                       &cache_key);
1767   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1768                                                            &cache_key))
1769   {
1770     handle->emsg=GNUNET_strdup("invalid_request");
1771     handle->edesc=GNUNET_strdup("missing parameter client_id");
1772     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1773     GNUNET_SCHEDULER_add_now (&do_error, handle);
1774     return;
1775   }
1776   handle->oidc->client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1777                                                 &cache_key);
1778   handle->oidc->client_id = GNUNET_strdup (handle->oidc->client_id);
1779
1780   if ( GNUNET_OK
1781       != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
1782                                                      strlen (handle->oidc->client_id),
1783                                                      &handle->oidc->client_pkey) )
1784   {
1785     handle->emsg = GNUNET_strdup("unauthorized_client");
1786     handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1787                                   "authorization code using this method.");
1788     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1789     GNUNET_SCHEDULER_add_now (&do_error, handle);
1790     return;
1791   }
1792
1793
1794   if ( NULL == handle->ego_head )
1795   {
1796     handle->emsg = GNUNET_strdup("server_error");
1797     handle->edesc = GNUNET_strdup ("Egos are missing");
1798     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1799     GNUNET_SCHEDULER_add_now (&do_error, handle);
1800     return;
1801   }
1802
1803   handle->ego_entry = handle->ego_head;
1804   handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
1805   handle->oidc->is_client_trusted = GNUNET_NO;
1806
1807   // Checks if client_id is valid:
1808   handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
1809       handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
1810       handle, &namestore_iteration_callback, handle,
1811       &namestore_iteration_finished_GET, handle);
1812 }
1813
1814 /**
1815  * Iteration over all results finished, build final
1816  * response.
1817  *
1818  * @param cls the `struct RequestHandle`
1819  */
1820 static void namestore_iteration_finished_POST (void *cls)
1821 {
1822   struct RequestHandle *handle = cls;
1823   json_t *cache_object;
1824   char *expected_redirect_uri;
1825   char *expected_scope;
1826   char delimiter[]=" ";
1827   int number_of_ignored_parameter, iterator;
1828
1829
1830   handle->ego_entry = handle->ego_entry->next;
1831
1832   if(NULL != handle->ego_entry){
1833     handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
1834     handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (handle->namestore_handle, &handle->priv_key,
1835                                            &oidc_iteration_error, handle, &namestore_iteration_callback, handle,
1836                                            &namestore_iteration_finished_POST, handle);
1837     return;
1838   }
1839   if (GNUNET_YES != handle->oidc->is_client_trusted)
1840   {
1841     handle->emsg = GNUNET_strdup("unauthorized_client");
1842     handle->edesc = GNUNET_strdup("The client is not authorized to request an "
1843                                   "authorization code using this method.");
1844     GNUNET_SCHEDULER_add_now (&do_error, handle);
1845     return;
1846   }
1847
1848   // REQUIRED value: redirect_uri
1849   cache_object = json_object_get (handle->oidc->post_object, OIDC_REDIRECT_URI_KEY);
1850   if ( NULL == cache_object || !json_is_string(cache_object) )
1851   {
1852     handle->emsg=GNUNET_strdup("invalid_request");
1853     handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
1854     GNUNET_SCHEDULER_add_now (&do_error, handle);
1855     return;
1856   }
1857   handle->oidc->redirect_uri = json_string_value (cache_object);
1858
1859   GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", handle->oidc->client_id);
1860   // verify the redirect uri matches https://<client_id>.zkey[/xyz]
1861   if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, strlen(expected_redirect_uri)) )
1862   {
1863     handle->emsg=GNUNET_strdup("invalid_request");
1864     handle->edesc=GNUNET_strdup("Invalid redirect_uri");
1865     GNUNET_SCHEDULER_add_now (&do_error, handle);
1866     GNUNET_free(expected_redirect_uri);
1867     return;
1868   }
1869   handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
1870   GNUNET_free(expected_redirect_uri);
1871
1872   // REQUIRED value: response_type
1873   cache_object = json_object_get (handle->oidc->post_object, OIDC_RESPONSE_TYPE_KEY);
1874   if ( NULL == cache_object || !json_is_string(cache_object) )
1875   {
1876     handle->emsg=GNUNET_strdup("invalid_request");
1877     handle->edesc=GNUNET_strdup("missing parameter response_type");
1878     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1879     return;
1880   }
1881   handle->oidc->response_type = json_string_value (cache_object);
1882   handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
1883
1884   // REQUIRED value: scope
1885   cache_object = json_object_get (handle->oidc->post_object, OIDC_SCOPE_KEY);
1886   if ( NULL == cache_object || !json_is_string(cache_object) )
1887   {
1888     handle->emsg=GNUNET_strdup("invalid_request");
1889     handle->edesc=GNUNET_strdup("missing parameter scope");
1890     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1891     return;
1892   }
1893   handle->oidc->scope = json_string_value (cache_object);
1894   handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
1895
1896   //OPTIONAL value: nonce
1897   cache_object = json_object_get (handle->oidc->post_object, OIDC_NONCE_KEY);
1898   if ( NULL != cache_object && json_is_string(cache_object) )
1899   {
1900     handle->oidc->nonce = json_string_value (cache_object);
1901     //TODO: what do we do with the nonce?
1902     handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
1903   }
1904
1905   //TODO check other values and use them accordingly
1906   number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1907   for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1908   {
1909     cache_object = json_object_get (handle->oidc->post_object, OIDC_ignored_parameter_array[iterator]);
1910     if( NULL != cache_object && json_is_string(cache_object) )
1911     {
1912       handle->emsg=GNUNET_strdup("access_denied");
1913       GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
1914                        OIDC_ignored_parameter_array[iterator]);
1915       GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1916       return;
1917     }
1918   }
1919
1920   // Checks if response_type is 'code'
1921   if( 0 != strcmp( handle->oidc->response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
1922   {
1923     handle->emsg=GNUNET_strdup("unsupported_response_type");
1924     handle->edesc=GNUNET_strdup("The authorization server does not support "
1925                                 "obtaining this authorization code.");
1926     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1927     return;
1928   }
1929
1930   // Checks if scope contains 'openid'
1931   expected_scope = GNUNET_strdup(handle->oidc->scope);
1932   expected_scope = strtok (expected_scope, delimiter);
1933   while (NULL != expected_scope)
1934   {
1935     if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
1936     {
1937       break;
1938     }
1939     expected_scope = strtok (NULL, delimiter);
1940   }
1941   if (NULL == expected_scope)
1942   {
1943     handle->emsg = GNUNET_strdup("invalid_scope");
1944     handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1945                                 "malformed.");
1946     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1947     return;
1948   }
1949
1950   GNUNET_free(expected_scope);
1951
1952   if( NULL != handle->oidc->login_identity )
1953   {
1954     GNUNET_SCHEDULER_add_now(&login_check,handle);
1955     return;
1956   }
1957
1958   GNUNET_SCHEDULER_add_now(&login_redirection,handle);
1959 }
1960
1961
1962 /**
1963  * Responds to authorization POST request
1964  *
1965  * @param con_handle the connection handle
1966  * @param url the url
1967  * @param cls the RequestHandle
1968  */
1969 static void
1970 authorize_POST_cont (struct GNUNET_REST_RequestHandle *con_handle,
1971                 const char* url,
1972                 void *cls)
1973 {
1974   struct RequestHandle *handle = cls;
1975   json_t *cache_object;
1976   json_error_t error;
1977   handle->oidc->post_object = json_loads (handle->rest_handle->data, 0, &error);
1978
1979   //gets identity of login try with cookie
1980   cookie_identity_interpretation(handle);
1981
1982   //RECOMMENDED value: state - REQUIRED for answers
1983   cache_object = json_object_get (handle->oidc->post_object, OIDC_STATE_KEY);
1984   if ( NULL != cache_object && json_is_string(cache_object) )
1985   {
1986     handle->oidc->state = json_string_value (cache_object);
1987     handle->oidc->state = GNUNET_strdup(handle->oidc->state);
1988   }
1989
1990   // REQUIRED value: client_id
1991   cache_object = json_object_get (handle->oidc->post_object,
1992                                   OIDC_CLIENT_ID_KEY);
1993   if ( NULL == cache_object || !json_is_string(cache_object) )
1994   {
1995     handle->emsg = GNUNET_strdup("invalid_request");
1996     handle->edesc = GNUNET_strdup("missing parameter client_id");
1997     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1998     GNUNET_SCHEDULER_add_now (&do_error, handle);
1999     return;
2000   }
2001   handle->oidc->client_id = json_string_value (cache_object);
2002   handle->oidc->client_id = GNUNET_strdup(handle->oidc->client_id);
2003
2004   if ( GNUNET_OK
2005       != GNUNET_CRYPTO_ecdsa_public_key_from_string (
2006           handle->oidc->client_id, strlen (handle->oidc->client_id),
2007           &handle->oidc->client_pkey) )
2008   {
2009     handle->emsg = GNUNET_strdup("unauthorized_client");
2010     handle->edesc = GNUNET_strdup("The client is not authorized to request an "
2011                                   "authorization code using this method.");
2012     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2013     GNUNET_SCHEDULER_add_now (&do_error, handle);
2014     return;
2015   }
2016
2017   if ( NULL == handle->ego_head )
2018   {
2019     //TODO throw error or ignore if egos are missing?
2020     handle->emsg = GNUNET_strdup("server_error");
2021     handle->edesc = GNUNET_strdup ("Egos are missing");
2022     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2023     GNUNET_SCHEDULER_add_now (&do_error, handle);
2024     return;
2025   }
2026
2027   handle->ego_entry = handle->ego_head;
2028   handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego);
2029   handle->oidc->is_client_trusted = GNUNET_NO;
2030
2031   // Checks if client_id is valid:
2032   handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
2033       handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
2034       handle, &namestore_iteration_callback, handle,
2035       &namestore_iteration_finished_POST, handle);
2036 }
2037
2038 /**
2039  * Combines an identity with a login time and responds OK to login request
2040  *
2041  * @param con_handle the connection handle
2042  * @param url the url
2043  * @param cls the RequestHandle
2044  */
2045 static void
2046 login_cont (struct GNUNET_REST_RequestHandle *con_handle,
2047             const char* url,
2048             void *cls)
2049 {
2050   struct MHD_Response *resp = GNUNET_REST_create_response ("");
2051   struct RequestHandle *handle = cls;
2052   struct GNUNET_HashCode cache_key;
2053   struct GNUNET_TIME_Absolute *current_time;
2054   struct GNUNET_TIME_Absolute *last_time;
2055   char* cookie;
2056   json_t *root;
2057   json_error_t error;
2058   json_t *identity;
2059   root = json_loads (handle->rest_handle->data, 0, &error);
2060   identity = json_object_get (root, "identity");
2061   if ( json_is_string(identity) )
2062   {
2063     GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
2064
2065     GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
2066
2067     current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
2068     *current_time = GNUNET_TIME_relative_to_absolute (
2069         GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_minute_ (),
2070                                        30));
2071     last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, &cache_key);
2072     if (NULL != last_time)
2073     {
2074       GNUNET_free(last_time);
2075     }
2076     GNUNET_CONTAINER_multihashmap_put (
2077         OIDC_identity_login_time, &cache_key, current_time,
2078         GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
2079
2080     handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
2081   }
2082   else
2083   {
2084     handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
2085   }
2086   GNUNET_free(cookie);
2087   json_decref (root);
2088   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
2089   return;
2090 }
2091
2092 static void
2093 token_cont(struct GNUNET_REST_RequestHandle *con_handle,
2094                 const char* url,
2095                 void *cls)
2096 {
2097   //TODO static strings
2098   struct RequestHandle *handle = cls;
2099   struct GNUNET_HashCode cache_key;
2100   char *authorization, *cache_authorization, *credentials;
2101   char delimiter[]=" ";
2102   char delimiter_user_psw[]=":";
2103   json_t *cache_object;
2104   json_error_t error;
2105   char *grant_type, *code, *expected_jwt, *redirect_uri, *expected_redirect_uri;
2106   char *user_psw, *user, *psw;
2107   char *expected_psw;
2108   int client_exists = GNUNET_NO;
2109
2110   handle->oidc->post_object = json_loads (handle->rest_handle->data, 0, &error);
2111   //Check Authorization Header
2112   GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
2113                       &cache_key);
2114   if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->header_param_map,
2115                                                              &cache_key) )
2116   {
2117     //error
2118   }
2119   authorization = GNUNET_CONTAINER_multihashmap_get ( handle->rest_handle->header_param_map, &cache_key);
2120   //split JWT in "Basic" and [content]
2121   cache_authorization = GNUNET_strdup (authorization);
2122   credentials = strtok(cache_authorization,delimiter);
2123   if( NULL != credentials)
2124   {
2125     credentials = strtok(credentials, delimiter);
2126     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Test:%s\n", credentials);
2127   }
2128   if (NULL == credentials)
2129   {
2130     //error
2131   }
2132   GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), &user_psw);
2133
2134   if ( NULL == user_psw )
2135   {
2136     //error
2137   }
2138   user = strtok (user_psw, delimiter_user_psw);
2139   if ( NULL == user )
2140   {
2141     //error
2142   }
2143
2144   psw = strtok (user, delimiter_user_psw);
2145   if (NULL == psw)
2146   {
2147     //error
2148   }
2149
2150   //check psw
2151   if ( GNUNET_OK
2152       == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
2153                                                 "psw", &expected_psw) )
2154   {
2155     if (0 != strcmp (expected_psw, psw))
2156     {
2157       //error
2158     }
2159     GNUNET_free(expected_psw);
2160   }
2161   else
2162   {
2163     handle->emsg = GNUNET_strdup("server_error");
2164     handle->edesc = GNUNET_strdup ("gnunet configuration failed");
2165     handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
2166     GNUNET_SCHEDULER_add_now (&do_error, handle);
2167     return;
2168   }
2169
2170   //check client_id
2171   for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; )
2172   {
2173     if (handle->ego_entry->keystring == user)
2174     {
2175       client_exists = GNUNET_YES;
2176       break;
2177     }
2178     handle->ego_entry = handle->ego_entry->next;
2179   }
2180   if (GNUNET_NO == client_exists)
2181   {
2182     //error
2183   }
2184
2185   cache_object = json_object_get (handle->oidc->post_object, "grant_type");
2186   if ( NULL == cache_object || !json_is_string(cache_object) )
2187   {
2188     handle->emsg=GNUNET_strdup("invalid_request");
2189     handle->edesc=GNUNET_strdup("missing parameter grant_type");
2190     GNUNET_SCHEDULER_add_now (&do_error, handle);
2191     return;
2192   }
2193   grant_type = json_string_value (cache_object);
2194
2195   //Check parameter grant_type == "authorization_code"
2196   if (0 != strcmp("authorization_code", grant_type))
2197   {
2198     //error
2199   }
2200
2201   cache_object = json_object_get (handle->oidc->post_object, "code");
2202   if ( NULL == cache_object || !json_is_string(cache_object) )
2203   {
2204     handle->emsg=GNUNET_strdup("invalid_request");
2205     handle->edesc=GNUNET_strdup("missing parameter code");
2206     GNUNET_SCHEDULER_add_now (&do_error, handle);
2207     return;
2208   }
2209   code = json_string_value (cache_object);
2210
2211   // lookup code in grants_hashmap and check if [content] is same
2212
2213   cache_object = json_object_get (handle->oidc->post_object, "redirect_uri");
2214   if ( NULL == cache_object || !json_is_string(cache_object) )
2215   {
2216     handle->emsg=GNUNET_strdup("invalid_request");
2217     handle->edesc=GNUNET_strdup("missing parameter code");
2218     GNUNET_SCHEDULER_add_now (&do_error, handle);
2219     return;
2220   }
2221   redirect_uri = json_string_value (cache_object);
2222
2223   // check redirect_uri
2224   GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey", user);
2225   // verify the redirect uri matches https://<client_id>.zkey[/xyz]
2226   if( 0 != strncmp( expected_redirect_uri, redirect_uri, strlen(expected_redirect_uri)) )
2227   {
2228     handle->emsg=GNUNET_strdup("invalid_request");
2229     handle->edesc=GNUNET_strdup("Invalid redirect_uri");
2230     GNUNET_SCHEDULER_add_now (&do_error, handle);
2231     GNUNET_free(expected_redirect_uri);
2232     return;
2233   }
2234   handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
2235   GNUNET_free(expected_redirect_uri);
2236
2237   //return something
2238
2239   GNUNET_free(cache_authorization);
2240   json_decref(handle->oidc->post_object);
2241 }
2242
2243 /**
2244  * Handle rest request
2245  *
2246  * @param handle the request handle
2247  */
2248 static void
2249 init_cont (struct RequestHandle *handle)
2250 {
2251   struct GNUNET_REST_RequestHandlerError err;
2252   static const struct GNUNET_REST_RequestHandler handlers[] = {
2253     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
2254     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
2255     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
2256     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_GET_cont},
2257     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_GET_cont},
2258     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
2259     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_cont},
2260     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
2261     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
2262     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
2263       &options_cont},
2264     GNUNET_REST_HANDLER_END
2265   };
2266
2267   if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
2268                                                handlers,
2269                                                &err,
2270                                                handle))
2271   {
2272     handle->response_code = err.error_code;
2273     GNUNET_SCHEDULER_add_now (&do_error, handle);
2274   }
2275 }
2276
2277 /**
2278  * If listing is enabled, prints information about the egos.
2279  *
2280  * This function is initially called for all egos and then again
2281  * whenever a ego's identifier changes or if it is deleted.  At the
2282  * end of the initial pass over all egos, the function is once called
2283  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
2284  * be invoked in the future or that there was an error.
2285  *
2286  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
2287  * this function is only called ONCE, and 'NULL' being passed in
2288  * 'ego' does indicate an error (i.e. name is taken or no default
2289  * value is known).  If 'ego' is non-NULL and if '*ctx'
2290  * is set in those callbacks, the value WILL be passed to a subsequent
2291  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
2292  * that one was not NULL).
2293  *
2294  * When an identity is renamed, this function is called with the
2295  * (known) ego but the NEW identifier.
2296  *
2297  * When an identity is deleted, this function is called with the
2298  * (known) ego and "NULL" for the 'identifier'.  In this case,
2299  * the 'ego' is henceforth invalid (and the 'ctx' should also be
2300  * cleaned up).
2301  *
2302  * @param cls closure
2303  * @param ego ego handle
2304  * @param ctx context for application to store data for this ego
2305  *                 (during the lifetime of this process, initially NULL)
2306  * @param identifier identifier assigned by the user for this ego,
2307  *                   NULL if the user just deleted the ego and it
2308  *                   must thus no longer be used
2309  */
2310 static void
2311 list_ego (void *cls,
2312           struct GNUNET_IDENTITY_Ego *ego,
2313           void **ctx,
2314           const char *identifier)
2315 {
2316   struct RequestHandle *handle = cls;
2317   struct EgoEntry *ego_entry;
2318   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
2319
2320   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
2321   {
2322     handle->state = ID_REST_STATE_POST_INIT;
2323     init_cont (handle);
2324     return;
2325   }
2326   if (ID_REST_STATE_INIT == handle->state) {
2327     ego_entry = GNUNET_new (struct EgoEntry);
2328     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
2329     ego_entry->keystring =
2330       GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
2331     ego_entry->ego = ego;
2332     ego_entry->identifier = GNUNET_strdup (identifier);
2333     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
2334   }
2335
2336 }
2337
2338 static void
2339 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
2340                               GNUNET_REST_ResultProcessor proc,
2341                               void *proc_cls)
2342 {
2343   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
2344   handle->oidc = GNUNET_new (struct OIDC_Variables);
2345   if ( NULL == OIDC_identity_login_time )
2346     OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2347   if ( NULL == OIDC_identity_grants )
2348     OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
2349   handle->response_code = 0;
2350   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
2351   handle->proc_cls = proc_cls;
2352   handle->proc = proc;
2353   handle->state = ID_REST_STATE_INIT;
2354   handle->rest_handle = rest_handle;
2355
2356   handle->url = GNUNET_strdup (rest_handle->url);
2357   if (handle->url[strlen (handle->url)-1] == '/')
2358     handle->url[strlen (handle->url)-1] = '\0';
2359   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2360               "Connecting...\n");
2361   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
2362                                                      &list_ego,
2363                                                      handle);
2364   handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
2365   handle->timeout_task =
2366     GNUNET_SCHEDULER_add_delayed (handle->timeout,
2367                                   &do_timeout,
2368                                   handle);
2369   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2370               "Connected\n");
2371 }
2372
2373 /**
2374  * Entry point for the plugin.
2375  *
2376  * @param cls Config info
2377  * @return NULL on error, otherwise the plugin context
2378  */
2379 void *
2380 libgnunet_plugin_rest_identity_provider_init (void *cls)
2381 {
2382   static struct Plugin plugin;
2383   struct GNUNET_REST_Plugin *api;
2384
2385   cfg = cls;
2386   if (NULL != plugin.cfg)
2387     return NULL;                /* can only initialize once! */
2388   memset (&plugin, 0, sizeof (struct Plugin));
2389   plugin.cfg = cfg;
2390   api = GNUNET_new (struct GNUNET_REST_Plugin);
2391   api->cls = &plugin;
2392   api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
2393   api->process_request = &rest_identity_process_request;
2394   GNUNET_asprintf (&allow_methods,
2395                    "%s, %s, %s, %s, %s",
2396                    MHD_HTTP_METHOD_GET,
2397                    MHD_HTTP_METHOD_POST,
2398                    MHD_HTTP_METHOD_PUT,
2399                    MHD_HTTP_METHOD_DELETE,
2400                    MHD_HTTP_METHOD_OPTIONS);
2401
2402   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2403               _("Identity Provider REST API initialized\n"));
2404   return api;
2405 }
2406
2407
2408 /**
2409  * Exit point from the plugin.
2410  *
2411  * @param cls the plugin context (as returned by "init")
2412  * @return always NULL
2413  */
2414 void *
2415 libgnunet_plugin_rest_identity_provider_done (void *cls)
2416 {
2417   struct GNUNET_REST_Plugin *api = cls;
2418   struct Plugin *plugin = api->cls;
2419   plugin->cfg = NULL;
2420
2421   struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
2422   void *value = NULL;
2423   hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
2424       OIDC_identity_login_time);
2425   while (GNUNET_YES ==
2426          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2427   {
2428     if (NULL != value)
2429       GNUNET_free(value);
2430   }
2431   GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time);
2432   hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_identity_grants);
2433   while (GNUNET_YES ==
2434          GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
2435   {
2436     if (NULL != value)
2437       GNUNET_free(value);
2438   }
2439   GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
2440   GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it);
2441   GNUNET_free_non_null (allow_methods);
2442   GNUNET_free (api);
2443   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2444               "Identity Provider REST plugin is finished\n");
2445   return NULL;
2446 }
2447
2448 /* end of plugin_rest_identity_provider.c */