diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java index 8e06990092..2596373e5f 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java @@ -28,6 +28,7 @@ import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.security.authentication.ReactiveAuthenticationManager; import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager; import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService; import org.springframework.security.core.userdetails.ReactiveUserDetailsService; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.reactive.result.method.annotation.AuthenticationPrincipalArgumentResolver; @@ -54,6 +55,9 @@ class ServerHttpSecurityConfiguration implements WebFluxConfigurer { @Autowired(required = false) private PasswordEncoder passwordEncoder; + @Autowired(required = false) + private ReactiveUserDetailsPasswordService userDetailsPasswordService; + @Autowired(required = false) private BeanFactory beanFactory; @@ -92,6 +96,7 @@ class ServerHttpSecurityConfiguration implements WebFluxConfigurer { if(this.passwordEncoder != null) { manager.setPasswordEncoder(this.passwordEncoder); } + manager.setUserDetailsPasswordService(this.userDetailsPasswordService); return manager; } return null; diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java index 60ce3aaffc..7d6ee06919 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java @@ -237,6 +237,34 @@ public class EnableWebFluxSecurityTests { } } + @Test + public void passwordUpdateManagerUsed() { + this.spring.register(MapReactiveUserDetailsServiceConfig.class).autowire(); + WebTestClient client = WebTestClientBuilder.bindToWebFilters(this.springSecurityFilterChain).build(); + + client + .get() + .uri("/") + .headers(h -> h.setBasicAuth("user", "password")) + .exchange() + .expectStatus().isOk(); + + ReactiveUserDetailsService users = this.spring.getContext().getBean(ReactiveUserDetailsService.class); + assertThat(users.findByUsername("user").block().getPassword()).startsWith("{bcrypt}"); + } + + @EnableWebFluxSecurity + static class MapReactiveUserDetailsServiceConfig { + @Bean + public MapReactiveUserDetailsService userDetailsService() { + return new MapReactiveUserDetailsService(User.withUsername("user") + .password("{noop}password") + .roles("USER") + .build() + ); + } + } + @Test public void formLoginWorks() { this.spring.register(Config.class).autowire(); diff --git a/core/src/main/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManager.java b/core/src/main/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManager.java index 7e67677eb4..0a79e6b244 100644 --- a/core/src/main/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManager.java +++ b/core/src/main/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManager.java @@ -20,7 +20,6 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService; import org.springframework.security.core.userdetails.ReactiveUserDetailsService; -import org.springframework.security.core.userdetails.User; import org.springframework.security.crypto.factory.PasswordEncoderFactories; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.util.Assert; diff --git a/core/src/test/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManagerTests.java b/core/src/test/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManagerTests.java index 4de034dcb5..2037bfef6e 100644 --- a/core/src/test/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManagerTests.java +++ b/core/src/test/java/org/springframework/security/authentication/UserDetailsRepositoryReactiveAuthenticationManagerTests.java @@ -115,7 +115,6 @@ public class UserDetailsRepositoryReactiveAuthenticationManagerTests { public void authenticateWhenPasswordServiceAndBadCredentialsThenNotUpdated() { when(this.userDetailsService.findByUsername(any())).thenReturn(Mono.just(this.user)); when(this.encoder.matches(any(), any())).thenReturn(false); - when(this.userDetailsPasswordService.updatePassword(any(), any())).thenReturn(Mono.just(this.user)); this.manager.setPasswordEncoder(this.encoder); this.manager.setUserDetailsPasswordService(this.userDetailsPasswordService); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( @@ -132,7 +131,6 @@ public class UserDetailsRepositoryReactiveAuthenticationManagerTests { when(this.userDetailsService.findByUsername(any())).thenReturn(Mono.just(this.user)); when(this.encoder.matches(any(), any())).thenReturn(true); when(this.encoder.upgradeEncoding(any())).thenReturn(false); - when(this.userDetailsPasswordService.updatePassword(any(), any())).thenReturn(Mono.just(this.user)); this.manager.setPasswordEncoder(this.encoder); this.manager.setUserDetailsPasswordService(this.userDetailsPasswordService); UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(