mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-31 17:22:13 +00:00
Refactor AuthenticationDetailsSource support
- BearerTokenAuthenticationFilter exposes this directly, simplifying configuration and removing a package tangle Closes gh-9576
This commit is contained in:
parent
21f9876d87
commit
7ded671858
@ -39,7 +39,6 @@ import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
|||||||
import org.springframework.security.oauth2.jwt.Jwt;
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
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.JwtAuthenticationConverter;
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
|
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.authentication.OpaqueTokenAuthenticationProvider;
|
||||||
@ -52,7 +51,6 @@ import org.springframework.security.oauth2.server.resource.web.DefaultBearerToke
|
|||||||
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
|
||||||
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
import org.springframework.security.web.util.matcher.AndRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
|
||||||
@ -80,8 +78,6 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
|
|||||||
* authentication failures are handled
|
* authentication failures are handled
|
||||||
* <li>{@link #bearerTokenResolver(BearerTokenResolver)} - customizes how to resolve a
|
* <li>{@link #bearerTokenResolver(BearerTokenResolver)} - customizes how to resolve a
|
||||||
* bearer token from the request</li>
|
* bearer token from the request</li>
|
||||||
* <li>{@link #authenticationConverter(AuthenticationConverter)}</li> - customizes how to
|
|
||||||
* convert a bearer token authentication from the request
|
|
||||||
* <li>{@link #jwt(Customizer)} - enables Jwt-encoded bearer token support</li>
|
* <li>{@link #jwt(Customizer)} - enables Jwt-encoded bearer token support</li>
|
||||||
* <li>{@link #opaqueToken(Customizer)} - enables opaque bearer token support</li>
|
* <li>{@link #opaqueToken(Customizer)} - enables opaque bearer token support</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
@ -163,8 +159,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|||||||
|
|
||||||
private BearerTokenRequestMatcher requestMatcher = new BearerTokenRequestMatcher();
|
private BearerTokenRequestMatcher requestMatcher = new BearerTokenRequestMatcher();
|
||||||
|
|
||||||
private AuthenticationConverter authenticationConverter;
|
|
||||||
|
|
||||||
public OAuth2ResourceServerConfigurer(ApplicationContext context) {
|
public OAuth2ResourceServerConfigurer(ApplicationContext context) {
|
||||||
Assert.notNull(context, "context cannot be null");
|
Assert.notNull(context, "context cannot be null");
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@ -195,12 +189,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OAuth2ResourceServerConfigurer<H> authenticationConverter(AuthenticationConverter authenticationConverter) {
|
|
||||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
|
||||||
this.authenticationConverter = authenticationConverter;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JwtConfigurer jwt() {
|
public JwtConfigurer jwt() {
|
||||||
if (this.jwtConfigurer == null) {
|
if (this.jwtConfigurer == null) {
|
||||||
this.jwtConfigurer = new JwtConfigurer(this.context);
|
this.jwtConfigurer = new JwtConfigurer(this.context);
|
||||||
@ -265,10 +253,8 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|||||||
resolver = (request) -> authenticationManager;
|
resolver = (request) -> authenticationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.authenticationConverter = getAuthenticationConverter();
|
|
||||||
|
|
||||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver);
|
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(resolver);
|
||||||
filter.setAuthenticationConverter(this.authenticationConverter);
|
filter.setBearerTokenResolver(bearerTokenResolver);
|
||||||
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
||||||
filter = postProcess(filter);
|
filter = postProcess(filter);
|
||||||
http.addFilter(filter);
|
http.addFilter(filter);
|
||||||
@ -362,20 +348,6 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<
|
|||||||
return this.bearerTokenResolver;
|
return this.bearerTokenResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthenticationConverter getAuthenticationConverter() {
|
|
||||||
if (this.authenticationConverter == null) {
|
|
||||||
if (this.context.getBeanNamesForType(BearerTokenAuthenticationConverter.class).length > 0) {
|
|
||||||
this.authenticationConverter = this.context.getBean(BearerTokenAuthenticationConverter.class);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter();
|
|
||||||
converter.setBearerTokenResolver(getBearerTokenResolver());
|
|
||||||
this.authenticationConverter = converter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.authenticationConverter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class JwtConfigurer {
|
public class JwtConfigurer {
|
||||||
|
|
||||||
private final ApplicationContext context;
|
private final ApplicationContext context;
|
||||||
|
@ -75,11 +75,13 @@ import org.springframework.http.ResponseEntity;
|
|||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
|
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||||
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
import org.springframework.security.authentication.AuthenticationEventPublisher;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
@ -109,20 +111,20 @@ import org.springframework.security.oauth2.jwt.JwtDecoder;
|
|||||||
import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
|
import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
|
||||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||||
import org.springframework.security.oauth2.jwt.TestJwts;
|
import org.springframework.security.oauth2.jwt.TestJwts;
|
||||||
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication;
|
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.JwtAuthenticationConverter;
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.JwtIssuerAuthenticationManagerResolver;
|
import org.springframework.security.oauth2.server.resource.authentication.JwtIssuerAuthenticationManagerResolver;
|
||||||
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
|
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
|
||||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
||||||
|
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter;
|
||||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
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.DefaultBearerTokenResolver;
|
||||||
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
|
||||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
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.AccessDeniedHandler;
|
||||||
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
@ -724,68 +726,14 @@ public class OAuth2ResourceServerConfigurerTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBearerTokenAuthenticationConverterWhenDuplicateConverterBeansAndAnotherOnTheDslThenTheDslOneIsUsed() {
|
public void requestWhenCustomAuthenticationDetailsSourceThenUsed() throws Exception {
|
||||||
BearerTokenAuthenticationConverter converterBean = new BearerTokenAuthenticationConverter();
|
this.spring.register(CustomAuthenticationDetailsSource.class, JwtDecoderConfig.class, BasicController.class)
|
||||||
BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter();
|
.autowire();
|
||||||
GenericWebApplicationContext context = new GenericWebApplicationContext();
|
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
|
||||||
context.registerBean("converterOne", BearerTokenAuthenticationConverter.class, () -> converterBean);
|
given(decoder.decode(anyString())).willReturn(JWT);
|
||||||
context.registerBean("converterTwo", BearerTokenAuthenticationConverter.class, () -> converterBean);
|
this.mvc.perform(get("/authenticated").with(bearerToken(JWT_TOKEN))).andExpect(status().isOk())
|
||||||
this.spring.context(context).autowire();
|
.andExpect(content().string(JWT_SUBJECT));
|
||||||
OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context);
|
verifyBean(AuthenticationDetailsSource.class).buildDetails(any());
|
||||||
oauth2.authenticationConverter(converter);
|
|
||||||
assertThat(oauth2.getAuthenticationConverter()).isEqualTo(converter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getBearerTokenAuthenticationConverterWhenDuplicateConverterBeansThenWiringException() {
|
|
||||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> this.spring
|
|
||||||
.register(MultipleBearerTokenAuthenticationConverterBeansConfig.class, JwtDecoderConfig.class)
|
|
||||||
.autowire()).withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getBearerTokenAuthenticationConverterWhenConverterBeanAndAnotherOnTheDslThenTheDslOneIsUsed() {
|
|
||||||
BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter();
|
|
||||||
BearerTokenAuthenticationConverter converterBean = new BearerTokenAuthenticationConverter();
|
|
||||||
GenericWebApplicationContext context = new GenericWebApplicationContext();
|
|
||||||
context.registerBean(BearerTokenAuthenticationConverter.class, () -> converterBean);
|
|
||||||
this.spring.context(context).autowire();
|
|
||||||
OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context);
|
|
||||||
oauth2.authenticationConverter(converter);
|
|
||||||
assertThat(oauth2.getAuthenticationConverter()).isEqualTo(converter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getBearerTokenAuthenticationConverterWhenNoConverterSpecifiedThenTheDefaultIsUsed() {
|
|
||||||
ApplicationContext context = this.spring.context(new GenericWebApplicationContext()).getContext();
|
|
||||||
OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context);
|
|
||||||
assertThat(oauth2.getAuthenticationConverter()).isInstanceOf(BearerTokenAuthenticationConverter.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getBearerTokenAuthenticationConverterWhenConverterBeanRegisteredThenBeanIsUsed() {
|
|
||||||
BearerTokenAuthenticationConverter converterBean = new BearerTokenAuthenticationConverter();
|
|
||||||
GenericWebApplicationContext context = new GenericWebApplicationContext();
|
|
||||||
context.registerBean(BearerTokenAuthenticationConverter.class, () -> converterBean);
|
|
||||||
this.spring.context(context).autowire();
|
|
||||||
OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context);
|
|
||||||
assertThat(oauth2.getAuthenticationConverter()).isEqualTo(converterBean);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getBearerTokenAuthenticationConverterWhenOnlyResolverBeanRegisteredThenUseTheResolver() {
|
|
||||||
HttpServletRequest servletRequest = mock(HttpServletRequest.class);
|
|
||||||
BearerTokenResolver resolverBean = (request) -> "bearer customToken";
|
|
||||||
GenericWebApplicationContext context = new GenericWebApplicationContext();
|
|
||||||
context.registerBean(BearerTokenResolver.class, () -> resolverBean);
|
|
||||||
this.spring.context(context).autowire();
|
|
||||||
OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context);
|
|
||||||
BearerTokenAuthenticationToken bearerTokenAuthenticationToken = (BearerTokenAuthenticationToken) oauth2
|
|
||||||
.getAuthenticationConverter().convert(servletRequest);
|
|
||||||
String token = bearerTokenAuthenticationToken.getToken();
|
|
||||||
assertThat(token).isEqualTo("bearer customToken");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -1940,29 +1888,35 @@ public class OAuth2ResourceServerConfigurerTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
static class MultipleBearerTokenAuthenticationConverterBeansConfig extends WebSecurityConfigurerAdapter {
|
static class CustomAuthenticationDetailsSource {
|
||||||
|
|
||||||
@Override
|
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = mock(
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
AuthenticationDetailsSource.class);
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SecurityFilterChain web(HttpSecurity http) throws Exception {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
http
|
http
|
||||||
.oauth2ResourceServer()
|
.authorizeRequests((authorize) -> authorize
|
||||||
.jwt();
|
.anyRequest().authenticated()
|
||||||
// @formatter:on
|
)
|
||||||
|
.oauth2ResourceServer((oauth2) -> oauth2
|
||||||
|
.jwt(withDefaults())
|
||||||
|
.withObjectPostProcessor(new ObjectPostProcessor<BearerTokenAuthenticationFilter>() {
|
||||||
|
@Override
|
||||||
|
public BearerTokenAuthenticationFilter postProcess(BearerTokenAuthenticationFilter object) {
|
||||||
|
object.setAuthenticationDetailsSource(CustomAuthenticationDetailsSource.this.authenticationDetailsSource);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
BearerTokenAuthenticationConverter converterOne() {
|
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource() {
|
||||||
BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter();
|
return this.authenticationDetailsSource;
|
||||||
return converter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
BearerTokenAuthenticationConverter converterTwo() {
|
|
||||||
BearerTokenAuthenticationConverter converter = new BearerTokenAuthenticationConverter();
|
|
||||||
return converter;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002-2021 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 javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
|
||||||
import org.springframework.security.oauth2.server.resource.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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts from a HttpServletRequest to {@link BearerTokenAuthenticationToken} that can
|
|
||||||
* be authenticated. Null authentication possible if there was no Authorization header
|
|
||||||
* with Bearer Token.
|
|
||||||
*
|
|
||||||
* @author Jeongjin Kim
|
|
||||||
* @since 5.5
|
|
||||||
*/
|
|
||||||
public final class BearerTokenAuthenticationConverter implements AuthenticationConverter {
|
|
||||||
|
|
||||||
private BearerTokenResolver bearerTokenResolver = new DefaultBearerTokenResolver();
|
|
||||||
|
|
||||||
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BearerTokenAuthenticationToken convert(HttpServletRequest request) {
|
|
||||||
String token = this.bearerTokenResolver.resolve(request);
|
|
||||||
|
|
||||||
if (token == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
BearerTokenAuthenticationToken authenticationRequest = new BearerTokenAuthenticationToken(token);
|
|
||||||
authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
|
||||||
return authenticationRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the {@link BearerTokenResolver} to use. Defaults to
|
|
||||||
* {@link DefaultBearerTokenResolver}.
|
|
||||||
* @param bearerTokenResolver the {@code BearerTokenResolver} to use
|
|
||||||
*/
|
|
||||||
public void setBearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
|
|
||||||
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
|
|
||||||
this.bearerTokenResolver = bearerTokenResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.springframework.core.log.LogMessage;
|
import org.springframework.core.log.LogMessage;
|
||||||
|
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
@ -31,12 +32,12 @@ import org.springframework.security.core.Authentication;
|
|||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationConverter;
|
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider;
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
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.authentication.AuthenticationFailureHandler;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
@ -51,6 +52,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
|
|||||||
* @author Josh Cummings
|
* @author Josh Cummings
|
||||||
* @author Vedran Pavic
|
* @author Vedran Pavic
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
|
* @author Jeongjin Kim
|
||||||
* @since 5.1
|
* @since 5.1
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc6750" target="_blank">The OAuth 2.0
|
* @see <a href="https://tools.ietf.org/html/rfc6750" target="_blank">The OAuth 2.0
|
||||||
* Authorization Framework: Bearer Token Usage</a>
|
* Authorization Framework: Bearer Token Usage</a>
|
||||||
@ -69,7 +71,9 @@ public final class BearerTokenAuthenticationFilter extends OncePerRequestFilter
|
|||||||
this.authenticationEntryPoint.commence(request, response, exception);
|
this.authenticationEntryPoint.commence(request, response, exception);
|
||||||
};
|
};
|
||||||
|
|
||||||
private AuthenticationConverter authenticationConverter = new BearerTokenAuthenticationConverter();
|
private BearerTokenResolver bearerTokenResolver = new DefaultBearerTokenResolver();
|
||||||
|
|
||||||
|
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a {@code BearerTokenAuthenticationFilter} using the provided parameter(s)
|
* Construct a {@code BearerTokenAuthenticationFilter} using the provided parameter(s)
|
||||||
@ -103,21 +107,24 @@ public final class BearerTokenAuthenticationFilter extends OncePerRequestFilter
|
|||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
Authentication authenticationRequest;
|
String token;
|
||||||
try {
|
try {
|
||||||
authenticationRequest = this.authenticationConverter.convert(request);
|
token = this.bearerTokenResolver.resolve(request);
|
||||||
}
|
}
|
||||||
catch (AuthenticationException invalid) {
|
catch (OAuth2AuthenticationException invalid) {
|
||||||
this.logger.trace("Sending to authentication entry point since failed to resolve bearer token", invalid);
|
this.logger.trace("Sending to authentication entry point since failed to resolve bearer token", invalid);
|
||||||
this.authenticationEntryPoint.commence(request, response, invalid);
|
this.authenticationEntryPoint.commence(request, response, invalid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (authenticationRequest == null) {
|
if (token == null) {
|
||||||
this.logger.trace("Did not process request since did not find bearer token");
|
this.logger.trace("Did not process request since did not find bearer token");
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BearerTokenAuthenticationToken authenticationRequest = new BearerTokenAuthenticationToken(token);
|
||||||
|
authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
AuthenticationManager authenticationManager = this.authenticationManagerResolver.resolve(request);
|
AuthenticationManager authenticationManager = this.authenticationManagerResolver.resolve(request);
|
||||||
Authentication authenticationResult = authenticationManager.authenticate(authenticationRequest);
|
Authentication authenticationResult = authenticationManager.authenticate(authenticationRequest);
|
||||||
@ -140,28 +147,10 @@ public final class BearerTokenAuthenticationFilter extends OncePerRequestFilter
|
|||||||
* Set the {@link BearerTokenResolver} to use. Defaults to
|
* Set the {@link BearerTokenResolver} to use. Defaults to
|
||||||
* {@link DefaultBearerTokenResolver}.
|
* {@link DefaultBearerTokenResolver}.
|
||||||
* @param bearerTokenResolver the {@code BearerTokenResolver} to use
|
* @param bearerTokenResolver the {@code BearerTokenResolver} to use
|
||||||
* @deprecated Instead, use {@link BearerTokenAuthenticationConverter} explicitly
|
|
||||||
* @see BearerTokenAuthenticationConverter
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public void setBearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
|
public void setBearerTokenResolver(BearerTokenResolver bearerTokenResolver) {
|
||||||
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
|
Assert.notNull(bearerTokenResolver, "bearerTokenResolver cannot be null");
|
||||||
Assert.isTrue(this.authenticationConverter instanceof BearerTokenAuthenticationConverter,
|
this.bearerTokenResolver = bearerTokenResolver;
|
||||||
"bearerTokenResolver and authenticationConverter cannot both be customized in this filter. "
|
|
||||||
+ "Since you've customized the authenticationConverter, "
|
|
||||||
+ "please consider configuring the bearerTokenResolver there.");
|
|
||||||
((BearerTokenAuthenticationConverter) this.authenticationConverter).setBearerTokenResolver(bearerTokenResolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the {@link AuthenticationConverter} to use. Defaults to
|
|
||||||
* {@link BearerTokenAuthenticationConverter}.
|
|
||||||
* @param authenticationConverter the {@code AuthenticationConverter} to use
|
|
||||||
* @since 5.5
|
|
||||||
*/
|
|
||||||
public void setAuthenticationConverter(AuthenticationConverter authenticationConverter) {
|
|
||||||
Assert.notNull(authenticationConverter, "authenticationConverter cannot be null");
|
|
||||||
this.authenticationConverter = authenticationConverter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -185,4 +174,16 @@ public final class BearerTokenAuthenticationFilter extends OncePerRequestFilter
|
|||||||
this.authenticationFailureHandler = authenticationFailureHandler;
|
this.authenticationFailureHandler = authenticationFailureHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link AuthenticationDetailsSource} to use. Defaults to
|
||||||
|
* {@link WebAuthenticationDetailsSource}.
|
||||||
|
* @param authenticationDetailsSource the {@code AuthenticationConverter} to use
|
||||||
|
* @since 5.5
|
||||||
|
*/
|
||||||
|
public void setAuthenticationDetailsSource(
|
||||||
|
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
|
||||||
|
Assert.notNull(authenticationDetailsSource, "authenticationDetailsSource cannot be null");
|
||||||
|
this.authenticationDetailsSource = authenticationDetailsSource;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002-2021 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 javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
|
||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
|
||||||
import static org.mockito.BDDMockito.given;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link BearerTokenAuthenticationConverter}
|
|
||||||
*
|
|
||||||
* @author Jeongjin Kim
|
|
||||||
* @since 5.5
|
|
||||||
*/
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
|
||||||
public class BearerTokenAuthenticationConverterTests {
|
|
||||||
|
|
||||||
private BearerTokenAuthenticationConverter converter;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup() {
|
|
||||||
this.converter = new BearerTokenAuthenticationConverter();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void setBearerTokenResolverWithNullThenThrowsException() {
|
|
||||||
// @formatter:off
|
|
||||||
assertThatIllegalArgumentException()
|
|
||||||
.isThrownBy(() -> this.converter.setBearerTokenResolver(null))
|
|
||||||
.withMessageContaining("bearerTokenResolver cannot be null");
|
|
||||||
// @formatter:on
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void setAuthenticationDetailsSourceWithNullThenThrowsException() {
|
|
||||||
// @formatter:off
|
|
||||||
assertThatIllegalArgumentException()
|
|
||||||
.isThrownBy(() -> this.converter.setAuthenticationDetailsSource(null))
|
|
||||||
.withMessageContaining("authenticationDetailsSource cannot be null");
|
|
||||||
// @formatter:on
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void convertWhenNoBearerTokenHeaderThenNull() {
|
|
||||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
|
||||||
|
|
||||||
BearerTokenAuthenticationToken convert = this.converter.convert(request);
|
|
||||||
|
|
||||||
assertThat(convert).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void convertWhenBearerTokenThenBearerTokenAuthenticationToken() {
|
|
||||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
|
||||||
given(request.getHeader(HttpHeaders.AUTHORIZATION)).willReturn("Bearer token");
|
|
||||||
|
|
||||||
BearerTokenAuthenticationToken token = this.converter.convert(request);
|
|
||||||
|
|
||||||
assertThat(token.getToken()).isEqualTo("token");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -32,6 +32,7 @@ import org.springframework.http.HttpStatus;
|
|||||||
import org.springframework.mock.web.MockFilterChain;
|
import org.springframework.mock.web.MockFilterChain;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
import org.springframework.security.authentication.AuthenticationManagerResolver;
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
@ -73,6 +74,9 @@ public class BearerTokenAuthenticationFilterTests {
|
|||||||
@Mock
|
@Mock
|
||||||
BearerTokenResolver bearerTokenResolver;
|
BearerTokenResolver bearerTokenResolver;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;
|
||||||
|
|
||||||
MockHttpServletRequest request;
|
MockHttpServletRequest request;
|
||||||
|
|
||||||
MockHttpServletResponse response;
|
MockHttpServletResponse response;
|
||||||
@ -167,6 +171,15 @@ public class BearerTokenAuthenticationFilterTests {
|
|||||||
.isThrownBy(() -> filter.doFilter(this.request, this.response, this.filterChain));
|
.isThrownBy(() -> filter.doFilter(this.request, this.response, this.filterChain));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void doFilterWhenCustomAuthenticationDetailsSourceThenUses() throws ServletException, IOException {
|
||||||
|
given(this.bearerTokenResolver.resolve(this.request)).willReturn("token");
|
||||||
|
BearerTokenAuthenticationFilter filter = addMocks(
|
||||||
|
new BearerTokenAuthenticationFilter(this.authenticationManager));
|
||||||
|
filter.doFilter(this.request, this.response, this.filterChain);
|
||||||
|
verify(this.authenticationDetailsSource).buildDetails(this.request);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setAuthenticationEntryPointWhenNullThenThrowsException() {
|
public void setAuthenticationEntryPointWhenNullThenThrowsException() {
|
||||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);
|
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);
|
||||||
@ -192,8 +205,8 @@ public class BearerTokenAuthenticationFilterTests {
|
|||||||
// @formatter:off
|
// @formatter:off
|
||||||
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);
|
BearerTokenAuthenticationFilter filter = new BearerTokenAuthenticationFilter(this.authenticationManager);
|
||||||
assertThatIllegalArgumentException()
|
assertThatIllegalArgumentException()
|
||||||
.isThrownBy(() -> filter.setAuthenticationConverter(null))
|
.isThrownBy(() -> filter.setAuthenticationDetailsSource(null))
|
||||||
.withMessageContaining("authenticationConverter cannot be null");
|
.withMessageContaining("authenticationDetailsSource cannot be null");
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,6 +231,7 @@ public class BearerTokenAuthenticationFilterTests {
|
|||||||
private BearerTokenAuthenticationFilter addMocks(BearerTokenAuthenticationFilter filter) {
|
private BearerTokenAuthenticationFilter addMocks(BearerTokenAuthenticationFilter filter) {
|
||||||
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
filter.setAuthenticationEntryPoint(this.authenticationEntryPoint);
|
||||||
filter.setBearerTokenResolver(this.bearerTokenResolver);
|
filter.setBearerTokenResolver(this.bearerTokenResolver);
|
||||||
|
filter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user