challenger

OAuth 2.0-based authentication service that validates user can receive messages at a certain address
Log | Files | Refs | Submodules | README | LICENSE

commit 690ce695415810012382f371fb11ab5f872bdeac
parent 68fa678c29f4fe74a12464998518a5ff59d2adc4
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue,  5 Mar 2024 22:47:51 +0100

implement #8556

Diffstat:
Msrc/challenger/challenger-httpd.c | 35+++++++++++++++++++++++++++++++++++
Msrc/challenger/challenger-httpd.h | 10++++++++++
Msrc/challenger/challenger-httpd_authorize.c | 2++
Msrc/challenger/challenger-httpd_challenge.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 117 insertions(+), 0 deletions(-)

diff --git a/src/challenger/challenger-httpd.c b/src/challenger/challenger-httpd.c @@ -95,6 +95,16 @@ struct GNUNET_TIME_Relative CH_validation_expiration; struct GNUNET_TIME_Relative CH_pin_retransmission_frequency; /** + * JSON object with key-object pairs mapping address keys (from the + * form) to an object with a field "regex" containing a regular + * expressions expressing restrictions on values for the address and a + * field "hint" (and possibly "hint_i18n") containing a human-readable + * message explaining the restriction. Missing map entries indicate + * that the input is unrestricted. + */ +json_t *CH_restrictions; + +/** * Type of addresses this challenger validates. */ char *CH_address_type; @@ -593,6 +603,31 @@ run (void *cls, "ADDRESS_TYPE"); return; } + { + char *restrictions; + + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (config, + "CHALLENGER", + "ADDRESS_RESTRICTIONS", + &restrictions)) + { + json_error_t err; + + CH_restrictions = json_loads (restrictions, + JSON_REJECT_DUPLICATES, + &err); + GNUNET_free (restrictions); + if (NULL == CH_restrictions) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "CHALLENGER", + "ADDRESS_RESTRICTIONS", + err.text); + return; + } + } + } global_ret = EXIT_NOTCONFIGURED; GNUNET_SCHEDULER_add_shutdown (&do_shutdown, diff --git a/src/challenger/challenger-httpd.h b/src/challenger/challenger-httpd.h @@ -157,6 +157,16 @@ extern struct GNUNET_TIME_Relative CH_validation_expiration; extern struct GNUNET_TIME_Relative CH_pin_retransmission_frequency; /** + * JSON object with key-object pairs mapping address keys (from the + * form) to an object with a field "regex" containing a regular + * expressions expressing restrictions on values for the address and a + * field "hint" (and possibly "hint_i18n") containing a human-readable + * message explaining the restriction. Missing map entries indicate + * that the input is unrestricted. + */ +extern json_t *CH_restrictions; + +/** * Kick MHD to run now, to be called after MHD_resume_connection(). * Basically, we need to explicitly resume MHD's event loop whenever * we made progress serving a request. This function re-schedules diff --git a/src/challenger/challenger-httpd_authorize.c b/src/challenger/challenger-httpd_authorize.c @@ -207,6 +207,8 @@ CH_handler_authorize (struct CH_HandlerContext *hc, "enter-%s-form", CH_address_type); args = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_object_incref ("restrictions", + CH_restrictions), GNUNET_JSON_pack_bool ("fix_address", 0 == address_attempts_left), GNUNET_JSON_pack_string ("nonce", diff --git a/src/challenger/challenger-httpd_challenge.c b/src/challenger/challenger-httpd_challenge.c @@ -20,6 +20,7 @@ */ #include "platform.h" #include "challenger-httpd.h" +#include <regex.h> #include <gnunet/gnunet_util_lib.h> #include "challenger-httpd_challenge.h" #include <taler/taler_json_lib.h> @@ -429,6 +430,61 @@ post_iter (void *cls, } +/** + * Check if the given address satisfies our restrictions. + * + * @param address address data provided by the client + * @return NULL on success, otherwise the key that failed + */ +static const char * +check_restrictions (const json_t *address) +{ + const char *key; + const json_t *val; + + json_object_foreach ((json_t *) address, key, val) + { + const char *str = json_string_value (val); + const char *regex = json_string_value ( + json_object_get ( + json_object_get (CH_restrictions, + key), + "regex")); + regex_t re; + + if (NULL == str) + return key; + if (NULL == regex) + continue; + if (0 != regcomp (&re, + regex, + REG_EXTENDED)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid regex `%s' address restriction specified for `%s'\n", + regex, + key); + continue; + } + if (0 != regexec (&re, + str, + 0, + NULL, + 0)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Client input `%s' rejected as it does not match address restriction `%s' specified for `%s'\n", + str, + regex, + key); + return key; + } + regfree (&re); + } + return NULL; +} + + MHD_RESULT CH_handler_challenge (struct CH_HandlerContext *hc, const char *upload_data, @@ -533,6 +589,20 @@ CH_handler_challenge (struct CH_HandlerContext *hc, address); free (address); } + { + const char *bad_field; + + bad_field = check_restrictions (bc->address); + if (NULL != bad_field) + { + GNUNET_break_op (0); + return TALER_TEMPLATING_reply_error (hc->connection, + "invalid-request", + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + bad_field); + } + } if (! bc->db_finished) { enum GNUNET_DB_QueryStatus qs;