Skip to content

Commit a50d9e3

Browse files
committed
Replace bean method calls with injection
This is so that our configuration classes do not rely on CGLIB to proxy bean methods. Fixes spring-projectsgh-6818
1 parent f699854 commit a50d9e3

12 files changed

+337
-36
lines changed

config/src/main/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfiguration.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -107,8 +107,7 @@ public AuthenticationManager getAuthenticationManager() throws Exception {
107107
if (this.authenticationManagerInitialized) {
108108
return this.authenticationManager;
109109
}
110-
AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder(
111-
this.objectPostProcessor, this.applicationContext);
110+
AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
112111
if (this.buildingAuthenticationManager.getAndSet(true)) {
113112
return new AuthenticationManagerDelegator(authBuilder);
114113
}

config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java

+8-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,10 +29,7 @@
2929
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3030
import org.springframework.beans.factory.SmartInitializingSingleton;
3131
import org.springframework.beans.factory.annotation.Autowired;
32-
import org.springframework.context.annotation.AdviceMode;
33-
import org.springframework.context.annotation.Bean;
34-
import org.springframework.context.annotation.Configuration;
35-
import org.springframework.context.annotation.ImportAware;
32+
import org.springframework.context.annotation.*;
3633
import org.springframework.core.annotation.AnnotationAttributes;
3734
import org.springframework.core.annotation.AnnotationUtils;
3835
import org.springframework.core.type.AnnotationMetadata;
@@ -110,7 +107,6 @@ public <T> T postProcess(T object) {
110107
* <li>{@link #accessDecisionManager()}</li>
111108
* <li>{@link #afterInvocationManager()}</li>
112109
* <li>{@link #authenticationManager()}</li>
113-
* <li>{@link #methodSecurityMetadataSource()}</li>
114110
* <li>{@link #runAsManager()}</li>
115111
*
116112
* </ul>
@@ -119,19 +115,19 @@ public <T> T postProcess(T object) {
119115
* Subclasses can override this method to provide a different
120116
* {@link MethodInterceptor}.
121117
* </p>
118+
* @param methodSecurityMetadataSource the default {@link MethodSecurityMetadataSource}.
122119
*
123120
* @return the {@link MethodInterceptor}.
124-
* @throws Exception
125121
*/
126122
@Bean
127-
public MethodInterceptor methodSecurityInterceptor() throws Exception {
123+
public MethodInterceptor methodSecurityInterceptor(MethodSecurityMetadataSource methodSecurityMetadataSource) {
128124
this.methodSecurityInterceptor = isAspectJ()
129125
? new AspectJMethodSecurityInterceptor()
130126
: new MethodSecurityInterceptor();
131127
methodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager());
132128
methodSecurityInterceptor.setAfterInvocationManager(afterInvocationManager());
133129
methodSecurityInterceptor
134-
.setSecurityMetadataSource(methodSecurityMetadataSource());
130+
.setSecurityMetadataSource(methodSecurityMetadataSource);
135131
RunAsManager runAsManager = runAsManager();
136132
if (runAsManager != null) {
137133
methodSecurityInterceptor.setRunAsManager(runAsManager);
@@ -197,8 +193,8 @@ private void initializeMethodSecurityInterceptor() throws Exception {
197193

198194
/**
199195
* Provide a custom {@link AfterInvocationManager} for the default implementation of
200-
* {@link #methodSecurityInterceptor()}. The default is null if pre post is not
201-
* enabled. Otherwise, it returns a {@link AfterInvocationProviderManager}.
196+
* {@link #methodSecurityInterceptor(MethodSecurityMetadataSource)}. The default is null
197+
* if pre post is not enabled. Otherwise, it returns a {@link AfterInvocationProviderManager}.
202198
*
203199
* <p>
204200
* Subclasses should override this method to provide a custom
@@ -224,7 +220,7 @@ protected AfterInvocationManager afterInvocationManager() {
224220

225221
/**
226222
* Provide a custom {@link RunAsManager} for the default implementation of
227-
* {@link #methodSecurityInterceptor()}. The default is null.
223+
* {@link #methodSecurityInterceptor(MethodSecurityMetadataSource)}. The default is null.
228224
*
229225
* @return the {@link RunAsManager} to use
230226
*/

config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java

+10-5
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
* @since 5.0
4444
*/
4545
@Configuration
46-
class ServerHttpSecurityConfiguration implements WebFluxConfigurer {
46+
class ServerHttpSecurityConfiguration {
4747
private static final String BEAN_NAME_PREFIX = "org.springframework.security.config.annotation.web.reactive.HttpSecurityConfiguration.";
4848
private static final String HTTPSECURITY_BEAN_NAME = BEAN_NAME_PREFIX + "httpSecurity";
4949

@@ -85,9 +85,15 @@ void setUserDetailsPasswordService(ReactiveUserDetailsPasswordService userDetail
8585
this.userDetailsPasswordService = userDetailsPasswordService;
8686
}
8787

88-
@Override
89-
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
90-
configurer.addCustomResolver(authenticationPrincipalArgumentResolver());
88+
@Bean
89+
public WebFluxConfigurer authenticationPrincipalArgumentResolverConfigurer(
90+
AuthenticationPrincipalArgumentResolver authenticationPrincipalArgumentResolver) {
91+
return new WebFluxConfigurer() {
92+
@Override
93+
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
94+
configurer.addCustomResolver(authenticationPrincipalArgumentResolver);
95+
}
96+
};
9197
}
9298

9399
@Bean
@@ -110,7 +116,6 @@ public CurrentSecurityContextArgumentResolver reactiveCurrentSecurityContextArgu
110116
return resolver;
111117
}
112118

113-
114119
@Bean(HTTPSECURITY_BEAN_NAME)
115120
@Scope("prototype")
116121
public ServerHttpSecurity httpSecurity() {

config/src/main/java/org/springframework/security/config/annotation/web/socket/AbstractSecurityWebSocketMessageBrokerConfigurer.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -103,10 +103,10 @@ public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentRes
103103

104104
@Override
105105
public final void configureClientInboundChannel(ChannelRegistration registration) {
106-
ChannelSecurityInterceptor inboundChannelSecurity = inboundChannelSecurity();
107-
registration.setInterceptors(securityContextChannelInterceptor());
106+
ChannelSecurityInterceptor inboundChannelSecurity = context.getBean(ChannelSecurityInterceptor.class);
107+
registration.setInterceptors(context.getBean(SecurityContextChannelInterceptor.class));
108108
if (!sameOriginDisabled()) {
109-
registration.setInterceptors(csrfChannelInterceptor());
109+
registration.setInterceptors(context.getBean(CsrfChannelInterceptor.class));
110110
}
111111
if (inboundRegistry.containsMapping()) {
112112
registration.setInterceptors(inboundChannelSecurity);
@@ -153,9 +153,9 @@ public CsrfChannelInterceptor csrfChannelInterceptor() {
153153
}
154154

155155
@Bean
156-
public ChannelSecurityInterceptor inboundChannelSecurity() {
156+
public ChannelSecurityInterceptor inboundChannelSecurity(MessageSecurityMetadataSource messageSecurityMetadataSource) {
157157
ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(
158-
inboundMessageSecurityMetadataSource());
158+
messageSecurityMetadataSource);
159159
MessageExpressionVoter<Object> voter = new MessageExpressionVoter<>();
160160
voter.setExpressionHandler(getMessageExpressionHandler());
161161

config/src/test/java/org/springframework/security/config/annotation/authentication/configuration/AuthenticationConfigurationTests.java

+19-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
3434
import org.springframework.security.authentication.TestingAuthenticationToken;
3535
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
3636
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
37+
import org.springframework.security.config.annotation.AlreadyBuiltException;
3738
import org.springframework.security.config.annotation.ObjectPostProcessor;
3839
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
3940
import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration;
@@ -64,9 +65,7 @@
6465
import static org.mockito.ArgumentMatchers.any;
6566
import static org.mockito.ArgumentMatchers.eq;
6667
import static org.mockito.ArgumentMatchers.startsWith;
67-
import static org.mockito.Mockito.mock;
68-
import static org.mockito.Mockito.verify;
69-
import static org.mockito.Mockito.when;
68+
import static org.mockito.Mockito.*;
7069

7170
public class AuthenticationConfigurationTests {
7271

@@ -530,4 +529,20 @@ public AuthenticationManager manager2() {
530529
}
531530

532531
}
532+
533+
@Test
534+
public void getAuthenticationManagerWhenAuthenticationConfigurationSubclassedThenBuildsUsingBean()
535+
throws Exception {
536+
this.spring.register(AuthenticationConfigurationSubclass.class).autowire();
537+
AuthenticationManagerBuilder ap = this.spring.getContext().getBean(AuthenticationManagerBuilder.class);
538+
539+
this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
540+
541+
assertThatThrownBy(ap::build)
542+
.isInstanceOf(AlreadyBuiltException.class);
543+
}
544+
545+
@Configuration(proxyBeanMethods = false)
546+
static class AuthenticationConfigurationSubclass extends AuthenticationConfiguration {
547+
}
533548
}

config/src/test/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfigurationTests.java

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
2020
import java.util.Map;
2121
import javax.sql.DataSource;
2222

23+
import org.aopalliance.intercept.MethodInterceptor;
2324
import org.junit.Rule;
2425
import org.junit.Test;
2526
import org.junit.rules.ExpectedException;
@@ -553,4 +554,20 @@ static class CustomAuthorityService {
553554
public void emptyPrefixRoleUser() {}
554555
}
555556
}
557+
558+
@Test
559+
public void methodSecurityInterceptorUsesMetadataSourceBeanWhenProxyingDisabled() {
560+
this.spring.register(CustomMetadataSourceProxylessConfig.class).autowire();
561+
MethodSecurityInterceptor methodInterceptor =
562+
(MethodSecurityInterceptor) this.spring.getContext().getBean(MethodInterceptor.class);
563+
MethodSecurityMetadataSource methodSecurityMetadataSource =
564+
this.spring.getContext().getBean(MethodSecurityMetadataSource.class);
565+
566+
assertThat(methodInterceptor.getSecurityMetadataSource()).isSameAs(methodSecurityMetadataSource);
567+
}
568+
569+
@EnableGlobalMethodSecurity(prePostEnabled = true)
570+
@Configuration(proxyBeanMethods = false)
571+
public static class CustomMetadataSourceProxylessConfig extends GlobalMethodSecurityConfiguration {
572+
}
556573
}

config/src/test/java/org/springframework/security/config/annotation/method/configuration/NamespaceGlobalMethodSecurityTests.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -163,8 +163,8 @@ public void methodSecurityWhenCustomAuthenticationManagerThenAuthorizes() {
163163
public static class CustomAuthenticationConfig extends GlobalMethodSecurityConfiguration {
164164

165165
@Override
166-
public MethodInterceptor methodSecurityInterceptor() throws Exception {
167-
MethodInterceptor interceptor = super.methodSecurityInterceptor();
166+
public MethodInterceptor methodSecurityInterceptor(MethodSecurityMetadataSource methodSecurityMetadataSource) {
167+
MethodInterceptor interceptor = super.methodSecurityInterceptor(methodSecurityMetadataSource);
168168
((MethodSecurityInterceptor) interceptor).setAlwaysReauthenticate(true);
169169
return interceptor;
170170
}

config/src/test/java/org/springframework/security/config/annotation/method/configuration/ReactiveMethodSecurityConfigurationTests.java

+20
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,24 @@ GrantedAuthorityDefaults grantedAuthorityDefaults() {
8888
}
8989
}
9090

91+
@Test
92+
public void rolePrefixWithGrantedAuthorityDefaultsAndSubclassWithProxyingDisabled() {
93+
this.spring.register(SubclassConfig.class).autowire();
94+
95+
TestingAuthenticationToken authentication = new TestingAuthenticationToken(
96+
"principal", "credential", "ROLE_ABC");
97+
MockMethodInvocation methodInvocation = mock(MockMethodInvocation.class);
98+
99+
EvaluationContext context = this.methodSecurityExpressionHandler
100+
.createEvaluationContext(authentication, methodInvocation);
101+
SecurityExpressionRoot root = (SecurityExpressionRoot) context.getRootObject()
102+
.getValue();
103+
104+
assertThat(root.hasRole("ROLE_ABC")).isTrue();
105+
assertThat(root.hasRole("ABC")).isTrue();
106+
}
107+
108+
@Configuration(proxyBeanMethods = false)
109+
static class SubclassConfig extends ReactiveMethodSecurityConfiguration {
110+
}
91111
}

config/src/test/java/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurationTests.java

+50-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
3434
import org.springframework.security.access.expression.SecurityExpressionHandler;
3535
import org.springframework.security.authentication.TestingAuthenticationToken;
3636
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
37+
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
3738
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
3839
import org.springframework.security.config.annotation.web.builders.WebSecurity;
3940
import org.springframework.security.config.test.SpringTestRule;
@@ -403,4 +404,52 @@ public void getMethodDelegatingApplicationListenerWhenWebSecurityConfigurationTh
403404
Method method = ClassUtils.getMethod(WebSecurityConfiguration.class, "delegatingApplicationListener", null);
404405
assertThat(Modifier.isStatic(method.getModifiers())).isTrue();
405406
}
407+
408+
@Test
409+
public void loadConfigWhenProxyingDisabledAndSubclassThenFilterChainsCreated() {
410+
this.spring.register(GlobalAuthenticationWebSecurityConfigurerAdaptersConfig.class, SubclassConfig.class).autowire();
411+
412+
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
413+
List<SecurityFilterChain> filterChains = filterChainProxy.getFilterChains();
414+
415+
assertThat(filterChains).hasSize(4);
416+
}
417+
418+
@Configuration(proxyBeanMethods = false)
419+
static class SubclassConfig extends WebSecurityConfiguration {
420+
}
421+
422+
@Import(AuthenticationTestConfiguration.class)
423+
@EnableGlobalAuthentication
424+
static class GlobalAuthenticationWebSecurityConfigurerAdaptersConfig {
425+
@Configuration
426+
@Order(1)
427+
static class WebConfigurer1 extends WebSecurityConfigurerAdapter {
428+
@Override
429+
public void configure(WebSecurity web) throws Exception {
430+
web
431+
.ignoring()
432+
.antMatchers("/ignore1", "/ignore2");
433+
}
434+
435+
@Override
436+
protected void configure(HttpSecurity http) throws Exception {
437+
http
438+
.antMatcher("/anonymous/**")
439+
.authorizeRequests()
440+
.anyRequest().anonymous();
441+
}
442+
}
443+
444+
@Configuration
445+
static class WebConfigurer2 extends WebSecurityConfigurerAdapter {
446+
447+
@Override
448+
protected void configure(HttpSecurity http) throws Exception {
449+
http
450+
.authorizeRequests()
451+
.anyRequest().authenticated();
452+
}
453+
}
454+
}
406455
}

0 commit comments

Comments
 (0)