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:
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,