Search code examples
spring-bootspring-security

Spring Boot 3 Security Filters


With Spring Boot 3 and Security 6, I have the following Security filters

@Bean
@Order(1)
public SecurityFilterChain showLoginFormFilter(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(auth -> {
        // Main page
        auth.requestMatchers("/").permitAll();
        // Customer site
        auth.requestMatchers("/customers**").authenticated();

        // Any other request must be authenticated
        auth.anyRequest().authenticated();   // No change if commented.
    });

    // Client setting - shows the login screen
    http.oauth2Login(withDefaults());

    return http.build();
}

@Bean
@Order(3)
public SecurityFilterChain publicDownloadRedirectFilter(HttpSecurity http) throws Exception {
    LOGGER.info("publicDownloadRedirectFilter - Initialized");
    http.securityMatcher("/downloadRedirect/**")
            .authorizeHttpRequests(authorize -> authorize
                    .requestMatchers(new DownloadRedirectMatcher()).permitAll()
                    .anyRequest().authenticated()
    );

    return http.build();
}

DownloadRedirectMatcher is like

public class DownloadRedirectMatcher implements org.springframework.security.web.util.matcher.RequestMatcher {
    private static final Logger LOGGER = LoggerFactory.getLogger(DownloadRedirectMatcher.class);

    @Override
    public boolean matches(HttpServletRequest request) {
        LOGGER.info("Custom matcher ************* {}", "public".equals(request.getHeader("X-Public")));
        return ("public".equals(request.getHeader("X-Public")));
    }
}

What I was expecting:

  1. If / is called the page is displayed (OK)
  2. If /customer/ is called the page asks for user/password (OK)
  3. If /downloadRedirect is called with a "public" header then the permitAll is applied, instead the /login page is called and user/password are prompted (NG)

It's like the publicDownloadRedirectFilter is never applied.

Another try:

Both filters with securityMatcher, something like

@Bean
@Order(1)
public SecurityFilterChain clientFilterChain(HttpSecurity http) throws Exception {
    LOGGER.info("clientFilterChain - Initialized");

    http.securityMatcher("/customer*")
            .authorizeHttpRequests(authorize -> authorize
                    .anyRequest().authenticated()
            );
    // Client setting - shows the login screen
    http.oauth2Login(withDefaults());

    return http.build();
}

// And same publicDownloadRedirectFilter

But now the result is

  1. If / is called the page is displayed (OK)
  2. If /customer/ is called the /login page is not found and 404 is returned (NG)
  3. If /downloadRedirect is called with a "public" header then the permitAll is applied. (OK)

Any help will be appreciated.


Solution

  • Here's a Spring Security 6 configuration that might accomplishes your requirements. Please try and let us know

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig {
    
        @Bean
        public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
            http
                .authorizeHttpRequests((authz) -> authz 
                    .requestMatchers("/", "/customer/**").permitAll() // Permit root and '/customer' paths
                    .requestMatchers(new DownloadRedirectMatcher()).permitAll() 
                    .anyRequest().authenticated() // Authenticate everything else
                );
    
            return http.build();
        }
    
    }