Impersonation in ASP.NET web application does not work when running on IIS - asp.net-mvc-3

I am working on ASP.NET 4.0 MVC3 web application that works in intranet environment. The application makes use of Windows authentication. Its application pool is run by domain user that has spn set on a domain controller. Authentication works using Kerberos (on IE and Firefox after some additional configuration).
Now I want to upload files to sharepoint, but it's important for me to upload the file as the user currently logged in into the application (so the file is created on Sharepoint with his/her credentials).
I have the following code in ResourceExists(Uri uri) function:
'...
Dim identity As System.Security.Principal.WindowsIdentity = HttpContext.User.Identity
Dim impersonationContext = identity.Impersonate()
response = request.GetResponse()
impersonationContext.Undo()
'...
This works when running locally, but when I deploy to the server I get the exception:
System.Net.WebException: The remote server returned an error: (401) Unauthorized.\r\n at WebDav.WebDavClient.ResourceExists(Uri uri)\r\n at Website.Website.WebdavController.Upload(HttpPostedFileBase file, UploadViewModel vm)
I read something about passing on the credentials, that is not possible with NTLM, but I am sure I am using Kerberos (I checked the headers with wireshark and fiddler) and I see the following:
Authorization: Negotiate YIIFpQYGKwYBBQUCoIIFmTCCBZWgJDAiBgkqhkiC9x...
Any ideas why the impersonation does not work when running on the IIS server?

I found the answer here:
http://support.microsoft.com/kb/810572
"Kerberos does not work in a load-balanced architecture and IIS drops back to NTLM authentication. Because you cannot use NTLM for delegation, any applications or services that require delegation do not work. For more information, click the following article number to view the article in the Microsoft"
And that was exactly the case. I tried now with another machine that is not load-balanced and it works.
The only thing that still surprises me is that ImpersonationLevel of the identity is still Impersonate not Delegate...

After setting <identity impersonate="true"/> in your web.config try the following:
using (((WindowsIdentity)User.Identity).Impersonate())
using (var client = new WebClient { Credentials = CredentialCache.DefaultNetworkCredentials })
{
string result = client.DownloadString("http://sharepoint");
}

you need to configure your site correctly in IIS for impersonation to work.
see Configure ASP.NET Impersonation Authentication (IIS 7)

Related

401 Unauthorized accessing Web API withing Javascript

I have web api that uses windows authentication. I've created my own Active Directory Server and a separate IIS Server. I have registered the IIS server to the domain but for some reason I'm getting a 401 issue when I use the API URL in my Javascript.
But works when using it directly from web browser
Please note that this is the same code (javascript, SQL Server, and ASP.NET Web Api) I'm developing at work. The only difference are the url for LDAP and domain. I have tried everything from changing Windows Authentication Providers. I'm just curious if I need to add my machine as a trusted to the Active Directory which I'm not sure how. I have added the Active Directory User to the IIS with Full Control but still no luck.

Using Windows Authentication to call a Web API from a Windows Store application

Here is the context of my issue: I am developing a Windows Store application that will be side-loaded on several tablets our client is planning to use. This tablet app will make calls into a Web API which in turn will do CRUD operations with a repository (SQL Server via EntityFramework). Everything has to use Windows Authentication. The tablets are Dell running Windows 10. Each user will log in with its own active domain credentials. The tablet will pass the credentials to the Web API which in turn will pass them to the repository (database). Based on the credentials, the repository will determine the group the user belongs to and based on that, it will give access to resources the user is allowed to access.
My Web API works fine. I tested it with Fiddler. For the HTTP GET request, I want to test, I checked the "Automatically Authenticate" checkbox and I can see the three successive messages, first two returning with 401 and the third returning HTTP Code 200, along with the data I requested.
However, when I try to call it from my Windows Store app, I only send one GET Request, the first one. My Web API is hosted in IIS Express. At the advice of a very distinct member of this group, I configured IIS Express to expose the Web API using the IP address of my development machine rather than "localhost". Before doing this I wouldn't see any GET Requests hitting the server, not even the first one.
I know that Windows Authentication uses the NTLM scheme and it requires a negotiation process, hence the 3 messages Fiddler sends initially to the server?
How do I need to write my Web API Client code to bypass this negotiation? I spent all morning and afternoon reading solutions to my problem, here on SO and many other websites, but somehow, I still did not get it to work. I must be missing something and I don't know what. Here is my code on the Web API Client side:
var authHandler = new HttpClientHandler()
{
Credentials = CredentialCache.DefaultNetworkCredentials,
ClientCertificateOptions = ClientCertificateOption.Automatic
};
var webApiClient = new HttpClient(authHandler)
{
BaseAddress = new Uri(_serviceUri), // _serviceUri is a string that looks like this "http://10.120.5.201:53045"
};
webApiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await webApiClient.GetAsync("api/user");
My call never returns from GetAsync, but in Fiddler, I can see only the first GET Requests being posted to the server. How can I get my client to follow up, behind the scenes, just like Fiddler does, and send the other two messages so that, eventually, the third one would return with a response HTTP 200 code and with the data I receive in Fiddler?
If anyone can point me in the right direction, I would be highly appreciative.
The problem was that the "Enterprise Authentication" setting was not set in the Capabilities tab of the Package.appxmanifest file of my app. It took me a while to figure out that that was the problem, but as soon as I checked it, my app started using Windows Authentication.

Using windows authentication for database connection - Which user is used?

I have am ASP.NET Web API application that currently makes use of SQL Authentication when connecting to the database. I would like to change the connection to using Windows Authentication. In doing so, how do I specify the user that the web app, and therefore the database access, makes use of? I am using IIS v8.5.9600.16384
I can't say I agree with using integrated for the applications DB access as it makes security a bit more challenging as well as the coding issues tied to always having to deal with the possibility of different priv's for each user but obviously I don't know all the requirements of your situation.
So to answer your question:
If your connection string is set to Intergated Security the identity of the executing thread is used to provide the credentials.
By default the identity of the ASP.NET Worker Process will be the network credentials tied to the identity.
You can view the credentials like this:
IPrincipal threadPrincipal = Thread.CurrentPrincipal;
Console.WriteLine("Name: {0}\nIsAuthenticated: {1}" +
"\nAuthenticationType: {2}",
threadPrincipal.Identity.Name,
threadPrincipal.Identity.IsAuthenticated,
threadPrincipal.Identity.AuthenticationType);
You may set the identity via impersonation in the web.config or programatically.
Web.config:
<identity impersonate="true" userName="accountname" password="password" />
Code: (using the creds of the HttpContext user) this assumes that IIS is using integrated too
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
//User is the HttpContext.User
//Insert your code that runs under the security context of the authenticating user here.
impersonationContext.Undo();
You will have to turn off Anonymous Authentication and enable Windows Authentication via IIS Manager.

Sending Email from Windows Azure Through BPOS

I'm trying to send an email via asp.net mvc2, and all works well on our companies mail server.
However, we're looking to switch to using our client's BPOS account. This works fine locally, but when deployed to azure, we're getting some timeout errors.
Can anybody confirm I have the following correct?
SmtpClient smtp = new SmtpClient("Smtp.mail.emea.microsoftonline.com");
smtp.Port = 587;
smtp.EnableSsl = true;
smtp.Credentials = new NetworkCredential("BPOS-EMAIL", "BPOS-PASSWORD");
In addition, does anyone know why it works when run locally, but not when run on azure?
Are you running the web role in Full Trust? By default, SmtpClient is going to execute under ASP Medium trust. Under that model, Smtp is only allowed to communicate over port 25 in Azure.
If you need to use the SmtpClient.Port property, you'll need to have the role run under full trust.
That's achieved by setting the enableNativeCodeExecution attribute on the Web Role in the Service Definition.
<WebRole name="WebRole1" enableNativeCodeExecution="true">
Thats the only thing I can think it might be. If that's not it and you can post error logs, that may show more details as to the problem.

ADFS v2.0 Error : MSIS7042: The same client browser session has made '6' requests in the last '1' seconds

Folks,
I've got an ASP.NET MVC application that I am attempting to secure using the Release Candidate version of ADFS v2.0 (Geneva). I have configured the application as a relying party trust, and I've used Fedutil.exe to modify the application's Web.config so that it has the information about the Geneva server and uses the Geneva server as its claims source.
However, when I try and hit the MVC app, it redirects to Geneva, which then (after warning me about self-signed certs) re-directs me to the MVC app again. After accepting both self-signed cert warnings, the two servers play ping-pong with each other in an infinite redirect loop until finally Geneva spews the following message:
The same client browser session has made '6' requests in the last '1' seconds. There could be a possible bad configuration. Contact your administrator for details.
There are no errors in the event logs on the MVC side or on Geneva except for an event containing the above message. If someone could give me some information on how to try and debug, diagnose, and hopefully fix this problem, I would be eternally grateful.
Again, the Geneva box is the ADFS v2.0 Release Candidate and the ASP.NET MVC site was built using the latest (late '09) version of the Windows Identity Foundation SDK with Web.config modified using FedUtil.exe from the WIF SDK.
So you will all get a kick out of this... I tried this same application from Firefox and ... IT WORKS. I get prompted for my domain credentials, the ADFS v2 server re-directs me ONCE and then I end up on the home page of my application, complete with my account name and personalized greeting.
So now the real issue is this: Why the hell is IE8 getting caught in an infinite redirect loop and Firefox ISN'T ??
After even further testing, I've been able to get this scenario working, out of the box, without modification of any of the default pipeline stuff from ADFS v2 (RC) or from WIF (RTW) on BOTH Safari AND Firefox. IE8 is the ONLY browser to exhibit any problem dealing with this authentication scenario. I've tried everything, including installing and trusting the self-signed certs, adding the sites to my local intranet zone and dropping security to low and even setting first AND third party cookies to always allow.
I had the same issue with ADFS 1.0
And to resolve it, I made sure that the URL had a trailing forward slash "/" that would always work in FireFox as well as IE
eg : https://somedomain.com/Application_2/
Turns out that the host name of the relying party had an underscore in it (khoffman_2). Apparently, the underscore is an illegal DNS character and ONLY IE will reject the information with the underscore in it.
I renamed my machine from khoffman_2 to khoffman2 and the ADFS v2/MVC relying party combination works flawlessly on Firefox, Safari, AND IE.
While this isn't your problem, we have had identical problems to what you described. Our solution was to:
Enabled Basic Authentication in IIS (this solved nothing but was required for the next 2 steps)
Disable Windows Authentication in IIS (this solved the problem for some IE browsers but not all)
Disable Anonymous Access in IIS (this solved the problem for the rest of the IE browsers)
Jaxidian's answer is close.
In my case I only had to:
Windows Authentication -> Disabled
Anonymous Auth -> Enabled
ASP.NET Impersonation -> Disabled
Forms Auth -> Disabled
Windows Auth -> Disabled
This loop can occur when a user is not authorized to access a page.
We had a custom authorization attribute on our MVC controller that checks to see if the user was in a role based on the claims provided if the setting for UseADFS was true in the config files. I thought this setting was set to true and was confounded that I kept getting the adfs loop when accessing the page because I was in the groups that were authorized to access the page.
The key to troubleshooting was to make a web page that displayed my adfs claims without necessarily requiring authentication.
#if (User.Identity.IsAuthenticated)
{
<div>UserName: #User.Identity.Name;</div>
var claimsIdentity = User.Identity as System.Security.Claims.ClaimsIdentity;
<table>
#foreach (var claim in claimsIdentity.Claims)
{
<tr><td>#claim.Type</td><td>#claim.Value</td></tr>
}
</table>
}
I noticed that I was getting logged into ADFS, and my claims were getting set, so ADFS was working. The actual issue was my config file had UserADFS="true" instead of UseADFS="true" which basically caused my custom authorization code to return false on authorization. Therefore, the page kept forwarding me back to adfs to authenticate again.
Anyways, if a user does not have the correct claims to access the page, then this adfs login loop can occur, as well.
Also, if you wrote a custom authorize attribute be sure to check out the following link which describes how to prevent the loop.
Redirect loop with .Net MVC Authorize attribute with ADFS Claims
Custom HandleUnauthorizedRequest handler code for AuthorizeAttribute from that link:
protected override void HandleUnauthorizedRequest System.Web.Mvc.AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
//One Strategy:
//filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
//Another Strategy:
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
{
controller = "u",
action = "LoginStatus",
errorMessage = "Error occurred during authorization or you do not have sufficient priviliges to view this page."
})
);
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}

Resources