-add login and login timeout
[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 namespace
70  */
71 #define GNUNET_REST_API_NS_AUTHORIZE "/idp/authorize"
72
73 /**
74  * Login namespace
75  */
76 #define GNUNET_REST_API_NS_LOGIN "/idp/login"
77
78 /**
79  * Attribute key
80  */
81 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
82
83 /**
84  * Ticket key
85  */
86 #define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket"
87
88
89 /**
90  * Value key
91  */
92 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value"
93
94 /**
95  * State while collecting all egos
96  */
97 #define ID_REST_STATE_INIT 0
98
99 /**
100  * Done collecting egos
101  */
102 #define ID_REST_STATE_POST_INIT 1
103
104 /**
105  * OIDC response_type key
106  */
107 #define OIDC_RESPONSE_TYPE_KEY "response_type"
108
109 /**
110  * OIDC client_id key
111  */
112 #define OIDC_CLIENT_ID_KEY "client_id"
113
114 /**
115  * OIDC scope key
116  */
117 #define OIDC_SCOPE_KEY "scope"
118
119 /**
120  * OIDC redirect_uri key
121  */
122 #define OIDC_REDIRECT_URI_KEY "redirect_uri"
123
124 /**
125  * OIDC state key
126  */
127 #define OIDC_STATE_KEY "state"
128
129 /**
130  * OIDC nonce key
131  */
132 #define OIDC_NONCE_KEY "nonce"
133
134 /**
135  * OIDC authorization header key
136  */
137 #define OIDC_AUTHORIZATION_HEADER_KEY "Authorization"
138
139 /**
140  * OIDC expected response_type while authorizing
141  */
142 #define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
143
144 /**
145  * OIDC expected scope part while authorizing
146  */
147 #define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
148
149
150 /**
151  * OIDC ignored parameter array
152  */
153 char* OIDC_ignored_parameter_array [] =
154 {
155   "display", "prompt", "max_age", "ui_locales", "response_mode",
156   "id_token_hint", "login_hint", "acr_values"
157 };
158
159 /**
160  * OIDC authorized identities and times hashmap
161  */
162 struct GNUNET_CONTAINER_MultiHashMap *OIDC_authorized_identities;
163
164 /**
165  * The configuration handle
166  */
167 const struct GNUNET_CONFIGURATION_Handle *cfg;
168
169 /**
170  * HTTP methods allows for this plugin
171  */
172 static char* allow_methods;
173
174 /**
175  * @brief struct returned by the initialization function of the plugin
176  */
177 struct Plugin
178 {
179   const struct GNUNET_CONFIGURATION_Handle *cfg;
180 };
181
182 /**
183  * The ego list
184  */
185 struct EgoEntry
186 {
187   /**
188    * DLL
189    */
190   struct EgoEntry *next;
191
192   /**
193    * DLL
194    */
195   struct EgoEntry *prev;
196
197   /**
198    * Ego Identifier
199    */
200   char *identifier;
201
202   /**
203    * Public key string
204    */
205   char *keystring;
206
207   /**
208    * The Ego
209    */
210   struct GNUNET_IDENTITY_Ego *ego;
211 };
212
213
214 struct RequestHandle
215 {
216   /**
217    * Ego list
218    */
219   struct EgoEntry *ego_head;
220
221   /**
222    * Ego list
223    */
224   struct EgoEntry *ego_tail;
225
226   /**
227    * Selected ego
228    */
229   struct EgoEntry *ego_entry;
230
231   /**
232    * Ptr to current ego private key
233    */
234   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
235
236   /**
237    * The processing state
238    */
239   int state;
240
241   /**
242    * Handle to Identity service.
243    */
244   struct GNUNET_IDENTITY_Handle *identity_handle;
245
246   /**
247    * Rest connection
248    */
249   struct GNUNET_REST_RequestHandle *rest_handle;
250
251
252   /**
253    * IDENTITY Operation
254    */
255   struct GNUNET_IDENTITY_Operation *op;
256
257   /**
258    * Identity Provider
259    */
260   struct GNUNET_IDENTITY_PROVIDER_Handle *idp;
261
262   /**
263    * Idp Operation
264    */
265   struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op;
266
267   /**
268    * Attribute iterator
269    */
270   struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it;
271
272   /**
273    * Ticket iterator
274    */
275   struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it;
276
277   /**
278    * Desired timeout for the lookup (default is no timeout).
279    */
280   struct GNUNET_TIME_Relative timeout;
281
282   /**
283    * ID of a task associated with the resolution process.
284    */
285   struct GNUNET_SCHEDULER_Task *timeout_task;
286
287   /**
288    * The plugin result processor
289    */
290   GNUNET_REST_ResultProcessor proc;
291
292   /**
293    * The closure of the result processor
294    */
295   void *proc_cls;
296
297   /**
298    * The url
299    */
300   char *url;
301
302   /**
303    * Error response message
304    */
305   char *emsg;
306
307   /**
308    * Error response uri
309    */
310   char *eredirect;
311
312   /**
313    * Error response description
314    */
315   char *edesc;
316
317   /**
318    * Reponse code
319    */
320   int response_code;
321
322   /**
323    * Response object
324    */
325   struct GNUNET_JSONAPI_Document *resp_object;
326
327 };
328
329
330
331 /**
332  * Cleanup lookup handle
333  * @param handle Handle to clean up
334  */
335 static void
336 cleanup_handle (struct RequestHandle *handle)
337 {
338   struct EgoEntry *ego_entry;
339   struct EgoEntry *ego_tmp;
340   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341               "Cleaning up\n");
342   if (NULL != handle->resp_object)
343     GNUNET_JSONAPI_document_delete (handle->resp_object);
344   if (NULL != handle->timeout_task)
345     GNUNET_SCHEDULER_cancel (handle->timeout_task);
346   if (NULL != handle->identity_handle)
347     GNUNET_IDENTITY_disconnect (handle->identity_handle);
348   if (NULL != handle->attr_it)
349     GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it);
350   if (NULL != handle->ticket_it)
351     GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it);
352   if (NULL != handle->idp)
353     GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp);
354   if (NULL != handle->url)
355     GNUNET_free (handle->url);
356   if (NULL != handle->emsg)
357     GNUNET_free (handle->emsg);
358   for (ego_entry = handle->ego_head;
359        NULL != ego_entry;)
360   {
361     ego_tmp = ego_entry;
362     ego_entry = ego_entry->next;
363     GNUNET_free (ego_tmp->identifier);
364     GNUNET_free (ego_tmp->keystring);
365     GNUNET_free (ego_tmp);
366   }
367   GNUNET_free (handle);
368 }
369
370 static void
371 cleanup_handle_delayed (void *cls)
372 {
373   cleanup_handle (cls);
374 }
375
376
377 /**
378  * Task run on error, sends error message.  Cleans up everything.
379  *
380  * @param cls the `struct RequestHandle`
381  */
382 static void
383 do_error (void *cls)
384 {
385   struct RequestHandle *handle = cls;
386   struct MHD_Response *resp;
387   char *json_error;
388
389   GNUNET_asprintf (&json_error,
390                    "{error : %s}",
391                    handle->emsg);
392   resp = GNUNET_REST_create_response (json_error);
393   handle->proc (handle->proc_cls, resp, handle->response_code);
394   cleanup_handle (handle);
395   GNUNET_free (json_error);
396 }
397
398 /**
399  * Task run on error, sends error message.  Cleans up everything.
400  *
401  * @param cls the `struct RequestHandle`
402  */
403 static void
404 do_redirect_error (void *cls)
405 {
406   struct RequestHandle *handle = cls;
407   struct MHD_Response *resp;
408   char* redirect;
409   //TODO handle->url is wrong
410   GNUNET_asprintf (&redirect,
411                    "%s?error=%s&error_description=%s",
412                    handle->eredirect, handle->emsg, handle->edesc );
413   resp = GNUNET_REST_create_response ("");
414   MHD_add_response_header (resp, "Location", redirect);
415   handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
416   cleanup_handle (handle);
417   GNUNET_free (redirect);
418 }
419
420 /**
421  * Task run on timeout, sends error message.  Cleans up everything.
422  *
423  * @param cls the `struct RequestHandle`
424  */
425 static void
426 do_timeout (void *cls)
427 {
428   struct RequestHandle *handle = cls;
429
430   handle->timeout_task = NULL;
431   do_error (handle);
432 }
433
434
435 static void
436 collect_error_cb (void *cls)
437 {
438   struct RequestHandle *handle = cls;
439
440   do_error (handle);
441 }
442
443 static void
444 finished_cont (void *cls,
445                int32_t success,
446                const char *emsg)
447 {
448   struct RequestHandle *handle = cls;
449   struct MHD_Response *resp;
450
451   resp = GNUNET_REST_create_response (emsg);
452   if (GNUNET_OK != success)
453   {
454     GNUNET_SCHEDULER_add_now (&do_error, handle);
455     return;
456   }
457   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
458   GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
459 }
460
461
462 /**
463  * Return attributes for identity
464  *
465  * @param cls the request handle
466  */
467 static void
468 return_response (void *cls)
469 {
470   char* result_str;
471   struct RequestHandle *handle = cls;
472   struct MHD_Response *resp;
473
474   GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str);
475   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str);
476   resp = GNUNET_REST_create_response (result_str);
477   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
478   GNUNET_free (result_str);
479   cleanup_handle (handle);
480 }
481
482
483 static void
484 collect_finished_cb (void *cls)
485 {
486   struct RequestHandle *handle = cls;
487   //Done
488   handle->attr_it = NULL;
489   handle->ticket_it = NULL;
490   GNUNET_SCHEDULER_add_now (&return_response, handle);
491 }
492
493
494 /**
495  * Collect all attributes for an ego
496  *
497  */
498 static void
499 ticket_collect (void *cls,
500                 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
501 {
502   struct GNUNET_JSONAPI_Resource *json_resource;
503   struct RequestHandle *handle = cls;
504   json_t *value;
505   char* tmp;
506
507   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n");
508   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
509                                              sizeof (uint64_t));
510   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET,
511                                                        tmp);
512   GNUNET_free (tmp);
513   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
514
515   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity,
516                                              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
517   value = json_string (tmp);
518   GNUNET_JSONAPI_resource_add_attr (json_resource,
519                                     "issuer",
520                                     value);
521   GNUNET_free (tmp);
522   json_decref (value);
523   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
524                                              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
525   value = json_string (tmp);
526   GNUNET_JSONAPI_resource_add_attr (json_resource,
527                                     "audience",
528                                     value);
529   GNUNET_free (tmp);
530   json_decref (value);
531   tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
532                                              sizeof (uint64_t));
533   value = json_string (tmp);
534   GNUNET_JSONAPI_resource_add_attr (json_resource,
535                                     "rnd",
536                                     value);
537   GNUNET_free (tmp);
538   json_decref (value);
539   GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it);
540 }
541
542
543
544 /**
545  * List tickets for identity request
546  *
547  * @param con_handle the connection handle
548  * @param url the url
549  * @param cls the RequestHandle
550  */
551 static void
552 list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle,
553                    const char* url,
554                    void *cls)
555 {
556   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
557   struct RequestHandle *handle = cls;
558   struct EgoEntry *ego_entry;
559   char *identity;
560
561   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n",
562               handle->url);
563   if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >=
564        strlen (handle->url))
565   {
566     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
567     GNUNET_SCHEDULER_add_now (&do_error, handle);
568     return;
569   }
570   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1;
571
572   for (ego_entry = handle->ego_head;
573        NULL != ego_entry;
574        ego_entry = ego_entry->next)
575     if (0 == strcmp (identity, ego_entry->identifier))
576       break;
577   handle->resp_object = GNUNET_JSONAPI_document_new ();
578
579   if (NULL == ego_entry)
580   {
581     //Done
582     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
583                 identity);
584     GNUNET_SCHEDULER_add_now (&return_response, handle);
585     return;
586   }
587   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
588   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
589   handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp,
590                                                                        priv_key,
591                                                                        &collect_error_cb,
592                                                                        handle,
593                                                                        &ticket_collect,
594                                                                        handle,
595                                                                        &collect_finished_cb,
596                                                                        handle);
597 }
598
599
600 static void
601 add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
602                     const char* url,
603                     void *cls)
604 {
605   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
606   const char* identity;
607   const char* name_str;
608   const char* value_str;
609
610   struct RequestHandle *handle = cls;
611   struct EgoEntry *ego_entry;
612   struct MHD_Response *resp;
613   struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute;
614   struct GNUNET_JSONAPI_Document *json_obj;
615   struct GNUNET_JSONAPI_Resource *json_res;
616   char term_data[handle->rest_handle->data_size+1];
617   json_t *value_json;
618   json_t *data_json;
619   json_error_t err;
620   struct GNUNET_JSON_Specification docspec[] = {
621     GNUNET_JSON_spec_jsonapi_document (&json_obj),
622     GNUNET_JSON_spec_end()
623   };
624
625   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n",
626               handle->url);
627   if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
628        strlen (handle->url))
629   {
630     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
631     GNUNET_SCHEDULER_add_now (&do_error, handle);
632     return;
633   }
634   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
635
636   for (ego_entry = handle->ego_head;
637        NULL != ego_entry;
638        ego_entry = ego_entry->next)
639     if (0 == strcmp (identity, ego_entry->identifier))
640       break;
641
642   if (NULL == ego_entry)
643   {
644     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
645                 "Identity unknown (%s)\n", identity);
646     GNUNET_JSONAPI_document_delete (json_obj);
647     return;
648   }
649   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
650
651   if (0 >= handle->rest_handle->data_size)
652   {
653     GNUNET_SCHEDULER_add_now (&do_error, handle);
654     return;
655   }
656
657   term_data[handle->rest_handle->data_size] = '\0';
658   GNUNET_memcpy (term_data,
659                  handle->rest_handle->data,
660                  handle->rest_handle->data_size);
661   data_json = json_loads (term_data,
662                           JSON_DECODE_ANY,
663                           &err);
664   GNUNET_assert (GNUNET_OK ==
665                  GNUNET_JSON_parse (data_json, docspec,
666                                     NULL, NULL));
667   json_decref (data_json);
668   if (NULL == json_obj)
669   {
670     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
671                 "Unable to parse JSONAPI Object from %s\n",
672                 term_data);
673     GNUNET_SCHEDULER_add_now (&do_error, handle);
674     return;
675   }
676   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
677   {
678     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
679                 "Cannot create more than 1 resource! (Got %d)\n",
680                 GNUNET_JSONAPI_document_resource_count (json_obj));
681     GNUNET_JSONAPI_document_delete (json_obj);
682     GNUNET_SCHEDULER_add_now (&do_error, handle);
683     return;
684   }
685   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
686   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
687                                                        GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE))
688   {
689     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
690                 "Unsupported JSON data type\n");
691     GNUNET_JSONAPI_document_delete (json_obj);
692     resp = GNUNET_REST_create_response (NULL);
693     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
694     cleanup_handle (handle);
695     return;
696   }
697   name_str = GNUNET_JSONAPI_resource_get_id (json_res);
698   value_json = GNUNET_JSONAPI_resource_read_attr (json_res,
699                                                   "value");
700   value_str = json_string_value (value_json);
701   attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str,
702                                                       GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
703                                                       value_str,
704                                                       strlen (value_str) + 1);
705   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
706   handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp,
707                                                              identity_priv,
708                                                              attribute,
709                                                              &finished_cont,
710                                                              handle);
711   GNUNET_free (attribute);
712   GNUNET_JSONAPI_document_delete (json_obj);
713 }
714
715
716
717 /**
718  * Collect all attributes for an ego
719  *
720  */
721 static void
722 attr_collect (void *cls,
723               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
724               const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
725 {
726   struct GNUNET_JSONAPI_Resource *json_resource;
727   struct RequestHandle *handle = cls;
728   json_t *value;
729   
730   if ((NULL == attr->name) || (NULL == attr->data))
731   {
732     GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
733     return;
734   }
735
736   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
737               attr->name);
738   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
739                                                attr->name);
740   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
741
742   value = json_string (attr->data);
743   GNUNET_JSONAPI_resource_add_attr (json_resource,
744                                     "value",
745                                     value);
746   json_decref (value);
747   GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
748 }
749
750
751
752 /**
753  * List attributes for identity request
754  *
755  * @param con_handle the connection handle
756  * @param url the url
757  * @param cls the RequestHandle
758  */
759 static void
760 list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle,
761                      const char* url,
762                      void *cls)
763 {
764   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
765   struct RequestHandle *handle = cls;
766   struct EgoEntry *ego_entry;
767   char *identity;
768
769   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n",
770               handle->url);
771   if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >=
772        strlen (handle->url))
773   {
774     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n");
775     GNUNET_SCHEDULER_add_now (&do_error, handle);
776     return;
777   }
778   identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1;
779
780   for (ego_entry = handle->ego_head;
781        NULL != ego_entry;
782        ego_entry = ego_entry->next)
783     if (0 == strcmp (identity, ego_entry->identifier))
784       break;
785   handle->resp_object = GNUNET_JSONAPI_document_new ();
786
787
788   if (NULL == ego_entry)
789   {
790     //Done
791     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n",
792                 identity);
793     GNUNET_SCHEDULER_add_now (&return_response, handle);
794     return;
795   }
796   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
797   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
798   handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp,
799                                                                    priv_key,
800                                                                    &collect_error_cb,
801                                                                    handle,
802                                                                    &attr_collect,
803                                                                    handle,
804                                                                    &collect_finished_cb,
805                                                                    handle);
806 }
807
808
809 static void
810 revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
811                     const char* url,
812                     void *cls)
813 {
814   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
815   const char* identity_str;
816   const char* audience_str;
817   const char* rnd_str;
818
819   struct RequestHandle *handle = cls;
820   struct EgoEntry *ego_entry;
821   struct MHD_Response *resp;
822   struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
823   struct GNUNET_JSONAPI_Document *json_obj;
824   struct GNUNET_JSONAPI_Resource *json_res;
825   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
826   char term_data[handle->rest_handle->data_size+1];
827   json_t *rnd_json;
828   json_t *identity_json;
829   json_t *audience_json;
830   json_t *data_json;
831   json_error_t err;
832   struct GNUNET_JSON_Specification docspec[] = {
833     GNUNET_JSON_spec_jsonapi_document (&json_obj),
834     GNUNET_JSON_spec_end()
835   };
836
837   if (0 >= handle->rest_handle->data_size)
838   {
839     GNUNET_SCHEDULER_add_now (&do_error, handle);
840     return;
841   }
842
843   term_data[handle->rest_handle->data_size] = '\0';
844   GNUNET_memcpy (term_data,
845                  handle->rest_handle->data,
846                  handle->rest_handle->data_size);
847   data_json = json_loads (term_data,
848                           JSON_DECODE_ANY,
849                           &err);
850   GNUNET_assert (GNUNET_OK ==
851                  GNUNET_JSON_parse (data_json, docspec,
852                                     NULL, NULL));
853   json_decref (data_json);
854   if (NULL == json_obj)
855   {
856     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
857                 "Unable to parse JSONAPI Object from %s\n",
858                 term_data);
859     GNUNET_SCHEDULER_add_now (&do_error, handle);
860     return;
861   }
862   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
863   {
864     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
865                 "Cannot create more than 1 resource! (Got %d)\n",
866                 GNUNET_JSONAPI_document_resource_count (json_obj));
867     GNUNET_JSONAPI_document_delete (json_obj);
868     GNUNET_SCHEDULER_add_now (&do_error, handle);
869     return;
870   }
871   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
872   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
873                                                        GNUNET_REST_JSONAPI_IDENTITY_TICKET))
874   {
875     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
876                 "Unsupported JSON data type\n");
877     GNUNET_JSONAPI_document_delete (json_obj);
878     resp = GNUNET_REST_create_response (NULL);
879     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
880     cleanup_handle (handle);
881     return;
882   }
883   rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
884                                                 "rnd");
885   identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
886                                                      "identity");
887   audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
888                                                      "audience");
889   rnd_str = json_string_value (rnd_json);
890   identity_str = json_string_value (identity_json);
891   audience_str = json_string_value (audience_json);
892
893   GNUNET_STRINGS_string_to_data (rnd_str,
894                                  strlen (rnd_str),
895                                  &ticket.rnd,
896                                  sizeof (uint64_t));
897 //  GNUNET_STRINGS_string_to_data (identity_str,
898 //                                 strlen (identity_str),
899 //                                 &ticket.identity,type filter text
900 //                                 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
901   GNUNET_STRINGS_string_to_data (audience_str,
902                                  strlen (audience_str),
903                                  &ticket.audience,
904                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
905
906   for (ego_entry = handle->ego_head;
907        NULL != ego_entry;
908        ego_entry = ego_entry->next)
909   {
910     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
911                                         &tmp_pk);
912     if (0 == memcmp (&ticket.identity,
913                      &tmp_pk,
914                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
915       break;
916   }
917   if (NULL == ego_entry)
918   {
919     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
920                 "Identity unknown (%s)\n", identity_str);
921     GNUNET_JSONAPI_document_delete (json_obj);
922     return;
923   }
924   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
925
926   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
927   handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp,
928                                                            identity_priv,
929                                                            &ticket,
930                                                            &finished_cont,
931                                                            handle);
932   GNUNET_JSONAPI_document_delete (json_obj);
933 }
934
935 static void
936 consume_cont (void *cls,
937               const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
938               const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
939 {
940   struct RequestHandle *handle = cls;
941   struct GNUNET_JSONAPI_Resource *json_resource;
942   json_t *value;
943
944   if (NULL == identity)
945   {
946     GNUNET_SCHEDULER_add_now (&return_response, handle);
947     return;
948   }
949
950   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n",
951               attr->name);
952   json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE,
953                                                attr->name);
954   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
955
956   value = json_string (attr->data);
957   GNUNET_JSONAPI_resource_add_attr (json_resource,
958                                     "value",
959                                     value);
960   json_decref (value);
961 }
962
963 static void
964 consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle,
965                      const char* url,
966                      void *cls)
967 {
968   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv;
969   const char* identity_str;
970   const char* audience_str;
971   const char* rnd_str;
972
973   struct RequestHandle *handle = cls;
974   struct EgoEntry *ego_entry;
975   struct MHD_Response *resp;
976   struct GNUNET_IDENTITY_PROVIDER_Ticket ticket;
977   struct GNUNET_JSONAPI_Document *json_obj;
978   struct GNUNET_JSONAPI_Resource *json_res;
979   struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk;
980   char term_data[handle->rest_handle->data_size+1];
981   json_t *rnd_json;
982   json_t *identity_json;
983   json_t *audience_json;
984   json_t *data_json;
985   json_error_t err;
986   struct GNUNET_JSON_Specification docspec[] = {
987     GNUNET_JSON_spec_jsonapi_document (&json_obj),
988     GNUNET_JSON_spec_end()
989   };
990
991   if (0 >= handle->rest_handle->data_size)
992   {
993     GNUNET_SCHEDULER_add_now (&do_error, handle);
994     return;
995   }
996
997   term_data[handle->rest_handle->data_size] = '\0';
998   GNUNET_memcpy (term_data,
999                  handle->rest_handle->data,
1000                  handle->rest_handle->data_size);
1001   data_json = json_loads (term_data,
1002                           JSON_DECODE_ANY,
1003                           &err);
1004   GNUNET_assert (GNUNET_OK ==
1005                  GNUNET_JSON_parse (data_json, docspec,
1006                                     NULL, NULL));
1007   json_decref (data_json);
1008   if (NULL == json_obj)
1009   {
1010     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1011                 "Unable to parse JSONAPI Object from %s\n",
1012                 term_data);
1013     GNUNET_SCHEDULER_add_now (&do_error, handle);
1014     return;
1015   }
1016   if (1 != GNUNET_JSONAPI_document_resource_count (json_obj))
1017   {
1018     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1019                 "Cannot create more than 1 resource! (Got %d)\n",
1020                 GNUNET_JSONAPI_document_resource_count (json_obj));
1021     GNUNET_JSONAPI_document_delete (json_obj);
1022     GNUNET_SCHEDULER_add_now (&do_error, handle);
1023     return;
1024   }
1025   json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0);
1026   if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res,
1027                                                        GNUNET_REST_JSONAPI_IDENTITY_TICKET))
1028   {
1029     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1030                 "Unsupported JSON data type\n");
1031     GNUNET_JSONAPI_document_delete (json_obj);
1032     resp = GNUNET_REST_create_response (NULL);
1033     handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT);
1034     cleanup_handle (handle);
1035     return;
1036   }
1037   rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1038                                                 "rnd");
1039   identity_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1040                                                      "identity");
1041   audience_json = GNUNET_JSONAPI_resource_read_attr (json_res,
1042                                                      "audience");
1043   rnd_str = json_string_value (rnd_json);
1044   identity_str = json_string_value (identity_json);
1045   audience_str = json_string_value (audience_json);
1046
1047   GNUNET_STRINGS_string_to_data (rnd_str,
1048                                  strlen (rnd_str),
1049                                  &ticket.rnd,
1050                                  sizeof (uint64_t));
1051   GNUNET_STRINGS_string_to_data (identity_str,
1052                                  strlen (identity_str),
1053                                  &ticket.identity,
1054                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1055   GNUNET_STRINGS_string_to_data (audience_str,
1056                                  strlen (audience_str),
1057                                  &ticket.audience,
1058                                  sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1059
1060   for (ego_entry = handle->ego_head;
1061        NULL != ego_entry;
1062        ego_entry = ego_entry->next)
1063   {
1064     GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
1065                                         &tmp_pk);
1066     if (0 == memcmp (&ticket.audience,
1067                      &tmp_pk,
1068                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1069       break;
1070   }
1071   if (NULL == ego_entry)
1072   {
1073     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1074                 "Identity unknown (%s)\n", identity_str);
1075     GNUNET_JSONAPI_document_delete (json_obj);
1076     return;
1077   }
1078   identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1079   handle->resp_object = GNUNET_JSONAPI_document_new ();
1080   handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
1081   handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp,
1082                                                             identity_priv,
1083                                                             &ticket,
1084                                                             &consume_cont,
1085                                                             handle);
1086   GNUNET_JSONAPI_document_delete (json_obj);
1087 }
1088
1089
1090
1091 /**
1092  * Respond to OPTIONS request
1093  *
1094  * @param con_handle the connection handle
1095  * @param url the url
1096  * @param cls the RequestHandle
1097  */
1098 static void
1099 options_cont (struct GNUNET_REST_RequestHandle *con_handle,
1100               const char* url,
1101               void *cls)
1102 {
1103   struct MHD_Response *resp;
1104   struct RequestHandle *handle = cls;
1105
1106   //For now, independent of path return all options
1107   resp = GNUNET_REST_create_response (NULL);
1108   MHD_add_response_header (resp,
1109                            "Access-Control-Allow-Methods",
1110                            allow_methods);
1111   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1112   cleanup_handle (handle);
1113   return;
1114 }
1115
1116 /**
1117  * Respond to OPTIONS request
1118  *
1119  * @param con_handle the connection handle
1120  * @param url the url
1121  * @param cls the RequestHandle
1122  */
1123 static void
1124 authorize_cont (struct GNUNET_REST_RequestHandle *con_handle,
1125                 const char* url,
1126                 void *cls)
1127 {
1128   struct MHD_Response *resp;
1129   struct RequestHandle *handle = cls;
1130   char *response_type, *client_id, *scope, *redirect_uri, *state = 0,
1131       *nonce = 0;
1132   struct timeval now, login_time;
1133   OIDC_authorized_identities  = GNUNET_CONTAINER_multihashmap_create( 10, GNUNET_NO );
1134   char *login_base_url, *new_redirect;
1135   struct GNUNET_HashCode cache_key;
1136
1137   //TODO clean up method
1138
1139   /**   The Authorization Server MUST validate all the OAuth 2.0 parameters
1140    *    according to the OAuth 2.0 specification.
1141    */
1142   /**
1143    *    If the sub (subject) Claim is requested with a specific value for the
1144    *    ID Token, the Authorization Server MUST only send a positive response
1145    *    if the End-User identified by that sub value has an active session with
1146    *    the Authorization Server or has been Authenticated as a result of the
1147    *    request. The Authorization Server MUST NOT reply with an ID Token or
1148    *    Access Token for a different user, even if they have an active session
1149    *    with the Authorization Server. Such a request can be made either using
1150    *    an id_token_hint parameter or by requesting a specific Claim Value as
1151    *    described in Section 5.5.1, if the claims parameter is supported by
1152    *    the implementation.
1153    */
1154
1155
1156
1157   // REQUIRED value: client_id
1158   GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
1159                       &cache_key);
1160   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1161                                                            &cache_key))
1162   {
1163     handle->emsg=GNUNET_strdup("invalid_request");
1164     handle->edesc=GNUNET_strdup("Missing parameter: client_id");
1165     GNUNET_SCHEDULER_add_now (&do_error, handle);
1166     return;
1167   }
1168   client_id = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1169                                                 &cache_key);
1170
1171   // Checks if client_id is valid:
1172   // TODO change check (lookup trusted public_key?)
1173 //  if( strcmp( client_id, "localhost" ) != 0 )
1174 //  {
1175 //    handle->emsg=GNUNET_strdup("unauthorized_client");
1176 //    handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1177 //    GNUNET_SCHEDULER_add_now (&do_error, handle);
1178 //    return;
1179 //  }
1180
1181   // REQUIRED value: redirect_uri
1182   GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
1183                       &cache_key);
1184   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1185                                                            &cache_key))
1186   {
1187     handle->emsg=GNUNET_strdup("invalid_request");
1188     handle->edesc=GNUNET_strdup("Missing parameter: redirect_uri");
1189     GNUNET_SCHEDULER_add_now (&do_error, handle);
1190     return;
1191   }
1192   redirect_uri = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1193                                                 &cache_key);
1194
1195   // Checks if redirect_uri is valid:
1196   // TODO change check (check client_id->public key == address)
1197 //  if( strcmp( redirect_uri, "https://localhost:8000" ) != 0 )
1198 //  {
1199 //    handle->emsg=GNUNET_strdup("invalid_request");
1200 //    handle->edesc=GNUNET_strdup("Invalid or mismatching redirect_uri");
1201 //    GNUNET_SCHEDULER_add_now (&do_error, handle);
1202 //    return;
1203 //  }
1204   handle->eredirect = GNUNET_strdup(redirect_uri);
1205
1206   // REQUIRED value: response_type
1207   GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
1208                       &cache_key);
1209   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1210                                                            &cache_key))
1211   {
1212     handle->emsg=GNUNET_strdup("invalid_request");
1213     handle->edesc=GNUNET_strdup("Missing parameter: response_type");
1214     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1215     return;
1216   }
1217   response_type = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1218                                                     &cache_key);
1219
1220   // REQUIRED value: scope
1221   GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
1222   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1223                                                            &cache_key))
1224   {
1225     handle->emsg=GNUNET_strdup("invalid_request");
1226     handle->edesc=GNUNET_strdup("Missing parameter: scope");
1227     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1228     return;
1229   }
1230   scope = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1231                                             &cache_key);
1232
1233   //RECOMMENDED value: state
1234   GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
1235   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1236                                                            &cache_key))
1237   {
1238     state = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1239                                               &cache_key);
1240   }
1241
1242   //OPTIONAL value: nonce
1243   GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
1244   if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map,
1245                                                            &cache_key))
1246   {
1247     nonce = GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
1248                                               &cache_key);
1249   }
1250
1251   int number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
1252   int iterator;
1253   for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
1254   {
1255     GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
1256                         strlen(OIDC_ignored_parameter_array[iterator]),
1257                         &cache_key);
1258     if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
1259                                                             &cache_key))
1260     {
1261       handle->emsg=GNUNET_strdup("access_denied");
1262       //TODO rewrite error description
1263       handle->edesc=GNUNET_strdup("Server will not handle parameter");
1264       GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1265       return;
1266     }
1267   }
1268
1269   // Checks if response_type is 'code'
1270   if( strcmp( response_type, OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) != 0 )
1271   {
1272     handle->emsg=GNUNET_strdup("unsupported_response_type");
1273     handle->edesc=GNUNET_strdup("The authorization server does not support "
1274                                 "obtaining this authorization code.");
1275     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1276     return;
1277   }
1278   // Checks if scope contains 'openid'
1279   if( strstr( scope, OIDC_EXPECTED_AUTHORIZATION_SCOPE ) == NULL )
1280   {
1281     handle->emsg=GNUNET_strdup("invalid_scope");
1282     handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
1283                                 "malformed.");
1284     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
1285     return;
1286   }
1287
1288
1289   //TODO check other values and use them accordingly
1290
1291
1292
1293
1294   //if header-authorization == ID
1295     //if ID is still logged
1296       // ego get Public Key of Identity
1297       // return token with public key?
1298   // save request
1299
1300   GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
1301                       strlen (OIDC_AUTHORIZATION_HEADER_KEY),
1302                       &cache_key);
1303   //No Authorization Parameter -> redirect to login
1304   if(GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(con_handle->header_param_map,
1305                                                           &cache_key))
1306   {
1307     if ( GNUNET_OK
1308         == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
1309                                                   "address", &login_base_url) )
1310     {
1311       GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
1312                        login_base_url,
1313                        OIDC_RESPONSE_TYPE_KEY,
1314                        response_type,
1315                        OIDC_CLIENT_ID_KEY,
1316                        client_id,
1317                        OIDC_REDIRECT_URI_KEY,
1318                        redirect_uri,
1319                        OIDC_SCOPE_KEY,
1320                        scope,
1321                        OIDC_STATE_KEY,
1322                        (state) ? state : "",
1323                        OIDC_NONCE_KEY,
1324                        (nonce) ? nonce : "");
1325       resp = GNUNET_REST_create_response ("");
1326       MHD_add_response_header (resp, "Location", new_redirect);
1327     }
1328     else
1329     {
1330       handle->emsg = GNUNET_strdup("No server configuration");
1331       handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1332       GNUNET_SCHEDULER_add_now (&do_error, handle);
1333       return;
1334     }
1335     handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1336     cleanup_handle (handle);
1337     GNUNET_free(new_redirect);
1338     return;
1339   }
1340   else
1341   {
1342     char* identity = GNUNET_CONTAINER_multihashmap_get ( con_handle->header_param_map,
1343                                                          &cache_key);
1344     GNUNET_CRYPTO_hash (identity, strlen (identity), &cache_key);
1345     if(GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(OIDC_authorized_identities,
1346                                                            &cache_key))
1347     {
1348       login_time = *(struct timeval *)GNUNET_CONTAINER_multihashmap_get(OIDC_authorized_identities,
1349                                                                     &cache_key);
1350       gettimeofday(&now, NULL);
1351       //After 30 minutes redirect to login
1352       if( now.tv_sec - login_time.tv_sec >= 1800)
1353       {
1354         //TODO remove redundancy [redirect to login]
1355         if ( GNUNET_OK
1356             == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
1357                                                       "address", &login_base_url) )
1358         {
1359           GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
1360                            login_base_url,
1361                            OIDC_RESPONSE_TYPE_KEY,
1362                            response_type,
1363                            OIDC_CLIENT_ID_KEY,
1364                            client_id,
1365                            OIDC_REDIRECT_URI_KEY,
1366                            redirect_uri,
1367                            OIDC_SCOPE_KEY,
1368                            scope,
1369                            OIDC_STATE_KEY,
1370                            (state) ? state : "",
1371                            OIDC_NONCE_KEY,
1372                            (nonce) ? nonce : "");
1373           resp = GNUNET_REST_create_response ("");
1374           MHD_add_response_header (resp, "Location", new_redirect);
1375         }
1376         else
1377         {
1378           handle->emsg = GNUNET_strdup("No server configuration");
1379           handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
1380           GNUNET_SCHEDULER_add_now (&do_error, handle);
1381           return;
1382         }
1383         handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1384         cleanup_handle (handle);
1385         GNUNET_free(new_redirect);
1386         return;
1387       }
1388     }
1389     else
1390     {
1391       gettimeofday( &now, NULL );
1392       GNUNET_CONTAINER_multihashmap_put( OIDC_authorized_identities, &cache_key, &now,
1393                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1394     }
1395     resp = GNUNET_REST_create_response ("");
1396 //    MHD_add_response_header (resp, "Access-Control-Allow-Origin", "*");
1397     MHD_add_response_header (resp, "Location", redirect_uri);
1398     handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
1399     cleanup_handle (handle);
1400     return;
1401   }
1402 }
1403
1404
1405 /**
1406  * Respond to LOGIN request
1407  *
1408  * @param con_handle the connection handle
1409  * @param url the url
1410  * @param cls the RequestHandle
1411  */
1412 static void
1413 login_cont (struct GNUNET_REST_RequestHandle *con_handle,
1414                 const char* url,
1415                 void *cls)
1416 {
1417   struct MHD_Response *resp = GNUNET_REST_create_response ("");
1418   struct RequestHandle *handle = cls;
1419   char* cookie;
1420   json_t *root;
1421   json_error_t error;
1422   json_t *identity;
1423   root = json_loads( handle->rest_handle->data, 0, &error );
1424   identity = json_object_get(root, "identity");
1425   if(json_is_string(identity))
1426   {
1427     GNUNET_asprintf(&cookie,"Identity=%s",json_string_value(identity));
1428     MHD_add_response_header (resp, "Set-Cookie", cookie);
1429     handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
1430   }
1431   else
1432   {
1433     handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
1434   }
1435   json_decref(root);
1436   cleanup_handle (handle);
1437   GNUNET_free(cookie);
1438   return;
1439 }
1440
1441 /**
1442  * Handle rest request
1443  *
1444  * @param handle the request handle
1445  */
1446 static void
1447 init_cont (struct RequestHandle *handle)
1448 {
1449   struct GNUNET_REST_RequestHandlerError err;
1450   static const struct GNUNET_REST_RequestHandler handlers[] = {
1451     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont},
1452     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont},
1453     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont},
1454     {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_cont},
1455     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
1456     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_cont},
1457     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont},
1458     {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont},
1459     {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
1460       &options_cont},
1461     GNUNET_REST_HANDLER_END
1462   };
1463
1464   if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
1465                                                handlers,
1466                                                &err,
1467                                                handle))
1468   {
1469     handle->response_code = err.error_code;
1470     GNUNET_SCHEDULER_add_now (&do_error, handle);
1471   }
1472 }
1473
1474 /**
1475  * If listing is enabled, prints information about the egos.
1476  *
1477  * This function is initially called for all egos and then again
1478  * whenever a ego's identifier changes or if it is deleted.  At the
1479  * end of the initial pass over all egos, the function is once called
1480  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
1481  * be invoked in the future or that there was an error.
1482  *
1483  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
1484  * this function is only called ONCE, and 'NULL' being passed in
1485  * 'ego' does indicate an error (i.e. name is taken or no default
1486  * value is known).  If 'ego' is non-NULL and if '*ctx'
1487  * is set in those callbacks, the value WILL be passed to a subsequent
1488  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
1489  * that one was not NULL).
1490  *
1491  * When an identity is renamed, this function is called with the
1492  * (known) ego but the NEW identifier.
1493  *
1494  * When an identity is deleted, this function is called with the
1495  * (known) ego and "NULL" for the 'identifier'.  In this case,
1496  * the 'ego' is henceforth invalid (and the 'ctx' should also be
1497  * cleaned up).
1498  *
1499  * @param cls closure
1500  * @param ego ego handle
1501  * @param ctx context for application to store data for this ego
1502  *                 (during the lifetime of this process, initially NULL)
1503  * @param identifier identifier assigned by the user for this ego,
1504  *                   NULL if the user just deleted the ego and it
1505  *                   must thus no longer be used
1506  */
1507 static void
1508 list_ego (void *cls,
1509           struct GNUNET_IDENTITY_Ego *ego,
1510           void **ctx,
1511           const char *identifier)
1512 {
1513   struct RequestHandle *handle = cls;
1514   struct EgoEntry *ego_entry;
1515   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
1516
1517   if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
1518   {
1519     handle->state = ID_REST_STATE_POST_INIT;
1520     init_cont (handle);
1521     return;
1522   }
1523   if (ID_REST_STATE_INIT == handle->state) {
1524     ego_entry = GNUNET_new (struct EgoEntry);
1525     GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1526     ego_entry->keystring =
1527       GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
1528     ego_entry->ego = ego;
1529     ego_entry->identifier = GNUNET_strdup (identifier);
1530     GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, ego_entry);
1531   }
1532
1533 }
1534
1535 /**
1536  * Function processing the REST call
1537  *
1538  * @param method HTTP method
1539  * @param url URL of the HTTP request
1540  * @param data body of the HTTP request (optional)
1541  * @param data_size length of the body
1542  * @param proc callback function for the result
1543  * @param proc_cls closure for callback function
1544  * @return GNUNET_OK if request accepted
1545  */
1546 static void
1547 rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
1548                               GNUNET_REST_ResultProcessor proc,
1549                               void *proc_cls)
1550 {
1551   struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
1552
1553   handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1554   handle->proc_cls = proc_cls;
1555   handle->proc = proc;
1556   handle->state = ID_REST_STATE_INIT;
1557   handle->rest_handle = rest_handle;
1558
1559   handle->url = GNUNET_strdup (rest_handle->url);
1560   if (handle->url[strlen (handle->url)-1] == '/')
1561     handle->url[strlen (handle->url)-1] = '\0';
1562   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1563               "Connecting...\n");
1564   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
1565                                                      &list_ego,
1566                                                      handle);
1567   handle->timeout_task =
1568     GNUNET_SCHEDULER_add_delayed (handle->timeout,
1569                                   &do_timeout,
1570                                   handle);
1571   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1572               "Connected\n");
1573 }
1574
1575 /**
1576  * Entry point for the plugin.
1577  *
1578  * @param cls Config info
1579  * @return NULL on error, otherwise the plugin context
1580  */
1581 void *
1582 libgnunet_plugin_rest_identity_provider_init (void *cls)
1583 {
1584   static struct Plugin plugin;
1585   struct GNUNET_REST_Plugin *api;
1586
1587   cfg = cls;
1588   if (NULL != plugin.cfg)
1589     return NULL;                /* can only initialize once! */
1590   memset (&plugin, 0, sizeof (struct Plugin));
1591   plugin.cfg = cfg;
1592   api = GNUNET_new (struct GNUNET_REST_Plugin);
1593   api->cls = &plugin;
1594   api->name = GNUNET_REST_API_NS_IDENTITY_PROVIDER;
1595   api->process_request = &rest_identity_process_request;
1596   GNUNET_asprintf (&allow_methods,
1597                    "%s, %s, %s, %s, %s",
1598                    MHD_HTTP_METHOD_GET,
1599                    MHD_HTTP_METHOD_POST,
1600                    MHD_HTTP_METHOD_PUT,
1601                    MHD_HTTP_METHOD_DELETE,
1602                    MHD_HTTP_METHOD_OPTIONS);
1603
1604   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1605               _("Identity Provider REST API initialized\n"));
1606   return api;
1607 }
1608
1609
1610 /**
1611  * Exit point from the plugin.
1612  *
1613  * @param cls the plugin context (as returned by "init")
1614  * @return always NULL
1615  */
1616 void *
1617 libgnunet_plugin_rest_identity_provider_done (void *cls)
1618 {
1619   struct GNUNET_REST_Plugin *api = cls;
1620   struct Plugin *plugin = api->cls;
1621
1622   plugin->cfg = NULL;
1623   GNUNET_free_non_null (allow_methods);
1624   GNUNET_free (api);
1625   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1626               "Identity Provider REST plugin is finished\n");
1627   return NULL;
1628 }
1629
1630 /* end of plugin_rest_identity_provider.c */