Skip to content

Improve documentation of WebFlux Username/Password login, WebSession persistence. #16926

Closed
@BLCK-B

Description

@BLCK-B

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions