How to enable CORS as I dont have WebApiConfig.cs - asp.net

I want to enable CORS on my controller in ASP website. The tutorials show that I have to change WebApiConfig.cs and add a line config.EnableCors();
The problem is I dont have this file. The closes I have is RouteConfig.cs, where do enable CORS in my project then?
I have added the following section in web.config file
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
but the Ajax calls to the API's still return
the server responded with a status of 405 (Method Not Allowed)
When I call the API using the browser, it works.

CORS or Cross-Origin Resource Sharing is used for cross domain communication from the browser. The endpoint you're calling from the browser is the one to tell the browser if the request is allowed to be fulfilled and processed by the browser or not by sending Access-Control-* headers in the response.
When the browser receives the response it first checks if Access-Control-* headers exist and if the information in them matches your request, if they exist and the information in them matches the request then the browser will allow your custom client code to process the response, if headers are not there or the information in the headers do not match the request you made then the browser will block the response for any further processing.
What you have to do is to set those headers in your response.
For further reading about CORS headers: W3C CORS

Related

ASP.NET WebAPI2 and AngularJS

I'm using firefox to perform a connection between an AngularJS/HTML client page and a controller on the ASP.NET WebAPI.
The issue is that I keep getting the "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost:44377/project/all. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)." unless I enable the CORS firefox extension.
Even with that enabled, my page doesn't seem to be grabbing the required data; but the errors are gone.
[EnableCors(origins: "https://localhost:PortNumberHereWithoutTheForwardSlah", headers: "", methods: "")] above my Controller:ApiController and used the config.EnableCors(); in the WebApi.Config in App_Start.
Note: the method that uses [HttpGet] does work when I try to use it in my browser.
</system.webServer> Thanks, but I found inserting this between /handlers and /system.webServer in Web.config to be more flexible from another post.

Browser cache not expiring

I am developing my application in asp.net and wanted force refreshing of .js files after certain period of time. In order to test that in local environment, I made following change to my web.config file:
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="must-revalidate max-age=120" />
</customHeaders>
</httpProtocol>
As I understand cache-control, based on above settings, browser cache should expire after 2:00 minutes and any new postback should send a request to webserver to check if newer version of .js is avialable or not. I used fiddler to monitor network traffic and I don't see any request for js file. The browser I am using is Chrome. So I used dev tools to monitor network traffic. I see that the browser is using cached version of that file.
Are there any other settings that would force the browser to expire the cached files?
Your Cache-Control is invalid, try separate values by comma: must-revalidate, max-age=120.
Relevant excerpt from RFC 7234 Hypertext Transfer Protocol (HTTP/1.1): Caching:
Cache-Control = 1#cache-directive
cache-directive = token [ "=" ( token / quoted-string ) ]
And ABNF List Extension from RFC 7230 Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing:
A construct "#" is defined, similar to "*", for defining
comma-delimited lists of elements. The full form is "<n>#<m>element"
indicating at least <n> and at most <m> elements, each separated by a
single comma (",") and optional whitespace (OWS).
Also make sure to put new configuration in right place. For more information check Is it possible to add response http headers in web.config?.

Why is an OPTIONS request sent and can I disable it?

I am building a web API. I found whenever I use Chrome to POST, GET to my API, there is always an OPTIONS request sent before the real request, which is quite annoying. Currently, I get the server to ignore any OPTIONS requests. Now my question is what's good to send an OPTIONS request to double the server's load? Is there any way to completely stop the browser from sending OPTIONS requests?
edit 2018-09-13: added some precisions about this pre-flight request and how to avoid it at the end of this reponse.
OPTIONS requests are what we call pre-flight requests in Cross-origin resource sharing (CORS).
They are necessary when you're making requests across different origins in specific situations.
This pre-flight request is made by some browsers as a safety measure to ensure that the request being done is trusted by the server.
Meaning the server understands that the method, origin and headers being sent on the request are safe to act upon.
Your server should not ignore but handle these requests whenever you're attempting to do cross origin requests.
A good resource can be found here http://enable-cors.org/
A way to handle these to get comfortable is to ensure that for any path with OPTIONS method the server sends a response with this header
Access-Control-Allow-Origin: *
This will tell the browser that the server is willing to answer requests from any origin.
For more information on how to add CORS support to your server see the following flowchart
http://www.html5rocks.com/static/images/cors_server_flowchart.png
edit 2018-09-13
CORS OPTIONS request is triggered only in somes cases, as explained in MDN docs:
Some requests don’t trigger a CORS preflight. Those are called “simple requests” in this article, though the Fetch spec (which defines CORS) doesn’t use that term. A request that doesn’t trigger a CORS preflight—a so-called “simple request”—is one that meets all the following conditions:
The only allowed methods are:
GET
HEAD
POST
Apart from the headers set automatically by the user agent (for example, Connection, User-Agent, or any of the other headers with names defined in the Fetch spec as a “forbidden header name”), the only headers which are allowed to be manually set are those which the Fetch spec defines as being a “CORS-safelisted request-header”, which are:
Accept
Accept-Language
Content-Language
Content-Type (but note the additional requirements below)
DPR
Downlink
Save-Data
Viewport-Width
Width
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
No event listeners are registered on any XMLHttpRequestUpload object used in the request; these are accessed using the XMLHttpRequest.upload property.
No ReadableStream object is used in the request.
Have gone through this issue, below is my conclusion to this issue and my solution.
According to the CORS strategy (highly recommend you read about it) You can't just force the browser to stop sending OPTIONS request if it thinks it needs to.
There are two ways you can work around it:
Make sure your request is a "simple request"
Set Access-Control-Max-Age for the OPTIONS request
Simple request
A simple cross-site request is one that meets all the following conditions:
The only allowed methods are:
GET
HEAD
POST
Apart from the headers set automatically by the user agent (e.g. Connection, User-Agent, etc.), the only headers which are allowed to be manually set are:
Accept
Accept-Language
Content-Language
Content-Type
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
A simple request will not cause a pre-flight OPTIONS request.
Set a cache for the OPTIONS check
You can set a Access-Control-Max-Age for the OPTIONS request, so that it will not check the permission again until it is expired.
Access-Control-Max-Age gives the value in seconds for how long the response to the preflight request can be cached for without sending another preflight request.
Limitation Noted
For Chrome, the maximum seconds for Access-Control-Max-Age is 600 which is 10 minutes, according to chrome source code
Access-Control-Max-Age only works for one resource every time, for example, GET requests with same URL path but different queries will be treated as different resources. So the request to the second resource will still trigger a preflight request.
Please refer this answer on the actual need for pre-flighted OPTIONS request: CORS - What is the motivation behind introducing preflight requests?
To disable the OPTIONS request, below conditions must be satisfied for ajax request:
Request does not set custom HTTP headers like 'application/xml' or 'application/json' etc
The request method has to be one of GET, HEAD or POST. If POST, content type should be one of application/x-www-form-urlencoded, multipart/form-data, or text/plain
Reference:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
When you have the debug console open and the Disable Cache option turned on, preflight requests will always be sent (i.e. before each and every request). if you don't disable the cache, a pre-flight request will be sent only once (per server)
Yes it's possible to avoid options request. Options request is a preflight request when you send (post) any data to another domain. It's a browser security issue. But we can use another technology: iframe transport layer. I strongly recommend you forget about any CORS configuration and use readymade solution and it will work anywhere.
Take a look here:
https://github.com/jpillora/xdomain
And working example:
http://jpillora.com/xdomain/
For a developer who understands the reason it exists but needs to access an API that doesn't handle OPTIONS calls without auth, I need a temporary answer so I can develop locally until the API owner adds proper SPA CORS support or I get a proxy API up and running.
I found you can disable CORS in Safari and Chrome on a Mac.
Disable same origin policy in Chrome
Chrome: Quit Chrome, open an terminal and paste this command: open /Applications/Google\ Chrome.app --args --disable-web-security --user-data-dir
Safari: Disabling same-origin policy in Safari
If you want to disable the same-origin policy on Safari (I have 9.1.1), then you only need to enable the developer menu, and select "Disable Cross-Origin Restrictions" from the develop menu.
As mentioned in previous posts already, OPTIONS requests are there for a reason. If you have an issue with large response times from your server (e.g. overseas connection) you can also have your browser cache the preflight requests.
Have your server reply with the Access-Control-Max-Age header and for requests that go to the same endpoint the preflight request will have been cached and not occur anymore.
I have solved this problem like.
if($_SERVER['REQUEST_METHOD'] == 'OPTIONS' && ENV == 'devel') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: X-Requested-With');
header("HTTP/1.1 200 OK");
die();
}
It is only for development. With this I am waiting 9ms and 500ms and not 8s and 500ms. I can do that because production JS app will be on the same machine as production so there will be no OPTIONS but development is my local.
You can't but you could avoid CORS using JSONP.
you can also use a API Manager (like Open Sources Gravitee.io) to prevent CORS issues between frontend app and backend services by manipulating headers in preflight.
Header used in response to a preflight request to indicate which HTTP headers can be used when making the actual request :
content-type
access-control-allow-header
authorization
x-requested-with
and specify the "allow-origin" = localhost:4200 for example
After spending a whole day and a half trying to work through a similar problem I found it had to do with IIS.
My Web API project was set up as follows:
// WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
//...
}
I did not have CORS specific config options in the web.config > system.webServer node like I have seen in so many posts
No CORS specific code in the global.asax or in the controller as a decorator
The problem was the app pool settings.
The managed pipeline mode was set to classic (changed it to integrated) and the Identity was set to Network Service (changed it to ApplicationPoolIdentity)
Changing those settings (and refreshing the app pool) fixed it for me.
OPTIONS request is a feature of web browsers, so it's not easy to disable it. But I found a way to redirect it away with proxy. It's useful in case that the service endpoint just cannot handle CORS/OPTIONS yet, maybe still under development, or mal-configured.
Steps:
Setup a reverse proxy for such requests with tools of choice (nginx, YARP, ...)
Create an endpoint just to handle the OPTIONS request. It might be easier to create a normal empty endpoint, and make sure it handles CORS well.
Configure two sets of rules for the proxy. One is to route all OPTIONS requests to the dummy endpoint above. Another to route all other requests to actual endpoint in question.
Update the web site to use proxy instead.
Basically this approach is to cheat browser that OPTIONS request works. Considering CORS is not to enhance security, but to relax the same-origin policy, I hope this trick could work for a while. :)
One solution I have used in the past - lets say your site is on mydomain.com, and you need to make an ajax request to foreigndomain.com
Configure an IIS rewrite from your domain to the foreign domain - e.g.
<rewrite>
<rules>
<rule name="ForeignRewrite" stopProcessing="true">
<match url="^api/v1/(.*)$" />
<action type="Rewrite" url="https://foreigndomain.com/{R:1}" />
</rule>
</rules>
</rewrite>
on your mydomain.com site - you can then make a same origin request, and there's no need for any options request :)
It can be solved in case of use of a proxy that intercept the request and write the appropriate headers.
In the particular case of Varnish these would be the rules:
if (req.http.host == "CUSTOM_URL" ) {
set resp.http.Access-Control-Allow-Origin = "*";
if (req.method == "OPTIONS") {
set resp.http.Access-Control-Max-Age = "1728000";
set resp.http.Access-Control-Allow-Methods = "GET, POST, PUT, DELETE, PATCH, OPTIONS";
set resp.http.Access-Control-Allow-Headers = "Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since";
set resp.http.Content-Length = "0";
set resp.http.Content-Type = "text/plain charset=UTF-8";
set resp.status = 204;
}
}
What worked for me was to import "github.com/gorilla/handlers" and then use it this way:
router := mux.NewRouter()
router.HandleFunc("/config", getConfig).Methods("GET")
router.HandleFunc("/config/emcServer", createEmcServers).Methods("POST")
headersOk := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type"})
originsOk := handlers.AllowedOrigins([]string{"*"})
methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "OPTIONS"})
log.Fatal(http.ListenAndServe(":" + webServicePort, handlers.CORS(originsOk, headersOk, methodsOk)(router)))
As soon as I executed an Ajax POST request and attaching JSON data to it, Chrome would always add the Content-Type header which was not in my previous AllowedHeaders config.

CORS error - No 'Access-Control-Allow-Origin' header is present on the requested resource

I am using an Angular front end to connect to a WEB API 2 backend. The failing use case is the following. When a user registers, on successful registration, they must be logged into the system and be redirected to a new page to collect further information. I am using TOKENS for authentication.
I have enabled CORS in the WebAPI config:
var cors = new EnableCorsAttribute("http://localhost:7812", "*", "*");
config.EnableCors(cors);
The registration request is successful and the response headers have the required CORS headers:
**Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://localhost:7812**
Content-Length:0
Date:Sun, 24 Aug 2014 09:31:55 GMT
Server:Microsoft-IIS/8.0
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcUHJvamVjdHNcVGVzdGluZ1xNYWx0QXBhcnRtZW50c1xNYWx0YXBhcnRtZW50cy5BUElcTWFsdGFwYXJ0bWVudHMuQVBJXGFwaVxhY2NvdW50XHJlZ2lzdGVy?=
In the next step I attempt to log in the user to the system. As part of the login, the front end requests a TOKEN from the server at Request URL:http://localhost:7802/token. The request header once again sends a Origin header Origin:http://localhost:7812 but this time I get the error : XMLHttpRequest cannot load http://localhost:7802/token. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:7812' is therefore not allowed access.
Anyone have any ideas?
When dealing with CORS, we need to keep in mind that there may be two requests sent by the browsers for a non GET request. There is usually the preflight (OPTIONS) request and then the actual request (POST). During the preflight requests, the server needs to add the Access-Control-Allow-Origin header with the value matching the request Origin header. This authorizes the subsequent request to be sent.
For the subsequent/actual request, the server also needs to add the Access-Control-Allow-Origin header. Otherwise, this request fails.
When using the OWIN OAuthAuthorizationServerProvider, we need to customize the MatchEndpoint handler to manage the header logic. This handler is executed before validate client authentication.
For more background information, look at this link: http://www.ozkary.com/2016/04/web-api-owin-cors-handling-no-access.html
It's because of Preflighted requests.
Read these articles for solutions:
How to make CORS Authentication in WebAPI 2?
http://www.codeproject.com/Articles/617892/Using-CORS-in-ASP-NET-WebAPI-Without-Being-a-Rocke
I believe you got two problems :
1- With Web API 2, you need to add the header manually when you grant the bearer token.
2- Your data needs to be url encoded, so you need to intercept the $http post message to encode the data.
refer to my article which I use Web API 2 from an AngularJS client side.
http://www.codeproject.com/Articles/742532/Using-Web-API-Individual-User-Account-plus-CORS-En
Hope that helps.
Use these line in web.config :
<system.webServer>
<modules>
<remove name="WebDAVModule" />
...
</modules>
<handlers>
<remove name="WebDAV" />
...
</handlers>
</system.webServer>
Its fixes my problem, may be it also help you.

CORS POST Requests not working - OPTIONS (Bad Request) - The origin is not allowed

I'm having a lot of trouble getting a cross domain POST request to hit an Api controller in the latest beta 2 release.
Chrome (and other browsers) spit out:
OPTIONS http://api.hybridwebapp.com/api/values 400 (Bad Request)
POST http://api.hybridwebapp.com/api/values 404 (Not Found)
It may be related to this issue but I have applied that workaround and several other fixes such as web.config additions here
I've been banging my head with this for a while so I created a solution to reproduce the problem exactly.
Load the web app there will be 2 buttons one for GET one for POST and the response will appear next to the button. GET works. Cannot get POST to return successfully.
I'm able to get a hint at the cause from Fiddler but it makes no sense because if you look at the response it DOES include the domain in the Access-Controll-Allow-Origin header:
There is a folder in the solution called "ConfigurationScreenshots" with a few screenshots of the IIS configuration (website bindings) and Project properties configurations to make it as easy as possible to help me :)
EDIT: Don't forget to add this entry to host file (%SystemRoot%\system32\drivers\etc):
127.0.0.1 hybridwebapp.com api.hybridwebapp.com
**STATUS: ** It seems that some browsers like Chrome allow me to proceed with the POST regardless of the error message in the OPTIONS response (while others like Firefox don't). But I don't consider that solved.
Look at the Fidler screenshots of the OPTIONS request it has
Access-Control-Allow-Origin: http://hybridwebapp.com
And yet the error:
The origin http://hybridwebapp.com is not allowed
That is completely contradictory it's as if it's ignoring the header.
Ok I got past this. This has got to be the strangest issue I've ever encountered. Here's how to "solve" it:
Continue on with life as usual until suddenly out of no where OPTIONS requests to this domain begin returning 200 OK (instead of 400 Bad Request) and POST never happens (or at least seems like it doesn't because the browser swallows it)
Realize that Fiddler's OPTIONS response mysteriously contains duplicates for "Access-Control-Allow-XXX".
Try removing the following statement from you web.config even though you clearly remember trying that to fix the previous issue and it not working:
Remove this:
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
<add name="Access-Control-Allow-Origin" value="http://mydomain.com" />
<add name="Access-Control-Allow-Headers" value="Accept, Content-Type, Origin" />
<add name="Access-Control-Allow-Methods" value="GET, PUT, POST, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
Because you already have this:
var enableCorsAttribute = new EnableCorsAttribute("http://mydomain.com",
"Origin, Content-Type, Accept",
"GET, PUT, POST, DELETE, OPTIONS");
config.EnableCors(enableCorsAttribute);
Moral: You only need one.
if you use OAuth Authorization . request not go direct to web api. You need to enable OWIN CORS support for that endpoint.
How i do on my site:
Install owin cors
Install-Package Microsoft.Owin.Cors
Note: please not use : Install-Package Microsoft.AspNet.WebApi.Cors
In file Startup.Auth.cs
//add this line
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
I have an MVC controller (not an ApiController) but the solution I came up with may help others. To allow cross domain access to a POST action (/data/xlsx) on the controller I implemented 2 actions:
for the pre-flight check
for the post
If you don't have the HttpOptions action then you get 404's on the pre-flight check.
Code:
[HttpOptions]
public ActionResult Xlsx()
{
// Catches and authorises pre-flight requests for /data/xlsx from remote domains
Response.AddHeader("Access-Control-Allow-Origin", "*");
Response.AddHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
Response.AddHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
return null;
}
[HttpPost]
public ActionResult Xlsx(string data, string name)
{
Xlsx(); // Add CORS headers
/* ... implementation here ... */
}
I've tested it in IE 11, Chrome, FireFox.
Add this to your startup.cs file inside ConfigureOAuth
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
Try to add below code in your Response header:
Response.AddHeader("Access-Control-Allow-Origin", "*");

Resources