Spring Security 6.1.2 requestMatchers error.
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.