From 78a0c837355f97df7331212e4faf71eed81c05ca Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 6 Sep 2023 22:41:31 +0200 Subject: towards fixing #7793 --- src/backend/taler-merchant-httpd.c | 115 ++++++++++------------------- src/backend/taler-merchant-httpd.h | 6 +- src/testing/test_merchant_instance_auth.sh | 88 +++++++++++++++++++++- 3 files changed, 124 insertions(+), 85 deletions(-) diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index 475487e7..b714ac8c 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -199,6 +199,9 @@ TMH_check_token (const char *token, enum GNUNET_DB_QueryStatus qs; struct TALER_MERCHANTDB_LoginTokenP btoken; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "checking token %s\n", + token); if (NULL == token) return TMH_AS_NONE; if (GNUNET_OK != @@ -206,7 +209,10 @@ TMH_check_token (const char *token, strlen (token), &btoken, sizeof (btoken))) + { + GNUNET_break_op (0); return TMH_AS_NONE; + } qs = TMH_db->select_login_token (TMH_db->cls, instance_id, &btoken, @@ -220,13 +226,25 @@ TMH_check_token (const char *token, return TMH_AS_NONE; } if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Token %s unknown\n", + token); return TMH_AS_NONE; + } if (GNUNET_TIME_absolute_is_past (expiration.abs_time)) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Token %s expired\n", + token); /* FIXME: may want to return special EC to indicate (recently) expired token in the future */ return TMH_AS_NONE; } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Token %s has scope %d\n", + token, + scope); return scope; } @@ -800,28 +818,6 @@ url_handler (void *cls, /* Body should be pretty small. */ .max_upload = 1024 * 1024 }, - /* POST /token: */ - { - .url_prefix = "/instances/", - .auth_scope = TMH_AS_REFRESHABLE, - .url_suffix = "token", - .method = MHD_HTTP_METHOD_POST, - .have_id_segment = true, - .handler = &TMH_private_post_instances_ID_auth, - /* Body should be tiny. */ - .max_upload = 1024 - }, -#if FUTURE_FIXME - /* DELETE /token: */ - { - .url_prefix = "/instances/", - .auth_scope = TMH_AS_READ_ONLY, - .url_suffix = "token", - .method = MHD_HTTP_METHOD_DELETE, - .have_id_segment = true, - .handler = &TMH_private_delete_instances_ID_auth, - }, -#endif /* POST /kyc: */ { .url_prefix = "/instances/", @@ -1019,17 +1015,6 @@ url_handler (void *cls, to set a conservative bound for sane wallets */ .max_upload = 1024 * 1024 }, - // FIXME: legacy API - { - .url_prefix = "/reserves/", - .url_suffix = "authorize-tip", - .have_id_segment = true, - .method = MHD_HTTP_METHOD_POST, - .handler = &TMH_private_post_reserves_ID_authorize_reward, - /* the body should be pretty small, allow 1 MB of upload - to set a conservative bound for sane wallets */ - .max_upload = 1024 * 1024 - }, /* POST /rewards: */ { .url_prefix = "/rewards", @@ -1039,15 +1024,6 @@ url_handler (void *cls, to set a conservative bound for sane wallets */ .max_upload = 1024 * 1024 }, - // FIXME: legacy API - { - .url_prefix = "/tips", - .method = MHD_HTTP_METHOD_POST, - .handler = &TMH_private_post_rewards, - /* the body should be pretty small, allow 1 MB of upload - to set a conservative bound for sane wallets */ - .max_upload = 1024 * 1024 - }, /* GET /rewards: */ { .url_prefix = "/rewards", @@ -1055,13 +1031,6 @@ url_handler (void *cls, .method = MHD_HTTP_METHOD_GET, .handler = &TMH_private_get_rewards }, - // FIXME: legacy API - { - .url_prefix = "/tips", - .allow_deleted_instance = true, - .method = MHD_HTTP_METHOD_GET, - .handler = &TMH_private_get_rewards - }, /* GET /rewards/$ID: */ { .url_prefix = "/rewards/", @@ -1070,14 +1039,6 @@ url_handler (void *cls, .have_id_segment = true, .handler = &TMH_private_get_rewards_ID }, - // FIXME: legacy API - { - .url_prefix = "/tips/", - .method = MHD_HTTP_METHOD_GET, - .allow_deleted_instance = true, - .have_id_segment = true, - .handler = &TMH_private_get_rewards_ID - }, /* GET /reserves: */ { .url_prefix = "/reserves", @@ -1283,6 +1244,22 @@ url_handler (void *cls, .handler = &TMH_private_delete_account_ID, .have_id_segment = true }, + /* POST /token: */ + { + .url_prefix = "/token", + .auth_scope = TMH_AS_REFRESHABLE, + .method = MHD_HTTP_METHOD_POST, + .handler = &TMH_private_post_instances_ID_token, + /* Body should be tiny. */ + .max_upload = 1024 + }, + /* DELETE /token: */ + { + .url_prefix = "/token", + .auth_scope = TMH_AS_READ_ONLY, + .method = MHD_HTTP_METHOD_DELETE, + .handler = &TMH_private_delete_instances_ID_token, + }, { .url_prefix = NULL } @@ -1399,14 +1376,6 @@ url_handler (void *cls, .have_id_segment = true, .handler = &TMH_get_rewards_ID }, - // FIXME: legacy API - { - .url_prefix = "/tips/", - .method = MHD_HTTP_METHOD_GET, - .allow_deleted_instance = true, - .have_id_segment = true, - .handler = &TMH_get_rewards_ID - }, /* POST /rewards/$ID/pickup: */ { .url_prefix = "/rewards/", @@ -1419,18 +1388,6 @@ url_handler (void *cls, to set a conservative bound for sane wallets */ .max_upload = 1024 * 1024 }, - // FIXME: legacy API - { - .url_prefix = "/tips/", - .method = MHD_HTTP_METHOD_POST, - .have_id_segment = true, - .allow_deleted_instance = true, - .url_suffix = "pickup", - .handler = &TMH_post_rewards_ID_pickup, - /* wallet may give us many coins to sign, allow 1 MB of upload - to set a conservative bound for sane wallets */ - .max_upload = 1024 * 1024 - }, /* GET /static/ *: */ { .url_prefix = "/static/", @@ -1861,6 +1818,8 @@ url_handler (void *cls, ? TMH_AS_ALL : TMH_check_token (tok, hc->instance->settings.id); + if (TMH_AS_NONE != hc->auth_scope) + auth_malformed = false; /* We grant access if: - scope is 'all' - rh has an explicit non-NONE scope that matches @@ -1868,7 +1827,7 @@ url_handler (void *cls, if (! ( (TMH_AS_ALL == hc->auth_scope) || ( (TMH_AS_NONE != hc->rh->auth_scope) && (hc->rh->auth_scope == (hc->rh->auth_scope & hc->auth_scope)) ) || - ( (TMH_AS_READ_ONLY == hc->auth_scope) && + ( (TMH_AS_READ_ONLY == (hc->auth_scope & TMH_AS_READ_ONLY)) && (0 == strcmp (MHD_HTTP_METHOD_GET, method)) ) ) ) { diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h index 6e9d8793..eaeef55e 100644 --- a/src/backend/taler-merchant-httpd.h +++ b/src/backend/taler-merchant-httpd.h @@ -423,14 +423,14 @@ enum TMH_AuthScope { TMH_AS_READ_ONLY = 1, /** - * /login access to renew the token is OK. + * /login access to renew the token is OK. */ - TMH_AS_REFRESHABLE = 1 << 30, + TMH_AS_REFRESHABLE = 2, /** * Full access is granted to everything. */ - TMH_AS_ALL = INT32_MAX + TMH_AS_ALL = 7 }; diff --git a/src/testing/test_merchant_instance_auth.sh b/src/testing/test_merchant_instance_auth.sh index 8d6e347a..d1315b73 100755 --- a/src/testing/test_merchant_instance_auth.sh +++ b/src/testing/test_merchant_instance_auth.sh @@ -96,7 +96,7 @@ fi echo -n "Creating order to test auth is ok..." >&2 STATUS=$(curl -H "Content-Type: application/json" -X POST \ 'http://localhost:9966/instances/default/private/orders' \ - -H 'Authorization: Bearer '$NEW_SECRET \ + -H 'Authorization: Bearer '"$NEW_SECRET" \ -d '{"order":{"amount":"TESTKUDOS:1","summary":"payme"}}' \ -w "%{http_code}" -s -o "$LAST_RESPONSE") @@ -110,7 +110,7 @@ ORDER_ID=$(jq -e -r .order_id < "$LAST_RESPONSE") TOKEN=$(jq -e -r .token < "$LAST_RESPONSE") STATUS=$(curl "http://localhost:9966/instances/default/private/orders/${ORDER_ID}" \ - -H 'Authorization: Bearer '$NEW_SECRET \ + -H 'Authorization: Bearer '"$NEW_SECRET" \ -w "%{http_code}" -s -o "$LAST_RESPONSE") if [ "$STATUS" != "200" ] @@ -126,7 +126,7 @@ echo "OK order ${ORDER_ID} with ${TOKEN} and ${PAY_URL}" >&2 echo -n "Configuring 'second' instance ..." >&2 STATUS=$(curl -H "Content-Type: application/json" -X POST \ - -H 'Authorization: Bearer '$NEW_SECRET \ + -H 'Authorization: Bearer '"$NEW_SECRET" \ http://localhost:9966/management/instances \ -d '{"auth":{"method":"token","token":"secret-token:second"},"id":"second","name":"second","address":{},"jurisdiction":{},"use_stefan":true,"default_wire_transfer_delay":{"d_us" : 3600000000},"default_pay_delay":{"d_us": 3600000000}}' \ -w "%{http_code}" -s -o /dev/null) @@ -141,7 +141,7 @@ echo "OK" >&2 echo -n "Updating 'second' instance token using the 'default' auth token..." >&2 STATUS=$(curl -H "Content-Type: application/json" -X POST \ - -H 'Authorization: Bearer '$NEW_SECRET \ + -H 'Authorization: Bearer '"$NEW_SECRET" \ http://localhost:9966/management/instances/second/auth \ -d '{"method":"token","token":"secret-token:new_one"}' \ -w "%{http_code}" -s -o /dev/null) @@ -150,8 +150,88 @@ if [ "$STATUS" != "204" ] then exit_fail "Expected 204, instance auth token changed. got: $STATUS" fi +NEW_SECRET="secret-token:new_one" +echo " OK" >&2 + + +echo -n "Requesting login token..." >&2 + +STATUS=$(curl -H "Content-Type: application/json" -X POST \ + -H 'Authorization: Bearer '"$NEW_SECRET" \ + http://localhost:9966/instances/second/private/token \ + -d '{"scope":"readonly","refreshable":true}' \ + -w "%{http_code}" -s -o "$LAST_RESPONSE") + +if [ "$STATUS" != "200" ] +then + jq < "$LAST_RESPONSE" >&2 + exit_fail "Expected 200, login token created. got: $STATUS" +fi + +TOKEN=$(jq -e -r .token < "$LAST_RESPONSE") echo " OK" >&2 + +echo -n "Using login token..." >&2 + +STATUS=$(curl "http://localhost:9966/instances/second/private/orders" \ + -H 'Authorization: '"$TOKEN" \ + -w "%{http_code}" -s -o "$LAST_RESPONSE") + +if [ "$STATUS" != "200" ] +then + jq < "$LAST_RESPONSE" >&2 + exit_fail "Expected 200, getting orders. got: $STATUS" +fi + +echo " OK" >&2 + +echo -n "Refreshing login token..." >&2 + +STATUS=$(curl -H "Content-Type: application/json" -X POST \ + -H 'Authorization: '"$TOKEN" \ + http://localhost:9966/instances/second/private/token \ + -d '{"scope":"write","refreshable":true}' \ + -w "%{http_code}" -s -o "$LAST_RESPONSE") + +if [ "$STATUS" != "403" ] +then + jq < "$LAST_RESPONSE" >&2 + exit_fail "Expected 403, refused to upgrade login token. got: $STATUS" +fi + +echo " OK" >&2 + + +echo -n "Deleting login token..." >&2 + +STATUS=$(curl -H "Content-Type: application/json" -X DELETE \ + -H 'Authorization: '"$TOKEN" \ + http://localhost:9966/instances/second/private/token \ + -w "%{http_code}" -s -o "$LAST_RESPONSE") + +if [ "$STATUS" != "204" ] +then + jq < "$LAST_RESPONSE" >&2 + exit_fail "Expected 204, login token deleted. got: $STATUS" +fi +echo " OK" >&2 + +echo -n "Using deleted login token..." >&2 + +STATUS=$(curl "http://localhost:9966/instances/second/private/orders" \ + -H 'Authorization: '"$TOKEN" \ + -w "%{http_code}" -s -o "$LAST_RESPONSE") + +if [ "$STATUS" != "401" ] +then + jq < "$LAST_RESPONSE" >&2 + exit_fail "Expected 401, token was deleted. got: $STATUS" +fi + +echo " OK" >&2 + + echo "Test PASSED" exit 0 -- cgit v1.2.3