Skip to content

Commit ec1bfa1

Browse files
committed
Use SecurityContextHolderStrategy for Database Support
Issue gh-11060
1 parent 52dc120 commit ec1bfa1

File tree

4 files changed

+68
-5
lines changed

4 files changed

+68
-5
lines changed

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
3232
import org.springframework.security.core.Authentication;
3333
import org.springframework.security.core.context.SecurityContextHolder;
34+
import org.springframework.security.core.context.SecurityContextHolderStrategy;
3435
import org.springframework.security.core.userdetails.User;
3536
import org.springframework.security.core.userdetails.UserDetails;
3637
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
@@ -55,6 +56,9 @@ public class InMemoryUserDetailsManager implements UserDetailsManager, UserDetai
5556

5657
private final Map<String, MutableUserDetails> users = new HashMap<>();
5758

59+
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
60+
.getContextHolderStrategy();
61+
5862
private AuthenticationManager authenticationManager;
5963

6064
public InMemoryUserDetailsManager() {
@@ -113,7 +117,7 @@ public boolean userExists(String username) {
113117

114118
@Override
115119
public void changePassword(String oldPassword, String newPassword) {
116-
Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();
120+
Authentication currentUser = this.securityContextHolderStrategy.getContext().getAuthentication();
117121
if (currentUser == null) {
118122
// This would indicate bad coding somewhere
119123
throw new AccessDeniedException(
@@ -154,6 +158,17 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx
154158
user.isCredentialsNonExpired(), user.isAccountNonLocked(), user.getAuthorities());
155159
}
156160

161+
/**
162+
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
163+
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
164+
*
165+
* @since 5.8
166+
*/
167+
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
168+
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
169+
this.securityContextHolderStrategy = securityContextHolderStrategy;
170+
}
171+
157172
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
158173
this.authenticationManager = authenticationManager;
159174
}

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.springframework.security.core.authority.SimpleGrantedAuthority;
4141
import org.springframework.security.core.context.SecurityContext;
4242
import org.springframework.security.core.context.SecurityContextHolder;
43+
import org.springframework.security.core.context.SecurityContextHolderStrategy;
4344
import org.springframework.security.core.userdetails.User;
4445
import org.springframework.security.core.userdetails.UserCache;
4546
import org.springframework.security.core.userdetails.UserDetails;
@@ -108,6 +109,9 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
108109

109110
protected final Log logger = LogFactory.getLog(getClass());
110111

112+
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
113+
.getContextHolderStrategy();
114+
111115
private String createUserSql = DEF_CREATE_USER_SQL;
112116

113117
private String deleteUserSql = DEF_DELETE_USER_SQL;
@@ -260,7 +264,7 @@ private void deleteUserAuthorities(String username) {
260264

261265
@Override
262266
public void changePassword(String oldPassword, String newPassword) throws AuthenticationException {
263-
Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();
267+
Authentication currentUser = this.securityContextHolderStrategy.getContext().getAuthentication();
264268
if (currentUser == null) {
265269
// This would indicate bad coding somewhere
266270
throw new AccessDeniedException(
@@ -280,9 +284,9 @@ public void changePassword(String oldPassword, String newPassword) throws Authen
280284
this.logger.debug("Changing password for user '" + username + "'");
281285
getJdbcTemplate().update(this.changePasswordSql, newPassword, username);
282286
Authentication authentication = createNewAuthentication(currentUser, newPassword);
283-
SecurityContext context = SecurityContextHolder.createEmptyContext();
287+
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
284288
context.setAuthentication(authentication);
285-
SecurityContextHolder.setContext(context);
289+
this.securityContextHolderStrategy.setContext(context);
286290
this.userCache.removeUserFromCache(username);
287291
}
288292

@@ -419,6 +423,17 @@ private int findGroupId(String group) {
419423
return getJdbcTemplate().queryForObject(this.findGroupIdSql, Integer.class, group);
420424
}
421425

426+
/**
427+
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
428+
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
429+
*
430+
* @since 5.8
431+
*/
432+
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
433+
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
434+
this.securityContextHolderStrategy = securityContextHolderStrategy;
435+
}
436+
422437
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
423438
this.authenticationManager = authenticationManager;
424439
}

core/src/test/java/org/springframework/security/provisioning/InMemoryUserDetailsManagerTests.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 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.
@@ -20,12 +20,19 @@
2020

2121
import org.junit.jupiter.api.Test;
2222

23+
import org.springframework.security.authentication.TestAuthentication;
24+
import org.springframework.security.core.Authentication;
25+
import org.springframework.security.core.context.SecurityContextHolderStrategy;
26+
import org.springframework.security.core.context.SecurityContextImpl;
2327
import org.springframework.security.core.userdetails.PasswordEncodedUser;
2428
import org.springframework.security.core.userdetails.User;
2529
import org.springframework.security.core.userdetails.UserDetails;
2630

2731
import static org.assertj.core.api.Assertions.assertThat;
2832
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
33+
import static org.mockito.BDDMockito.given;
34+
import static org.mockito.Mockito.mock;
35+
import static org.mockito.Mockito.verify;
2936

3037
/**
3138
* @author Rob Winch
@@ -79,4 +86,15 @@ public void constructorWhenUserPropertiesNoRolesThenException() {
7986
.withMessage("The entry with username 'joe' could not be converted to an UserDetails");
8087
}
8188

89+
@Test
90+
public void changePasswordWhenCustomSecurityContextHolderStrategyThenUses() {
91+
Authentication authentication = TestAuthentication.authenticatedUser();
92+
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager((User) authentication.getPrincipal());
93+
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
94+
given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
95+
manager.setSecurityContextHolderStrategy(strategy);
96+
manager.changePassword("password", "newpassword");
97+
verify(strategy).getContext();
98+
}
99+
82100
}

core/src/test/java/org/springframework/security/provisioning/JdbcUserDetailsManagerTests.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import org.springframework.security.core.authority.AuthorityUtils;
4040
import org.springframework.security.core.authority.SimpleGrantedAuthority;
4141
import org.springframework.security.core.context.SecurityContextHolder;
42+
import org.springframework.security.core.context.SecurityContextHolderStrategy;
43+
import org.springframework.security.core.context.SecurityContextImpl;
4244
import org.springframework.security.core.userdetails.User;
4345
import org.springframework.security.core.userdetails.UserCache;
4446
import org.springframework.security.core.userdetails.UserDetails;
@@ -48,6 +50,7 @@
4850
import static org.mockito.ArgumentMatchers.any;
4951
import static org.mockito.BDDMockito.given;
5052
import static org.mockito.Mockito.mock;
53+
import static org.mockito.Mockito.verify;
5154

5255
/**
5356
* Tests for {@link JdbcUserDetailsManager}
@@ -205,6 +208,18 @@ public void changePasswordSucceedsWithAuthenticatedUserAndNoAuthenticationManage
205208
assertThat(this.cache.getUserMap().containsKey("joe")).isFalse();
206209
}
207210

211+
@Test
212+
public void changePasswordWhenCustomSecurityContextHolderStrategyThenUses() {
213+
insertJoe();
214+
Authentication authentication = authenticateJoe();
215+
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
216+
given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
217+
given(strategy.createEmptyContext()).willReturn(new SecurityContextImpl());
218+
this.manager.setSecurityContextHolderStrategy(strategy);
219+
this.manager.changePassword("wrongpassword", "newPassword");
220+
verify(strategy).getContext();
221+
}
222+
208223
@Test
209224
public void changePasswordSucceedsWithIfReAuthenticationSucceeds() {
210225
insertJoe();

0 commit comments

Comments
 (0)