Summary

I have CORS activated via spring in my dispatcher config. According to the documentation only the cors tag should make CORS work with spring security. But in my case it does not.

I make an AJAX POST call from different domain and that results in a preflight OPTIONS call which needs to return 200 with CORS headers. But i get a 401.

Actual Behavior

The preflight request return a 401 instead of ok with CORS headers. Request URL:http://localhost:8080/rest/client/user Request Method:OPTIONS Status Code:401 Full authentication is required to access this resource Remote Address:[::1]:8080 Referrer Policy:no-referrer-when-downgrade

Expected Behavior

I have added my own filter to return ok and now my AJAX post is working:

Request URL:http://localhost:8080/rest/client/user Request Method:OPTIONS Status Code:200 OK Remote Address:[::1]:8080 Referrer Policy:no-referrer-when-downgrade Response Headers Access-Control-Allow-Headers:Authorization, Origin, Content-Type, Accept Access-Control-Allow-Methods:GET,PUT,OPTIONS,POST,DELETE,PATCH Access-Control-Allow-Origin:*

and than the POST call will follow.

Configuration

my dispatcher.xml

<mvc:cors>
    <mvc:mapping path="/rest/client/**" allowed-headers="*" allowed-methods="*" allowed-origins="*" allow-credentials="true" />
</mvc:cors>

my security.xml

<!-- start REST security -->
<http entry-point-ref="basicAuthEntryPoint" pattern="/app/rest/**" use-expressions="true" disable-url-rewriting="false">
    <intercept-url pattern="/app/rest/**" access="hasRole('ROLE_USER')" />
    <custom-filter ref="basicAuthenticationFilter" after="BASIC_AUTH_FILTER" />
    <csrf disabled="true" />
    <cors />   <!-- this is not working :( -->
</http>

(the cors tag is not working)

My own filter (which i needed because the cors tag above is not working):

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    if (request.getMethod().equals("OPTIONS")) {
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        resp.addHeader("Access-Control-Allow-Origin", "*");
        resp.addHeader("Access-Control-Allow-Methods", "GET,PUT,OPTIONS,POST,DELETE,PATCH");
        // resp.addHeader("Access-Control-Max-Age","1000");
        resp.addHeader("Access-Control-Allow-Headers", "Authorization, Origin, Content-Type, Accept");
        // Just ACCEPT and REPLY OK if OPTIONS
        resp.setStatus(HttpServletResponse.SC_OK);
        return;
    }
    chain.doFilter(request, servletResponse);
}

Version

spring.version = 4.3.12.RELEASE
spring.security.version = 4.2.3.RELEASE

Sample

here my javascript call:

   <head>
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
 </head>
 <body id="loginBody">
 <script>

 $.ajax({
     type: 'POST',
     url: 'http://localhost:8080/rest/client/user',
     crossDomain: true,
     beforeSend: function (xhr) {
       xhr.setRequestHeader ("Authorization", "Basic " + btoa("user:user"));
     },
     data: '{"some":"json"}',
     dataType: 'json',
     success: function(responseData, textStatus, jqXHR) {
         var value = responseData.data.username;
         $("#result").text(value);
     },
     error: function (responseData, textStatus, errorThrown) {
         alert('POST failed.');
     }
 });

 </script>
 <div id="result">test</div>

Comment From: rwinch

Thanks for reaching out @tibistibi! Spring Security's CORS support requires that you provide a CorsConfigurationSource. This means the 'my own filter' will not work out of the box with Spring Security.

You have a few options:

1) Place "my own filter" before Spring Security in your web.xml. This is probably the easiest approach if you want to use your own filter. However, you don't get all the header protection. 2) Place "my own filter" in Spring Security's filters just after the headers filter. This is the best option if you want to use "my own filter"

<http ...>
    ...
    <custom-filter after="HEADERS_FILTER" ref="myOwnFilterBeanName" />
</http>

3) Switch to using Spring's CorsConfigurationSource. See https://docs.spring.io/spring-security/site/docs/4.2.x/reference/htmlsingle/#cors for more information.

I'm going to close this, but feel free to reopen if you feel your problem has not been addressed

Comment From: tibistibi

Thanks. the point is: i do not want to use my own filter. i want this to work:

If you are using Spring MVC’s CORS support, you can omit specifying the CorsConfigurationSource and Spring Security will leverage the CORS configuration provided to Spring MVC.

<http>
<!-- Default to Spring MVC's CORS configuration -->
<cors />
...
</http>

Comment From: rwinch

Is Spring Security in the same application context as Spring MVC or is Security in the ContextLoaderListener and MVC in the DispatcherServlet?

Comment From: tibistibi

Good question. mvc is in my dispatcher-servlet.xml and spring security is run from my web.xml (security.xml)

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:/applicationContext-resources.xml
        classpath:/applicationContext-dao.xml
        classpath:/applicationContext-service.xml
        classpath:/applicationContext-timer.xml
        classpath*:/applicationContext.xml
        /WEB-INF/applicationContext*.xml
        /WEB-INF/cxf-servlet.xml
        /WEB-INF/security.xml
    </param-value>
</context-param>

Comment From: tibistibi

i have moved the config to the same security.xml file like this:

<mvc:cors>
<mvc:mapping path="/rest/client/**" allowed-headers="*" allowed-methods="GET,PUT,HEAD,OPTIONS,POST,DELETE,PATCH" allowed-origins="*" allow-credentials="true" /> 
</mvc:cors>
<!-- start REST security -->
<http entry-point-ref="basicAuthEntryPoint" pattern="/app/rest/**" use-expressions="true" disable-url-rewriting="false">
    <intercept-url pattern="/app/rest/**" access="hasRole('ROLE_USER')" />
    <custom-filter ref="basicAuthenticationFilter" after="BASIC_AUTH_FILTER" />
    <csrf disabled="true" />
    <cors />
</http>

but still the same result (i need my filter to get OPTION to work). or do i misunderstand your questions?

Comment From: rwinch

I think you need to provide a sample and instructions to reproduce the problem at this point.

Comment From: tibistibi

yes i understand. i will try to find the time to make an example.

Comment From: tibistibi

i dubble checked my config and there was a double mvn deceleration. removing that from my dispatcher.xml file made CORS not work at all. moving it from my security.xml to my dispatcher.xml file did make CORS work voor POST but still not for the OPTIONS method. so spring security is not taking over the mvn settings from my dispatcher.xml

you asked me this question: 'Is Spring Security in the same application context as Spring MVC or is Security in the ContextLoaderListener and MVC in the DispatcherServlet?'

could this be the problem?

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: jzheaux

It's possible that what you describe could be the problem, but to make more progress, I think we'll need a minimal sample that reproduces the issue.

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: spring-projects-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

Comment From: tibistibi

I agree to close it, this was so long ago that I can not remember what I was working on. When I come across this issue again I will let you know

thanks for the work and a good 2021 ;)