gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] branch master updated: instance auth: refactor, make it


From: gnunet
Subject: [taler-merchant] branch master updated: instance auth: refactor, make it serializable
Date: Tue, 20 Jul 2021 20:53:04 +0200

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

dold pushed a commit to branch master
in repository merchant.

The following commit(s) were added to refs/heads/master by this push:
     new 1e257c78 instance auth: refactor, make it serializable
1e257c78 is described below

commit 1e257c787a4344f242fd941dbfcdb957c7be4ba0
Author: Florian Dold <florian@dold.me>
AuthorDate: Tue Jul 20 20:52:58 2021 +0200

    instance auth: refactor, make it serializable
---
 contrib/merchant-backoffice                        |   2 +-
 src/backend/taler-merchant-httpd.c                 |   1 +
 src/backend/taler-merchant-httpd.h                 |   9 ++
 src/backend/taler-merchant-httpd_helper.c          |  50 +++++++++
 src/backend/taler-merchant-httpd_helper.h          |   8 ++
 ...merchant-httpd_private-post-instances-ID-auth.c | 114 +++++++++++++--------
 .../taler-merchant-httpd_private-post-instances.c  |  48 ++-------
 src/backenddb/plugin_merchantdb_postgres.c         |   3 +
 8 files changed, 148 insertions(+), 87 deletions(-)

diff --git a/contrib/merchant-backoffice b/contrib/merchant-backoffice
index 1732185a..4320467d 160000
--- a/contrib/merchant-backoffice
+++ b/contrib/merchant-backoffice
@@ -1 +1 @@
-Subproject commit 1732185ac1d1dcc783b8f2489f2ce333b5254d92
+Subproject commit 4320467db1392e5f48a4acd079f7e2a253cf9984
diff --git a/src/backend/taler-merchant-httpd.c 
b/src/backend/taler-merchant-httpd.c
index 861b5f47..58f82f35 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -1916,6 +1916,7 @@ url_handler (void *cls,
       extract_token (&auth);
       if (NULL == auth)
         auth_malformed = true;
+      hc->auth_token = auth;
     }
 
     /* If we have zero configured instances (not even ones that have been
diff --git a/src/backend/taler-merchant-httpd.h 
b/src/backend/taler-merchant-httpd.h
index 29a67acc..03e62d2c 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -322,6 +322,15 @@ struct TMH_HandlerContext
    */
   const char *url;
 
+  /**
+   * Client-provided authentication token for this
+   * request, can be NULL.
+   *
+   * Used to check for concurrent, conflicting updates of
+   * the authentication information in the database.
+   */
+  const char *auth_token;
+
   /**
    * Infix part of @a url.
    */
diff --git a/src/backend/taler-merchant-httpd_helper.c 
b/src/backend/taler-merchant-httpd_helper.c
index 30ff4a90..fb0cf318 100644
--- a/src/backend/taler-merchant-httpd_helper.c
+++ b/src/backend/taler-merchant-httpd_helper.c
@@ -104,3 +104,53 @@ TMH_setup_wire_account (const char *payto_uri)
   wm->active = true;
   return wm;
 }
+
+enum GNUNET_GenericReturnValue
+TMH_check_auth_config (struct MHD_Connection *connection,
+                       const json_t *jauth,
+                       const char **auth_token)
+{
+  bool auth_wellformed = false;
+  const char *auth_method = json_string_value (json_object_get (jauth,
+                                                                "method"));
+  *auth_token = NULL;
+  if (NULL == auth_method)
+  {
+    GNUNET_break_op (0);
+  }
+  else if (0 == strcmp (auth_method,
+                        "external"))
+  {
+    auth_wellformed = true;
+  }
+  else if (0 == strcmp (auth_method,
+                        "token"))
+  {
+    *auth_token = json_string_value (json_object_get (jauth,
+                                                      "token"));
+    if (NULL == *auth_token)
+    {
+      GNUNET_break_op (0);
+    }
+    else
+    {
+      if (0 != strncasecmp (RFC_8959_PREFIX,
+                            *auth_token,
+                            strlen (RFC_8959_PREFIX)))
+        GNUNET_break_op (0);
+      else
+        auth_wellformed = true;
+    }
+  }
+
+  if (! auth_wellformed)
+  {
+    GNUNET_break_op (0);
+    return (MHD_YES ==
+            TALER_MHD_reply_with_error (connection,
+                                        MHD_HTTP_BAD_REQUEST,
+                                        
TALER_EC_MERCHANT_PRIVATE_POST_INSTANCES_BAD_AUTH,
+                                        "bad authentication config")) ? 
GNUNET_NO : GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
diff --git a/src/backend/taler-merchant-httpd_helper.h 
b/src/backend/taler-merchant-httpd_helper.h
index 5f478c18..d15ef2e0 100644
--- a/src/backend/taler-merchant-httpd_helper.h
+++ b/src/backend/taler-merchant-httpd_helper.h
@@ -46,5 +46,13 @@ TMH_payto_uri_array_valid (const json_t *payto_uris);
 struct TMH_WireMethod *
 TMH_setup_wire_account (const char *payto_uri);
 
+/**
+ * FIXME: document
+ */
+enum GNUNET_GenericReturnValue
+TMH_check_auth_config (struct MHD_Connection *connection,
+                       const json_t *jauth,
+                       const char **auth_token);
+
 
 #endif
diff --git a/src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c 
b/src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c
index 93b0f784..17316348 100644
--- a/src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c
+++ b/src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c
@@ -25,6 +25,7 @@
  */
 #include "platform.h"
 #include "taler-merchant-httpd_private-post-instances-ID-auth.h"
+#include "taler-merchant-httpd_helper.h"
 #include <taler/taler_json_lib.h>
 
 
@@ -52,44 +53,13 @@ post_instances_ID_auth (struct TMH_MerchantInstance *mi,
   json_t *jauth = hc->request_body;
 
   {
-    bool auth_ok = false;
-    const char *auth_method = json_string_value (json_object_get (jauth,
-                                                                  "method"));
+    enum GNUNET_GenericReturnValue ret;
 
-    if (NULL == auth_method)
-    {
-      GNUNET_break_op (0);
-    }
-    else if (0 == strcmp (auth_method,
-                          "external"))
-    {
-      auth_token = NULL;
-      auth_ok = true;
-    }
-    else if (0 == strcmp (auth_method,
-                          "token"))
-    {
-      auth_token = json_string_value (json_object_get (jauth,
-                                                       "token"));
-      if (NULL != auth_token)
-      {
-        if (0 == strncasecmp (RFC_8959_PREFIX,
-                              auth_token,
-                              strlen (RFC_8959_PREFIX)))
-          auth_ok = true;
-      }
-      else
-        GNUNET_break_op (0);
-    }
-
-    if (! auth_ok)
-    {
-      GNUNET_break_op (0);
-      return TALER_MHD_reply_with_error (connection,
-                                         MHD_HTTP_BAD_REQUEST,
-                                         
TALER_EC_MERCHANT_PRIVATE_POST_INSTANCE_AUTH_BAD_AUTH,
-                                         "bad authentication config");
-    }
+    ret = TMH_check_auth_config (connection,
+                                 jauth,
+                                 &auth_token);
+    if (GNUNET_OK != ret)
+      return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
   }
 
   if (NULL == auth_token)
@@ -108,6 +78,7 @@ post_instances_ID_auth (struct TMH_MerchantInstance *mi,
                       &ias.auth_hash);
   }
 
+  /* Store the new auth information in the database */
   {
     enum GNUNET_DB_QueryStatus qs;
 
@@ -122,6 +93,55 @@ post_instances_ID_auth (struct TMH_MerchantInstance *mi,
                                            TALER_EC_GENERIC_DB_START_FAILED,
                                            NULL);
       }
+
+      /* Make the authentication update a serializable operation.
+         We first check that the authentication information
+         that the caller's request authenticated with
+         is still up to date.
+         Otherwise, we've detected a conflicting update
+         to the authentication. */
+      {
+        struct TALER_MERCHANTDB_InstanceAuthSettings db_ias;
+        qs = TMH_db->lookup_instance_auth (TMH_db->cls,
+                                           mi->settings.id,
+                                           &db_ias);
+
+        switch (qs)
+        {
+          case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+            /* Instance got purged. */
+            TMH_db->rollback (TMH_db->cls);
+            return TALER_MHD_reply_with_error (connection,
+                                              MHD_HTTP_UNAUTHORIZED,
+                                              
TALER_EC_GENERIC_DB_COMMIT_FAILED,
+                                              NULL);
+          case GNUNET_DB_STATUS_SOFT_ERROR:
+            TMH_db->rollback (TMH_db->cls);
+            goto retry;
+          case GNUNET_DB_STATUS_HARD_ERROR:
+            TMH_db->rollback (TMH_db->cls);
+            return TALER_MHD_reply_with_error (connection,
+                                             MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                             TALER_EC_GENERIC_DB_FETCH_FAILED,
+                                             NULL);
+          case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+            /* Success! */
+            break;
+        }
+
+        if (GNUNET_OK !=
+            TMH_check_auth (hc->auth_token,
+                            &db_ias.auth_salt,
+                            &db_ias.auth_hash))
+        {
+          TMH_db->rollback (TMH_db->cls);
+          return TALER_MHD_reply_with_error (connection,
+                                             MHD_HTTP_UNAUTHORIZED,
+                                             
TALER_EC_MERCHANT_GENERIC_UNAUTHORIZED,
+                                             NULL);
+        }
+      }
+
       qs = TMH_db->update_instance_auth (TMH_db->cls,
                                          mi->settings.id,
                                          &ias);
@@ -129,12 +149,13 @@ post_instances_ID_auth (struct TMH_MerchantInstance *mi,
       {
         GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
         TMH_db->rollback (TMH_db->cls);
-        goto retry;
-      }
-      if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
-      {
-        GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
-        TMH_db->rollback (TMH_db->cls);
+        if (GNUNET_DB_STATUS_HARD_ERROR == qs)
+        {
+          return TALER_MHD_reply_with_error (connection,
+                                             MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                             TALER_EC_GENERIC_DB_FETCH_FAILED,
+                                             NULL);
+        }
         goto retry;
       }
       qs = TMH_db->commit (TMH_db->cls);
@@ -156,7 +177,12 @@ retry:
   }
   if (0 == strcmp (mi->settings.id,
                    "default"))
-    GNUNET_free (TMH_default_auth); /* clear after it was manually set */
+  {
+    /* The default auth string should've been
+       cleared with the first request
+       for the default instance. */
+    GNUNET_assert (NULL == TMH_default_auth);
+  }
   return TALER_MHD_reply_static (connection,
                                  MHD_HTTP_NO_CONTENT,
                                  NULL,
diff --git a/src/backend/taler-merchant-httpd_private-post-instances.c 
b/src/backend/taler-merchant-httpd_private-post-instances.c
index 71739c3d..4c5919e9 100644
--- a/src/backend/taler-merchant-httpd_private-post-instances.c
+++ b/src/backend/taler-merchant-httpd_private-post-instances.c
@@ -189,49 +189,13 @@ TMH_private_post_instances (const struct 
TMH_RequestHandler *rh,
   }
 
   {
-    bool auth_wellformed = false;
-    const char *auth_method = json_string_value (json_object_get (jauth,
-                                                                  "method"));
+    enum GNUNET_GenericReturnValue ret;
 
-    if (NULL == auth_method)
-    {
-      GNUNET_break_op (0);
-    }
-    else if (0 == strcmp (auth_method,
-                          "external"))
-    {
-      auth_token = NULL;
-      auth_wellformed = true;
-    }
-    else if (0 == strcmp (auth_method,
-                          "token"))
-    {
-      auth_token = json_string_value (json_object_get (jauth,
-                                                       "token"));
-      if (NULL == auth_token)
-      {
-        GNUNET_break_op (0);
-      }
-      else
-      {
-        if (0 != strncasecmp (RFC_8959_PREFIX,
-                              auth_token,
-                              strlen (RFC_8959_PREFIX)))
-          GNUNET_break_op (0);
-        else
-          auth_wellformed = true;
-      }
-    }
-
-    if (! auth_wellformed)
-    {
-      GNUNET_break_op (0);
-      GNUNET_JSON_parse_free (spec);
-      return TALER_MHD_reply_with_error (connection,
-                                         MHD_HTTP_BAD_REQUEST,
-                                         
TALER_EC_MERCHANT_PRIVATE_POST_INSTANCES_BAD_AUTH,
-                                         "bad authentication config");
-    }
+    ret = TMH_check_auth_config (connection,
+                                 jauth,
+                                 &auth_token);
+    if (GNUNET_OK != ret)
+      return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
   }
 
   /* check payto_uris for well-formedness */
diff --git a/src/backenddb/plugin_merchantdb_postgres.c 
b/src/backenddb/plugin_merchantdb_postgres.c
index 2327b16c..86e30d0b 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -3640,6 +3640,7 @@ RETRY:
                                              params);
     if (0 > qs)
     {
+      /* FIXME: distinguish hard error */
       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
       postgres_rollback (pg);
       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
@@ -3681,6 +3682,7 @@ RETRY:
                                              params);
     if (0 > qs)
     {
+      /* FIXME: distinguish hard error */
       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
       postgres_rollback (pg);
       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
@@ -3710,6 +3712,7 @@ RETRY:
                                              params);
     if (0 > qs)
     {
+      /* FIXME: distinguish hard error */
       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
       postgres_rollback (pg);
       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

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