grails REST API with Spring Security core and CORS plugins not working for OPTIONS http method requests - angularjs

Trying to do cross-domain request [CORS] from AngularJS front-end to Grails 2.3.1 RESTful Service on other server.
AngularJS sends OPTIONS http request first for any cross-domain requests.
To support this, I added following method to my Controller that extends RestfulController
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE", options: "OPTIONS", trace: "TRACE", head: "HEAD"]
#Secured(value=['permitAll'], httpMethod='OPTIONS')
def options() {
log.debug("i am in options method")
response.setHeader("Allow", "GET,POST,PUT,DELETE,OPTIONS,TRACE,HEAD")
return
}
For cURL command bellow, my options() method on my Controller never getting called. curl always gets 301 response.
curl -H "Origin: http://example.com" -X OPTIONS --verbose http://localhost:8080/Console/tenants/1/spaces.xml
Is this a bug in Spring Security core plugin or am I missing something?
My environment consists, Grails 2.3.1, Spring Security Core and ACL 2.0-RC1 plugins and CORS plugin 1.1.1

That's because the browser checks for cross domain requests before your action. You can do that using a servlet filter, or just use the CORS Grails plugin.

using latest CORS Grails plugin solves the problem. It includes a filter that intercept OPTIONS request and provide the response.

Related

Enable CORS in an Angular Paypal Docker application

My application with angular front end and springboot backend is trying to make a REST POST call to one of the PayPal APIs from Angular front end. The application is deployed as a Docker container in GCP VM instance. If I dont open the broser with web security disabled I get the ERROR
"Access to XMLHttpRequest at 'https://pilot-payflowpro.paypal.com/' from origin 'http://myserverip' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource."
I see lot of answers for this question in SO and others with adding headers in httpd.conf / .htaccess files. But I dont have both these files. I tried adding headers to Dockerfile and also adding commands to docker-compose.yaml file. Also tried adding the end URL in angular proxy configuration file. None of it worked.
Is there any way to enable CORS either in a docker config file or in the server itself.
docker-compose.yml
image: docker.image.link
privileged: true
ports:
- '80:8080'
restart: 'no'
volumes:
- '/var/sftp/upload:/usr/share/invoice/invoiceFile'
environment:
- SPRING_PROFILES_ACTIVE=docker
- DB_CONN_STRING=jdbc:postgresql:url
- DB_USER=postgres
- DB_PASS=postgres
- HOST_NAME=hostname
- SMTP_HOST=smtphost
- SMTP_PORT=25
- SMTP_AUTH_TRUE_FALSE=false
Dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
ADD target/${JAR_FILE} /usr/share/application.jar
ADD template/ /usr/share/template
VOLUME /tmp
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/usr/share/application.jar"]
The CORS error is an error emitted by the browser when the request response, from the backend, hasn't the properly headers to tell to the browser that this client can perform/view the request.
So, in your case the backend is the PayPal (https://pilot-payflowpro.paypal.com/ -> paypal.com) not your backend, so even if you add any headers to your backend or frontend, the problem will persist because the only header that is important when you perform the request to the https://pilot-payflowpro.paypal.com/ is the header from the response of this request.
To solve this problem the https://pilot-payflowpro.paypal.com/ needs to send the correct header response allowing you to perform this request, and I think it's not possible because security reasons.
Some endpoints can't be use from a frontend application, only from a backend, and I think it's your case.
To avoid the CORS problem you can create an endpoint in your backend that call the https://pilot-payflowpro.paypal.com/. So, in your frontend you call your backend endpoint and the backend call the PayPal API.
calling the REST call is one solution. Another solution would be to mask the endpoint URL in the proxy configuration in Angular.
"/paypal" : {
"target" : "https://pilot-payflowpro.paypal.com/",
"secure" : true,
"changeOrigin": true,
"pathRewrite":{
"^/paypal":""
}
}
And calling /paypal where we have to do the REST call.

CORS error on Axios PUT request from React to Spring API

I am working on an update functionality using PUT. I have a React front end and Spring back-end API. Here is the following PUT request made from front-end:
updateStuff(username, id, stuff){
return Axios.put(`http://localhost:8080/stuff/${username}`, {stuff})
}
Controller to handle this request:
#RestController
#CrossOrigin(origins="http://localhost:3000")
public class StuffController {
#Autowired
private StuffService stuffService;
#PutMapping(path="/stuff/{username}/{id}")
public ResponseEntity<Stuff> updateStuff(#PathVariable String username,
#PathVariable long id,
#RequestBody Stuff stuff) {
Stuff response = stuffService.save(stuff);
return new ResponseEntity<Stuff>(stuff, HttpStatus.OK);
}
I am able to use the same service for GET and DELETE. I am also able to send request using REST client. But when I am trying using browser I am getting this error in console:
Access to XMLHttpRequest at 'http://localhost:8080/stuff/abc' from origin
'http://localhost:3000' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No 'Access-
Control-Allow-Origin' header is present on the requested resource.
PUT http://localhost:8080/stuff/abc net::ERR_FAILED
Not able to figure out why its just happening for PUT request? How to resolve this? Appreciate your help and time!
EDIT:
Updated the front-end to:
updateStuff(username, id, stuff){
return Axios.put(`http://localhost:8080/stuff/${username}`, {
headers:{
'Access-Control-Allow-Origin':'*',
'Content-Type': 'application/json;charset=UTF-8',
}
})
}
Still its throwing the same error. So far Spring Security is not configured. I am just checking a simple update flow without any authentication or authorization.
EDIT 2: Request headers in browser has Access-Control-Allow-Origin: *:
I ran into a similar issue a while ago. Check if the variables of your model class in the backend have the same name as in your frontend. That fixed it for me.
The best way to deal with this cors policy is to add a proxy field in the pakage.json file.enter image description here
In reactjs application you can use your spring boot api's URL as proxy to avoid CORS issue.
package.
package.json
{
"proxy": "http://localhost:8080/",
"dependencies": {
.
.
.
}
}
axios
Axios.put(stuff/${username}, {stuff})

How to allow CORS in Google Cloud Endpoints?

As stated in the January 2017 Endpoints release notes, I tried to update my openapi.yaml file to stop the Extensible Service Proxy (ESP) from blocking cross-origin requests by adding to x-google-endpoints:
swagger: "2.0"
info:
description: "Market scan using technical indicators."
title: "Talib Test"
version: "1.0.0"
host: "YOUR-PROJECT-ID.appspot.com"
x-google-endpoints:
- name: "YOUR-PROJECT-ID.appspot.com"
allowCors: "true"
basePath: "/"
consumes:
- "application/json"
produces:
- "application/json"
schemes:
- "http"
...
I continue to get an error in the browser when trying to make http calls from my angular application. The error is in both developer mode and after I deploy my angular application:
XMLHttpRequest cannot load
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
When i look at Google Cloud logging I see that requestMethod:"OPTIONS" and status:200. The API is a POST method so I'm guessing it's the ESP blocking the request. Also, I have allowed CORS in my python application using FLASK-CORS so it should be working.
My application has two services that are both on Google App Engine. The first is Standard Envrionment. The second, which I am having issues with is Flexible Environment. I am using a dispatch.yaml file and separate openapi.yaml files if that's relevant. Also, the API works on hurl it and postman.
Any help would be awesome!
Most likely your backend application did not handle CORS OPTIONS correctly.
If "allowCors" is true, Endpoint proxy will pass the request to your backend application. Proxy will not add anything to the request. If "allowCors" is false, proxy will return 404.

Enabling CORS in Azure Service Fabric Web Api

I have an angular app that sends an http request to my Service Fabric Web API (deployed on a Secure Service Fabric cluster) like so:
$scope.request_headers = {
"Content-Type": "application/xml; charset=utf-8",
"Access-Control-Allow-Origin":"*"
}
$http({
url: "Service_Fabric_web_api_url",
method: "GET",
headers:$scope.request_headers
}).
then(function (result) {
console.log(result);
});
I've also enabled CORS globally in my web api startup class like so:
HttpConfiguration config = new HttpConfiguration();
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
When I run my angular app locally and try sending the http request, I still get this error:
XMLHttpRequest cannot load Service_Fabric_web_api_url. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:xxxxx' is therefore not allowed access. The response had HTTP status code 500.
I'm able to access my service directly from my browser with the same url.
Also, the same http request works when I tried deploying my Web Api on an unsecure Service Fabric Cluster with the same lines added to the startup class to enable CORS.
Why is this happening even though I've enabled CORS globally in my Web API and particularly when its on a secure cluster?
In your Startup.cs class, do you have this line? :
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
}
There are also a couple NuGet packages associated with Cors:
<package id="Microsoft.AspNet.Cors" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.Owin.Cors" version="3.0.1" targetFramework="net45" />
The CORS message is a red herring. If you look at the end of the error message you'll see this:
The response had HTTP status code 500.
Usually the response will include some detail about the error. I suggest using a tool like Fiddler with HTTPS decryption enabled so you can see the content of the response.

Call Django API running on a server from Angular running locally

I am learning with Django and Angular.
I have setup a Django API back-end on on http://serverip:8666/athletics/
I have created a small Angular application that I am running from my local machine.
The following code in my Angular app:
$scope.list_athletes = function(){
console.log('hey');
$http
.get('http://serverip:8666/athletics/')
.success(function (result) {
console.log('success');
})
}
generates the error:
XMLHttpRequest cannot load http://serverip:8666/athletics/. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://127.0.0.1:65356' is therefore not allowed
access.
What causes this error? How can I resolve it so that I can access the Django API from my local Angular app?
The problem you're having is related to not having CORS enabled.
As a security policy, JavaScript can't make requests across domains while running in your browser. This is meant to prevent untrusted code from executing without the user's knowledge. The workaround is to enable CORS by white listing domains.
You need to set the Access-Control-Allow-Origin response header in your responses like so:
def my_view(request):
data = json.dumps({'foo':'bar'})
response = HttpResponse(data)
response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:65356'
return response
This will enable CORS for your angular app. You can even add django-cors-headers to your project to have this functionality implemented for you. This can be added to any Django response object, such as django.http.repsonse.HttpResponse. Because you appear to be using a DRF Response object, you may need to use something like
return Response(serializer.data, headers={'Access-Control-Allow-Origin': 'http://127.0.0.1:65356'})
to set your response headers.
You should also check out this site for more information on how to enable CORS in your webapp.
Have you done the settings part in settings.py
INSTALLED_APPS = (
'corsheaders',
)
MIDDLEWARE_CLASSES = (
'corsheaders.middleware.CorsMiddleware',
)
CORS_ORIGIN_WHITELIST = (
'http://127.0.0.1:65356'
)
And also include CORS_ALLOW_CREDENTIALS, CORS_ALLOW_HEADERS settings

Resources