I have an ASP.NET 4.0 application running on Windows 7 / IIS 7.5 in the "ASP.NET v4.0 Classic" application pool, which is configured to run as Network Service. The application has an Application_EndRequest
handler which connects to a local SQL Server instance. The SQL connection string specifies Integrated Security=SSPI
. Web.config does not have <identity impersonate="true" />
.
When I browse to http://localhost/TestSite/
, the following exception is thrown:
System.Data.SqlClient.SqlException (0x80131904): Login failed for user 'NT AUTHORITY\IUSR'.
...
at System.Data.SqlClient.SqlConnection.Open()
at Global.Application_EndRequest(Object sender, EventArgs e)
This exception is not thrown when I browse to http://localhost/TestSite/default.aspx
(the default document configured in IIS) or any other .aspx page; in those cases the application correctly connects to SQL Server as "NT AUTHORITY\NETWORK SERVICE", which is a valid login.
Why would ASP.NET impersonate "NT AUTHORITY\IUSR" in EndRequest even though impersonation is disabled? Is this a bug in ASP.NET?
The following Global.asax.cs file demonstrates the problem:
public class Global : HttpApplication
{
public Global()
{
this.BeginRequest += delegate { Log("BeginRequest"); };
this.PreRequestHandlerExecute += delegate { Log("PreRequestHandlerExecute"); };
this.PostRequestHandlerExecute += delegate { Log("PostRequestHandlerExecute"); };
this.EndRequest += delegate { Log("EndRequest"); };
}
protected void Application_EndRequest(Object sender, EventArgs e)
{
try
{
using (SqlConnection connection = new SqlConnection("Server=.;Integrated Security=SSPI"))
{
connection.Open();
}
}
catch (Exception ex)
{
Trace.WriteLine(ex);
}
}
private static void Log(string eventName)
{
HttpContext context = HttpContext.Current;
Type impersonationContextType = typeof(HttpContext).Assembly.GetType("System.Web.ImpersonationContext", true);
Trace.WriteLine(string.Format("ThreadId={0} {1} {2} Impersonating={3}",
Thread.CurrentThread.ManagedThreadId,
context.Request.Url,
eventName,
impersonationContextType.InvokeMember("CurrentThreadTokenExists", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetProperty, null, context, null)));
}
}
Here's the trace output:
ThreadId=3 http://localhost/TestSite/ BeginRequest Impersonating=False
ThreadId=3 http://localhost/TestSite/ PreRequestHandlerExecute Impersonating=False
ThreadId=7 http://localhost/TestSite/default.aspx BeginRequest Impersonating=False
ThreadId=7 http://localhost/TestSite/default.aspx PreRequestHandlerExecute Impersonating=False
ThreadId=7 http://localhost/TestSite/default.aspx PostRequestHandlerExecute Impersonating=False
ThreadId=7 http://localhost/TestSite/default.aspx EndRequest Impersonating=False
ThreadId=7 http://localhost/TestSite/ PostRequestHandlerExecute Impersonating=True
ThreadId=7 http://localhost/TestSite/ EndRequest Impersonating=True
System.Data.SqlClient.SqlException (0x80131904): Login failed for user 'NT AUTHORITY\IUSR'.
...
at System.Data.SqlClient.SqlConnection.Open()
at Global.Application_EndRequest(Object sender, EventArgs e)
Note that a request to TestSite/
(which is mapped to DefaultHttpHandler
) seems to spawn a nested request to TestSite/default.aspx
(which is mapped to ASP.default_aspx
). After ASP.NET finishes processing TestSite/default.aspx
, it impersonates "NT AUTHORITY\IUSR" when it resumes processing the request to TestSite/
.
UPDATE: I've submitted this issue to Microsoft Connect.
NT AUTHORITY\IUSR is a built-in Windows account that is the default identity used when Anonymous Authentication is enabled for your application.
In the application's Web. config file, set the impersonate attribute in the identity element to true. Set the NTFS access control list (ACL) for the ManagerInformation directory to allow access to only those identities that are in the Windows Manager group and any required system accounts.
Most likely, the settings for your server, site or application are set so that "Anonymous Authentication" mode causes page requests to be handled as the IUSR user. It doesn't matter that your application is not requesting impersonation; IIS is forcing it. (By the way, "impersonation" is generic term in Windows-land for assuming another user's credentials. It is not specific to ASP.NET.)
A bit of background:
For security reasons, IIS allows your server to field "anonymous" and "authenticated" requests under different system credentials.
Now, in IIS 7.5, if you have both anonymous authentication and Forms authentication enabled (which is typical), before your website user logs in via Forms, it considers your user "anonymous". After your user logs in with Forms Auth, it considers your user "authenticated."
I found this behavior confusing at first because it's a change from IIS 6.0, which wasn't aware of Forms auth, and considered all Forms-Authenticated users to be anonymous!
If you want, you can change the identity under which anonymous requests are fielded. My preference (and it sounds like yours too) is that they run under the same system credentials as my site's app pool. To make IIS do that, do the following:
Step 5 also confused me at first, because I thought "application pool identity" meant "the application pool pseudo-account" (another new feature in IIS 7.5). What it really means, of course, is "the same account the app pool is configured to run under, whatever that is."
If you want this behavior by default for all of your websites on that server, or even just single application under a particular site, you can configure the authentication options at those levels too. Just select the node you want to configure in the Connections pane, then repeat steps 3-6.
Why would the application attempt to log in as "NT AUTHORITY\IUSR" even though the application is (probably) not using impersonation?
If you do
<identity impersonate="true"/>
it will impersonate the logged in user
If you do
<identity impersonate="true" userName="contoso\Jane" password="pass"/>
it will impersonate the user set above.
But if you don't impersonate at all and use windows authentication, it would make sense that it uses a default system account.
I do not know why it makes the first attempt as IUSR and then automatically switches to NETWORK SERVICE on subsequent requests. But I do know that when you jump from one server to another, the application pool credenticals are NOT used. Unless you set an impersonated user as shown below, NETWORK SERVICE is default account that is used to fetch resources outside the server.
<connectionStrings>
<add name="myConnectionString" connectionString="Data Source=MyServerName;Initial Catalog=MyDataBaseName;Integrated Security=True;"
providerName="System.Data.SqlClient" />
</connectionStrings>
<identity impersonate="true" userName="contoso\Jane" password="pass"/>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With