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.