Prompted for a username and password in Chrome for a JQuery Kendo dataSource request - iis-7

When I try to access a Kendo datasource like this:
dataSource: {
transport: {
read: {
url: constructServerActionUrl(reportsController, getVisitorsAction),
dataType: "json",
data: {
start: $("#report-bar-start").val(),
end: $("#report-bar-end").val()
}
}
}
I get prompted for a username and password in chrome when there's an attempt to access the datasource. This doesn't happen on the staging and live servers, only on local and test. I've tried:
Enabling anonymous access in IIS
Enabling Windows Authentication in IIS
Giving the IUSR account read access to all files in the application
Setting the app pool identity to an administrator account
Stopping and starting IIS
Although this is clearly an IIS configuration issue, I'm wondering if there's any way I can guarantee this issue to never occur, for example by specifying a 'no authorization' header before the datasource request is made, within the 'read' property of the dataSource. Something like this (which doesn't work):
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'None');
Alternatively, what other IIS setting may be causing this?

The problem turned out to be that my controller is called 'reports', which unbelievably clashes with SQL server reporting services if it happens to be running on the machine. I changed the controller name and everything now works.

Related

Issue with https on production environment

I have tried many options and this is my last resort to see if any of the community members have any ideas.
I have .NET MVC 5 application in which I use a Filter to force HTTPS on each unsecured request.
Here is the scenario:
Access my application at say, http://portal.mywebsite.com
It is redirected to third party (auth0) SSO provider for authentication. If the user is not already authenticated, he is redirected to the SSO login page.
The user enters valid credentials, authenticated.
The above scenario works perfectly. But the issue is If I access the same application with https say https://portal.mywebsite.com, it fails. To be precise, it fails to retrieve a ExternalIdentity (ExternalCookie) on the server.
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var externalIdentity = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
if (externalIdentity == null)
{
throw(new Exception("Could not get the external identity. Please check your Auth0 configuration settings and ensure that " +
"you configured UseCookieAuthentication and UseExternalSignInCookie in the OWIN Startup class. " +
"Also make sure you are not calling setting the callbackOnLocationHash option on the JavaScript login widget."));
}
AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = true }, CreateIdentity(externalIdentity));
return RedirectToLocal(returnUrl);
}
Also, accessing the application with https on my test environment works and not the production environment.
All my web applications are hosted as Azure WebRoles.
I tried Fiddler to watch the requests between working and non-working to see if I can find any useful information in identifying the issue but no success.
Any thoughts or ideas that I could try to help me narrow down the cause?
Thanks in advance!
There is a bug in Microsoft's Owin implementation for System.Web. The temporary fix is addressed here at github.com/KentorIT/owin-cookie-saver
Someone had the same issue .AspNetApplicationCookie and ASP.NET_SessionId not created

How does SoapUI bypass CORS issue when my ajax call can't do it?

This might be a silly question but here is my simple webapi 2 method
public class ProductsController : ApiController
{
Product[] products = new Product[]
{
new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 },
new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M },
new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M }
};
public IEnumerable<Product> GetAllProducts()
{
return products;
}
Now if I run it , on my pc it runs on http://localhost:3145/Products, and I can see the products as XML
It also works using soapui
But now if I try to access this with a html file and this javascript
<script type="text/javascript">
function GetProducts() {
$.ajax({
url: "http://localhost:3145/Products",
dataType: "json",
success: function (data) {
for (var i = 0; i < data.length; i++)
$('#myDiv').append(data[i].Category).append("<br/>");
},
error: function (xhr, status) {
alert(xhr);
}
});
}
</script>
</head>
<body onload="GetProducts()">
<h1>My App</h1>
<div id="myDiv"></div>
I get the CORS error
How is SOAP UI not getting an error here when it is using http as well?
Thanks
Put that index file into some server location, and then browse the page with server url , like, http://localhost/virtual_dir/index.html , else it will say it file:/// domain does not match with http://localhost:port . And you might face CORS issue if you deploy this page to some other domain and start using.
I have seen that you are using webapi , and you might face CORS issue if you place you JS in domain ( "example1.com"), i mean files served from example1.com will have ajax calls to webapi and that webapi may be hosted in example2.com. This will raise CORS issue. Browser restricts ajax call to other domains, unless that domain allow you to invoke. To achieve this, you can follow this link - Angular.js $resource with ASP.Net webapi? (don't go by the title)
I have answered there the same scenario.
I just experienced the same situation with a web page I was developing that needed to send a SOAP request to a web service that was served by a remote server that was not CORS-enabled. This was in a test environment; in production, the web page and web service are served from the same domain and port.
How is SOAP UI not getting an error here when it is using http as well?
Yes, SoapUI and a web browser both use HTTP. But SoapUI is not a web browser, and does not share the same restrictions.
A colleague solved this issue for me by pointing me to CORS Anywhere.
Install Node.js, if you don't already have it.
Install CORS Anywhere (npm install cors-anywhere).
Run CORS Anywhere (node cors-anywhere.js).
Instead of using your original non-CORS-enabled web service URL, use the domain and port in the resulting message from CORS Anywhere ("Running CORS Anywhere on ..."), with your original web service URL as the path component.
You can specify the CORS Anywhere port in an environment variable (or edit the default value in your local copy of cors-anywhere.js).
In my case, the production web service URL is hardcoded in the web page as a relative path. But I've added code that reads a URL from a parameter in the fragment identifier ("hash string"), overriding the default web service URL.
For example:
http://localhost:8081/mywebpage.html#url=http://localhost:8089/remote.domain.com:8085/servicename
where:
http://localhost:8081/mywebpage.html is my web page (I'm using http://, not file://, for this).
http://localhost:8089 is the CORS Anywhere proxy.
remote.domain.com:8085/servicename (you can drop the leading http://) is the remote, non-CORS-enabled web service.
I could point you 2 options to solve this:
Disable your browser CORS: Due the CORS enforcement is done by the browser you can just disable this during development in yourself browser. If you use Chrome, you must just set an parameter otherwise I may guess looking to the underneath image you are using Firefox, for this you have an extension to do this: https://addons.mozilla.org/pt-PT/firefox/addon/cors-everywhere/
Allow CORS in SOAP UI: It can take a little bit more effort than above solution but it fits very good when you need to share with mutiple teammates or just to make the solution attached to the mock service. To do this,you must add a response for the root of resource path that responds to OPTIONS and with headers you need for CORS with status 204 (or 200).
After, in the MockService you just need to add a script to grab these same headers in all calls that passes through.
Here is the article to solve this step-by-step:
https://medium.com/#andrelimamail/how-to-deal-with-cors-in-soap-ui-mock-services-or-anyother-f4cc55b3dccd

Get log in credentials from web.config in javascript for ajax request asp.net

I am wondering if it is possible to get log in credentials from a web.config file, and then use it in jquery .ajax method? Basically, for this scenario I cannot use code behind to accomplish this.
Second - if I am able to get the credentials, how do I use them in .ajax? If the username is 'Joe' and the password '1234', and the URL /mytest.aspx, would it look something like this:
$.ajax({
url: '/mytest.aspx',
type: 'get',
data: -- would log in info go here? --,
success: function(data) {
alert(xhr.statuscode);
}
});
Thanks for any help!
I am wondering if it is possible to get log in credentials from a
web.config file, and then use it in jquery .ajax method? Basically,
for this scenario I cannot use code behind to accomplish this.
Absolutely not, only server side code can access web.config. Javascript runs client side, and web.config is not accessible from the client. You would either need to include the web.config values in the page as it's rendered such as in hidden fields(thus your javascript could retrieve the values from the hidden fields), or have create a web service method that will allow you to retrieve the values via an ajax call.
Second - if I am able to get the credentials, how do I use them in
.ajax? If the username is 'Joe' and the password '1234', and the URL
/mytest.aspx, would it look something like this:
This is using an json object:
$.ajax({
url: '/mytest.aspx',
type: 'get',
data: { username: usernameVar , email: emailVar },
success: function(data) {
alert(xhr.statuscode);
}
});
Assumes you have declared a usernameVar and emailVar holding the values you wish to submit in the ajax call. Obviously add whatever properties of the credentials you want to pass, I have shown username and email. If you are passing password then you should ensure you have an encrypted connection, i.e. SSL and https as the protocol on the ajax url.
Note that the client, whoever the user is on this webpage, will be able to get these credentials(it's easy to inspect the webpage's hidden fields or the ajax request). So basically it reveals the username and password in your web.config to all of your users. I have a strong feeling what you are trying to do is very bad.
It might be advantageous to ask a new question that covers more of what your intentions are and why you are trying to do what you are asking.

File permissions with FileSystemObject - CScript.exe says one thing, Classic ASP says another

I have a classic ASP page - written in JScript - that's using Scripting.FileSystemObject to save files to a network share - and it's not working. ("Permission denied")
The ASP page is running under IIS using Windows authentication, with impersonation enabled.
If I run the following block of code locally via CScript.exe:
var objNet = new ActiveXObject("WScript.Network");
WScript.Echo(objNet.ComputerName);
WScript.Echo(objNet.UserName);
WScript.Echo(objNet.UserDomain);
var fso = new ActiveXObject("Scripting.FileSystemObject");
var path = "\\\\myserver\\my_share\\some_path";
if (fso.FolderExists(path)) {
WScript.Echo("Yes");
} else {
WScript.Echo("No");
}
I get the (expected) output:
MY_COMPUTER
dylan.beattie
MYDOMAIN
Yes
If I run the same code as part of a .ASP page, substituting Response.Write for WScript.Echo I get this output:
MY_COMPUTER
dylan.beattie
MYDOMAIN
No
Now - my understanding is that the WScript.Network object will retrieve the current security credentials of the thread that's actually running the code. If this is correct - then why is the same user, on the same domain, getting different results from CScript.exe vs ASP? If my ASP code is running as dylan.beattie, then why can't I see the network share? And if it's not running as dylan.beattie, why does WScript.Network think it is?
Your problem is clear. In the current implementation you have only impersonation of users and no delegation. I don't want to repeat information already written by Stephen Martin. I only want to add at least three solutions. The classical way of delegation which Stephen Martin suggests is only one way. You can read some more ways here: http://msdn.microsoft.com/en-us/library/ff647404.aspx#paght000023_delegation. I see three practical ways of you solving your problem:
Convert the impersonation token of the user to a token with delegation level of impersonation or to a new primary token. You can do this with respect of DuplicateToken or DuplicateTokenEx.
Use S4U2Self (see http://msdn.microsoft.com/en-us/magazine/cc188757.aspx and http://msdn.microsoft.com/en-us/library/ms998355.aspx) to receive a new token from the old one with respect of one simple .NET statement WindowsIdentity wi = new WindowsIdentity(identity);
You can access another server with respect of one fixed account. It can be a computer account on an account of the application pool of the IIS. It can be another fixed defined account which one will only use for access to the file system.
It is important to know which version of Windows Server you have on the server where IIS is running and which Domain Function Level you have in Active Directory for your Domain (you see this in "Active Directory Domain and Trusts" tool if you select your domain and choose "Raise Domain Functional Level"). It is also interesting to know under which account the application pool of the IIS runs.
The first and the third way will always work. The third way can be bad for your environment and for the current permission in the file system. The second one is very elegant. It allows control of which servers (file server) are accessed from IIS. This way has some restrictions and it needs some work to be done in Active Directory.
Because you use classic ASP, a small scriptable software component must be created to support your implementation.
Which way do you prefer?
UPDATED based on the question from comment: Because you use classic ASP you can not use a Win32 API directly, but you can write a small COM component in VB6 or in .NET which use APIs which you need. As an example you can use code from http://support.microsoft.com/kb/248187/en. But you should do some other things inside. So I explain now which Win32 API can help you to do everything what you need with tokens and impersonation.
First of all a small explanation about impersonation. Everything works very easy. There are always one primary token under which the process runs. To any thread another token (thread token) can be assigned. To do this one needs to have a token of a user hUserToken and call API ImpersonateLoggedOnUser(hUserToken);.
To go back to the original process token (for the current thread only) you can call RevertToSelf() function. The token of user will be received and already impersonated for you by IIS, because you so configured your Web Site. To go back to the original process token you should implement calling of the function RevertToSelf() in your custom COM component. Probably, if you need to do nothing more in the ASP page, it will be enough, but I recommend you be more careful and save current users token in a variable before operation with files. Then you make all operations with file system and at the end reassign users token back to the current thread. You can assign an impersonation token to a thread with respect of SetThreadToken(NULL,hUserToken);. To give (save) current thread token (user token in your case) you can use OpenThreadToken API. It must work.
UPDATED 2: Probably the usage of RevertToSelf() function at the end of one ASP page would be already OK for you. The corresponding C# code can be so:
Create a new Project in C# of the type "Class Library" with the name LoginAdmin. Paste the following code inside
using System;
using System.Runtime.InteropServices;
namespace LoginAdmin {
[InterfaceTypeAttribute (ComInterfaceType.InterfaceIsDual)]
public interface IUserImpersonate {
[DispId(1)]
bool RevertToSelf ();
}
internal static class NativeMethods {
[DllImport ("advapi32.dll", SetLastError = true)]
internal static extern bool RevertToSelf ();
}
[ClassInterface (ClassInterfaceType.AutoDual)]
public class UserImpersonate : IUserImpersonate {
public UserImpersonate () { }
public bool RevertToSelf () {
return NativeMethods.RevertToSelf();
}
}
}
Check in project properties in "Build" part "Register for COM interop". In "Signing" part of the project check Sign the assembly and in "Choose a strong name key file" choose <New...>, then type any filename and password (or check off "protect my key..."). At the end you should modify a line from AssemblyInfo.cs in Properties part of the project:
[assembly: ComVisible (true)]
After compiling this project you get two files, LoginAdmin.dll and LoginAdmin.tlb. The DLL is already registered on the current computer. To register if on the other computer use RegAsm.exe.
To test this COM DLL on a ASP page you can do following
<%# Language="javascript" %>
<html><body>
<% var objNet = Server.CreateObject("WScript.Network");
Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("<br/>");
Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("<br/>");
var objLoginAdmin = Server.CreateObject("LoginAdmin.UserImpersonate");
var isOK = objLoginAdmin.RevertToSelf();
if (isOK)
Response.Write("RevertToSelf return true<br/>");
else
Response.Write("RevertToSelf return false<br/>");
Response.Write("One more time after RevertToSelf()<br/>");
Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("<br/>");
Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("<br/>");
var fso = Server.CreateObject("Scripting.FileSystemObject");
var path = "\\\\mk01\\C\\Oleg";
if (fso.FolderExists(path)) {
Response.Write("Yes");
} else {
Response.Write("No");
}%>
</body></html>
If the account used to run the IIS application pool has access to the corresponding network share, the output will be look like following
Current user: Oleg
Current user's domain: WORKGROUP
RevertToSelf return true
One more time after RevertToSelf()
Current user: DefaultAppPool
Current user's domain: WORKGROUP
Yes
Under impersonation you can only access securable resources on the local computer you cannot access anything over the network.
On Windows when you are running as an impersonated user you are running under what is called a Network token. This token has the user's credentials for local computer access but has no credentials for remote access. So when you access the network share you are actually accessing it as the Anonymous user.
When you are running a process on your desktop (like CScript.exe) then you are running under an Interactive User token. This token has full credentials for both local and remote access, so you are able to access the network share.
In order to access remote resources while impersonating a Windows user you must use Delegation rather then Impersonation. This will involve some changes to your Active directory to allow delegation for the computer and/or the users in your domain. This can be a security risk so it should be reviewed carefully.

jquery together with asp.net and authentication

I'm using jquery to access a asp.net web service from my website. This web service needs to get the userid of the user that access it and the user is logged in with asp.net authentication on my website.
In asp.net I can just write "User.Identity.Name" to get the userid, now I need to find a way of getting this on the client side, how is that possible?
My code for accessing the web service:
$.ajax({
type: "GET",
url: "http://domain.com/Service.svc/search?keyword=" + this.value + "&userid=" + HERE I NEED THE USERID,
dataType: "json"
.....
});
One way would be to put the userid in a hidden field or something and access it that way, could that be the way to go?
Assuming this all on a trusted internal network (e.g. a company?), then the jQuery call will be offering the user's credentials to the web service in the same way it does to your web site. Can the web service just check who is authenticated on the call (using User.Identity.Name for example) ?
This approach would be far preferable to providing the username on the querystring ( or as an argument to the web service call), as either of these would be easily subvertible.
$.ajax({
type: "GET",
url: "http://domain.com/Service.svc/search?keyword="
+ this.value + "&userid=<%= User.Identity.Name %>",
dataType: "json"
.....
});
Would do it, but are you sure you need to? If this is not a cross domain call, the request should come from the authenticated user session, and so in your service you can extract that information in the code behind.
As Rob points out, this can easily be modified by someone, so you'd probably actually want to use something else, for example encrypting the user name using a salt and key that you know at both ends.

Resources