InMemoryUserDetailsManager preserve user type
Closes gh-3192
This commit is contained in:
parent
503d653cea
commit
6d657ea3da
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2022 the original author or authors.
|
* Copyright 2002-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -30,6 +30,7 @@ import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.CredentialsContainer;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.core.userdetails.User;
|
import org.springframework.security.core.userdetails.User;
|
||||||
|
@ -96,7 +97,13 @@ public class InMemoryUserDetailsManager implements UserDetailsManager, UserDetai
|
||||||
@Override
|
@Override
|
||||||
public void createUser(UserDetails user) {
|
public void createUser(UserDetails user) {
|
||||||
Assert.isTrue(!userExists(user.getUsername()), "user should not exist");
|
Assert.isTrue(!userExists(user.getUsername()), "user should not exist");
|
||||||
this.users.put(user.getUsername().toLowerCase(), new MutableUser(user));
|
|
||||||
|
if (user instanceof MutableUserDetails mutable) {
|
||||||
|
this.users.put(user.getUsername().toLowerCase(), mutable);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.users.put(user.getUsername().toLowerCase(), new MutableUser(user));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -107,7 +114,13 @@ public class InMemoryUserDetailsManager implements UserDetailsManager, UserDetai
|
||||||
@Override
|
@Override
|
||||||
public void updateUser(UserDetails user) {
|
public void updateUser(UserDetails user) {
|
||||||
Assert.isTrue(userExists(user.getUsername()), "user should exist");
|
Assert.isTrue(userExists(user.getUsername()), "user should exist");
|
||||||
this.users.put(user.getUsername().toLowerCase(), new MutableUser(user));
|
|
||||||
|
if (user instanceof MutableUserDetails mutable) {
|
||||||
|
this.users.put(user.getUsername().toLowerCase(), mutable);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.users.put(user.getUsername().toLowerCase(), new MutableUser(user));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -154,6 +167,9 @@ public class InMemoryUserDetailsManager implements UserDetailsManager, UserDetai
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw new UsernameNotFoundException(username);
|
throw new UsernameNotFoundException(username);
|
||||||
}
|
}
|
||||||
|
if (user instanceof CredentialsContainer) {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
return new User(user.getUsername(), user.getPassword(), user.isEnabled(), user.isAccountNonExpired(),
|
return new User(user.getUsername(), user.getPassword(), user.isEnabled(), user.isAccountNonExpired(),
|
||||||
user.isCredentialsNonExpired(), user.isAccountNonLocked(), user.getAuthorities());
|
user.isCredentialsNonExpired(), user.isAccountNonLocked(), user.getAuthorities());
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,15 @@
|
||||||
|
|
||||||
package org.springframework.security.provisioning;
|
package org.springframework.security.provisioning;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.security.authentication.TestAuthentication;
|
import org.springframework.security.authentication.TestAuthentication;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.CredentialsContainer;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.core.context.SecurityContextImpl;
|
import org.springframework.security.core.context.SecurityContextImpl;
|
||||||
import org.springframework.security.core.userdetails.PasswordEncodedUser;
|
import org.springframework.security.core.userdetails.PasswordEncodedUser;
|
||||||
|
@ -105,6 +108,20 @@ public class InMemoryUserDetailsManagerTests {
|
||||||
.withMessage("user should not exist");
|
.withMessage("user should not exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createUserWhenInstanceOfMutableUserDetailsThenChangePasswordWorks() {
|
||||||
|
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||||
|
CustomUser user = new CustomUser(User.withUserDetails(PasswordEncodedUser.user()).build());
|
||||||
|
Authentication authentication = TestAuthentication.authenticated(user);
|
||||||
|
SecurityContextHolderStrategy strategy = mock(SecurityContextHolderStrategy.class);
|
||||||
|
given(strategy.getContext()).willReturn(new SecurityContextImpl(authentication));
|
||||||
|
manager.setSecurityContextHolderStrategy(strategy);
|
||||||
|
manager.createUser(user);
|
||||||
|
String newPassword = "newPassword";
|
||||||
|
manager.changePassword(user.getPassword(), newPassword);
|
||||||
|
assertThat(manager.loadUserByUsername(user.getUsername()).getPassword()).isEqualTo(newPassword);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateUserWhenUserDoesNotExistThenException() {
|
public void updateUserWhenUserDoesNotExistThenException() {
|
||||||
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
|
||||||
|
@ -119,4 +136,57 @@ public class InMemoryUserDetailsManagerTests {
|
||||||
.isThrownBy(() -> manager.loadUserByUsername(this.user.getUsername()));
|
.isThrownBy(() -> manager.loadUserByUsername(this.user.getUsername()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadUserByUsernameWhenNotInstanceOfCredentialsContainerThenReturnInstanceOfCredentialsContainer() {
|
||||||
|
MutableUser user = new MutableUser(User.withUserDetails(PasswordEncodedUser.user()).build());
|
||||||
|
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(user);
|
||||||
|
assertThat(user).isNotInstanceOf(CredentialsContainer.class);
|
||||||
|
assertThat(manager.loadUserByUsername(user.getUsername())).isInstanceOf(CredentialsContainer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadUserByUsernameWhenInstanceOfCredentialsContainerThenReturnInstance() {
|
||||||
|
CustomUser user = new CustomUser(User.withUserDetails(PasswordEncodedUser.user()).build());
|
||||||
|
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(user);
|
||||||
|
assertThat(manager.loadUserByUsername(user.getUsername())).isSameAs(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CustomUser implements MutableUserDetails, CredentialsContainer {
|
||||||
|
|
||||||
|
private final UserDetails delegate;
|
||||||
|
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
CustomUser(UserDetails user) {
|
||||||
|
this.delegate = user;
|
||||||
|
this.password = user.getPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
|
return this.delegate.getAuthorities();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPassword() {
|
||||||
|
return this.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPassword(final String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsername() {
|
||||||
|
return this.delegate.getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void eraseCredentials() {
|
||||||
|
this.password = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue