UserDetailsRepository->ReactiveUserDetailsService

Issue gh-4615
This commit is contained in:
Rob Winch 2017-10-10 09:46:15 -05:00
parent f1bc82dcef
commit 4681697581
16 changed files with 74 additions and 87 deletions

View File

@ -23,7 +23,7 @@ import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UserDetailsRepositoryAuthenticationManager;
import org.springframework.security.config.web.server.HttpSecurity;
import org.springframework.security.core.userdetails.UserDetailsRepository;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.reactive.result.method.annotation.AuthenticationPrincipalArgumentResolver;
import org.springframework.web.reactive.config.WebFluxConfigurer;
@ -46,7 +46,7 @@ public class HttpSecurityConfiguration implements WebFluxConfigurer {
private ReactiveAuthenticationManager authenticationManager;
@Autowired(required = false)
private UserDetailsRepository userDetailsRepository;
private ReactiveUserDetailsService reactiveUserDetailsService;
@Autowired(required = false)
private PasswordEncoder passwordEncoder;
@ -76,9 +76,9 @@ public class HttpSecurityConfiguration implements WebFluxConfigurer {
if(this.authenticationManager != null) {
return this.authenticationManager;
}
if(this.userDetailsRepository != null) {
if(this.reactiveUserDetailsService != null) {
UserDetailsRepositoryAuthenticationManager manager =
new UserDetailsRepositoryAuthenticationManager(this.userDetailsRepository);
new UserDetailsRepositoryAuthenticationManager(this.reactiveUserDetailsService);
if(this.passwordEncoder != null) {
manager.setPasswordEncoder(this.passwordEncoder);
}

View File

@ -20,31 +20,32 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.security.core.userdetails.MapUserDetailsRepository;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.util.InMemoryResource;
import java.util.Collection;
/**
* Constructs an {@link MapUserDetailsRepository} from a resource using {@link UserDetailsResourceFactoryBean}.
* Constructs an {@link MapReactiveUserDetailsService} from a resource using {@link UserDetailsResourceFactoryBean}.
*
* @author Rob Winch
* @since 5.0
* @see UserDetailsResourceFactoryBean
*/
public class UserDetailsRepositoryResourceFactoryBean implements ResourceLoaderAware, FactoryBean<MapUserDetailsRepository> {
public class ReactiveUserDetailsServiceResourceFactoryBean
implements ResourceLoaderAware, FactoryBean<MapReactiveUserDetailsService> {
private UserDetailsResourceFactoryBean userDetails = new UserDetailsResourceFactoryBean();
@Override
public MapUserDetailsRepository getObject() throws Exception {
public MapReactiveUserDetailsService getObject() throws Exception {
Collection<UserDetails> users = userDetails.getObject();
return new MapUserDetailsRepository(users);
return new MapReactiveUserDetailsService(users);
}
@Override
public Class<?> getObjectType() {
return MapUserDetailsRepository.class;
return MapReactiveUserDetailsService.class;
}
@Override
@ -78,8 +79,8 @@ public class UserDetailsRepositoryResourceFactoryBean implements ResourceLoaderA
* @param resourceLocatiton the location of the properties file that contains the users (i.e. "classpath:users.properties")
* @return the UserDetailsResourceFactoryBean
*/
public static UserDetailsRepositoryResourceFactoryBean fromResourceLocation(String resourceLocatiton) {
UserDetailsRepositoryResourceFactoryBean result = new UserDetailsRepositoryResourceFactoryBean();
public static ReactiveUserDetailsServiceResourceFactoryBean fromResourceLocation(String resourceLocatiton) {
ReactiveUserDetailsServiceResourceFactoryBean result = new ReactiveUserDetailsServiceResourceFactoryBean();
result.setResourceLocation(resourceLocatiton);
return result;
}
@ -91,8 +92,8 @@ public class UserDetailsRepositoryResourceFactoryBean implements ResourceLoaderA
* @param propertiesResource the Resource that is a properties file that contains the users
* @return the UserDetailsResourceFactoryBean
*/
public static UserDetailsRepositoryResourceFactoryBean fromResource(Resource propertiesResource) {
UserDetailsRepositoryResourceFactoryBean result = new UserDetailsRepositoryResourceFactoryBean();
public static ReactiveUserDetailsServiceResourceFactoryBean fromResource(Resource propertiesResource) {
ReactiveUserDetailsServiceResourceFactoryBean result = new ReactiveUserDetailsServiceResourceFactoryBean();
result.setResource(propertiesResource);
return result;
}
@ -104,8 +105,8 @@ public class UserDetailsRepositoryResourceFactoryBean implements ResourceLoaderA
* @param users the users in the format defined in {@link UserDetailsResourceFactoryBean}
* @return the UserDetailsResourceFactoryBean
*/
public static UserDetailsRepositoryResourceFactoryBean fromString(String users) {
UserDetailsRepositoryResourceFactoryBean result = new UserDetailsRepositoryResourceFactoryBean();
public static ReactiveUserDetailsServiceResourceFactoryBean fromString(String users) {
ReactiveUserDetailsServiceResourceFactoryBean result = new ReactiveUserDetailsServiceResourceFactoryBean();
result.setResource(new InMemoryResource(users));
return result;
}

View File

@ -28,9 +28,9 @@ import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.config.web.server.HttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.MapUserDetailsRepository;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsRepository;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
@ -138,8 +138,8 @@ public class EnableWebFluxSecurityTests {
@EnableWebFluxSecurity
static class Config {
@Bean
public UserDetailsRepository userDetailsRepository() {
return new MapUserDetailsRepository(User.withUsername("user")
public ReactiveUserDetailsService userDetailsRepository() {
return new MapReactiveUserDetailsService(User.withUsername("user")
.password("password")
.roles("USER")
.build()
@ -178,8 +178,8 @@ public class EnableWebFluxSecurityTests {
@EnableWebFluxSecurity
static class Config {
@Bean
public UserDetailsRepository userDetailsRepository(PasswordEncoder encoder) {
return new MapUserDetailsRepository(User.withUsername("user")
public ReactiveUserDetailsService userDetailsRepository(PasswordEncoder encoder) {
return new MapReactiveUserDetailsService(User.withUsername("user")
.password(encoder.encode("password"))
.roles("USER")
.build()
@ -226,8 +226,8 @@ public class EnableWebFluxSecurityTests {
@EnableWebFluxSecurity
static class Config {
@Bean
public UserDetailsRepository userDetailsRepository() {
return new MapUserDetailsRepository(User.withUsername("user")
public ReactiveUserDetailsService userDetailsRepository() {
return new MapReactiveUserDetailsService(User.withUsername("user")
.password("password")
.roles("USER")
.build()
@ -275,8 +275,8 @@ public class EnableWebFluxSecurityTests {
}
@Bean
public UserDetailsRepository userDetailsRepository() {
return new MapUserDetailsRepository(User.withUsername("user")
public ReactiveUserDetailsService userDetailsRepository() {
return new MapReactiveUserDetailsService(User.withUsername("user")
.password("password")
.roles("USER")
.build()

View File

@ -22,7 +22,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.UserDetailsRepository;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.util.InMemoryResource;
import org.springframework.test.context.junit4.SpringRunner;
@ -33,9 +33,8 @@ import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
* @since 5.0
*/
@RunWith(SpringRunner.class)
public class UserDetailsRepositoryResourceFactoryBeanPropertiesResourceITests {
@Autowired
UserDetailsRepository users;
public class ReactiveUserDetailsServiceResourceFactoryBeanPropertiesResourceITests {
@Autowired ReactiveUserDetailsService users;
@Test
public void loadUserByUsernameWhenUserFoundThenNotNull() {
@ -45,8 +44,8 @@ public class UserDetailsRepositoryResourceFactoryBeanPropertiesResourceITests {
@Configuration
static class Config {
@Bean
public UserDetailsRepositoryResourceFactoryBean userDetailsService() {
return UserDetailsRepositoryResourceFactoryBean.fromResource(new InMemoryResource("user=password,ROLE_USER"));
public ReactiveUserDetailsServiceResourceFactoryBean userDetailsService() {
return ReactiveUserDetailsServiceResourceFactoryBean.fromResource(new InMemoryResource("user=password,ROLE_USER"));
}
}
}

View File

@ -22,8 +22,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.UserDetailsRepository;
import org.springframework.security.util.InMemoryResource;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
@ -33,9 +32,8 @@ import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
* @since 5.0
*/
@RunWith(SpringRunner.class)
public class UserDetailsRepositoryResourceFactoryBeanStringITests {
@Autowired
UserDetailsRepository users;
public class ReactiveUserDetailsServiceResourceFactoryBeanPropertiesResourceLocationITests {
@Autowired ReactiveUserDetailsService users;
@Test
public void loadUserByUsernameWhenUserFoundThenNotNull() {
@ -45,8 +43,8 @@ public class UserDetailsRepositoryResourceFactoryBeanStringITests {
@Configuration
static class Config {
@Bean
public UserDetailsRepositoryResourceFactoryBean userDetailsService() {
return UserDetailsRepositoryResourceFactoryBean.fromString("user=password,ROLE_USER");
public ReactiveUserDetailsServiceResourceFactoryBean userDetailsService() {
return ReactiveUserDetailsServiceResourceFactoryBean.fromResourceLocation("classpath:users.properties");
}
}
}

View File

@ -22,7 +22,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.UserDetailsRepository;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
@ -32,9 +32,8 @@ import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
* @since 5.0
*/
@RunWith(SpringRunner.class)
public class UserDetailsRepositoryResourceFactoryBeanPropertiesResourceLocationITests {
@Autowired
UserDetailsRepository users;
public class ReactiveUserDetailsServiceResourceFactoryBeanStringITests {
@Autowired ReactiveUserDetailsService users;
@Test
public void loadUserByUsernameWhenUserFoundThenNotNull() {
@ -44,8 +43,8 @@ public class UserDetailsRepositoryResourceFactoryBeanPropertiesResourceLocationI
@Configuration
static class Config {
@Bean
public UserDetailsRepositoryResourceFactoryBean userDetailsService() {
return UserDetailsRepositoryResourceFactoryBean.fromResourceLocation("classpath:users.properties");
public ReactiveUserDetailsServiceResourceFactoryBean userDetailsService() {
return ReactiveUserDetailsServiceResourceFactoryBean.fromString("user=password,ROLE_USER");
}
}
}

View File

@ -23,7 +23,7 @@ import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UserDetailsRepositoryAuthenticationManager;
import org.springframework.security.core.userdetails.MapUserDetailsRepository;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.htmlunit.server.WebTestClientHtmlUnitDriverBuilder;
@ -45,7 +45,7 @@ public class FormLoginTests {
private UserDetails user = User.withUsername("user").password("password").roles("USER").build();
private HttpSecurity http = HttpSecurity.http();
ReactiveAuthenticationManager manager = new UserDetailsRepositoryAuthenticationManager(new MapUserDetailsRepository(this.user));
ReactiveAuthenticationManager manager = new UserDetailsRepositoryAuthenticationManager(new MapReactiveUserDetailsService(this.user));
@Test
public void defaultLoginPage() {

View File

@ -20,7 +20,7 @@ import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UserDetailsRepositoryAuthenticationManager;
import org.springframework.security.core.userdetails.MapUserDetailsRepository;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.htmlunit.server.WebTestClientHtmlUnitDriverBuilder;
@ -37,7 +37,7 @@ public class LogoutBuilderTests {
private UserDetails user = User.withUsername("user").password("password").roles("USER").build();
private HttpSecurity http = HttpSecurity.http();
ReactiveAuthenticationManager manager = new UserDetailsRepositoryAuthenticationManager(new MapUserDetailsRepository(this.user));
ReactiveAuthenticationManager manager = new UserDetailsRepositoryAuthenticationManager(new MapReactiveUserDetailsService(this.user));
@Test
public void defaultLogout() {

View File

@ -16,11 +16,9 @@
package org.springframework.security.authentication;
import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsRepository;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.Assert;
@ -32,13 +30,13 @@ import reactor.core.scheduler.Schedulers;
* @since 5.0
*/
public class UserDetailsRepositoryAuthenticationManager implements ReactiveAuthenticationManager {
private final UserDetailsRepository repository;
private final ReactiveUserDetailsService repository;
private PasswordEncoder passwordEncoder = NoOpPasswordEncoder.getInstance();
public UserDetailsRepositoryAuthenticationManager(UserDetailsRepository userDetailsRepository) {
Assert.notNull(userDetailsRepository, "userDetailsRepository cannot be null");
this.repository = userDetailsRepository;
public UserDetailsRepositoryAuthenticationManager(ReactiveUserDetailsService reactiveUserDetailsService) {
Assert.notNull(reactiveUserDetailsService, "userDetailsRepository cannot be null");
this.repository = reactiveUserDetailsService;
}
@Override

View File

@ -30,20 +30,20 @@ import reactor.core.publisher.Mono;
* @author Rob Winch
* @since 5.0
*/
public class MapUserDetailsRepository implements UserDetailsRepository {
public class MapReactiveUserDetailsService implements ReactiveUserDetailsService {
private final Map<String,UserDetails> users;
public MapUserDetailsRepository(Map<String,UserDetails> users) {
public MapReactiveUserDetailsService(Map<String,UserDetails> users) {
this.users = users;
}
public MapUserDetailsRepository(UserDetails... users) {
public MapReactiveUserDetailsService(UserDetails... users) {
this(Arrays.asList(users));
}
public MapUserDetailsRepository(Collection<UserDetails> users) {
public MapReactiveUserDetailsService(Collection<UserDetails> users) {
Assert.notEmpty(users, "users cannot be null or empty");
this.users = users.stream().collect(Collectors.toMap( u -> getKey(u.getName()), Function.identity()));
this.users = users.stream().collect(Collectors.toConcurrentMap( u -> getKey(u.getName()), Function.identity()));
}
@Override

View File

@ -20,7 +20,7 @@ import org.springframework.security.core.userdetails.UserDetails;
import reactor.core.publisher.Mono;
public interface UserDetailsRepository {
public interface ReactiveUserDetailsService {
Mono<UserDetails> findByUsername(String username);
}

View File

@ -28,7 +28,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsRepository;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@ -38,9 +38,8 @@ import reactor.test.StepVerifier;
* @since 5.0
*/
@RunWith(MockitoJUnitRunner.class)
public class UserDetailsRepositoryAuthenticationManagerTests {
@Mock
UserDetailsRepository repository;
public class ReactiveUserDetailsServiceAuthenticationManagerTests {
@Mock ReactiveUserDetailsService repository;
@Mock
PasswordEncoder passwordEncoder;
UserDetailsRepositoryAuthenticationManager manager;
@ -56,7 +55,7 @@ public class UserDetailsRepositoryAuthenticationManagerTests {
@Test(expected = IllegalArgumentException.class)
public void constructorNullUserDetailsRepository() {
UserDetailsRepository udr = null;
ReactiveUserDetailsService udr = null;
new UserDetailsRepositoryAuthenticationManager(udr);
}

View File

@ -23,30 +23,27 @@ import java.util.Collection;
import java.util.Collections;
import org.junit.Test;
import org.springframework.security.core.userdetails.MapUserDetailsRepository;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import reactor.core.publisher.Mono;
public class MapUserDetailsRepositoryTests {
public class MapReactiveUserDetailsServiceTests {
private static final UserDetails USER_DETAILS = User.withUsername("user")
.password("password")
.roles("USER")
.build();
private MapUserDetailsRepository users = new MapUserDetailsRepository(Arrays.asList(USER_DETAILS));
private MapReactiveUserDetailsService users = new MapReactiveUserDetailsService(Arrays.asList(USER_DETAILS));
@Test(expected = IllegalArgumentException.class)
public void constructorNullUsers() {
Collection<UserDetails> users = null;
new MapUserDetailsRepository(users);
new MapReactiveUserDetailsService(users);
}
@Test(expected = IllegalArgumentException.class)
public void constructorEmptyUsers() {
Collection<UserDetails> users = Collections.emptyList();
new MapUserDetailsRepository(users);
new MapReactiveUserDetailsService(users);
}
@Test

View File

@ -18,16 +18,12 @@ package sample;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
import org.springframework.security.core.userdetails.MapUserDetailsRepository;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.HttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import reactor.core.publisher.Mono;
/**
* @author Rob Winch
@ -48,10 +44,10 @@ public class SecurityConfig {
}
@Bean
public MapUserDetailsRepository userDetailsRepository() {
public MapReactiveUserDetailsService userDetailsRepository() {
UserDetails rob = User.withUsername("rob").password("rob").roles("USER").build();
UserDetails admin = User.withUsername("admin").password("admin").roles("USER","ADMIN").build();
return new MapUserDetailsRepository(rob, admin);
return new MapReactiveUserDetailsService(rob, admin);
}
}

View File

@ -18,7 +18,7 @@ package sample;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.core.userdetails.MapUserDetailsRepository;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
@ -30,11 +30,11 @@ import org.springframework.security.core.userdetails.UserDetails;
public class HelloWebfluxSecurityConfig {
@Bean
public MapUserDetailsRepository userDetailsRepository() {
public MapReactiveUserDetailsService userDetailsRepository() {
UserDetails user = User.withUsername("user")
.password("user")
.roles("USER")
.build();
return new MapUserDetailsRepository(user);
return new MapReactiveUserDetailsService(user);
}
}

View File

@ -18,7 +18,7 @@ package sample;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.core.userdetails.MapUserDetailsRepository;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
@ -30,11 +30,11 @@ import org.springframework.security.core.userdetails.UserDetails;
public class HelloWebfluxFnSecurityConfig {
@Bean
public MapUserDetailsRepository userDetailsRepository() {
public MapReactiveUserDetailsService userDetailsRepository() {
UserDetails user = User.withUsername("user")
.password("user")
.roles("USER")
.build();
return new MapUserDetailsRepository(user);
return new MapReactiveUserDetailsService(user);
}
}