I have a web service "someWebServiceOnServer" that sends back a json response and a Cookie. If I hit this URL through the browser, I see the following:
{"IsAuth":true,"Message":"","UserName":"guest"}
And if I inspect the page Resources -> Cookies, I see a Cookie set.
Now in my Sencha Touch 2 application, I am making an ajax call as follows:
Ext.Ajax.request({
url: 'someWebServiceOnServer',
useDefaultXhrHeader: false,
callback: function(options, success, response) {
console.log(response.responseText)
},
});
On running this, I get the JSON response as expected. But the cookie is not set. Also I cannot find the cookie in the response header. Why does this happen ?
Note: CORS has been implemented on the server and my application can access this service. I have not used withCredentials: true, since this throws an error XMLHttpRequest cannot load . Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true. .
Cookies are already enabled on my browser.
I need the cookie since I will be making subsequent calls that will send this cookie info back to the server.
Try this:
Add the following headers to the server response.
Access-Control-Allow-Origin: http://clientdomain.com
Access-Control-Allow-Credentials: true
And add withCredentials: true in the Ajax request.
For IIS WCF with ExtJS request apply this to web.config (eg. for localhost so locally hosted application for example via SenchaTouch packagedr or PhoneGap):
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://localhost" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
</system.webServer>
And In Ext.JS request use those parameters:
disableCaching: true,
useDefaultXhrHeader: false,
withCredentials: true
This in turn forces Ext.ajax.request to use cookies.
Related
I have created simple API in MVC.
I want to call it from Ionic App. I wrote code in my WebApiConfig.cs file to allow CORS. But when I try to call same from Ionic it throws an error:
Failed to load http://localhost:53377/api/member/2: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:8100' is therefore not allowed
access.
How can I resolve the issue?
In each applications when you are going to send requests to another web application, you must set the Access-Control-Allow-Origin header.
This post has complete info about it.
Access-Control-Allow-Origin header
My English is not good, but I will try to help you.
Add this in your web.config
<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" />
</customHeaders>
</httpProtocol>
See your requisitions allowed in Access-Control-Allow-Methods. Add GET, POST, PUT OR DELETE according to your need.
Alert: I don't know of informations of security about it. But in simple requisition, should solve.
Alert 2: I reccomend to pass a security token in webapi requisition.
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.
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.
I realize this question has been asked a dozen or more times and each response given indicates I am doing it right but perhaps I am missing something.
AJAX serves up CORS request like so...
$.ajax({
url: 'someotherdomain.com',
type: 'post',
data: {key: 'value'},
dataType: 'json',
async: false,
crossDomain: true,
beforeSend: function(xhr){
xhr.withCredentials = true;
},
success: function(x, status, xhr){
},
error: function(xhr, status, error){
}
});
PHP serves up CORS requests like so...
header('Access-Control-Max-Age: 1728000');
header('Access-Control-Allow-Origin: http://someotherdomain.com');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-MD5, X-Alt-Referer');
header('Access-Control-Allow-Credentials: true');
header("Content-Type: application/json; charset=utf-8");
According to all documentation as long as the 'Access-Control-Allow-Credentials' server side header, and the 'withCredentials=true' client side header is set session cookie handling between the domains should be transparent. Am I missing something?
async: false
was preventing the session cookie from being sent back to the server on each request. The following fixed it.
async: true
Although this does allow for the session cookie to get set by the browser when making a cross origin request sharing call, I am now experiencing problems regarding the following scenario:
Server A sends response to client
Client using CORS makes request of server B
XMLHttpRequest -> PHP -> Session handler -> MySQL -> Stored Procedure
Due to the MUTEX locks in the PHP session management the asynchronous nature and apparently, requirement may force a work around of manually setting the cookie with a different header option such as XCookie or something similar to keep the servers session and client requests synchronized.
This particular work around does not sit well with me as I believe it would open up an easy lane of travel for session hijacking and session replay attack vectors.
Using an SSL/TLS wrapped connection may assist in preventing the above scenario but in terms of independently providing security measures for the client I do not believe this should suffice.
Anyone with any thoughts on this?
In your example above, you are setting the Access-Control-Allow-Origin header to 'http://someotherdomain.com', which is the same as the url you are requesting from JQuery. The Access-Control-Allow-Origin header should be the value of the domain the request is coming from. As a quick, test, try setting the value of this header to '*' (without the quotes) and see if it works ('*' means all domains are allowed).
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