summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-03-04 10:40:50 +0100
committerChristian Grothoff <christian@grothoff.org>2021-03-04 10:40:50 +0100
commitc2a9a820522f8f44505ecf5a46149515c6a87a03 (patch)
tree4be9c43a4c525fc2e9b4ea13703badad237a4b22
parent1e6bd4db09bebef2f65a88829d4637cd3017adb1 (diff)
parent950f7cd53ef2457494ea98a06be667f06cd3f1e8 (diff)
downloadmerchant-c2a9a820522f8f44505ecf5a46149515c6a87a03.tar.gz
merchant-c2a9a820522f8f44505ecf5a46149515c6a87a03.tar.bz2
merchant-c2a9a820522f8f44505ecf5a46149515c6a87a03.zip
Merge branch 'master' of git+ssh://git.taler.net/merchant
-rw-r--r--.gitignore1
-rw-r--r--src/.gitignore3
-rw-r--r--src/backend/Makefile.am2
-rw-r--r--src/backend/taler-merchant-httpd.c81
-rw-r--r--src/backend/taler-merchant-httpd.h5
-rw-r--r--src/backend/taler-merchant-httpd_private-get-instances-ID.c9
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-instances-ID.c27
-rw-r--r--src/backend/taler-merchant-httpd_private-post-instances-ID-auth.c162
-rw-r--r--src/backend/taler-merchant-httpd_private-post-instances-ID-auth.h44
-rw-r--r--src/backend/taler-merchant-httpd_private-post-instances.c69
-rw-r--r--src/backenddb/plugin_merchantdb_postgres.c64
-rw-r--r--src/backenddb/test_merchantdb.c6
-rw-r--r--src/include/platform.h2
-rw-r--r--src/include/taler_merchant_service.h2
-rw-r--r--src/include/taler_merchant_testing_lib.h2
-rw-r--r--src/include/taler_merchantdb_plugin.h45
-rw-r--r--src/lib/merchant_api_patch_instance.c18
-rw-r--r--src/lib/merchant_api_post_instances.c27
-rw-r--r--src/testing/Makefile.am7
-rwxr-xr-xsrc/testing/test-merchant-walletharness.sh18
-rw-r--r--src/testing/test_merchant_api.c9
-rw-r--r--src/testing/testing_api_cmd_patch_instance.c8
22 files changed, 480 insertions, 131 deletions
diff --git a/.gitignore b/.gitignore
index f40449cf..90301629 100644
--- a/.gitignore
+++ b/.gitignore
@@ -80,3 +80,4 @@ doc/stamp-?
doc/stamp-vti
doc/mdate-sh
doc/texinfo.tex
+.private-key
diff --git a/src/.gitignore b/src/.gitignore
index 90ea1a04..4f49c073 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -6,4 +6,5 @@
*.log
*.trs
*/__pycache__
-test-* \ No newline at end of file
+test-*
+!test-*.sh
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 45d7ed07..5519f517 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"
@@ -774,6 +775,7 @@ handle_mhd_completion_callback (void *cls,
if (NULL == hc)
return;
+ GNUNET_SCHEDULER_begin_async_scope (&hc->async_scope_id);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Finished handling request for `%s' with MHD termination code %d\n",
hc->url,
@@ -786,6 +788,9 @@ handle_mhd_completion_callback (void *cls,
json_decref (hc->request_body);
if (NULL != hc->instance)
TMH_instance_decref (hc->instance);
+ memset (&hc->async_scope_id,
+ 0,
+ sizeof (struct GNUNET_AsyncScopeId));
GNUNET_free (hc);
*con_cls = NULL;
}
@@ -955,6 +960,35 @@ TMH_add_instance (struct TMH_MerchantInstance *mi)
return ret;
}
+/**
+ * Extract the token from authorization header value @a auth.
+ *
+ * @param auth pointer to authorization header value,
+ * will be updated to point to the start of the token
+ * or set to NULL if header value is invalid
+ */
+static void
+extract_token (const char **auth)
+{
+ const char *bearer = "Bearer ";
+ const char *tok = *auth;
+ if (0 != strncmp (tok, bearer, strlen (bearer)))
+ {
+ *auth = NULL;
+ return;
+ }
+ tok = tok + strlen (bearer);
+ while (' ' == *tok)
+ tok++;
+ if (0 != strncasecmp (tok,
+ RFC_8959_PREFIX,
+ strlen (RFC_8959_PREFIX)))
+ {
+ *auth = NULL;
+ return;
+ }
+ *auth = tok;
+}
/**
* A client has requested the given url using the given method
@@ -1049,6 +1083,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",
@@ -1490,8 +1532,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);
}
}
@@ -1508,6 +1550,7 @@ url_handler (void *cls,
{
handlers = private_handlers;
url += strlen (private_prefix) - 1;
+ use_private = true;
}
else
{
@@ -1641,23 +1684,15 @@ url_handler (void *cls,
MHD_HTTP_HEADER_AUTHORIZATION);
if (NULL != auth)
{
- if (0 != strncasecmp (auth,
- RFC_8959_PREFIX,
- strlen (RFC_8959_PREFIX)))
- {
- /* We _only_ complain about malformed auth headers if
- authorization was truly required (#6737). This helps
- in case authorization was disabled in the backend
- because some reverse proxy is already doing it, and
- then that reverse proxy may forward malformed auth
- headers to the backend. */
+ /* We _only_ complain about malformed auth headers if
+ authorization was truly required (#6737). This helps
+ in case authorization was disabled in the backend
+ because some reverse proxy is already doing it, and
+ then that reverse proxy may forward malformed auth
+ headers to the backend. */
+ extract_token (&auth);
+ if (NULL == auth)
auth_malformed = true;
- auth = NULL;
- }
- else
- {
- auth += strlen (RFC_8959_PREFIX);
- }
}
/* Are the credentials provided OK for the default instance?
@@ -1673,8 +1708,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) &&
@@ -1687,8 +1722,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)
@@ -1773,6 +1808,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[])
{
@@ -1782,6 +1818,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-get-instances-ID.c b/src/backend/taler-merchant-httpd_private-get-instances-ID.c
index a7bea350..8f392393 100644
--- a/src/backend/taler-merchant-httpd_private-get-instances-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-instances-ID.c
@@ -68,7 +68,8 @@ TMH_private_get_instances_ID (const struct TMH_RequestHandler *rh,
connection,
MHD_HTTP_OK,
"{s:o, s:s, s:o, s:O, s:O,"
- " s:o, s:o, s:I, s:o, s:o}",
+ " s:o, s:o, s:I, s:o, s:o,"
+ " s:{ s:s } }",
"accounts",
ja,
"name",
@@ -95,7 +96,11 @@ TMH_private_get_instances_ID (const struct TMH_RequestHandler *rh,
mi->settings.default_wire_transfer_delay),
"default_pay_delay",
GNUNET_JSON_from_time_rel (
- mi->settings.default_pay_delay));
+ mi->settings.default_pay_delay),
+ /* end of second group of 5 */
+ "auth",
+ "method",
+ GNUNET_is_zero (mi->auth.auth_hash.bits) ? "external" : "token");
}
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);
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c
index 616172f1..a1b659db 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -343,6 +343,11 @@ struct LookupInstancesContext
struct TALER_MERCHANTDB_InstanceSettings is;
/**
+ * Instance authentication settings, valid only during find_instances_cb().
+ */
+ struct TALER_MERCHANTDB_InstanceAuthSettings ias;
+
+ /**
* Instance serial number, valid only during find_instances_cb().
*/
uint64_t instance_serial;
@@ -407,6 +412,7 @@ call_with_accounts (struct LookupInstancesContext *lic,
&lic->merchant_pub,
(0 == qs) ? NULL : &merchant_priv,
&lic->is,
+ &lic->ias,
num_accounts,
accounts);
}
@@ -493,11 +499,11 @@ lookup_instances_cb (void *cls,
&lic->merchant_pub),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("auth_hash",
- &lic->is.auth_hash),
+ &lic->ias.auth_hash),
&no_auth),
GNUNET_PQ_result_spec_allow_null (
GNUNET_PQ_result_spec_auto_from_type ("auth_salt",
- &lic->is.auth_salt),
+ &lic->ias.auth_salt),
&no_salt),
GNUNET_PQ_result_spec_string ("merchant_id",
&lic->is.id),
@@ -524,12 +530,12 @@ lookup_instances_cb (void *cls,
GNUNET_PQ_query_param_end
};
- memset (&lic->is.auth_salt,
+ memset (&lic->ias.auth_salt,
0,
- sizeof (lic->is.auth_salt));
- memset (&lic->is.auth_hash,
+ sizeof (lic->ias.auth_salt));
+ memset (&lic->ias.auth_hash,
0,
- sizeof (lic->is.auth_hash));
+ sizeof (lic->ias.auth_hash));
if (GNUNET_OK !=
GNUNET_PQ_extract_result (result,
rs,
@@ -610,13 +616,14 @@ static enum GNUNET_DB_QueryStatus
postgres_insert_instance (void *cls,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_MerchantPrivateKeyP *merchant_priv,
- const struct TALER_MERCHANTDB_InstanceSettings *is)
+ const struct TALER_MERCHANTDB_InstanceSettings *is,
+ const struct TALER_MERCHANTDB_InstanceAuthSettings *ias)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (&is->auth_hash),
- GNUNET_PQ_query_param_auto_from_type (&is->auth_salt),
+ GNUNET_PQ_query_param_auto_from_type (&ias->auth_hash),
+ GNUNET_PQ_query_param_auto_from_type (&ias->auth_salt),
GNUNET_PQ_query_param_string (is->id),
GNUNET_PQ_query_param_string (is->name),
TALER_PQ_query_param_json (is->address),
@@ -753,6 +760,31 @@ postgres_update_instance (void *cls,
GNUNET_PQ_query_param_relative_time (
&is->default_wire_transfer_delay),
GNUNET_PQ_query_param_relative_time (&is->default_pay_delay),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "update_instance",
+ params);
+}
+
+/**
+ * Update information about an instance's authentication settings
+ * into our database.
+ *
+ * @param cls closure
+ * @param ias details about the instance
+ * @return database result code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_update_instance_auth (void *cls,
+ const char *merchant_id,
+ const struct TALER_MERCHANTDB_InstanceAuthSettings *is)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (merchant_id),
GNUNET_PQ_query_param_auto_from_type (&is->auth_hash),
GNUNET_PQ_query_param_auto_from_type (&is->auth_salt),
GNUNET_PQ_query_param_end
@@ -760,7 +792,7 @@ postgres_update_instance (void *cls,
check_connection (pg);
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "update_instance",
+ "update_instance_auth",
params);
}
@@ -6149,10 +6181,15 @@ postgres_connect (void *cls)
",default_wire_fee_amortization=$9"
",default_wire_transfer_delay=$10"
",default_pay_delay=$11"
- ",auth_hash=$12"
- ",auth_salt=$13"
" WHERE merchant_id = $1",
- 13),
+ 11),
+ /* for postgres_update_instance_auth() */
+ GNUNET_PQ_make_prepare ("update_instance_auth",
+ "UPDATE merchant_instances SET"
+ " auth_hash=$2"
+ ",auth_salt=$3"
+ " WHERE merchant_id = $1",
+ 3),
/* for postgres_inactivate_account() */
GNUNET_PQ_make_prepare ("inactivate_account",
"UPDATE merchant_accounts SET"
@@ -8487,6 +8524,7 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
plugin->delete_instance_private_key = &postgres_delete_instance_private_key;
plugin->purge_instance = &postgres_purge_instance;
plugin->update_instance = &postgres_update_instance;
+ plugin->update_instance_auth = &postgres_update_instance_auth;
plugin->activate_account = &postgres_activate_account;
plugin->inactivate_account = &postgres_inactivate_account;
plugin->lookup_products = &postgres_lookup_products;
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index 9be7933d..be07c3cf 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.c
@@ -266,6 +266,7 @@ check_accounts_equal (const struct TALER_MERCHANTDB_AccountDetails *a,
* @param merchant_pub public key of the instance
* @param merchant_priv private key of the instance, NULL if not available
* @param is general instance settings
+ * @param ias instance authentication settings
* @param accounts_length length of the @a accounts array
* @param accounts list of accounts of the merchant
*/
@@ -274,6 +275,7 @@ lookup_instances_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[])
{
@@ -324,11 +326,13 @@ static int
test_insert_instance (const struct InstanceData *instance,
enum GNUNET_DB_QueryStatus expected_result)
{
+ struct TALER_MERCHANTDB_InstanceAuthSettings ias = { 0 };
TEST_COND_RET_ON_FAIL (expected_result ==
plugin->insert_instance (plugin->cls,
&instance->merchant_pub,
&instance->merchant_priv,
- &instance->instance),
+ &instance->instance,
+ &ias),
"Insert instance failed\n");
return 0;
}
diff --git a/src/include/platform.h b/src/include/platform.h
index 70c296fd..ab260ebe 100644
--- a/src/include/platform.h
+++ b/src/include/platform.h
@@ -62,7 +62,7 @@
* Mark Nottingham thinks this should be fixed by revising HTTP
* spec (https://github.com/httpwg/http-core/issues/733))
*/
-#define RFC_8959_PREFIX "Bearer secret-token:"
+#define RFC_8959_PREFIX "secret-token:"
#endif /* PLATFORM_H_ */
diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h
index 9937750b..8a8cc25b 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -503,7 +503,6 @@ typedef void
* @param default_max_deposit_fee default maximum deposit fee merchant is willing to pay
* @param default_wire_transfer_delay default wire transfer delay merchant will ask for
* @param default_pay_delay default validity period for offers merchant makes
- * @param auth_token authorization token needed to access the instance, can be NULL
* @param cb function to call with the
* backend's instances information
* @param cb_cls closure for @a config_cb
@@ -595,7 +594,6 @@ TALER_MERCHANT_instance_patch (
const struct TALER_Amount *default_max_deposit_fee,
struct GNUNET_TIME_Relative default_wire_transfer_delay,
struct GNUNET_TIME_Relative default_pay_delay,
- const char *auth_token,
TALER_MERCHANT_InstancePatchCallback cb,
void *cb_cls);
diff --git a/src/include/taler_merchant_testing_lib.h b/src/include/taler_merchant_testing_lib.h
index 4eafd6fa..2e872406 100644
--- a/src/include/taler_merchant_testing_lib.h
+++ b/src/include/taler_merchant_testing_lib.h
@@ -177,7 +177,6 @@ TALER_TESTING_cmd_merchant_post_instances2 (
* @param default_max_deposit_fee default maximum deposit fee merchant is willing to pay
* @param default_wire_transfer_delay default wire transfer delay merchant will ask for
* @param default_pay_delay default validity period for offers merchant makes
- * @param auth_token authorization token needed to access the instance, can be NULL
* @param http_status expected HTTP response code.
* @return the command.
*/
@@ -196,7 +195,6 @@ TALER_TESTING_cmd_merchant_patch_instance (
const char *default_max_deposit_fee,
struct GNUNET_TIME_Relative default_wire_transfer_delay,
struct GNUNET_TIME_Relative default_pay_delay,
- const char *auth_token,
unsigned int http_status);
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
index 963f9234..6f94e514 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -60,6 +60,22 @@ struct TALER_MERCHANTDB_AccountDetails
};
+/**
+ * Authentication settings for an instance.
+ */
+struct TALER_MERCHANTDB_InstanceAuthSettings
+{
+ /**
+ * Hash used for authentication. All zero if authentication is off.
+ */
+ struct GNUNET_HashCode auth_hash;
+
+ /**
+ * Salt used to hash the "Authentication" header, the result must then
+ * match the @e auth_hash.
+ */
+ struct GNUNET_ShortHashCode auth_salt;
+};
/**
* General settings for an instance.
@@ -118,17 +134,6 @@ struct TALER_MERCHANTDB_InstanceSettings
*/
struct GNUNET_TIME_Relative default_pay_delay;
- /**
- * Hash used for authentication. All zero if authentication is off.
- */
- struct GNUNET_HashCode auth_hash;
-
- /**
- * Salt used to hash the "Authentication" header, the result must then
- * match the @e auth_hash.
- */
- struct GNUNET_ShortHashCode auth_salt;
-
};
@@ -148,6 +153,7 @@ typedef void
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[]);
@@ -784,7 +790,8 @@ struct TALER_MERCHANTDB_Plugin
(*insert_instance)(void *cls,
const struct TALER_MerchantPublicKeyP *merchant_pub,
const struct TALER_MerchantPrivateKeyP *merchant_priv,
- const struct TALER_MERCHANTDB_InstanceSettings *is);
+ const struct TALER_MERCHANTDB_InstanceSettings *is,
+ const struct TALER_MERCHANTDB_InstanceAuthSettings *ias);
/**
* Insert information about an instance's account into our database.
@@ -836,6 +843,20 @@ struct TALER_MERCHANTDB_Plugin
const struct TALER_MERCHANTDB_InstanceSettings *is);
/**
+ * Update information about an instance's authentication settings
+ * into our database.
+ *
+ * @param cls closure
+ * @param merchant_id merchant backend instance ID
+ * @param ias instance auth settings
+ * @return database result code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*update_instance_auth)(void *cls,
+ const char *merchant_id,
+ const struct TALER_MERCHANTDB_InstanceAuthSettings *ias);
+
+ /**
* Set an instance's account in our database to "inactive".
*
* @param cls closure
diff --git a/src/lib/merchant_api_patch_instance.c b/src/lib/merchant_api_patch_instance.c
index 536fbdcf..bd69a8ba 100644
--- a/src/lib/merchant_api_patch_instance.c
+++ b/src/lib/merchant_api_patch_instance.c
@@ -169,7 +169,6 @@ TALER_MERCHANT_instance_patch (
const struct TALER_Amount *default_max_deposit_fee,
struct GNUNET_TIME_Relative default_wire_transfer_delay,
struct GNUNET_TIME_Relative default_pay_delay,
- const char *auth_token,
TALER_MERCHANT_InstancePatchCallback cb,
void *cb_cls)
{
@@ -177,19 +176,6 @@ TALER_MERCHANT_instance_patch (
json_t *jpayto_uris;
json_t *req_obj;
- if (NULL != auth_token)
- {
- if (0 != strncasecmp (RFC_8959_PREFIX,
- auth_token,
- strlen (RFC_8959_PREFIX)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Authentication token must start with `%s'\n",
- RFC_8959_PREFIX);
- return NULL;
- }
- auth_token += strlen (RFC_8959_PREFIX);
- }
jpayto_uris = json_array ();
if (NULL == jpayto_uris)
{
@@ -207,10 +193,8 @@ TALER_MERCHANT_instance_patch (
return NULL;
}
}
- req_obj = json_pack ("{s:s?, s:o, s:s, s:O, s:O"
+ req_obj = json_pack ("{s:o, s:s, s:O, s:O"
" s:o, s:I: s:o, s:o, s:o}",
- "auth_token",
- auth_token,
"payto_uris",
jpayto_uris,
"name",
diff --git a/src/lib/merchant_api_post_instances.c b/src/lib/merchant_api_post_instances.c
index a6452045..8aede243 100644
--- a/src/lib/merchant_api_post_instances.c
+++ b/src/lib/merchant_api_post_instances.c
@@ -178,6 +178,7 @@ TALER_MERCHANT_instances_post (
struct TALER_MERCHANT_InstancesPostHandle *iph;
json_t *jpayto_uris;
json_t *req_obj;
+ json_t *auth_obj;
if (NULL != auth_token)
{
@@ -190,11 +191,27 @@ TALER_MERCHANT_instances_post (
RFC_8959_PREFIX);
return NULL;
}
- auth_token += strlen (RFC_8959_PREFIX);
+ auth_obj = json_pack ("{s:s, s:s}",
+ "method",
+ "token",
+ "token",
+ auth_token);
+ }
+ else
+ {
+ auth_obj = json_pack ("{s:s}",
+ "method",
+ "external");
+ }
+ if (NULL == auth_obj)
+ {
+ GNUNET_break (0);
+ return NULL;
}
jpayto_uris = json_array ();
if (NULL == jpayto_uris)
{
+ json_decref (auth_obj);
GNUNET_break (0);
return NULL;
}
@@ -205,13 +222,14 @@ TALER_MERCHANT_instances_post (
json_string (payto_uris[i])))
{
GNUNET_break (0);
+ json_decref (auth_obj);
json_decref (jpayto_uris);
return NULL;
}
}
req_obj = json_pack ("{s:o, s:s, s:s, s:O, s:O"
",s:o, s:I: s:o, s:o, s:o"
- ",s:s?}",
+ ",s:o}",
"payto_uris",
jpayto_uris,
"id",
@@ -233,10 +251,11 @@ TALER_MERCHANT_instances_post (
GNUNET_JSON_from_time_rel (default_wire_transfer_delay),
"default_pay_delay",
GNUNET_JSON_from_time_rel (default_pay_delay),
- "auth_token",
- auth_token);
+ "auth",
+ auth_obj);
if (NULL == req_obj)
{
+ json_decref (auth_obj);
GNUNET_break (0);
return NULL;
}
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index fb045996..cad802fb 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -6,6 +6,9 @@ if USE_COVERAGE
XLIB = -lgcov
endif
+
+check_SCRIPTS = test-merchant-walletharness.sh
+
lib_LTLIBRARIES = \
libtalermerchanttesting.la
@@ -82,7 +85,9 @@ endif
endif
TESTS = \
- $(check_PROGRAMS)
+ $(check_PROGRAMS) \
+ $(check_SCRIPTS)
+
test_merchant_api_twisted_SOURCES = \
test_merchant_api_twisted.c
diff --git a/src/testing/test-merchant-walletharness.sh b/src/testing/test-merchant-walletharness.sh
new file mode 100755
index 00000000..f3f1d59a
--- /dev/null
+++ b/src/testing/test-merchant-walletharness.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+# This script runs test from the wallet's integration test harness.
+# If the wallet is not installed, the tests are skipped.
+# Only tests from the "merchant" test suite are run.
+
+set -eu
+
+res=0
+taler-wallet-cli testing run-integrationtests --dry --suites merchant 2&>/dev/null || res=$?
+
+if [[ $res -ne 0 ]]; then
+ echo "skipping wallet test harness"
+ exit 77
+fi
+
+
+exec taler-wallet-cli testing run-integrationtests --suites merchant
diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c
index b1932cd6..93b6194f 100644
--- a/src/testing/test_merchant_api.c
+++ b/src/testing/test_merchant_api.c
@@ -1181,7 +1181,6 @@ run (void *cls,
"USD:0.5",
GNUNET_TIME_UNIT_MINUTES,
GNUNET_TIME_UNIT_MINUTES,
- NULL,
MHD_HTTP_CONFLICT),
TALER_TESTING_cmd_merchant_patch_instance ("instance-patch-i1",
merchant_url,
@@ -1200,7 +1199,6 @@ run (void *cls,
"EUR:0.5",
GNUNET_TIME_UNIT_MINUTES,
GNUNET_TIME_UNIT_MINUTES,
- NULL,
MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_merchant_get_instance2 ("instances-get-i1-2",
merchant_url,
@@ -1229,7 +1227,6 @@ run (void *cls,
"EUR:0.5",
GNUNET_TIME_UNIT_MINUTES,
GNUNET_TIME_UNIT_MINUTES,
- NULL,
MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_merchant_get_instance2 ("instances-get-i1-3",
merchant_url,
@@ -1265,7 +1262,10 @@ run (void *cls,
"EUR:0.2",
GNUNET_TIME_UNIT_MINUTES,
GNUNET_TIME_UNIT_MINUTES,
- RFC_8959_PREFIX "EXAMPLE",
+ // FIXME: change this back once
+ // we have a update auth test CMD
+ //RFC_8959_PREFIX "EXAMPLE",
+ NULL,
MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_merchant_patch_instance ("instance-patch-ACL",
merchant_url,
@@ -1284,7 +1284,6 @@ run (void *cls,
"EUR:0.5",
GNUNET_TIME_UNIT_MINUTES,
GNUNET_TIME_UNIT_MINUTES,
- RFC_8959_PREFIX "SANDBOX",
MHD_HTTP_NO_CONTENT),
TALER_TESTING_cmd_merchant_post_instances ("instance-create-i2",
merchant_url,
diff --git a/src/testing/testing_api_cmd_patch_instance.c b/src/testing/testing_api_cmd_patch_instance.c
index 2cbd0e5b..a7a82ef7 100644
--- a/src/testing/testing_api_cmd_patch_instance.c
+++ b/src/testing/testing_api_cmd_patch_instance.c
@@ -80,11 +80,6 @@ struct PatchInstanceState
json_t *jurisdiction;
/**
- * Authentication token to require, can be NULL.
- */
- const char *auth_token;
-
- /**
* Wire fee to use.
*/
struct TALER_Amount default_max_wire_fee;
@@ -183,7 +178,6 @@ patch_instance_run (void *cls,
&pis->default_max_deposit_fee,
pis->default_wire_transfer_delay,
pis->default_pay_delay,
- pis->auth_token,
&patch_instance_cb,
pis);
GNUNET_assert (NULL != pis->iph);
@@ -286,7 +280,6 @@ TALER_TESTING_cmd_merchant_patch_instance (
const char *default_max_deposit_fee,
struct GNUNET_TIME_Relative default_wire_transfer_delay,
struct GNUNET_TIME_Relative default_pay_delay,
- const char *auth_token,
unsigned int http_status)
{
struct PatchInstanceState *pis;
@@ -313,7 +306,6 @@ TALER_TESTING_cmd_merchant_patch_instance (
&pis->default_max_deposit_fee));
pis->default_wire_transfer_delay = default_wire_transfer_delay;
pis->default_pay_delay = default_pay_delay;
- pis->auth_token = auth_token;
{
struct TALER_TESTING_Command cmd = {
.cls = pis,