Replace bean method calls with injection
This is so that our configuration classes do not rely on CGLIB to proxy bean methods. Fixes gh-6818
This commit is contained in:
parent
97a01260f1
commit
06d3b60947
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2018 the original author or authors.
|
* Copyright 2002-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -107,8 +107,7 @@ public class AuthenticationConfiguration {
|
||||||
if (this.authenticationManagerInitialized) {
|
if (this.authenticationManagerInitialized) {
|
||||||
return this.authenticationManager;
|
return this.authenticationManager;
|
||||||
}
|
}
|
||||||
AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder(
|
AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
|
||||||
this.objectPostProcessor, this.applicationContext);
|
|
||||||
if (this.buildingAuthenticationManager.getAndSet(true)) {
|
if (this.buildingAuthenticationManager.getAndSet(true)) {
|
||||||
return new AuthenticationManagerDelegator(authBuilder);
|
return new AuthenticationManagerDelegator(authBuilder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2018 the original author or authors.
|
* Copyright 2002-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -29,10 +29,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.AdviceMode;
|
import org.springframework.context.annotation.*;
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.ImportAware;
|
|
||||||
import org.springframework.core.annotation.AnnotationAttributes;
|
import org.springframework.core.annotation.AnnotationAttributes;
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.core.type.AnnotationMetadata;
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
|
@ -110,7 +107,6 @@ public class GlobalMethodSecurityConfiguration
|
||||||
* <li>{@link #accessDecisionManager()}</li>
|
* <li>{@link #accessDecisionManager()}</li>
|
||||||
* <li>{@link #afterInvocationManager()}</li>
|
* <li>{@link #afterInvocationManager()}</li>
|
||||||
* <li>{@link #authenticationManager()}</li>
|
* <li>{@link #authenticationManager()}</li>
|
||||||
* <li>{@link #methodSecurityMetadataSource()}</li>
|
|
||||||
* <li>{@link #runAsManager()}</li>
|
* <li>{@link #runAsManager()}</li>
|
||||||
*
|
*
|
||||||
* </ul>
|
* </ul>
|
||||||
|
@ -119,19 +115,19 @@ public class GlobalMethodSecurityConfiguration
|
||||||
* Subclasses can override this method to provide a different
|
* Subclasses can override this method to provide a different
|
||||||
* {@link MethodInterceptor}.
|
* {@link MethodInterceptor}.
|
||||||
* </p>
|
* </p>
|
||||||
|
* @param methodSecurityMetadataSource the default {@link MethodSecurityMetadataSource}.
|
||||||
*
|
*
|
||||||
* @return the {@link MethodInterceptor}.
|
* @return the {@link MethodInterceptor}.
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public MethodInterceptor methodSecurityInterceptor() throws Exception {
|
public MethodInterceptor methodSecurityInterceptor(MethodSecurityMetadataSource methodSecurityMetadataSource) {
|
||||||
this.methodSecurityInterceptor = isAspectJ()
|
this.methodSecurityInterceptor = isAspectJ()
|
||||||
? new AspectJMethodSecurityInterceptor()
|
? new AspectJMethodSecurityInterceptor()
|
||||||
: new MethodSecurityInterceptor();
|
: new MethodSecurityInterceptor();
|
||||||
methodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager());
|
methodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager());
|
||||||
methodSecurityInterceptor.setAfterInvocationManager(afterInvocationManager());
|
methodSecurityInterceptor.setAfterInvocationManager(afterInvocationManager());
|
||||||
methodSecurityInterceptor
|
methodSecurityInterceptor
|
||||||
.setSecurityMetadataSource(methodSecurityMetadataSource());
|
.setSecurityMetadataSource(methodSecurityMetadataSource);
|
||||||
RunAsManager runAsManager = runAsManager();
|
RunAsManager runAsManager = runAsManager();
|
||||||
if (runAsManager != null) {
|
if (runAsManager != null) {
|
||||||
methodSecurityInterceptor.setRunAsManager(runAsManager);
|
methodSecurityInterceptor.setRunAsManager(runAsManager);
|
||||||
|
@ -197,8 +193,8 @@ public class GlobalMethodSecurityConfiguration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a custom {@link AfterInvocationManager} for the default implementation of
|
* Provide a custom {@link AfterInvocationManager} for the default implementation of
|
||||||
* {@link #methodSecurityInterceptor()}. The default is null if pre post is not
|
* {@link #methodSecurityInterceptor(MethodSecurityMetadataSource)}. The default is null
|
||||||
* enabled. Otherwise, it returns a {@link AfterInvocationProviderManager}.
|
* if pre post is not enabled. Otherwise, it returns a {@link AfterInvocationProviderManager}.
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* Subclasses should override this method to provide a custom
|
* Subclasses should override this method to provide a custom
|
||||||
|
@ -224,7 +220,7 @@ public class GlobalMethodSecurityConfiguration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a custom {@link RunAsManager} for the default implementation of
|
* Provide a custom {@link RunAsManager} for the default implementation of
|
||||||
* {@link #methodSecurityInterceptor()}. The default is null.
|
* {@link #methodSecurityInterceptor(MethodSecurityMetadataSource)}. The default is null.
|
||||||
*
|
*
|
||||||
* @return the {@link RunAsManager} to use
|
* @return the {@link RunAsManager} to use
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -43,7 +43,7 @@ import org.springframework.web.reactive.result.method.annotation.ArgumentResolve
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
class ServerHttpSecurityConfiguration implements WebFluxConfigurer {
|
class ServerHttpSecurityConfiguration {
|
||||||
private static final String BEAN_NAME_PREFIX = "org.springframework.security.config.annotation.web.reactive.HttpSecurityConfiguration.";
|
private static final String BEAN_NAME_PREFIX = "org.springframework.security.config.annotation.web.reactive.HttpSecurityConfiguration.";
|
||||||
private static final String HTTPSECURITY_BEAN_NAME = BEAN_NAME_PREFIX + "httpSecurity";
|
private static final String HTTPSECURITY_BEAN_NAME = BEAN_NAME_PREFIX + "httpSecurity";
|
||||||
|
|
||||||
|
@ -85,9 +85,15 @@ class ServerHttpSecurityConfiguration implements WebFluxConfigurer {
|
||||||
this.userDetailsPasswordService = userDetailsPasswordService;
|
this.userDetailsPasswordService = userDetailsPasswordService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebFluxConfigurer authenticationPrincipalArgumentResolverConfigurer(
|
||||||
|
AuthenticationPrincipalArgumentResolver authenticationPrincipalArgumentResolver) {
|
||||||
|
return new WebFluxConfigurer() {
|
||||||
@Override
|
@Override
|
||||||
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
|
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
|
||||||
configurer.addCustomResolver(authenticationPrincipalArgumentResolver());
|
configurer.addCustomResolver(authenticationPrincipalArgumentResolver);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -110,7 +116,6 @@ class ServerHttpSecurityConfiguration implements WebFluxConfigurer {
|
||||||
return resolver;
|
return resolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Bean(HTTPSECURITY_BEAN_NAME)
|
@Bean(HTTPSECURITY_BEAN_NAME)
|
||||||
@Scope("prototype")
|
@Scope("prototype")
|
||||||
public ServerHttpSecurity httpSecurity() {
|
public ServerHttpSecurity httpSecurity() {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2018 the original author or authors.
|
* Copyright 2002-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -103,10 +103,10 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void configureClientInboundChannel(ChannelRegistration registration) {
|
public final void configureClientInboundChannel(ChannelRegistration registration) {
|
||||||
ChannelSecurityInterceptor inboundChannelSecurity = inboundChannelSecurity();
|
ChannelSecurityInterceptor inboundChannelSecurity = context.getBean(ChannelSecurityInterceptor.class);
|
||||||
registration.setInterceptors(securityContextChannelInterceptor());
|
registration.setInterceptors(context.getBean(SecurityContextChannelInterceptor.class));
|
||||||
if (!sameOriginDisabled()) {
|
if (!sameOriginDisabled()) {
|
||||||
registration.setInterceptors(csrfChannelInterceptor());
|
registration.setInterceptors(context.getBean(CsrfChannelInterceptor.class));
|
||||||
}
|
}
|
||||||
if (inboundRegistry.containsMapping()) {
|
if (inboundRegistry.containsMapping()) {
|
||||||
registration.setInterceptors(inboundChannelSecurity);
|
registration.setInterceptors(inboundChannelSecurity);
|
||||||
|
@ -153,9 +153,9 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ChannelSecurityInterceptor inboundChannelSecurity() {
|
public ChannelSecurityInterceptor inboundChannelSecurity(MessageSecurityMetadataSource messageSecurityMetadataSource) {
|
||||||
ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(
|
ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(
|
||||||
inboundMessageSecurityMetadataSource());
|
messageSecurityMetadataSource);
|
||||||
MessageExpressionVoter<Object> voter = new MessageExpressionVoter<>();
|
MessageExpressionVoter<Object> voter = new MessageExpressionVoter<>();
|
||||||
voter.setExpressionHandler(getMessageExpressionHandler());
|
voter.setExpressionHandler(getMessageExpressionHandler());
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2018 the original author or authors.
|
* Copyright 2002-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -34,6 +34,7 @@ import org.springframework.security.authentication.TestAuthentication;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
|
import org.springframework.security.config.annotation.AlreadyBuiltException;
|
||||||
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
import org.springframework.security.config.annotation.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||||
|
@ -64,9 +65,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.ArgumentMatchers.startsWith;
|
import static org.mockito.ArgumentMatchers.startsWith;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
public class AuthenticationConfigurationTests {
|
public class AuthenticationConfigurationTests {
|
||||||
|
|
||||||
|
@ -530,4 +529,20 @@ public class AuthenticationConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAuthenticationManagerWhenAuthenticationConfigurationSubclassedThenBuildsUsingBean()
|
||||||
|
throws Exception {
|
||||||
|
this.spring.register(AuthenticationConfigurationSubclass.class).autowire();
|
||||||
|
AuthenticationManagerBuilder ap = this.spring.getContext().getBean(AuthenticationManagerBuilder.class);
|
||||||
|
|
||||||
|
this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
|
||||||
|
|
||||||
|
assertThatThrownBy(ap::build)
|
||||||
|
.isInstanceOf(AlreadyBuiltException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class AuthenticationConfigurationSubclass extends AuthenticationConfiguration {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2018 the original author or authors.
|
* Copyright 2002-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -20,6 +20,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
|
@ -553,4 +554,20 @@ public class GlobalMethodSecurityConfigurationTests {
|
||||||
public void emptyPrefixRoleUser() {}
|
public void emptyPrefixRoleUser() {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void methodSecurityInterceptorUsesMetadataSourceBeanWhenProxyingDisabled() {
|
||||||
|
this.spring.register(CustomMetadataSourceProxylessConfig.class).autowire();
|
||||||
|
MethodSecurityInterceptor methodInterceptor =
|
||||||
|
(MethodSecurityInterceptor) this.spring.getContext().getBean(MethodInterceptor.class);
|
||||||
|
MethodSecurityMetadataSource methodSecurityMetadataSource =
|
||||||
|
this.spring.getContext().getBean(MethodSecurityMetadataSource.class);
|
||||||
|
|
||||||
|
assertThat(methodInterceptor.getSecurityMetadataSource()).isSameAs(methodSecurityMetadataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
public static class CustomMetadataSourceProxylessConfig extends GlobalMethodSecurityConfiguration {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2018 the original author or authors.
|
* Copyright 2002-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -163,8 +163,8 @@ public class NamespaceGlobalMethodSecurityTests {
|
||||||
public static class CustomAuthenticationConfig extends GlobalMethodSecurityConfiguration {
|
public static class CustomAuthenticationConfig extends GlobalMethodSecurityConfiguration {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodInterceptor methodSecurityInterceptor() throws Exception {
|
public MethodInterceptor methodSecurityInterceptor(MethodSecurityMetadataSource methodSecurityMetadataSource) {
|
||||||
MethodInterceptor interceptor = super.methodSecurityInterceptor();
|
MethodInterceptor interceptor = super.methodSecurityInterceptor(methodSecurityMetadataSource);
|
||||||
((MethodSecurityInterceptor) interceptor).setAlwaysReauthenticate(true);
|
((MethodSecurityInterceptor) interceptor).setAlwaysReauthenticate(true);
|
||||||
return interceptor;
|
return interceptor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,4 +88,24 @@ public class ReactiveMethodSecurityConfigurationTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rolePrefixWithGrantedAuthorityDefaultsAndSubclassWithProxyingDisabled() {
|
||||||
|
this.spring.register(SubclassConfig.class).autowire();
|
||||||
|
|
||||||
|
TestingAuthenticationToken authentication = new TestingAuthenticationToken(
|
||||||
|
"principal", "credential", "ROLE_ABC");
|
||||||
|
MockMethodInvocation methodInvocation = mock(MockMethodInvocation.class);
|
||||||
|
|
||||||
|
EvaluationContext context = this.methodSecurityExpressionHandler
|
||||||
|
.createEvaluationContext(authentication, methodInvocation);
|
||||||
|
SecurityExpressionRoot root = (SecurityExpressionRoot) context.getRootObject()
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
assertThat(root.hasRole("ROLE_ABC")).isTrue();
|
||||||
|
assertThat(root.hasRole("ABC")).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class SubclassConfig extends ReactiveMethodSecurityConfiguration {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2018 the original author or authors.
|
* Copyright 2002-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -34,6 +34,7 @@ import org.springframework.security.access.expression.AbstractSecurityExpression
|
||||||
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||||
import org.springframework.security.config.test.SpringTestRule;
|
import org.springframework.security.config.test.SpringTestRule;
|
||||||
|
@ -403,4 +404,52 @@ public class WebSecurityConfigurationTests {
|
||||||
Method method = ClassUtils.getMethod(WebSecurityConfiguration.class, "delegatingApplicationListener", null);
|
Method method = ClassUtils.getMethod(WebSecurityConfiguration.class, "delegatingApplicationListener", null);
|
||||||
assertThat(Modifier.isStatic(method.getModifiers())).isTrue();
|
assertThat(Modifier.isStatic(method.getModifiers())).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadConfigWhenProxyingDisabledAndSubclassThenFilterChainsCreated() {
|
||||||
|
this.spring.register(GlobalAuthenticationWebSecurityConfigurerAdaptersConfig.class, SubclassConfig.class).autowire();
|
||||||
|
|
||||||
|
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
|
||||||
|
List<SecurityFilterChain> filterChains = filterChainProxy.getFilterChains();
|
||||||
|
|
||||||
|
assertThat(filterChains).hasSize(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class SubclassConfig extends WebSecurityConfiguration {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Import(AuthenticationTestConfiguration.class)
|
||||||
|
@EnableGlobalAuthentication
|
||||||
|
static class GlobalAuthenticationWebSecurityConfigurerAdaptersConfig {
|
||||||
|
@Configuration
|
||||||
|
@Order(1)
|
||||||
|
static class WebConfigurer1 extends WebSecurityConfigurerAdapter {
|
||||||
|
@Override
|
||||||
|
public void configure(WebSecurity web) throws Exception {
|
||||||
|
web
|
||||||
|
.ignoring()
|
||||||
|
.antMatchers("/ignore1", "/ignore2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.antMatcher("/anonymous/**")
|
||||||
|
.authorizeRequests()
|
||||||
|
.anyRequest().anonymous();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class WebConfigurer2 extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.authorizeRequests()
|
||||||
|
.anyRequest().authenticated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2019 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.config.annotation.web.reactive;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.test.SpringTestRule;
|
||||||
|
import org.springframework.security.config.users.ReactiveAuthenticationTestConfiguration;
|
||||||
|
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link ServerHttpSecurityConfiguration}.
|
||||||
|
*
|
||||||
|
* @author Eleftheria Stein
|
||||||
|
*/
|
||||||
|
public class ServerHttpSecurityConfigurationTest {
|
||||||
|
@Rule
|
||||||
|
public final SpringTestRule spring = new SpringTestRule();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadConfigWhenReactiveUserDetailsServiceConfiguredThenServerHttpSecurityExists() {
|
||||||
|
this.spring.register(ServerHttpSecurityConfiguration.class, ReactiveAuthenticationTestConfiguration.class,
|
||||||
|
WebFluxSecurityConfiguration.class).autowire();
|
||||||
|
ServerHttpSecurity serverHttpSecurity = this.spring.getContext().getBean(ServerHttpSecurity.class);
|
||||||
|
|
||||||
|
assertThat(serverHttpSecurity).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadConfigWhenProxyingDisabledAndSubclassThenServerHttpSecurityExists() {
|
||||||
|
this.spring.register(SubclassConfig.class, ReactiveAuthenticationTestConfiguration.class,
|
||||||
|
WebFluxSecurityConfiguration.class).autowire();
|
||||||
|
ServerHttpSecurity serverHttpSecurity = this.spring.getContext().getBean(ServerHttpSecurity.class);
|
||||||
|
|
||||||
|
assertThat(serverHttpSecurity).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class SubclassConfig extends ServerHttpSecurityConfiguration {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2019 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.config.annotation.web.reactive;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.test.SpringTestRule;
|
||||||
|
import org.springframework.security.config.users.ReactiveAuthenticationTestConfiguration;
|
||||||
|
import org.springframework.security.web.server.WebFilterChainProxy;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link WebFluxSecurityConfiguration}.
|
||||||
|
*
|
||||||
|
* @author Eleftheria Stein
|
||||||
|
*/
|
||||||
|
public class WebFluxSecurityConfigurationTests {
|
||||||
|
@Rule
|
||||||
|
public final SpringTestRule spring = new SpringTestRule();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadConfigWhenReactiveUserDetailsServiceConfiguredThenWebFilterChainProxyExists() {
|
||||||
|
this.spring.register(ServerHttpSecurityConfiguration.class, ReactiveAuthenticationTestConfiguration.class,
|
||||||
|
WebFluxSecurityConfiguration.class).autowire();
|
||||||
|
WebFilterChainProxy webFilterChainProxy = this.spring.getContext().getBean(WebFilterChainProxy.class);
|
||||||
|
|
||||||
|
assertThat(webFilterChainProxy).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadConfigWhenProxyingDisabledAndSubclassThenWebFilterChainProxyExists() {
|
||||||
|
this.spring.register(ServerHttpSecurityConfiguration.class, ReactiveAuthenticationTestConfiguration.class,
|
||||||
|
WebFluxSecurityConfigurationTests.SubclassConfig.class).autowire();
|
||||||
|
WebFilterChainProxy webFilterChainProxy = this.spring.getContext().getBean(WebFilterChainProxy.class);
|
||||||
|
|
||||||
|
assertThat(webFilterChainProxy).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class SubclassConfig extends WebFluxSecurityConfiguration {
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -26,6 +26,8 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
@ -40,6 +42,7 @@ import org.springframework.messaging.handler.invocation.HandlerMethodArgumentRes
|
||||||
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||||
import org.springframework.messaging.simp.SimpMessageType;
|
import org.springframework.messaging.simp.SimpMessageType;
|
||||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||||
|
import org.springframework.messaging.support.AbstractMessageChannel;
|
||||||
import org.springframework.messaging.support.GenericMessage;
|
import org.springframework.messaging.support.GenericMessage;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
@ -53,6 +56,10 @@ import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler;
|
import org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler;
|
||||||
import org.springframework.security.messaging.access.expression.MessageSecurityExpressionRoot;
|
import org.springframework.security.messaging.access.expression.MessageSecurityExpressionRoot;
|
||||||
|
import org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor;
|
||||||
|
import org.springframework.security.messaging.access.intercept.MessageSecurityMetadataSource;
|
||||||
|
import org.springframework.security.messaging.context.SecurityContextChannelInterceptor;
|
||||||
|
import org.springframework.security.messaging.web.csrf.CsrfChannelInterceptor;
|
||||||
import org.springframework.security.web.csrf.CsrfToken;
|
import org.springframework.security.web.csrf.CsrfToken;
|
||||||
import org.springframework.security.web.csrf.DefaultCsrfToken;
|
import org.springframework.security.web.csrf.DefaultCsrfToken;
|
||||||
import org.springframework.security.web.csrf.MissingCsrfTokenException;
|
import org.springframework.security.web.csrf.MissingCsrfTokenException;
|
||||||
|
@ -199,6 +206,16 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
|
||||||
messageChannel.send(message);
|
messageChannel.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void csrfProtectionDefinedByBean() {
|
||||||
|
loadConfig(SockJsProxylessSecurityConfig.class);
|
||||||
|
|
||||||
|
MessageChannel messageChannel = clientInboundChannel();
|
||||||
|
CsrfChannelInterceptor csrfChannelInterceptor = context.getBean(CsrfChannelInterceptor.class);
|
||||||
|
|
||||||
|
assertThat(((AbstractMessageChannel) messageChannel).getInterceptors()).contains(csrfChannelInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void messagesConnectUseCsrfTokenHandshakeInterceptor() throws Exception {
|
public void messagesConnectUseCsrfTokenHandshakeInterceptor() throws Exception {
|
||||||
|
|
||||||
|
@ -421,6 +438,41 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void channelSecurityInterceptorUsesMetadataSourceBeanWhenProxyingDisabled() {
|
||||||
|
|
||||||
|
loadConfig(SockJsProxylessSecurityConfig.class);
|
||||||
|
|
||||||
|
ChannelSecurityInterceptor channelSecurityInterceptor = context.getBean(ChannelSecurityInterceptor.class);
|
||||||
|
MessageSecurityMetadataSource messageSecurityMetadataSource =
|
||||||
|
context.getBean(MessageSecurityMetadataSource.class);
|
||||||
|
|
||||||
|
assertThat(channelSecurityInterceptor.obtainSecurityMetadataSource()).isSameAs(messageSecurityMetadataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void securityContextChannelInterceptorDefinedByBean() {
|
||||||
|
loadConfig(SockJsProxylessSecurityConfig.class);
|
||||||
|
|
||||||
|
MessageChannel messageChannel = clientInboundChannel();
|
||||||
|
SecurityContextChannelInterceptor securityContextChannelInterceptor =
|
||||||
|
context.getBean(SecurityContextChannelInterceptor.class);
|
||||||
|
|
||||||
|
assertThat(((AbstractMessageChannel) messageChannel).getInterceptors())
|
||||||
|
.contains(securityContextChannelInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void inboundChannelSecurityDefinedByBean() {
|
||||||
|
loadConfig(SockJsProxylessSecurityConfig.class);
|
||||||
|
|
||||||
|
MessageChannel messageChannel = clientInboundChannel();
|
||||||
|
ChannelSecurityInterceptor inboundChannelSecurity = context.getBean(ChannelSecurityInterceptor.class);
|
||||||
|
|
||||||
|
assertThat(((AbstractMessageChannel) messageChannel).getInterceptors())
|
||||||
|
.contains(inboundChannelSecurity);
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSocketMessageBroker
|
@EnableWebSocketMessageBroker
|
||||||
@Import(SyncExecutorConfig.class)
|
@Import(SyncExecutorConfig.class)
|
||||||
|
@ -706,6 +758,38 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@EnableWebSocketMessageBroker
|
||||||
|
@Import(SyncExecutorConfig.class)
|
||||||
|
static class SockJsProxylessSecurityConfig extends
|
||||||
|
AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||||
|
private ApplicationContext context;
|
||||||
|
|
||||||
|
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||||
|
registry.addEndpoint("/chat")
|
||||||
|
.setHandshakeHandler(context.getBean(TestHandshakeHandler.class))
|
||||||
|
.withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setContext(ApplicationContext context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
@Override
|
||||||
|
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||||
|
messages
|
||||||
|
.anyMessage().denyAll();
|
||||||
|
}
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TestHandshakeHandler testHandshakeHandler() {
|
||||||
|
return new TestHandshakeHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class SyncExecutorConfig {
|
static class SyncExecutorConfig {
|
||||||
@Bean
|
@Bean
|
||||||
|
|
Loading…
Reference in New Issue