challenger

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

commit 6dda14e6d1c093f7f7775eacf62dfcf8db7b4381
parent 63f715831537b6a26ba7a3071941f91cf9d52470
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun, 18 Feb 2024 12:07:05 +0100

return 'state' when returning errors via OAuth2

Diffstat:
Msrc/challenger/challenger-httpd_authorize.c | 1+
Msrc/challenger/challenger-httpd_challenge.c | 30++++++++++++++++++++----------
Msrc/challenger/challenger-httpd_common.c | 24++++++++++++++++++++----
Msrc/challenger/challenger-httpd_common.h | 2++
Msrc/challenger/challenger-httpd_solve.c | 11++++++++++-
Msrc/challengerdb/challenger_do_challenge_set_address_and_pin.sql | 4++++
Msrc/challengerdb/challenger_do_validate_and_solve_pin.sql | 4++++
Msrc/challengerdb/pg_challenge_set_address_and_pin.c | 6++++++
Msrc/challengerdb/pg_challenge_set_address_and_pin.h | 2++
Msrc/challengerdb/pg_validate_solve_pin.c | 6++++++
Msrc/challengerdb/pg_validate_solve_pin.h | 2++
Msrc/include/challenger_database_plugin.h | 4++++
12 files changed, 81 insertions(+), 15 deletions(-)

diff --git a/src/challenger/challenger-httpd_authorize.c b/src/challenger/challenger-httpd_authorize.c @@ -184,6 +184,7 @@ CH_handler_authorize (struct CH_HandlerContext *hc, return TALER_MHD_redirect_with_oauth_status ( hc->connection, redirect_uri, + state, "unauthorized_client", "client exceeded authorization attempts limit (too many addresses)", NULL); diff --git a/src/challenger/challenger-httpd_challenge.c b/src/challenger/challenger-httpd_challenge.c @@ -91,6 +91,11 @@ struct ChallengeContext char *client_redirect_uri; /** + * OAuth2 state. + */ + char *state; + + /** * When did we transmit last? */ struct GNUNET_TIME_Absolute last_tx_time; @@ -210,6 +215,7 @@ cleanup_ctx (void *cls) } json_decref (bc->address); GNUNET_free (bc->data); + GNUNET_free (bc->state); GNUNET_free (bc->last_key); GNUNET_free (bc->client_redirect_uri); GNUNET_free (bc); @@ -532,16 +538,18 @@ CH_handler_challenge (struct CH_HandlerContext *hc, enum GNUNET_DB_QueryStatus qs; GNUNET_assert (NULL == bc->client_redirect_uri); - qs = CH_db->challenge_set_address_and_pin (CH_db->cls, - &bc->nonce, - bc->address, - CH_validation_duration, - &bc->tan, - &bc->last_tx_time, - &bc->pin_attempts_left, - &bc->retransmit, - &bc->client_redirect_uri, - &bc->address_refused); + qs = CH_db->challenge_set_address_and_pin ( + CH_db->cls, + &bc->nonce, + bc->address, + CH_validation_duration, + &bc->tan, + &bc->state, + &bc->last_tx_time, + &bc->pin_attempts_left, + &bc->retransmit, + &bc->client_redirect_uri, + &bc->address_refused); switch (qs) { case GNUNET_DB_STATUS_HARD_ERROR: @@ -572,6 +580,7 @@ CH_handler_challenge (struct CH_HandlerContext *hc, return TALER_MHD_redirect_with_oauth_status ( hc->connection, bc->client_redirect_uri, + bc->state, "unauthorized_client", "client exceeded authorization attempts limit (too many addresses attempted)", NULL); @@ -583,6 +592,7 @@ CH_handler_challenge (struct CH_HandlerContext *hc, return TALER_MHD_redirect_with_oauth_status ( hc->connection, bc->client_redirect_uri, + bc->state, "unauthorized_client", "client exceeded authorization attempts limit (too many PINs)", NULL); diff --git a/src/challenger/challenger-httpd_common.c b/src/challenger/challenger-httpd_common.c @@ -163,6 +163,7 @@ MHD_RESULT TALER_MHD_redirect_with_oauth_status ( struct MHD_Connection *connection, const char *client_redirect_uri, + const char *state, const char *oauth_error, const char *oauth_error_description, const char *oauth_error_uri) @@ -184,14 +185,29 @@ TALER_MHD_redirect_with_oauth_status ( "text/plain")); { char *url; - + char *enc_err; + char *enc_state; + char *enc_desc = NULL; + char *enc_uri = NULL; + + enc_err = TALER_urlencode (oauth_error); + enc_state = TALER_urlencode (state); + if (NULL != oauth_error_description) + enc_desc = TALER_urlencode (oauth_error_description); + if (NULL != oauth_error_uri) + enc_uri = TALER_urlencode (oauth_error_uri); url = TALER_url_join ( client_redirect_uri, "", - "error", oauth_error, - "error_description", oauth_error_description, - "error_uri", oauth_error_uri, + "state", enc_state, + "error", enc_err, + "error_description", enc_desc, + "error_uri", enc_uri, NULL); + GNUNET_free (enc_err); + GNUNET_free (enc_state); + GNUNET_free (enc_desc); + GNUNET_free (enc_uri); if (MHD_NO == MHD_add_response_header (response, MHD_HTTP_HEADER_LOCATION, diff --git a/src/challenger/challenger-httpd_common.h b/src/challenger/challenger-httpd_common.h @@ -94,6 +94,7 @@ TALER_MHD_reply_with_oauth_error ( * * @param connection HTTP request to handle * @param client_redirect_uri base URI where to redirect + * @param state client state to pass to server * @param oauth_error error status to return (e.g. "invalid_scope") * @param oauth_error_description longer description to return, optional, can be NULL * @param oauth_error_uri URI with additional information about the error, optional, can be NULL @@ -103,6 +104,7 @@ MHD_RESULT TALER_MHD_redirect_with_oauth_status ( struct MHD_Connection *connection, const char *client_redirect_uri, + const char *state, const char *oauth_error, const char *oauth_error_description, const char *oauth_error_uri); diff --git a/src/challenger/challenger-httpd_solve.c b/src/challenger/challenger-httpd_solve.c @@ -56,6 +56,11 @@ struct SolveContext char *pin; /** + * OAuth2 state. + */ + char *state; + + /** * Number of bytes in @a pin, excluding 0-terminator. */ size_t pin_len; @@ -94,6 +99,7 @@ cleanup_ctx (void *cls) MHD_destroy_post_processor (bc->pp)); } GNUNET_free (bc->pin); + GNUNET_free (bc->state); GNUNET_free (bc); } @@ -232,6 +238,7 @@ CH_handler_solve (struct CH_HandlerContext *hc, &solved, &exhausted, &no_challenge, + &bc->state, &bc->addr_left, &bc->auth_attempts_left, &bc->pin_transmissions_left, @@ -263,7 +270,8 @@ CH_handler_solve (struct CH_HandlerContext *hc, MHD_RESULT ret; json_t *details; - if ( (0 == bc->addr_left) && + if ( (NULL != bc->state) && + (0 == bc->addr_left) && (0 == bc->pin_transmissions_left) && (0 == bc->auth_attempts_left) ) { @@ -272,6 +280,7 @@ CH_handler_solve (struct CH_HandlerContext *hc, return TALER_MHD_redirect_with_oauth_status ( hc->connection, bc->client_redirect_uri, + bc->state, "access_denied", "users exhausted all possibilities of passing the check", NULL); diff --git a/src/challengerdb/challenger_do_challenge_set_address_and_pin.sql b/src/challengerdb/challenger_do_challenge_set_address_and_pin.sql @@ -24,6 +24,7 @@ CREATE OR REPLACE FUNCTION challenger_do_challenge_set_address_and_pin ( OUT out_not_found BOOLEAN, OUT out_last_tx_time INT8, OUT out_last_pin INT4, + OUT out_state TEXT, OUT out_pin_transmit BOOLEAN, OUT out_auth_attempts_left INT4, OUT out_client_redirect_uri TEXT, @@ -44,6 +45,7 @@ SELECT address ,client_redirect_uri ,last_pin ,auth_attempts_left + ,client_state INTO my_status FROM validations WHERE nonce=in_nonce; @@ -57,6 +59,7 @@ THEN out_auth_attempts_left=0; out_client_redirect_uri=NULL; out_address_refused=TRUE; + out_state=NULL; RETURN; END IF; out_not_found=FALSE; @@ -64,6 +67,7 @@ out_last_tx_time=my_status.last_tx_time; out_last_pin=my_status.last_pin; out_pin_transmit=FALSE; out_auth_attempts_left=my_status.auth_attempts_left; +out_state=my_status.client_state; out_client_redirect_uri=my_status.client_redirect_uri; IF ( (0 = my_status.address_attempts_left) AND diff --git a/src/challengerdb/challenger_do_validate_and_solve_pin.sql b/src/challengerdb/challenger_do_validate_and_solve_pin.sql @@ -21,6 +21,7 @@ CREATE OR REPLACE FUNCTION challenger_do_validate_and_solve_pin ( OUT out_exhausted BOOLEAN, OUT out_no_challenge BOOLEAN, OUT out_solved BOOLEAN, + OUT out_state TEXT, OUT out_address_attempts_left INT4, OUT out_auth_attempts_left INT4, OUT out_pin_transmissions_left INT4, @@ -36,6 +37,7 @@ SELECT auth_attempts_left ,pin_transmissions_left ,last_pin ,client_redirect_uri + ,client_state INTO my_status FROM validations WHERE nonce=in_nonce; @@ -50,12 +52,14 @@ THEN out_auth_attempts_left=0; out_pin_transmissions_left=0; out_client_redirect_uri=NULL; + out_state=NULL; RETURN; END IF; out_not_found=FALSE; out_address_attempts_left=my_status.address_attempts_left; out_pin_transmissions_left=my_status.pin_transmissions_left; out_client_redirect_uri=my_status.client_redirect_uri; +out_state=my_status.client_state; IF (my_status.last_pin IS NULL) THEN diff --git a/src/challengerdb/pg_challenge_set_address_and_pin.c b/src/challengerdb/pg_challenge_set_address_and_pin.c @@ -33,6 +33,7 @@ CH_PG_challenge_set_address_and_pin ( const json_t *address, struct GNUNET_TIME_Relative validation_duration, uint32_t *tan, + char **state, struct GNUNET_TIME_Absolute *last_tx_time, uint32_t *auth_attempts_left, bool *pin_transmit, @@ -69,6 +70,10 @@ CH_PG_challenge_set_address_and_pin ( GNUNET_PQ_result_spec_string ("client_redirect_uri", client_redirect_uri), NULL), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_string ("state", + state), + NULL), GNUNET_PQ_result_spec_bool ("address_refused", address_refused), GNUNET_PQ_result_spec_end @@ -83,6 +88,7 @@ CH_PG_challenge_set_address_and_pin ( ",out_last_tx_time AS last_tx_time" ",out_pin_transmit AS pin_transmit" ",out_last_pin AS last_pin" + ",out_state AS state" ",out_auth_attempts_left AS auth_attempts_left" ",out_client_redirect_uri AS client_redirect_uri" ",out_address_refused AS address_refused" diff --git a/src/challengerdb/pg_challenge_set_address_and_pin.h b/src/challengerdb/pg_challenge_set_address_and_pin.h @@ -37,6 +37,7 @@ * @param address the new address to validate * @param validation_duration minimum time between transmissions * @param[in,out] tan set to the PIN/TAN last send to @a address, input should be random PIN/TAN to use if address did not change + * @param[out] state set to client's OAuth2 state if available * @param[out] last_tx_time set to the last time when we (presumably) send a PIN to @a address, input should be current time to use if the existing value for tx_time is past @a next_tx_time * @param[out] pin_transmit set to true if we should transmit the @a last_pin to the @a address * @param[out] auth_attempts_left set to number of attempts the user has left on this pin @@ -54,6 +55,7 @@ CH_PG_challenge_set_address_and_pin ( const json_t *address, struct GNUNET_TIME_Relative validation_duration, uint32_t *tan, + char **state, struct GNUNET_TIME_Absolute *last_tx_time, uint32_t *auth_attempts_left, bool *pin_transmit, diff --git a/src/challengerdb/pg_validate_solve_pin.c b/src/challengerdb/pg_validate_solve_pin.c @@ -33,6 +33,7 @@ CH_PG_validate_solve_pin (void *cls, bool *solved, bool *exhausted, bool *no_challenge, + char **state, uint32_t *addr_left, uint32_t *auth_attempts_left, uint32_t *pin_transmissions_left, @@ -60,6 +61,10 @@ CH_PG_validate_solve_pin (void *cls, GNUNET_PQ_result_spec_string ("client_redirect_uri", client_redirect_uri), NULL), + GNUNET_PQ_result_spec_allow_null ( + GNUNET_PQ_result_spec_string ("state", + state), + NULL), GNUNET_PQ_result_spec_end }; enum GNUNET_DB_QueryStatus qs; @@ -72,6 +77,7 @@ CH_PG_validate_solve_pin (void *cls, ",out_solved AS solved" ",out_exhausted AS exhausted" ",out_no_challenge AS no_challenge" + ",out_state AS state" ",out_address_attempts_left AS address_attempts_left" ",out_auth_attempts_left AS auth_attempts_left" ",out_pin_transmissions_left AS pin_transmissions_left" diff --git a/src/challengerdb/pg_validate_solve_pin.h b/src/challengerdb/pg_validate_solve_pin.h @@ -35,6 +35,7 @@ * @param[out] solved set to true if the PIN was correct * @param[out] exhausted set to true if the number of attempts to enter the correct PIN has been exhausted * @param[out] no_challenge set to true if we never even issued a challenge + * @param[out] state set to client's OAuth2 state if available * @param[out] addr_left set to number of address changes remaining * @param[out] auth_attempts_left set to number of authentication attempts remaining * @param[out] pin_transmissions_left set to number of times the PIN can still be re-requested @@ -52,6 +53,7 @@ CH_PG_validate_solve_pin ( bool *solved, bool *exhausted, bool *no_challenge, + char **state, uint32_t *addr_left, uint32_t *auth_attempts_left, uint32_t *pin_transmissions_left, diff --git a/src/include/challenger_database_plugin.h b/src/include/challenger_database_plugin.h @@ -258,6 +258,7 @@ struct CHALLENGER_DatabasePlugin * @param address the new address to validate * @param validation_duration minimum time between transmissions * @param[in,out] tan set to the PIN/TAN last send to @a address, input should be random PIN/TAN to use if address did not change + * @param[out] state set to client's OAuth2 state if available * @param[out] last_tx_time set to the last time when we (presumably) send a PIN to @a address, input should be current time to use if the existing value for tx_time is past @a next_tx_time * @param[out] pin_transmit set to true if we should transmit the @a last_pin to the @a address * @param[out] auth_attempts_left set to number of attempts the user has left on this pin @@ -275,6 +276,7 @@ struct CHALLENGER_DatabasePlugin const json_t *address, struct GNUNET_TIME_Relative validation_duration, uint32_t *tan, + char **state, struct GNUNET_TIME_Absolute *last_tx_time, uint32_t *auth_attempts_left, bool *pin_transmit, @@ -291,6 +293,7 @@ struct CHALLENGER_DatabasePlugin * @param[out] solved set to true if the PIN was correct * @param[out] exhausted set to true if the number of attempts to enter the correct PIN has been exhausted * @param[out] no_challenge set to true if we never even issued a challenge + * @param[out] state set to client's OAuth2 state if available * @param[out] addr_left set to number of address changes remaining * @param[out] auth_attempts_left set to number of authentication attempts remaining * @param[out] pin_transmissions_left set to number of times the PIN can still be re-requested @@ -307,6 +310,7 @@ struct CHALLENGER_DatabasePlugin bool *solved, bool *exhausted, bool *no_challenge, + char **state, uint32_t *addr_left, uint32_t *auth_attempts_left, uint32_t *pin_transmissions_left,