grails-core
grails-core copied to clipboard
CORS support broken in Grails 4
From some investigation, it's possible this is a documentation bug, possibly caused by changes in underlying Spring. But not being an expert in grails/cors, someone should look at it, and at the very least, update the doco.
Here's the situation...
I have a working Angular / Grails 3 app. It has the most basic CORS setup in application.yml:
grails:
cors:
enabled: true
If I look at what happens in Fiddler, the server responds with these headers:
Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: http://localhost:4200
Good stuff.
But in Grails 4 the server responds like this:
Access-Control-Allow-Origin: *
This results in the browser failing like this:
Access to XMLHttpRequest at 'http://localhost:8080/plant/sectionData/' from origin 'http://localhost:4200' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
But it turns out if I turn on "allowedCredentials" it starts to work...
grails:
cors:
enabled: true
allowCredentials: true
However the documentation claims that merely settings grails.cors.enabled=true results in a mapping of "/**" with "allowCredentials= true".
As far as I can see, the reason for this change in behaviour is found in Spring's CorsConfiguration.java: applyPermitDefaultValues, where Spring4 used to have a line:
public CorsConfiguration applyPermitDefaultValues() {
//blah blah
if (this.allowCredentials == null) {
this.setAllowCredentials(true);
}
//blah blah
}
But Spring 5 doesn't have that line in the code.
So I'm assuming this is for some reason deliberate, and I guess maybe the correct thing is to update this table in the documentation: https://docs.grails.org/4.0.10/guide/single.html#cors
allowedOrigins | ['*'] |
---|---|
allowedMethods | ['*'] |
allowedHeaders | ['*'] |
exposedHeaders | null |
maxAge | 1800 |
allowCredentials | true |
to align with what is currently existing in CorsConfiguration.applyPermitDefaultValues()
and present some examples that actually work.
Task List
Create an Angular or javascript app, that makes grails requests. Use this config:
grails:
cors:
enabled: true
Observe the wrong headers.
Expected Behaviour
Headers returned by Grails 3, as per above
Actual Behaviour
The headers make browsers CORS security fail.
Environment Information
- Operating System: Windows 10
- Grails Version: 4.0.0 through 4.0.9 fail
- JDK Version: 1.8.0
Example Application
@xpusostomos Would you be interested in sending PR to update the documentation?
I ran into the same issue. This was working in grails 3.3.11 and failed in 4.0.11:
cors { enabled = true mappings = [ "/**": [ allowedOrigins: [ 'http://' + System.env.SERVER_HOST_PORT, 'https://' + System.env.SERVER_HOST_PORT, 'http://' + System.env.AWS_GS_ASSETS_CLOUDFRONT_URL, 'https://' + System.env.AWS_GS_ASSETS_CLOUDFRONT_URL ] ] ] }
I tried changing it to this:
cors { enabled = true allowedOrigins = [ 'http://' + System.env.SERVER_HOST_PORT, 'https://' + System.env.SERVER_HOST_PORT, 'http://' + System.env.AWS_ASSETS_CLOUDFRONT_URL, 'https://' + System.env.AWS_ASSETS_CLOUDFRONT_URL ] }
but it still failed until I added allowCredentials = true
It would appear that in grails 5, Spring has changed again and you now need allowedOriginPatterns
grails:
cors:
enabled: true
allowCredentials: true
allowedOriginPatterns: '*'