Blame SOURCES/0013-Allow-configuring-which-header-value-is-used-to-calc.patch

5b8408
From 5a1f90847efce160631ee2a16d7b9d1da3496616 Mon Sep 17 00:00:00 2001
5b8408
From: Hiroyuki Wada <h2-wada@nri.co.jp>
5b8408
Date: Tue, 21 Apr 2020 20:29:25 +0900
5b8408
Subject: [PATCH 13/13] Allow configuring which header value is used to
5b8408
 calculate the fingerprint of the state during authentication
5b8408
5b8408
(cherry picked from commit 2a97eced569ebbff82fc0370c4f741d04ba7cb13)
5b8408
---
5b8408
 auth_openidc.conf      |  4 ++++
5b8408
 src/config.c           | 25 +++++++++++++++++++++++++
5b8408
 src/mod_auth_openidc.c | 30 +++++++++++++++++-------------
5b8408
 src/mod_auth_openidc.h |  5 +++++
5b8408
 src/parse.c            | 33 +++++++++++++++++++++++++++++++++
5b8408
 src/parse.h            |  1 +
5b8408
 6 files changed, 85 insertions(+), 13 deletions(-)
5b8408
5b8408
diff --git a/auth_openidc.conf b/auth_openidc.conf
5b8408
index 33cea64..4012df3 100644
5b8408
--- a/auth_openidc.conf
5b8408
+++ b/auth_openidc.conf
5b8408
@@ -774,3 +774,7 @@
5b8408
 # When not defined no claims are whitelisted and all claims are stored except when blacklisted with OIDCBlackListedClaims.
5b8408
 #OIDCWhiteListedClaims [<claim>]+
5b8408
 
5b8408
+# Defines whether the value of the User-Agent and X-Forwarded-For headers will be used as the input
5b8408
+# for calculating the fingerprint of the state during authentication.
5b8408
+# When not defined the default "both" is used.
5b8408
+#OIDCStateInputHeaders [none|user-agent|x-forwarded-for|both]
5b8408
diff --git a/src/config.c b/src/config.c
5b8408
index 8e56716..588e1a3 100644
5b8408
--- a/src/config.c
5b8408
+++ b/src/config.c
5b8408
@@ -166,6 +166,8 @@
5b8408
 #define OIDC_DEFAULT_AUTH_REQUEST_METHOD OIDC_AUTH_REQUEST_METHOD_GET
5b8408
 /* define whether the issuer will be added to the redirect uri by default to mitigate the IDP mixup attack */
5b8408
 #define OIDC_DEFAULT_PROVIDER_ISSUER_SPECIFIC_REDIRECT_URI 0
5b8408
+/* default setting for calculating the fingerprint of the state from request headers during authentication */
5b8408
+#define OIDC_DEFAULT_STATE_INPUT_HEADERS OIDC_STATE_INPUT_HEADERS_USER_AGENT | OIDC_STATE_INPUT_HEADERS_X_FORWARDED_FOR
5b8408
 
5b8408
 #define OIDCProviderMetadataURL              "OIDCProviderMetadataURL"
5b8408
 #define OIDCProviderIssuer                   "OIDCProviderIssuer"
5b8408
@@ -261,6 +263,7 @@
5b8408
 #define OIDCProviderAuthRequestMethod        "OIDCProviderAuthRequestMethod"
5b8408
 #define OIDCBlackListedClaims                "OIDCBlackListedClaims"
5b8408
 #define OIDCOAuthServerMetadataURL           "OIDCOAuthServerMetadataURL"
5b8408
+#define OIDCStateInputHeaders                  "OIDCStateInputHeaders"
5b8408
 
5b8408
 extern module AP_MODULE_DECLARE_DATA auth_openidc_module;
5b8408
 
5b8408
@@ -1030,6 +1033,17 @@ int oidc_cfg_delete_oldest_state_cookies(oidc_cfg *cfg) {
5b8408
 	return cfg->delete_oldest_state_cookies;
5b8408
 }
5b8408
 
5b8408
+/*
5b8408
+ * define which header we use for calculating the fingerprint of the state during authentication
5b8408
+ */
5b8408
+static const char * oidc_set_state_input_headers_as(cmd_parms *cmd, void *m,
5b8408
+		const char *arg) {
5b8408
+	oidc_cfg *cfg = (oidc_cfg *) ap_get_module_config(
5b8408
+			cmd->server->module_config, &auth_openidc_module);
5b8408
+	const char *rv = oidc_parse_set_state_input_headers_as(cmd->pool, arg, &cfg->state_input_headers);
5b8408
+	return OIDC_CONFIG_DIR_RV(cmd, rv);
5b8408
+}
5b8408
+
5b8408
 /*
5b8408
  * create a new server config record with defaults
5b8408
  */
5b8408
@@ -1176,6 +1190,8 @@ void *oidc_create_server_config(apr_pool_t *pool, server_rec *svr) {
5b8408
 	c->provider.issuer_specific_redirect_uri =
5b8408
 			OIDC_DEFAULT_PROVIDER_ISSUER_SPECIFIC_REDIRECT_URI;
5b8408
 
5b8408
+	c->state_input_headers = OIDC_DEFAULT_STATE_INPUT_HEADERS;
5b8408
+
5b8408
 	return c;
5b8408
 }
5b8408
 
5b8408
@@ -1617,6 +1633,10 @@ void *oidc_merge_server_config(apr_pool_t *pool, void *BASE, void *ADD) {
5b8408
 					add->provider.issuer_specific_redirect_uri :
5b8408
 					base->provider.issuer_specific_redirect_uri;
5b8408
 
5b8408
+	c->state_input_headers =
5b8408
+			add->state_input_headers != OIDC_DEFAULT_STATE_INPUT_HEADERS ?
5b8408
+					add->state_input_headers : base->state_input_headers;
5b8408
+
5b8408
 	return c;
5b8408
 }
5b8408
 
5b8408
@@ -2866,5 +2886,10 @@ const command_rec oidc_config_cmds[] = {
5b8408
 				(void*)APR_OFFSETOF(oidc_cfg, oauth.metadata_url),
5b8408
 				RSRC_CONF,
5b8408
 				"Authorization Server metadata URL."),
5b8408
+		AP_INIT_TAKE123(OIDCStateInputHeaders,
5b8408
+				oidc_set_state_input_headers_as,
5b8408
+				NULL,
5b8408
+				RSRC_CONF,
5b8408
+				"Specify header name which is used as the input for calculating the fingerprint of the state during authentication; must be one of \"none\", \"user-agent\", \"x-forwarded-for\" or \"both\" (default)."),
5b8408
 		{ NULL }
5b8408
 };
5b8408
diff --git a/src/mod_auth_openidc.c b/src/mod_auth_openidc.c
5b8408
index 8740e02..38558d2 100644
5b8408
--- a/src/mod_auth_openidc.c
5b8408
+++ b/src/mod_auth_openidc.c
5b8408
@@ -226,7 +226,7 @@ void oidc_strip_cookies(request_rec *r) {
5b8408
 /*
5b8408
  * calculates a hash value based on request fingerprint plus a provided nonce string.
5b8408
  */
5b8408
-static char *oidc_get_browser_state_hash(request_rec *r, const char *nonce) {
5b8408
+static char *oidc_get_browser_state_hash(request_rec *r, oidc_cfg *c, const char *nonce) {
5b8408
 
5b8408
 	oidc_debug(r, "enter");
5b8408
 
5b8408
@@ -238,17 +238,21 @@ static char *oidc_get_browser_state_hash(request_rec *r, const char *nonce) {
5b8408
 	/* Initialize the hash context */
5b8408
 	apr_sha1_init(&sha1;;
5b8408
 
5b8408
-	/* get the X-FORWARDED-FOR header value  */
5b8408
-	value = oidc_util_hdr_in_x_forwarded_for_get(r);
5b8408
-	/* if we have a value for this header, concat it to the hash input */
5b8408
-	if (value != NULL)
5b8408
-		apr_sha1_update(&sha1, value, strlen(value));
5b8408
+	if (c->state_input_headers & OIDC_STATE_INPUT_HEADERS_X_FORWARDED_FOR) {
5b8408
+		/* get the X-FORWARDED-FOR header value  */
5b8408
+		value = oidc_util_hdr_in_x_forwarded_for_get(r);
5b8408
+		/* if we have a value for this header, concat it to the hash input */
5b8408
+		if (value != NULL)
5b8408
+			apr_sha1_update(&sha1, value, strlen(value));
5b8408
+	}
5b8408
 
5b8408
-	/* get the USER-AGENT header value  */
5b8408
-	value = oidc_util_hdr_in_user_agent_get(r);
5b8408
-	/* if we have a value for this header, concat it to the hash input */
5b8408
-	if (value != NULL)
5b8408
-		apr_sha1_update(&sha1, value, strlen(value));
5b8408
+	if (c->state_input_headers & OIDC_STATE_INPUT_HEADERS_USER_AGENT) {
5b8408
+		/* get the USER-AGENT header value  */
5b8408
+		value = oidc_util_hdr_in_user_agent_get(r);
5b8408
+		/* if we have a value for this header, concat it to the hash input */
5b8408
+		if (value != NULL)
5b8408
+			apr_sha1_update(&sha1, value, strlen(value));
5b8408
+	}
5b8408
 
5b8408
 	/* get the remote client IP address or host name */
5b8408
 	/*
5b8408
@@ -821,7 +825,7 @@ static apr_byte_t oidc_restore_proto_state(request_rec *r, oidc_cfg *c,
5b8408
 	const char *nonce = oidc_proto_state_get_nonce(*proto_state);
5b8408
 
5b8408
 	/* calculate the hash of the browser fingerprint concatenated with the nonce */
5b8408
-	char *calc = oidc_get_browser_state_hash(r, nonce);
5b8408
+	char *calc = oidc_get_browser_state_hash(r, c, nonce);
5b8408
 	/* compare the calculated hash with the value provided in the authorization response */
5b8408
 	if (apr_strnatcmp(calc, state) != 0) {
5b8408
 		oidc_error(r,
5b8408
@@ -2345,7 +2349,7 @@ static int oidc_authenticate_user(request_rec *r, oidc_cfg *c,
5b8408
 		oidc_proto_state_set_pkce_state(proto_state, pkce_state);
5b8408
 
5b8408
 	/* get a hash value that fingerprints the browser concatenated with the random input */
5b8408
-	char *state = oidc_get_browser_state_hash(r, nonce);
5b8408
+	char *state = oidc_get_browser_state_hash(r, c, nonce);
5b8408
 
5b8408
 	/*
5b8408
 	 * create state that restores the context when the authorization response comes in
5b8408
diff --git a/src/mod_auth_openidc.h b/src/mod_auth_openidc.h
5b8408
index c3a0a23..fada56d 100644
5b8408
--- a/src/mod_auth_openidc.h
5b8408
+++ b/src/mod_auth_openidc.h
5b8408
@@ -222,6 +222,9 @@ APLOG_USE_MODULE(auth_openidc);
5b8408
 #define OIDC_TOKEN_BINDING_POLICY_REQUIRED  2
5b8408
 #define OIDC_TOKEN_BINDING_POLICY_ENFORCED  3
5b8408
 
5b8408
+#define OIDC_STATE_INPUT_HEADERS_USER_AGENT 1
5b8408
+#define OIDC_STATE_INPUT_HEADERS_X_FORWARDED_FOR 2
5b8408
+
5b8408
 typedef apr_byte_t (*oidc_proto_pkce_state)(request_rec *r, char **state);
5b8408
 typedef apr_byte_t (*oidc_proto_pkce_challenge)(request_rec *r, const char *state, char **code_challenge);
5b8408
 typedef apr_byte_t (*oidc_proto_pkce_verifier)(request_rec *r, const char *state, char **code_verifier);
5b8408
@@ -403,6 +406,8 @@ typedef struct oidc_cfg {
5b8408
 	apr_hash_t *black_listed_claims;
5b8408
 	apr_hash_t *white_listed_claims;
5b8408
 
5b8408
+	apr_byte_t state_input_headers;
5b8408
+
5b8408
 } oidc_cfg;
5b8408
 
5b8408
 int oidc_check_user_id(request_rec *r);
5b8408
diff --git a/src/parse.c b/src/parse.c
5b8408
index 2d09584..a0cedcb 100644
5b8408
--- a/src/parse.c
5b8408
+++ b/src/parse.c
5b8408
@@ -1254,3 +1254,36 @@ const char *oidc_parse_max_number_of_state_cookies(apr_pool_t *pool,
5b8408
 		rv = oidc_parse_boolean(pool, arg2, bool_value);
5b8408
 	return rv;
5b8408
 }
5b8408
+
5b8408
+#define OIDC_STATE_INPUT_HEADERS_AS_BOTH            "both"
5b8408
+#define OIDC_STATE_INPUT_HEADERS_AS_USER_AGENT      "user-agent"
5b8408
+#define OIDC_STATE_INPUT_HEADERS_AS_X_FORWARDED_FOR "x-forwarded-for"
5b8408
+#define OIDC_STATE_INPUT_HEADERS_AS_NONE            "none"
5b8408
+
5b8408
+/*
5b8408
+ * parse a "set state input headers as" value from the provided string
5b8408
+ */
5b8408
+const char *oidc_parse_set_state_input_headers_as(apr_pool_t *pool, const char *arg,
5b8408
+		apr_byte_t *state_input_headers) {
5b8408
+	static char *options[] = {
5b8408
+			OIDC_STATE_INPUT_HEADERS_AS_BOTH,
5b8408
+			OIDC_STATE_INPUT_HEADERS_AS_USER_AGENT,
5b8408
+			OIDC_STATE_INPUT_HEADERS_AS_X_FORWARDED_FOR,
5b8408
+			OIDC_STATE_INPUT_HEADERS_AS_NONE,
5b8408
+			NULL };
5b8408
+	const char *rv = oidc_valid_string_option(pool, arg, options);
5b8408
+	if (rv != NULL)
5b8408
+		return rv;
5b8408
+
5b8408
+	if (apr_strnatcmp(arg, OIDC_STATE_INPUT_HEADERS_AS_BOTH) == 0) {
5b8408
+		*state_input_headers = OIDC_STATE_INPUT_HEADERS_USER_AGENT | OIDC_STATE_INPUT_HEADERS_X_FORWARDED_FOR;
5b8408
+	} else if (apr_strnatcmp(arg, OIDC_STATE_INPUT_HEADERS_AS_USER_AGENT) == 0) {
5b8408
+		*state_input_headers = OIDC_STATE_INPUT_HEADERS_USER_AGENT;
5b8408
+	} else if (apr_strnatcmp(arg, OIDC_STATE_INPUT_HEADERS_AS_X_FORWARDED_FOR) == 0) {
5b8408
+		*state_input_headers = OIDC_STATE_INPUT_HEADERS_X_FORWARDED_FOR;
5b8408
+	} else if (apr_strnatcmp(arg, OIDC_STATE_INPUT_HEADERS_AS_NONE) == 0) {
5b8408
+		*state_input_headers = 0;
5b8408
+	}
5b8408
+
5b8408
+	return NULL;
5b8408
+}
5b8408
diff --git a/src/parse.h b/src/parse.h
5b8408
index bdf5651..c4301a3 100644
5b8408
--- a/src/parse.h
5b8408
+++ b/src/parse.h
5b8408
@@ -118,6 +118,7 @@ const char *oidc_parse_token_binding_policy(apr_pool_t *pool, const char *arg, i
5b8408
 const char *oidc_token_binding_policy2str(apr_pool_t *pool, int v);
5b8408
 const char *oidc_parse_auth_request_method(apr_pool_t *pool, const char *arg, int *method);
5b8408
 const char *oidc_parse_max_number_of_state_cookies(apr_pool_t *pool, const char *arg1, const char *arg2, int *int_value, int *bool_value);
5b8408
+const char *oidc_parse_set_state_input_headers_as(apr_pool_t *pool, const char *arg, apr_byte_t *state_input_headers);
5b8408
 
5b8408
 typedef const char *(*oidc_valid_int_function_t)(apr_pool_t *, int);
5b8408
 typedef const char *(*oidc_valid_function_t)(apr_pool_t *, const char *);
5b8408
-- 
5b8408
2.26.2
5b8408