Forráskód Böngészése

Allow custom header during bearer token extraction

Added ability to specify the header that
ServerBearerTokenAuthenticationConverter and
DefaultBearerTokenResolver use to extract a Bearer Token.

Fixes gh-8337
Teddy Reinert 5 éve
szülő
commit
2f8eb16d76

+ 17 - 2
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);
 

+ 16 - 2
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<Authentication> 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);
 

+ 10 - 1
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();

+ 11 - 0
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() {