0

somewhat related to this other stackoverflow topic which doesn't give a proper solution nor is applicable to Spring 6 (Spring Boot 3).

I came up with a basic spring-boot app to make my case.

There is a controller with two end-points, where one must be secured and the other accessible.

@RestController
public class TestController {

    @GetMapping("/secured-api")
    public String securedApi() {
        return "secured";
    }

    @GetMapping("/public/open-api")
    public String openApi() {
        return "open";
    }

}

Security context as follow, imagine that MyFilter is doing something fancy, e.g: validating a JWT token and firing an exception if the token is invalid / expired.

@Configuration
public class ComponentSecurityContext {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        return http
            .addFilterAt(new MyFilter(), BasicAuthenticationFilter.class)
            .authorizeHttpRequests(customizer -> customizer
                .requestMatchers(new AntPathRequestMatcher("/public/**"))
                .permitAll()
                .anyRequest()
                .authenticated())
            .build();
    }

    public static class MyFilter extends OncePerRequestFilter {

        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
            FilterChain filterChain) throws ServletException, IOException {

            System.out.println("Filter is called for uri: " + request.getRequestURI());

            // performs some authentication

            filterChain.doFilter(request, response);
        }
    }

}

Executing the following two curls on the server

curl http://localhost:9003/public/open-api
curl http://localhost:9003/secured-api

is triggering MyFilter

Filter is called for uri: /public/open-api
Filter is called for uri: /secured-api

I would expect MyFilter to be called only for secured end-points, I don't care if an expired token is used to access an unprotected end-point.

Any advise on how to properly wire spring-security to achieve just that?

Brian Clozel
  • 56,583
  • 15
  • 167
  • 176
Gabriel Dinant
  • 306
  • 1
  • 12
  • Does this answer your question? [How to apply Spring Security filter only on secured endpoints?](https://stackoverflow.com/questions/36795894/how-to-apply-spring-security-filter-only-on-secured-endpoints) – dur Jan 04 '23 at 11:54
  • See also https://stackoverflow.com/questions/35890540/when-to-use-spring-securitys-antmatcher – dur Jan 04 '23 at 11:56
  • See https://stackoverflow.com/questions/74447778/spring-security-in-spring-boot-3 – dur Jan 04 '23 at 12:07
  • Eventually a useful comment ;-). Thanks @dur I found the solution thanks to you. The documentation of spring-security is outdated and mostly focus on 5.7 still. It's not easy to find the right place to make that change. – Gabriel Dinant Jan 04 '23 at 12:16

1 Answers1

2

Working solution where the filter is scoped by the securityMatcher:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

    return http
        .securityMatcher(new NegatedRequestMatcher(new AntPathRequestMatcher("/public/**")))
        .addFilterAt(new MyFilter(), BasicAuthenticationFilter.class)
        .authorizeHttpRequests((requests) -> requests.anyRequest().authenticated())
        .build();
}
Gabriel Dinant
  • 306
  • 1
  • 12