How to remove unwanted WWW-Authenticate headers - asp.net-mvc-3

From an MVC app, I'm sourcing an iCal subscription with authentication following the answer to this SO question:
Serving an iCalendar file in ASPNET MVC with authentication
The iCal stream is being created dynamically from events in the DB using the DDay.iCal library.
This solution works fine on the local development server: both OSX Calendar and Outlook can subscribe to and receive updates from the app.
However, on the shared server at my web host, the authentication fails for both Calendar and Outlook. That is, they both keep asking me for user & password after the (correct) ones fail.
EDIT: If I point a browser at the calendar URL it also fails authentication.
EDIT: Getting weirder—Firefox authenticates and gets the iCal file. Safari, Chrome and IE fail authentication.
If I point curl at the calendar URL with the same credentials I'm successful (i.e. I get the desired iCal file). And, of course, the same credentials can be used to login to the MVC app.
EDIT — I think I know what's going on, but I don't know how to fix it. In my OnAuthorization() I add only WWW-Authentication Basic but with Fiddler I can see that three types of authentication are offered:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Secure Calendar"
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
... etc ...
At this point only Firefox responds with Basic Authorization, which succeeds.
GET <<URL>> HTTP/1.1
...
Authorization: Basic <<encoded credentials>>
IE responds with Negotiate, which fails
GET <<URL>> HTTP/1.1
...
Authorization Negotiate <<encoded stuff>>
Who is adding the other two and how can I make it stop? Here's more detail from the server response:
HTTP/1.1 401 Unauthorized
Cache-Control: private
Transfer-Encoding: chunked
Content-Type: text/html
Server: Microsoft-IIS/7.5
X-AspNetMvc-Version: 3.0
WWW-Authenticate: Basic realm="Secure Calendar"
X-AspNet-Version: 4.0.30319
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
X-Powered-By-Plesk: PleskWin
Date: Tue, 23 Oct 2012 13:27:48 GMT
Thanks,
Eric

Ha ha, the answer lay in IIS configuration.
I asked the admins at my host to turn off the other authentications, which broke everything but the iCal feed.
Now they've turned a couple back on again and the MVC site works as well as the calendar feed with authentication... whew! Very, very big smile.
Here's the IIS configuration we ended up with:
Name Status Response Type
Anonymous Authentication Enabled
ASP.NET Impersonation Disabled
Basic Authentication Disabled HTTP 401 Challenge
Digest Authentication Disabled HTTP 401 Challenge
Forms Authentication Enabled HTTP 302 Login/Redirect
Windows Authentication Enabled HTTP 401 Challenge
I'm not sure why this works—or what else might break—but today I'm happy.

WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
are used by Windows authentication. Since you finally enabled anonymous authentication, all WWW-Authenticate headers will not appear.

Easy way :
If you want this "X-Powered-By-Plesk" Header to be removed from EVERY NEWLY created domains, you can create a default web.config file within the "httpdocs" folder of the "Default Host Template".
This default website template is usually located under : "C:\inetpub\vhosts.skel\0\httpdocs".
That web.config file will be used by default when you create a new website.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By-Plesk" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
TIP 1 : You can use this method to remove any unwanted Custom header (In order to not tell too much to bad guys about your server) :
<remove name="X-Powered-By"/>
<remove name="X-Powered-By-Plesk"/>
<remove name="X-AspNet-Version"/>
<remove name="X-AspNetMvc-Version"/>
TIP 2 : If you want to remove any Dynamic header (like the famous "Server" header), you will need to operate with outboundRules :
<configuration>
<system.webServer>
<rewrite>
<outboundRules>
<rule name="StripHeader_Server" patternSyntax="Wildcard">
<match serverVariable="RESPONSE_SERVER" pattern="*"/>
<action type="Rewrite" value=""></action>
</rule>
<rule name="StripHeader_ETag">
<match serverVariable="RESPONSE_ETag" pattern=".+" />
<action type="Rewrite" value="" />
</rule>
</outboundRules>
</rewrite>
</system.webServer>
</configuration>
TIP 3 : Additionally, you can use this default web.config file to set all configuration parameters you want to use for every new website (in example : to define a list of default documents for your websites, as explained on this Plesk Help article : https://support.plesk.com/hc/en-us/articles/213364049-How-to-configure-global-default-document-settings-in-Parallels-Plesk )

As a belated answer to this, you could also handle this by creating a custom message handler.
The message handler would be inheriting from DelegatingHandler and has to be added to the HttpConfiguration its MessageHandlers
A way this could look would be the following:
public class EnsureNoAuthenticationHeaderHandler : DelegatingHandler
{
async protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken )
{
var response = await base.SendAsync( request, cancellationToken );
if ( response.StatusCode == System.Net.HttpStatusCode.Unauthorized )
{
response.Headers.Remove( "WWW-Authenticate" );
}
return response;
}
}
And then register it in the HttpConfiguration somewhat like the following
private void Register( HttpConfiguration configuration )
{
configuration.MessageHandlers.Add( new EnsureNoAuthenticationHeaderHandler() );
}
Which you would probably call from your global configuration. A message handler can also be attached to a route directly, so if you don't want it to be available everywhere, just have a looked at the linked article on MSDN for more explanation

I had the same problem.
The response included 3 WWW-Authenticate headers and only Firefox worked correctly. Chrome, Bing and IE prompted for username and password but after that they did not send the Authenticate Header to the server.
I just changed IIS Authentication settings and it was solved:
Anonymous Authentication Enabled
ASP.NET Impersonation Disabled
Basic Authentication Disabled HTTP 401 Challenge
Forms Authentication Disabled HTTP 302 Login/Redirect
Windows Authentication Disabled HTTP 401 Challenge

Related

Docker app requests blocked by CORS to another container [duplicate]

Apparently, I have completely misunderstood its semantics. I thought of something like this:
A client downloads JavaScript code MyCode.js from http://siteA - the origin.
The response header of MyCode.js contains Access-Control-Allow-Origin: http://siteB, which I thought meant that MyCode.js was allowed to make cross-origin references to the site B.
The client triggers some functionality of MyCode.js, which in turn make requests to http://siteB, which should be fine, despite being cross-origin requests.
Well, I am wrong. It does not work like this at all. So, I have read Cross-origin resource sharing and attempted to read Cross-Origin Resource Sharing in w3c recommendation.
One thing is sure - I still do not understand how I am supposed to use this header.
I have full control of both site A and site B. How do I enable the JavaScript code downloaded from the site A to access resources on the site B using this header?
P.S.: I do not want to utilize JSONP.
Access-Control-Allow-Origin is a CORS (cross-origin resource sharing) header.
When Site A tries to fetch content from Site B, Site B can send an Access-Control-Allow-Origin response header to tell the browser that the content of this page is accessible to certain origins. (An origin is a domain, plus a scheme and port number.) By default, Site B's pages are not accessible to any other origin; using the Access-Control-Allow-Origin header opens a door for cross-origin access by specific requesting origins.
For each resource/page that Site B wants to make accessible to Site A, Site B should serve its pages with the response header:
Access-Control-Allow-Origin: http://siteA.com
Modern browsers will not block cross-domain requests outright. If Site A requests a page from Site B, the browser will actually fetch the requested page on the network level and check if the response headers list Site A as a permitted requester domain. If Site B has not indicated that Site A is allowed to access this page, the browser will trigger the XMLHttpRequest's error event and deny the response data to the requesting JavaScript code.
Non-simple requests
What happens on the network level can be slightly more complex than explained above. If the request is a "non-simple" request, the browser first sends a data-less "preflight" OPTIONS request, to verify that the server will accept the request. A request is non-simple when either (or both):
using an HTTP verb other than GET or POST (e.g. PUT, DELETE)
using non-simple request headers; the only simple requests headers are:
Accept
Accept-Language
Content-Language
Content-Type (this is only simple when its value is application/x-www-form-urlencoded, multipart/form-data, or text/plain)
If the server responds to the OPTIONS preflight with appropriate response headers (Access-Control-Allow-Headers for non-simple headers, Access-Control-Allow-Methods for non-simple verbs) that match the non-simple verb and/or non-simple headers, then the browser sends the actual request.
Supposing that Site A wants to send a PUT request for /somePage, with a non-simple Content-Type value of application/json, the browser would first send a preflight request:
OPTIONS /somePage HTTP/1.1
Origin: http://siteA.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type
Note that Access-Control-Request-Method and Access-Control-Request-Headers are added by the browser automatically; you do not need to add them. This OPTIONS preflight gets the successful response headers:
Access-Control-Allow-Origin: http://siteA.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type
When sending the actual request (after preflight is done), the behavior is identical to how a simple request is handled. In other words, a non-simple request whose preflight is successful is treated the same as a simple request (i.e., the server must still send Access-Control-Allow-Origin again for the actual response).
The browsers sends the actual request:
PUT /somePage HTTP/1.1
Origin: http://siteA.com
Content-Type: application/json
{ "myRequestContent": "JSON is so great" }
And the server sends back an Access-Control-Allow-Origin, just as it would for a simple request:
Access-Control-Allow-Origin: http://siteA.com
See Understanding XMLHttpRequest over CORS for a little more information about non-simple requests.
Cross-Origin Resource Sharing - CORS (A.K.A. Cross-Domain AJAX request) is an issue that most web developers might encounter, according to Same-Origin-Policy, browsers restrict client JavaScript in a security sandbox, usually JS cannot directly communicate with a remote server from a different domain. In the past developers created many tricky ways to achieve Cross-Domain resource request, most commonly using ways are:
Use Flash/Silverlight or server side as a "proxy" to communicate
with remote.
JSON With Padding (JSONP).
Embeds remote server in an iframe and communicate through fragment or window.name, refer here.
Those tricky ways have more or less some issues, for example JSONP might result in security hole if developers simply "eval" it, and #3 above, although it works, both domains should build strict contract between each other, it neither flexible nor elegant IMHO:)
W3C had introduced Cross-Origin Resource Sharing (CORS) as a standard solution to provide a safe, flexible and a recommended standard way to solve this issue.
The Mechanism
From a high level we can simply deem CORS as a contract between client AJAX call from domain A and a page hosted on domain B, a typical Cross-Origin request/response would be:
DomainA AJAX request headers
Host DomainB.com
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json
Accept-Language en-us;
Accept-Encoding gzip, deflate
Keep-Alive 115
Origin http://DomainA.com
DomainB response headers
Cache-Control private
Content-Type application/json; charset=utf-8
Access-Control-Allow-Origin DomainA.com
Content-Length 87
Proxy-Connection Keep-Alive
Connection Keep-Alive
The blue parts I marked above were the kernal facts, "Origin" request header "indicates where the cross-origin request or preflight request originates from", the "Access-Control-Allow-Origin" response header indicates this page allows remote request from DomainA (if the value is * indicate allows remote requests from any domain).
As I mentioned above, W3 recommended browser to implement a "preflight request" before submiting the actually Cross-Origin HTTP request, in a nutshell it is an HTTP OPTIONS request:
OPTIONS DomainB.com/foo.aspx HTTP/1.1
If foo.aspx supports OPTIONS HTTP verb, it might return response like below:
HTTP/1.1 200 OK
Date: Wed, 01 Mar 2011 15:38:19 GMT
Access-Control-Allow-Origin: http://DomainA.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, HEAD
Access-Control-Allow-Headers: X-Requested-With
Access-Control-Max-Age: 1728000
Connection: Keep-Alive
Content-Type: application/json
Only if the response contains "Access-Control-Allow-Origin" AND its value is "*" or contain the domain who submitted the CORS request, by satisfying this mandtory condition browser will submit the actual Cross-Domain request, and cache the result in "Preflight-Result-Cache".
I blogged about CORS three years ago: AJAX Cross-Origin HTTP request
According to this Mozilla Developer Network article,
A resource makes a cross-origin HTTP request when it requests a resource from a different domain, or port than the one which the first resource itself serves.
An HTML page served from http://domain-a.com makes an <img> src request for http://domain-b.com/image.jpg.
Many pages on the web today load resources like CSS style sheets, images and scripts from separate domains (thus it should be cool).
Same-Origin Policy
For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts.
For example, XMLHttpRequest and Fetch follow the same-origin policy.
So, a web application using XMLHttpRequest or Fetch could only make HTTP requests to its own domain.
Cross-Origin Resource Sharing (CORS)
To improve web applications, developers asked browser vendors to allow cross-domain requests.
The Cross-origin resource sharing (CORS) mechanism gives web servers cross-domain access controls, which enable secure cross-domain data transfers.
Modern browsers use CORS in an API container - such as XMLHttpRequest or fetch - to mitigate risks of cross-origin HTTP requests.
How CORS works (Access-Control-Allow-Origin header)
Wikipedia:
The CORS standard describes new HTTP headers which provide browsers and servers a way to request remote URLs only when they have permission.
Although some validation and authorization can be performed by the server, it is generally the browser's responsibility to support these headers and honor the restrictions they impose.
Example
The browser sends the OPTIONS request with an Origin HTTP header.
The value of this header is the domain that served the parent page. When a page from http://www.example.com attempts to access a user's data in service.example.com, the following request header would be sent to service.example.com:
Origin: http://www.example.com
The server at service.example.com may respond with:
An Access-Control-Allow-Origin (ACAO) header in its response indicating which origin sites are allowed.
For example:
Access-Control-Allow-Origin: http://www.example.com
An error page if the server does not allow the cross-origin request
An Access-Control-Allow-Origin (ACAO) header with a wildcard that allows all domains:
Access-Control-Allow-Origin: *
Whenever I start thinking about CORS, my intuition about which site hosts the headers is incorrect, just as you described in your question. For me, it helps to think about the purpose of the same-origin policy.
The purpose of the same-origin policy is to protect you from malicious JavaScript on siteA.com accessing private information you've chosen to share only with siteB.com. Without the same-origin policy, JavaScript written by the authors of siteA.com could have your browser make requests to siteB.com, using your authentication cookies for siteB.com. In this way, siteA.com could steal the secret information you share with siteB.com.
Sometimes you need to work cross domain, which is where CORS comes in. CORS relaxes the same-origin policy for siteB.com, using the Access-Control-Allow-Origin header to list other domains (siteA.com) that are trusted to run JavaScript that can interact with siteB.com.
To understand which domain should serve the CORS headers, consider this. You visit malicious.com, which contains some JavaScript that tries to make a cross domain request to mybank.com. It should be up to mybank.com, not malicious.com, to decide whether or not it sets CORS headers that relax the same-origin policy, allowing the JavaScript from malicious.com to interact with it. If malicous.com could set its own CORS headers allowing its own JavaScript access to mybank.com, this would completely nullify the same-origin policy.
I think the reason for my bad intuition is the point of view I have when developing a site. It's my site, with all my JavaScript. Therefore, it isn't doing anything malicious, and it should be up to me to specify which other sites my JavaScript can interact with. When in fact I should be thinking: Which other sites' JavaScript are trying to interact with my site and should I use CORS to allow them?
From my own experience, it's hard to find a simple explanation why CORS is even a concern.
Once you understand why it's there, the headers and discussion becomes a lot clearer. I'll give it a shot in a few lines.
It's all about cookies. Cookies are stored on a client by their domain.
An example story: On your computer, there's a cookie for yourbank.com. Maybe your session is in there.
Key point: When a client makes a request to the server, it will send the cookies stored under the domain for that request.
You're logged in on your browser to yourbank.com. You request to see all your accounts, and cookies are sent for yourbank.com. yourbank.com receives the pile of cookies and sends back its response (your accounts).
If another client makes a cross origin request to a server, those cookies are sent along, just as before. Ruh roh.
You browse to malicious.com. Malicious makes a bunch of requests to different banks, including yourbank.com.
Since the cookies are validated as expected, the server will authorize the response.
Those cookies get gathered up and sent along - and now, malicious.com has a response from yourbank.
Yikes.
So now, a few questions and answers become apparent:
"Why don't we just block the browser from doing that?" Yep. That's CORS.
"How do we get around it?" Have the server tell the request that CORS is OK.
1. A client downloads javascript code MyCode.js from http://siteA - the origin.
The code that does the downloading - your html script tag or xhr from javascript or whatever - came from, let's say, http://siteZ. And, when the browser requests MyCode.js, it sends an Origin: header saying "Origin: http://siteZ", because it can see that you're requesting to siteA and siteZ != siteA. (You cannot stop or interfere with this.)
2. The response header of MyCode.js contains Access-Control-Allow-Origin: http://siteB, which I thought meant that MyCode.js was allowed to make cross-origin references to the site B.
no. It means, Only siteB is allowed to do this request. So your request for MyCode.js from siteZ gets an error instead, and the browser typically gives you nothing. But if you make your server return A-C-A-O: siteZ instead, you'll get MyCode.js . Or if it sends '*', that'll work, that'll let everybody in. Or if the server always sends the string from the Origin: header... but... for security, if you're afraid of hackers, your server should only allow origins on a shortlist, that are allowed to make those requests.
Then, MyCode.js comes from siteA. When it makes requests to siteB, they are all cross-origin, the browser sends Origin: siteA, and siteB has to take the siteA, recognize it's on the short list of allowed requesters, and send back A-C-A-O: siteA. Only then will the browser let your script get the result of those requests.
Using React and Axios, join a proxy link to the URL and add a header as shown below:
https://cors-anywhere.herokuapp.com/ + Your API URL
Just adding the proxy link will work, but it can also throw an error for No Access again. Hence it is better to add a header as shown below.
axios.get(`https://cors-anywhere.herokuapp.com/[YOUR_API_URL]`,{headers: {'Access-Control-Allow-Origin': '*'}})
.then(response => console.log(response:data);
}
Warning: Not to be used in production
This is just a quick fix. If you're struggling with why you're not able to get a response, you can use this.
But again it's not the best answer for production.
If you are using PHP, try adding the following code at the beginning of the php file:
If you are using localhost, try this:
header("Access-Control-Allow-Origin: *");
If you are using external domains such as server, try this:
header("Access-Control-Allow-Origin: http://www.website.com");
I worked with Express.js 4, Node.js 7.4 and Angular, and I had the same problem. This helped me:
a) server side: in file app.js I add headers to all responses, like:
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
This must be before all routes.
I saw a lot of added this headers:
res.header("Access-Control-Allow-Headers","*");
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
But I don’t need that,
b) client side: in sending by Ajax, you need to add "withCredentials: true," like:
$http({
method: 'POST',
url: 'url',
withCredentials: true,
data : {}
}).then(function(response){
// Code
}, function (response) {
// Code
});
If you want just to test a cross-domain application in which the browser blocks your request, then you can just open your browser in unsafe mode and test your application without changing your code and without making your code unsafe.
From macOS, you can do this from the terminal line:
open -a Google\ Chrome --args --disable-web-security --user-data-dir
In Python, I have been using the Flask-CORS library with great success. It makes dealing with CORS super easy and painless. I added some code from the library's documentation below.
Installing:
pip install -U flask-cors
Simple example that allows CORS for all domains on all routes:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
#app.route("/")
def helloWorld():
return "Hello, cross-origin-world!"
For more specific examples, see the documentation. I have used the simple example above to get around the CORS issue in an Ionic application I am building that has to access a separate flask server.
Simply paste the following code in your web.config file.
Noted that, you have to paste the following code under <system.webServer> tag
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
I can't configure it on the back-end server, but with these extensions in the browsers, it works for me:
For Firefox:
CORS Everywhere
For Google Chrome:
Allow CORS: Access-Control-Allow-Origin
Note: CORS works for me with this configuration:
For cross origin sharing, set header: 'Access-Control-Allow-Origin':'*';
Php: header('Access-Control-Allow-Origin':'*');
Node: app.use('Access-Control-Allow-Origin':'*');
This will allow to share content for different domain.
Nginx and Apache
As an addition to apsiller's answer, I would like to add a wiki graph which shows when a request is simple or not (and OPTIONS pre-flight request is send or not)
For a simple request (e.g., hotlinking images), you don't need to change your server configuration files, but you can add headers in the application (hosted on the server, e.g., in PHP) like Melvin Guerrero mentions in his answer - but remember: if you add full CORS headers in your server (configuration) and at same time you allow simple CORS in the application (e.g., PHP), this will not work at all.
And here are configurations for two popular servers:
turn on CORS on Nginx (nginx.conf file)
location ~ ^/index\.php(/|$) {
...
add_header 'Access-Control-Allow-Origin' "$http_origin" always; # if you change "$http_origin" to "*" you shoud get same result - allow all domain to CORS (but better change it to your particular domain)
add_header 'Access-Control-Allow-Credentials' 'true' always;
if ($request_method = OPTIONS) {
add_header 'Access-Control-Allow-Origin' "$http_origin"; # DO NOT remove THIS LINES (doubled with outside 'if' above)
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 days
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # arbitrary methods
add_header 'Access-Control-Allow-Headers' 'My-First-Header,My-Second-Header,Authorization,Content-Type,Accept,Origin'; # arbitrary headers
add_header 'Content-Length' 0;
add_header 'Content-Type' 'text/plain charset=UTF-8';
return 204;
}
}
turn on CORS on Apache (.htaccess file)
# ------------------------------------------------------------------------------
# | Cross-domain Ajax requests |
# ------------------------------------------------------------------------------
# Enable cross-origin Ajax requests.
# http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity
# http://enable-cors.org/
# change * (allow any domain) below to your domain
Header set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header always set Access-Control-Allow-Headers "My-First-Header,My-Second-Header,Authorization, content-type, csrf-token"
Header always set Access-Control-Allow-Credentials "true"
The Access-Control-Allow-Origin response header indicates whether the
response can be shared with requesting code from the given origin.
Header type Response header
-------------------------------------------
Forbidden header name no
A response that tells the browser to allow code from any origin to
access a resource will include the following:
Access-Control-Allow-Origin: *
For more information, visit Access-Control-Allow-Origin...
For .NET Core 3.1 API With Angular
Startup.cs : Add CORS
//SERVICES
public void ConfigureServices(IServiceCollection services){
//CORS (Cross Origin Resource Sharing)
//=====================================
services.AddCors();
}
//MIDDLEWARES
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
//ORDER: CORS -> Authentication -> Authorization)
//CORS (Cross Origin Resource Sharing)
//=====================================
app.UseCors(x=>x.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:4200"));
app.UseHttpsRedirection();
}
}
Controller : Enable CORS For Authorized Controller
//Authorize all methods inside this controller
[Authorize]
[EnableCors()]
public class UsersController : ControllerBase
{
//ActionMethods
}
Note: Only a temporary solution for testing
For those who can't control the backend for Options 405 Method Not Allowed, here is a workaround for theChrome browser.
Execute in the command line:
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="path_to_profile"
Example:
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="C:\Users\vital\AppData\Local\Google\Chrome\User Data\Profile 2"
Most CORS issues are because you are trying to request via client side ajax from a react, angular, jquery apps that are frontend basic libs.
You must request from a backend application.
You are trying to request from a frontend API, but the API you are trying to consume is expecting this request to be made from a backend application and it will never accept client side requests.

Cross-Origin Request Blocked while authenticating

I am trying to design an OAuth2 authentication system that secures a variety of backend APIs. I started by downloading and installing the three interconnected Spring Boot / Cloud / OAuth2 apps in this github project.
But my project requires two major architectural changes:
1.) The main portal UI must be running in Node.js, so that users can
view a public site and also login using a Node.js-hosted app that
makes REST calls to a backend authentication server, without feeling
like they are being redirected anywhere for authentication.
2.) My app requires multi-factor authentication, so I need to create (or
at least customize) my own endpoints on the `authserver` app instead
of relying to the standard password authentication endpoint.
What specific changes need to be made so that my Node.js-hosted UI app can successfully interact with the authserver app and the resource app?
At the moment, adding AngularJS login code to either my own Node.js portal app OR to the ui app in the github sample results in the FireFox console showing the following error messages when the AngularJS code tries to call the authserver app running on port 9000:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost:9000/login-form. (Reason: CORS
header 'Access-Control-Allow-Origin' missing). <unknown>
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost:9000/login-form. (Reason: CORS
request failed).
The AngularJS code that calls the new /login-form endpoint that I added to the authserver endpoint is:
$scope.credentials = {};
$scope.loginError = false;
$scope.showLogin = false;
$scope.loginShow = function() {
$scope.showLogin = true;
console.log('filler to add break point for debugger.');
};
$scope.loginLocal = function() {
console.log('Just filler to add a break point in debugger.');
var funcJSON = { 'type': 'Message',
'content1': $scope.credentials.username,
'content2': $scope.credentials.password
};
console.log('filler to add break point.');
$http.post('http://localhost:9999/uaa/login-form', funcJSON).then(function(response) {
if(response.data.content1==='success'){
$scope.Oauthenticated = true;
console.log('filler to add a break point');
}else {
$scope.Oauthenticated = false;
$scope.loginError = true;
console.log('filler to add break point');
}
});
};
The FireFox debugger shows that the line of the above AngularJS code that throws the error in the FireFox console shown at top is:
$http.post('http://localhost:9999/uaa/login-form', funcJSON).then(function(response) {
I added a new /login-form end point to the AuthserverApplication.java file in the authserver app, and you can read my entire new AuthserverApplication.java file at a file sharing site by clicking on this link.
I am open to running the main portal UI app inside of Spring Boot. I have read that this would require using the #EnableSidecar annotation. However, I get the same error message above whether the new login form is run inside the Spring Cloud ui app from the github link above, or from my Node.js-hosted portal UI. So what do I need to change to set up a secure way of managing this authentication from my Node.js-hosted portal app?
ONGOING RESEARCH:
Per #Ulises' suggestion, I added code to override a method of AuthserverApplication.java. I also double checked the url and slightly altered the url for the $http.post(... call (which I changed in-line above in the OP to avoid confusion. The result is the same error in the FireFox console, plus an explicit log of the request in the Spring Boot log for the authserver app.
You can read my new AuthserverApplication.java class including #Ulises's suggestion at a file sharing site by clicking this link. The Node.js-hosted app that makes the call is running on port 7000.
And you can read the entire Spring Boot log for the request at a file sharing site by clicking on this link.
Similarly, when I change the suggested method to read:
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/login-form").allowedOrigins("http://localhost*");
}
I get the Spring Boot error log that you can read at a file sharing site by clicking on this link. And the Network tab of the FireFox debugger gives a 401 error, with the following raw headers:
Request headers:
Host: localhost:9999
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://localhost:7000
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-requested-with
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Response headers:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate, no-store
Content-Type: application/xhtml+xml;charset=UTF-8
Date: Wed, 13 Apr 2016 09:32:40 GMT
Expires: 0
Pragma: no-cache, no-cache
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
WWW-Authenticate: Bearer realm="null", error="unauthorized", error_description="Full authentication is required to access this resource"
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
x-content-type-options: nosniff
The same new error persists even when I add the following method to the LoginConfig inner class inside AuthserverApplication.java to try to get Spring Security to ignore the /login-form endpoint:
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity.ignoring().antMatchers("/login-form", "/error");
}
I am currently reading the Spring OAuth2 Developer's Guide at this link, which refers to sample apps on github at this link. However, the sample apps use JSP, which is obsolete, and does not address the use case described in this OP.
In your AuthServerApplication override method addCorsMapping(CorsRegistry) from WebMvcConfigurerAdapter like this:
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/login-form").allowedOrigins("http://localhost:9000");
}
Or wherever origin you're calling it from. You can also use * for everything and/or add any fine-grained configuration

How to enable CORS for simple AJAX web application

I have searce a lot of solutions about AJAX call CORS, but I still can not get XML data from that other server.
This is console note:
XMLHttpRequest cannot load url.xml. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access
I have follow instructions from: http://www.html5rocks.com/en/tutorials/cors/ section: CORS from jQuery, this is code that I try:
$.ajax({
type:'GET',
url:'http://www.someurl.xml',
contentType:'text/plain',
xhrFields:{
withCredentials: false
},
headers: {
'Access-Control-Allow-Origin':'http://localhost:8080',
'Access-Control-Allow-Method':'GET',
'Access-Control-Allow-Headers':'Content-Type,x-requested-with,Authorization,Access-Control-Allow-Origin'
},
success: function(data){
var test = data;
}
});
I know that this question has been asked for many times, but no answer help to fix my problem.
For testing in localhost I am using IIS 8.5
The headers section in your $.ajax code adds headers to the request to the server, but CORS headers need to be present on responses from the server.
Working with IIS, you can add those headers with a few lines in the <system.webServer> section of your web.config. Adding this will get you started for GET requests:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
</system.webServer>
See this post for more information: http://encosia.com/using-cors-to-access-asp-net-services-across-domains/
The CORS headers must be sent by the server you are making the call to, you cannot provide them with the request itself.
When making a request across domains, your browser will perform a preflight request to get the relevant CORS headers before actually requesting data (I believe this uses the OPTION method).
If the CORS headers from preflight include the current origin or a wildcard matching it, then the browser will continue on with the real request and fetch some data.

IIS 7.5 Windows + Anonymous Authentication works intermittently

I have an MVC 3 site in which some controllers/action require Windows authentication, other do not, i.e. are anonymous.
The site runs fine for a while, I can access both the anonymous actions and authenticated ones (without prompting, credentials are passed automatically in Chrome/IE/FireFox) but then the authentication just stops working, I start getting prompted for credentials that are never accepted.
I have to either restart the whole server, or change the site physical path to another app, make an authenticated request, which works, when back to the original site. The situation is then rinse and repeat, but I can find no pattern to it. If I do nothing, the authentication stays broken.
I have IIS 7.5 configured as follows:
App Pool
.NET Framework Version - v4.0
Managed Pipeline Mode - Integrated
Application Pool Identity - ApplicationPoolIdentity
Site
Anonymous Authentication - Enabled
Anonymous user identity - IUSR [I believe this is the default]
ASP.NET Impersonation - Disabled
Forms Authentication - Disabled
Windows Authentication - Enabled
Windows Authentication Extended Protection - Off
Windows Authentication Enable Kernel-mode authentication - On
Windows Authentication Providers - Negotiate, NTLM
Controllers
// Anonymous Controller
public class HomeController : Controller
{
public ActionResult Index()
{
return this.View();
}
}
// Authenticated Controller
[Authorize]
public class AnotherController : Controller
{
public ActionResult Index()
{
var viewModel = // create view model;
return this.View(viewModel);
}
}
At all times, authentication working or not a GET to /home/index returns 200. Exactly as expected.
When authentication is working a GET request to /another/index looks like this:
> GET /another/index
Response: 401
Response Headers: WWW-Authenticate: NTLM, WWW-Authenticate:Negotiate
> GET /another/index
Request Header: Authorization: Negotiate TlRMIVNDUAACAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==
Response: 401
Response Header: WWW-Authenticate: Negotiate TlRMTVNTUAACAAAACAAEADgAAAAVgoni2YSlwIHmCL4AAAAAAAAAAIgAiAA8AAAABgGxHQAAAA9GAFIAAgAEAEYAUgABABQARgBSAEkATgBUAFIAQQBOAEUAVAAEABQARgBSAC5ATgBEAFMALgBjAG8AbQADACoARgBSAKkATgBUAFIAQQBUAEUAVAAuAGCAcgAuAG4AZACzAC4AYvBvAG0ABQAOAE4ARABTAC6AYwBvAG0ABwAIAOST3lPK980BAAAAAA==
> GET /another/index
Request Headers: Authorization: Negotiate TlRMTVNTUAACAAAACAAEADgAAAAVgoni2YSlwIHmCL4AAAAAAAAAAIgAiAA8AAAABgGxHQAAAA9GAFIAAgAEAEYAUgABABQARgBSAEkATgBUAFIAQQBOAEUAVAAEABQARgBSAC5ATgBEAFMALgBjAG8AbQADACoARgBSAKkATgBUAFIAQQBUAEUAVAAuAGCAcgAuAG4AZACzAC4AYvBvAG0ABQAOAE4ARABTAC6AYwBvAG0ABwAIAOST3lPK980BAAAAAA==
Response: 200
When authentication breaks a GET request to /another/index looks like this:
> GET /another/index
Response: 401
Response Headers: WWW-Authenticate: NTLM, WWW-Authenticate:Negotiate
> GET /another/index
Request Header: Authorization: Negotiate TlRMIVNDUAACAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==
Response: 401
Response Headers: WWW-Authenticate: NTLM, WWW-Authenticate:Negotiate
At this point I am prompted for credentials, which I enter, the same request, response is resent:
> GET /another/index
Request Header: Authorization: Negotiate TlRMIVNDUAACAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==
Response: 401
Response Headers: WWW-Authenticate: NTLM, WWW-Authenticate:Negotiate
Does anyone know if I have something misconfigured (I'm fairly sure I don't or I wouldn't expect it to work at all), why the authentication breaks or how I can stop it?
Many thanks all.
So it turns out this was as a result of the bad usage of the httpErrors section of the web.config
<httpErrors errorMode="Custom">
<remove statusCode="401" subStatusCode="-1"/>
<error statusCode="401" path="/Unauthorized" responseMode="ExecuteURL"/>
<remove statusCode="403" subStatusCode="-1"/>
<error statusCode="403" path="/Unauthorized" responseMode="ExecuteURL"/>
<remove statusCode="404" subStatusCode="-1"/>
<error statusCode="404" path="/NotFound" responseMode="ExecuteURL"/>
<remove statusCode="500" subStatusCode="-1"/>
<error statusCode="500" path="/ServerError" responseMode="ExecuteURL"/>
</httpErrors>
This resulted in the NTLM requirement to resubmit the credentials not being sent from the server when authentication was required. i.e. What should happen Request, Challenge (please resubmit with credentials) Response. What actually happened Request, Response. The Challenge was never sent.
The correct approach is to remove this section completely and in my errors controller actions use the extension method TrySkipIisCustomErrors.

cross domain ajax post request

I'm probably missing something but till now haven't figure it out.
I have a MVC application which listens on the web default port (i.e. 80), at the end of the interaction with the user, it sends an ajax post request (using jquery) to a WCF 4 REST service which listens on port 90, sadly enough, I'm not allowed to do so because of the brower same origin policy security issue.
I read that Chrome, Safari and firefox support by default the CORS protocol which allow cross domain requests.
In my server I've added to the response's headers the following: Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Allow-Headers and Access-Control-Max-Age.
from what I saw all the cors plugins handle microsoft xdr object and doesn't change the xhr default behavior.
Any help will be appriciated,
Thanks,
Ron
Hey stewe thanks for the reply, adding the headers to the service response didn't do the trick.
But the following did (Cors solution):
a) I was using jquery v 1.5.1 and found out that someone report a bug related to cross domain requests which was fixed in later version.
b) In the Service web config I've decalred the following:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*"/>
<add name="Access-Control-Allow-Headers" value="Content-Type"/>
</customHeaders>
</httpProtocol>
This sln relevant only for browsers which support CORS protocol (i.e. not IE) for that we can use easyxdm.
Eventually, I've decided not to expose my service to the user, but through an UI.
Thanks,
Ron

Resources