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

241 lines
10 KiB
Diff

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