spring-projects / spring-projects/spring-security

Spring Security 6.1.2 String requestMatchers error UnsupportedOperationException

Open
#13,609 4 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage type: bug
Dominant language
Java
Stars
9.6k
Forks
6.3k
Avg merge
2d 11h
Merged PRs (30d)
52

Description

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

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'filterChain' threw exception with message: 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.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:171)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655)
	... 78 common frames omitted
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)
	at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:197)
	at org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry.requestMatchers(AbstractRequestMatcherRegistry.java:248)
	at x.y.z.SecurityLocalConfiguration.lambda$filterChain$0(SecurityLocalConfiguration.java:42)
	at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeHttpRequests(HttpSecurity.java:1466)
	at x.y.z.SecurityLocalConfiguration.filterChain(SecurityLocalConfiguration.java:41)
	at x.y.z.SecurityLocalConfiguration$$SpringCGLIB$$0.CGLIB$filterChain$2(<generated>)
	at x.y.z.SecurityLocalConfiguration$$SpringCGLIB$$2.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258)
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
	at x.y.z.SecurityLocalConfiguration$$SpringCGLIB$$0.filterChain(<generated>)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139)
	... 79 common frames omitted

The code that caused this is:

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

Our current workaround is to not use requestMatchers with String arguments but to pass a AntPathRequestMatcher.
This ensures our application works again.
Working code:

@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()
            )
            .build();
}

The implementation of the requestMatchers method was altered in response to CVE https://spring.io/security/cve-2023-34035
PR and commit can be found in this issue: https://github.com/spring-projects/spring-security/issues/13551

The requestMatchers method has been changed to call servletContext.getServletRegistrations(); in commit
Tomcat does not seem to allow this and throws the UnsupportedOperationException.
This also matches the javadoc of the getServletRegistrations method

While searching for a solution I found this old issue https://github.com/spring-projects/spring-security/issues/4027 that had the same exception after a code change that also used servletContext.getServletRegistrations();.
This was reverted by this PR: https://github.com/spring-projects/spring-security/pull/4031

It seems that the mitigation for cve-2023-34035 might need a different solution to ensure it works on tomcat 10.1?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at AbstractRequestMatcherRegistry.requestMatchers, where the issue reports a call to servletContext.getServletRegistrations(), and compare that change with the linked CVE-2023-34035 commit and the earlier issue 4027/PR 4031. Reproduce the UnsupportedOperationException on Tomcat 10.1 using the String matcher example. Done means the mitigation remains effective without breaking this configuration or requiring the AntPathRequestMatcher workaround.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.