aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-07-20 20:52:58 +0200
committerFlorian Dold <florian@dold.me>2021-07-20 20:52:58 +0200
commit1e257c787a4344f242fd941dbfcdb957c7be4ba0 (patch)
treefa3b1db2e00cb7d088a958538b49cd17537660b4 /src
parent9a89fbb3440325344e8029340ce409ba9418dc3d (diff)
instance auth: refactor, make it serializable
Diffstat (limited to 'src')
-rw-r--r--src/backend/taler-merchant-httpd.c1
-rw-r--r--src/backend/taler-merchant-httpd.h9
-rw-r--r--src/backend/taler-merchant-httpd_helper.c50
-rw-r--r--src/backend/taler-merchant-httpd_helper.h8
-rw-r--r--src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c114
-rw-r--r--src/backend/taler-merchant-httpd_private-post-instances.c48
-rw-r--r--src/backenddb/plugin_merchantdb_postgres.c3
7 files changed, 147 insertions, 86 deletions
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
@@ -323,6 +323,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.
*/
char *infix;
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)