minor fix
[oweals/gnunet.git] / src / reclaim / plugin_rest_openid_connect.c
index 2dde8995095e52d495ef1d79e2f683ec57526164..09b3c8248a2de75894e3c494f51a292a09069f30 100644 (file)
@@ -32,7 +32,7 @@
 #include "gnunet_gnsrecord_lib.h"
 #include "gnunet_identity_service.h"
 #include "gnunet_namestore_service.h"
-#include "gnunet_reclaim_attribute_lib.h"
+#include "gnunet_reclaim_lib.h"
 #include "gnunet_reclaim_service.h"
 #include "gnunet_rest_lib.h"
 #include "gnunet_rest_plugin.h"
  */
 #define OIDC_NONCE_KEY "nonce"
 
+/**
+ * OIDC claims key
+ */
+#define OIDC_CLAIMS_KEY "claims"
+
 /**
  * OIDC PKCE code challenge
  */
@@ -290,6 +295,11 @@ struct OIDC_Variables
    */
   char *nonce;
 
+  /**
+   * The OIDC claims
+   */
+  char *claims;
+
   /**
    * The OIDC response type
    */
@@ -418,7 +428,13 @@ struct RequestHandle
   /**
    * Attribute claim list
    */
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
+  struct GNUNET_RECLAIM_AttributeList *attr_list;
+
+  /**
+   * Attestation list
+   */
+  struct GNUNET_RECLAIM_AttestationList *attests_list;
+
 
   /**
    * IDENTITY Operation
@@ -440,6 +456,12 @@ struct RequestHandle
    */
   struct GNUNET_RECLAIM_AttributeIterator *attr_it;
 
+  /**
+   * Attestation iterator
+   */
+  struct GNUNET_RECLAIM_AttestationIterator *attest_it;
+
+
   /**
    * Ticket iterator
    */
@@ -513,10 +535,7 @@ struct RequestHandle
 static void
 cleanup_handle (struct RequestHandle *handle)
 {
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_entry;
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *claim_tmp;
   struct EgoEntry *ego_entry;
-  struct EgoEntry *ego_tmp;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
   if (NULL != handle->timeout_task)
@@ -525,8 +544,12 @@ cleanup_handle (struct RequestHandle *handle)
     GNUNET_IDENTITY_disconnect (handle->identity_handle);
   if (NULL != handle->attr_it)
     GNUNET_RECLAIM_get_attributes_stop (handle->attr_it);
+  if (NULL != handle->attest_it)
+    GNUNET_RECLAIM_get_attestations_stop (handle->attest_it);
   if (NULL != handle->ticket_it)
     GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it);
+  if (NULL != handle->idp_op)
+    GNUNET_RECLAIM_cancel (handle->idp_op);
   if (NULL != handle->idp)
     GNUNET_RECLAIM_disconnect (handle->idp);
   GNUNET_free_non_null (handle->url);
@@ -554,24 +577,19 @@ cleanup_handle (struct RequestHandle *handle)
     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;)
+  if (NULL!=handle->attr_list)
+    GNUNET_RECLAIM_attribute_list_destroy (handle->attr_list);
+  if (NULL!=handle->attests_list)
+    GNUNET_RECLAIM_attestation_list_destroy (handle->attests_list);
+
+  while (NULL != (ego_entry = handle->ego_head))
   {
-    ego_tmp = ego_entry;
-    ego_entry = ego_entry->next;
-    GNUNET_free (ego_tmp->identifier);
-    GNUNET_free (ego_tmp->keystring);
-    GNUNET_free (ego_tmp);
+    GNUNET_CONTAINER_DLL_remove (handle->ego_head,
+                                 handle->ego_tail,
+                                 ego_entry);
+    GNUNET_free_non_null (ego_entry->identifier);
+    GNUNET_free_non_null (ego_entry->keystring);
+    GNUNET_free (ego_entry);
   }
   GNUNET_free (handle);
 }
@@ -697,7 +715,7 @@ return_userinfo_response (void *cls)
   struct MHD_Response *resp;
 
   result_str = json_dumps (handle->oidc->response, 0);
-
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"ID-Token: %s\n",result_str);
   resp = GNUNET_REST_create_response (result_str);
   handle->proc (handle->proc_cls, resp, MHD_HTTP_OK);
   GNUNET_free (result_str);
@@ -838,7 +856,7 @@ login_redirect (void *cls)
                                                           &login_base_url))
   {
     GNUNET_asprintf (&new_redirect,
-                     "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
+                     "%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s",
                      login_base_url,
                      OIDC_RESPONSE_TYPE_KEY,
                      handle->oidc->response_type,
@@ -854,7 +872,10 @@ login_redirect (void *cls)
                      (NULL != handle->oidc->code_challenge) ?
                      handle->oidc->code_challenge : "",
                      OIDC_NONCE_KEY,
-                     (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "");
+                     (NULL != handle->oidc->nonce) ? handle->oidc->nonce : "",
+                     OIDC_CLAIMS_KEY,
+                     (NULL != handle->oidc->claims) ? handle->oidc->claims :
+                     "");
     resp = GNUNET_REST_create_response ("");
     MHD_add_response_header (resp, "Location", new_redirect);
     GNUNET_free (login_base_url);
@@ -912,10 +933,10 @@ oidc_ticket_issue_cb (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
   ticket_str =
     GNUNET_STRINGS_data_to_string_alloc (&handle->ticket,
                                          sizeof(struct GNUNET_RECLAIM_Ticket));
-  // TODO change if more attributes are needed (see max_age)
   code_string = OIDC_build_authz_code (&handle->priv_key,
                                        &handle->ticket,
                                        handle->attr_list,
+                                       handle->attests_list,
                                        handle->oidc->nonce,
                                        handle->oidc->code_challenge);
   if ((NULL != handle->redirect_prefix) && (NULL != handle->redirect_suffix) &&
@@ -950,7 +971,53 @@ oidc_ticket_issue_cb (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
 
 
 static void
-oidc_collect_finished_cb (void *cls)
+oidc_attest_collect_finished_cb (void *cls)
+{
+  struct RequestHandle *handle = cls;
+
+  handle->attest_it = NULL;
+  handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp,
+                                                &handle->priv_key,
+                                                &handle->oidc->client_pkey,
+                                                handle->attr_list,
+                                                &oidc_ticket_issue_cb,
+                                                handle);
+}
+
+
+/**
+ * Collects all attributes for an ego if in scope parameter
+ */
+static void
+oidc_attest_collect (void *cls,
+                     const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
+                     const struct GNUNET_RECLAIM_Attestation *attest)
+{
+  struct RequestHandle *handle = cls;
+  struct GNUNET_RECLAIM_AttributeListEntry *le;
+
+  for (le = handle->attr_list->list_head; NULL != le; le = le->next)
+  {
+    if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&le->attribute->attestation,
+                                                 &attest->id))
+    {
+      struct GNUNET_RECLAIM_AttestationListEntry *ale;
+      ale = GNUNET_new (struct GNUNET_RECLAIM_AttestationListEntry);
+      ale->attestation = GNUNET_RECLAIM_attestation_new (attest->name,
+                                                         attest->type,
+                                                         attest->data,
+                                                         attest->data_size);
+      GNUNET_CONTAINER_DLL_insert (handle->attests_list->list_head,
+                                   handle->attests_list->list_tail,
+                                   ale);
+    }
+  }
+  GNUNET_RECLAIM_get_attestations_next (handle->attest_it);
+}
+
+
+static void
+oidc_attr_collect_finished_cb (void *cls)
 {
   struct RequestHandle *handle = cls;
 
@@ -963,6 +1030,17 @@ oidc_collect_finished_cb (void *cls)
     GNUNET_SCHEDULER_add_now (&do_redirect_error, handle);
     return;
   }
+  handle->attests_list = GNUNET_new (struct GNUNET_RECLAIM_AttestationList);
+  handle->attest_it =
+    GNUNET_RECLAIM_get_attestations_start (handle->idp,
+                                           &handle->priv_key,
+                                           &oidc_iteration_error,
+                                           handle,
+                                           &oidc_attest_collect,
+                                           handle,
+                                           &oidc_attest_collect_finished_cb,
+                                           handle);
+
   handle->idp_op = GNUNET_RECLAIM_ticket_issue (handle->idp,
                                                 &handle->priv_key,
                                                 &handle->oidc->client_pkey,
@@ -978,21 +1056,14 @@ oidc_collect_finished_cb (void *cls)
 static void
 oidc_attr_collect (void *cls,
                    const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
-                   const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
-                   const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest)
+                   const struct GNUNET_RECLAIM_Attribute *attr)
 {
   struct RequestHandle *handle = cls;
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
+  struct GNUNET_RECLAIM_AttributeListEntry *le;
   char *scope_variables;
   char *scope_variable;
   char delimiter[] = " ";
 
-  if ((NULL == attr->name) || (NULL == attr->data))
-  {
-    GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
-    return;
-  }
-
   scope_variables = GNUNET_strdup (handle->oidc->scope);
   scope_variable = strtok (scope_variables, delimiter);
   while (NULL != scope_variable)
@@ -1005,17 +1076,19 @@ oidc_attr_collect (void *cls,
   {
     GNUNET_RECLAIM_get_attributes_next (handle->attr_it);
     GNUNET_free (scope_variables);
+    // We can ignore this
     return;
   }
   GNUNET_free (scope_variables);
-
-  le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
-  le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name,
-                                                  attr->type,
-                                                  attr->data,
-                                                  attr->data_size);
-  le->claim->id = attr->id;
-  le->claim->version = attr->version;
+  le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
+  le->attribute = GNUNET_RECLAIM_attribute_new (attr->name,
+                                                &attr->attestation,
+                                                attr->type,
+                                                attr->data,
+                                                attr->data_size);
+  le->attribute->id = attr->id;
+  le->attribute->flag = attr->flag;
+  le->attribute->attestation = attr->attestation;
   GNUNET_CONTAINER_DLL_insert (handle->attr_list->list_head,
                                handle->attr_list->list_tail,
                                le);
@@ -1077,7 +1150,7 @@ code_redirect (void *cls)
             *GNUNET_IDENTITY_ego_get_private_key (handle->ego_entry->ego);
           handle->idp = GNUNET_RECLAIM_connect (cfg);
           handle->attr_list =
-            GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
+            GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
           handle->attr_it =
             GNUNET_RECLAIM_get_attributes_start (handle->idp,
                                                  &handle->priv_key,
@@ -1085,7 +1158,7 @@ code_redirect (void *cls)
                                                  handle,
                                                  &oidc_attr_collect,
                                                  handle,
-                                                 &oidc_collect_finished_cb,
+                                                 &oidc_attr_collect_finished_cb,
                                                  handle);
           return;
         }
@@ -1305,6 +1378,9 @@ build_authz_response (void *cls)
   // OPTIONAL value: nonce
   handle->oidc->nonce = get_url_parameter_copy (handle, OIDC_NONCE_KEY);
 
+  // OPTIONAL value: claims
+  handle->oidc->claims = get_url_parameter_copy (handle, OIDC_CLAIMS_KEY);
+
   // TODO check other values if needed
   number_of_ignored_parameter =
     sizeof(OIDC_ignored_parameter_array) / sizeof(char *);
@@ -1455,6 +1531,8 @@ authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
       handle->ego_entry = handle->ego_tail;
     }
   }
+  handle->oidc->scope = get_url_parameter_copy (handle, OIDC_SCOPE_KEY);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scope: %s\n", handle->oidc->scope);
   if (NULL == handle->tld)
     GNUNET_CONFIGURATION_iterate_section_values (cfg, "gns", tld_iter, handle);
   if (NULL == handle->tld)
@@ -1706,7 +1784,8 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
   struct RequestHandle *handle = cls;
   const struct EgoEntry *ego_entry;
   struct GNUNET_TIME_Relative expiration_time;
-  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *cl;
+  struct GNUNET_RECLAIM_AttributeList *cl = NULL;
+  struct GNUNET_RECLAIM_AttestationList *al = NULL;
   struct GNUNET_RECLAIM_Ticket ticket;
   struct GNUNET_CRYPTO_EcdsaPublicKey cid;
   const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
@@ -1794,7 +1873,7 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
 
   // decode code
   if (GNUNET_OK != OIDC_parse_authz_code (privkey, code, code_verifier, &ticket,
-                                          &cl, &nonce))
+                                          &cl, &al, &nonce))
   {
     handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST);
     handle->edesc = GNUNET_strdup ("invalid code");
@@ -1834,6 +1913,7 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
   id_token = OIDC_id_token_new (&ticket.audience,
                                 &ticket.identity,
                                 cl,
+                                al,
                                 &expiration_time,
                                 (NULL != nonce) ? nonce : NULL,
                                 jwt_secret);
@@ -1849,7 +1929,8 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
   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);
-  GNUNET_RECLAIM_ATTRIBUTE_list_destroy (cl);
+  GNUNET_RECLAIM_attribute_list_destroy (cl);
+  GNUNET_RECLAIM_attestation_list_destroy (al);
   GNUNET_free (access_token);
   GNUNET_free (json_response);
   GNUNET_free (id_token);
@@ -1863,24 +1944,87 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle,
 static void
 consume_ticket (void *cls,
                 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
-                const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr,
-                const struct GNUNET_RECLAIM_ATTESTATION_Claim *attest)
+                const struct GNUNET_RECLAIM_Attribute *attr,
+                const struct GNUNET_RECLAIM_Attestation *attest)
 {
   struct RequestHandle *handle = cls;
-  char *tmp_value;
-  json_t *value;
+  handle->idp_op = NULL;
 
   if (NULL == identity)
   {
     GNUNET_SCHEDULER_add_now (&return_userinfo_response, handle);
     return;
   }
-  tmp_value = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
-                                                        attr->data,
-                                                        attr->data_size);
-  value = json_string (tmp_value);
-  json_object_set_new (handle->oidc->response, attr->name, value);
-  GNUNET_free (tmp_value);
+  if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attr->attestation))
+  {
+    char *tmp_value;
+    json_t *value;
+    tmp_value = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
+                                                          attr->data,
+                                                          attr->data_size);
+    value = json_string (tmp_value);
+    json_object_set_new (handle->oidc->response, attr->name, value);
+    GNUNET_free (tmp_value);
+    return;
+  }
+  json_t *claim_sources;
+  json_t *claim_sources_jwt;
+  json_t *claim_names;
+  char *attest_val_str;
+  claim_sources = json_object_get (handle->oidc->response,"_claim_sources");
+  claim_names = json_object_get (handle->oidc->response,"_claim_names");
+  attest_val_str =
+    GNUNET_RECLAIM_attestation_value_to_string (attest->type,
+                                                attest->data,
+                                                attest->data_size);
+  if ((NULL == claim_sources) && (NULL == claim_names) )
+  {
+    claim_sources = json_object ();
+    claim_names = json_object ();
+  }
+  char *source_name;
+  int i = 0;
+  GNUNET_asprintf (&source_name, "src%d", i);
+  while (NULL != (claim_sources_jwt = json_object_get (claim_sources,
+                                                       source_name)))
+  {
+    if (0 == strcmp (json_string_value (json_object_get (claim_sources_jwt,
+                                                         "JWT")),
+                     attest_val_str))
+    {
+      // Adapt only the claim names
+      json_object_set_new (claim_names, attr->data,
+                           json_string (source_name));
+      json_object_set (handle->oidc->response,
+                       "_claim_names", claim_names);
+      break;
+    }
+    i++;
+    GNUNET_free (source_name);
+    GNUNET_asprintf (&source_name, "src%d", i);
+  }
+
+  // Create new one
+  if (NULL == claim_sources_jwt)
+  {
+    claim_sources_jwt = json_object ();
+    // Set the JWT for names
+    json_object_set_new (claim_names, attr->data,
+                         json_string (source_name));
+    // Set the JWT for the inner source
+    json_object_set_new (claim_sources_jwt, "JWT",
+                         json_string (attest_val_str));
+    // Set the JWT for the source
+    json_object_set_new (claim_sources, source_name, claim_sources_jwt);
+    // Set as claims
+    json_object_set (handle->oidc->response, "_claim_names", claim_names);
+    json_object_set (handle->oidc->response, "_claim_sources",claim_sources);
+  }
+
+  json_decref (claim_sources);
+  json_decref (claim_names);
+  json_decref (claim_sources_jwt);
+  GNUNET_free (attest_val_str);
 }
 
 
@@ -2117,13 +2261,16 @@ list_ego (void *cls,
     for (ego_entry = handle->ego_head; NULL != ego_entry;
          ego_entry = ego_entry->next)
     {
-      if (ego_entry->ego == ego)
-        break;
-    }
-    if (NULL != ego_entry)
+      if (ego_entry->ego != ego)
+        continue;
       GNUNET_CONTAINER_DLL_remove (handle->ego_head,
                                    handle->ego_tail,
                                    ego_entry);
+      GNUNET_free (ego_entry->identifier);
+      GNUNET_free (ego_entry->keystring);
+      GNUNET_free (ego_entry);
+      return;
+    }
   }
 }
 
@@ -2137,7 +2284,8 @@ rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
 
   handle->oidc = GNUNET_new (struct OIDC_Variables);
   if (NULL == OIDC_cookie_jar_map)
-    OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
+    OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10,
+                                                                GNUNET_NO);
   if (NULL == OIDC_access_token_map)
     OIDC_access_token_map =
       GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
@@ -2162,11 +2310,11 @@ rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle,
 
 
 /**
- * Entry point for the plugin.
- *
- * @param cls Config info
- * @return NULL on error, otherwise the plugin context
- */
  * Entry point for the plugin.
  *
  * @param cls Config info
  * @return NULL on error, otherwise the plugin context
  */
 void *
 libgnunet_plugin_rest_openid_connect_init (void *cls)
 {
@@ -2175,7 +2323,7 @@ libgnunet_plugin_rest_openid_connect_init (void *cls)
 
   cfg = cls;
   if (NULL != plugin.cfg)
-    return NULL; /* can only initialize once! */
+    return NULL;     /* can only initialize once! */
   memset (&plugin, 0, sizeof(struct Plugin));
   plugin.cfg = cfg;
   api = GNUNET_new (struct GNUNET_REST_Plugin);
@@ -2197,11 +2345,11 @@ libgnunet_plugin_rest_openid_connect_init (void *cls)
 
 
 /**
- * Exit point from the plugin.
- *
- * @param cls the plugin context (as returned by "init")
- * @return always NULL
- */
  * Exit point from the plugin.
  *
  * @param cls the plugin context (as returned by "init")
  * @return always NULL
  */
 void *
 libgnunet_plugin_rest_openid_connect_done (void *cls)
 {
@@ -2215,7 +2363,8 @@ libgnunet_plugin_rest_openid_connect_done (void *cls)
   hashmap_it =
     GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_cookie_jar_map);
   while (GNUNET_YES ==
-         GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
+         GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL,
+                                                      value))
     GNUNET_free_non_null (value);
   GNUNET_CONTAINER_multihashmap_iterator_destroy (hashmap_it);
   GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map);
@@ -2223,7 +2372,8 @@ libgnunet_plugin_rest_openid_connect_done (void *cls)
   hashmap_it =
     GNUNET_CONTAINER_multihashmap_iterator_create (OIDC_access_token_map);
   while (GNUNET_YES ==
-         GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL, value))
+         GNUNET_CONTAINER_multihashmap_iterator_next (hashmap_it, NULL,
+                                                      value))
     GNUNET_free_non_null (value);
   GNUNET_CONTAINER_multihashmap_destroy (OIDC_access_token_map);
   GNUNET_CONTAINER_multihashmap_iterator_destroy (hashmap_it);