Add Support BearerTokenAuthenticationConverter
Closes gh-14750 Signed-off-by: Max Batischev <mblancer@mail.ru>
This commit is contained in:
committed by
Josh Cummings
parent
3f0326d3f1
commit
4967f3feee
@@ -127,12 +127,14 @@ import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthen
|
||||
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.BearerTokenAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
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;
|
||||
@@ -759,13 +761,6 @@ public class OAuth2ResourceServerConfigurerTests {
|
||||
assertThat(oauth2.getBearerTokenResolver()).isEqualTo(resolver);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBearerTokenResolverWhenNoResolverSpecifiedThenTheDefaultIsUsed() {
|
||||
ApplicationContext context = this.spring.context(new GenericWebApplicationContext()).getContext();
|
||||
OAuth2ResourceServerConfigurer oauth2 = new OAuth2ResourceServerConfigurer(context);
|
||||
assertThat(oauth2.getBearerTokenResolver()).isInstanceOf(DefaultBearerTokenResolver.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenCustomAuthenticationDetailsSourceThenUsed() throws Exception {
|
||||
this.spring.register(CustomAuthenticationDetailsSource.class, JwtDecoderConfig.class, BasicController.class)
|
||||
@@ -1415,6 +1410,47 @@ public class OAuth2ResourceServerConfigurerTests {
|
||||
verify(authenticationConverter).convert(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
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.getAuthenticationConverter()).isInstanceOf(BearerTokenAuthenticationConverter.class);
|
||||
}
|
||||
|
||||
private static <T> void registerMockBean(GenericApplicationContext context, String name, Class<T> clazz) {
|
||||
context.registerBean(name, clazz, () -> mock(clazz));
|
||||
}
|
||||
@@ -2516,6 +2552,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 MultipleIssuersConfig {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2025 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.
|
||||
@@ -25,7 +25,6 @@ import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -50,13 +49,11 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mockito;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||
@@ -85,12 +82,14 @@ import org.springframework.security.oauth2.jwt.JwtClaimNames;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.TestJwts;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
||||
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
@@ -462,6 +461,24 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
|
||||
verify(bearerTokenResolver).resolve(any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenCustomAuthenticationConverterThenUses() throws Exception {
|
||||
this.spring
|
||||
.configLocations(xml("MockAuthenticationConverter"), xml("MockJwtDecoder"), xml("AuthenticationConverter"))
|
||||
.autowire();
|
||||
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
|
||||
given(decoder.decode("token")).willReturn(TestJwts.jwt().build());
|
||||
AuthenticationConverter authenticationConverter = this.spring.getContext()
|
||||
.getBean(AuthenticationConverter.class);
|
||||
given(authenticationConverter.convert(any(HttpServletRequest.class)))
|
||||
.willReturn(new BearerTokenAuthenticationToken("token"));
|
||||
|
||||
this.mvc.perform(get("/")).andExpect(status().isNotFound());
|
||||
|
||||
verify(decoder).decode("token");
|
||||
verify(authenticationConverter).convert(any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenBearerTokenResolverAllowsRequestBodyThenEitherHeaderOrRequestBodyIsAccepted()
|
||||
throws Exception {
|
||||
@@ -521,14 +538,6 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBearerTokenResolverWhenNoResolverSpecifiedThenTheDefaultIsUsed() {
|
||||
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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenCustomJwtDecoderThenUsed() throws Exception {
|
||||
this.spring.configLocations(xml("MockJwtDecoder"), xml("Jwt")).autowire();
|
||||
@@ -545,6 +554,12 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
|
||||
.isThrownBy(() -> this.spring.configLocations(xml("JwtDecoderAndJwkSetUri")).autowire());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWhenAuthenticationConverterAndJwkSetUriThenException() {
|
||||
assertThatExceptionOfType(BeanDefinitionStoreException.class).isThrownBy(
|
||||
() -> this.spring.configLocations(xml("AuthenticationConverterAndBearerTokenResolver")).autowire());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenRealmNameConfiguredThenUsesOnUnauthenticated() throws Exception {
|
||||
this.spring.configLocations(xml("MockJwtDecoder"), xml("AuthenticationEntryPoint")).autowire();
|
||||
|
||||
Reference in New Issue
Block a user