diff options
author | Florian Dold <florian@dold.me> | 2021-07-20 20:52:58 +0200 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2021-07-20 20:52:58 +0200 |
commit | 1e257c787a4344f242fd941dbfcdb957c7be4ba0 (patch) | |
tree | fa3b1db2e00cb7d088a958538b49cd17537660b4 /src | |
parent | 9a89fbb3440325344e8029340ce409ba9418dc3d (diff) |
instance auth: refactor, make it serializable
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/taler-merchant-httpd.c | 1 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd.h | 9 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_helper.c | 50 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_helper.h | 8 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c | 114 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_private-post-instances.c | 48 | ||||
-rw-r--r-- | src/backenddb/plugin_merchantdb_postgres.c | 3 |
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) |