diff --git a/config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.java index 512361b38f..2704ca6d4d 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.java @@ -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"); * you may not use this file except in compliance with the License. @@ -107,8 +107,7 @@ public class AuthenticationConfiguration { if (this.authenticationManagerInitialized) { return this.authenticationManager; } - AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder( - this.objectPostProcessor, this.applicationContext); + AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class); if (this.buildingAuthenticationManager.getAndSet(true)) { return new AuthenticationManagerDelegator(authBuilder); } diff --git a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java index 1139119251..38925a45d0 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java @@ -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"); * 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.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.AdviceMode; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportAware; +import org.springframework.context.annotation.*; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.type.AnnotationMetadata; @@ -110,7 +107,6 @@ public class GlobalMethodSecurityConfiguration *
  • {@link #accessDecisionManager()}
  • *
  • {@link #afterInvocationManager()}
  • *
  • {@link #authenticationManager()}
  • - *
  • {@link #methodSecurityMetadataSource()}
  • *
  • {@link #runAsManager()}
  • * * @@ -119,19 +115,19 @@ public class GlobalMethodSecurityConfiguration * Subclasses can override this method to provide a different * {@link MethodInterceptor}. *

    + * @param methodSecurityMetadataSource the default {@link MethodSecurityMetadataSource}. * * @return the {@link MethodInterceptor}. - * @throws Exception */ @Bean - public MethodInterceptor methodSecurityInterceptor() throws Exception { + public MethodInterceptor methodSecurityInterceptor(MethodSecurityMetadataSource methodSecurityMetadataSource) { this.methodSecurityInterceptor = isAspectJ() ? new AspectJMethodSecurityInterceptor() : new MethodSecurityInterceptor(); methodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager()); methodSecurityInterceptor.setAfterInvocationManager(afterInvocationManager()); methodSecurityInterceptor - .setSecurityMetadataSource(methodSecurityMetadataSource()); + .setSecurityMetadataSource(methodSecurityMetadataSource); RunAsManager runAsManager = runAsManager(); if (runAsManager != null) { methodSecurityInterceptor.setRunAsManager(runAsManager); @@ -197,8 +193,8 @@ public class GlobalMethodSecurityConfiguration /** * Provide a custom {@link AfterInvocationManager} for the default implementation of - * {@link #methodSecurityInterceptor()}. The default is null if pre post is not - * enabled. Otherwise, it returns a {@link AfterInvocationProviderManager}. + * {@link #methodSecurityInterceptor(MethodSecurityMetadataSource)}. The default is null + * if pre post is not enabled. Otherwise, it returns a {@link AfterInvocationProviderManager}. * *

    * 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 - * {@link #methodSecurityInterceptor()}. The default is null. + * {@link #methodSecurityInterceptor(MethodSecurityMetadataSource)}. The default is null. * * @return the {@link RunAsManager} to use */ diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java index 1cc17fed54..a0d9084b6f 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java @@ -43,7 +43,7 @@ import org.springframework.web.reactive.result.method.annotation.ArgumentResolve * @since 5.0 */ @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 HTTPSECURITY_BEAN_NAME = BEAN_NAME_PREFIX + "httpSecurity"; @@ -85,9 +85,15 @@ class ServerHttpSecurityConfiguration implements WebFluxConfigurer { this.userDetailsPasswordService = userDetailsPasswordService; } - @Override - public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) { - configurer.addCustomResolver(authenticationPrincipalArgumentResolver()); + @Bean + public WebFluxConfigurer authenticationPrincipalArgumentResolverConfigurer( + AuthenticationPrincipalArgumentResolver authenticationPrincipalArgumentResolver) { + return new WebFluxConfigurer() { + @Override + public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) { + configurer.addCustomResolver(authenticationPrincipalArgumentResolver); + } + }; } @Bean @@ -110,7 +116,6 @@ class ServerHttpSecurityConfiguration implements WebFluxConfigurer { return resolver; } - @Bean(HTTPSECURITY_BEAN_NAME) @Scope("prototype") public ServerHttpSecurity httpSecurity() { diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java index d3b2de2709..42c560af68 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java @@ -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"); * you may not use this file except in compliance with the License. @@ -103,10 +103,10 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends @Override public final void configureClientInboundChannel(ChannelRegistration registration) { - ChannelSecurityInterceptor inboundChannelSecurity = inboundChannelSecurity(); - registration.setInterceptors(securityContextChannelInterceptor()); + ChannelSecurityInterceptor inboundChannelSecurity = context.getBean(ChannelSecurityInterceptor.class); + registration.setInterceptors(context.getBean(SecurityContextChannelInterceptor.class)); if (!sameOriginDisabled()) { - registration.setInterceptors(csrfChannelInterceptor()); + registration.setInterceptors(context.getBean(CsrfChannelInterceptor.class)); } if (inboundRegistry.containsMapping()) { registration.setInterceptors(inboundChannelSecurity); @@ -153,9 +153,9 @@ public abstract class AbstractSecurityWebSocketMessageBrokerConfigurer extends } @Bean - public ChannelSecurityInterceptor inboundChannelSecurity() { + public ChannelSecurityInterceptor inboundChannelSecurity(MessageSecurityMetadataSource messageSecurityMetadataSource) { ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor( - inboundMessageSecurityMetadataSource()); + messageSecurityMetadataSource); MessageExpressionVoter voter = new MessageExpressionVoter<>(); voter.setExpressionHandler(getMessageExpressionHandler()); diff --git a/config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfigurationTests.java index a3505ab9b2..ace8664ad8 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfigurationTests.java @@ -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"); * 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.UsernamePasswordAuthenticationToken; 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.authentication.builders.AuthenticationManagerBuilder; 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.eq; import static org.mockito.ArgumentMatchers.startsWith; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; 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 { + } } diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfigurationTests.java index acb97a9619..e06dde1764 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfigurationTests.java @@ -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"); * 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 javax.sql.DataSource; +import org.aopalliance.intercept.MethodInterceptor; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -553,4 +554,20 @@ public class GlobalMethodSecurityConfigurationTests { 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 { + } } diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/NamespaceGlobalMethodSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/NamespaceGlobalMethodSecurityTests.java index 2f72ea9a56..1174a77d34 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/NamespaceGlobalMethodSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/NamespaceGlobalMethodSecurityTests.java @@ -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"); * 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 { @Override - public MethodInterceptor methodSecurityInterceptor() throws Exception { - MethodInterceptor interceptor = super.methodSecurityInterceptor(); + public MethodInterceptor methodSecurityInterceptor(MethodSecurityMetadataSource methodSecurityMetadataSource) { + MethodInterceptor interceptor = super.methodSecurityInterceptor(methodSecurityMetadataSource); ((MethodSecurityInterceptor) interceptor).setAlwaysReauthenticate(true); return interceptor; } diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java index 97f8294df3..789e9f11f1 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java @@ -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 { + } } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java index d786129a23..5a7709f5f5 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java @@ -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"); * 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.authentication.TestingAuthenticationToken; 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.WebSecurity; import org.springframework.security.config.test.SpringTestRule; @@ -403,4 +404,52 @@ public class WebSecurityConfigurationTests { Method method = ClassUtils.getMethod(WebSecurityConfiguration.class, "delegatingApplicationListener", null); 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 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(); + } + } + } } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfigurationTest.java b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfigurationTest.java new file mode 100644 index 0000000000..193cdc0613 --- /dev/null +++ b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfigurationTest.java @@ -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 { + } +} diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfigurationTests.java new file mode 100644 index 0000000000..a4e1f328fd --- /dev/null +++ b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfigurationTests.java @@ -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 { + } +} diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java index 2bd5419532..b1b0617eef 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurerTests.java @@ -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"); * 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.Before; 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.Configuration; 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.SimpMessageType; import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.messaging.support.AbstractMessageChannel; import org.springframework.messaging.support.GenericMessage; import org.springframework.mock.web.MockHttpServletRequest; 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.messaging.access.expression.DefaultMessageSecurityExpressionHandler; 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.DefaultCsrfToken; import org.springframework.security.web.csrf.MissingCsrfTokenException; @@ -199,6 +206,16 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests { 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 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 @EnableWebSocketMessageBroker @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 static class SyncExecutorConfig { @Bean