diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/Makefile.am | 2 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd.c | 23 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd.h | 5 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_private-patch-instances-ID.c | 27 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c | 162 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_private-post-instances-ID-auth.h | 44 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_private-post-instances.c | 69 |
7 files changed, 286 insertions, 46 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 4c05db42..3dd126a6 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -66,6 +66,8 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-patch-products-ID.h \ taler-merchant-httpd_private-post-instances.c \ taler-merchant-httpd_private-post-instances.h \ + taler-merchant-httpd_private-post-instances-ID-auth.c \ + taler-merchant-httpd_private-post-instances-ID-auth.h \ taler-merchant-httpd_private-post-products.c \ taler-merchant-httpd_private-post-products.h \ taler-merchant-httpd_private-post-products-ID-lock.c \ diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index 7f9f8e3b..0690e621 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -49,6 +49,7 @@ #include "taler-merchant-httpd_private-patch-orders-ID-forget.h" #include "taler-merchant-httpd_private-patch-products-ID.h" #include "taler-merchant-httpd_private-post-instances.h" +#include "taler-merchant-httpd_private-post-instances-ID-auth.h" #include "taler-merchant-httpd_private-post-orders.h" #include "taler-merchant-httpd_private-post-orders-ID-refund.h" #include "taler-merchant-httpd_private-post-products.h" @@ -1053,6 +1054,14 @@ url_handler (void *cls, in the code... */ .max_upload = 1024 * 1024 * 8 }, + /* POST /auth: */ + { + .url_prefix = "/auth", + .method = MHD_HTTP_METHOD_POST, + .handler = &TMH_private_post_instances_ID_auth, + /* Body should be pretty small. */ + .max_upload = 1024 * 1024, + }, /* GET /products: */ { .url_prefix = "/products", @@ -1494,8 +1503,8 @@ url_handler (void *cls, { /* Override default instance access control */ TMH_compute_auth (default_auth, - &hc->instance->settings.auth_salt, - &hc->instance->settings.auth_hash); + &hc->instance->auth.auth_salt, + &hc->instance->auth.auth_hash); GNUNET_free (default_auth); } } @@ -1677,8 +1686,8 @@ url_handler (void *cls, (NULL == default_auth) ) auth_ok = (GNUNET_OK == TMH_check_auth (auth, - &def_instance->settings.auth_salt, - &def_instance->settings.auth_hash)); + &def_instance->auth.auth_salt, + &def_instance->auth.auth_hash)); /* Only permit 'default' auth if we are either working with the default instance OR patching/deleting an instance OR have no instance */ if ( (hc->rh->handler != &TMH_private_patch_instances_ID) && @@ -1691,8 +1700,8 @@ url_handler (void *cls, if (NULL != hc->instance) auth_ok |= (GNUNET_OK == TMH_check_auth (auth, - &hc->instance->settings.auth_salt, - &hc->instance->settings.auth_hash)); + &hc->instance->auth.auth_salt, + &hc->instance->auth.auth_hash)); if (! auth_ok) { if (auth_malformed) @@ -1777,6 +1786,7 @@ add_instance_cb (void *cls, const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_MerchantPrivateKeyP *merchant_priv, const struct TALER_MERCHANTDB_InstanceSettings *is, + const struct TALER_MERCHANTDB_InstanceAuthSettings *ias, unsigned int accounts_length, const struct TALER_MERCHANTDB_AccountDetails accounts[]) { @@ -1786,6 +1796,7 @@ add_instance_cb (void *cls, GNUNET_assert (NULL != merchant_priv); mi = GNUNET_new (struct TMH_MerchantInstance); mi->settings = *is; + mi->auth = *ias; mi->settings.id = GNUNET_strdup (mi->settings.id); mi->settings.name = GNUNET_strdup (mi->settings.name); mi->settings.address = json_incref (mi->settings.address); diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h index 50badbb1..7cb3c836 100644 --- a/src/backend/taler-merchant-httpd.h +++ b/src/backend/taler-merchant-httpd.h @@ -133,6 +133,11 @@ struct TMH_MerchantInstance struct TALER_MERCHANTDB_InstanceSettings settings; /** + * General settings for an instance. + */ + struct TALER_MERCHANTDB_InstanceAuthSettings auth; + + /** * Reference counter on this structure. Only destroyed if the * counter hits zero. */ diff --git a/src/backend/taler-merchant-httpd_private-patch-instances-ID.c b/src/backend/taler-merchant-httpd_private-patch-instances-ID.c index 637ded04..edda6228 100644 --- a/src/backend/taler-merchant-httpd_private-patch-instances-ID.c +++ b/src/backend/taler-merchant-httpd_private-patch-instances-ID.c @@ -63,14 +63,10 @@ TMH_private_patch_instances_ID (const struct TMH_RequestHandler *rh, struct TMH_MerchantInstance *mi = hc->instance; struct TALER_MERCHANTDB_InstanceSettings is; json_t *payto_uris; - const char *auth_token = NULL; const char *name; struct TMH_WireMethod *wm_head = NULL; struct TMH_WireMethod *wm_tail = NULL; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("auth_token", - &auth_token)), GNUNET_JSON_spec_json ("payto_uris", &payto_uris), GNUNET_JSON_spec_string ("name", @@ -149,14 +145,6 @@ TMH_private_patch_instances_ID (const struct TMH_RequestHandler *rh, /* Check for equality of settings */ if (! ( (0 == strcmp (mi->settings.name, name)) && - ( ( (NULL != auth_token) && - (GNUNET_OK == - TMH_check_auth (auth_token, - &mi->settings.auth_salt, - &mi->settings.auth_hash)) ) || - ( (NULL == auth_token) && - (GNUNET_YES == - GNUNET_is_zero (&mi->settings.auth_hash))) ) && (1 == json_equal (mi->settings.address, is.address)) && (1 == json_equal (mi->settings.jurisdiction, @@ -404,21 +392,6 @@ giveup: json_decref (mi->settings.address); json_decref (mi->settings.jurisdiction); is.id = mi->settings.id; - if (NULL == auth_token) - { - memset (&is.auth_salt, - 0, - sizeof (is.auth_salt)); - memset (&is.auth_hash, - 0, - sizeof (is.auth_hash)); - } - else - { - TMH_compute_auth (auth_token, - &is.auth_salt, - &is.auth_hash); - } mi->settings = is; mi->settings.address = json_incref (mi->settings.address); mi->settings.jurisdiction = json_incref (mi->settings.jurisdiction); 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 new file mode 100644 index 00000000..8d8df93f --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c @@ -0,0 +1,162 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems SA + + GNU Taler is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-merchant-httpd_private-post-instances-ID-auth.c + * @brief implementing POST /instances/$ID/auth request handling + * @author Christian Grothoff + * @author Florian Dold + */ +#include "platform.h" +#include "taler-merchant-httpd_private-post-instances-ID-auth.h" +#include <taler/taler_json_lib.h> + + +/** + * How often do we retry the simple INSERT database transaction? + */ +#define MAX_RETRIES 3 + + +/** + * Change the authentication settings of an instance. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_post_instances_ID_auth (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct TALER_MERCHANTDB_InstanceAuthSettings ias; + const char *auth_token = NULL; + struct TMH_MerchantInstance *mi = hc->instance; + json_t *jauth = hc->request_body; + + { + bool auth_ok = false; + const char *auth_method = json_string_value (json_object_get (jauth, + "method")); + + 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))) + GNUNET_break_op (0); + else + 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"); + } + } + + if (NULL == auth_token) + { + memset (&ias.auth_salt, + 0, + sizeof (ias.auth_salt)); + memset (&ias.auth_hash, + 0, + sizeof (ias.auth_hash)); + } + else + { + TMH_compute_auth (auth_token, + &ias.auth_salt, + &ias.auth_hash); + } + + { + enum GNUNET_DB_QueryStatus qs; + + for (unsigned int i = 0; i<MAX_RETRIES; i++) + { + if (GNUNET_OK != + TMH_db->start (TMH_db->cls, + "post /instances/$ID/auth")) + { + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_START_FAILED, + NULL); + } + qs = TMH_db->update_instance_auth (TMH_db->cls, + mi->settings.id, + &ias); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) + { + 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); + goto retry; + } + qs = TMH_db->commit (TMH_db->cls); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; +retry: + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + break; /* success! -- or hard failure */ + } /* for .. MAX_RETRIES */ + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) + { + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_COMMIT_FAILED, + NULL); + } + /* Finally, also update our running process */ + mi->auth = ias; + } + return TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); +} + +/* end of taler-merchant-httpd_private-post-instances-ID-auth.c */ diff --git a/src/backend/taler-merchant-httpd_private-post-instances-ID-auth.h b/src/backend/taler-merchant-httpd_private-post-instances-ID-auth.h new file mode 100644 index 00000000..3a47c42c --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-post-instances-ID-auth.h @@ -0,0 +1,44 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems SA + + GNU Taler is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-merchant-httpd_private-post-instances-ID-auth.h + * @brief implements POST /instances/$ID/auth request handling + * @author Christian Grothoff + * @author Florian Dold + */ +#ifndef TALER_MERCHANT_HTTPD_PRIVATE_POST_INSTANCES_ID_AUTH_H +#define TALER_MERCHANT_HTTPD_PRIVATE_POST_INSTANCES_ID_AUTH_H +#include "taler-merchant-httpd.h" + + +/** + * Change the instance's auth settings. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_post_instances_ID_auth (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); + +#endif diff --git a/src/backend/taler-merchant-httpd_private-post-instances.c b/src/backend/taler-merchant-httpd_private-post-instances.c index c4d1d617..88a51a26 100644 --- a/src/backend/taler-merchant-httpd_private-post-instances.c +++ b/src/backend/taler-merchant-httpd_private-post-instances.c @@ -141,14 +141,15 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh, struct TMH_HandlerContext *hc) { struct TALER_MERCHANTDB_InstanceSettings is; + struct TALER_MERCHANTDB_InstanceAuthSettings ias; json_t *payto_uris; const char *auth_token = NULL; struct TMH_WireMethod *wm_head = NULL; struct TMH_WireMethod *wm_tail = NULL; + json_t *jauth; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("auth_token", - &auth_token)), + GNUNET_JSON_spec_json ("auth", + &jauth), GNUNET_JSON_spec_json ("payto_uris", &payto_uris), GNUNET_JSON_spec_string ("id", @@ -184,6 +185,47 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh, : MHD_NO; } + + { + bool auth_ok = false; + const char *auth_method = json_string_value (json_object_get (jauth, + "method")); + + 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))) + GNUNET_break_op (0); + else + auth_ok = true; + } + else + GNUNET_break_op (0); + } + + if (! auth_ok) + { + 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"); + } + } + + if ((0 != strcasecmp (is.default_max_deposit_fee.currency, TMH_currency)) || (0 != strcasecmp (is.default_max_wire_fee.currency, @@ -212,11 +254,11 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh, ( ( (NULL != auth_token) && (GNUNET_OK == TMH_check_auth (auth_token, - &mi->settings.auth_salt, - &mi->settings.auth_hash)) ) || + &mi->auth.auth_salt, + &mi->auth.auth_hash)) ) || ( (NULL == auth_token) && (GNUNET_YES == - GNUNET_is_zero (&mi->settings.auth_hash))) ) && + GNUNET_is_zero (&mi->auth.auth_hash))) ) && (1 == json_equal (mi->settings.address, is.address)) && (1 == json_equal (mi->settings.jurisdiction, @@ -357,18 +399,18 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh, if (NULL == auth_token) { - memset (&is.auth_salt, + memset (&ias.auth_salt, 0, - sizeof (is.auth_salt)); - memset (&is.auth_hash, + sizeof (ias.auth_salt)); + memset (&ias.auth_hash, 0, - sizeof (is.auth_hash)); + sizeof (ias.auth_hash)); } else { TMH_compute_auth (auth_token, - &is.auth_salt, - &is.auth_hash); + &ias.auth_salt, + &ias.auth_hash); } { struct TMH_MerchantInstance *mi; @@ -402,7 +444,8 @@ TMH_private_post_instances (const struct TMH_RequestHandler *rh, qs = TMH_db->insert_instance (TMH_db->cls, &mi->merchant_pub, &mi->merchant_priv, - &mi->settings); + &mi->settings, + &mi->auth); if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); |