Closed
Description
Expected Behavior
I have read through the docs and reference and found that more information could be provided about WebFlux Username/Password login. Given the issue described below, I am unsure whether the SecurityContext
, WebSession
need to be explicitly persisted, if I have to use browser cookies/tokens or if the issue lies with my configuration.
Current Behavior
On login the Security context is saved in a WebSession. On following requests to protected endpoints, the session lookup fails. How is the session associated with the browser?
Example test and output:
webTestClient
.mutateWith(csrf())
.post()
.uri("/auth/login")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(credentials)
.exchange()
.expectStatus().isOk();
webTestClient
.mutateWith(csrf())
.get()
.uri("/users/userAccountInfo")
.exchange()
.expectStatus().isOk()
WebSessionServerSecurityContextRepository : Saved SecurityContext 'SecurityContextImpl [...], Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[USER]]]' in WebSession : 'org.springframework.web.server.session.InMemoryWebSessionStore$InMemoryWebSession@472c317e'
a.DelegatingReactiveAuthorizationManager : Checking authorization on '/users/userAccountInfo' using org.springframework.security.authorization.AuthenticatedReactiveAuthorizationManager@555fdfaf
WebSessionServerSecurityContextRepository : No SecurityContext found in WebSession: 'org.springframework.web.server.session.InMemoryWebSessionStore$InMemoryWebSession@e35c0ee'
Context
WebSessionServerSecurityContextRepository
Username/password authentication and security config:
public Mono<Void> loginUser(ServerWebExchange exchange,
Authentication authRequest,
ReactiveAuthenticationManager reactiveAuthenticationManager) {
return reactiveAuthenticationManager.authenticate(authRequest)
.flatMap(authResponse -> {
SecurityContext securityContext = new SecurityContextImpl(authResponse);
return securityContextRepository.save(exchange, securityContext);
})
.onErrorResume(e -> Mono.error(new InvalidCredentialsException("Invalid credentials: " + e)));
}
@Configuration
@EnableWebFluxSecurity
public class SecurityConfiguration {
@Bean
public SecurityWebFilterChain apiFilterChain(ServerHttpSecurity http) {
http
.csrf(csrf -> csrf.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()))
.securityContextRepository(new WebSessionServerSecurityContextRepository())
.authorizeExchange(exchanges -> exchanges
.pathMatchers("/auth/**").permitAll()
.anyExchange().authenticated()
);
return http.build();
}
@Bean
public WebSessionServerSecurityContextRepository securityContextRepository() {
return new WebSessionServerSecurityContextRepository();
}
@Bean
public ReactiveUserDetailsService userDetailsService(AccountService accountService) {
return accountService;
}
@Bean
public ReactiveAuthenticationManager reactiveAuthenticationManager(ReactiveUserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
UserDetailsRepositoryReactiveAuthenticationManager authenticationManager = new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService);
authenticationManager.setPasswordEncoder(passwordEncoder);
return authenticationManager;
}
I have already tried asking on StackOverflow.