davidtinker / grails-cors Goto Github PK
View Code? Open in Web Editor NEWGrails plugin to add Cross-Origin Resource Sharing (CORS) headers
Grails plugin to add Cross-Origin Resource Sharing (CORS) headers
When using asset-pipeline the css from the cors plugin web-app directory is overwriting css from assets directory.
Plugin seems to not add CORS headers when rendering data as JSON using grails JSON converter. I'm using grails 2.0.3
import grails.converters.JSON
class RestaurantApiController{
def summary() {
def student=Student.get(params.id)
render student as JSON
}
}
I just installed the Cors 1.1.0 plugin to deal with CORS issues, however I am getting a CORS issue due to the browser not receiving an "http status code of 200 Ok". I am limited in terms of spring-security-core plugin versions since I am working on a legacy Grails 2.4.5 App that requires a version of spring-security-core version that only works with that CORS version available in the nexus repository.
I wrote some code in my controller to return the status code, however I don't understand why the ReactJS Front-end browser doesn't get it. I can see that status 200 code from the command line with "curl" as well as when I launch the back-end in the browser.
$ curl -i -v -H "Authorization: Bearer token" http://localhost:5000/server-app/api/v1/user/xxx
* Trying 127.0.0.1:5000...
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET /server-app/api/v1/user/qatest1 HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.79.1
> Accept: */*
> Authorization: Bearer token
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
Server: Apache-Coyote/1.1
< Set-Cookie: JSESSIONID=xxx; Path=/server-web; HttpOnly
Set-Cookie: JSESSIONID=xxx; Path=/server-app; HttpOnly
< Content-Type: application/json;charset=UTF-8
Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
Transfer-Encoding: chunked
< Date: Wed, 12 Jan 2022 22:17:47 GMT
Date: Wed, 12 Jan 2022 22:17:47 GMT
<
{
"id": xxx,
"username": "xxx",
"firstName": "xxx",
"lastName": null,
"department":
[
"{id:xx name:xxx, description:xxx}"
]
}* Connection #0 to host localhost left intact
cors.enable.logging = true // enable logging of failed requests
cors.url.pattern = '/api/v1/*'
cors.headers = ['Access-Control-Allow-Origin': 'http://localhost:3000', // Only allow access to that origin
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Methods': 'GET, HEAD, TRACE, OPTIONS',
]
def index(){
def users = User?.list(max:5, sort: "username", order:"asc")
response.status = 200
render(users as JSON)
}
static mappings = {
'/api/v1/users'(resources:'user')
"/api/v1/user/$username"(controller:'user', action:"findByUsername", method: 'GET')
...
}
Great tool David!
Can you explain in more detail in your readme.md file how to create the servlet filter, where it should be palced, what else needs to be configured?
Thanks
Roberto
Spring security plugin now uses a config of 'grails.plugin.springsecurity'. Notice plugin is no longer plural.
so this code block in CorsGrailsPlugin.groovy needs to be updated.
if (application.config.grails.plugins.springsecurity?.useBasicAuth) {
basicAuthenticationEntryPoint(CorsCompatibleBasicAuthenticationEntryPoint) { bean ->
realmName = application.config.grails.plugins.springsecurity.basic.realmName
}
}
In the Config.groovy, when I set the cors.url.pattern = '/rest/profile/ it causes Catalina to fail when restarting. However if I change it from /rest/* to the new value without restarting everything seems to work.
| Loading Grails 2.1.1
| Configuring classpath
| Configuring classpath.
| Environment set to development
| Environment set to development.
| Environment set to development..
| Environment set to development...
| Environment set to development....
| Environment set to development.....
| Packaging Grails application
| Packaging Grails application.
| Packaging Grails application..
| Packaging Grails application...
| Packaging Grails application....
| Packaging Grails application.....
| Compiling 1 source files
| Compiling 1 source files.
| Compiling 1 source files..
| Compiling 1 source files..
| Compiling 1 source files...
| Compiling 1 source files...
| Compiling 1 source files...
| Compiling 1 source files....
| Compiling 1 source files....
| Compiling 1 source files....
| Compiling 1 source files.....
| Running Grails application
| Error 2013-02-18 23:05:24,184 [Tomcat-startStop-1] ERROR core.ContainerBase - A child container failed during start
Message: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[/untitled]]
Line | Method
->> 222 | innerGet in java.util.concurrent.FutureTask$Sync
| 83 | get in java.util.concurrent.FutureTask
| 303 | innerRun in java.util.concurrent.FutureTask$Sync
| 138 | run in java.util.concurrent.FutureTask
| 886 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker
| 908 | run in ''
^ 680 | run . . in java.lang.Thread
Caused by LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost].StandardContext[/untitled]]
->> 303 | innerRun in java.util.concurrent.FutureTask$Sync
| 138 | run in java.util.concurrent.FutureTask
| 886 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker
| 908 | run in ''
^ 680 | run . . in java.lang.Thread
Caused by IllegalArgumentException: Invalid /rest/profile/ in filter mapping
->> 303 | innerRun in java.util.concurrent.FutureTask$Sync
| 138 | run in java.util.concurrent.FutureTask
| 886 | runTask in java.util.concurrent.ThreadPoolExecutor$Worker
| 908 | run in ''
^ 680 | run . . in java.lang.Thread
| Error 2013-02-18 23:05:24,214 [main] ERROR core.ContainerBase - A child container failed during start
Message: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost]]
Line | Method
->> 222 | innerGet in java.util.concurrent.FutureTask$Sync
| 83 | get in java.util.concurrent.FutureTask
| 137 | doStart . in org.grails.plugins.tomcat.InlineExplodedTomcatServer
| 102 | start in org.grails.plugins.tomcat.TomcatServer
| 176 | doCall . in _GrailsRun_groovy$_run_closure5_closure12
| 153 | doCall in _GrailsRun_groovy$_run_closure5
| 121 | runInline in _GrailsRun_groovy
| 67 | doCall in _GrailsRun_groovy$_run_closure1
| 33 | doCall . in RunApp$_run_closure1
^ 120 | main in com.intellij.rt.execution.application.AppMain
Caused by LifecycleException: Failed to start component [StandardEngine[Tomcat].StandardHost[localhost]]
->> 303 | innerRun in java.util.concurrent.FutureTask$Sync
| 138 | run in java.util.concurrent.FutureTask
| 886 | runTask . in java.util.concurrent.ThreadPoolExecutor$Worker
| 908 | run in ''
^ 680 | run . . . in java.lang.Thread
Caused by LifecycleException: A child container failed during start
->> 303 | innerRun in java.util.concurrent.FutureTask$Sync
| 138 | run in java.util.concurrent.FutureTask
| 886 | runTask . in java.util.concurrent.ThreadPoolExecutor$Worker
| 908 | run in ''
^ 680 | run . . . in java.lang.Thread
| Error Failed to start component [StandardServer[-1]](NOTE: Stack trace has been filtered. Use --verbose to see entire trace.)
org.apache.catalina.LifecycleException: Failed to start component [StandardServer[-1]]
at org.grails.plugins.tomcat.InlineExplodedTomcatServer.doStart(InlineExplodedTomcatServer.groovy:137)
at org.grails.plugins.tomcat.TomcatServer.start(TomcatServer.groovy:102)
at _GrailsRun_groovy$_run_closure5_closure12.doCall(_GrailsRun_groovy:176)
at _GrailsRun_groovy$_run_closure5.doCall(_GrailsRun_groovy:153)
at _GrailsRun_groovy.runInline(_GrailsRun_groovy:121)
at _GrailsRun_groovy$_run_closure1.doCall(_GrailsRun_groovy:67)
at RunApp$_run_closure1.doCall(RunApp:33)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardService[Tomcat]]
... 8 more
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Tomcat]]
... 8 more
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
... 8 more
| Error Server failed to start: org.apache.catalina.LifecycleException: Failed to start component [StandardServer[-1]]
Process finished with exit code 1
The documentation says that "you can override the default values used for the headers by supplying a headers map", included Access-Control-Allow-Origin, as the example suggest.
But this particular header is not respected, and the Origin header is always echoed back [1], because the code removes the configured header from the map [2].
I need to respond '*' as Access-Control-Allow-Origin.
spring-security-core 2.0 use now grails.plugin.springsecurity as configuration settings meanwhile CorsGrailsPlugin at doWithSpring try to use grails.plugins.security.
"Your security configuration settings use the old prefix 'grails.plugins.springsecurity' but must now use 'grails.plugin.springsecurity' "
In order to allow authentication via cors using this plugin, a header Access-Control-Allow-Credentials=true
must always be sent to the client, not only for an OPTIONS
request. This allowes the client to add withCredentials
to the XHR request.
This is required e.g for exchanging the session cookie or OAuth cookies.
See here for more details: http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server
Hi
I'm struggling to configure Access-Control-Allow-Headers to allow the standard values, plus a new x-abc, i.e. [origin, authorization, accept, content-type, x-requested-with, x-abc]
Please could you provide an example Config.groovy configuration?
We have requirements where we need to disable CORS in some environments but enable it in others. Right now I'm using the cors.allow.origin.regex
to a never true regex to turn it off in those Configs where we don't want it, but it would be nice if there were an explicit enabled/disabled flag.
Hi Guys,
I'm facing a situation where different browsers (Safari, Mobile Safari, and Chrome) are requesting different headers, of course that I can add each header manually but I'm afraid a new version of any of the browsers will request a new header in the future and my app will stop working. Since you cannot use wildcards on the Allow-Headers, wouldn't it be nice to add an option in the config to respond with the requested headers?
I added this to the CorsFilter file:
resp.addHeader("Access-Control-Allow-Headers",req.getHeader("Access-Control-Request-Headers"));
And it's working fine for me.
What are your thoughts about this? Can this be seen as a security flaw?
Thanks!
Matias
Hi,
I'm trying to use your plugin with this configuration:
cors.url.pattern = '/api/*'
cors.headers = [
'Access-Control-Allow-Origin': '*'
]
and it's ok, but when I set
grails.plugins.springsecurity.apf.filterProcessesUrl = '/api/v1/auth'
after that, the first request OPTIONS returns with origin failed
please help.
Hi.
When I use this plugin with the last version of springsecurity:
compile ":spring-security-core:2.0-RC4"
I get a lot of compilation errors, probably because the plugin uses the old springsecurity plugin.
Do you have plans to make it compatible with the new version?
When using this plugin along with the Spring Security basic auth filter, CORS breaks down because it seems the auth is getting applied to the OPTIONS requests as well. This causes the options requests to return with a status of 401 which in turn breaks CORS on pretty much any browser.
It seems fair that the basic auth filter would get applied to all request types. I'm just wondering if there is some way we can override the default filter behavior when used in conjunction with this plugin. I'd be willing to put in the work and submit a PR but am just throwing this out there for ideas before I get started on it!
Hi again, when I send request to standart SS method j_spring_security_check, its return canceled. What am I doing wrong?
setup:
grails create-app; add plugin arrested:1.18 to BuildConfig; grails create-arrested-app gives the following error in cors1.1.4 plugin:
when: using the arrested plugin (depends on cors1.1.4), though the error will happen if cors is used directly
error: MultipleCompilationErrorsException
\target\work\plugins\cors-1.1.4.\CorsGrailsPlugin.groovy: 19: unable to resolve class org.codehaus.groovy.grails.commons.ConfigurationHolder
Looks like ConfigurationHolder has been removed from grails 2.4
Got it working by adding these to CorsGrailsPlugin.groovy:
def grailsApplication = grails.util.Holders.getGrailsApplication()
and replace CH with grailsApplication
As of Grails 2.3, the CORS plugin always returns 405 for all OPTIONS requests, resulting in obvious client-side problems. This issue says I can handle OPTIONS requests: http://jira.grails.org/browse/GRAILS-5531. I do not see how/why this bug was marked resolved. Any attempt to handle any OPTIONS request is ineffective. No URL mapping or Filter seems to be triggered.
Filing in both places: http://jira.grails.org/browse/GRAILS-10429. Not sure exactly where the problem is.
When I added
compile ":cors:1.1.0"
to my dependencies
I got:
| Downloading: cors-1.1.0.pom.sha1
:: problems summary ::
:::: WARNINGS
::::::::::::::::::::::::::::::::::::::::::::::
:: UNRESOLVED DEPENDENCIES ::
::::::::::::::::::::::::::::::::::::::::::::::
:: #cors;1.1.0: java.text.ParseException: inconsistent module descriptor file found in 'http://plugins.grails.org/grails-cors/tags/RELEASE_1_1_0/cors-1.1.0.pom': bad organisation: expected='' found='org.grails.plugins';
::::::::::::::::::::::::::::::::::::::::::::::
:::: ERRORS
grailsCentral: bad organisation found in http://plugins.grails.org/grails-cors/tags/RELEASE_1_1_0/cors-1.1.0.pom: expected='' found='org.grails.plugins'
| Downloading: cors-1.1.0.pom.sha1
:: problems summary ::
:::: WARNINGS
::::::::::::::::::::::::::::::::::::::::::::::
:: UNRESOLVED DEPENDENCIES ::
::::::::::::::::::::::::::::::::::::::::::::::
:: #cors;1.1.0: java.text.ParseException: inconsistent module descriptor file found in 'http://plugins.grails.org/grails-cors/tags/RELEASE_1_1_0/cors-1.1.0.pom': bad organisation: expected='' found='org.grails.plugins';
::::::::::::::::::::::::::::::::::::::::::::::
:::: ERRORS
grailsCentral: bad organisation found in http://plugins.grails.org/grails-cors/tags/RELEASE_1_1_0/cors-1.1.0.pom: expected='' found='org.grails.plugins'
| Downloading: cors-1.1.0.pom.sha1
:: problems summary ::
:::: WARNINGS
::::::::::::::::::::::::::::::::::::::::::::::
:: UNRESOLVED DEPENDENCIES ::
::::::::::::::::::::::::::::::::::::::::::::::
:: #cors;1.1.0: java.text.ParseException: inconsistent module descriptor file found in 'http://plugins.grails.org/grails-cors/tags/RELEASE_1_1_0/cors-1.1.0.pom': bad organisation: expected='' found='org.grails.plugins';
::::::::::::::::::::::::::::::::::::::::::::::
:::: ERRORS
grailsCentral: bad organisation found in http://plugins.grails.org/grails-cors/tags/RELEASE_1_1_0/cors-1.1.0.pom: expected='' found='org.grails.plugins'
| Error Failed to resolve dependencies (Set log level to 'warn' in BuildConfig.groovy for more information):
I was not able to get where to add this CORS plugin into Grails 3.0.x. Did you mean "application.yml". Would be helpful if you add the location of these files you mentioned in your read me.
Bottom line it works and rocks.. Thanks
Hi,
We use grails cors plugin in our project and we have seen a strange issue :
When I wrote in config.groovy :
cors.url.pattern = '/beer/_'
cors.allow.origin.regex='._mon.domaine.autorise([/].*)?
And started application (in dev mode and prod mode), I have tested theses cases :
curl -H "Origin: http://mon.domaine.autorise/authenticationFom/" --verbose http://sf713606.societe.mma.fr:8084/applicationBlanche/immortalCats
=> No headers in response
curl -H "Origin: http://mon.domaine.autorise/authenticationFom/" --verbose http://sf713606.societe.mma.fr:8084/applicationBlanche/beer/show/1
=> headers in response :
Access-Control-Allow-Origin: http://mon.domaine.autorise/authenticationFom/
Access-Control-Allow-Origin: true
curl -H "Origin: http://mon.domaine.non.autorise/authenticationFom/" --verbose http://sf713606.societe.mma.fr:8084/applicationBlanche/beer/show/1
=> No headers in response
==> All is good.
But we need to externalise params in config.properties; we wrote this in config.properties and suppressed it from config.groovy :
cors.url.pattern = '/beer/_'
cors.allow.origin.regex='._mon.domaine.autorise([/].*)?
When the application starts in prod mode we have these results :
curl -H "Origin: http://mon.domaine.autorise/authenticationFom/" --verbose http://sf713606.societe.mma.fr:8084/applicationBlanche/immortalCats
=> headers in response :
Access-Control-Allow-Origin: http://mon.domaine.autorise/authenticationFom/
Access-Control-Allow-Origin: true
curl -H "Origin: http://mon.domaine.autorise/authenticationFom/" --verbose http://sf713606.societe.mma.fr:8084/applicationBlanche/beer/show/1
=> headers in response :
Access-Control-Allow-Origin: http://mon.domaine.autorise/authenticationFom/
Access-Control-Allow-Origin: true
curl -H "Origin: http://mon.domaine.non.autorise/authenticationFom/" --verbose http://sf713606.societe.mma.fr:8084/applicationBlanche/beer/show/1
=> headers in response :
Access-Control-Allow-Origin: http://mon.domaine.non.autorise/authenticationFom/
Access-Control-Allow-Origin: true
==> It's like the plugin don't see the params and make a default comportment. Could you test it ?
PS : We use grails 2.2 and grails cors plugin 1.1.6 and standards grails mechanincs for properties.
This grails-cors plugin seems to work great on Chrome/Firefox/Android, but doesn't work on Safari (Mac and iOS).
Example A jsFiddle:
http://jsfiddle.net/davidfrahm/7TQYh/
Example B on test-cors.org:
http://client.cors-api.appspot.com/client#?client_method=GET&client_credentials=false&server_url=http%3A%2F%2Ftest.budgetease.com%2Fapi%2Fenvelopes&server_enable=true&server_status=200&server_credentials=false&server_tabs=remote
We first tried v1.1.0, and then also back to 1.0.4 with no impact to this issue.
I actually haven't used this option at all, but just reading through README.md it looks like there are missing quotes around the values for the new Stringy options.
Current:
Due to the 'Stringy' nature of external properties files, headers can be configured using a single line 'string' map:
cors.headers = ['Access-Control-Allow-Origin': 'http://app.example.com','My-Custom-Header': 'some value']
Should be:
Due to the 'Stringy' nature of external properties files, headers can be configured using a single line 'string' map:
cors.headers = "['Access-Control-Allow-Origin': 'http://app.example.com','My-Custom-Header': 'some value']"
And also Original:
Due to the 'Stringy' nature of external properties files, url patterns can be configured using a comma seperated string such as:
cors.url.pattern = /api/*, /api-docs/*
Should be:
Due to the 'Stringy' nature of external properties files, url patterns can be configured using a comma seperated string such as:
cors.url.pattern = "/api/*, /api-docs/*"
Hi, there's a section in the Readme that says:
Note that you can always send back '' instead of echoing the 'Origin' header by including:
cors.headers = ['Access-Control-Allow-Origin': '*']
This can be combined with cors.allow.origin.regex to limit allowed domains.
That last sentence is kind of confusing since I don't know, from the context, what are you referring to by "combining with allow origin regex to limit allowed domains". Wouldn't setting the cors.allow.origin.regex
property be enough since it would cancel out the *
in the Access-Control-Allow-Origin
?
Can you clarify this a little? Then I can fork the documentation and fix that part if you want to.
Thanks!
Hello,
If one uses the Resources plugin (http://grails.org/plugin/resources), then the CORS plugin won't work. This is because the Resources plugins put their filter mappings ahead of CORS. Resources accomplishes by using webxml plugin (see https://github.com/grails-plugins/grails-resources/blob/master/ResourcesGrailsPlugin.groovy#L60 and http://grails.org/plugin/webxml). The CORS plugin can fix this by also leveraging webxml plugin's getWebXmlFilterOrder.
def getWebXmlFilterOrder() {
def FilterManager = getClass().getClassLoader().loadClass('grails.plugin.webxml.FilterManager')
// Be before the earliest Resource filter.
['cors-headers': FilterManager.DEFAULT_POSITION - 400]
}
I have tested that works for me.
Steve
When I include the following in my BuildConfig.groovy, it cannot be resolved
runtime ":cors:1.1.6"
The error I get is:
::::::::::::::::::::::::::::::::::::::::::::::
:: UNRESOLVED DEPENDENCIES ::
::::::::::::::::::::::::::::::::::::::::::::::
:: org.grails.plugins#cors;1.1.6: not found
::::::::::::::::::::::::::::::::::::::::::::::
Not sure what's going on. Here is the repositories section of the BuildConfig.groovy:
repositories {
grailsPlugins()
grailsHome()
grailsCentral()
// uncomment the below to enable remote dependency resolution
// from public Maven repositories
mavenLocal()
mavenCentral()
mavenRepo "http://snapshots.repository.codehaus.org"
mavenRepo "http://repository.codehaus.org"
mavenRepo "http://download.java.net/maven/2/"
mavenRepo "http://repository.jboss.com/maven2/"
mavenRepo "http://repo.springsource.org/milestone"
mavenRepo "http://mavenrepo.google-api-java-client.googlecode.com/hg"
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.