Implement UserDetailsPasswordService in JdbcUserDetailsManager

Signed-off-by: Junhyeok Lee <jhl221123@naver.com>
This commit is contained in:
Junhyeok Lee 2025-05-08 01:41:22 +09:00 committed by Rob Winch
parent 817938fa49
commit 0722c2dc41
2 changed files with 46 additions and 1 deletions

View File

@ -46,6 +46,7 @@ import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
import org.springframework.security.core.userdetails.cache.NullUserCache;
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;
import org.springframework.util.Assert;
@ -65,7 +66,8 @@ import org.springframework.util.Assert;
* @author Luke Taylor
* @since 2.0
*/
public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsManager, GroupManager {
public class JdbcUserDetailsManager extends JdbcDaoImpl
implements UserDetailsManager, GroupManager, UserDetailsPasswordService {
public static final String DEF_CREATE_USER_SQL = "insert into users (username, password, enabled) values (?,?,?)";
@ -162,6 +164,8 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
private RowMapper<GrantedAuthority> grantedAuthorityMapper = this::mapToGrantedAuthority;
private boolean enableUpdatePassword = false;
public JdbcUserDetailsManager() {
}
@ -591,6 +595,20 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
this.userCache = userCache;
}
/**
* Sets whether the {@link #updatePassword(UserDetails, String)} method should
* actually update the password.
* <p>
* Defaults to {@code false} to prevent accidental password updates that might produce
* passwords that are too large for the current database schema. Users must explicitly
* set this to {@code true} to enable password updates.
* @param enableUpdatePassword {@code true} to enable password updates, {@code false}
* otherwise.
*/
public void setEnableUpdatePassword(boolean enableUpdatePassword) {
this.enableUpdatePassword = enableUpdatePassword;
}
private void validateUserDetails(UserDetails user) {
Assert.hasText(user.getUsername(), "Username may not be empty or null");
validateAuthorities(user.getAuthorities());
@ -604,4 +622,14 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
}
}
@Override
public UserDetails updatePassword(UserDetails user, String newPassword) {
if (this.enableUpdatePassword) {
UserDetails updated = User.withUserDetails(user).password(newPassword).build();
updateUser(updated);
return updated;
}
return user;
}
}

View File

@ -410,6 +410,23 @@ public class JdbcUserDetailsManagerTests {
verify(mockMapper).mapRow(any(), anyInt());
}
@Test
void updatePasswordWhenDisabledReturnOriginalUser() {
insertJoe();
this.manager.updatePassword(joe, "new");
UserDetails newJoe = this.manager.loadUserByUsername("joe");
assertThat(newJoe.getPassword()).isEqualTo("password");
}
@Test
void updatePasswordWhenEnabledShouldUpdatePassword() {
insertJoe();
this.manager.setEnableUpdatePassword(true);
this.manager.updatePassword(joe, "new");
UserDetails newJoe = this.manager.loadUserByUsername("joe");
assertThat(newJoe.getPassword()).isEqualTo("new");
}
private Authentication authenticateJoe() {
UsernamePasswordAuthenticationToken auth = UsernamePasswordAuthenticationToken.authenticated("joe", "password",
joe.getAuthorities());