Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression in 5.6.2: UnsupportedOperationException: public abstract void javax.servlet.ServletRequest.setAttribute(java.lang.String,java.lang.Object) is not supported #11055

Closed
Artur- opened this issue Apr 5, 2022 · 5 comments
Assignees
Labels
in: web An issue in web modules (web, webmvc) status: duplicate A duplicate of another issue

Comments

@Artur-
Copy link

Artur- commented Apr 5, 2022

Describe the bug
We have a method that checks if a request refers to a given path using

    private Optional<Method> getEndpoint(HttpServletRequest request) {
        PathPatternParser pathParser = new PathPatternParser();
        PathPattern pathPattern = pathParser
                .parse(endpointProperties.getEndpointPrefix()
                        + EndpointController.ENDPOINT_METHODS);
        RequestPath requestPath = ServletRequestPathUtils
                .parseAndCache(request);
...

This seems to work fine in most cases but in some cases, like when doing a dummy POST to a restricted URL, the method is called with a HttpServletRequest of type org.springframework.security.web.FilterInvocation$DummyRequest. When you call ServletRequestPathUtils.parseAndCache on this request, it fails with

Apr 05, 2022 2:38:56 PM org.apache.catalina.core.StandardHostValve custom
SEVERE: Exception Processing ErrorPage[errorCode=0, location=/error]
java.lang.UnsupportedOperationException: public abstract void javax.servlet.ServletRequest.setAttribute(java.lang.String,java.lang.Object) is not supported
        at org.springframework.security.web.FilterInvocation$UnsupportedOperationExceptionInvocationHandler.invoke(FilterInvocation.java:326)
        at com.sun.proxy.$Proxy110.setAttribute(Unknown Source)
        at javax.servlet.ServletRequestWrapper.setAttribute(ServletRequestWrapper.java:259)
        at org.springframework.web.util.ServletRequestPathUtils.parseAndCache(ServletRequestPathUtils.java:67)
        at dev.hilla.EndpointUtil.getEndpoint(EndpointUtil.java:70)
        at dev.hilla.EndpointUtil.isAnonymousEndpoint(EndpointUtil.java:99)
        at com.vaadin.flow.spring.security.RequestUtil.isAnonymousEndpoint(RequestUtil.java:107)
        at org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource.getAttributes(DefaultFilterInvocationSecurityMetadataSource.java:84)
        at org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator.isAllowed(DefaultWebInvocationPrivilegeEvaluator.java:92)
        at org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator.isAllowed(DefaultWebInvocationPrivilegeEvaluator.java:67)
        at org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.isAllowed(RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.java:76)
        at org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter.isAllowed(ErrorPageSecurityFilter.java:88)
        at org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter.doFilter(ErrorPageSecurityFilter.java:76)
        at org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter.doFilter(ErrorPageSecurityFilter.java:70)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)

as parseAndCache is trying to cache the result as a request attribute.

To Reproduce
Presumably, untested, only extracted from Vaadin code

http.exceptionHandling().accessDeniedHandler(createAccessDeniedHandler())

...

private AccessDeniedHandler createAccessDeniedHandler() {
    final LinkedHashMap<RequestMatcher, AccessDeniedHandler> matcherHandlers = new LinkedHashMap<>();
    matcherHandlers.put(request -> {ServletRequestPathUtils.parseAndCache(request); return false;}, 
                new AccessDeniedHandlerImpl());
    return new RequestMatcherDelegatingAccessDeniedHandler(matcherHandlers,
                new AccessDeniedHandlerImpl());
}

Expected behavior
No exception is thrown. The checker method can conclude this is not an endpoint request.

@rdanilin
Copy link

rdanilin commented Apr 6, 2022

We could see a strange issue with DummyRequest (which may not relate to the original issue) after upgrading to v5.6.2. The version 5.6.0 works fine.

Exception Processing ErrorPage[errorCode=0, location=/error]
java.lang.NullPointerException: null
	at java.base/java.util.Collections$3.<init>(Collections.java:5260)
	at java.base/java.util.Collections.enumeration(Collections.java:5259)
	at org.springframework.security.web.FilterInvocation$DummyRequest.getHeaders(FilterInvocation.java:260)
	at org.springframework.web.context.request.ServletWebRequest.getHeaderValues(ServletWebRequest.java:135)
	at org.springframework.web.accept.HeaderContentNegotiationStrategy.resolveMediaTypes(HeaderContentNegotiationStrategy.java:46)
	at org.springframework.security.web.util.matcher.MediaTypeRequestMatcher.matches(MediaTypeRequestMatcher.java:203)
	at org.springframework.security.web.util.matcher.OrRequestMatcher.matches(OrRequestMatcher.java:58)
	at org.springframework.security.web.DefaultSecurityFilterChain.matches(DefaultSecurityFilterChain.java:72)
	at org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.getDelegate(RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.java:120)
	at org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.isAllowed(RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.java:71)
	at org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter.isAllowed(ErrorPageSecurityFilter.java:75)
	at org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter.doFilter(ErrorPageSecurityFilter.java:65)
	at org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter.doFilter(ErrorPageSecurityFilter.java:60)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)

@Artur-
Copy link
Author

Artur- commented Apr 7, 2022

Here is a reduce reproduction case:

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final class FailingMatcher implements RequestMatcher {
        @Override
        public boolean matches(HttpServletRequest request) {
            System.out.println("Request to " + ServletRequestPathUtils.parseAndCache(request));
            return true;
        }
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.requestMatcher(new FailingMatcher());
    }

}

Error triggered by

curl localhost:8080

Also in https://github.com/Artur-/spring-security-test

@Artur-
Copy link
Author

Artur- commented Apr 13, 2022

This indeed does not happen with Spring Boot 2.6.3, i.e. Spring Security 5.6.1
but it happens with Spring Boot 2.6.4+ i.e. Spring Security 5.6.2+

@Artur- Artur- changed the title UnsupportedOperationException: public abstract void javax.servlet.ServletRequest.setAttribute(java.lang.String,java.lang.Object) is not supported Regression in 5.6.2: UnsupportedOperationException: public abstract void javax.servlet.ServletRequest.setAttribute(java.lang.String,java.lang.Object) is not supported Apr 13, 2022
@Artur-
Copy link
Author

Artur- commented Apr 13, 2022

Bisected. Caused by 994e937 by @marcusdacoregio

@marcusdacoregio marcusdacoregio self-assigned this Apr 13, 2022
@marcusdacoregio marcusdacoregio added in: web An issue in web modules (web, webmvc) and removed status: waiting-for-triage An issue we've not yet triaged type: bug A general bug labels Apr 13, 2022
@marcusdacoregio
Copy link
Contributor

Hi, thanks for the report.

Prior to 5.6.2, the WebInvocationPrivilegeEvaluator was not aware of multiple filter chains, it was also not aware of the requestMatcher for the SecurityFilterChain at all. 994e937 fixed this behavior by taking into consideration the requestMatcher for each SecurityFilterChain configured.

In Spring Boot 2.6.0, the ErrorPageSecurityFilter was introduced to perform authorization checks on DispatcherType.ERROR, and it uses the WebInvocationPrivilegeEvaluator API to perform those checks. The WebInvocationPrivilegeEvaluator is not intended to use in scenarios where users need anything but the URL from the request, therefore its usage does not really fit into the ErrorPageSecurityFilter, see #10919 and #11092.

That said, what I recommend folks do is to consider removing the ErrorPageSecurityFilter:

@Bean
public static BeanFactoryPostProcessor removeErrorSecurityFilter() {
	return beanFactory -> ((DefaultListableBeanFactory) beanFactory).removeBeanDefinition("errorPageSecurityInterceptor");
}

And, if you want the authorization checks for all DispatcherTypes you can do:

http
	.authorizeRequests((requests) -> requests
		.filterSecurityInterceptorOncePerRequest(false)
		...
	)
        ...

If you are using authorizeHttpRequests, once 5.7.0 is released, you can use shouldFilterAllDispatcherTypes, like so:

http
	.authorizeHttpRequests((requests) -> requests
		.shouldFilterAllDispatcherTypes(true)
		...
	)
        ...

Note that in Spring Security 6.0, all the DispatcherTypes will be filtered by default, see #11027.

Related:

@marcusdacoregio marcusdacoregio added the status: duplicate A duplicate of another issue label Apr 13, 2022
dbyron-sf added a commit to dbyron-sf/gate that referenced this issue Aug 8, 2024
…yInterceptor

to prevent java.lang.UnsupportedOperationException: public abstract int
javax.servlet.ServletRequest.getLocalPort() is not supported when processing error
responses.

See spring-projects/spring-security#11055 (comment) for background.
dbyron-sf added a commit to dbyron-sf/gate that referenced this issue Aug 9, 2024
…yInterceptor

to prevent java.lang.UnsupportedOperationException: public abstract int
javax.servlet.ServletRequest.getLocalPort() is not supported when processing error
responses.

See spring-projects/spring-security#11055 (comment) for background.
dbyron-sf added a commit to dbyron-sf/gate that referenced this issue Aug 9, 2024
…yInterceptor

to prevent java.lang.UnsupportedOperationException: public abstract int
javax.servlet.ServletRequest.getLocalPort() is not supported when processing error
responses.

See spring-projects/spring-security#11055 (comment) for background.
mergify bot pushed a commit to spinnaker/gate that referenced this issue Aug 10, 2024
…yFilter (#1819)

* test(web): demonstrate bug in MultiAutoSupport

where handling of certain error responses generates html:

<!doctype html><html lang="en"><head><title>HTTP Status 400 – Bad Request</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 400 – Bad Request</h1></body></html>

instead of json, and the following exception in the logs:

java.lang.UnsupportedOperationException: public abstract int javax.servlet.ServletRequest.getLocalPort() is not supported
    at org.springframework.security.web.FilterInvocation$UnsupportedOperationExceptionInvocationHandler.invoke(FilterInvocation.java:326)
    at jdk.proxy2/jdk.proxy2.$Proxy256.getLocalPort(Unknown Source)
    at javax.servlet.ServletRequestWrapper.getLocalPort(ServletRequestWrapper.java:329)
    at com.netflix.spinnaker.gate.config.MultiAuthSupport$1.lambda$requestMatcher$0(MultiAuthSupport.java:30)
    at org.springframework.security.web.DefaultSecurityFilterChain.matches(DefaultSecurityFilterChain.java:72)
    at org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.getDelegate(RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.java:120)
    at org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.isAllowed(RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.java:71)
    at org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter.isAllowed(ErrorPageSecurityFilter.java:88)
    at org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter.doFilter(ErrorPageSecurityFilter.java:76)
    at org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter.doFilter(ErrorPageSecurityFilter.java:70)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:337)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:106)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:87)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:219)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at javax.servlet.FilterChain$doFilter.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at javax.servlet.FilterChain$doFilter.call(Unknown Source)
    at com.netflix.spinnaker.gate.security.oauth2.ExternalAuthTokenFilter.doFilter(ExternalAuthTokenFilter.groovy:65)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:142)
    at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:82)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:661)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:427)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:357)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:294)
    at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:377)
    at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:237)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:166)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:765)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:346)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:928)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1794)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
    at java.base/java.lang.Thread.run(Thread.java:840)

The test uses basic auth, but we've seen this in production using oauth2.

* fix(core): remove ErrorPageSecurityFilter bean named errorPageSecurityInterceptor

to prevent java.lang.UnsupportedOperationException: public abstract int
javax.servlet.ServletRequest.getLocalPort() is not supported when processing error
responses.

See spring-projects/spring-security#11055 (comment) for background.

* refactor(basic): use constructor injection in BasicAuthConfig

to facilitate testing

* test(web): verify some error handling behavior of AuthConfig

* fix(core): update the name of the ErrorPageSecurityFilter bean for spring boot 2.7.x
mergify bot pushed a commit to spinnaker/gate that referenced this issue Aug 10, 2024
…yInterceptor (#1817)

* test(web): demonstrate bug in MultiAutoSupport

where handling of certain error responses generates html:

<!doctype html><html lang="en"><head><title>HTTP Status 400 – Bad Request</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 400 – Bad Request</h1></body></html>

instead of json, and the following exception in the logs:

java.lang.UnsupportedOperationException: public abstract int javax.servlet.ServletRequest.getLocalPort() is not supported
    at org.springframework.security.web.FilterInvocation$UnsupportedOperationExceptionInvocationHandler.invoke(FilterInvocation.java:326)
    at jdk.proxy2/jdk.proxy2.$Proxy256.getLocalPort(Unknown Source)
    at javax.servlet.ServletRequestWrapper.getLocalPort(ServletRequestWrapper.java:329)
    at com.netflix.spinnaker.gate.config.MultiAuthSupport$1.lambda$requestMatcher$0(MultiAuthSupport.java:30)
    at org.springframework.security.web.DefaultSecurityFilterChain.matches(DefaultSecurityFilterChain.java:72)
    at org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.getDelegate(RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.java:120)
    at org.springframework.security.web.access.RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.isAllowed(RequestMatcherDelegatingWebInvocationPrivilegeEvaluator.java:71)
    at org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter.isAllowed(ErrorPageSecurityFilter.java:88)
    at org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter.doFilter(ErrorPageSecurityFilter.java:76)
    at org.springframework.boot.web.servlet.filter.ErrorPageSecurityFilter.doFilter(ErrorPageSecurityFilter.java:70)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:337)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:106)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:87)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:219)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at javax.servlet.FilterChain$doFilter.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at javax.servlet.FilterChain$doFilter.call(Unknown Source)
    at com.netflix.spinnaker.gate.security.oauth2.ExternalAuthTokenFilter.doFilter(ExternalAuthTokenFilter.groovy:65)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:142)
    at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:82)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:102)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:661)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:427)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:357)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:294)
    at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:377)
    at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:237)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:166)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:765)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:346)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:928)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1794)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
    at java.base/java.lang.Thread.run(Thread.java:840)

The test uses basic auth, but we've seen this in production using oauth2.

* fix(core): remove ErrorPageSecurityFilter bean named errorPageSecurityInterceptor

to prevent java.lang.UnsupportedOperationException: public abstract int
javax.servlet.ServletRequest.getLocalPort() is not supported when processing error
responses.

See spring-projects/spring-security#11055 (comment) for background.

* refactor(basic): use constructor injection in BasicAuthConfig

to facilitate testing

* test(web): verify some error handling behavior of AuthConfig
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web An issue in web modules (web, webmvc) status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

3 participants