diff --git a/core/src/main/java/org/springframework/security/core/userdetails/UserDetailsPasswordService.java b/core/src/main/java/org/springframework/security/core/userdetails/UserDetailsPasswordService.java new file mode 100644 index 0000000000..a282db973d --- /dev/null +++ b/core/src/main/java/org/springframework/security/core/userdetails/UserDetailsPasswordService.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.core.userdetails; + +/** + * An API for changing a {@link UserDetails} password. + * @author Rob Winch + * @since 5.1 + */ +public interface UserDetailsPasswordService { + + /** + * Modify the specified user's password. This should change the user's password in the + * persistent user repository (datbase, LDAP etc). + * + * @param user the user to modify the password for + * @param newPassword the password to change to + * @return the updated UserDetails with the new password + */ + UserDetails updatePassword(UserDetails user, String newPassword); +} 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 6592d63b40..55c462cde4 100644 --- a/core/src/main/java/org/springframework/security/provisioning/InMemoryUserDetailsManager.java +++ b/core/src/main/java/org/springframework/security/provisioning/InMemoryUserDetailsManager.java @@ -30,6 +30,7 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsPasswordService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.memory.UserAttribute; import org.springframework.security.core.userdetails.memory.UserAttributeEditor; @@ -45,7 +46,8 @@ import org.springframework.util.Assert; * @author Luke Taylor * @since 3.1 */ -public class InMemoryUserDetailsManager implements UserDetailsManager { +public class InMemoryUserDetailsManager implements UserDetailsManager, + UserDetailsPasswordService { protected final Log logger = LogFactory.getLog(getClass()); private final Map users = new HashMap<>(); @@ -138,6 +140,14 @@ public class InMemoryUserDetailsManager implements UserDetailsManager { user.setPassword(newPassword); } + @Override + public UserDetails updatePassword(UserDetails user, String newPassword) { + String username = user.getUsername(); + MutableUserDetails mutableUser = this.users.get(username); + mutableUser.setPassword(newPassword); + return mutableUser; + } + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserDetails user = users.get(username.toLowerCase()); diff --git a/core/src/test/java/org/springframework/security/provisioning/InMemoryUserDetailsManagerTests.java b/core/src/test/java/org/springframework/security/provisioning/InMemoryUserDetailsManagerTests.java new file mode 100644 index 0000000000..9f58cc5385 --- /dev/null +++ b/core/src/test/java/org/springframework/security/provisioning/InMemoryUserDetailsManagerTests.java @@ -0,0 +1,40 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.provisioning; + +import org.junit.Test; +import org.springframework.security.core.userdetails.PasswordEncodedUser; +import org.springframework.security.core.userdetails.UserDetails; + +import static org.assertj.core.api.Assertions.*; + +/** + * @author Rob Winch + * @since 5.1 + */ +public class InMemoryUserDetailsManagerTests { + private final UserDetails user = PasswordEncodedUser.user(); + + private InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(this.user); + + @Test + public void changePassword() { + String newPassword = "newPassword"; + this.manager.updatePassword(this.user, newPassword); + assertThat(this.manager.loadUserByUsername(this.user.getUsername()).getPassword()).isEqualTo(newPassword); + } +}