Skip to content

Commit b8d5172

Browse files
committed
Immutable SecurityContext
Issue gh-10032
1 parent 3ab6bee commit b8d5172

File tree

15 files changed

+66
-22
lines changed

15 files changed

+66
-22
lines changed

cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource;
3838
import org.springframework.security.core.Authentication;
3939
import org.springframework.security.core.AuthenticationException;
40+
import org.springframework.security.core.context.SecurityContext;
4041
import org.springframework.security.core.context.SecurityContextHolder;
4142
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
4243
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
@@ -219,7 +220,9 @@ protected final void successfulAuthentication(HttpServletRequest request, HttpSe
219220
}
220221
this.logger.debug(
221222
LogMessage.format("Authentication success. Updating SecurityContextHolder to contain: %s", authResult));
222-
SecurityContextHolder.getContext().setAuthentication(authResult);
223+
SecurityContext context = SecurityContextHolder.createEmptyContext();
224+
context.setAuthentication(authResult);
225+
SecurityContextHolder.setContext(context);
223226
if (this.eventPublisher != null) {
224227
this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
225228
}

core/src/main/java/org/springframework/security/access/intercept/AbstractSecurityInterceptor.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,9 @@ protected InterceptorStatusToken beforeInvocation(Object object) {
217217
Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attributes);
218218
if (runAs != null) {
219219
SecurityContext origCtx = SecurityContextHolder.getContext();
220-
SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
221-
SecurityContextHolder.getContext().setAuthentication(runAs);
220+
SecurityContext newCtx = SecurityContextHolder.createEmptyContext();
221+
newCtx.setAuthentication(runAs);
222+
SecurityContextHolder.setContext(newCtx);
222223

223224
if (this.logger.isDebugEnabled()) {
224225
this.logger.debug(LogMessage.format("Switched to RunAs authentication %s", runAs));
@@ -316,7 +317,9 @@ private Authentication authenticateIfRequired() {
316317
if (this.logger.isDebugEnabled()) {
317318
this.logger.debug(LogMessage.format("Re-authenticated %s before authorizing", authentication));
318319
}
319-
SecurityContextHolder.getContext().setAuthentication(authentication);
320+
SecurityContext context = SecurityContextHolder.createEmptyContext();
321+
context.setAuthentication(authentication);
322+
SecurityContextHolder.setContext(context);
320323
return authentication;
321324
}
322325

core/src/main/java/org/springframework/security/core/Authentication.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
* the code:
3737
*
3838
* <pre>
39-
* SecurityContextHolder.getContext().setAuthentication(anAuthentication);
39+
* SecurityContext context = SecurityContextHolder.createEmptyContext();
40+
* context.setAuthentication(anAuthentication);
41+
* SecurityContextHolder.setContext(context);
4042
* </pre>
4143
*
4244
* Note that unless the <tt>Authentication</tt> has the <tt>authenticated</tt> property

core/src/main/java/org/springframework/security/provisioning/JdbcUserDetailsManager.java

Lines changed: 6 additions & 2 deletions
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-2021 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.
@@ -38,6 +38,7 @@
3838
import org.springframework.security.core.GrantedAuthority;
3939
import org.springframework.security.core.authority.AuthorityUtils;
4040
import org.springframework.security.core.authority.SimpleGrantedAuthority;
41+
import org.springframework.security.core.context.SecurityContext;
4142
import org.springframework.security.core.context.SecurityContextHolder;
4243
import org.springframework.security.core.userdetails.User;
4344
import org.springframework.security.core.userdetails.UserCache;
@@ -277,7 +278,10 @@ public void changePassword(String oldPassword, String newPassword) throws Authen
277278
}
278279
this.logger.debug("Changing password for user '" + username + "'");
279280
getJdbcTemplate().update(this.changePasswordSql, newPassword, username);
280-
SecurityContextHolder.getContext().setAuthentication(createNewAuthentication(currentUser, newPassword));
281+
Authentication authentication = createNewAuthentication(currentUser, newPassword);
282+
SecurityContext context = SecurityContextHolder.createEmptyContext();
283+
context.setAuthentication(authentication);
284+
SecurityContextHolder.setContext(context);
281285
this.userCache.removeUserFromCache(username);
282286
}
283287

remoting/src/main/java/org/springframework/security/remoting/rmi/ContextPropagatingRemoteInvocation.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
2828
import org.springframework.security.core.Authentication;
2929
import org.springframework.security.core.SpringSecurityCoreVersion;
30+
import org.springframework.security.core.context.SecurityContext;
3031
import org.springframework.security.core.context.SecurityContextHolder;
3132

3233
/**
@@ -97,7 +98,9 @@ public Object invoke(Object targetObject)
9798
if (this.principal != null) {
9899
Authentication request = createAuthenticationRequest(this.principal, this.credentials);
99100
request.setAuthenticated(false);
100-
SecurityContextHolder.getContext().setAuthentication(request);
101+
SecurityContext context = SecurityContextHolder.createEmptyContext();
102+
context.setAuthentication(request);
103+
SecurityContextHolder.setContext(context);
101104
logger.debug(LogMessage.format("Set SecurityContextHolder to contain: %s", request));
102105
}
103106
try {

web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2004-2020 the original author or authors.
2+
* Copyright 2004-2021 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.
@@ -36,6 +36,7 @@
3636
import org.springframework.security.core.Authentication;
3737
import org.springframework.security.core.AuthenticationException;
3838
import org.springframework.security.core.SpringSecurityMessageSource;
39+
import org.springframework.security.core.context.SecurityContext;
3940
import org.springframework.security.core.context.SecurityContextHolder;
4041
import org.springframework.security.web.AuthenticationEntryPoint;
4142
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
@@ -208,7 +209,8 @@ protected void sendStartAuthentication(HttpServletRequest request, HttpServletRe
208209
AuthenticationException reason) throws ServletException, IOException {
209210
// SEC-112: Clear the SecurityContextHolder's Authentication, as the
210211
// existing Authentication is no longer considered valid
211-
SecurityContextHolder.getContext().setAuthentication(null);
212+
SecurityContext context = SecurityContextHolder.createEmptyContext();
213+
SecurityContextHolder.setContext(context);
212214
this.requestCache.saveRequest(request, response);
213215
this.authenticationEntryPoint.commence(request, response, reason);
214216
}

web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.springframework.security.core.Authentication;
3939
import org.springframework.security.core.AuthenticationException;
4040
import org.springframework.security.core.SpringSecurityMessageSource;
41+
import org.springframework.security.core.context.SecurityContext;
4142
import org.springframework.security.core.context.SecurityContextHolder;
4243
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
4344
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
@@ -310,7 +311,9 @@ public abstract Authentication attemptAuthentication(HttpServletRequest request,
310311
*/
311312
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
312313
Authentication authResult) throws IOException, ServletException {
313-
SecurityContextHolder.getContext().setAuthentication(authResult);
314+
SecurityContext context = SecurityContextHolder.createEmptyContext();
315+
context.setAuthentication(authResult);
316+
SecurityContextHolder.setContext(context);
314317
if (this.logger.isDebugEnabled()) {
315318
this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult));
316319
}

web/src/main/java/org/springframework/security/web/authentication/AnonymousAuthenticationFilter.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.security.core.Authentication;
3333
import org.springframework.security.core.GrantedAuthority;
3434
import org.springframework.security.core.authority.AuthorityUtils;
35+
import org.springframework.security.core.context.SecurityContext;
3536
import org.springframework.security.core.context.SecurityContextHolder;
3637
import org.springframework.util.Assert;
3738
import org.springframework.web.filter.GenericFilterBean;
@@ -87,7 +88,10 @@ public void afterPropertiesSet() {
8788
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
8889
throws IOException, ServletException {
8990
if (SecurityContextHolder.getContext().getAuthentication() == null) {
90-
SecurityContextHolder.getContext().setAuthentication(createAuthentication((HttpServletRequest) req));
91+
Authentication authentication = createAuthentication((HttpServletRequest) req);
92+
SecurityContext context = SecurityContextHolder.createEmptyContext();
93+
context.setAuthentication(authentication);
94+
SecurityContextHolder.setContext(context);
9195
if (this.logger.isTraceEnabled()) {
9296
this.logger.trace(LogMessage.of(() -> "Set SecurityContextHolder to "
9397
+ SecurityContextHolder.getContext().getAuthentication()));

web/src/main/java/org/springframework/security/web/authentication/logout/SecurityContextLogoutHandler.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,12 @@ public void logout(HttpServletRequest request, HttpServletResponse response, Aut
7070
}
7171
if (this.clearAuthentication) {
7272
SecurityContext context = SecurityContextHolder.getContext();
73+
SecurityContextHolder.clearContext();
7374
context.setAuthentication(null);
7475
}
75-
SecurityContextHolder.clearContext();
76+
else {
77+
SecurityContextHolder.clearContext();
78+
}
7679
}
7780

7881
public boolean isInvalidateHttpSession() {

web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java

Lines changed: 5 additions & 2 deletions
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-2021 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.event.InteractiveAuthenticationSuccessEvent;
3535
import org.springframework.security.core.Authentication;
3636
import org.springframework.security.core.AuthenticationException;
37+
import org.springframework.security.core.context.SecurityContext;
3738
import org.springframework.security.core.context.SecurityContextHolder;
3839
import org.springframework.security.web.WebAttributes;
3940
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
@@ -206,7 +207,9 @@ private void doAuthenticate(HttpServletRequest request, HttpServletResponse resp
206207
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
207208
Authentication authResult) throws IOException, ServletException {
208209
this.logger.debug(LogMessage.format("Authentication success: %s", authResult));
209-
SecurityContextHolder.getContext().setAuthentication(authResult);
210+
SecurityContext context = SecurityContextHolder.createEmptyContext();
211+
context.setAuthentication(authResult);
212+
SecurityContextHolder.setContext(context);
210213
if (this.eventPublisher != null) {
211214
this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
212215
}

0 commit comments

Comments
 (0)