diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java index f96cdbcddb..386b6ebfcf 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolver.java @@ -45,6 +45,8 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver { private boolean allowUriQueryParameter = false; + private String bearerTokenHeaderName = HttpHeaders.AUTHORIZATION; + /** * {@inheritDoc} */ @@ -85,8 +87,21 @@ public final class DefaultBearerTokenResolver implements BearerTokenResolver { this.allowUriQueryParameter = allowUriQueryParameter; } - private static String resolveFromAuthorizationHeader(HttpServletRequest request) { - String authorization = request.getHeader(HttpHeaders.AUTHORIZATION); + /** + * Set this value to configure what header is checked when resolving a Bearer Token. + * This value is defaulted to {@link HttpHeaders#AUTHORIZATION}. + * + * This allows other headers to be used as the Bearer Token source such as {@link HttpHeaders#PROXY_AUTHORIZATION} + * + * @param bearerTokenHeaderName the header to check when retrieving the Bearer Token. + * @since 5.4 + */ + public void setBearerTokenHeaderName(String bearerTokenHeaderName) { + this.bearerTokenHeaderName = bearerTokenHeaderName; + } + + private String resolveFromAuthorizationHeader(HttpServletRequest request) { + String authorization = request.getHeader(this.bearerTokenHeaderName); if (StringUtils.startsWithIgnoreCase(authorization, "bearer")) { Matcher matcher = authorizationPattern.matcher(authorization); diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java index f6dda6cab7..eaa579c4d4 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverter.java @@ -50,6 +50,7 @@ public class ServerBearerTokenAuthenticationConverter Pattern.CASE_INSENSITIVE); private boolean allowUriQueryParameter = false; + private String bearerTokenHeaderName = HttpHeaders.AUTHORIZATION; public Mono convert(ServerWebExchange exchange) { return Mono.justOrEmpty(token(exchange.getRequest())) @@ -90,8 +91,21 @@ public class ServerBearerTokenAuthenticationConverter this.allowUriQueryParameter = allowUriQueryParameter; } - private static String resolveFromAuthorizationHeader(HttpHeaders headers) { - String authorization = headers.getFirst(HttpHeaders.AUTHORIZATION); + /** + * Set this value to configure what header is checked when resolving a Bearer Token. + * This value is defaulted to {@link HttpHeaders#AUTHORIZATION}. + * + * This allows other headers to be used as the Bearer Token source such as {@link HttpHeaders#PROXY_AUTHORIZATION} + * + * @param bearerTokenHeaderName the header to check when retrieving the Bearer Token. + * @since 5.4 + */ + public void setBearerTokenHeaderName(String bearerTokenHeaderName) { + this.bearerTokenHeaderName = bearerTokenHeaderName; + } + + private String resolveFromAuthorizationHeader(HttpHeaders headers) { + String authorization = headers.getFirst(this.bearerTokenHeaderName); if (StringUtils.startsWithIgnoreCase(authorization, "bearer")) { Matcher matcher = authorizationPattern.matcher(authorization); diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java index d048736942..f2015a6b07 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/DefaultBearerTokenResolverTests.java @@ -33,7 +33,7 @@ import static org.assertj.core.api.Assertions.assertThatCode; * @author Vedran Pavic */ public class DefaultBearerTokenResolverTests { - + private static final String CUSTOM_HEADER = "custom-header"; private static final String TEST_TOKEN = "test-token"; private DefaultBearerTokenResolver resolver; @@ -51,6 +51,15 @@ public class DefaultBearerTokenResolverTests { assertThat(this.resolver.resolve(request)).isEqualTo(TEST_TOKEN); } + @Test + public void resolveWhenCustomDefinedHeaderIsValidAndPresentThenTokenIsResolved() { + this.resolver.setBearerTokenHeaderName(CUSTOM_HEADER); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader(CUSTOM_HEADER, "Bearer " + TEST_TOKEN); + + assertThat(this.resolver.resolve(request)).isEqualTo(TEST_TOKEN); + } + @Test public void resolveWhenLowercaseHeaderIsPresentThenTokenIsResolved() { MockHttpServletRequest request = new MockHttpServletRequest(); diff --git a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverterTests.java b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverterTests.java index 1a36a2eef8..f3e8eefefd 100644 --- a/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverterTests.java +++ b/oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/web/server/ServerBearerTokenAuthenticationConverterTests.java @@ -38,6 +38,7 @@ import static org.assertj.core.api.Assertions.catchThrowableOfType; * @since 5.1 */ public class ServerBearerTokenAuthenticationConverterTests { + private static final String CUSTOM_HEADER = "custom-header"; private static final String TEST_TOKEN = "test-token"; private ServerBearerTokenAuthenticationConverter converter; @@ -56,6 +57,16 @@ public class ServerBearerTokenAuthenticationConverterTests { assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN); } + @Test + public void resolveWhenCustomDefinedHeaderIsValidAndPresentThenTokenIsResolved() { + this.converter.setBearerTokenHeaderName(CUSTOM_HEADER); + MockServerHttpRequest.BaseBuilder request = MockServerHttpRequest + .get("/") + .header(CUSTOM_HEADER, "Bearer " + TEST_TOKEN); + + assertThat(convertToToken(request).getToken()).isEqualTo(TEST_TOKEN); + } + // gh-7011 @Test public void resolveWhenValidHeaderIsEmptyStringThenTokenIsResolved() {