Azure AD in ASP.NET Core MVC web application causes CORB for JavaScript requests - asp.net-core-mvc

Integration of Azure AD into a ASP.NET Core MVC web application causes Cross-Origin Read Blocking for requests made by JavaScript frontend to ASP.NET controllers.
I am writing an ASP.NET Core MVC application that requires users to login using a Microsoft work account. This works. I added the following code to Startup.cs:
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddAzureAd(options => Configuration.Bind("AzureAd", options))
.AddCookie(options =>
{
options.LoginPath = "/Account/SignIn/";
options.AccessDeniedPath = "/Account/AccessDenied/";
});
I am also using Telerik UI widgets for the applications user interface. Because of this, there are multiple places where I use JavaScript to make requests to my ASP.NET controllers. Ex:
function onEvent(e) {
$.post("Controller/Foo", function (data) {
...
});
}
This works great when I'm running and debugging locally using IIS Express but when I deploy the application to our server running IIS I start getting warnings about Cross-Origin Read Blocking in my browsers development tools and none of my javascript functions that make requests to my ASP.NET controllers receive data.
Here is a screenshot of the warnings:
If anyone happens to know how to approach this problem I would be very grateful; I'm new to all of this and I have no idea where to start with this particular problem.
My current thinking is either I need to figure out how to handle the 'Access-Control-Allow-Origin' header in javascript or that there is something that needs to be done in Azure.
The first thing I did was enable CORS in my application but that just allows other domains to make cross-origin requests from my application, which isn't what's happening here.

If anyone comes across this issue with CORB in Chrome and dotnet core please note that in my case I was using the ResponseCache attribute. On the first non cached request it worked and subsequent ones failed with CORB error.
Once I removed the attribute the error went away.
This does not solve the issue but gives one some direction as to where the issue might be.
I did not bother with the response cache as it's no longer needed.
Below was the offending code
[ResponseCache(Duration = 15, Location = ResponseCacheLocation.Any, VaryByQueryKeys = new[] {"key", "type", "identifier", "app"})]

Related

How to handle Custom Errors With .Net Core 2.2 MVC

I saw on youtube how to handle custom errors but it was with web.config and in dotnet core 2.2 it does not have this file or I'm not finding it through visual studio 2019.
ASP.NET Core doesn't use Web.config, unless you're hosting in IIS, and then only for minimal IIS module configuration. Custom error handling is done via middleware configuration in your Startup.Configure method. This is actually covered in the default project template, though, so it's odd that you don't have something included by default to at least work from. Regardless, you're looking at something like:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
}
That will generally route any global uncaught exception to a general /Error endpoint, which could be either a controller action or Razor Page. More likely than not, you'll want a little more flexibility, and you will also want to not expose an actual "error" URL in the browser, so you'll probably sub UseExceptionHandler with UseStatusCodePagesWithReExecute:
app.UseStatusCodePagesWithReExecute("/StatusCode","?code={0}");
That will keep the URL, without redirecting and load up a /StatusCode endpoint while passing the specific status code (404, 400, 500, etc.), allowing you to return custom messaging per error type.
All of this and more is in the documentation.

Calling SAP SOAP Webservices via Ajax Javascript – Go round the cross-domain-policies

I’m trying to develop a web application, which should submit a SOAP-Request (POST) to a SAP Webservice using Ajax / Javascript. After that the appropriate data from the SAP System should be displayed on the web application.
However, I’m now faced with the cross-domain problem, because of the web application and the system are on different domains. If I adjust my IE (btw. IE11) security settings, the application will run correctly.
But I want to avoid that, because the application will not be only used on my computer, but also it’s to be used by many other users. It’s important that it supports all browsers and mobile devices, without the need to adjust the security settings.
With the default security level, the application no longer works for me and I get the error message “XMLHttpRequest: Access denied” because apparently CORS and CORS Preflight is required.
Looking for a solution, I’m first stumbled upon JSONP. But since this are standard SAP Webservices and the data are transmitted in XML-form (not json) by means of the WSDL, this method in my opinion, falls out. In addition, I use “POST”-methods. In JSONP only “GET”-methods will be supported.
I would also like to avoid to solve the problem via another server or a proxy which is stored between the SAP system and the web application, because I had no knowledge of those topics related with SAP Systems and does not know how to implement this.
CORS seems to be a good option in my case.
From the request header I can deduce that following attributes are sent to the host of the SAP System:
Option: with the domain of the Web application
Access-Control-Request-Method: with the value “POST”-method
Access-Control-Request-Header: with the entries “content-type, accept”
Requirement: with “OPTION”
See request header: http://up.picr.de/23122262lo.png
If I understood CORS correctly, the SAP system must now respond appropriately to this request to allow the cross-access. I’ve tried using a “crossdomain.xml” – file like in flash or adobe which I’ve provided in the root of the SAP System domain. Calling via the path “SAP domain/crossdomain.xml”, the XML-file is shown as follows:
<?xml version="1.0" ?>
<cross-domain-policy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<site-control permitted-cross-domain-policies="all"/>
<allow-access-from domain="*" to-ports="*" secure="false"/>
<allow-http-request-headers-from domain="*" headers="*" secure="false"/>
</cross-domain-policy>
Unfortunately, this is apparently not entirely sufficient. From the response header I can see that the XML-file is not taken.
See response header: http://up.picr.de/23122265yp.png
How should I attach that CORS permissions to the response headers in SAP? Is this solution only possible for adobe or flash? Can I also use this in my case or can I bind the appropriate permissions in the webservice settings (SOAMANAGER), eg. in a binding?
How it looks with a SAP sided proxy? Would that be an option and if so, do you have any advice for the implementation?
I would be very grateful about helpful tips and answers, especially since I have no other ideas at the moment, how to solve this cross-domain problem.
Thank you in advance for your assistance.
Here is my request-snippet:
`//jQuery.support.cors = true;
$(document).ready(function () {
var wsUrl = "http://BCSW-SAP016.xxxxxx.net:8000/sap/bc/srt/rfc/sap/z_agbs_webservice_xxxx/001/service/binding";
var soapRequest ='<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:urn="urn:sap-com:document:sap:soap:functions:mc-style">'
+ '<soap:Header/>'
+ '<soap:Body>'
+ '<urn:ZAgbsWebserviceComTab>'
+ '<Aosuser>'+aOSUser+'</Aosuser>'
+ '<Asystem>'+aSystem+'</Asystem>'
+ '<EvTabelle>'
+ '</EvTabelle>'
+ '</urn:ZAgbsWebserviceComTab>'
+ '</soap:Body>'
+ '</soap:Envelope>';
$.ajax({
type: "POST",
url: wsUrl,
contentType: "application/soap+xml", // charset=UTF-8", //
action: "urn:sap-com:document:sap:soap:functions:mc-style:Z_AGBS_WEBSERVICE_xxxx:ZAgbsWebserviceComTabRequest",
dataType: "xml",
data: soapRequest,
success: processSuccess,
error: processError
});
});
Check out this blog post
You need to add a custom handler that sets the "Access-Control-Allow-Origin" header and then assign the header in SICF.

WebAPI SignalR Negotiate response different on different browsers

The main problem about Access-Control-Allow-Origin I think. But when I configure the Web API project as defined in the given documentation, it still not working in chrome and firefox but working in IE well (it is about IE thinks localhost is not cross domain, AFAIK). I tried different ways to make it work but no result.
I put the example project to github repository. Project is very simple. There are two applications working on cross domains. It is very simple chat application like in signalr examples.
You must change the value of api host in client javascript file:
https://github.com/yusufuzun/WebApiSignalR/blob/master/ChatApp/Scripts/app/chat.js#L2
When you open the Chat page in mvc project, there will be two requests to api application
1- Regular ajax request (which is working fine)
2- Signalr negotiate request (cancelled)
And also I don't think browser disables the CORS because of if it disables there would not be an hit to server. So I think it is about browser but not about browser disables (something else).
Details are in repository
Readme: https://github.com/yusufuzun/WebApiSignalR/blob/master/README.md
Fiddler Results: https://github.com/yusufuzun/WebApiSignalR/blob/master/FiddlerResults
The bad part about it also is server returning 500 with this error:
System.InvalidOperationException: 'chat' Hub could not be resolved.
Which hub name is chat also.
https://github.com/yusufuzun/WebApiSignalR/blob/master/ChatApi/Hubs/ChatHub.cs#L10
You can enable CORS for Web Api in project with different ways for test purposes. Each one is giving different errors all about XMLHttpRequest Access-Control-Allow-Origin.
I commented them, so you can uncomment and make test for each one:
https://github.com/yusufuzun/WebApiSignalR/blob/master/ChatApi/Global.asax.cs#L24
https://github.com/yusufuzun/WebApiSignalR/blob/master/ChatApi/App_Start/WebApiConfig.cs#L14
https://github.com/yusufuzun/WebApiSignalR/blob/master/ChatApi/App_Start/WebApiConfig.cs#L16
https://github.com/yusufuzun/WebApiSignalR/blob/master/ChatApi/Controllers/ChatController.cs#L17
So what is going on here?
After I talked with David Fowler in JabbR, he mentioned the thing about using CORS with SignalR. My signalr startup code was wrong. So after changing the startup code like in his advice it worked well.
He also mentioned SignalR and Web API are working with different CORS definitions. So enabling or disabling one doesn't affect other.
Here is the new startup code:
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.RunSignalR(new HubConfiguration()
{
EnableDetailedErrors = true,
EnableJavaScriptProxies = true
});
});
The old one:
app.MapSignalR(new HubConfiguration()
{
EnableDetailedErrors = true,
EnableJavaScriptProxies = true
}).UseCors(CorsOptions.AllowAll);
Hope it helps to somebody out there.

Angular JS $http request does not reach the server in ie8

I'm having issues with using $http on ie8. The request does not reach the server, until I hit a refresh. Coming back to the same link still has the same problem until I hit refresh again.
The weird thing is if the web server is on LAN and the request is made to a server in LAN, it works fine. But if the webserver is hosted remotely, it does not work!
Here is the code:
Index.html
{{test}}
Controller
app.controller(
"TestController",
function( $scope, $http) {
var url = '/test/get_data';
$http.get(url).success(function(data) {
$scope.test = data;
});
}
);
I got this error: TypeError: Object doesn't support this property or methodundefined
I prepared a JSFiddle earlier but JSFiddle is broken in ie8 so I don't provide it here.
Unfortunately I don't have a remote server that I can share with you.
Edit
Previously I used an external url which gave me 'Access Denied' error in ie because of Same Origin Policy as mentioned by one answer below. But this was not my original problem. I still have the issue above when request is from the same origin
This is a cross domain request, which is not allowed in ajax because of Same Origin Policy.
There are two solutions for this
1. JSONP: It is a cross browser way to handle cross domain ajax requests using javascript callback mechanism
2. CORS: It is a HTML5 standard, it is implemented by most of the modern browsers except IE
Mongodb lab is not supporting jsonp since it has support for CORS, that is why your request is failing in IE and works in Chrome and other browsers.
As per this post they do not have any plan to support jsonp, so I don't thick there is a way to make this work in IE.
So I found the fix... Hope this helps anyone out there that experience this problem
Angular script needs to be loaded after jQuery. I didn't have this because Yii framework that I use autoloads jQuery and the angular was not included after the jQuery.
All the controller functions need to be at the end of body section (just before the closing )
Updating to angular 1.0.5 seems to fix the problem. The problem occurred in 1.0.4 with all the above tricks. I think is related to fix 791804bd

Issue with METHOD in prototype / Ajax.Request

I am trying to call yahoo api via Ajax to find current weather:
var query = "select * from weather.forecast where location in ('UKXX0085','UKXX0061','CAXX0518','CHXX0049') and u='c'";
var url = 'http://query.yahooapis.com/v1/public/yql?q=' + encodeURIComponent(query) +'&rnd=1344223&format=json&callback=jsonp1285353223470';
new Ajax.Request(url, {
method: 'get',
onComplete: function(transport) {
alert(transport.Status); // say 'null'
alert(transport.responseText); // say ''
}
});
I noticed, that instead of GET firebug says OPTIONS. What is it and how I can use force prototype to use GET?
Here is functionality which i am trying to recreate.
And here is full URL which I am trying to access:
http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20location%20in%20(%27UKXX0085%27%2C%27UKXX0061%27%2C%27CAXX0518%27%2C%27CHXX0049%27)%20and%20u%3D%27c%27&rnd=1344223&format=json&callback=jsonp1285353223470
After hours of trying to debug the same issue myself, I came to the following conclusion.
I believe this happens because of XSS counter-measures in newer browsers.
You can find very detailed information about these new counter-measures here:
https://developer.mozilla.org/en/http_access_control
Basically, a site can specify how "careful" the browser should be about allowing scripts from other domains. If your site, or a site from which you're loading external JavaScript code, includes one of these pieces of "browser advice", newer browsers will react by enforcing a stronger XSS policy.
For some reason, Prototype's Ajax.Request, under Firefox, seems to react by attempting to do an OPTIONS request, rather than a GET or POST, so perhaps Prototype has not been updated to correctly handle these new security conditions.
At least that was the conclusion in my case. Maybe this clue can help with your case...

Resources