mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-08 05:02:13 +00:00
Polish BearerTokenAuthenticationConverter Support
- Moved to BearerTokenAuthenticationFilter constructor to align with AuthenticationFilter - Undeprecated BearerTokenResolver to reduce number of migration scenarios - Updated to 7.0 schema - Added migration docs Issue gh-14750
This commit is contained in:
parent
30577bd291
commit
eaab42a73c
@ -23,8 +23,6 @@ import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
@ -44,7 +42,6 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
|
||||
@ -69,7 +66,6 @@ import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.accept.ContentNegotiationStrategy;
|
||||
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
|
||||
@ -200,13 +196,9 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated please use {@link #authenticationConverter} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public OAuth2ResourceServerConfigurer<H> bearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
|
||||
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
|
||||
this.authenticationConverter = new BearerTokenResolverAuthenticationConverterAdapter(bearerTokenResolver);
|
||||
this.authenticationConverter = new BearerTokenResolverHoldingAuthenticationConverter(bearerTokenResolver);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -214,7 +206,7 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
* Sets the {@link AuthenticationConverter} to use.
|
||||
* @param authenticationConverter the authentication converter
|
||||
* @return the {@link OAuth2ResourceServerConfigurer} for further configuration
|
||||
* @since 6.5
|
||||
* @since 7.0
|
||||
*/
|
||||
public OAuth2ResourceServerConfigurer<H> authenticationConverter(AuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
@ -299,10 +291,9 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
resolver = (request) -> authenticationManager;
|
||||
}
|
||||
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver);
|
||||
AuthenticationConverter converter = getAuthenticationConverter();
|
||||
this.requestMatcher.setAuthenticationConverter(converter);
|
||||
filter.setAuthenticationConverter(converter);
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver, converter);
|
||||
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
||||
filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
filter = postProcess(filter);
|
||||
@ -394,7 +385,7 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
}
|
||||
else if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) {
|
||||
BearerTokenResolver bearerTokenResolver = this.context.getBean(BearerTokenResolver.class);
|
||||
this.authenticationConverter = new BearerTokenResolverAuthenticationConverterAdapter(bearerTokenResolver);
|
||||
this.authenticationConverter = new BearerTokenResolverHoldingAuthenticationConverter(bearerTokenResolver);
|
||||
}
|
||||
else {
|
||||
this.authenticationConverter = new BearerTokenAuthenticationConverter();
|
||||
@ -404,7 +395,7 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
|
||||
BearerTokenResolver getBearerTokenResolver() {
|
||||
AuthenticationConverter authenticationConverter = getAuthenticationConverter();
|
||||
if (authenticationConverter instanceof BearerTokenResolverAuthenticationConverterAdapter bearer) {
|
||||
if (authenticationConverter instanceof OAuth2ResourceServerConfigurer.BearerTokenResolverHoldingAuthenticationConverter bearer) {
|
||||
return bearer.bearerTokenResolver;
|
||||
}
|
||||
return null;
|
||||
@ -614,24 +605,22 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
||||
|
||||
}
|
||||
|
||||
private static final class BearerTokenResolverAuthenticationConverterAdapter implements AuthenticationConverter {
|
||||
|
||||
private final Log logger = LogFactory.getLog(BearerTokenResolverAuthenticationConverterAdapter.class);
|
||||
private static final class BearerTokenResolverHoldingAuthenticationConverter implements AuthenticationConverter {
|
||||
|
||||
private final BearerTokenResolver bearerTokenResolver;
|
||||
|
||||
BearerTokenResolverAuthenticationConverterAdapter(BearerTokenResolver bearerTokenResolver) {
|
||||
private final AuthenticationConverter authenticationConverter;
|
||||
|
||||
BearerTokenResolverHoldingAuthenticationConverter(BearerTokenResolver bearerTokenResolver) {
|
||||
this.bearerTokenResolver = bearerTokenResolver;
|
||||
BearerTokenAuthenticationConverter authenticationConverter = new BearerTokenAuthenticationConverter();
|
||||
authenticationConverter.setBearerTokenResolver(bearerTokenResolver);
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication convert(HttpServletRequest request) {
|
||||
String token = this.bearerTokenResolver.resolve(request);
|
||||
if (!StringUtils.hasText(token)) {
|
||||
this.logger.trace("Did not process request since did not find bearer token");
|
||||
return null;
|
||||
}
|
||||
return new BearerTokenAuthenticationToken(token);
|
||||
return this.authenticationConverter.convert(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -72,8 +72,6 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
||||
|
||||
static final String BEARER_TOKEN_RESOLVER = "bearerTokenResolver";
|
||||
|
||||
static final String AUTHENTICATION_CONVERTER = "authenticationConverter";
|
||||
|
||||
static final String AUTHENTICATION_ENTRY_POINT = "authenticationEntryPoint";
|
||||
|
||||
private final BeanReference authenticationManager;
|
||||
@ -152,7 +150,7 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
||||
this.authenticationFilterSecurityContextHolderStrategy);
|
||||
|
||||
if (authenticationConverter != null) {
|
||||
filterBuilder.addPropertyValue(AUTHENTICATION_CONVERTER, authenticationConverter);
|
||||
filterBuilder.addConstructorArgValue(authenticationConverter);
|
||||
}
|
||||
if (bearerTokenResolver != null) {
|
||||
filterBuilder.addPropertyValue(BEARER_TOKEN_RESOLVER, bearerTokenResolver);
|
||||
@ -170,7 +168,9 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
||||
}
|
||||
BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(BearerTokenAuthenticationRequestMatcher.class);
|
||||
if (authenticationConverter != null) {
|
||||
requestMatcherBuilder.addConstructorArgValue(authenticationConverter);
|
||||
}
|
||||
return requestMatcherBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
@ -409,6 +409,10 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
||||
|
||||
private final AuthenticationConverter authenticationConverter;
|
||||
|
||||
BearerTokenAuthenticationRequestMatcher() {
|
||||
this.authenticationConverter = new BearerTokenAuthenticationConverter();
|
||||
}
|
||||
|
||||
BearerTokenAuthenticationRequestMatcher(AuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
|
@ -650,9 +650,6 @@ oauth2-resource-server.attlist &=
|
||||
oauth2-resource-server.attlist &=
|
||||
## Reference to a AuthenticationEntryPoint
|
||||
attribute entry-point-ref {xsd:token}?
|
||||
oauth2-resource-server.attlist &=
|
||||
## Reference to a AuthenticationConverter
|
||||
attribute authentication-converter-ref {xsd:token}?
|
||||
|
||||
jwt =
|
||||
## Configures JWT authentication
|
||||
|
@ -1999,12 +1999,6 @@
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="authentication-converter-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Reference to a AuthenticationConverter
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="jwt">
|
||||
<xs:annotation>
|
||||
|
@ -650,6 +650,9 @@ oauth2-resource-server.attlist &=
|
||||
oauth2-resource-server.attlist &=
|
||||
## Reference to a AuthenticationEntryPoint
|
||||
attribute entry-point-ref {xsd:token}?
|
||||
oauth2-resource-server.attlist &=
|
||||
## Reference to a AuthenticationConverter
|
||||
attribute authentication-converter-ref {xsd:token}?
|
||||
|
||||
jwt =
|
||||
## Configures JWT authentication
|
||||
|
@ -1999,6 +1999,12 @@
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="authentication-converter-ref" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Reference to a AuthenticationConverter
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="jwt">
|
||||
<xs:annotation>
|
||||
|
@ -2571,16 +2571,20 @@ public class OAuth2ResourceServerConfigurerTests {
|
||||
|
||||
@Bean
|
||||
AuthenticationConverter authenticationConverterOne() {
|
||||
BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter();
|
||||
converter.setAllowUriQueryParameter(true);
|
||||
return converter;
|
||||
DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver();
|
||||
resolver.setAllowUriQueryParameter(true);
|
||||
BearerTokenAuthenticationConverter authenticationConverter = new BearerTokenAuthenticationConverter();
|
||||
authenticationConverter.setBearerTokenResolver(resolver);
|
||||
return authenticationConverter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationConverter authenticationConverterTwo() {
|
||||
BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter();
|
||||
converter.setAllowUriQueryParameter(true);
|
||||
return converter;
|
||||
DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver();
|
||||
resolver.setAllowUriQueryParameter(true);
|
||||
BearerTokenAuthenticationConverter authenticationConverter = new BearerTokenAuthenticationConverter();
|
||||
authenticationConverter.setBearerTokenResolver(resolver);
|
||||
return authenticationConverter;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -115,3 +115,58 @@ fun authenticationConverter(val registrations: RelyingPartyRegistrationRepositor
|
||||
======
|
||||
|
||||
If you must continue using `Saml2AuthenticationTokenConverter`, `OpenSaml4AuthenticationTokenConverter`, or `OpenSaml5AuthenticationTokenConverter` to process GET requests, you can call `setShouldConvertGetRequests` to `true.`
|
||||
|
||||
== Provide an AuthenticationConverter to BearerTokenAuthenticationFilter
|
||||
|
||||
In Spring Security 7, `BearerTokenAuthenticationFilter#setBearerTokenResolver` and `#setAuthenticaionDetailsSource` are deprecated in favor of configuring those on `BearerTokenAuthenticationConverter`.
|
||||
|
||||
The `oauth2ResourceServer` DSL addresses most use cases and you need to nothing.
|
||||
|
||||
If you are setting a `BearerTokenResolver` or `AuthenticationDetailsSource` directly on `BearerTokenAuthenticationFilter` similar to the following:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(authenticationManager);
|
||||
filter.setBearerTokenResolver(myBearerTokenResolver);
|
||||
filter.setAuthenticationDetailsSource(myAuthenticationDetailsSource);
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
val filter = BearerTokenAuthenticationFilter(authenticationManager)
|
||||
filter.setBearerTokenResolver(myBearerTokenResolver)
|
||||
filter.setAuthenticationDetailsSource(myAuthenticationDetailsSource)
|
||||
----
|
||||
======
|
||||
|
||||
you are encouraged to use `BearerTokenAuthenticationConverter` to specify both:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
BearerTokenAuthenticationConverter authenticationConverter =
|
||||
new BearerTokenAuthenticationConverter();
|
||||
authenticationConverter.setBearerTokenResolver(myBearerTokenResolver);
|
||||
authenticationConverter.setAuthenticationDetailsSource(myAuthenticationDetailsSource);
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(authenticationManager, authenicationConverter);
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
val authenticationConverter = BearerTokenAuthenticationConverter()
|
||||
authenticationConverter.setBearerTokenResolver(myBearerTokenResolver)
|
||||
authenticationConverter.setAuthenticationDetailsSource(myAuthenticationDetailsSource)
|
||||
val filter = BearerTokenAuthenticationFilter(authenticationManager, authenticationConverter)
|
||||
----
|
||||
======
|
||||
|
@ -1266,7 +1266,8 @@ Reference to an `AuthenticationManagerResolver` which will resolve the `Authenti
|
||||
|
||||
[[nsa-oauth2-resource-server-bearer-token-resolver-ref]]
|
||||
* **bearer-token-resolver-ref**
|
||||
Reference to a `BearerTokenResolver` which will retrieve the bearer token from the request
|
||||
Reference to a `BearerTokenResolver` which will retrieve the bearer token from the request.
|
||||
This cannot be used in conjunction with `authentication-converter-ref`
|
||||
|
||||
[[nsa-oauth2-resource-server-entry-point-ref]]
|
||||
* **entry-point-ref**
|
||||
@ -1274,7 +1275,8 @@ Reference to a `AuthenticationEntryPoint` which will handle unauthorized request
|
||||
|
||||
[[nsa-oauth2-resource-server-authentication-converter-ref]]
|
||||
* **authentication-converter-ref**
|
||||
Reference to a `AuthenticationConverter` which convert request to authentication
|
||||
Reference to a `AuthenticationConverter` which convert request to authentication.
|
||||
This cannot be used in conjunction with `bearer-token-resolver-ref`
|
||||
|
||||
[[nsa-jwt]]
|
||||
== <jwt>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -29,10 +29,7 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
* @since 5.1
|
||||
* @see <a href="https://tools.ietf.org/html/rfc6750#section-2" target="_blank">RFC 6750
|
||||
* Section 2: Authenticated Requests</a>
|
||||
* @deprecated Use
|
||||
* {@link org.springframework.security.web.authentication.AuthenticationConverter} instead
|
||||
*/
|
||||
@Deprecated
|
||||
@FunctionalInterface
|
||||
public interface BearerTokenResolver {
|
||||
|
||||
|
@ -16,20 +16,13 @@
|
||||
|
||||
package org.springframework.security.oauth2.server.resource.web.authentication;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenError;
|
||||
import org.springframework.security.oauth2.server.resource.BearerTokenErrors;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
||||
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.util.Assert;
|
||||
@ -40,131 +33,29 @@ import org.springframework.util.StringUtils;
|
||||
* {@link BearerTokenAuthenticationToken}
|
||||
*
|
||||
* @author Max Batischev
|
||||
* @since 6.5
|
||||
* @author Josh Cummings
|
||||
* @since 7.0
|
||||
*/
|
||||
public final class BearerTokenAuthenticationConverter implements AuthenticationConverter {
|
||||
|
||||
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||
|
||||
private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?<token>[a-zA-Z0-9-._~+/]+=*)$",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private static final String ACCESS_TOKEN_PARAMETER_NAME = "access_token";
|
||||
|
||||
private boolean allowFormEncodedBodyParameter = false;
|
||||
|
||||
private boolean allowUriQueryParameter = false;
|
||||
|
||||
private String bearerTokenHeaderName = HttpHeaders.AUTHORIZATION;
|
||||
private BearerTokenResolver bearerTokenResolver = new DefaultBearerTokenResolver();
|
||||
|
||||
@Override
|
||||
public Authentication convert(HttpServletRequest request) {
|
||||
String token = resolveToken(request);
|
||||
String token = this.bearerTokenResolver.resolve(request);
|
||||
if (StringUtils.hasText(token)) {
|
||||
BearerTokenAuthenticationToken authenticationToken = new BearerTokenAuthenticationToken(token);
|
||||
authenticationToken.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
||||
|
||||
return authenticationToken;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String resolveToken(HttpServletRequest request) {
|
||||
final String authorizationHeaderToken = resolveFromAuthorizationHeader(request);
|
||||
final String parameterToken = isParameterTokenSupportedForRequest(request)
|
||||
? resolveFromRequestParameters(request) : null;
|
||||
if (authorizationHeaderToken != null) {
|
||||
if (parameterToken != null) {
|
||||
final BearerTokenError error = BearerTokenErrors
|
||||
.invalidRequest("Found multiple bearer tokens in the request");
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
return authorizationHeaderToken;
|
||||
}
|
||||
if (parameterToken != null && isParameterTokenEnabledForRequest(request)) {
|
||||
return parameterToken;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String resolveFromAuthorizationHeader(HttpServletRequest request) {
|
||||
String authorization = request.getHeader(this.bearerTokenHeaderName);
|
||||
if (!StringUtils.startsWithIgnoreCase(authorization, "bearer")) {
|
||||
return null;
|
||||
}
|
||||
Matcher matcher = authorizationPattern.matcher(authorization);
|
||||
if (!matcher.matches()) {
|
||||
BearerTokenError error = BearerTokenErrors.invalidToken("Bearer token is malformed");
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
return matcher.group("token");
|
||||
}
|
||||
|
||||
private boolean isParameterTokenEnabledForRequest(HttpServletRequest request) {
|
||||
return ((this.allowFormEncodedBodyParameter && isFormEncodedRequest(request) && !isGetRequest(request)
|
||||
&& !hasAccessTokenInQueryString(request)) || (this.allowUriQueryParameter && isGetRequest(request)));
|
||||
}
|
||||
|
||||
private static String resolveFromRequestParameters(HttpServletRequest request) {
|
||||
String[] values = request.getParameterValues(ACCESS_TOKEN_PARAMETER_NAME);
|
||||
if (values == null || values.length == 0) {
|
||||
return null;
|
||||
}
|
||||
if (values.length == 1) {
|
||||
return values[0];
|
||||
}
|
||||
BearerTokenError error = BearerTokenErrors.invalidRequest("Found multiple bearer tokens in the request");
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
|
||||
private boolean isParameterTokenSupportedForRequest(final HttpServletRequest request) {
|
||||
return isFormEncodedRequest(request) || isGetRequest(request);
|
||||
}
|
||||
|
||||
private boolean isGetRequest(HttpServletRequest request) {
|
||||
return HttpMethod.GET.name().equals(request.getMethod());
|
||||
}
|
||||
|
||||
private boolean isFormEncodedRequest(HttpServletRequest request) {
|
||||
return MediaType.APPLICATION_FORM_URLENCODED_VALUE.equals(request.getContentType());
|
||||
}
|
||||
|
||||
private static boolean hasAccessTokenInQueryString(HttpServletRequest request) {
|
||||
return (request.getQueryString() != null) && request.getQueryString().contains(ACCESS_TOKEN_PARAMETER_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if transport of access token using URI query parameter is supported. Defaults
|
||||
* to {@code false}.
|
||||
*
|
||||
* The spec recommends against using this mechanism for sending bearer tokens, and
|
||||
* even goes as far as stating that it was only included for completeness.
|
||||
* @param allowUriQueryParameter if the URI query parameter is supported
|
||||
*/
|
||||
public void setAllowUriQueryParameter(boolean allowUriQueryParameter) {
|
||||
this.allowUriQueryParameter = allowUriQueryParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void setBearerTokenHeaderName(String bearerTokenHeaderName) {
|
||||
this.bearerTokenHeaderName = bearerTokenHeaderName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if transport of access token using form-encoded body parameter is supported.
|
||||
* Defaults to {@code false}.
|
||||
* @param allowFormEncodedBodyParameter if the form-encoded body parameter is
|
||||
* supported
|
||||
*/
|
||||
public void setAllowFormEncodedBodyParameter(boolean allowFormEncodedBodyParameter) {
|
||||
this.allowFormEncodedBodyParameter = allowFormEncodedBodyParameter;
|
||||
public void setBearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
|
||||
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
|
||||
this.bearerTokenResolver = bearerTokenResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,6 +40,7 @@ import org.springframework.security.oauth2.server.resource.BearerTokenErrors;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
||||
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
|
||||
@ -76,6 +77,8 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private final AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
|
||||
|
||||
private final AuthenticationConverter authenticationConverter;
|
||||
|
||||
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
|
||||
.getContextHolderStrategy();
|
||||
|
||||
@ -84,20 +87,15 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
private AuthenticationFailureHandler authenticationFailureHandler = new AuthenticationEntryPointFailureHandler(
|
||||
(request, response, exception) -> this.authenticationEntryPoint.commence(request, response, exception));
|
||||
|
||||
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||
|
||||
private SecurityContextRepository securityContextRepository = new RequestAttributeSecurityContextRepository();
|
||||
|
||||
private AuthenticationConverter authenticationConverter = new BearerTokenAuthenticationConverter();
|
||||
|
||||
/**
|
||||
* Construct a {@code BearerTokenAuthenticationFilter} using the provided parameter(s)
|
||||
* @param authenticationManagerResolver
|
||||
*/
|
||||
public BearerTokenAuthenticationFilter(
|
||||
AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver) {
|
||||
Assert.notNull(authenticationManagerResolver, "authenticationManagerResolver cannot be null");
|
||||
this.authenticationManagerResolver = authenticationManagerResolver;
|
||||
this(authenticationManagerResolver, new BearerTokenAuthenticationConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,8 +103,43 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
* @param authenticationManager
|
||||
*/
|
||||
public BearerTokenAuthenticationFilter(AuthenticationManager authenticationManager) {
|
||||
this(authenticationManager, new BearerTokenAuthenticationConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct this filter using the provided parameters
|
||||
* @param authenticationManager the {@link AuthenticationManager} to use
|
||||
* @param authenticationConverter the {@link AuthenticationConverter} to use
|
||||
* @since 7.0
|
||||
* @see JwtAuthenticationProvider
|
||||
* @see OpaqueTokenAuthenticationProvider
|
||||
* @see BearerTokenAuthenticationConverter
|
||||
*/
|
||||
public BearerTokenAuthenticationFilter(AuthenticationManager authenticationManager,
|
||||
AuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationManager, "authenticationManager cannot be null");
|
||||
this.authenticationManagerResolver = (request) -> authenticationManager;
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
this.authenticationManagerResolver = (authentication) -> authenticationManager;
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct this filter using the provided parameters
|
||||
* @param authenticationManagerResolver the {@link AuthenticationManagerResolver} to
|
||||
* use
|
||||
* @param authenticationConverter the {@link AuthenticationConverter} to use
|
||||
* @since 7.0
|
||||
* @see JwtAuthenticationProvider
|
||||
* @see OpaqueTokenAuthenticationProvider
|
||||
* @see BearerTokenAuthenticationConverter
|
||||
*/
|
||||
public BearerTokenAuthenticationFilter(
|
||||
AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver,
|
||||
AuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationManagerResolver, "authenticationManagerResolver cannot be null");
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
this.authenticationManagerResolver = authenticationManagerResolver;
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -190,17 +223,20 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
* Set the {@link BearerTokenResolver} to use. Defaults to
|
||||
* {@link DefaultBearerTokenResolver}.
|
||||
* @param bearerTokenResolver the {@code BearerTokenResolver} to use
|
||||
* @deprecated Please provide an {@link AuthenticationConverter} in the constructor
|
||||
* instead
|
||||
* @see BearerTokenAuthenticationConverter
|
||||
*/
|
||||
@Deprecated
|
||||
public void setBearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
|
||||
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
|
||||
this.authenticationConverter = (request) -> {
|
||||
String token = bearerTokenResolver.resolve(request);
|
||||
if (!StringUtils.hasText(token)) {
|
||||
this.logger.trace("Did not process request since did not find bearer token");
|
||||
return null;
|
||||
if (this.authenticationConverter instanceof BearerTokenAuthenticationConverter converter) {
|
||||
converter.setBearerTokenResolver(bearerTokenResolver);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
"You cannot both specify an AuthenticationConverter and a BearerTokenResolver.");
|
||||
}
|
||||
return new BearerTokenAuthenticationToken(token);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -227,13 +263,24 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
/**
|
||||
* Set the {@link AuthenticationDetailsSource} to use. Defaults to
|
||||
* {@link WebAuthenticationDetailsSource}.
|
||||
* @param authenticationDetailsSource the {@code AuthenticationConverter} to use
|
||||
* @param authenticationDetailsSource the {@code AuthenticationDetailsSource} to use
|
||||
* @since 5.5
|
||||
* @deprecated Please provide an {@link AuthenticationConverter} in the constructor
|
||||
* and set the {@link AuthenticationDetailsSource} there instead. For example, you can
|
||||
* use {@link BearerTokenAuthenticationConverter#setAuthenticationDetailsSource}
|
||||
* @see BearerTokenAuthenticationConverter
|
||||
*/
|
||||
@Deprecated
|
||||
public void setAuthenticationDetailsSource(
|
||||
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
|
||||
Assert.notNull(authenticationDetailsSource, "authenticationDetailsSource cannot be null");
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
if (this.authenticationConverter instanceof BearerTokenAuthenticationConverter converter) {
|
||||
converter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
"You cannot specify both an AuthenticationConverter and an AuthenticationDetailsSource");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isDPoPBoundAccessToken(Authentication authentication) {
|
||||
@ -249,15 +296,4 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
return StringUtils.hasText(jwkThumbprintClaim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link AuthenticationConverter} to use. Defaults to
|
||||
* {@link BearerTokenAuthenticationConverter}.
|
||||
* @param authenticationConverter the {@code AuthenticationConverter} to use
|
||||
* @since 6.5
|
||||
*/
|
||||
public void setAuthenticationConverter(AuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@ -46,8 +47,14 @@ public class BearerTokenAuthenticationConverterTests {
|
||||
|
||||
private static final String BEARER_TOKEN = "test_bearer_token";
|
||||
|
||||
private final DefaultBearerTokenResolver resolver = new DefaultBearerTokenResolver();
|
||||
|
||||
private final BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter();
|
||||
|
||||
{
|
||||
this.converter.setBearerTokenResolver(this.resolver);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenAuthorizationHeaderIsPresentThenTokenIsConverted() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
@ -64,7 +71,7 @@ public class BearerTokenAuthenticationConverterTests {
|
||||
request.setMethod(HttpMethod.GET.name());
|
||||
request.addParameter("access_token", BEARER_TOKEN);
|
||||
|
||||
this.converter.setAllowUriQueryParameter(true);
|
||||
this.resolver.setAllowUriQueryParameter(true);
|
||||
|
||||
Authentication authentication = this.converter.convert(request);
|
||||
assertThat(authentication).isNotNull();
|
||||
@ -86,6 +93,7 @@ public class BearerTokenAuthenticationConverterTests {
|
||||
request.setMethod(HttpMethod.GET.name());
|
||||
request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + BEARER_TOKEN);
|
||||
|
||||
this.resolver.setAllowUriQueryParameter(true);
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.converter.convert(request))
|
||||
.withMessageContaining("Found multiple bearer tokens in the request");
|
||||
}
|
||||
@ -95,7 +103,7 @@ public class BearerTokenAuthenticationConverterTests {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader(X_AUTH_TOKEN_HEADER, "Bearer " + TEST_X_AUTH_TOKEN);
|
||||
|
||||
this.converter.setBearerTokenHeaderName(X_AUTH_TOKEN_HEADER);
|
||||
this.resolver.setBearerTokenHeaderName(X_AUTH_TOKEN_HEADER);
|
||||
|
||||
Authentication authentication = this.converter.convert(request);
|
||||
assertThat(authentication).isNotNull();
|
||||
@ -140,7 +148,7 @@ public class BearerTokenAuthenticationConverterTests {
|
||||
request.setMethod(HttpMethod.POST.name());
|
||||
request.setContentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
||||
request.addParameter("access_token", BEARER_TOKEN);
|
||||
this.converter.setAllowFormEncodedBodyParameter(true);
|
||||
this.resolver.setAllowFormEncodedBodyParameter(true);
|
||||
|
||||
assertThat(this.converter.convert(request)).isNotNull();
|
||||
}
|
||||
|
@ -75,8 +75,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class BearerTokenAuthenticationFilterTests {
|
||||
|
||||
private static final String TEST_TOKEN = "token";
|
||||
|
||||
@Mock
|
||||
AuthenticationEntryPoint authenticationEntryPoint;
|
||||
|
||||
@ -95,9 +93,6 @@ public class BearerTokenAuthenticationFilterTests {
|
||||
@Mock
|
||||
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;
|
||||
|
||||
@Mock
|
||||
AuthenticationConverter authenticationConverter;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
|
||||
MockHttpServletResponse response;
|
||||
@ -269,6 +264,24 @@ public class BearerTokenAuthenticationFilterTests {
|
||||
assertThat(error.getDescription()).isEqualTo("Invalid bearer token");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenSetAuthenticationConverterAndAuthenticationDetailsSourceThenIllegalArgument(
|
||||
@Mock AuthenticationConverter authenticationConverter) {
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager,
|
||||
authenticationConverter);
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> filter.setAuthenticationDetailsSource(this.authenticationDetailsSource));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenSetBearerTokenResolverAndAuthenticationConverterThenIllegalArgument(
|
||||
@Mock AuthenticationConverter authenticationConverter) {
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager,
|
||||
authenticationConverter);
|
||||
assertThatExceptionOfType(IllegalArgumentException.class)
|
||||
.isThrownBy(() -> filter.setBearerTokenResolver(this.bearerTokenResolver));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthenticationEntryPointWhenNullThenThrowsException() {
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);
|
||||
@ -302,9 +315,8 @@ public class BearerTokenAuthenticationFilterTests {
|
||||
@Test
|
||||
public void setConverterWhenNullThenThrowsException() {
|
||||
// @formatter:off
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> filter.setAuthenticationConverter(null))
|
||||
.isThrownBy(() -> new BearerTokenAuthenticationFilter(this.authenticationManager, null))
|
||||
.withMessageContaining("authenticationConverter cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
@ -327,171 +339,6 @@ public class BearerTokenAuthenticationFilterTests {
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenBearerTokenPresentAndConverterSetThenAuthenticates() throws ServletException, IOException {
|
||||
given(this.authenticationConverter.convert(this.request))
|
||||
.willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN));
|
||||
BearerTokenAuthenticationFilter filter = addMocksWithConverter(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
ArgumentCaptor<BearerTokenAuthenticationToken> captor = ArgumentCaptor
|
||||
.forClass(BearerTokenAuthenticationToken.class);
|
||||
verify(this.authenticationManager).authenticate(captor.capture());
|
||||
assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN);
|
||||
assertThat(this.request.getAttribute(RequestAttributeSecurityContextRepository.DEFAULT_REQUEST_ATTR_NAME))
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenSecurityContextRepositoryAndConverterSetThenSaves() throws ServletException, IOException {
|
||||
SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class);
|
||||
given(this.authenticationConverter.convert(this.request))
|
||||
.willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN));
|
||||
TestingAuthenticationToken expectedAuthentication = new TestingAuthenticationToken("test", "password");
|
||||
given(this.authenticationManager.authenticate(any())).willReturn(expectedAuthentication);
|
||||
BearerTokenAuthenticationFilter filter = addMocksWithConverter(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
filter.setSecurityContextRepository(securityContextRepository);
|
||||
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
ArgumentCaptor<BearerTokenAuthenticationToken> captor = ArgumentCaptor
|
||||
.forClass(BearerTokenAuthenticationToken.class);
|
||||
verify(this.authenticationManager).authenticate(captor.capture());
|
||||
assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN);
|
||||
ArgumentCaptor<SecurityContext> contextArg = ArgumentCaptor.forClass(SecurityContext.class);
|
||||
verify(securityContextRepository).saveContext(contextArg.capture(), eq(this.request), eq(this.response));
|
||||
assertThat(contextArg.getValue().getAuthentication().getName()).isEqualTo(expectedAuthentication.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenUsingAuthenticationManagerResolverAndConverterSetThenAuthenticates() throws Exception {
|
||||
BearerTokenAuthenticationFilter filter = addMocksWithConverter(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManagerResolver));
|
||||
given(this.authenticationConverter.convert(this.request))
|
||||
.willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN));
|
||||
given(this.authenticationManagerResolver.resolve(any())).willReturn(this.authenticationManager);
|
||||
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
ArgumentCaptor<BearerTokenAuthenticationToken> captor = ArgumentCaptor
|
||||
.forClass(BearerTokenAuthenticationToken.class);
|
||||
verify(this.authenticationManager).authenticate(captor.capture());
|
||||
assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN);
|
||||
assertThat(this.request.getAttribute(RequestAttributeSecurityContextRepository.DEFAULT_REQUEST_ATTR_NAME))
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenNoBearerTokenPresentAndConverterSetThenDoesNotAuthenticate()
|
||||
throws ServletException, IOException {
|
||||
given(this.authenticationConverter.convert(this.request)).willReturn(null);
|
||||
BearerTokenAuthenticationFilter filter = addMocksWithConverter(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
verifyNoMoreInteractions(this.authenticationManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenMalformedBearerTokenAndConverterSetThenPropagatesError()
|
||||
throws ServletException, IOException {
|
||||
BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_REQUEST, HttpStatus.BAD_REQUEST,
|
||||
"description", "uri");
|
||||
OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error);
|
||||
given(this.authenticationConverter.convert(this.request)).willThrow(exception);
|
||||
BearerTokenAuthenticationFilter filter = addMocksWithConverter(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
verifyNoMoreInteractions(this.authenticationManager);
|
||||
verify(this.authenticationEntryPoint).commence(this.request, this.response, exception);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenAuthenticationFailsWithDefaultHandlerAndConverterSetThenPropagatesError()
|
||||
throws ServletException, IOException {
|
||||
BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN, HttpStatus.UNAUTHORIZED,
|
||||
"description", "uri");
|
||||
OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error);
|
||||
given(this.authenticationConverter.convert(this.request))
|
||||
.willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN));
|
||||
given(this.authenticationManager.authenticate(any(BearerTokenAuthenticationToken.class))).willThrow(exception);
|
||||
BearerTokenAuthenticationFilter filter = addMocksWithConverter(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
verify(this.authenticationEntryPoint).commence(this.request, this.response, exception);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenAuthenticationFailsWithCustomHandlerAndConverterSetThenPropagatesError()
|
||||
throws ServletException, IOException {
|
||||
BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN, HttpStatus.UNAUTHORIZED,
|
||||
"description", "uri");
|
||||
OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error);
|
||||
given(this.authenticationConverter.convert(this.request))
|
||||
.willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN));
|
||||
given(this.authenticationManager.authenticate(any(BearerTokenAuthenticationToken.class))).willThrow(exception);
|
||||
BearerTokenAuthenticationFilter filter = addMocksWithConverter(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
filter.setAuthenticationFailureHandler(this.authenticationFailureHandler);
|
||||
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
verify(this.authenticationFailureHandler).onAuthenticationFailure(this.request, this.response, exception);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenConverterSetAndAuthenticationServiceExceptionThenRethrows() {
|
||||
AuthenticationServiceException exception = new AuthenticationServiceException("message");
|
||||
given(this.authenticationConverter.convert(this.request))
|
||||
.willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN));
|
||||
given(this.authenticationManager.authenticate(any())).willThrow(exception);
|
||||
BearerTokenAuthenticationFilter filter = addMocksWithConverter(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
|
||||
assertThatExceptionOfType(AuthenticationServiceException.class)
|
||||
.isThrownBy(() -> filter.doFilter(this.request, this.response, this.filterChain));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenConverterSetAndCustomEntryPointAndAuthenticationErrorThenUses()
|
||||
throws ServletException, IOException {
|
||||
AuthenticationException exception = new InvalidBearerTokenException("message");
|
||||
given(this.authenticationConverter.convert(this.request))
|
||||
.willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN));
|
||||
given(this.authenticationManager.authenticate(any())).willThrow(exception);
|
||||
BearerTokenAuthenticationFilter filter = addMocksWithConverter(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
AuthenticationEntryPoint entrypoint = mock(AuthenticationEntryPoint.class);
|
||||
filter.setAuthenticationEntryPoint(entrypoint);
|
||||
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
verify(entrypoint).commence(any(), any(), any(InvalidBearerTokenException.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenConverterSetCustomSecurityContextHolderStrategyThenUses()
|
||||
throws ServletException, IOException {
|
||||
given(this.authenticationConverter.convert(this.request))
|
||||
.willReturn(new BearerTokenAuthenticationToken(TEST_TOKEN));
|
||||
BearerTokenAuthenticationFilter filter = addMocksWithConverter(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
|
||||
given(strategy.createEmptyContext()).willReturn(new SecurityContextImpl());
|
||||
filter.setSecurityContextHolderStrategy(strategy);
|
||||
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
verify(strategy).setContext(any());
|
||||
}
|
||||
|
||||
private BearerTokenAuthenticationFilter addMocks(BearerTokenAuthenticationFilter filter) {
|
||||
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
||||
filter.setBearerTokenResolver(this.bearerTokenResolver);
|
||||
@ -506,10 +353,4 @@ public class BearerTokenAuthenticationFilterTests {
|
||||
verifyNoMoreInteractions(this.authenticationManager);
|
||||
}
|
||||
|
||||
private BearerTokenAuthenticationFilter addMocksWithConverter(BearerTokenAuthenticationFilter filter) {
|
||||
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
||||
filter.setAuthenticationConverter(this.authenticationConverter);
|
||||
return filter;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user