From 02e7f1537bb5b9c218711980a09823ec17c595a6 Mon Sep 17 00:00:00 2001 From: junhyeong9812 Date: Sun, 14 Jun 2026 18:39:24 +0900 Subject: [PATCH] Lowercase username in changePassword lookup InMemoryUserDetailsManager keys its user map on the lower-cased username everywhere except changePassword, which looked the current user up with the raw name. A user whose username contains uppercase letters could therefore not change its password. Lower-case the lookup key to match the rest of the class. Closes gh-19336 Signed-off-by: junhyeong9812 --- .../provisioning/InMemoryUserDetailsManager.java | 2 +- .../InMemoryUserDetailsManagerTests.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/springframework/security/provisioning/InMemoryUserDetailsManager.java b/core/src/main/java/org/springframework/security/provisioning/InMemoryUserDetailsManager.java index 55e65ea1456..cff1cff83dd 100644 --- a/core/src/main/java/org/springframework/security/provisioning/InMemoryUserDetailsManager.java +++ b/core/src/main/java/org/springframework/security/provisioning/InMemoryUserDetailsManager.java @@ -150,7 +150,7 @@ public void changePassword(@Nullable String oldPassword, @Nullable String newPas else { this.logger.debug("No authentication manager set. Password won't be re-checked."); } - MutableUserDetails user = this.users.get(username); + MutableUserDetails user = this.users.get(username.toLowerCase(Locale.ROOT)); Assert.state(user != null, "Current user doesn't exist in database."); user.setPassword(newPassword); } diff --git a/core/src/test/java/org/springframework/security/provisioning/InMemoryUserDetailsManagerTests.java b/core/src/test/java/org/springframework/security/provisioning/InMemoryUserDetailsManagerTests.java index 7d311f4c18f..a861b7c4a01 100644 --- a/core/src/test/java/org/springframework/security/provisioning/InMemoryUserDetailsManagerTests.java +++ b/core/src/test/java/org/springframework/security/provisioning/InMemoryUserDetailsManagerTests.java @@ -123,6 +123,22 @@ public void changePasswordWhenCustomSecurityContextHolderStrategyThenUses() { verify(strategy).getContext(); } + @Test + public void changePasswordWhenCurrentUsernameIsNotInLowercaseThenChangesPassword() { + UserDetails userNotLowerCase = User.withUserDetails(PasswordEncodedUser.user()).username("User").build(); + InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(userNotLowerCase); + Authentication authentication = new UsernamePasswordAuthenticationToken("User", userNotLowerCase.getPassword(), + userNotLowerCase.getAuthorities()); + SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class); + given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication)); + manager.setSecurityContextHolderStrategy(strategy); + + String newPassword = "newPassword"; + manager.changePassword(userNotLowerCase.getPassword(), newPassword); + + assertThat(manager.loadUserByUsername("User").getPassword()).isEqualTo(newPassword); + } + @Test public void createUserWhenUserAlreadyExistsThenException() { assertThatIllegalArgumentException().isThrownBy(() -> this.manager.createUser(this.user))