Hi,

Working version: 2.5.7 Broken version: 2.6.x

I have a Filter that will check if the matched handler method has a particular annotation and wrap the servlet response if that is the case.

In 2.6.x requestMappingHandlerMapping.getHandler(httpServletRequest) throws

java.lang.IllegalArgumentException: Expected parsed RequestPath in request attribute "org.springframework.web.util.ServletRequestPathUtils.PATH".
    at org.springframework.util.Assert.notNull(Assert.java:201) ~[spring-core-5.3.13.jar!/:5.3.13]
    at org.springframework.web.util.ServletRequestPathUtils.getParsedRequestPath(ServletRequestPathUtils.java:77) ~[spring-web-5.3.13.jar!/:5.3.13]
    at org.springframework.web.servlet.handler.AbstractHandlerMapping.initLookupPath(AbstractHandlerMapping.java:574) ~[spring-webmvc-5.3.13.jar!/:5.3.13]
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:380) ~[spring-webmvc-5.3.13.jar!/:5.3.13]
    at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getHandlerInternal(RequestMappingInfoHandlerMapping.java:125) ~[spring-webmvc-5.3.13.jar!/:5.3.13]
    at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getHandlerInternal(RequestMappingInfoHandlerMapping.java:67) ~[spring-webmvc-5.3.13.jar!/:5.3.13]
    at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:498) ~[spring-webmvc-5.3.13.jar!/:5.3.13]

A minimal example of how we are using this code

@Component
@ConditionalOnWebApplication
public class DataFilter implements Filter {

 @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        try {
            Optional<HandlerExecutionChain> handlerExecutionChain = Optional.ofNullable(requestMappingHandlerMapping.getHandler(httpServletRequest));
            if (handlerExecutionChain.isPresent()) {
                HandlerMethod handlerMethod = (HandlerMethod) handlerExecutionChain.get().getHandler();
                if (handlerMethod.getMethod().isAnnotationPresent(MonitorData.class)) {
                    //wrap the response
                    chain.doFilter(request, wrappedResponse);
                    }
       ...

I that the default matching strategy has been changed in #24805, but I've been unable to resolve this issue in my codebase.

Comment From: william00179

Rolling back to the old behaviour by setting spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER works around this issue in the mean time.

Comment From: zifnab87

Rolling back to the old behaviour by setting spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER works around this issue in the mean time.

This indeed is a workaround to the problem but using rest-assured with those endpoints that involve filters is still failing the tests even with this setting in my application-test.yaml .

The issue is replicated in this simple example

@Component
public class ChatBotAuthenticationFilter extends OncePerRequestFilter {

    private final RequestMappingHandlerMapping reqMap;

    public ChatBotAuthenticationFilter(RequestMappingHandlerMapping reqMap) {
        this.reqMap = reqMap;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
        boolean isChatBotOnly = isEndpointChatBotOnly(req);
        //[...] custom logic
        chain.doFilter(req, res);
    }

    private boolean isEndpointChatBotOnly(HttpServletRequest req) {
        HandlerMethod method;
        try {
            // this call of reqMap.getHandler(req) throws the aforementioned exception
            method = (HandlerMethod) reqMap.getHandler(req).getHandler();
        } catch (Exception e) {
            return false;
        }

        return method.getMethod().isAnnotationPresent(ChatbotOnlyEndpoint.class);
    }
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ChatbotOnlyEndpoint {
}

Here I am annotating some controller endpoints with @ChatbotOnlyEndpoint to enforce some kind of authorization filtering based on the headers that are being submitted (tokens/ids etc)

Comment From: bclozel

This path matching strategy has been available since Spring Framework 5.3 and Spring Boot 2.4 (as an option first, in #21694). This strategy will also become the new default in Spring Framework.

The problem here is that those custom Servlet filters are leveraging the RequestMappingHandlerMapping without adapting to the changes made in Spring Framework 5.3.

To avoid parsing the request path (for efficient matching) multiple times per request, this is done once and cached as a request attribute. At the time those filters process the request, this hasn't been done yet. This is usually done by the DispatcherServlet itself or by a ServletRequestPathFilter, as explained in AbsractHandlerMapping's javadoc.

I'd suggest to ways to fix the filter implementation: * check if the new path matching is configured with org.springframework.web.servlet.handler.AbstractHandlerMapping#getPatternParser and manually populate the cached request path with org.springframework.web.util.ServletRequestPathUtils#parseAndCache in your filter * or simply declare a ServletRequestPathFilter ahead of your filter

This issue is really about adapting custom code to the new path matching - changing the default in Spring Boot merely brought an existing problem to your attention. I'm closing this issue as a result. Thanks!

Comment From: bclozel

As an additional comment, I'd like to add that RequestMappingHandlerMapping is really a strategy for the DispatcherServlet, so using it outside of that scope is not supported and considered as a bad practice. The solution I've provided in my previous comment is really a workaround and further changes should be considered in custom filters doing this.

Without knowing more about the use case, it's hard to point to alternatives. Maybe a org.springframework.web.servlet.HandlerInterceptor would be a better choice? In the interest of keeping questions outside of the Spring Boot issue tracker, feel free to ask questions on StackOverflow and report the link back here.

Comment From: zifnab87

@bclozel Thanks for your suggestions! I tried the first suggestion and this is what I changed:

I added these lines

     if (!ServletRequestPathUtils.hasParsedRequestPath(req)) {
          ServletRequestPathUtils.parseAndCache(req);
     }

just before method = (HandlerMethod) reqMap.getHandler(req).getHandler();

and it fixed my problem - is this the correct way to fix the issue or this could introduce performance problems?

Do I really need to check ServletRequestPathUtils.hasParsedRequestPath(req) beforehand?

Thanks in advance!

@Component
public class CustomAuthenticationFilter extends OncePerRequestFilter {

    private final RequestMappingHandlerMapping reqMap;

    public ChatBotAuthenticationFilter(RequestMappingHandlerMapping reqMap) {
        this.reqMap = reqMap;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
        boolean isChatBotOnly = isEndpointCustomAuthenticationOnly(req);
        //[...] custom logic
        chain.doFilter(req, res);
    }

    private boolean isEndpointCustomAuthenticationOnly(HttpServletRequest req) {
        HandlerMethod method;
        try {
             if (!ServletRequestPathUtils.hasParsedRequestPath(req)) {
                ServletRequestPathUtils.parseAndCache(req);
            }
            method = (HandlerMethod) reqMap.getHandler(req).getHandler();
        } catch (Exception e) {
            return false;
        }

        return method.getMethod().isAnnotationPresent(CustomAuthenticationEndpoint.class);
    }
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CustomAuthenticationEndpoint {
}

Comment From: bclozel

Sorry for the late reply @zifnab87 This looks ok to me. The performance problem here is really about performing the matching process twice (once in this filter, and another time for the actual handling). Looking up/setting a request attribute is really cheap compared to that.

Comment From: orubel

@bclozel I still seem to be having this issue and it occurs when you use other supported Mappings like SimpleUrlHandlerMapping with CorsFilter. Even thopugh you can establish a corsConfiguration with SimpleUrlHandlerMapping, the CorsFilter will STILL USE RequestMappingHandlerMapping for routing requests

The mapping works fine and passes all tests (batching, chaining, different JWT ROLES, etc) but when used with CORS, it fails

I am integrating it like so:

@Bean(name='simpleUrlHandlerMapping')
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {

            ...

    SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
    mapping.registerHandlers(urlMap)
    mapping.setUrlMap(urlMap);
    mapping.setOrder(1);
    mapping.setInterceptors(new Object[]{
            new ApiInterceptor(throttleCacheService, exchangeService, batchService, chainService, traceExchangeService, apiProperties)
    })
    mapping.setApplicationContext(context);
    //resourceCache.putAllResources(urlSet);

    mapping.setCorsConfigurations(getCorsConfigurations());
    return mapping;
}

protected Map<String, CorsConfiguration> getCorsConfigurations() {
    CorsRegistry registry = new CorsRegistry()
    registry.addMapping("/**")
            .allowedOrigins("http://localhost","http://test.nosegrind.net")
            .allowedMethods("*")
            .allowedHeaders("*")
            .exposedHeaders("*")
            .allowCredentials(true);
    return registry.getCorsConfigurations();
}

Comment From: orubel

So a followup... All my tests pass from a shell perspective (and have been for sometime) but when testing with CORS, I noticed that it is defaulting to ResourceHttpRequestHandler :

08:25:28.708 [http-nio-127.0.0.1-8080-exec-2] DEBUG o.s.w.s.h.SimpleUrlHandlerMapping - Mapped to ResourceHttpRequestHandler [classpath [META-INF/resources/], classpath [resources/], classpath [static/], classpath [public/], ServletContext [/]]
08:25:28.715 [http-nio-127.0.0.1-8080-exec-2] DEBUG o.s.web.servlet.DispatcherServlet - GET "/v1.0/hook/getServices?_=1684855528179", parameters={masked}
08:25:28.720 [http-nio-127.0.0.1-8080-exec-2] DEBUG o.s.w.s.h.SimpleUrlHandlerMapping - Mapped to ResourceHttpRequestHandler [classpath [META-INF/resources/], classpath [resources/], classpath [static/], classpath [public/], ServletContext [/]]
08:25:28.722 [http-nio-127.0.0.1-8080-exec-2] DEBUG o.s.w.s.r.ResourceHttpRequestHandler - Resource not found
08:25:28.723 [http-nio-127.0.0.1-8080-exec-2] DEBUG o.s.web.servlet.DispatcherServlet - Completed 404 NOT_FOUND
08:25:28.724 [http-nio-127.0.0.1-8080-exec-2] DEBUG o.s.web.servlet.DispatcherServlet - GET "/v1.0/hook/getServices?_=1684855528179", parameters={masked}
08:25:28.724 [http-nio-127.0.0.1-8080-exec-2] DEBUG o.s.w.s.h.SimpleUrlHandlerMapping - Mapped to ResourceHttpRequestHandler [classpath [META-INF/resources/], classpath [resources/], classpath [static/], classpath [public/], ServletContext [/]]
08:25:28.725 [http-nio-127.0.0.1-8080-exec-2] DEBUG o.s.w.s.r.ResourceHttpRequestHandler - Resource not found

This should not be occurring since I set the ORDER for SimpleUrlHandlerMapping to mapping.setOrder(Integer.MAX_VALUE - 2); to override that behaviour

And again, this ONLY happens when using CORS and is throwing the following error:

Caused by: java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
    at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:472)
    at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129)
    at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129)
    at javax.servlet.http.HttpServletResponseWrapper.sendError(HttpServletResponseWrapper.java:129)
    at org.springframework.security.web.util.OnCommittedResponseWrapper.sendError(OnCommittedResponseWrapper.java:116)
    at org.springframework.web.servlet.resource.ResourceHttpRequestHandler.handleRequest(ResourceHttpRequestHandler.java:561)
    at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:52)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)

Comment From: orubel

Will gladly allow access to sourcecode upon request. Right now it is in a private dev build

I DEBUGGED and know these patterns exist as well:


09:54:20.510 [main] DEBUG o.s.w.s.h.SimpleUrlHandlerMapping - Patterns [/v1.0/connector/update/**, /v1.0/connector/update/, /v1.0-1/connector/update/**, /v1.0-1/connector/update/, /b1.0/connector/update/**, /b1.0/connector/update/, /b1.0-1/connector/update/**, /b1.0-1/connector/update/, /c1.0/connector/update/**, /c1.0/connector/update/, /c1.0-1/connector/update/**, /c1.0-1/connector/update/, /t1.0/connector/update/**, /t1.0/connector/update/, /t1.0-1/connector/update/**, /t1.0-1/connector/update/, /v1.0/apidoc/show/**, /v1.0/apidoc/show/, /v1.0-1/apidoc/show/**, /v1.0-1/apidoc/show/, /b1.0/apidoc/show/**, /b1.0/apidoc/show/, /b1.0-1/apidoc/show/**, /b1.0-1/apidoc/show/, /c1.0/apidoc/show/**, /c1.0/apidoc/show/, /c1.0-1/apidoc/show/**, /c1.0-1/apidoc/show/, /t1.0/apidoc/show/**, /t1.0/apidoc/show/, /t1.0-1/apidoc/show/**, /t1.0-1/apidoc/show/, /v1.0/branch/show/**, /v1.0/branch/show/, /v1.0-1/branch/show/**, /v1.0-1/branch/show/, /b1.0/branch/show/**, /b1.0/branch/show/, /b1.0-1/branch/show/**, /b1.0-1/branch/show/, /c1.0/branch/show/**, /c1.0/branch/show/, /c1.0-1/branch/show/**, /c1.0-1/branch/show/, /t1.0/branch/show/**, /t1.0/branch/show/, /t1.0-1/branch/show/**, /t1.0-1/branch/show/, /v1.0/branch/create/**, /v1.0/branch/create/, /v1.0-1/branch/create/**, /v1.0-1/branch/create/, /b1.0/branch/create/**, /b1.0/branch/create/, /b1.0-1/branch/create/**, /b1.0-1/branch/create/, /c1.0/branch/create/**, /c1.0/branch/create/, /c1.0-1/branch/create/**, /c1.0-1/branch/create/, /t1.0/branch/create/**, /t1.0/branch/create/, /t1.0-1/branch/create/**, /t1.0-1/branch/create/, /v1.0/branch/delete/**, /v1.0/branch/delete/, /v1.0-1/branch/delete/**, /v1.0-1/branch/delete/, /b1.0/branch/delete/**, /b1.0/branch/delete/, /b1.0-1/branch/delete/**, /b1.0-1/branch/delete/, /c1.0/branch/delete/**, /c1.0/branch/delete/, /c1.0-1/branch/delete/**, /c1.0-1/branch/delete/, /t1.0/branch/delete/**, /t1.0/branch/delete/, /t1.0-1/branch/delete/**, /t1.0-1/branch/delete/, /v1.0/company/show/**, /v1.0/company/show/, /v1.0-1/company/show/**, /v1.0-1/company/show/, /b1.0/company/show/**, /b1.0/company/show/, /b1.0-1/company/show/**, /b1.0-1/company/show/, /c1.0/company/show/**, /c1.0/company/show/, /c1.0-1/company/show/**, /c1.0-1/company/show/, /t1.0/company/show/**, /t1.0/company/show/, /t1.0-1/company/show/**, /t1.0-1/company/show/, /v1.0/company/create/**, /v1.0/company/create/, /v1.0-1/company/create/**, /v1.0-1/company/create/, /b1.0/company/create/**, /b1.0/company/create/, /b1.0-1/company/create/**, /b1.0-1/company/create/, /c1.0/company/create/**, /c1.0/company/create/, /c1.0-1/company/create/**, /c1.0-1/company/create/, /t1.0/company/create/**, /t1.0/company/create/, /t1.0-1/company/create/**, /t1.0-1/company/create/, /v1.0/company/update/**, /v1.0/company/update/, /v1.0-1/company/update/**, /v1.0-1/company/update/, /b1.0/company/update/**, /b1.0/company/update/, /b1.0-1/company/update/**, /b1.0-1/company/update/, /c1.0/company/update/**, /c1.0/company/update/, /c1.0-1/company/update/**, /c1.0-1/company/update/, /t1.0/company/update/**, /t1.0/company/update/, /t1.0-1/company/update/**, /t1.0-1/company/update/, /v1.0/company/delete/**, /v1.0/company/delete/, /v1.0-1/company/delete/**, /v1.0-1/company/delete/, /b1.0/company/delete/**, /b1.0/company/delete/, /b1.0-1/company/delete/**, /b1.0-1/company/delete/, /c1.0/company/delete/**, /c1.0/company/delete/, /c1.0-1/company/delete/**, /c1.0-1/company/delete/, /t1.0/company/delete/**, /t1.0/company/delete/, /t1.0-1/company/delete/**, /t1.0-1/company/delete/, /v1.0/user/show/**, /v1.0/user/show/, /v1.0-1/user/show/**, /v1.0-1/user/show/, /b1.0/user/show/**, /b1.0/user/show/, /b1.0-1/user/show/**, /b1.0-1/user/show/, /c1.0/user/show/**, /c1.0/user/show/, /c1.0-1/user/show/**, /c1.0-1/user/show/, /t1.0/user/show/**, /t1.0/user/show/, /t1.0-1/user/show/**, /t1.0-1/user/show/, /v1.0/user/getByUsername/**, /v1.0/user/getByUsername/, /v1.0-1/user/getByUsername/**, /v1.0-1/user/getByUsername/, /b1.0/user/getByUsername/**, /b1.0/user/getByUsername/, /b1.0-1/user/getByUsername/**, /b1.0-1/user/getByUsername/, /c1.0/user/getByUsername/**, /c1.0/user/getByUsername/, /c1.0-1/user/getByUsername/**, /c1.0-1/user/getByUsername/, /t1.0/user/getByUsername/**, /t1.0/user/getByUsername/, /t1.0-1/user/getByUsername/**, /t1.0-1/user/getByUsername/, /v1.0/user/updatePassword/**, /v1.0/user/updatePassword/, /v1.0-1/user/updatePassword/**, /v1.0-1/user/updatePassword/, /b1.0/user/updatePassword/**, /b1.0/user/updatePassword/, /b1.0-1/user/updatePassword/**, /b1.0-1/user/updatePassword/, /c1.0/user/updatePassword/**, /c1.0/user/updatePassword/, /c1.0-1/user/updatePassword/**, /c1.0-1/user/updatePassword/, /t1.0/user/updatePassword/**, /t1.0/user/updatePassword/, /t1.0-1/user/updatePassword/**, /t1.0-1/user/updatePassword/, /v1.0/user/create/**, /v1.0/user/create/, /v1.0-1/user/create/**, /v1.0-1/user/create/, /b1.0/user/create/**, /b1.0/user/create/, /b1.0-1/user/create/**, /b1.0-1/user/create/, /c1.0/user/create/**, /c1.0/user/create/, /c1.0-1/user/create/**, /c1.0-1/user/create/, /t1.0/user/create/**, /t1.0/user/create/, /t1.0-1/user/create/**, /t1.0-1/user/create/, /v1.0/user/list/**, /v1.0/user/list/, /v1.0-1/user/list/**, /v1.0-1/user/list/, /b1.0/user/list/**, /b1.0/user/list/, /b1.0-1/user/list/**, /b1.0-1/user/list/, /c1.0/user/list/**, /c1.0/user/list/, /c1.0-1/user/list/**, /c1.0-1/user/list/, /t1.0/user/list/**, /t1.0/user/list/, /t1.0-1/user/list/**, /t1.0-1/user/list/, /v1.0/authority/create/**, /v1.0/authority/create/, /v1.0-1/authority/create/**, /v1.0-1/authority/create/, /b1.0/authority/create/**, /b1.0/authority/create/, /b1.0-1/authority/create/**, /b1.0-1/authority/create/, /c1.0/authority/create/**, /c1.0/authority/create/, /c1.0-1/authority/create/**, /c1.0-1/authority/create/, /t1.0/authority/create/**, /t1.0/authority/create/, /t1.0-1/authority/create/**, /t1.0-1/authority/create/, /v1.0/authority/list/**, /v1.0/authority/list/, /v1.0-1/authority/list/**, /v1.0-1/authority/list/, /b1.0/authority/list/**, /b1.0/authority/list/, /b1.0-1/authority/list/**, /b1.0-1/authority/list/, /c1.0/authority/list/**, /c1.0/authority/list/, /c1.0-1/authority/list/**, /c1.0-1/authority/list/, /t1.0/authority/list/**, /t1.0/authority/list/, /t1.0-1/authority/list/**, /t1.0-1/authority/list/, /v1.0/dept/show/**, /v1.0/dept/show/, /v1.0-1/dept/show/**, /v1.0-1/dept/show/, /b1.0/dept/show/**, /b1.0/dept/show/, /b1.0-1/dept/show/**, /b1.0-1/dept/show/, /c1.0/dept/show/**, /c1.0/dept/show/, /c1.0-1/dept/show/**, /c1.0-1/dept/show/, /t1.0/dept/show/**, /t1.0/dept/show/, /t1.0-1/dept/show/**, /t1.0-1/dept/show/, /v1.0/dept/create/**, /v1.0/dept/create/, /v1.0-1/dept/create/**, /v1.0-1/dept/create/, /b1.0/dept/create/**, /b1.0/dept/create/, /b1.0-1/dept/create/**, /b1.0-1/dept/create/, /c1.0/dept/create/**, /c1.0/dept/create/, /c1.0-1/dept/create/**, /c1.0-1/dept/create/, /t1.0/dept/create/**, /t1.0/dept/create/, /t1.0-1/dept/create/**, /t1.0-1/dept/create/, /v1.0/dept/update/**, /v1.0/dept/update/, /v1.0-1/dept/update/**, /v1.0-1/dept/update/, /b1.0/dept/update/**, /b1.0/dept/update/, /b1.0-1/dept/update/**, /b1.0-1/dept/update/, /c1.0/dept/update/**, /c1.0/dept/update/, /c1.0-1/dept/update/**, /c1.0-1/dept/update/, /t1.0/dept/update/**, /t1.0/dept/update/, /t1.0-1/dept/update/**, /t1.0-1/dept/update/, /v1.0/dept/delete/**, /v1.0/dept/delete/, /v1.0-1/dept/delete/**, /v1.0-1/dept/delete/, /b1.0/dept/delete/**, /b1.0/dept/delete/, /b1.0-1/dept/delete/**, /b1.0-1/dept/delete/, /c1.0/dept/delete/**, /c1.0/dept/delete/, /c1.0-1/dept/delete/**, /c1.0-1/dept/delete/, /t1.0/dept/delete/**, /t1.0/dept/delete/, /t1.0-1/dept/delete/**, /t1.0-1/dept/delete/] in org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
09:54:20.704 [main] DEBUG o.s.w.s.h.SimpleUrlHandlerMapping - Patterns [/webjars/**, /**] in 'resourceHandlerMapping'

The security config is fairly simple and straight forward:

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable().cors();
        httpSecurity.authorizeRequests().antMatchers("/authenticate", "/register").permitAll().anyRequest().authenticated();
        httpSecurity.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint);
        //httpSecurity.addFilterAfter(requestInitializationFilter, CorsFilter.class);
        httpSecurity.addFilterAfter(jwtRequestFilter(), ExceptionTranslationFilter.class);
        //httpSecurity.addFilterAfter(requestInitializationFilter, JwtRequestFilter.class);
        httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

Comment From: bclozel

The fact that the request is considered with the ResourceHttpRequestHandler indicates that this was not a match for the previous handlers. Maybe the request doesn't qualify as a CORS request and is ignored by the CORS support. Maybe debug through CorsUtils.isCorsRequest? In any case, a sample application showing the problem would be really helpful. If you believe this is a bug in Spring Framework, please raise an issue there.

Comment From: orubel

@bclozel Thanks a mill. Yeah that passed with flying colors. Just to be sure. This goes to HTTPSecurity??

Comment From: bclozel

@orubel, no CORS support is in Spring Framework, see CorsUtils and related classes.