gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [gnunet] branch master updated (d4ad64d79 -> 82e4a63b4)


From: gnunet
Subject: [GNUnet-SVN] [gnunet] branch master updated (d4ad64d79 -> 82e4a63b4)
Date: Sun, 25 Feb 2018 16:25:04 +0100

This is an automated email from the git hooks/post-receive script.

martin-schanzenbach pushed a change to branch master
in repository gnunet.

    from d4ad64d79 couple of markups in developer chap.
     new 514dd6f53 -start oidc
     new d4b252fd7 Merge branch 'identity_abe' into identity_oidc
     new e4a65af29 Merge branch 'identity_abe' into identity_oidc
     new c68eae71c -commit broken
     new 28e046cf5 Merge branch 'identity_abe' into identity_oidc
     new 5126e9d42 Merge remote-tracking branch 'origin/identity_abe' into 
identity_oidc
     new cd0ff1852 Merge branch 'identity_oidc' of 
git-int.aisec.fraunhofer.de:sas/gnunet-mirror into identity_oidc
     new 089a4f09b --commit still broken
     new ecfab268b Merge branch 'identity_oidc' of 
git-int.aisec.fraunhofer.de:sas/gnunet-mirror into identity_oidc
     new 68978a08e Refactored file
     new 3fdb794b6 -merge
     new 5da3c7cf7 -add header map to rest handle
     new 5cefcd299 -fix
     new c78175649 -minor
     new c92893e0b -fixed nonce=(null)
     new 508784b4a -merge
     new a89f95db7 -commit header parse work in progress
     new c75b7de71 -merge branch 'identity_oidc' of 
git-int.aisec.fraunhofer.de:sas/gnunet-mirror into identity_oidc
     new e87ca099f -merge branch 'identity_oidc' of 
git-int.aisec.fraunhofer.de:sas/gnunet-mirror into identity_oidc
     new a38dbfc3c -add login and login timeout
     new 2e810e7d8 -merge
     new 3428214e4 -add todos; cleanup
     new 9f5ea1f7f -fix login time
     new f2d31fb82 Merge remote-tracking branch 'origin/master' into 
identity_oidc
     new f0a84723f -wip post authentication
     new afb2171eb -wip post request testing required and namestore handle fix 
required
     new 60c963315 Merge remote-tracking branch 'gnunet/master' into 
identity_oidc
     new 762463674 -wip client_id check
     new 595319b96 -wip attribute collection
     new cbe68f524 -fix get request without authorization code
     new a49f0792a -fix GET login finished
     new c2077b1c8 -fix GET request
     new ca115cc36 -fix get and post authorization request
     new 5cc1e5ae9 -wip token request
     new a67bd3630 -merge branch 'master' into identity_oidc
     new 963b0f5a7 -wip token request
     new 8c785ca6c Merge branch 'master' into identity_oidc
     new 1b7c41ecb -fix unsafed file
     new 99f500a20 -Merge branch 'master' into identity_oidc
     new 3f5460f21 -wip token endpoint
     new ddbd4e85b -changes for using token endpoint & added token endpoint
     new 0166171bb -wip token endpoint fix
     new faf1fef1e -wip token endpoint refactor
     new bbe8e9a4e -wip UserInfo Endpoint
     new 82e4a63b4 -fix

The 45 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/identity-attribute/identity_attribute.c        |   28 +
 src/identity-provider/jwt.c                        |   33 +-
 src/identity-provider/jwt.h                        |    9 +
 .../plugin_rest_identity_provider.c                | 1709 ++++++++++++++++++--
 src/identity-provider/test_idp.conf                |    7 +-
 src/include/gnunet_identity_attribute_lib.h        |    6 +
 src/include/gnunet_rest_lib.h                      |   23 +
 src/rest/gnunet-rest-server.c                      |   17 +-
 src/rest/rest.conf                                 |    2 +-
 9 files changed, 1722 insertions(+), 112 deletions(-)
 create mode 100644 src/identity-provider/jwt.h

diff --git a/src/identity-attribute/identity_attribute.c 
b/src/identity-attribute/identity_attribute.c
index cf50d058e..0111668fe 100644
--- a/src/identity-attribute/identity_attribute.c
+++ b/src/identity-attribute/identity_attribute.c
@@ -240,6 +240,34 @@ GNUNET_IDENTITY_ATTRIBUTE_claim_new (const char* attr_name,
   return attr;
 }
 
+/**
+ * Add a new claim list entry.
+ *
+ * @param claim_list the attribute name
+ * @param attr_name the attribute name
+ * @param type the attribute type
+ * @param data the attribute value
+ * @param data_size the attribute value size
+ * @return
+ */
+void
+GNUNET_IDENTITY_ATTRIBUTE_list_add (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList 
*claim_list,
+                                   const char* attr_name,
+                                   uint32_t type,
+                                   const void* data,
+                                   size_t data_size)
+{
+  struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
+  le = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry);
+  le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr_name,
+                                              type,
+                                              data,
+                                              data_size);
+  GNUNET_CONTAINER_DLL_insert (claim_list->list_head,
+                              claim_list->list_tail,
+                              le);
+}
+
 size_t
 GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (const struct 
GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs)
 {
diff --git a/src/identity-provider/jwt.c b/src/identity-provider/jwt.c
index 2f1e3240b..ff3676cb6 100644
--- a/src/identity-provider/jwt.c
+++ b/src/identity-provider/jwt.c
@@ -33,12 +33,15 @@
 #define JWT_ALG "alg"
 
 /*TODO is this the correct way to define new algs? */
-#define JWT_ALG_VALUE "ED512"
+#define JWT_ALG_VALUE "urn:org:gnunet:jwt:alg:ecdsa:ed25519"
 
 #define JWT_TYP "typ"
 
 #define JWT_TYP_VALUE "jwt"
 
+//TODO change server address
+#define SERVER_ADDRESS "https://localhost";
+
 static char*
 create_jwt_header(void)
 {
@@ -57,22 +60,22 @@ create_jwt_header(void)
 /**
  * Create a JWT from attributes
  *
- * @param sub_key the public of the subject
+ * @param aud_key the public of the subject
  * @param attrs the attribute list
  * @param priv_key the key used to sign the JWT
  * @return a new base64-encoded JWT string.
  */
 char*
-jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key,
+jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
                                                 const struct 
GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs,
                                                 const struct 
GNUNET_CRYPTO_EcdsaPrivateKey *priv_key)
 {
   struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
-  struct GNUNET_CRYPTO_EcdsaPublicKey iss_key;
+  struct GNUNET_CRYPTO_EcdsaPublicKey sub_key;
   struct GNUNET_CRYPTO_EcdsaSignature signature;
   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
   char* audience;
-  char* issuer;
+  char* subject;
   char* header;
   char* padding;
   char* body_str;
@@ -84,20 +87,28 @@ jwt_create_from_list (const struct 
GNUNET_CRYPTO_EcdsaPublicKey *sub_key,
   char* attr_val_str;
   json_t* body;
 
-  GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &iss_key);
+  //exp REQUIRED time expired from config
+  //iat REQUIRED time now
+  //auth_time only if max_age
+  //nonce only if nonce
+  // OPTIONAL acr,amr,azp
+  GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &sub_key);
   /* TODO maybe we should use a local identity here */
-  issuer = GNUNET_STRINGS_data_to_string_alloc (&iss_key,
+  subject = GNUNET_STRINGS_data_to_string_alloc (&sub_key,
                                                 sizeof (struct 
GNUNET_CRYPTO_EcdsaPublicKey));
-  audience = GNUNET_STRINGS_data_to_string_alloc (sub_key,
+  audience = GNUNET_STRINGS_data_to_string_alloc (aud_key,
                                                   sizeof (struct 
GNUNET_CRYPTO_EcdsaPublicKey));
   header = create_jwt_header ();
   body = json_object ();
   /* TODO who is the issuer? local IdP or subject ? See self-issued tokens? */
+  //iss REQUIRED case sensitive server uri with https
   json_object_set_new (body,
-                       "iss", json_string (issuer));
+                       "iss", json_string (SERVER_ADDRESS));
+  //sub REQUIRED public key identity, not exceed 255 ASCII  length
   json_object_set_new (body,
-                       "sub", json_string (issuer));
+                       "sub", json_string (subject));
   /* TODO what should be in here exactly? */
+  //aud REQUIRED public key client_id must be there
   json_object_set_new (body,
                        "aud", json_string (audience));
   for (le = attrs->list_head; NULL != le; le = le->next)
@@ -135,7 +146,7 @@ jwt_create_from_list (const struct 
GNUNET_CRYPTO_EcdsaPublicKey *sub_key,
   while (NULL != padding)
     padding = strtok(NULL, "=");
 
-  GNUNET_free (issuer);
+  GNUNET_free (subject);
   GNUNET_free (audience);
 
   /**
diff --git a/src/identity-provider/jwt.h b/src/identity-provider/jwt.h
new file mode 100644
index 000000000..072958973
--- /dev/null
+++ b/src/identity-provider/jwt.h
@@ -0,0 +1,9 @@
+#ifndef JWT_H
+#define JWT_H
+
+char*
+jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key,
+                                                const struct 
GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs,
+                                                const struct 
GNUNET_CRYPTO_EcdsaPrivateKey *priv_key);
+
+#endif
diff --git a/src/identity-provider/plugin_rest_identity_provider.c 
b/src/identity-provider/plugin_rest_identity_provider.c
index 6eb856435..033c6e4ba 100644
--- a/src/identity-provider/plugin_rest_identity_provider.c
+++ b/src/identity-provider/plugin_rest_identity_provider.c
@@ -39,6 +39,7 @@
 #include "gnunet_signatures.h"
 #include "gnunet_identity_attribute_lib.h"
 #include "gnunet_identity_provider_service.h"
+#include "jwt.h"
 
 /**
  * REST root namespace
@@ -66,6 +67,26 @@
 #define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume"
 
 /**
+ * Authorize endpoint
+ */
+#define GNUNET_REST_API_NS_AUTHORIZE "/idp/authorize"
+
+/**
+ * Token endpoint
+ */
+#define GNUNET_REST_API_NS_TOKEN "/idp/token"
+
+/**
+ * UserInfo endpoint
+ */
+#define GNUNET_REST_API_NS_USERINFO "/idp/userinfo"
+
+/**
+ * Login namespace
+ */
+#define GNUNET_REST_API_NS_LOGIN "/idp/login"
+
+/**
  * Attribute key
  */
 #define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute"
@@ -91,6 +112,110 @@
  */
 #define ID_REST_STATE_POST_INIT 1
 
+/**
+ * OIDC grant_type key
+ */
+#define OIDC_GRANT_TYPE_KEY "grant_type"
+
+/**
+ * OIDC grant_type key
+ */
+#define OIDC_GRANT_TYPE_VALUE "authorization_code"
+
+/**
+ * OIDC code key
+ */
+#define OIDC_CODE_KEY "code"
+
+/**
+ * OIDC response_type key
+ */
+#define OIDC_RESPONSE_TYPE_KEY "response_type"
+
+/**
+ * OIDC client_id key
+ */
+#define OIDC_CLIENT_ID_KEY "client_id"
+
+/**
+ * OIDC scope key
+ */
+#define OIDC_SCOPE_KEY "scope"
+
+/**
+ * OIDC redirect_uri key
+ */
+#define OIDC_REDIRECT_URI_KEY "redirect_uri"
+
+/**
+ * OIDC state key
+ */
+#define OIDC_STATE_KEY "state"
+
+/**
+ * OIDC nonce key
+ */
+#define OIDC_NONCE_KEY "nonce"
+
+/**
+ * OIDC cookie header key
+ */
+#define OIDC_COOKIE_HEADER_KEY "Cookie"
+
+/**
+ * OIDC cookie header information key
+ */
+#define OIDC_AUTHORIZATION_HEADER_KEY "Authorization"
+
+/**
+ * OIDC cookie header information key
+ */
+#define OIDC_COOKIE_HEADER_INFORMATION_KEY "Identity="
+
+/**
+ * OIDC expected response_type while authorizing
+ */
+#define OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE "code"
+
+/**
+ * OIDC expected scope part while authorizing
+ */
+#define OIDC_EXPECTED_AUTHORIZATION_SCOPE "openid"
+
+/**
+ * OIDC ignored parameter array
+ */
+char* OIDC_ignored_parameter_array [] =
+{
+  "display",
+  "prompt",
+  "max_age",
+  "ui_locales", 
+  "response_mode",
+  "id_token_hint",
+  "login_hint", 
+  "acr_values"
+};
+
+/**
+ * OIDC authorized identities and times hashmap
+ */
+struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_login_time;
+
+/**
+ * OIDC authorized identities and times hashmap
+ */
+struct GNUNET_CONTAINER_MultiHashMap *OIDC_identity_grants;
+
+/**
+ * OIDC ticket/code use only once
+ */
+struct GNUNET_CONTAINER_MultiHashMap *OIDC_ticket_once;
+
+/**
+ * OIDC access_token to ticket and ego
+ */
+struct GNUNET_CONTAINER_MultiHashMap *OIDC_interpret_access_token;
 
 /**
  * The configuration handle
@@ -109,6 +234,33 @@ struct Plugin
 {
   const struct GNUNET_CONFIGURATION_Handle *cfg;
 };
+/**
+ * OIDC needed variables
+ */
+struct OIDC_Variables
+{
+
+  struct GNUNET_CRYPTO_EcdsaPublicKey client_pkey;
+
+  char *client_id;
+
+  int is_client_trusted;
+
+  char *redirect_uri;
+
+  char *scope;
+
+  char *state;
+
+  char *nonce;
+
+  char *response_type;
+
+  char *login_identity;
+
+  json_t *response;
+
+};
 
 /**
  * The ego list
@@ -160,9 +312,14 @@ struct RequestHandle
   struct EgoEntry *ego_entry;
 
   /**
-   * Ptr to current ego private key
+   * Pointer to ego private key
    */
-  const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
+  struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key;
+
+  /**
+   * OIDC variables
+   */
+  struct OIDC_Variables *oidc;
 
   /**
    * The processing state
@@ -179,6 +336,20 @@ struct RequestHandle
    */
   struct GNUNET_REST_RequestHandle *rest_handle;
 
+  /**
+   * Handle to NAMESTORE
+   */
+  struct GNUNET_NAMESTORE_Handle *namestore_handle;
+
+  /**
+   * Iterator for NAMESTORE
+   */
+  struct GNUNET_NAMESTORE_ZoneIterator *namestore_handle_it;
+
+  /**
+   * Attribute claim list
+   */
+  struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list;
 
   /**
    * IDENTITY Operation
@@ -236,6 +407,11 @@ struct RequestHandle
   char *emsg;
 
   /**
+   * Error response description
+   */
+  char *edesc;
+
+  /**
    * Reponse code
    */
   int response_code;
@@ -247,8 +423,6 @@ struct RequestHandle
 
 };
 
-
-
 /**
  * Cleanup lookup handle
  * @param handle Handle to clean up
@@ -256,6 +430,8 @@ struct RequestHandle
 static void
 cleanup_handle (struct RequestHandle *handle)
 {
+  struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_entry;
+  struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *claim_tmp;
   struct EgoEntry *ego_entry;
   struct EgoEntry *ego_tmp;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -276,6 +452,42 @@ cleanup_handle (struct RequestHandle *handle)
     GNUNET_free (handle->url);
   if (NULL != handle->emsg)
     GNUNET_free (handle->emsg);
+  if (NULL != handle->edesc)
+    GNUNET_free (handle->edesc);
+  if (NULL != handle->namestore_handle)
+    GNUNET_NAMESTORE_disconnect (handle->namestore_handle);
+  if (NULL != handle->oidc)
+  {
+    if (NULL != handle->oidc->client_id)
+      GNUNET_free(handle->oidc->client_id);
+    if (NULL != handle->oidc->login_identity)
+      GNUNET_free(handle->oidc->login_identity);
+    if (NULL != handle->oidc->nonce)
+      GNUNET_free(handle->oidc->nonce);
+    if (NULL != handle->oidc->redirect_uri)
+      GNUNET_free(handle->oidc->redirect_uri);
+    if (NULL != handle->oidc->response_type)
+      GNUNET_free(handle->oidc->response_type);
+    if (NULL != handle->oidc->scope)
+      GNUNET_free(handle->oidc->scope);
+    if (NULL != handle->oidc->state)
+      GNUNET_free(handle->oidc->state);
+    if (NULL != handle->oidc->response)
+      json_decref(handle->oidc->response);
+    GNUNET_free(handle->oidc);
+  }
+  if ( NULL != handle->attr_list )
+  {
+    for (claim_entry = handle->attr_list->list_head;
+    NULL != claim_entry;)
+    {
+      claim_tmp = claim_entry;
+      claim_entry = claim_entry->next;
+      GNUNET_free(claim_tmp->claim);
+      GNUNET_free(claim_tmp);
+    }
+    GNUNET_free (handle->attr_list);
+  }
   for (ego_entry = handle->ego_head;
        NULL != ego_entry;)
   {
@@ -285,6 +497,10 @@ cleanup_handle (struct RequestHandle *handle)
     GNUNET_free (ego_tmp->keystring);
     GNUNET_free (ego_tmp);
   }
+  if (NULL != handle->attr_it)
+  {
+    GNUNET_free(handle->attr_it);
+  }
   GNUNET_free (handle);
 }
 
@@ -307,15 +523,74 @@ do_error (void *cls)
   struct MHD_Response *resp;
   char *json_error;
 
-  GNUNET_asprintf (&json_error,
-                   "{Error while processing request: %s}",
-                   handle->emsg);
+  GNUNET_asprintf (&json_error, "{ \"error\" : \"%s\", \"error_description\" : 
\"%s\"%s%s%s}",
+                  handle->emsg,
+                  (NULL != handle->edesc) ? handle->edesc : "",
+                  (NULL != handle->oidc->state) ? ", \"state\":\"" : "",
+                  (NULL != handle->oidc->state) ? handle->oidc->state : "",
+                  (NULL != handle->oidc->state) ? "\"" : "");
+  if ( 0 == handle->response_code )
+  {
+    handle->response_code = MHD_HTTP_BAD_REQUEST;
+  }
   resp = GNUNET_REST_create_response (json_error);
+  if (MHD_HTTP_UNAUTHORIZED == handle->response_code)
+  {
+    MHD_add_response_header(resp, "WWW-Authenticate", "Basic");
+  }
+  MHD_add_response_header (resp, "Content-Type", "application/json");
   handle->proc (handle->proc_cls, resp, handle->response_code);
-  cleanup_handle (handle);
+  GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
   GNUNET_free (json_error);
 }
 
+
+/**
+ * Task run on error, sends error message.  Cleans up everything.
+ *
+ * @param cls the `struct RequestHandle`
+ */
+static void
+do_userinfo_error (void *cls)
+{
+  struct RequestHandle *handle = cls;
+  struct MHD_Response *resp;
+  char *error;
+
+  GNUNET_asprintf (&error, "error=\"%s\", error_description=\"%s\"",
+                  handle->emsg,
+                  (NULL != handle->edesc) ? handle->edesc : "");
+  resp = GNUNET_REST_create_response ("");
+  MHD_add_response_header(resp, "WWW-Authenticate", error);
+  handle->proc (handle->proc_cls, resp, handle->response_code);
+  GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
+  GNUNET_free (error);
+}
+
+
+/**
+ * Task run on error, sends error message.  Cleans up everything.
+ *
+ * @param cls the `struct RequestHandle`
+ */
+static void
+do_redirect_error (void *cls)
+{
+  struct RequestHandle *handle = cls;
+  struct MHD_Response *resp;
+  char* redirect;
+  GNUNET_asprintf (&redirect,
+                   "%s?error=%s&error_description=%s%s%s",
+                  handle->oidc->redirect_uri, handle->emsg, handle->edesc,
+                  (NULL != handle->oidc->state) ? "&state=" : "",
+                  (NULL != handle->oidc->state) ? handle->oidc->state : "");
+  resp = GNUNET_REST_create_response ("");
+  MHD_add_response_header (resp, "Location", redirect);
+  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
+  GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
+  GNUNET_free (redirect);
+}
+
 /**
  * Task run on timeout, sends error message.  Cleans up everything.
  *
@@ -378,6 +653,39 @@ return_response (void *cls)
   cleanup_handle (handle);
 }
 
+/**
+ * Return attributes for claim
+ *
+ * @param cls the request handle
+ */
+static void
+return_userinfo_response (void *cls)
+{
+  char* result_str;
+  struct RequestHandle *handle = cls;
+  struct MHD_Response *resp;
+
+  result_str = json_dumps (handle->oidc->response, 0);
+
+  resp = GNUNET_REST_create_response (result_str);
+  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+  GNUNET_free (result_str);
+  cleanup_handle (handle);
+}
+
+static char*
+base_64_encode(char *string)
+{
+  char *output;
+  GNUNET_STRINGS_base64_encode(string,strlen(string),&output);
+  int index = strlen(output)-1;
+  while ('=' == output[index])
+  {
+    output[index] = '\0';
+    index--;
+  }
+  return output;
+}
 
 static void
 collect_finished_cb (void *cls)
@@ -625,6 +933,7 @@ attr_collect (void *cls,
   struct GNUNET_JSONAPI_Resource *json_resource;
   struct RequestHandle *handle = cls;
   json_t *value;
+  char* tmp_value;
   
   if ((NULL == attr->name) || (NULL == attr->data))
   {
@@ -638,11 +947,17 @@ attr_collect (void *cls,
                                                attr->name);
   GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource);
 
-  value = json_string (attr->data);
+  tmp_value = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type,
+                                           attr->data,
+                                           attr->data_size);
+
+  value = json_string (tmp_value);
+
   GNUNET_JSONAPI_resource_add_attr (json_resource,
                                     "value",
                                     value);
   json_decref (value);
+  GNUNET_free(tmp_value);
   GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
 }
 
@@ -1013,107 +1328,1284 @@ options_cont (struct GNUNET_REST_RequestHandle 
*con_handle,
 }
 
 /**
- * Handle rest request
- *
- * @param handle the request handle
+ * Cookie interpretation
  */
 static void
-init_cont (struct RequestHandle *handle)
+cookie_identity_interpretation (struct RequestHandle *handle)
 {
-  struct GNUNET_REST_RequestHandlerError err;
-  static const struct GNUNET_REST_RequestHandler handlers[] = {
-    {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, 
&list_attribute_cont},
-    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, 
&add_attribute_cont},
-    {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, 
&list_tickets_cont},
-    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, 
&revoke_ticket_cont},
-    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, 
&consume_ticket_cont},
-    {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
-      &options_cont},
-    GNUNET_REST_HANDLER_END
-  };
-
-  if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
-                                               handlers,
-                                               &err,
-                                               handle))
+  struct GNUNET_HashCode cache_key;
+  char* cookies;
+  struct GNUNET_TIME_Absolute current_time, *relog_time;
+  char delimiter[] = "; ";
+
+  //gets identity of login try with cookie
+  GNUNET_CRYPTO_hash (OIDC_COOKIE_HEADER_KEY, strlen (OIDC_COOKIE_HEADER_KEY),
+                     &cache_key);
+  if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains 
(handle->rest_handle->header_param_map,
+                                                            &cache_key) )
   {
-    handle->response_code = err.error_code;
-    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    //splits cookies and find 'Identity' cookie
+    cookies = GNUNET_CONTAINER_multihashmap_get ( 
handle->rest_handle->header_param_map, &cache_key);
+    handle->oidc->login_identity = strtok(cookies, delimiter);
+
+    while ( NULL != handle->oidc->login_identity )
+    {
+      if ( NULL != strstr (handle->oidc->login_identity, 
OIDC_COOKIE_HEADER_INFORMATION_KEY) )
+      {
+       break;
+      }
+      handle->oidc->login_identity = strtok (NULL, delimiter);
+    }
+    GNUNET_CRYPTO_hash (handle->oidc->login_identity, strlen 
(handle->oidc->login_identity),
+                     &cache_key);
+    if ( GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains 
(OIDC_identity_login_time, &cache_key) )
+    {
+      relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
+                                                   &cache_key);
+      current_time = GNUNET_TIME_absolute_get ();
+      // 30 min after old login -> redirect to login
+      if ( current_time.abs_value_us <= relog_time->abs_value_us )
+      {
+       handle->oidc->login_identity = strtok(handle->oidc->login_identity, 
OIDC_COOKIE_HEADER_INFORMATION_KEY);
+       handle->oidc->login_identity = 
GNUNET_strdup(handle->oidc->login_identity);
+      }
+    }
+    else
+    {
+      handle->oidc->login_identity = NULL;
+    }
   }
 }
 
 /**
- * If listing is enabled, prints information about the egos.
- *
- * This function is initially called for all egos and then again
- * whenever a ego's identifier changes or if it is deleted.  At the
- * end of the initial pass over all egos, the function is once called
- * with 'NULL' for 'ego'. That does NOT mean that the callback won't
- * be invoked in the future or that there was an error.
- *
- * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
- * this function is only called ONCE, and 'NULL' being passed in
- * 'ego' does indicate an error (i.e. name is taken or no default
- * value is known).  If 'ego' is non-NULL and if '*ctx'
- * is set in those callbacks, the value WILL be passed to a subsequent
- * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
- * that one was not NULL).
- *
- * When an identity is renamed, this function is called with the
- * (known) ego but the NEW identifier.
- *
- * When an identity is deleted, this function is called with the
- * (known) ego and "NULL" for the 'identifier'.  In this case,
- * the 'ego' is henceforth invalid (and the 'ctx' should also be
- * cleaned up).
- *
- * @param cls closure
- * @param ego ego handle
- * @param ctx context for application to store data for this ego
- *                 (during the lifetime of this process, initially NULL)
- * @param identifier identifier assigned by the user for this ego,
- *                   NULL if the user just deleted the ego and it
- *                   must thus no longer be used
+ * Login redirection
  */
 static void
-list_ego (void *cls,
-          struct GNUNET_IDENTITY_Ego *ego,
-          void **ctx,
-          const char *identifier)
+login_redirection(void *cls)
 {
+  char *login_base_url;
+  char *new_redirect;
+  struct MHD_Response *resp;
   struct RequestHandle *handle = cls;
-  struct EgoEntry *ego_entry;
-  struct GNUNET_CRYPTO_EcdsaPublicKey pk;
 
-  if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
+  if ( GNUNET_OK
+      == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
+                                               "address", &login_base_url) )
   {
-    handle->state = ID_REST_STATE_POST_INIT;
-    init_cont (handle);
-    return;
+    GNUNET_asprintf (&new_redirect, "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
+                    login_base_url,
+                    OIDC_RESPONSE_TYPE_KEY,
+                    handle->oidc->response_type,
+                    OIDC_CLIENT_ID_KEY,
+                    handle->oidc->client_id,
+                    OIDC_REDIRECT_URI_KEY,
+                    handle->oidc->redirect_uri,
+                    OIDC_SCOPE_KEY,
+                    handle->oidc->scope,
+                    OIDC_STATE_KEY,
+                    (NULL != handle->oidc->state) ? handle->oidc->state : "",
+                    OIDC_NONCE_KEY,
+                    (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
+    resp = GNUNET_REST_create_response ("");
+    MHD_add_response_header (resp, "Location", new_redirect);
+    GNUNET_free(login_base_url);
   }
-  if (ID_REST_STATE_INIT == handle->state) {
-    ego_entry = GNUNET_new (struct EgoEntry);
-    GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
-    ego_entry->keystring =
-      GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
-    ego_entry->ego = ego;
-    ego_entry->identifier = GNUNET_strdup (identifier);
-    GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, 
ego_entry);
+  else
+  {
+    handle->emsg = GNUNET_strdup("server_error");
+    handle->edesc = GNUNET_strdup ("gnunet configuration failed");
+    handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
   }
-
+  handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
+  GNUNET_free(new_redirect);
+  GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
 }
 
+/**
+ * Function called if we had an error in zone-to-name mapping.
+ */
 static void
-rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
-                              GNUNET_REST_ResultProcessor proc,
-                              void *proc_cls)
+oidc_iteration_error (void *cls)
 {
-  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
+  struct RequestHandle *handle = cls;
+  handle->emsg = GNUNET_strdup("INTERNAL_SERVER_ERROR");
+  handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+  GNUNET_SCHEDULER_add_now (&do_error, handle);
+}
 
-  handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-  handle->proc_cls = proc_cls;
-  handle->proc = proc;
-  handle->state = ID_REST_STATE_INIT;
+static void
+oidc_ticket_issue_cb (void* cls,
+                 const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket)
+{
+  struct RequestHandle *handle = cls;
+  struct MHD_Response *resp;
+  char *ticket_str;
+  char *redirect_uri;
+  char *code_json_string;
+  char *code_base64_final_string;
+  handle->idp_op = NULL;
+  resp = GNUNET_REST_create_response ("");
+  if (NULL != ticket) {
+    ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket,
+                                                      sizeof (struct 
GNUNET_IDENTITY_PROVIDER_Ticket));
+    //TODO change if more attributes are needed (see max_age)
+    GNUNET_asprintf (&code_json_string, "{\"ticket\":\"%s\"%s%s%s}",
+                    ticket_str,
+                    (NULL != handle->oidc->nonce) ? ", \"nonce\":\"" : "",
+                    (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "",
+                    (NULL != handle->oidc->nonce) ? "\"" : "");
+    code_base64_final_string = base_64_encode(code_json_string);
+    GNUNET_asprintf (&redirect_uri, "%s?%s=%s&state=%s",
+                    handle->oidc->redirect_uri,
+                    handle->oidc->response_type,
+                    code_base64_final_string, handle->oidc->state);
+    MHD_add_response_header (resp, "Location", redirect_uri);
+    handle->proc (handle->proc_cls, resp, MHD_HTTP_FOUND);
+    GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
+    GNUNET_free (redirect_uri);
+    GNUNET_free (ticket_str);
+    GNUNET_free (code_json_string);
+    GNUNET_free (code_base64_final_string);
+    return;
+  }
+  handle->emsg = GNUNET_strdup("server_error");
+  handle->edesc = GNUNET_strdup("Server cannot generate ticket.");
+  GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+}
+
+static void
+oidc_collect_finished_cb (void *cls)
+{
+  struct RequestHandle *handle = cls;
+  handle->attr_it = NULL;
+  handle->ticket_it = NULL;
+  if (NULL == handle->attr_list->list_head)
+  {
+    handle->emsg = GNUNET_strdup("invalid_scope");
+    handle->edesc = GNUNET_strdup("The requested scope is not available.");
+    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+    return;
+  }
+  handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_issue (handle->idp,
+                                                    &handle->priv_key,
+                                                    &handle->oidc->client_pkey,
+                                                    handle->attr_list,
+                                                    &oidc_ticket_issue_cb,
+                                                    handle);
+}
+
+
+/**
+ * Collect all attributes for an ego
+ */
+static void
+oidc_attr_collect (void *cls,
+              const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
+              const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le;
+  char* scope_variables;
+  char* scope_variable;
+  char delimiter[]=" ";
+
+  if ( (NULL == attr->name) || (NULL == attr->data) )
+  {
+    GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
+    return;
+  }
+
+  scope_variables = GNUNET_strdup(handle->oidc->scope);
+  scope_variable = strtok (scope_variables, delimiter);
+  while (NULL != scope_variable)
+  {
+    if ( 0 == strcmp (attr->name, scope_variable) )
+    {
+      break;
+    }
+    scope_variable = strtok (NULL, delimiter);
+  }
+  if ( NULL == scope_variable )
+  {
+    GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
+    return;
+  }
+  GNUNET_free(scope_variables);
+
+  le = GNUNET_new(struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry);
+  le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr->name, attr->type,
+                                                  attr->data, attr->data_size);
+  GNUNET_CONTAINER_DLL_insert(handle->attr_list->list_head,
+                             handle->attr_list->list_tail, le);
+  GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it);
+}
+
+
+/**
+ * Cookie and Time check
+ */
+static void
+login_check (void *cls)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_TIME_Absolute current_time, *relog_time;
+  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey, ego_pkey;
+  struct GNUNET_HashCode cache_key;
+  char *identity_cookie;
+
+  GNUNET_asprintf (&identity_cookie, "Identity=%s", 
handle->oidc->login_identity);
+  GNUNET_CRYPTO_hash (identity_cookie, strlen (identity_cookie), &cache_key);
+  GNUNET_free(identity_cookie);
+  //No login time for identity -> redirect to login
+  if ( GNUNET_YES
+      == GNUNET_CONTAINER_multihashmap_contains (OIDC_identity_login_time,
+                                                &cache_key) )
+  {
+    relog_time = GNUNET_CONTAINER_multihashmap_get (OIDC_identity_login_time,
+                                                   &cache_key);
+    current_time = GNUNET_TIME_absolute_get ();
+    // 30 min after old login -> redirect to login
+    if ( current_time.abs_value_us <= relog_time->abs_value_us )
+    {
+      if ( GNUNET_OK
+         != GNUNET_CRYPTO_ecdsa_public_key_from_string (
+             handle->oidc->login_identity,
+             strlen (handle->oidc->login_identity), &pubkey) )
+      {
+       handle->emsg = GNUNET_strdup("invalid_cookie");
+       handle->edesc = GNUNET_strdup(
+           "The cookie of a login identity is not valid");
+       GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+       return;
+      }
+      // iterate over egos and compare their public key
+      for (handle->ego_entry = handle->ego_head;
+      NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
+      {
+       GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego, &ego_pkey);
+       if ( 0
+           == memcmp (&ego_pkey, &pubkey,
+                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+       {
+         handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key (
+             handle->ego_entry->ego);
+         handle->resp_object = GNUNET_JSONAPI_document_new ();
+         handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
+         handle->attr_list = GNUNET_new(
+             struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList);
+         handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (
+             handle->idp, &handle->priv_key, &oidc_iteration_error, handle,
+             &oidc_attr_collect, handle, &oidc_collect_finished_cb, handle);
+         return;
+       }
+      }
+      handle->emsg = GNUNET_strdup("invalid_cookie");
+      handle->edesc = GNUNET_strdup(
+         "The cookie of the login identity is not valid");
+      GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+      return;
+    }
+  }
+}
+
+/**
+ * Create a response with requested records
+ *
+ * @param handle the RequestHandle
+ */
+static void
+namestore_iteration_callback (
+    void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+    const char *rname, unsigned int rd_len,
+    const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_CRYPTO_EcdsaPublicKey login_identity_pkey;
+  struct GNUNET_CRYPTO_EcdsaPublicKey current_zone_pkey;
+  int i;
+
+  for (i = 0; i < rd_len; i++)
+  {
+    if ( GNUNET_GNSRECORD_TYPE_PKEY != rd[i].record_type )
+      continue;
+
+    if ( NULL != handle->oidc->login_identity )
+    {
+      GNUNET_CRYPTO_ecdsa_public_key_from_string (
+         handle->oidc->login_identity,
+         strlen (handle->oidc->login_identity),
+         &login_identity_pkey);
+      GNUNET_IDENTITY_ego_get_public_key (handle->ego_entry->ego,
+                                         &current_zone_pkey);
+
+      if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
+                    sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+      {
+       if ( 0 == memcmp (&login_identity_pkey, &current_zone_pkey,
+                      sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+       {
+         handle->oidc->is_client_trusted = GNUNET_YES;
+       }
+      }
+    }
+    else
+    {
+      if ( 0 == memcmp (rd[i].data, &handle->oidc->client_pkey,
+                    sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) )
+      {
+       handle->oidc->is_client_trusted = GNUNET_YES;
+      }
+    }
+  }
+
+  GNUNET_NAMESTORE_zone_iterator_next (handle->namestore_handle_it);
+}
+
+/**
+ * Iteration over all results finished, build final
+ * response.
+ *
+ * @param cls the `struct RequestHandle`
+ */
+static void namestore_iteration_finished (void *cls)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_HashCode cache_key;
+
+  char *expected_redirect_uri;
+  char *expected_scope;
+  char delimiter[]=" ";
+  int number_of_ignored_parameter, iterator;
+
+
+  handle->ego_entry = handle->ego_entry->next;
+
+  if(NULL != handle->ego_entry)
+  {
+    handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key 
(handle->ego_entry->ego);
+    handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start 
(handle->namestore_handle, &handle->priv_key,
+                                          &oidc_iteration_error, handle, 
&namestore_iteration_callback, handle,
+                                          &namestore_iteration_finished, 
handle);
+    return;
+  }
+  if (GNUNET_NO == handle->oidc->is_client_trusted)
+  {
+    handle->emsg = GNUNET_strdup("unauthorized_client");
+    handle->edesc = GNUNET_strdup("The client is not authorized to request an "
+                                 "authorization code using this method.");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+
+  // REQUIRED value: redirect_uri
+  GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
+                     &cache_key);
+  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains 
(handle->rest_handle->url_param_map,
+                                                          &cache_key))
+  {
+    handle->emsg=GNUNET_strdup("invalid_request");
+    handle->edesc=GNUNET_strdup("missing parameter redirect_uri");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  handle->oidc->redirect_uri = 
GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+                                               &cache_key);
+
+  GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey";, 
handle->oidc->client_id);
+  // verify the redirect uri matches https://<client_id>.zkey[/xyz]
+  if( 0 != strncmp( expected_redirect_uri, handle->oidc->redirect_uri, 
strlen(expected_redirect_uri)) )
+  {
+    handle->emsg=GNUNET_strdup("invalid_request");
+    handle->edesc=GNUNET_strdup("Invalid redirect_uri");
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    GNUNET_free(expected_redirect_uri);
+    return;
+  }
+  handle->oidc->redirect_uri = GNUNET_strdup(handle->oidc->redirect_uri);
+
+  GNUNET_free(expected_redirect_uri);
+  // REQUIRED value: response_type
+  GNUNET_CRYPTO_hash (OIDC_RESPONSE_TYPE_KEY, strlen (OIDC_RESPONSE_TYPE_KEY),
+                     &cache_key);
+  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains 
(handle->rest_handle->url_param_map,
+                                                          &cache_key))
+  {
+    handle->emsg=GNUNET_strdup("invalid_request");
+    handle->edesc=GNUNET_strdup("missing parameter response_type");
+    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+    return;
+  }
+  handle->oidc->response_type = 
GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+                                                    &cache_key);
+  handle->oidc->response_type = GNUNET_strdup (handle->oidc->response_type);
+
+  // REQUIRED value: scope
+  GNUNET_CRYPTO_hash (OIDC_SCOPE_KEY, strlen (OIDC_SCOPE_KEY), &cache_key);
+  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains 
(handle->rest_handle->url_param_map,
+                                                          &cache_key))
+  {
+    handle->emsg=GNUNET_strdup("invalid_request");
+    handle->edesc=GNUNET_strdup("missing parameter scope");
+    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+    return;
+  }
+  handle->oidc->scope = 
GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+                                           &cache_key);
+  handle->oidc->scope = GNUNET_strdup(handle->oidc->scope);
+
+  //OPTIONAL value: nonce
+  GNUNET_CRYPTO_hash (OIDC_NONCE_KEY, strlen (OIDC_NONCE_KEY), &cache_key);
+  if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains 
(handle->rest_handle->url_param_map,
+                                                          &cache_key))
+  {
+    handle->oidc->nonce = 
GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+                                             &cache_key);
+    handle->oidc->nonce = GNUNET_strdup (handle->oidc->nonce);
+  }
+
+  //TODO check other values if needed
+  number_of_ignored_parameter = sizeof(OIDC_ignored_parameter_array) / 
sizeof(char *);
+  for( iterator = 0; iterator < number_of_ignored_parameter; iterator++ )
+  {
+    GNUNET_CRYPTO_hash (OIDC_ignored_parameter_array[iterator],
+                       strlen(OIDC_ignored_parameter_array[iterator]),
+                       &cache_key);
+    if(GNUNET_YES == 
GNUNET_CONTAINER_multihashmap_contains(handle->rest_handle->url_param_map,
+                                                           &cache_key))
+    {
+      handle->emsg=GNUNET_strdup("access_denied");
+      GNUNET_asprintf (&handle->edesc, "Server will not handle parameter: %s",
+                      OIDC_ignored_parameter_array[iterator]);
+      GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+      return;
+    }
+  }
+
+  // Checks if response_type is 'code'
+  if( 0 != strcmp( handle->oidc->response_type, 
OIDC_EXPECTED_AUTHORIZATION_RESPONSE_TYPE ) )
+  {
+    handle->emsg=GNUNET_strdup("unsupported_response_type");
+    handle->edesc=GNUNET_strdup("The authorization server does not support "
+                               "obtaining this authorization code.");
+    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+    return;
+  }
+
+  // Checks if scope contains 'openid'
+  expected_scope = GNUNET_strdup(handle->oidc->scope);
+  expected_scope = strtok (expected_scope, delimiter);
+  while (NULL != expected_scope)
+  {
+    if ( 0 == strcmp (OIDC_EXPECTED_AUTHORIZATION_SCOPE, expected_scope) )
+    {
+      break;
+    }
+    expected_scope = strtok (NULL, delimiter);
+  }
+  if (NULL == expected_scope)
+  {
+    handle->emsg = GNUNET_strdup("invalid_scope");
+    handle->edesc=GNUNET_strdup("The requested scope is invalid, unknown, or "
+                               "malformed.");
+    GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
+    return;
+  }
+
+  GNUNET_free(expected_scope);
+
+  if( NULL != handle->oidc->login_identity )
+  {
+    GNUNET_SCHEDULER_add_now(&login_check,handle);
+    return;
+  }
+
+  GNUNET_SCHEDULER_add_now(&login_redirection,handle);
+}
+
+/**
+ * Responds to authorization GET and url-encoded POST request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
+                const char* url,
+                void *cls)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_HashCode cache_key;
+
+  cookie_identity_interpretation(handle);
+
+  //RECOMMENDED value: state - REQUIRED for answers
+  GNUNET_CRYPTO_hash (OIDC_STATE_KEY, strlen (OIDC_STATE_KEY), &cache_key);
+  if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains 
(handle->rest_handle->url_param_map,
+                                                          &cache_key))
+  {
+    handle->oidc->state = 
GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+                                             &cache_key);
+    handle->oidc->state = GNUNET_strdup (handle->oidc->state);
+  }
+
+  // REQUIRED value: client_id
+  GNUNET_CRYPTO_hash (OIDC_CLIENT_ID_KEY, strlen (OIDC_CLIENT_ID_KEY),
+                     &cache_key);
+  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains 
(handle->rest_handle->url_param_map,
+                                                          &cache_key))
+  {
+    handle->emsg=GNUNET_strdup("invalid_request");
+    handle->edesc=GNUNET_strdup("missing parameter client_id");
+    handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  handle->oidc->client_id = 
GNUNET_CONTAINER_multihashmap_get(handle->rest_handle->url_param_map,
+                                               &cache_key);
+  handle->oidc->client_id = GNUNET_strdup (handle->oidc->client_id);
+
+  if ( GNUNET_OK
+      != GNUNET_CRYPTO_ecdsa_public_key_from_string (handle->oidc->client_id,
+                                                    strlen 
(handle->oidc->client_id),
+                                                    
&handle->oidc->client_pkey) )
+  {
+    handle->emsg = GNUNET_strdup("unauthorized_client");
+    handle->edesc = GNUNET_strdup("The client is not authorized to request an "
+                                 "authorization code using this method.");
+    handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+
+
+  if ( NULL == handle->ego_head )
+  {
+    handle->emsg = GNUNET_strdup("server_error");
+    handle->edesc = GNUNET_strdup ("Egos are missing");
+    handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+
+  handle->ego_entry = handle->ego_head;
+  handle->priv_key = *GNUNET_IDENTITY_ego_get_private_key 
(handle->ego_head->ego);
+  handle->oidc->is_client_trusted = GNUNET_NO;
+
+  // Checks if client_id is valid:
+  handle->namestore_handle_it = GNUNET_NAMESTORE_zone_iteration_start (
+      handle->namestore_handle, &handle->priv_key, &oidc_iteration_error,
+      handle, &namestore_iteration_callback, handle,
+      &namestore_iteration_finished, handle);
+}
+
+/**
+ * Combines an identity with a login time and responds OK to login request
+ *
+ * @param con_handle the connection handle
+ * @param url the url
+ * @param cls the RequestHandle
+ */
+static void
+login_cont (struct GNUNET_REST_RequestHandle *con_handle,
+            const char* url,
+            void *cls)
+{
+  struct MHD_Response *resp = GNUNET_REST_create_response ("");
+  struct RequestHandle *handle = cls;
+  struct GNUNET_HashCode cache_key;
+  struct GNUNET_TIME_Absolute *current_time;
+  struct GNUNET_TIME_Absolute *last_time;
+  char* cookie;
+  json_t *root;
+  json_error_t error;
+  json_t *identity;
+  root = json_loads (handle->rest_handle->data, 0, &error);
+  identity = json_object_get (root, "identity");
+  if ( json_is_string(identity) )
+  {
+    GNUNET_asprintf (&cookie, "Identity=%s", json_string_value (identity));
+
+    GNUNET_CRYPTO_hash (cookie, strlen (cookie), &cache_key);
+
+    current_time = GNUNET_new(struct GNUNET_TIME_Absolute);
+    *current_time = GNUNET_TIME_relative_to_absolute (
+       GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_minute_ (),
+                                      30));
+    last_time = GNUNET_CONTAINER_multihashmap_get(OIDC_identity_login_time, 
&cache_key);
+    if (NULL != last_time)
+    {
+      GNUNET_free(last_time);
+    }
+    GNUNET_CONTAINER_multihashmap_put (
+       OIDC_identity_login_time, &cache_key, current_time,
+       GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
+
+    handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+  }
+  else
+  {
+    handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST);
+  }
+  GNUNET_free(cookie);
+  json_decref (root);
+  GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle);
+  return;
+}
+
+static void
+token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
+                const char* url,
+                void *cls)
+{
+  //TODO static strings
+
+  struct RequestHandle *handle = cls;
+  struct GNUNET_HashCode cache_key;
+  char *authorization, *credentials;
+  char delimiter[]=" ";
+  char delimiter_user_psw[]=":";
+  char *grant_type, *code, *redirect_uri, *expected_redirect_uri;
+  char *user_psw = NULL, *client_id, *psw;
+  char *expected_psw;
+  int client_exists = GNUNET_NO;
+  struct MHD_Response *resp;
+  char* code_output;
+  json_t *root, *ticket_string, *nonce, *max_age;
+  json_error_t error;
+  char *json_response;
+
+  /*
+   * Check Authorization
+   */
+  GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
+                     strlen (OIDC_AUTHORIZATION_HEADER_KEY),
+                     &cache_key);
+  if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains 
(handle->rest_handle->header_param_map,
+                                                            &cache_key) )
+  {
+    handle->emsg=GNUNET_strdup("invalid_client");
+    handle->edesc=GNUNET_strdup("missing authorization");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  authorization = GNUNET_CONTAINER_multihashmap_get ( 
handle->rest_handle->header_param_map, &cache_key);
+
+  //TODO authorization pointer will be moved as well
+  //split header in "Basic" and [content]
+  credentials = strtok (authorization, delimiter);
+  if (0 != strcmp ("Basic",credentials))
+  {
+    handle->emsg=GNUNET_strdup("invalid_client");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  credentials = strtok(NULL, delimiter);
+  if (NULL == credentials)
+  {
+    handle->emsg=GNUNET_strdup("invalid_client");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  GNUNET_STRINGS_base64_decode (credentials, strlen (credentials), &user_psw);
+
+  if ( NULL == user_psw )
+  {
+    handle->emsg=GNUNET_strdup("invalid_client");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  client_id = strtok (user_psw, delimiter_user_psw);
+  if ( NULL == client_id )
+  {
+    GNUNET_free_non_null(user_psw);
+    handle->emsg=GNUNET_strdup("invalid_client");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  psw = strtok (NULL, delimiter_user_psw);
+  if (NULL == psw)
+  {
+    GNUNET_free_non_null(user_psw);
+    handle->emsg=GNUNET_strdup("invalid_client");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  //check client password
+  if ( GNUNET_OK
+      == GNUNET_CONFIGURATION_get_value_string (cfg, "identity-rest-plugin",
+                                               "psw", &expected_psw) )
+  {
+    if (0 != strcmp (expected_psw, psw))
+    {
+      handle->emsg=GNUNET_strdup("invalid_client");
+      handle->response_code = MHD_HTTP_UNAUTHORIZED;
+      GNUNET_SCHEDULER_add_now (&do_error, handle);
+      return;
+    }
+    GNUNET_free(expected_psw);
+  }
+  else
+  {
+    handle->emsg = GNUNET_strdup("server_error");
+    handle->edesc = GNUNET_strdup ("gnunet configuration failed");
+    handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  //check client_id
+  for (handle->ego_entry = handle->ego_head; NULL != handle->ego_entry->next; )
+  {
+    if ( 0 == strcmp(handle->ego_entry->keystring, client_id))
+    {
+      client_exists = GNUNET_YES;
+      break;
+    }
+    handle->ego_entry = handle->ego_entry->next;
+  }
+  if (GNUNET_NO == client_exists)
+  {
+    handle->emsg=GNUNET_strdup("invalid_client");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+
+  /*
+   * Check parameter
+   */
+
+  //TODO Do not allow multiple equal parameter names
+  //REQUIRED grant_type
+  GNUNET_CRYPTO_hash (OIDC_GRANT_TYPE_KEY, strlen (OIDC_GRANT_TYPE_KEY), 
&cache_key);
+  if ( GNUNET_NO
+      == GNUNET_CONTAINER_multihashmap_contains (
+         handle->rest_handle->url_param_map, &cache_key) )
+  {
+    handle->emsg = GNUNET_strdup("invalid_request");
+    handle->edesc = GNUNET_strdup("missing parameter grant_type");
+    handle->response_code = MHD_HTTP_BAD_REQUEST;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  grant_type = GNUNET_CONTAINER_multihashmap_get (
+      handle->rest_handle->url_param_map, &cache_key);
+
+  //REQUIRED code
+  GNUNET_CRYPTO_hash (OIDC_CODE_KEY, strlen (OIDC_CODE_KEY), &cache_key);
+  if ( GNUNET_NO
+      == GNUNET_CONTAINER_multihashmap_contains (
+         handle->rest_handle->url_param_map, &cache_key) )
+  {
+    handle->emsg = GNUNET_strdup("invalid_request");
+    handle->edesc = GNUNET_strdup("missing parameter code");
+    handle->response_code = MHD_HTTP_BAD_REQUEST;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  code = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map,
+                                           &cache_key);
+
+  //REQUIRED redirect_uri
+  GNUNET_CRYPTO_hash (OIDC_REDIRECT_URI_KEY, strlen (OIDC_REDIRECT_URI_KEY),
+                     &cache_key);
+  if ( GNUNET_NO
+      == GNUNET_CONTAINER_multihashmap_contains (
+         handle->rest_handle->url_param_map, &cache_key) )
+  {
+    handle->emsg = GNUNET_strdup("invalid_request");
+    handle->edesc = GNUNET_strdup("missing parameter redirect_uri");
+    handle->response_code = MHD_HTTP_BAD_REQUEST;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  redirect_uri = GNUNET_CONTAINER_multihashmap_get (
+      handle->rest_handle->url_param_map, &cache_key);
+
+
+  //Check parameter grant_type == "authorization_code"
+  if (0 != strcmp(OIDC_GRANT_TYPE_VALUE, grant_type))
+  {
+    handle->emsg=GNUNET_strdup("unsupported_grant_type");
+    handle->response_code = MHD_HTTP_BAD_REQUEST;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  // check redirect_uri
+  GNUNET_asprintf (&expected_redirect_uri, "https://%s.zkey";, client_id);
+  // verify the redirect uri matches https://<client_id>.zkey[/xyz]
+  if( 0 != strncmp( expected_redirect_uri, redirect_uri, 
strlen(expected_redirect_uri)) )
+  {
+    handle->emsg=GNUNET_strdup("invalid_request");
+    handle->edesc=GNUNET_strdup("Invalid redirect_uri");
+    handle->response_code = MHD_HTTP_BAD_REQUEST;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    GNUNET_free(expected_redirect_uri);
+    return;
+  }
+  GNUNET_free(expected_redirect_uri);
+  GNUNET_CRYPTO_hash(code, strlen(code), &cache_key);
+  if ( GNUNET_YES == 
GNUNET_CONTAINER_multihashmap_contains(OIDC_ticket_once,&cache_key))
+  {
+    handle->emsg = GNUNET_strdup("invalid_request");
+    handle->edesc = GNUNET_strdup("Cannot use the same code more than once");
+    handle->response_code = MHD_HTTP_BAD_REQUEST;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+  int i=1;
+  
GNUNET_CONTAINER_multihashmap_put(OIDC_ticket_once,&cache_key,&i,GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
+
+  //decode code
+  GNUNET_STRINGS_base64_decode(code,strlen(code),&code_output);
+  root = json_loads (code_output, 0, &error);
+  GNUNET_free(code_output);
+  ticket_string = json_object_get (root, "ticket");
+  nonce = json_object_get (root, "nonce");
+  max_age = json_object_get (root, "max_age");
+
+  if(ticket_string == NULL && !json_is_string(ticket_string))
+  {
+    handle->emsg = GNUNET_strdup("invalid_request");
+    handle->edesc = GNUNET_strdup("invalid code");
+    handle->response_code = MHD_HTTP_BAD_REQUEST;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    return;
+  }
+
+  struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket = GNUNET_new(struct 
GNUNET_IDENTITY_PROVIDER_Ticket);
+  if ( GNUNET_OK
+      != GNUNET_STRINGS_string_to_data (json_string_value(ticket_string),
+                                       strlen 
(json_string_value(ticket_string)),
+                                       ticket,
+                                       sizeof(struct 
GNUNET_IDENTITY_PROVIDER_Ticket)))
+  {
+    handle->emsg = GNUNET_strdup("invalid_request");
+    handle->edesc = GNUNET_strdup("invalid code");
+    handle->response_code = MHD_HTTP_BAD_REQUEST;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    GNUNET_free(ticket);
+    return;
+  }
+  // this is the current client (relying party)
+  struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
+  GNUNET_IDENTITY_ego_get_public_key(handle->ego_entry->ego,&pub_key);
+  if (0 != memcmp(&pub_key,&ticket->audience,sizeof(struct 
GNUNET_CRYPTO_EcdsaPublicKey)))
+  {
+    handle->emsg = GNUNET_strdup("invalid_request");
+    handle->edesc = GNUNET_strdup("invalid code");
+    handle->response_code = MHD_HTTP_BAD_REQUEST;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    GNUNET_free(ticket);
+    return;
+  }
+
+  //create jwt
+  unsigned long long int expiration_time;
+  if ( GNUNET_OK
+      != GNUNET_CONFIGURATION_get_value_number(cfg, "identity-rest-plugin",
+                                               "expiration_time", 
&expiration_time) )
+  {
+    handle->emsg = GNUNET_strdup("server_error");
+    handle->edesc = GNUNET_strdup ("gnunet configuration failed");
+    handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    GNUNET_free(ticket);
+    return;
+  }
+
+  struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *cl = GNUNET_new (struct 
GNUNET_IDENTITY_ATTRIBUTE_ClaimList);
+  //aud REQUIRED public key client_id must be there
+  GNUNET_IDENTITY_ATTRIBUTE_list_add(cl,
+                                    "aud",
+                                    GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
+                                    client_id,
+                                    strlen(client_id));
+  //exp REQUIRED time expired from config
+  //TODO time as seconds
+  struct GNUNET_TIME_Absolute exp_time = GNUNET_TIME_relative_to_absolute (
+      GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_get_second_ (),
+                                    expiration_time));
+  const char* exp_time_string = 
GNUNET_STRINGS_absolute_time_to_string(exp_time);
+  GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
+                                     "exp",
+                                     GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
+                                     exp_time_string,
+                                     strlen(exp_time_string));
+  //iat REQUIRED time now
+  //TODO time as seconds
+  struct GNUNET_TIME_Absolute time_now = GNUNET_TIME_absolute_get();
+  const char* time_now_string = 
GNUNET_STRINGS_absolute_time_to_string(time_now);
+  GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
+                                     "iat",
+                                     GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
+                                     time_now_string,
+                                     strlen(time_now_string));
+  //nonce only if nonce is provided
+  if ( NULL != nonce && json_is_string(nonce) )
+  {
+    GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
+                                       "nonce",
+                                       GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
+                                       json_string_value(nonce),
+                                       strlen(json_string_value(nonce)));
+  }
+  //auth_time only if max_age is provided
+  if ( NULL != max_age && json_is_string(max_age) )
+  {
+    GNUNET_IDENTITY_ATTRIBUTE_list_add (cl,
+                                       "auth_time",
+                                       GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING,
+                                       json_string_value(max_age),
+                                       strlen(json_string_value(max_age)));
+  }
+  //TODO OPTIONAL acr,amr,azp
+
+  //TODO lookup client for client == audience of ticket
+  struct EgoEntry *ego_entry;
+  for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = 
ego_entry->next)
+  {
+    GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &pub_key);
+    if (0 == memcmp (&pub_key, &ticket->audience, sizeof(struct 
GNUNET_CRYPTO_EcdsaPublicKey)))
+    {
+      break;
+    }
+  }
+  if ( NULL == ego_entry )
+  {
+    handle->emsg = GNUNET_strdup("invalid_request");
+    handle->edesc = GNUNET_strdup("invalid code....");
+    handle->response_code = MHD_HTTP_BAD_REQUEST;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+    GNUNET_free(ticket);
+    return;
+  }
+  char *id_token = jwt_create_from_list(&ticket->audience,
+                                        cl,
+                                        
GNUNET_IDENTITY_ego_get_private_key(ego_entry->ego));
+
+  //Create random access_token
+  char* access_token_number;
+  char* access_token;
+  uint64_t random_number;
+  random_number = GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_NONCE, 
UINT64_MAX);
+  GNUNET_asprintf(&access_token_number, "%" PRIu64, random_number);
+  
GNUNET_STRINGS_base64_encode(access_token_number,strlen(access_token_number),&access_token);
+
+
+  
+  //TODO OPTIONAL add refresh_token and scope
+  GNUNET_asprintf (&json_response,
+                  "{ \"access_token\" : \"%s\", "
+                  "\"token_type\" : \"Bearer\", "
+                  "\"expires_in\" : %d, "
+                  "\"id_token\" : \"%s\"}",
+                  access_token,
+                  expiration_time,
+                  id_token);
+  GNUNET_CRYPTO_hash(access_token, strlen(access_token), &cache_key);
+  char *id_ticket_combination;
+  GNUNET_asprintf(&id_ticket_combination,
+                 "%s;%s",
+                 client_id,
+                 json_string_value(ticket_string));
+  GNUNET_CONTAINER_multihashmap_put(OIDC_interpret_access_token,
+                                   &cache_key,
+                                   id_ticket_combination,
+                                   
GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
+
+  resp = GNUNET_REST_create_response (json_response);
+  MHD_add_response_header (resp, "Cache-Control", "no-store");
+  MHD_add_response_header (resp, "Pragma", "no-cache");
+  MHD_add_response_header (resp, "Content-Type", "application/json");
+  handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
+
+  //TODO one time ticket/code
+
+  //TODO free
+  GNUNET_IDENTITY_ATTRIBUTE_list_destroy(cl);
+  GNUNET_free(access_token_number);
+  GNUNET_free(access_token);
+  GNUNET_free(user_psw);
+  GNUNET_free(json_response);
+  GNUNET_free(ticket);
+  GNUNET_free(id_token);
+  json_decref (root);
+  GNUNET_SCHEDULER_add_now(&cleanup_handle_delayed, handle);
+}
+
+
+static void
+consume_ticket (void *cls,
+              const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
+              const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr)
+{
+  struct RequestHandle *handle = cls;
+
+  if (NULL == identity)
+  {
+    GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle);
+    return;
+  }
+
+  json_object_set_new (handle->oidc->response,
+                      attr->name,
+                      json_string(attr->data));
+}
+
+static void
+userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
+                  const char* url, void *cls)
+{
+  struct RequestHandle *handle = cls;
+  char delimiter[] = " ";
+  char delimiter_db[] = ";";
+  struct GNUNET_HashCode cache_key;
+  char *authorization, *authorization_type, *authorization_access_token;
+  char *client_ticket;
+  struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket;
+
+  GNUNET_CRYPTO_hash (OIDC_AUTHORIZATION_HEADER_KEY,
+                     strlen (OIDC_AUTHORIZATION_HEADER_KEY),
+                     &cache_key);
+  if ( GNUNET_NO
+      == GNUNET_CONTAINER_multihashmap_contains (
+         handle->rest_handle->header_param_map, &cache_key) )
+  {
+    handle->emsg = GNUNET_strdup("invalid_token");
+    handle->edesc = GNUNET_strdup("No Access Token");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
+    return;
+  }
+  authorization = GNUNET_CONTAINER_multihashmap_get (
+      handle->rest_handle->header_param_map, &cache_key);
+
+  //TODO authorization pointer will be moved as well
+  //split header in "Bearer" and access_token
+  authorization_type = strtok (authorization, delimiter);
+  if ( 0 != strcmp ("Bearer", authorization_type) )
+  {
+    handle->emsg = GNUNET_strdup("invalid_token");
+    handle->edesc = GNUNET_strdup("No Access Token");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
+    return;
+  }
+  authorization_access_token = strtok (NULL, delimiter);
+  if ( NULL == authorization_access_token )
+  {
+    handle->emsg = GNUNET_strdup("invalid_token");
+    handle->edesc = GNUNET_strdup("No Access Token");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
+    return;
+  }
+
+  GNUNET_CRYPTO_hash (authorization_access_token,
+                     strlen (authorization_access_token),
+                     &cache_key);
+  if ( GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains 
(OIDC_interpret_access_token,
+                                                           &cache_key) )
+  {
+    handle->emsg = GNUNET_strdup("invalid_token");
+    handle->edesc = GNUNET_strdup("The Access Token expired");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
+    return;
+  }
+
+  client_ticket = 
GNUNET_CONTAINER_multihashmap_get(OIDC_interpret_access_token,
+                                                   &cache_key);
+
+  client_ticket = strtok(client_ticket,delimiter_db);
+  if (NULL == client_ticket)
+  {
+    handle->emsg = GNUNET_strdup("invalid_token");
+    handle->edesc = GNUNET_strdup("The Access Token expired");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
+    return;
+  }
+  handle->ego_entry = handle->ego_head;
+  for(; NULL != handle->ego_entry; handle->ego_entry = handle->ego_entry->next)
+  {
+    if (0 == strcmp(handle->ego_entry->keystring,client_ticket))
+    {
+      break;
+    }
+  }
+  if (NULL == handle->ego_entry)
+  {
+    handle->emsg = GNUNET_strdup("invalid_token");
+    handle->edesc = GNUNET_strdup("The Access Token expired");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
+    return;
+  }
+  client_ticket = strtok(NULL, delimiter_db);
+  if (NULL == client_ticket)
+  {
+    handle->emsg = GNUNET_strdup("invalid_token");
+    handle->edesc = GNUNET_strdup("The Access Token expired");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
+    return;
+  }
+  ticket = GNUNET_new(struct GNUNET_IDENTITY_PROVIDER_Ticket);
+  if ( GNUNET_OK
+      != GNUNET_STRINGS_string_to_data (client_ticket,
+                                       strlen (client_ticket),
+                                       ticket,
+                                       sizeof(struct 
GNUNET_IDENTITY_PROVIDER_Ticket)))
+  {
+    handle->emsg = GNUNET_strdup("invalid_token");
+    handle->edesc = GNUNET_strdup("The Access Token expired");
+    handle->response_code = MHD_HTTP_UNAUTHORIZED;
+    GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle);
+    GNUNET_free(ticket);
+    return;
+  }
+
+  handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg);
+  handle->oidc->response = json_object();
+  json_object_set_new( handle->oidc->response, "sub", json_string( 
handle->ego_entry->keystring));
+  handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (
+      handle->idp,
+      GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego),
+      ticket,
+      consume_ticket,
+      handle);
+  GNUNET_free(ticket);
+
+}
+
+
+/**
+ * Handle rest request
+ *
+ * @param handle the request handle
+ */
+static void
+init_cont (struct RequestHandle *handle)
+{
+  struct GNUNET_REST_RequestHandlerError err;
+  static const struct GNUNET_REST_RequestHandler handlers[] = {
+    {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, 
&list_attribute_cont},
+    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, 
&add_attribute_cont},
+    {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, 
&list_tickets_cont},
+    {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint},
+    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_AUTHORIZE, &authorize_endpoint}, 
//url-encoded
+    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_LOGIN, &login_cont},
+    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_TOKEN, &token_endpoint },
+    {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
+    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_USERINFO, &userinfo_endpoint },
+    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, 
&revoke_ticket_cont},
+    {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, 
&consume_ticket_cont},
+    {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER,
+      &options_cont},
+    GNUNET_REST_HANDLER_END
+  };
+
+  if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle,
+                                               handlers,
+                                               &err,
+                                               handle))
+  {
+    handle->response_code = err.error_code;
+    GNUNET_SCHEDULER_add_now (&do_error, handle);
+  }
+}
+
+/**
+ * If listing is enabled, prints information about the egos.
+ *
+ * This function is initially called for all egos and then again
+ * whenever a ego's identifier changes or if it is deleted.  At the
+ * end of the initial pass over all egos, the function is once called
+ * with 'NULL' for 'ego'. That does NOT mean that the callback won't
+ * be invoked in the future or that there was an error.
+ *
+ * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
+ * this function is only called ONCE, and 'NULL' being passed in
+ * 'ego' does indicate an error (i.e. name is taken or no default
+ * value is known).  If 'ego' is non-NULL and if '*ctx'
+ * is set in those callbacks, the value WILL be passed to a subsequent
+ * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
+ * that one was not NULL).
+ *
+ * When an identity is renamed, this function is called with the
+ * (known) ego but the NEW identifier.
+ *
+ * When an identity is deleted, this function is called with the
+ * (known) ego and "NULL" for the 'identifier'.  In this case,
+ * the 'ego' is henceforth invalid (and the 'ctx' should also be
+ * cleaned up).
+ *
+ * @param cls closure
+ * @param ego ego handle
+ * @param ctx context for application to store data for this ego
+ *                 (during the lifetime of this process, initially NULL)
+ * @param identifier identifier assigned by the user for this ego,
+ *                   NULL if the user just deleted the ego and it
+ *                   must thus no longer be used
+ */
+static void
+list_ego (void *cls,
+          struct GNUNET_IDENTITY_Ego *ego,
+          void **ctx,
+          const char *identifier)
+{
+  struct RequestHandle *handle = cls;
+  struct EgoEntry *ego_entry;
+  struct GNUNET_CRYPTO_EcdsaPublicKey pk;
+
+  if ((NULL == ego) && (ID_REST_STATE_INIT == handle->state))
+  {
+    handle->state = ID_REST_STATE_POST_INIT;
+    init_cont (handle);
+    return;
+  }
+  if (ID_REST_STATE_INIT == handle->state) {
+    ego_entry = GNUNET_new (struct EgoEntry);
+    GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
+    ego_entry->keystring =
+      GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
+    ego_entry->ego = ego;
+    ego_entry->identifier = GNUNET_strdup (identifier);
+    GNUNET_CONTAINER_DLL_insert_tail(handle->ego_head,handle->ego_tail, 
ego_entry);
+  }
+
+}
+
+static void
+rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle,
+                              GNUNET_REST_ResultProcessor proc,
+                              void *proc_cls)
+{
+  struct RequestHandle *handle = GNUNET_new (struct RequestHandle);
+  handle->oidc = GNUNET_new (struct OIDC_Variables);
+  if ( NULL == OIDC_identity_login_time )
+    OIDC_identity_login_time = GNUNET_CONTAINER_multihashmap_create (10, 
GNUNET_NO);
+  if ( NULL == OIDC_identity_grants )
+    OIDC_identity_grants = GNUNET_CONTAINER_multihashmap_create (10, 
GNUNET_NO);
+  if ( NULL == OIDC_ticket_once )
+    OIDC_ticket_once = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
+  if ( NULL == OIDC_interpret_access_token )
+    OIDC_interpret_access_token = GNUNET_CONTAINER_multihashmap_create (10, 
GNUNET_NO);
+  handle->response_code = 0;
+  handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+  handle->proc_cls = proc_cls;
+  handle->proc = proc;
+  handle->state = ID_REST_STATE_INIT;
   handle->rest_handle = rest_handle;
 
   handle->url = GNUNET_strdup (rest_handle->url);
@@ -1124,6 +2616,7 @@ rest_identity_process_request(struct 
GNUNET_REST_RequestHandle *rest_handle,
   handle->identity_handle = GNUNET_IDENTITY_connect (cfg,
                                                      &list_ego,
                                                      handle);
+  handle->namestore_handle = GNUNET_NAMESTORE_connect (cfg);
   handle->timeout_task =
     GNUNET_SCHEDULER_add_delayed (handle->timeout,
                                   &do_timeout,
@@ -1178,8 +2671,44 @@ libgnunet_plugin_rest_identity_provider_done (void *cls)
 {
   struct GNUNET_REST_Plugin *api = cls;
   struct Plugin *plugin = api->cls;
-
   plugin->cfg = NULL;
+
+  struct GNUNET_CONTAINER_MultiHashMapIterator *hashmap_it;
+  void *value = NULL;
+  hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create (
+      OIDC_identity_login_time);
+  while (GNUNET_YES ==
+         GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
+  {
+    if (NULL != value)
+      GNUNET_free(value);
+  }
+  GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_login_time);
+  hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create 
(OIDC_identity_grants);
+  while (GNUNET_YES ==
+         GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
+  {
+    if (NULL != value)
+      GNUNET_free(value);
+  }
+  GNUNET_CONTAINER_multihashmap_destroy(OIDC_identity_grants);
+  hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create 
(OIDC_ticket_once);
+  while (GNUNET_YES ==
+         GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
+  {
+    if (NULL != value)
+      GNUNET_free(value);
+  }
+  GNUNET_CONTAINER_multihashmap_destroy(OIDC_ticket_once);
+  hashmap_it = GNUNET_CONTAINER_multihashmap_iterator_create 
(OIDC_interpret_access_token);
+  while (GNUNET_YES ==
+         GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
+  {
+    if (NULL != value)
+      GNUNET_free(value);
+  }
+  GNUNET_CONTAINER_multihashmap_destroy(OIDC_interpret_access_token);
+  GNUNET_CONTAINER_multihashmap_iterator_destroy(hashmap_it);
   GNUNET_free_non_null (allow_methods);
   GNUNET_free (api);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
diff --git a/src/identity-provider/test_idp.conf 
b/src/identity-provider/test_idp.conf
index 2b76c7bf2..b11b43ae2 100644
--- a/src/identity-provider/test_idp.conf
+++ b/src/identity-provider/test_idp.conf
@@ -8,7 +8,7 @@ AUTOSTART = YES
 
 [rest]
 AUTOSTART = YES
-#PREFIX = valgrind --leak-check=full --track-origins=yes 
--log-file=/tmp/restlog
+PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/restlog
 
 [transport]
 PLUGINS =
@@ -26,3 +26,8 @@ DEFAULT_LOOKUP_TIMEOUT = 15 s
 RECORD_PUT_INTERVAL = 1 h
 ZONE_PUBLISH_TIME_WINDOW = 1 h
 DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0
+
+[identity-rest-plugin]
+address = http://localhost:8000/#/login
+psw = mysupersecretpassword
+expiration_time = 3600
\ No newline at end of file
diff --git a/src/include/gnunet_identity_attribute_lib.h 
b/src/include/gnunet_identity_attribute_lib.h
index 316b0bf95..8879ba925 100644
--- a/src/include/gnunet_identity_attribute_lib.h
+++ b/src/include/gnunet_identity_attribute_lib.h
@@ -148,6 +148,12 @@ GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (const 
struct GNUNET_IDENTITY_
 void
 GNUNET_IDENTITY_ATTRIBUTE_list_destroy (struct 
GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs);
 
+void
+GNUNET_IDENTITY_ATTRIBUTE_list_add (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList 
*attrs,
+                                   const char* attr_name,
+                                   uint32_t type,
+                                   const void* data,
+                                   size_t data_size);
 
 /**
  * Serialize an attribute list
diff --git a/src/include/gnunet_rest_lib.h b/src/include/gnunet_rest_lib.h
index 9821e23d5..41b85401d 100644
--- a/src/include/gnunet_rest_lib.h
+++ b/src/include/gnunet_rest_lib.h
@@ -38,11 +38,34 @@
 
 struct GNUNET_REST_RequestHandle
 {
+  /**
+   * Map of url parameters
+   */
   struct GNUNET_CONTAINER_MultiHashMap *url_param_map;
+
+  /**
+   * Map of headers
+   */
   struct GNUNET_CONTAINER_MultiHashMap *header_param_map;
+
+  /**
+   * The HTTP method as MHD value (see microhttpd.h)
+   */
   const char *method;
+
+  /**
+   * The url as string
+   */
   const char *url;
+
+  /**
+   * The POST data
+   */
   const char *data;
+
+  /**
+   * The POST data size
+   */
   size_t data_size;
 };
 
diff --git a/src/rest/gnunet-rest-server.c b/src/rest/gnunet-rest-server.c
index c79c807a6..fdcd4f9c5 100644
--- a/src/rest/gnunet-rest-server.c
+++ b/src/rest/gnunet-rest-server.c
@@ -303,6 +303,7 @@ post_data_iter (void *cls,
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Could not load add url param `%s'=%s\n",
                 key, data);
+    GNUNET_free(val);
   }
   return MHD_YES;
 
@@ -398,6 +399,10 @@ create_response (void *cls,
                                MHD_GET_ARGUMENT_KIND,
                                &url_iterator,
                                rest_conndata_handle);
+    MHD_get_connection_values (con,
+                               MHD_HEADER_KIND,
+                               &header_iterator,
+                               rest_conndata_handle);
     con_handle->pp = MHD_create_post_processor(con,
                                               4000,
                                               post_data_iter,
@@ -406,14 +411,8 @@ create_response (void *cls,
     {
       MHD_post_process(con_handle->pp, upload_data, *upload_data_size);
     }
-    else
-    {
-      MHD_destroy_post_processor(con_handle->pp);
-    }
-    MHD_get_connection_values (con,
-                               MHD_HEADER_KIND,
-                               &header_iterator,
-                               rest_conndata_handle);
+    MHD_destroy_post_processor(con_handle->pp);
+
     con_handle->state = GN_REST_STATE_PROCESSING;
     con_handle->plugin->process_request (rest_conndata_handle,
                                          &plugin_callback,
@@ -644,7 +643,7 @@ do_accept (void *cls)
                 _("Failed to pass client to MHD\n"));
     return;
   }
-
+  GNUNET_free(s);
   schedule_httpd ();
 }
 
diff --git a/src/rest/rest.conf b/src/rest/rest.conf
index b86e6c1a0..f74d772e8 100644
--- a/src/rest/rest.conf
+++ b/src/rest/rest.conf
@@ -3,4 +3,4 @@ UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-rest.sock
 BINARY=gnunet-rest-server
 REST_PORT=7776
 REST_ALLOW_HEADERS=Authorization,Accept,Content-Type
-REST_ALLOW_ORIGIN=*
+REST_ALLOW_ORIGIN=http://localhost:8000

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]