Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using spring SecurityWebFilterChain how to disable/block all non-https requests except few known paths

I am using Spring security within a Spring Boot Webflux application to serve traffic primarily on HTTPS port. However as an operational requirement I need to support couple of non-secure REST API paths in my Spring Boot application for health check etc that need to be exposed on HTTP as well.

So how do I enforce all the requests to HTTPS except for a known path using SecurityWebFilterChain bean?

This is how I have defined my SecurityWebFilterChain bean:

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {    
    @Bean
    SecurityWebFilterChain webFilterChain( ServerHttpSecurity http )
     throws Exception {
         return http 
            .authorizeExchange(exchanges -> exchanges
                    .anyExchange().permitAll()
                    .and()
                    .exceptionHandling()
                    .authenticationEntryPoint((exchange, exception) ->
                        Mono.error(exception))
                    )
            .csrf().disable()
            .headers().disable()
            .logout().disable()
            .build();
    }
}

This obviously won't work as intended because it is allowing all requests to use HTTP and HTTPS schemes whereas I want to always enforce HTTPS except for a path e.g. /health.

Please suggest what changes would I need in above code to get this done.

like image 439
anubhava Avatar asked Sep 05 '25 03:09

anubhava


1 Answers

Here is what I came up with to to solve this problem. I am calling a custom matcher in .matchers( customMatcher ) method

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    private static final Set<String> UNSECURED = 
                 Set.of ( "/health", "/heartbeat" );

    @Bean
    SecurityWebFilterChain webFilterChain( final ServerHttpSecurity http ) {    
        return http
                .authorizeExchange(
                        exchanges -> exchanges
                        .matchers( this::blockUnsecured ).permitAll()
                        .and()
                        .exceptionHandling()
                        .authenticationEntryPoint(
                               (exchange, exception) -> Mono.error(exception))
                        )
                .csrf().disable()
                .headers().disable()
                .logout().disable()
                .httpBasic().disable()
                .build();
    }

    Mono<MatchResult> blockUnsecured( final ServerWebExchange exchange ) {    
        // Deny all requests except few known ones using "http" scheme
        URI uri = exchange.getRequest().getURI();

        boolean invalid = "http".equalsIgnoreCase( uri.getScheme() ) &&
                !UNSECURED.contains ( uri.getPath().toLowerCase() );    
        return invalid ? MatchResult.notMatch() : MatchResult.match();    
    }
}

Not sure if there is a better way of doing same.

like image 121
anubhava Avatar answered Sep 08 '25 00:09

anubhava