Double Hop and ASP.NET - a workaround.

Tags: .NET, CodeSnippets

<Background>
Many people have stumbled across the IIS Double-Hop issue when trying to access Active Directory information on an ASP.NET page.
In short - when we access an ASP.NET page, IIS can impersonate our user credentials for code execution (if set in the web.config). On Windows networks, impersonated credentials can't be used to access network resources - this prevents a web-server from maliciously or accidently using the credentials of a user who innocently logged on to it to access protected network resources.
The problem is that when we try to access the Active Directory for legitimate purposes (to display the current user's details, for instance) while impersonating the user (as SPS does by default) we can't pass the credentials on and our AD query uses the understandbly-limited Anonymous Logon account.

The suggested workaround is to supply teh DirectoryServices request with a username and password so as not to use the impersonated credentials - but this, of course, opens up a whole set of problems relating to security and maintainability.
</Background>

<Solution>
This workaround will work only if the IIS worker process is running under a domain account.
Under IIS 6 - this is the user specified in the Identity tab of the Application Pool.
Under IIS 5 - this is the user specified in the Identity tab of the COM+ application that is generated for the IIS application.

Since our problem arises from having our code run in an impersonation context, the solution is simply to undo the impersonation so that the executing identity isn't the connecting user, but the user who started the process. Since we don't have any convenient .NET WindowsImpersonationContext object we can Undo(), we'll simply have to go deeper into Win32 code:

[DllImport("advapi32.dll")]
private static extern int RevertToSelf();

This very simple function (no parameters - no marshalling! Yipee!) will cancel the current impersonation session and return the actual running user - our IIS WP identity.
It would be prudent to re-impersonate the connected user after our code runs:

WindowsIdentity connectedUser = WindowsIdentity.GetCurrent();
RevertToSelf();
// DirectoryServices code here.
connectedUser.Impersonate()

If this revert/reimpersonate code is something we'll be running a lot, it would be nice to wrap this in a nice disposable object so we can wrap our code in a using() block:

using (new UnImpersonator())
{
   // Code running as the Worker Process identity.
}

This is similar to the ImpersonationContext class I described here - the constructor will save the current Identity in a member and call Revert, and the Dispose() will re-impersonate the user.

 </Solution>

13 Comments

  • Jack said

    I wish that worked for me.. Unfortunately it did not... My app pool is a Domain Admin but I still have issues.... Hopefully this will solve someone elses problems

  • Thomas Barns said

    My application pool currently uses the network service. How can I change that to a domain account without having it constantly asking for a login? There seems to be some sort of a problem with my setup.

  • Jens said

    Hello Guys i have the same problem like Thomas. after changing the account to a domain user it is contantly asking for a login. no mather what i input. do someone has a solution yet?

  • Cory Loriot said

    I bow down at your feet.... been working this issue for about a week now... spending about 8 1/2 of my 12 hour days googling... Can you believe that I didn't start getting good answers until I hit Ask.com? who would have thought... ? Anyways... implemented this fix into a SharePoint web part... worked like a dream.

  • Cory said

    Concerning the issues of thomas and jen... I am sure that they have been addressed by now, but consider checking if you are authenticating through Basic Authentication or NTLM... Basic authentication on the IIS Virtual server will cause a username and password to have to be entered multiple times.

  • T101 said

    the following code does very similar: SPSecurity.RunWithElevatedPrivileges(delegate() { listService.AllowAutoRedirect = false; listService.PreAuthenticate = true; listService.Credentials = (NetworkCredential)System.Net.CredentialCache.DefaultNetworkCredentials;

  • Ayomide said

    The Double Hop problem is hendering me from going forward with my app, part of the problem is my not fully understanding what it is am to do to render a workable solution from many various web pages offering diferent explanations. That being stated, the parameters I have are: IIS 6, ASP.NET 2.0 Framework, VB Code, SQL Server 2005, Active Directory. And of course the double hop issue. The scenario is: SQL Server on server S9999, application on server A12345, Active Directory on server AD 56567. Please, PLEASE what code do I write? And where, I have been researching for the past four weeks without a solution I can implement and follow.

  • tobi said

    Great, this worked painlessly for me (even 6 years after your original posting). I had googled for hours and was mentally preparing for Basic Auth/SSL or a Kerberos configuration journey... Thanks!

Comments have been disabled for this content.