exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit 35292b8520f926a4c8d67bf5f6248e0eb615973a
parent 0e0ecbbdf9488914e3ee27c659cd2f438fea3e70
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun, 11 Oct 2026 14:50:22 +0200

refuse http:// for oauth2 endpoints unless in debug mode

Diffstat:
Msrc/kyclogic/plugin_kyclogic_oauth2.c | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/testing/test_exchange_api.conf | 2++
Msrc/testing/test_exchange_api_age_restriction.conf | 2++
3 files changed, 81 insertions(+), 38 deletions(-)

diff --git a/src/kyclogic/plugin_kyclogic_oauth2.c b/src/kyclogic/plugin_kyclogic_oauth2.c @@ -351,6 +351,65 @@ oauth2_unload_configuration (struct TALER_KYCLOGIC_ProviderDetails *pd) /** + * Check that @a url, given in option @a option of section @a section, is + * an http(s) URL acceptable for an OAuth 2.0 endpoint. RFC 6749 (Sections + * 3.1, 3.2 and 10.9) requires TLS for these endpoints, as otherwise the + * client secret, authorization codes and access tokens are transmitted in + * the clear. Hence a plaintext "http://" URL is refused unless + * @a debug_mode is set, in which case it is accepted with a warning. + * + * @param section configuration section that configured @a url + * @param option configuration option that configured @a url + * @param url URL that was configured + * @param debug_mode true if KYC_OAUTH2_DEBUG_MODE is set + * @return true if @a url may be used + */ +static bool +check_endpoint_url (const char *section, + const char *option, + const char *url, + bool debug_mode) +{ + if (! TALER_url_valid_charset (url)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + option, + "not a valid URL"); + return false; + } + if (0 == strncasecmp (url, + "https://", + strlen ("https://"))) + return true; + if (0 != strncasecmp (url, + "http://", + strlen ("http://"))) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + option, + "not a valid URL"); + return false; + } + if (! debug_mode) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + option, + "OAuth 2.0 endpoints must use https:// (RFC 6749); plaintext http:// is only accepted with KYC_OAUTH2_DEBUG_MODE = YES"); + return false; + } + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "KYC_OAUTH2_DEBUG_MODE is set: accepting plaintext http:// endpoint `%s' in option `%s' of section `%s'; the client secret, authorization codes and access tokens will be transmitted in the clear. Never use this in production!\n", + url, + option, + section); + return true; +} + + +/** * Load the configuration of the KYC provider. * * @param cls closure @@ -368,6 +427,12 @@ oauth2_load_configuration (void *cls, pd = GNUNET_new (struct TALER_KYCLOGIC_ProviderDetails); pd->ps = ps; pd->section = GNUNET_strdup (provider_section_name); + /* parse debug mode first, it decides whether http:// URLs are allowed */ + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_yesno (ps->cfg, + provider_section_name, + "KYC_OAUTH2_DEBUG_MODE")) + pd->debug_mode = true; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (ps->cfg, provider_section_name, @@ -416,18 +481,11 @@ oauth2_load_configuration (void *cls, oauth2_unload_configuration (pd); return NULL; } - if ( (! TALER_url_valid_charset (s)) || - ( (0 != strncasecmp (s, - "http://", - strlen ("http://"))) && - (0 != strncasecmp (s, - "https://", - strlen ("https://"))) ) ) + if (! check_endpoint_url (provider_section_name, + "KYC_OAUTH2_TOKEN_URL", + s, + pd->debug_mode)) { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - provider_section_name, - "KYC_OAUTH2_TOKEN_URL", - "not a valid URL"); GNUNET_free (s); oauth2_unload_configuration (pd); return NULL; @@ -446,18 +504,11 @@ oauth2_load_configuration (void *cls, oauth2_unload_configuration (pd); return NULL; } - if ( (! TALER_url_valid_charset (s)) || - ( (0 != strncasecmp (s, - "http://", - strlen ("http://"))) && - (0 != strncasecmp (s, - "https://", - strlen ("https://"))) ) ) + if (! check_endpoint_url (provider_section_name, + "KYC_OAUTH2_AUTHORIZE_URL", + s, + pd->debug_mode)) { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - provider_section_name, - "KYC_OAUTH2_AUTHORIZE_URL", - "not a valid URL"); oauth2_unload_configuration (pd); GNUNET_free (s); return NULL; @@ -505,18 +556,11 @@ oauth2_load_configuration (void *cls, oauth2_unload_configuration (pd); return NULL; } - if ( (! TALER_url_valid_charset (s)) || - ( (0 != strncasecmp (s, - "http://", - strlen ("http://"))) && - (0 != strncasecmp (s, - "https://", - strlen ("https://"))) ) ) + if (! check_endpoint_url (provider_section_name, + "KYC_OAUTH2_INFO_URL", + s, + pd->debug_mode)) { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - provider_section_name, - "KYC_INFO_URL", - "not a valid URL"); GNUNET_free (s); oauth2_unload_configuration (pd); return NULL; @@ -563,11 +607,6 @@ oauth2_load_configuration (void *cls, oauth2_unload_configuration (pd); return NULL; } - if (GNUNET_OK == - GNUNET_CONFIGURATION_get_value_yesno (ps->cfg, - provider_section_name, - "KYC_OAUTH2_DEBUG_MODE")) - pd->debug_mode = true; return pd; } diff --git a/src/testing/test_exchange_api.conf b/src/testing/test_exchange_api.conf @@ -241,6 +241,8 @@ KYC_OAUTH2_CLIENT_ID = taler-exchange KYC_OAUTH2_CLIENT_SECRET = exchange-secret KYC_OAUTH2_POST_URL = http://example.com/ KYC_OAUTH2_CONVERTER_HELPER = taler-exchange-kyc-oauth2-test-converter.sh +# The test OAuth 2.0 service listens on plaintext http://localhost. +KYC_OAUTH2_DEBUG_MODE = YES [kyc-check-oauth-test-id] VOLUNTARY = NO diff --git a/src/testing/test_exchange_api_age_restriction.conf b/src/testing/test_exchange_api_age_restriction.conf @@ -87,6 +87,8 @@ KYC_OAUTH2_CLIENT_ID = taler-exchange KYC_OAUTH2_CLIENT_SECRET = exchange-secret KYC_OAUTH2_POST_URL = http://example.com/ KYC_OAUTH2_CONVERTER_HELPER = taler-exchange-kyc-oauth2-test-converter.sh +# The test OAuth 2.0 service listens on plaintext http://localhost. +KYC_OAUTH2_DEBUG_MODE = YES [kyc-check-oauth-test-id] VOLUNTARY = NO