Add support BearerTokenAuthenticationConverter
Closes gh-14750
This commit is contained in:
parent
c8e5fbf21b
commit
3317b0d9b8
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -41,6 +41,7 @@ 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.BearerTokenAuthenticationConverter;
|
||||
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;
|
||||
|
@ -49,13 +50,13 @@ import org.springframework.security.oauth2.server.resource.introspection.OpaqueT
|
|||
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;
|
||||
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;
|
||||
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
||||
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.web.access.DelegatingAccessDeniedHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.csrf.CsrfException;
|
||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||
|
@ -68,9 +69,8 @@ import org.springframework.web.accept.ContentNegotiationStrategy;
|
|||
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
||||
|
||||
/**
|
||||
*
|
||||
* An {@link AbstractHttpConfigurer} for OAuth 2.0 Resource Server Support.
|
||||
*
|
||||
* <p>
|
||||
* By default, this wires a {@link BearerTokenAuthenticationFilter}, which can be used to
|
||||
* parse the request for bearer tokens and make an authentication attempt.
|
||||
*
|
||||
|
@ -84,6 +84,8 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
|||
* authentication failures are handled
|
||||
* <li>{@link #bearerTokenResolver(BearerTokenResolver)} - customizes how to resolve a
|
||||
* bearer token from the request</li>
|
||||
* <li>{@link #authenticationConverter(AuthenticationConverter)} - customizes how to
|
||||
* convert a request to authentication</li>
|
||||
* <li>{@link #jwt(Customizer)} - enables Jwt-encoded bearer token support</li>
|
||||
* <li>{@link #opaqueToken(Customizer)} - enables opaque bearer token support</li>
|
||||
* </ul>
|
||||
|
@ -96,7 +98,7 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
|||
* <li>supply a {@link JwtDecoder} instance via {@link JwtConfigurer#decoder}, or</li>
|
||||
* <li>expose a {@link JwtDecoder} bean</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Also with {@link #jwt(Customizer)} consider
|
||||
*
|
||||
* <ul>
|
||||
|
@ -111,7 +113,7 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
|||
* </p>
|
||||
*
|
||||
* <h2>Security Filters</h2>
|
||||
*
|
||||
* <p>
|
||||
* The following {@code Filter}s are populated when {@link #jwt(Customizer)} is
|
||||
* configured:
|
||||
*
|
||||
|
@ -120,7 +122,7 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
|||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Created</h2>
|
||||
*
|
||||
* <p>
|
||||
* The following shared objects are populated:
|
||||
*
|
||||
* <ul>
|
||||
|
@ -128,7 +130,7 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
|||
* </ul>
|
||||
*
|
||||
* <h2>Shared Objects Used</h2>
|
||||
*
|
||||
* <p>
|
||||
* The following shared objects are used:
|
||||
*
|
||||
* <ul>
|
||||
|
@ -156,6 +158,8 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|||
|
||||
private BearerTokenResolver bearerTokenResolver;
|
||||
|
||||
private AuthenticationConverter authenticationConverter;
|
||||
|
||||
private JwtConfigurer jwtConfigurer;
|
||||
|
||||
private OpaqueTokenConfigurer opaqueTokenConfigurer;
|
||||
|
@ -198,6 +202,12 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|||
return this;
|
||||
}
|
||||
|
||||
public OAuth2ResourceServerConfigurer<H> authenticationConverter(AuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated For removal in 7.0. Use {@link #jwt(Customizer)} or
|
||||
* {@code jwt(Customizer.withDefaults())} to stick with defaults. See the <a href=
|
||||
|
@ -269,16 +279,25 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|||
|
||||
@Override
|
||||
public void configure(H http) {
|
||||
BearerTokenResolver bearerTokenResolver = getBearerTokenResolver();
|
||||
this.requestMatcher.setBearerTokenResolver(bearerTokenResolver);
|
||||
AuthenticationManagerResolver resolver = this.authenticationManagerResolver;
|
||||
if (resolver == null) {
|
||||
AuthenticationManager authenticationManager = getAuthenticationManager(http);
|
||||
resolver = (request) -> authenticationManager;
|
||||
}
|
||||
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver);
|
||||
filter.setBearerTokenResolver(bearerTokenResolver);
|
||||
|
||||
BearerTokenResolver bearerTokenResolver = getBearerTokenResolver();
|
||||
if (bearerTokenResolver != null) {
|
||||
this.requestMatcher.setBearerTokenResolver(bearerTokenResolver);
|
||||
filter.setBearerTokenResolver(bearerTokenResolver);
|
||||
}
|
||||
else {
|
||||
AuthenticationConverter converter = getAuthenticationConverter();
|
||||
this.requestMatcher.setAuthenticationConverter(converter);
|
||||
filter.setAuthenticationConverter(converter);
|
||||
}
|
||||
|
||||
filter.setAuthenticationConverter(getAuthenticationConverter());
|
||||
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
||||
filter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
|
||||
filter = postProcess(filter);
|
||||
|
@ -366,13 +385,22 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|||
if (this.context.getBeanNamesForType(BearerTokenResolver.class).length > 0) {
|
||||
this.bearerTokenResolver = this.context.getBean(BearerTokenResolver.class);
|
||||
}
|
||||
else {
|
||||
this.bearerTokenResolver = new DefaultBearerTokenResolver();
|
||||
}
|
||||
}
|
||||
return this.bearerTokenResolver;
|
||||
}
|
||||
|
||||
AuthenticationConverter getAuthenticationConverter() {
|
||||
if (this.authenticationConverter == null) {
|
||||
if (this.context.getBeanNamesForType(AuthenticationConverter.class).length > 0) {
|
||||
this.authenticationConverter = this.context.getBean(AuthenticationConverter.class);
|
||||
}
|
||||
else {
|
||||
this.authenticationConverter = new BearerTokenAuthenticationConverter();
|
||||
}
|
||||
}
|
||||
return this.authenticationConverter;
|
||||
}
|
||||
|
||||
public class JwtConfigurer {
|
||||
|
||||
private final ApplicationContext context;
|
||||
|
@ -560,10 +588,15 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|||
|
||||
private BearerTokenResolver bearerTokenResolver;
|
||||
|
||||
private AuthenticationConverter authenticationConverter;
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
try {
|
||||
return this.bearerTokenResolver.resolve(request) != null;
|
||||
if (this.bearerTokenResolver != null) {
|
||||
return this.bearerTokenResolver.resolve(request) != null;
|
||||
}
|
||||
return this.authenticationConverter.convert(request) != null;
|
||||
}
|
||||
catch (OAuth2AuthenticationException ex) {
|
||||
return false;
|
||||
|
@ -575,6 +608,11 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|||
this.bearerTokenResolver = tokenResolver;
|
||||
}
|
||||
|
||||
void setAuthenticationConverter(AuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -37,15 +37,16 @@ import org.springframework.security.config.Elements;
|
|||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationConverter;
|
||||
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;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
|
||||
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;
|
||||
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
||||
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
@ -64,10 +65,14 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
|||
|
||||
static final String BEARER_TOKEN_RESOLVER_REF = "bearer-token-resolver-ref";
|
||||
|
||||
static final String AUTHENTICATION_CONVERTER_REF = "authentication-converter-ref";
|
||||
|
||||
static final String ENTRY_POINT_REF = "entry-point-ref";
|
||||
|
||||
static final String BEARER_TOKEN_RESOLVER = "bearerTokenResolver";
|
||||
|
||||
static final String AUTHENTICATION_CONVERTER = "authenticationConverter";
|
||||
|
||||
static final String AUTHENTICATION_ENTRY_POINT = "authenticationEntryPoint";
|
||||
|
||||
private final BeanReference authenticationManager;
|
||||
|
@ -124,11 +129,9 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
|||
pc.getReaderContext().registerWithGeneratedName(opaqueTokenAuthenticationProvider)));
|
||||
}
|
||||
BeanMetadataElement bearerTokenResolver = getBearerTokenResolver(oauth2ResourceServer);
|
||||
BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(BearerTokenRequestMatcher.class);
|
||||
requestMatcherBuilder.addConstructorArgValue(bearerTokenResolver);
|
||||
BeanDefinition requestMatcher = requestMatcherBuilder.getBeanDefinition();
|
||||
BeanMetadataElement authenticationConverter = getAuthenticationConverter(oauth2ResourceServer);
|
||||
BeanMetadataElement authenticationEntryPoint = getEntryPoint(oauth2ResourceServer);
|
||||
BeanDefinition requestMatcher = buildRequestMatcher(bearerTokenResolver, authenticationConverter);
|
||||
this.entryPoints.put(requestMatcher, authenticationEntryPoint);
|
||||
this.deniedHandlers.put(requestMatcher, this.accessDeniedHandler);
|
||||
this.ignoreCsrfRequestMatchers.add(requestMatcher);
|
||||
|
@ -136,13 +139,30 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
|||
.rootBeanDefinition(BearerTokenAuthenticationFilter.class);
|
||||
BeanMetadataElement authenticationManagerResolver = getAuthenticationManagerResolver(oauth2ResourceServer);
|
||||
filterBuilder.addConstructorArgValue(authenticationManagerResolver);
|
||||
filterBuilder.addPropertyValue(BEARER_TOKEN_RESOLVER, bearerTokenResolver);
|
||||
filterBuilder.addPropertyValue(AUTHENTICATION_CONVERTER, authenticationConverter);
|
||||
filterBuilder.addPropertyValue(AUTHENTICATION_ENTRY_POINT, authenticationEntryPoint);
|
||||
filterBuilder.addPropertyValue("securityContextHolderStrategy",
|
||||
this.authenticationFilterSecurityContextHolderStrategy);
|
||||
if (bearerTokenResolver != null) {
|
||||
filterBuilder.addPropertyValue(BEARER_TOKEN_RESOLVER, bearerTokenResolver);
|
||||
}
|
||||
return filterBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
private BeanDefinition buildRequestMatcher(BeanMetadataElement bearerTokenResolver,
|
||||
BeanMetadataElement authenticationConverter) {
|
||||
if (bearerTokenResolver != null) {
|
||||
BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(BearerTokenRequestMatcher.class);
|
||||
requestMatcherBuilder.addConstructorArgValue(bearerTokenResolver);
|
||||
return requestMatcherBuilder.getBeanDefinition();
|
||||
}
|
||||
BeanDefinitionBuilder requestMatcherBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(BearerTokenAuthenticationRequestMatcher.class);
|
||||
requestMatcherBuilder.addConstructorArgValue(authenticationConverter);
|
||||
return requestMatcherBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
void validateConfiguration(Element oauth2ResourceServer, Element jwt, Element opaqueToken, ParserContext pc) {
|
||||
if (!oauth2ResourceServer.hasAttribute(AUTHENTICATION_MANAGER_RESOLVER_REF)) {
|
||||
if (jwt == null && opaqueToken == null) {
|
||||
|
@ -178,11 +198,19 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
|||
BeanMetadataElement getBearerTokenResolver(Element element) {
|
||||
String bearerTokenResolverRef = element.getAttribute(BEARER_TOKEN_RESOLVER_REF);
|
||||
if (!StringUtils.hasLength(bearerTokenResolverRef)) {
|
||||
return new RootBeanDefinition(DefaultBearerTokenResolver.class);
|
||||
return null;
|
||||
}
|
||||
return new RuntimeBeanReference(bearerTokenResolverRef);
|
||||
}
|
||||
|
||||
BeanMetadataElement getAuthenticationConverter(Element element) {
|
||||
String authenticationConverterRef = element.getAttribute(AUTHENTICATION_CONVERTER_REF);
|
||||
if (!StringUtils.hasLength(authenticationConverterRef)) {
|
||||
return new RootBeanDefinition(BearerTokenAuthenticationConverter.class);
|
||||
}
|
||||
return new RuntimeBeanReference(authenticationConverterRef);
|
||||
}
|
||||
|
||||
BeanMetadataElement getEntryPoint(Element element) {
|
||||
String entryPointRef = element.getAttribute(ENTRY_POINT_REF);
|
||||
if (!StringUtils.hasLength(entryPointRef)) {
|
||||
|
@ -366,4 +394,25 @@ final class OAuth2ResourceServerBeanDefinitionParser implements BeanDefinitionPa
|
|||
|
||||
}
|
||||
|
||||
static final class BearerTokenAuthenticationRequestMatcher implements RequestMatcher {
|
||||
|
||||
private final AuthenticationConverter authenticationConverter;
|
||||
|
||||
BearerTokenAuthenticationRequestMatcher(AuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(HttpServletRequest request) {
|
||||
try {
|
||||
return this.authenticationConverter.convert(request) != null;
|
||||
}
|
||||
catch (OAuth2AuthenticationException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -117,6 +117,7 @@ import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
|
|||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.TestJwts;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtIssuerAuthenticationManagerResolver;
|
||||
|
@ -133,6 +134,7 @@ import org.springframework.security.web.AuthenticationEntryPoint;
|
|||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultMatcher;
|
||||
|
@ -760,10 +762,44 @@ public class OAuth2ResourceServerConfigurerTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void getBearerTokenResolverWhenNoResolverSpecifiedThenTheDefaultIsUsed() {
|
||||
public void getAuthenticationConverterWhenDuplicateConverterBeansAndAnotherOnTheDslThenTheDslOneIsUsed() {
|
||||
AuthenticationConverter converter = mock(AuthenticationConverter.class);
|
||||
AuthenticationConverter converterBean = mock(AuthenticationConverter.class);
|
||||
GenericWebApplicationContext context = new GenericWebApplicationContext();
|
||||
context.registerBean("converterOne", AuthenticationConverter.class, () -> converterBean);
|
||||
context.registerBean("converterTwo", AuthenticationConverter.class, () -> converterBean);
|
||||
this.spring.context(context).autowire();
|
||||
OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context);
|
||||
oauth2.authenticationConverter(converter);
|
||||
assertThat(oauth2.getAuthenticationConverter()).isEqualTo(converter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAuthenticationConverterWhenConverterBeanAndAnotherOnTheDslThenTheDslOneIsUsed() {
|
||||
AuthenticationConverter converter = mock(AuthenticationConverter.class);
|
||||
AuthenticationConverter converterBean = mock(AuthenticationConverter.class);
|
||||
GenericWebApplicationContext context = new GenericWebApplicationContext();
|
||||
context.registerBean(AuthenticationConverter.class, () -> converterBean);
|
||||
this.spring.context(context).autowire();
|
||||
OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context);
|
||||
oauth2.authenticationConverter(converter);
|
||||
assertThat(oauth2.getAuthenticationConverter()).isEqualTo(converter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAuthenticationConverterWhenDuplicateConverterBeansThenWiringException() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(
|
||||
() -> this.spring.register(MultipleAuthenticationConverterBeansConfig.class, JwtDecoderConfig.class)
|
||||
.autowire())
|
||||
.withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAuthenticationConverterWhenNoConverterSpecifiedThenTheDefaultIsUsed() {
|
||||
ApplicationContext context = this.spring.context(new GenericWebApplicationContext()).getContext();
|
||||
OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context);
|
||||
assertThat(oauth2.getBearerTokenResolver()).isInstanceOf(DefaultBearerTokenResolver.class);
|
||||
assertThat(oauth2.getAuthenticationConverter()).isInstanceOf(BearerTokenAuthenticationConverter.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1999,6 +2035,39 @@ public class OAuth2ResourceServerConfigurerTests {
|
|||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class MultipleAuthenticationConverterBeansConfig {
|
||||
|
||||
@Bean
|
||||
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.oauth2ResourceServer()
|
||||
.jwt();
|
||||
return http.build();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationConverter authenticationConverterOne() {
|
||||
BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter();
|
||||
converter.setAllowUriQueryParameter(true);
|
||||
return converter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
AuthenticationConverter authenticationConverterTwo() {
|
||||
BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter();
|
||||
converter.setAllowUriQueryParameter(true);
|
||||
return converter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class MultipleBearerTokenResolverBeansConfig {
|
||||
|
@ -2048,6 +2117,7 @@ public class OAuth2ResourceServerConfigurerTests {
|
|||
)
|
||||
.oauth2ResourceServer((oauth2) -> oauth2
|
||||
.jwt(withDefaults())
|
||||
.bearerTokenResolver(new DefaultBearerTokenResolver())
|
||||
.withObjectPostProcessor(new ObjectPostProcessor<BearerTokenAuthenticationFilter>() {
|
||||
@Override
|
||||
public BearerTokenAuthenticationFilter postProcess(BearerTokenAuthenticationFilter object) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -522,11 +522,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void getBearerTokenResolverWhenNoResolverSpecifiedThenTheDefaultIsUsed() {
|
||||
public void getAuthenticationConverterWhenNoConverterSpecifiedThenTheDefaultIsUsed() {
|
||||
OAuth2ResourceServerBeanDefinitionParser oauth2 = new OAuth2ResourceServerBeanDefinitionParser(
|
||||
mock(BeanReference.class), mock(List.class), mock(Map.class), mock(Map.class), mock(List.class),
|
||||
mock(BeanMetadataElement.class));
|
||||
assertThat(oauth2.getBearerTokenResolver(mock(Element.class))).isInstanceOf(RootBeanDefinition.class);
|
||||
assertThat(oauth2.getAuthenticationConverter(mock(Element.class))).isInstanceOf(RootBeanDefinition.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.oauth2.server.resource.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.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link AuthenticationConverter}, that converts request to
|
||||
* {@link BearerTokenAuthenticationToken}
|
||||
*
|
||||
* @author Max Batischev
|
||||
* @since 6.3
|
||||
*/
|
||||
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;
|
||||
|
||||
@Override
|
||||
public Authentication convert(HttpServletRequest request) {
|
||||
String token = resolveToken(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link AuthenticationDetailsSource} to use. Defaults to
|
||||
* {@link WebAuthenticationDetailsSource}.
|
||||
* @param authenticationDetailsSource the {@code AuthenticationDetailsSource} to use
|
||||
*/
|
||||
public void setAuthenticationDetailsSource(
|
||||
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
|
||||
Assert.notNull(authenticationDetailsSource, "authenticationDetailsSource cannot be null");
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -33,25 +33,28 @@ import org.springframework.security.core.context.SecurityContext;
|
|||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationConverter;
|
||||
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.web.BearerTokenAuthenticationEntryPoint;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
||||
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
/**
|
||||
* Authenticates requests that contain an OAuth 2.0
|
||||
* <a href="https://tools.ietf.org/html/rfc6750#section-1.2" target="_blank">Bearer
|
||||
* Token</a>.
|
||||
*
|
||||
* <p>
|
||||
* This filter should be wired with an {@link AuthenticationManager} that can authenticate
|
||||
* a {@link BearerTokenAuthenticationToken}.
|
||||
*
|
||||
|
@ -76,12 +79,14 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
|
|||
private AuthenticationFailureHandler authenticationFailureHandler = new AuthenticationEntryPointFailureHandler(
|
||||
(request, response, exception) -> this.authenticationEntryPoint.commence(request, response, exception));
|
||||
|
||||
private BearerTokenResolver bearerTokenResolver = new DefaultBearerTokenResolver();
|
||||
private BearerTokenResolver bearerTokenResolver;
|
||||
|
||||
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
|
||||
|
@ -114,27 +119,35 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
|
|||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
String token;
|
||||
Authentication authentication;
|
||||
try {
|
||||
token = this.bearerTokenResolver.resolve(request);
|
||||
if (this.bearerTokenResolver != null) {
|
||||
String token = this.bearerTokenResolver.resolve(request);
|
||||
if (!StringUtils.hasText(token)) {
|
||||
this.logger.trace("Did not process request since did not find bearer token");
|
||||
return;
|
||||
}
|
||||
authentication = bearerTokenAuthenticationToken(token, request);
|
||||
}
|
||||
else {
|
||||
authentication = this.authenticationConverter.convert(request);
|
||||
}
|
||||
}
|
||||
catch (OAuth2AuthenticationException invalid) {
|
||||
this.logger.trace("Sending to authentication entry point since failed to resolve bearer token", invalid);
|
||||
this.authenticationEntryPoint.commence(request, response, invalid);
|
||||
return;
|
||||
}
|
||||
if (token == null) {
|
||||
this.logger.trace("Did not process request since did not find bearer token");
|
||||
|
||||
if (authentication == null) {
|
||||
this.logger.trace("Failed to convert authentication request");
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
BearerTokenAuthenticationToken authenticationRequest = new BearerTokenAuthenticationToken(token);
|
||||
authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
||||
|
||||
try {
|
||||
AuthenticationManager authenticationManager = this.authenticationManagerResolver.resolve(request);
|
||||
Authentication authenticationResult = authenticationManager.authenticate(authenticationRequest);
|
||||
Authentication authenticationResult = authenticationManager.authenticate(authentication);
|
||||
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
|
||||
context.setAuthentication(authenticationResult);
|
||||
this.securityContextHolderStrategy.setContext(context);
|
||||
|
@ -151,6 +164,12 @@ public class BearerTokenAuthenticationFilter extends OncePerRequestFilter {
|
|||
}
|
||||
}
|
||||
|
||||
private Authentication bearerTokenAuthenticationToken(String token, HttpServletRequest request) {
|
||||
BearerTokenAuthenticationToken authenticationToken = new BearerTokenAuthenticationToken(token);
|
||||
authenticationToken.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
||||
return authenticationToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
|
||||
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
|
||||
|
@ -208,13 +227,26 @@ 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
|
||||
*/
|
||||
public void setAuthenticationDetailsSource(
|
||||
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
|
||||
Assert.notNull(authenticationDetailsSource, "authenticationDetailsSource cannot be null");
|
||||
Assert.notNull(this.bearerTokenResolver,
|
||||
"bearerTokenResolver cannot be null, required authenticationDetailsSource must be set to authenticationConverter");
|
||||
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link AuthenticationConverter} to use. Defaults to
|
||||
* {@link BearerTokenAuthenticationConverter}.
|
||||
* @param authenticationConverter the {@code AuthenticationConverter} to use
|
||||
* @since 6.3
|
||||
*/
|
||||
public void setAuthenticationConverter(AuthenticationConverter authenticationConverter) {
|
||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
||||
this.authenticationConverter = authenticationConverter;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.oauth2.server.resource.authentication;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
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 static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Tests for {@link BearerTokenAuthenticationConverter}
|
||||
*
|
||||
* @author Max Batischev
|
||||
*/
|
||||
public class BearerTokenAuthenticationConverterTests {
|
||||
|
||||
private static final String X_AUTH_TOKEN_HEADER = "X-Auth-Token";
|
||||
|
||||
private static final String TEST_X_AUTH_TOKEN = "test-x-auth-token";
|
||||
|
||||
private static final String BEARER_TOKEN = "test_bearer_token";
|
||||
|
||||
private final BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter();
|
||||
|
||||
@Test
|
||||
public void convertWhenAuthorizationHeaderIsPresentThenTokenIsConverted() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + BEARER_TOKEN);
|
||||
|
||||
Authentication authentication = this.converter.convert(request);
|
||||
|
||||
assertThat(authentication).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenQueryParameterIsPresentThenTokenIsConverted() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod(HttpMethod.GET.name());
|
||||
request.addParameter("access_token", BEARER_TOKEN);
|
||||
|
||||
this.converter.setAllowUriQueryParameter(true);
|
||||
|
||||
Authentication authentication = this.converter.convert(request);
|
||||
assertThat(authentication).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenAuthorizationHeaderNotIsPresentThenTokenIsNotConverted() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
Authentication authentication = this.converter.convert(request);
|
||||
|
||||
assertThat(authentication).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenAuthorizationHeaderIsPresentTogetherWithQueryParameterThenAuthenticationExceptionIsThrown() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addParameter("access_token", BEARER_TOKEN);
|
||||
request.setMethod(HttpMethod.GET.name());
|
||||
request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + BEARER_TOKEN);
|
||||
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.converter.convert(request))
|
||||
.withMessageContaining("Found multiple bearer tokens in the request");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenXAuthTokenHeaderIsPresentAndBearerTokenHeaderNameSetThenTokenIsConverted() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader(X_AUTH_TOKEN_HEADER, "Bearer " + TEST_X_AUTH_TOKEN);
|
||||
|
||||
this.converter.setBearerTokenHeaderName(X_AUTH_TOKEN_HEADER);
|
||||
|
||||
Authentication authentication = this.converter.convert(request);
|
||||
assertThat(authentication).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenHeaderWithMissingTokenIsPresentThenAuthenticationExceptionIsThrown() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer ");
|
||||
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.converter.convert(request))
|
||||
.withMessageContaining(("Bearer token is malformed"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenHeaderWithInvalidCharactersIsPresentThenAuthenticationExceptionIsThrown() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer an\"invalid\"token");
|
||||
|
||||
assertThatExceptionOfType(OAuth2AuthenticationException.class).isThrownBy(() -> this.converter.convert(request))
|
||||
.withMessageContaining(("Bearer token is malformed"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void convertWhenCustomAuthenticationDetailsSourceSetThenTokenIsConverted() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + BEARER_TOKEN);
|
||||
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = Mockito
|
||||
.mock(AuthenticationDetailsSource.class);
|
||||
this.converter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||
|
||||
Authentication authentication = this.converter.convert(request);
|
||||
|
||||
verify(authenticationDetailsSource).buildDetails(any());
|
||||
assertThat(authentication).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertWhenFormParameterIsPresentAndAllowFormEncodedBodyParameterThenConverted() {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod(HttpMethod.POST.name());
|
||||
request.setContentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
||||
request.addParameter("access_token", BEARER_TOKEN);
|
||||
this.converter.setAllowFormEncodedBodyParameter(true);
|
||||
|
||||
assertThat(this.converter.convert(request)).isNotNull();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2024 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.
|
||||
|
@ -47,6 +47,7 @@ import org.springframework.security.oauth2.server.resource.InvalidBearerTokenExc
|
|||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
|
||||
import org.springframework.security.web.context.SecurityContextRepository;
|
||||
|
@ -69,6 +70,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
|
|||
@ExtendWith(MockitoExtension.class)
|
||||
public class BearerTokenAuthenticationFilterTests {
|
||||
|
||||
private static final String TEST_TOKEN = "token";
|
||||
|
||||
@Mock
|
||||
AuthenticationEntryPoint authenticationEntryPoint;
|
||||
|
||||
|
@ -78,6 +81,9 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
@Mock
|
||||
AuthenticationManager authenticationManager;
|
||||
|
||||
@Mock
|
||||
AuthenticationConverter authenticationConverter;
|
||||
|
||||
@Mock
|
||||
AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver;
|
||||
|
||||
|
@ -102,7 +108,7 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
|
||||
@Test
|
||||
public void doFilterWhenBearerTokenPresentThenAuthenticates() throws ServletException, IOException {
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn("token");
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn(TEST_TOKEN);
|
||||
BearerTokenAuthenticationFilter filter = addMocks(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
@ -117,12 +123,13 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
@Test
|
||||
public void doFilterWhenSecurityContextRepositoryThenSaves() throws ServletException, IOException {
|
||||
SecurityContextRepository securityContextRepository = mock(SecurityContextRepository.class);
|
||||
String token = "token";
|
||||
String token = TEST_TOKEN;
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn(token);
|
||||
TestingAuthenticationToken expectedAuthentication = new TestingAuthenticationToken("test", "password");
|
||||
given(this.authenticationManager.authenticate(any())).willReturn(expectedAuthentication);
|
||||
BearerTokenAuthenticationFilter filter = addMocks(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
|
||||
filter.setSecurityContextRepository(securityContextRepository);
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
ArgumentCaptor<BearerTokenAuthenticationToken> captor = ArgumentCaptor
|
||||
|
@ -138,13 +145,13 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
public void doFilterWhenUsingAuthenticationManagerResolverThenAuthenticates() throws Exception {
|
||||
BearerTokenAuthenticationFilter filter = addMocks(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManagerResolver));
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn("token");
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn(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("token");
|
||||
assertThat(captor.getValue().getPrincipal()).isEqualTo(TEST_TOKEN);
|
||||
assertThat(this.request.getAttribute(RequestAttributeSecurityContextRepository.DEFAULT_REQUEST_ATTR_NAME))
|
||||
.isNotNull();
|
||||
}
|
||||
|
@ -171,7 +178,7 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN, HttpStatus.UNAUTHORIZED,
|
||||
"description", "uri");
|
||||
OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error);
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn("token");
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn(TEST_TOKEN);
|
||||
given(this.authenticationManager.authenticate(any(BearerTokenAuthenticationToken.class))).willThrow(exception);
|
||||
BearerTokenAuthenticationFilter filter = addMocks(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
|
@ -185,7 +192,7 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
BearerTokenError error = new BearerTokenError(BearerTokenErrorCodes.INVALID_TOKEN, HttpStatus.UNAUTHORIZED,
|
||||
"description", "uri");
|
||||
OAuth2AuthenticationException exception = new OAuth2AuthenticationException(error);
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn("token");
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn(TEST_TOKEN);
|
||||
given(this.authenticationManager.authenticate(any(BearerTokenAuthenticationToken.class))).willThrow(exception);
|
||||
BearerTokenAuthenticationFilter filter = addMocks(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
|
@ -197,7 +204,7 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
@Test
|
||||
public void doFilterWhenAuthenticationServiceExceptionThenRethrows() {
|
||||
AuthenticationServiceException exception = new AuthenticationServiceException("message");
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn("token");
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn(TEST_TOKEN);
|
||||
given(this.authenticationManager.authenticate(any())).willThrow(exception);
|
||||
BearerTokenAuthenticationFilter filter = addMocks(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
|
@ -208,7 +215,7 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
@Test
|
||||
public void doFilterWhenCustomEntryPointAndAuthenticationErrorThenUses() throws ServletException, IOException {
|
||||
AuthenticationException exception = new InvalidBearerTokenException("message");
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn("token");
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn(TEST_TOKEN);
|
||||
given(this.authenticationManager.authenticate(any())).willThrow(exception);
|
||||
BearerTokenAuthenticationFilter filter = addMocks(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
|
@ -220,7 +227,7 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
|
||||
@Test
|
||||
public void doFilterWhenCustomAuthenticationDetailsSourceThenUses() throws ServletException, IOException {
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn("token");
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn(TEST_TOKEN);
|
||||
BearerTokenAuthenticationFilter filter = addMocks(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
@ -229,7 +236,7 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
|
||||
@Test
|
||||
public void doFilterWhenCustomSecurityContextHolderStrategyThenUses() throws ServletException, IOException {
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn("token");
|
||||
given(this.bearerTokenResolver.resolve(this.request)).willReturn(TEST_TOKEN);
|
||||
BearerTokenAuthenticationFilter filter = addMocks(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
|
||||
|
@ -260,7 +267,7 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void setAuthenticationConverterWhenNullThenThrowsException() {
|
||||
public void setAuthenticationDetailsSourceWhenNullThenThrowsException() {
|
||||
// @formatter:off
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);
|
||||
assertThatIllegalArgumentException()
|
||||
|
@ -269,6 +276,16 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthenticationConverterWhenNullThenThrowsException() {
|
||||
// @formatter:off
|
||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> filter.setAuthenticationConverter(null))
|
||||
.withMessageContaining("authenticationConverter cannot be null");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenNullAuthenticationManagerThenThrowsException() {
|
||||
// @formatter:off
|
||||
|
@ -287,6 +304,171 @@ 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);
|
||||
|
@ -294,6 +476,12 @@ public class BearerTokenAuthenticationFilterTests {
|
|||
return filter;
|
||||
}
|
||||
|
||||
private BearerTokenAuthenticationFilter addMocksWithConverter(BearerTokenAuthenticationFilter filter) {
|
||||
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
||||
filter.setAuthenticationConverter(this.authenticationConverter);
|
||||
return filter;
|
||||
}
|
||||
|
||||
private void dontAuthenticate() throws ServletException, IOException {
|
||||
BearerTokenAuthenticationFilter filter = addMocks(
|
||||
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||
|
|
Loading…
Reference in New Issue