Skip to content

Commit ce218c7

Browse files
committed
Add SecurityContextHolderStrategy Java Configuration for Defaults
Issue gh-11061
1 parent a31a99b commit ce218c7

17 files changed

+269
-12
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -24,6 +24,8 @@
2424
import org.springframework.context.annotation.Bean;
2525
import org.springframework.context.expression.BeanFactoryResolver;
2626
import org.springframework.expression.BeanResolver;
27+
import org.springframework.security.core.context.SecurityContextHolder;
28+
import org.springframework.security.core.context.SecurityContextHolderStrategy;
2729
import org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver;
2830
import org.springframework.security.web.method.annotation.CsrfTokenArgumentResolver;
2931
import org.springframework.security.web.method.annotation.CurrentSecurityContextArgumentResolver;
@@ -50,11 +52,15 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
5052

5153
private BeanResolver beanResolver;
5254

55+
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
56+
.getContextHolderStrategy();
57+
5358
@Override
5459
@SuppressWarnings("deprecation")
5560
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
5661
AuthenticationPrincipalArgumentResolver authenticationPrincipalResolver = new AuthenticationPrincipalArgumentResolver();
5762
authenticationPrincipalResolver.setBeanResolver(this.beanResolver);
63+
authenticationPrincipalResolver.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
5864
argumentResolvers.add(authenticationPrincipalResolver);
5965
argumentResolvers
6066
.add(new org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver());
@@ -72,6 +78,9 @@ RequestDataValueProcessor requestDataValueProcessor() {
7278
@Override
7379
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
7480
this.beanResolver = new BeanFactoryResolver(applicationContext.getAutowireCapableBeanFactory());
81+
if (applicationContext.getBeanNamesForType(SecurityContextHolderStrategy.class).length == 1) {
82+
this.securityContextHolderStrategy = applicationContext.getBean(SecurityContextHolderStrategy.class);
83+
}
7584
}
7685

7786
}

config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractAuthenticationFilterConfigurer.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -297,6 +297,7 @@ public void configure(B http) throws Exception {
297297
.getSecurityContextRepository();
298298
this.authFilter.setSecurityContextRepository(securityContextRepository);
299299
}
300+
this.authFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
300301
F filter = postProcess(this.authFilter);
301302
http.addFilter(filter);
302303
}

config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractHttpConfigurer.java

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -16,11 +16,14 @@
1616

1717
package org.springframework.security.config.annotation.web.configurers;
1818

19+
import org.springframework.context.ApplicationContext;
1920
import org.springframework.security.config.annotation.ObjectPostProcessor;
2021
import org.springframework.security.config.annotation.SecurityConfigurer;
2122
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
2223
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
2324
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
25+
import org.springframework.security.core.context.SecurityContextHolder;
26+
import org.springframework.security.core.context.SecurityContextHolderStrategy;
2427
import org.springframework.security.web.DefaultSecurityFilterChain;
2528

2629
/**
@@ -32,6 +35,8 @@
3235
public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T, B>, B extends HttpSecurityBuilder<B>>
3336
extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, B> {
3437

38+
private SecurityContextHolderStrategy securityContextHolderStrategy;
39+
3540
/**
3641
* Disables the {@link AbstractHttpConfigurer} by removing it. After doing so a fresh
3742
* version of the configuration can be applied.
@@ -49,4 +54,19 @@ public T withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
4954
return (T) this;
5055
}
5156

57+
protected SecurityContextHolderStrategy getSecurityContextHolderStrategy() {
58+
if (this.securityContextHolderStrategy != null) {
59+
return this.securityContextHolderStrategy;
60+
}
61+
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
62+
String[] names = context.getBeanNamesForType(SecurityContextHolderStrategy.class);
63+
if (names.length == 1) {
64+
this.securityContextHolderStrategy = context.getBean(SecurityContextHolderStrategy.class);
65+
}
66+
else {
67+
this.securityContextHolderStrategy = SecurityContextHolder.getContextHolderStrategy();
68+
}
69+
return this.securityContextHolderStrategy;
70+
}
71+
5272
}

config/src/main/java/org/springframework/security/config/annotation/web/configurers/AnonymousConfigurer.java

+1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ public void init(H http) {
146146
}
147147
if (this.authenticationFilter == null) {
148148
this.authenticationFilter = new AnonymousAuthenticationFilter(getKey(), this.principal, this.authorities);
149+
this.authenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
149150
}
150151
this.authenticationProvider = postProcess(this.authenticationProvider);
151152
http.authenticationProvider(this.authenticationProvider);

config/src/main/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurer.java

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ public void configure(H http) {
8686
AuthorizationFilter authorizationFilter = new AuthorizationFilter(authorizationManager);
8787
authorizationFilter.setAuthorizationEventPublisher(this.publisher);
8888
authorizationFilter.setShouldFilterAllDispatcherTypes(this.registry.shouldFilterAllDispatcherTypes);
89+
authorizationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
8990
http.addFilter(postProcess(authorizationFilter));
9091
}
9192

config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExceptionHandlingConfigurer.java

+2-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-2022 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.
@@ -187,6 +187,7 @@ public void configure(H http) {
187187
getRequestCache(http));
188188
AccessDeniedHandler deniedHandler = getAccessDeniedHandler(http);
189189
exceptionTranslationFilter.setAccessDeniedHandler(deniedHandler);
190+
exceptionTranslationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
190191
exceptionTranslationFilter = postProcess(exceptionTranslationFilter);
191192
http.addFilter(exceptionTranslationFilter);
192193
}

config/src/main/java/org/springframework/security/config/annotation/web/configurers/HttpBasicConfigurer.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -199,6 +199,7 @@ public void configure(B http) {
199199
if (rememberMeServices != null) {
200200
basicAuthenticationFilter.setRememberMeServices(rememberMeServices);
201201
}
202+
basicAuthenticationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
202203
basicAuthenticationFilter = postProcess(basicAuthenticationFilter);
203204
http.addFilter(basicAuthenticationFilter);
204205
}

config/src/main/java/org/springframework/security/config/annotation/web/configurers/LogoutConfigurer.java

+1
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ private LogoutFilter createLogoutFilter(H http) {
329329
this.logoutHandlers.add(postProcess(new LogoutSuccessEventPublishingLogoutHandler()));
330330
LogoutHandler[] handlers = this.logoutHandlers.toArray(new LogoutHandler[0]);
331331
LogoutFilter result = new LogoutFilter(getLogoutSuccessHandler(), handlers);
332+
result.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
332333
result.setLogoutRequestMatcher(getLogoutRequestMatcher(http));
333334
result = postProcess(result);
334335
return result;

config/src/main/java/org/springframework/security/config/annotation/web/configurers/SecurityContextConfigurer.java

+3-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-2022 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.
@@ -108,11 +108,13 @@ public void configure(H http) {
108108
if (this.requireExplicitSave) {
109109
SecurityContextHolderFilter securityContextHolderFilter = postProcess(
110110
new SecurityContextHolderFilter(securityContextRepository));
111+
securityContextHolderFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
111112
http.addFilter(securityContextHolderFilter);
112113
}
113114
else {
114115
SecurityContextPersistenceFilter securityContextFilter = new SecurityContextPersistenceFilter(
115116
securityContextRepository);
117+
securityContextFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
116118
SessionManagementConfigurer<?> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);
117119
SessionCreationPolicy sessionCreationPolicy = (sessionManagement != null)
118120
? sessionManagement.getSessionCreationPolicy() : null;

config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2022 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.
@@ -370,6 +370,7 @@ public void configure(H http) {
370370
if (trustResolver != null) {
371371
sessionManagementFilter.setTrustResolver(trustResolver);
372372
}
373+
sessionManagementFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
373374
sessionManagementFilter = postProcess(sessionManagementFilter);
374375
http.addFilter(sessionManagementFilter);
375376
if (isConcurrentSessionControlEnabled()) {
@@ -500,7 +501,6 @@ private SessionAuthenticationStrategy getSessionAuthenticationStrategy(H http) {
500501
concurrentSessionControlStrategy.setMaximumSessions(this.maximumSessions);
501502
concurrentSessionControlStrategy.setExceptionIfMaximumExceeded(this.maxSessionsPreventsLogin);
502503
concurrentSessionControlStrategy = postProcess(concurrentSessionControlStrategy);
503-
504504
RegisterSessionAuthenticationStrategy registerSessionStrategy = new RegisterSessionAuthenticationStrategy(
505505
sessionRegistry);
506506
registerSessionStrategy = postProcess(registerSessionStrategy);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.config;
18+
19+
import org.springframework.security.core.context.SecurityContext;
20+
import org.springframework.security.core.context.SecurityContextHolderStrategy;
21+
import org.springframework.security.core.context.SecurityContextImpl;
22+
23+
public class MockSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
24+
25+
private SecurityContext context;
26+
27+
@Override
28+
public void clearContext() {
29+
this.context = null;
30+
}
31+
32+
@Override
33+
public SecurityContext getContext() {
34+
if (this.context == null) {
35+
this.context = createEmptyContext();
36+
}
37+
return this.context;
38+
}
39+
40+
@Override
41+
public void setContext(SecurityContext context) {
42+
this.context = context;
43+
}
44+
45+
@Override
46+
public SecurityContext createEmptyContext() {
47+
return new SecurityContextImpl();
48+
}
49+
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.config.annotation;
18+
19+
import org.mockito.ArgumentMatcher;
20+
21+
import org.springframework.security.core.Authentication;
22+
import org.springframework.security.core.context.SecurityContext;
23+
import org.springframework.security.core.context.SecurityContextChangedEvent;
24+
25+
import static org.mockito.ArgumentMatchers.argThat;
26+
27+
public final class SecurityContextChangedListenerArgumentMatchers {
28+
29+
public static SecurityContextChangedEvent setAuthentication(Class<? extends Authentication> authenticationClass) {
30+
return argThat(new ArgumentMatcher<SecurityContextChangedEvent>() {
31+
public boolean matches(SecurityContextChangedEvent event) {
32+
Authentication previous = authentication(event.getOldContext());
33+
Authentication next = authentication(event.getNewContext());
34+
return previous == null && next != null && authenticationClass.isAssignableFrom(next.getClass());
35+
}
36+
37+
public String toString() {
38+
return "authentication set to " + authenticationClass;
39+
}
40+
});
41+
}
42+
43+
private static Authentication authentication(SecurityContext context) {
44+
if (context == null) {
45+
return null;
46+
}
47+
return context.getAuthentication();
48+
}
49+
50+
private SecurityContextChangedListenerArgumentMatchers() {
51+
52+
}
53+
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.config.annotation;
18+
19+
import org.springframework.context.annotation.Bean;
20+
import org.springframework.context.annotation.Configuration;
21+
import org.springframework.security.config.MockSecurityContextHolderStrategy;
22+
import org.springframework.security.core.context.ListeningSecurityContextHolderStrategy;
23+
import org.springframework.security.core.context.SecurityContextChangedListener;
24+
import org.springframework.security.core.context.SecurityContextHolderStrategy;
25+
26+
import static org.mockito.Mockito.mock;
27+
import static org.mockito.Mockito.spy;
28+
29+
@Configuration
30+
public class SecurityContextChangedListenerConfig {
31+
32+
private SecurityContextHolderStrategy strategy = new MockSecurityContextHolderStrategy();
33+
34+
private SecurityContextChangedListener listener = mock(SecurityContextChangedListener.class);
35+
36+
@Bean
37+
SecurityContextHolderStrategy securityContextHolderStrategy() {
38+
return spy(new ListeningSecurityContextHolderStrategy(this.strategy, this.listener));
39+
}
40+
41+
@Bean
42+
SecurityContextChangedListener securityContextChangedListener() {
43+
return this.listener;
44+
}
45+
46+
}

0 commit comments

Comments
 (0)