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