diff options
author | Christian Grothoff <grothoff@gnunet.org> | 2023-09-06 01:28:58 +0200 |
---|---|---|
committer | Christian Grothoff <grothoff@gnunet.org> | 2023-09-06 01:28:58 +0200 |
commit | e1b7792a233ef94b2d8639ce5333e3f32410424d (patch) | |
tree | f7beb49d105325359fcbbce32c17ae545774cacd | |
parent | c317eb88f9bac0e59f5bbbb8ba2eb99af49f40b3 (diff) | |
download | merchant-e1b7792a233ef94b2d8639ce5333e3f32410424d.tar.gz merchant-e1b7792a233ef94b2d8639ce5333e3f32410424d.tar.bz2 merchant-e1b7792a233ef94b2d8639ce5333e3f32410424d.zip |
implement login token mechanism
4 files changed, 125 insertions, 30 deletions
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index ce9f1e8c..475487e7 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -183,16 +183,54 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg; char *TMH_default_auth; -enum TMH_AuthScope +/** + * Check validity of login @a token for the given @a instance_id. + * + * @param token the login token given in the request + * @param instance_id the instance the login is to be checked against + * @return scope of the token if it is valid + */ +static enum TMH_AuthScope TMH_check_token (const char *token, const char *instance_id) { + enum TMH_AuthScope scope; + struct GNUNET_TIME_Timestamp expiration; + enum GNUNET_DB_QueryStatus qs; + struct TALER_MERCHANTDB_LoginTokenP btoken; + if (NULL == token) return TMH_AS_NONE; - GNUNET_break (0); // FIXME: not implemented - return TMH_AS_NONE; + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (token, + strlen (token), + &btoken, + sizeof (btoken))) + return TMH_AS_NONE; + qs = TMH_db->select_login_token (TMH_db->cls, + instance_id, + &btoken, + &expiration, + &scope); + if (qs < 0) + { + /* FIXME: may want to return 500 internal server error + in the future in this case... */ + GNUNET_break (0); + return TMH_AS_NONE; + } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + return TMH_AS_NONE; + if (GNUNET_TIME_absolute_is_past (expiration.abs_time)) + { + /* FIXME: may want to return special EC to indicate + (recently) expired token in the future */ + return TMH_AS_NONE; + } + return scope; } + enum GNUNET_GenericReturnValue TMH_check_auth (const char *token, struct TALER_MerchantAuthenticationSaltP *salt, @@ -765,7 +803,7 @@ url_handler (void *cls, /* POST /token: */ { .url_prefix = "/instances/", - .auth_scope = TMH_AS_RENEWABLE, + .auth_scope = TMH_AS_REFRESHABLE, .url_suffix = "token", .method = MHD_HTTP_METHOD_POST, .have_id_segment = true, diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h index 36f04fb9..30d84751 100644 --- a/src/backend/taler-merchant-httpd.h +++ b/src/backend/taler-merchant-httpd.h @@ -425,7 +425,7 @@ enum TMH_AuthScope { /** * /login access to renew the token is OK. */ - TMH_AS_RENEWABLE = 1 << 30, + TMH_AS_REFRESHABLE = 1 << 30, /** * Full access is granted to everything. diff --git a/src/backend/taler-merchant-httpd_private-delete-instances-ID-token.c b/src/backend/taler-merchant-httpd_private-delete-instances-ID-token.c index c5e8cc91..242b583a 100644 --- a/src/backend/taler-merchant-httpd_private-delete-instances-ID-token.c +++ b/src/backend/taler-merchant-httpd_private-delete-instances-ID-token.c @@ -35,19 +35,49 @@ TMH_private_delete_instances_ID_token (const struct TMH_RequestHandler *rh, { struct TMH_MerchantInstance *mi = hc->instance; const char *tok; + struct TALER_MERCHANTDB_LoginTokenP btoken; + enum GNUNET_DB_QueryStatus qs; tok = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_AUTHORIZATION); - GNUNET_break (0); // FIXME: not implemented - (void) tok; - (void) mi; - - return TALER_MHD_reply_static (connection, - MHD_HTTP_NO_CONTENT, - NULL, - NULL, - 0); + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (tok, + strlen (tok), + &btoken, + sizeof (btoken))) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_ec (connection, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "login token (in 'Authorization' header)"); + } + qs = TMH_db->delete_login_token (TMH_db->cls, + mi->settings.id, + &btoken); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + GNUNET_break (0); + return TALER_MHD_reply_with_ec (connection, + TALER_EC_GENERIC_DB_STORE_FAILED, + "delete_login_token"); + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + /* No 404, as the login token must have existed + when we got the request as it was accepted as + valid. So we can only get here due to concurrent + modification, and then the client should still + simply see the success. Hence, fall-through */ + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + return TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); + } + GNUNET_break (0); + return MHD_NO; } diff --git a/src/backend/taler-merchant-httpd_private-post-instances-ID-token.c b/src/backend/taler-merchant-httpd_private-post-instances-ID-token.c index e5128a56..74de6563 100644 --- a/src/backend/taler-merchant-httpd_private-post-instances-ID-token.c +++ b/src/backend/taler-merchant-httpd_private-post-instances-ID-token.c @@ -29,9 +29,9 @@ /** - * Maximum duration for the validity of a token token. + * Default duration for the validity of a login token. */ -#define MAX_DURATION GNUNET_TIME_UNIT_DAYS +#define DEFAULT_DURATION GNUNET_TIME_UNIT_DAYS MHD_RESULT @@ -42,9 +42,11 @@ TMH_private_post_instances_ID_token (const struct TMH_RequestHandler *rh, struct TMH_MerchantInstance *mi = hc->instance; json_t *jtoken = hc->request_body; const char *scope; + uint32_t iscope = TMH_AS_NONE; bool refreshable = false; + struct TALER_MERCHANTDB_LoginTokenP btoken; struct GNUNET_TIME_Relative duration - = MAX_DURATION; + = DEFAULT_DURATION; struct GNUNET_TIME_Timestamp expiration_time; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_string ("scope", @@ -59,9 +61,8 @@ TMH_private_post_instances_ID_token (const struct TMH_RequestHandler *rh, NULL), GNUNET_JSON_spec_end () }; - char *token; - MHD_RESULT ret; - + enum GNUNET_DB_QueryStatus qs; + { enum GNUNET_GenericReturnValue res; @@ -71,25 +72,51 @@ TMH_private_post_instances_ID_token (const struct TMH_RequestHandler *rh, if (GNUNET_OK != res) return (GNUNET_NO == res) ? MHD_YES : MHD_NO; } - duration = GNUNET_TIME_relative_min (duration, - MAX_DURATION); expiration_time = GNUNET_TIME_relative_to_timestamp (duration); - token = GNUNET_strdup ("FIXME-foo"); - (void) mi; - - ret = TALER_MHD_REPLY_JSON_PACK ( + if (0 == strcasecmp (scope, + "readonly")) + iscope = TMH_AS_READ_ONLY; + else if (0 == strcasecmp (scope, + "write")) + iscope = TMH_AS_ALL; + else + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_ec (connection, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "scope"); + } + if (refreshable) + iscope |= TMH_AS_REFRESHABLE; + qs = TMH_db->insert_login_token (TMH_db->cls, + mi->settings.id, + &btoken, + GNUNET_TIME_timestamp_get (), + expiration_time, + iscope); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + case GNUNET_DB_STATUS_SOFT_ERROR: + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_break (0); + return TALER_MHD_reply_with_ec (connection, + TALER_EC_GENERIC_DB_STORE_FAILED, + "insert_login_token"); + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + break; + } + return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_OK, - GNUNET_JSON_pack_string ("token", - token), + GNUNET_JSON_pack_data_auto ("token", + &btoken), GNUNET_JSON_pack_string ("scope", scope), GNUNET_JSON_pack_bool ("refreshable", refreshable), GNUNET_JSON_pack_timestamp ("expiration", expiration_time)); - GNUNET_free (token); - return ret; } |