Spring Security: Only show login form when url parameter is present

40 Views Asked by At

I am using Spring Cloud Gateway (2023.0.0) and Spring Boot (3.2.3) with oauth2Login and formLogin.

Currently when the application is opened i am redirected to the login page. On the login page i can choose between the form or select the OAuth provider (as expected).

I want to skip the login page by default and directly redirect to the OAuth provider. Only when the user uses a defined url parameter (e.g. ?local=true) in the inital request i want to show the login page with the form.

@Bean
public SecurityWebFilterChain springSecurityFilterChain(final ServerHttpSecurity http) {

    http
        ...
        .oauth2Login(withDefaults())
        .formLogin(withDefaults())
        ...;


    return http.build();
}

@Bean
MapReactiveUserDetailsService userDetailsService() {
    UserDetails userDetails = User
        .withUsername("admin")
        .password("{noop}admin")
        .roles("admin")
        .build();
    return new MapReactiveUserDetailsService(List.of(userDetails));
}

I already tried to implement a custom ServerAuthenticationEntryPoint:

@Bean
public SecurityWebFilterChain springSecurityFilterChain(final ServerHttpSecurity http) {
    http
        ...
        .oauth2Login(withDefaults())
        .formLogin(withDefaults())
        .exceptionHandling(c -> c.authenticationEntryPoint(customAuthenticationEntryPoint()))
        ...;

    return http.build();
}
public class ConditionalAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {
    private final RedirectServerAuthenticationEntryPoint oauth2EntryPoint;
    private final RedirectServerAuthenticationEntryPoint loginFormEntryPoint;

    public ConditionalAuthenticationEntryPoint() {
        this.oauth2EntryPoint = new RedirectServerAuthenticationEntryPoint("/oauth2/authorization/oauth-client");
        this.loginFormEntryPoint = new RedirectServerAuthenticationEntryPoint("/login");
    }

    @Override
    public Mono<Void> commence(final ServerWebExchange exchange, final AuthenticationException ex) {
        return exchange
            .getSession()
            .map(session -> {
                if (session.getAttribute("local") != null) {
                    return true;
                }
                var local = exchange.getRequest().getQueryParams().containsKey("local");
                if (local) {
                    session.getAttributes().putIfAbsent("local", true);
                }
                return local;
            })
            .flatMap(local -> {
                if (local) {
                    return loginFormEntryPoint.commence(exchange, ex);
                } else {
                    return oauth2EntryPoint.commence(exchange, ex);
                }
            });
    }
}

But this leads to endless redirects. Is this the correct approach?

0

There are 0 best solutions below