Spring Security 6.1.2 requestMatchers error.

3 minute read

Upgrading our application to Spring 6 with Spring Security 6.1.2 and Tomcat 10.1 resulted in the following UnsupportedOperationException:

Caused by: java.lang.UnsupportedOperationException: Section 4.4 of the Servlet 3.0 specification does not permit this method to be called from a ServletContextListener that was not defined in web.xml, a web-fragment.xml file nor annotated with @WebListener
	at org.apache.catalina.core.StandardContext$NoPluggabilityServletContext.getServletRegistrations(StandardContext.java:6233)

This rather cryptic message is caused by the following code:

@Bean
public SecurityFilterChain springSecurityFilterChain(HttpSecurity http, Filter autoLoginFilter) throws Exception {
    return http
            .csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(authorize -> authorize
                    .requestMatchers("/alive").permitAll()
                    .anyRequest().authenticated()
            )
            .addFilterBefore(autoLoginFilter, UsernamePasswordAuthenticationFilter.class)
            .build();
}

The implementation of the requestMatchers method was altered in Spring Security 6.1.2 due to recent security issue CVE-2023-34035: Authorization rules can be misconfigured when using multiple servlets.
To address this security issue the code was altered in the following pull request Improve RequestMatcher Validation

Before the change the implementation simply looked whether Spring WebMVC was on the classpath.
If so the requestMatchers method implementation created a MvcRequestMatcher or a AntPathRequestMatcher otherwise.

The new implementation tries to retrieve information from the ServletContext by invoking servletContext.getServletRegistrations().
This is not allowed by the Tomcat implementation of the Servlet spec, resulting in the exception being thrown.

To fix this issue we pass a MvcRequestMatcher or AntPathRequestMatcher to the requestMatchers method instead of a String.

@Bean
public SecurityFilterChain filterChain(HttpSecurity http, Filter autoLoginFilter) throws Exception {
    return http
        .csrf(AbstractHttpConfigurer::disable)
        .authorizeHttpRequests(authorize -> authorize
                .requestMatchers(new AntPathRequestMatcher("/alive")).permitAll()
                .anyRequest().authenticated()
        )
        .addFilterBefore(autoLoginFilter, UsernamePasswordAuthenticationFilter.class)
        .build();
}

Unfortunately there are reports of other issues caused by upgrading to this version Update to 6.1.2 causes errors on startup.
The change was also ported to version 5.8.5 and 6.0.5 of Spring Security.