No 'Access-Control-Allow-Origin' header is present on the requested resource. on the Pantheon Site - drupal

I have created a Webservice in Drupal 9 of the Pantheon (Locked) Site that I need to call from another domain. I have tried almost all the solutions I found but nothing is working.
services.yml
# Configure Cross-Site HTTP requests (CORS).
# Read https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
# for more information about the topic in general.
# Note: By default the configuration is disabled.
cors.config:
enabled: true
# Specify allowed headers, like 'x-allowed-header'.
allowedHeaders: ['x-csrf-token','authorization','content-type','accept','origin','x-requested-with', 'access-control-allow-origin','x-allowed-header','*']
# Specify allowed request methods, specify ['*'] to allow all possible ones.
allowedMethods: ['GET']
# Configure requests allowed from specific origins.
allowedOrigins: ['*']
# Sets the Access-Control-Expose-Headers header.
exposedHeaders: false
# Sets the Access-Control-Max-Age header.
maxAge: false
# Sets the Access-Control-Allow-Credentials header.
supportsCredentials: true
I am using this xhr to fetch the data.
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://***.pantheonsite.io/page/performance/', true);
xhr.withCredentials = true;
xhr.setRequestHeader('Authorization', 'Basic ' + btoa("test:123456!"));
xhr.setRequestHeader('Content-Type', 'text/html');
xhr.onload = function () {
if (xhr.status === 200) {
console.log(xhr.responseText);
} else {
console.error(xhr.statusText);
}
};
xhr.send();
Any help would be appreciated!

I tested this on my test site where I enabled CORS like this:
cors.config:
enabled: true
# Specify allowed headers, like 'x-allowed-header'.
allowedHeaders: ['x-csrf-token','authorization','content-type','accept','origin','x-requested-with', 'access-control-allow-origin','x-allowed-header','*']
# Specify allowed request methods, specify ['*'] to allow all possible ones.
allowedMethods: ['*']
# Configure requests allowed from specific origins. Do not include trailing
# slashes with URLs.
allowedOrigins: ['*']
# Sets the Access-Control-Expose-Headers header.
exposedHeaders: true
# Sets the Access-Control-Max-Age header.
maxAge: false
# Sets the Access-Control-Allow-Credentials header.
supportsCredentials: true
I also enabled basic auth from Pantheon dashboard. Then, I sent a request like this:
curl -I --location ‘https://<DOMAIN>/node/1?_format=json’ \
--header ‘Origin: https://example.com’ \
--header ‘Authorization: Basic <base64encoded>’
And got this as response:
HTTP/2 200
access-control-allow-origin: https://example.com
cache-control: max-age=3600, public
content-language: en
content-type: application/json
... lots more headers here
Which makes me think that it's working as expected.
If things are still not working for you, could you please provide some more info? (e.g. example request, example response)
Hope this helps!

Related

Vite self signed certificate error when calling local API

I created a simple Vue3 app, and I'm trying to call another local API (on a different port) on my machine. To better replicate the production server environment, I'm making a call to a relative API path. That means I need to use a proxy on the vite server to forward the API request to the correct localhost port for my local development. I defined my vite proxy like this in my vite.config.ts file:
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "#vitejs/plugin-vue";
import basicSsl from '#vitejs/plugin-basic-ssl'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
basicSsl(),
vue()
],
resolve: {
alias: {
"#": fileURLToPath(new URL("./src", import.meta.url)),
},
},
server: {
https: true,
proxy: {
'/api': {
target: 'https://localhost:44326', // The API is running locally via IIS on this port
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '') // The local API has a slightly different path
}
}
}
});
I'm successfully calling my API from the Vue app, but I get this error in the command line where I'm running the vite server:
5:15:14 PM [vite] http proxy error:
Error: self signed certificate
at TLSSocket.onConnectSecure (node:_tls_wrap:1530:34)
at TLSSocket.emit (node:events:526:28)
at TLSSocket._finishInit (node:_tls_wrap:944:8)
at TLSWrap.ssl.onhandshakedone (node:_tls_wrap:725:12)
I already tried to add the basic ssl package, and I don't particularly want to install the other NPM package that is in the top voted answer. Why does the vite server complain about a self signed certificate when I'm trying to call another API on my local machine? What can I do to fix this?
you could try secure: false
server: {
https: true,
proxy: {
'/api': {
target: 'https://localhost:44326', // The API is running locally via IIS on this port
changeOrigin: true,
secure: false,
rewrite: (path) => path.replace(/^\/api/, '') // The local API has a slightly different path
}
}
}
the set of full options is available at https://github.com/http-party/node-http-proxy#options
Options
httpProxy.createProxyServer supports the following options:
target: url string to be parsed with the url module
forward: url string to be parsed with the url module
agent: object to be passed to http(s).request (see Node's https agent and http agent objects)
ssl: object to be passed to https.createServer()
ws: true/false, if you want to proxy websockets
xfwd: true/false, adds x-forward headers
secure: true/false, if you want to verify the SSL Certs
toProxy: true/false, passes the absolute URL as the path (useful for proxying to proxies)
prependPath: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path
ignorePath: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request (note: you will have to append / manually if required).
localAddress: Local interface string to bind for outgoing connections
changeOrigin: true/false, Default: false - changes the origin of the host header to the target URL
preserveHeaderKeyCase: true/false, Default: false - specify whether you want to keep letter case of response header key
auth: Basic authentication i.e. 'user:password' to compute an Authorization header.
hostRewrite: rewrites the location hostname on (201/301/302/307/308) redirects.
autoRewrite: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false.
protocolRewrite: rewrites the location protocol on (201/301/302/307/308) redirects to 'http' or 'https'. Default: null.
cookieDomainRewrite: rewrites domain of set-cookie headers. Possible values:
false (default): disable cookie rewriting
String: new domain, for example cookieDomainRewrite: "new.domain". To remove the domain, use cookieDomainRewrite: "".
Object: mapping of domains to new domains, use "*" to match all domains.
For example keep one domain unchanged, rewrite one domain and remove other domains:
cookieDomainRewrite: {
"unchanged.domain": "unchanged.domain",
"old.domain": "new.domain",
"*": ""
}
cookiePathRewrite: rewrites path of set-cookie headers. Possible values:
false (default): disable cookie rewriting
String: new path, for example cookiePathRewrite: "/newPath/". To remove the path, use cookiePathRewrite: "". To set path to root use cookiePathRewrite: "/".
Object: mapping of paths to new paths, use "*" to match all paths.
For example, to keep one path unchanged, rewrite one path and remove other paths:
cookiePathRewrite: {
"/unchanged.path/": "/unchanged.path/",
"/old.path/": "/new.path/",
"*": ""
}
headers: object with extra headers to be added to target requests.
proxyTimeout: timeout (in millis) for outgoing proxy requests
timeout: timeout (in millis) for incoming requests
followRedirects: true/false, Default: false - specify whether you want to follow redirects
selfHandleResponse true/false, if set to true, none of the webOutgoing passes are called and it's your responsibility to appropriately return the response by listening and acting on the proxyRes event
buffer: stream of data to send as the request body. Maybe you have some middleware that consumes the request stream before proxying it on e.g. If you read the body of a request into a field called 'req.rawbody' you could restream this field in the buffer option:
'use strict';
const streamify = require('stream-array');
const HttpProxy = require('http-proxy');
const proxy = new HttpProxy();
module.exports = (req, res, next) => {
proxy.web(req, res, {
target: 'http://localhost:4003/',
buffer: streamify(req.rawBody)
}, next);
};

Getting input headers in openresty

I use openresty as nginx server with spnego-http-auth-nginx-module
This module replace request header Authorization: Negotiate YIIG... with Authorization: Basic ... and set REMOTE_USER header.
How to copy original Authorization header value to another custom header key to save original authorization header value?
This config snippet return needed data:
...
set_by_lua_block $xauth {
local inp = ngx.req.raw_header(true)
return string.match(inp, "Negotiate .*==")
}
uwsgi_param XAUTH $xauth;
...

ASP.NET 4.5 Rest API's work in Unity Android/iOS build but fails with "Unknown error" in Unity WebGL build

I have scoured every possible forum for this and somehow have not gotten my WebGL to consume my ASP.NET 4.5 REST API's.
From what I can tell it is possibly related to WebGL requiring CORS, but even enabling this I cannot get the game to communicate with my API's
So either there's something wrong with the way I have implemented global CORS settings in ASP.NET or something else is breaking.
To be clear these API's are running perfectly well on Android/iOS/Windows builds and even in the editor.
What I have done so far:
Installed the Microsoft CORS build as recommended by Microsoft's documentation relating to it, then added the following code to the WebAPIConfig class in Visual Studio:
public static void Register(HttpConfiguration config)
{
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
////new code
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
This is also in my web.config:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
</customHeaders>
</httpProtocol>
I need these settings global so I used the "*" as indicated by the documentation to include all domains, method types, and headers because I use ASP.NET token authentication for my API.
Here is a code snippet that gets the token in the Unity project (just to be clear, this works on other platforms, only throws an error in a WebGL build)
public IEnumerator login()
{
string url = API.ROUTEPATH + API.TOKEN;
WWWForm form = new WWWForm();
form.AddField("grant_type", "password");
form.AddField("username", API.APIUSERNAME);
form.AddField("password", API.APIPASSWORD);
UnityWebRequest uwr = UnityWebRequest.Post(url, form);
uwr.SetRequestHeader("Content-Type", "application/json");
yield return uwr.SendWebRequest();
try
{
if (uwr.isNetworkError)
{
Debug.Log(uwr.error);
}
else
{
APIAuthToken returnauth = JsonUtility.FromJson<APIAuthToken>(uwr.downloadHandler.text);
if (!string.IsNullOrEmpty(returnauth.access_token))
{
API.hasAuth = true;
API.token = returnauth.access_token;
Debug.Log(returnauth.access_token);
}
}
}
catch
{
}
}
uwr.error produces the following, very helpful error: Unknown Error So I'm not even sure if it is CORS related, it's just my best guess based on the research I have done, but even with multiple different implementations of it I still sit with the same error. So if it's not a problem with the API's and with my Unity code please just ignore the ASP.NET code snippet.
cURL - A simple curl -I <endpoint> or curl -X OPTIONS -v <endpoint> can reveal a ton of information about what is happening related to CORS. It can allow you to set different origins, check preflight responses, and more.
"Let's say you have a backend API that uses cookies for session management. Your game works great when testing on your own domain, but breaks horribly once you host the files on Kongregate due to the fact that your API requests are now cross-domain and subject to strict CORS rules."
Is this your problem?
Problably on both sides if things are not set up properly will refuse to send cookies, but its good, its mean you have the control to allow what domains your sessions cookies will be sent to.
So probably you need first to configure the server to allow multiplies origins but make sure to validate the value against a whitelist so that you aren't just enabling your session cookies to be sent to any origin domain.
Example on a Node Express with CORS middleware(game ID 12345) and an origin whitelist below:
express = require('express')
var cors = require('cors')
var app = express()
var whitelist = ['https://game12345.konggames.com'];
var corsOptions = {
credentials: true,
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
};
app.use(cors(corsOptions));
app.options('*', cors(corsOptions)); // Enable options for preflight
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(8080, () => console.log(`Example app listening on port 8080!`))
cURL command to check the headers for an OPTIONS preflight request from an origin in the whitelist array:
curl -X OPTIONS -H"Origin: https://game12345.konggames.com" -v http://localhost:8080/
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> OPTIONS / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.58.0
> Accept: */*
> Origin: https://game12345.konggames.com
>
< HTTP/1.1 204 No Content
< X-Powered-By: Express
< Access-Control-Allow-Origin: https://game12345.konggames.com
< Vary: Origin, Access-Control-Request-Headers
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
< Content-Length: 0
< Date: Tue, 24 Sep 2019 22:04:08 GMT
< Connection: keep-alive
<
* Connection #0 to host localhost left intact
instruct the client to include cookies when it makes a cross-domain request,If the preflight response did not include Access-Control-Allow-Credentials: true, or if your Access-Control-Allow-Access is set to a wildcard (*) then the cookies will not be sent and you are likely to see errors in your browser's Javascript console:
Access to XMLHttpRequest at 'https://api.mygamebackend.com' from origin 'https://game54321.konggames.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: 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.
Unity's UnityWebRequest and the older WWW classes use XMLHttpRequest under the hood to fetch data from remote servers. Since there is no option to set the withCredentials flag to true, we have to perform a pretty dirty hack when initializing our application in order to turn that on for the appropriate requests.
In your WebGL template or generated index.html:
<script>
XMLHttpRequest.prototype.originalOpen = XMLHttpRequest.prototype.open;
var newOpen = function(_, url) {
var original = this.originalOpen.apply(this, arguments);
if (url.indexOf('https://api.mygamebackend.com') === 0) {
this.withCredentials = true;
}
return original;
}
XMLHttpRequest.prototype.open = newOpen;
</script>
This snippet of code overrides the open method of XMLHttpRequest so that we can conditionally set withCredentials equal to true when desired. Once this is in place, cross-origin cookies should begin working between the Kongregate-hosted iframe domain and the game's backend servers!
info taken from here
also looks nice for this

woocommerce rest api: can't get preflight request to pass

I have a woocommerce site and I want its REST API to be open to the world.
I have learned that CORS headers need to be set, so I google and setup the following hook:
add_action('rest_api_init', function() {
remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
add_filter('rest_pre_serve_request', function( $value ) {
header( 'Access-Control-Allow-Origin: *' );
header( 'Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, PATCH, DELETE' );
header( 'Access-Control-Allow-Credentials: true' );
header('Access-Control-Allow-Headers: Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Origin,Content-Type,X-Auth-Token,Content-Range,Range');
return $value;
});
}, 15);
I confirmed that my server is responding with the correct CORS headers:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers:
Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Origin,Content-Type,X-Auth-Token,Content-Range,Range
Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, PATCH, DELETE
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: X-WP-Total, X-WP-TotalPages
Then I headed to code the client side:
xhr = new XMLHttpRequest();
xhr.open('POST', 'https://..../wp-json/wc/v3/products');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Authorization', 'Basic ' + btoa('mykey:mysecret'));
xhr.send(JSON.stirngify({ ... });
Above code was entered in Chrome console under a https://google.com tab. I just can't get the preflight request to work, here are the errors:
OPTIONS https://..../wp-json/wc/v3/products 401 (Unauthorized)
Access to XMLHttpRequest at 'https://..../wp-json/wc/v3/products' from origin
'https://www.google.com' has been blocked by CORS policy: Response to
preflight request doesn't pass access control check: It does not have
HTTP ok status.
Even though the response headers are exactly like posted above.
What am I doing wrong?
if you are using: "Access-Control-Allow-Credentials" = true make sure that "Access-Control-Allow-Origin" is not "*", it must be set with a proper domain!

asp.net Web Api 2 POST [duplicate]

I'm calling this function from my asp.net form and getting following error on firebug console while calling ajax.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://anotherdomain/test.json. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
var url= 'http://anotherdomain/test.json';
$.ajax({
url: url,
crossOrigin: true,
type: 'GET',
xhrFields: { withCredentials: true },
accept: 'application/json'
}).done(function (data) {
alert(data);
}).fail(function (xhr, textStatus, error) {
var title, message;
switch (xhr.status) {
case 403:
title = xhr.responseJSON.errorSummary;
message = 'Please login to your server before running the test.';
break;
default:
title = 'Invalid URL or Cross-Origin Request Blocked';
message = 'You must explictly add this site (' + window.location.origin + ') to the list of allowed websites in your server.';
break;
}
});
I've done alternate way but still unable to find the solution.
Note: I've no server rights to make server side(API/URL) changes.
This happens generally when you try access another domain's resources.
This is a security feature for avoiding everyone freely accessing any resources of that domain (which can be accessed for example to have an exact same copy of your website on a pirate domain).
The header of the response, even if it's 200OK do not allow other origins (domains, port) to access the resources.
You can fix this problem if you are the owner of both domains:
Solution 1: via .htaccess
To change that, you can write this in the .htaccess of the requested domain file:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
If you only want to give access to one domain, the .htaccess should look like this:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin 'https://my-domain.example'
</IfModule>
Solution 2: set headers the correct way
If you set this into the response header of the requested file, you will allow everyone to access the resources:
Access-Control-Allow-Origin : *
OR
Access-Control-Allow-Origin : http://www.my-domain.example
Server side put this on top of .php:
header('Access-Control-Allow-Origin: *');
You can set specific domain restriction access:
header('Access-Control-Allow-Origin: https://www.example.com')
in your ajax request, adding:
dataType: "jsonp",
after line :
type: 'GET',
should solve this problem ..
hope this help you
If you are using Express js in backend you can install the package cors, and then use it in your server like this :
const cors = require("cors");
app.use(cors());
This fixed my issue
This worked for me:
Create php file that will download content of another domain page without using js:
<?
//file name: your_php_page.php
echo file_get_contents('http://anotherdomain/test.json');
?>
Then run it in ajax (jquery). Example:
$.ajax({
url: your_php_page.php,
//optional data might be usefull
//type: 'GET',
//dataType: "jsonp",
//dataType: 'xml',
context: document.body
}).done(function(data) {
alert("data");
});
You have to modify your server side code, as given below
public class CorsResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
responseContext.getHeaders().add("Access-Control-Allow-Origin","*");
responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
}
}
You must have got the idea why you are getting this problem after going through above answers.
self.send_header('Access-Control-Allow-Origin', '*')
You just have to add the above line in your server side.
In a pinch, you can use this Chrome Extension to disable CORS on your local browser.
Allow CORS: Access-Control-Allow-Origin Chrome Extension

Resources