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