How to Impersonate

Guillermo recently started blogging about some Whidbey enhancements around impersonation.  However, figuring out how to impersonate in the first place can be a little less than obvious.

WindowsIdentity contains an Impersonate method, but it doesn’t accept any parameters.  That means that we’ll need to supply the user and password through some other means.  The constructor for WindowsIdentity that takes a string looks promising, however there doesn’t seem to be any way to get a password in.  Instead we’ll have to use the constructor that takes a token (as an IntPtr).  If we intend to go that route, then we might as well just use the static WindowsIdentity.Impersonate overload that takes a token directly.

OK, so how do we get that token?  Well, we can P/Invoke to LogonUserLogonUser takes a user name, domain, and password, and returns us a token that we can use with WindowsIdentity.  In addition to these parameters, LogonUser wants to know which logon provider to use (the default should suffice for most cases), and a logon type  Selecting a logon type can be a tricky, so lets take a look at our options.

Logon Type

Integer Value
(From WinBase.h)
Associated Rights
(From NTSecAPI.h)
BATCH 4 SeBatchLogonRight /
Perform a batch logon.  This is intended for servers where logon performance is vital.  LogonUser will not cache credentials for a user logged in with this type.
INTERACTIVE 2 SeInteractiveLogonRight /
Log a user into the computer if they will be interactively using the machine (for instance if your code is going to provide them with a shell).  LogonUser will cache credentials for a user logged in with this type.
NETWORK 3 SeBatchNetworkRight /
Similar to batch logon in that this logon type is intended for servers where logon performance is important.  Credentials will not be cached, and the token returned is not a primary token but an impersonation token instead.  It can be converted to a primary token with DuplicateHandle.
NETWORK_CLEARTEXT 8 SeBatchNetworkRight /
Similar to a network logon, except that the credentials are stored with the authentication package that validates the user.  This logon type is only available with the WINNT50 logon provider, and on Windows 2000 or higher.
NEW_CREDENTIALS 9 SeBatchNetworkRight /
Create a new set of credentials for network connections.  (For instance runas /netonly).  This logon type is only available with the WINNT50 logon provider and on Windows 2000 or higher.
SERVICE 5 SeServiceLogonRight /
Logon as a service.
UNLOCK 7 Reserved for use by GINA implementations.

One important thing to note is that in order to use WindowsIdentity.Impersonate(), we need a primary token, so if we go with LOGON32_LOGON_NETWORK, we’ll need to use DuplicateHandle in order to get at the primary token.  Since I like to avoid extra work like that, it looks like LOGON32_LOGON_BATCH or LOGON32_LOGON_INTERACTIVE would both be more appropriate choices.  Selecting between them will depend on the rights that the account we’re trying to logon has.

Once your call to LogonUser has gotten you a user token for the user you’d like to impersonate, you can then call WindowsIdentity.Impersonate() and have your thread take over the identity of the Windows user you just logged on.  The code might look something like this:

// Call LogonUser to get a token for the user
IntPtr userHandle = IntPtr.Zero();
bool loggedOn = LogonUser(
    out userHandle);
    throw new Win32Exception(Marshal.GetLastWin32Error());

// Begin impersonating the user
WindowsImpersonationContext impersonationContext = WindowsIdentity.Impersonate(userHandle.Token);


// Clean up

However this code has a very subtle security issue that’s just waiting to bite you.  Before I fix the problem tomorrow,  any guesses as to what might be wrong with the code?

Update 4:35 PM: Corrected an issue that wasn’t the bug I’m referring to above.

Comments (18)

  1. laimis says:

    The first thing that comes to my mind is that you don’t restore the process to its previous identity. First save the existing security context, impersonate, do priviledged work, restore back the security context to the original one.

  2. Shawn says:

    Shoot — you’re right, but that wasn’t the bug I was looking for 🙂 I’ve just updated to code to correct the issue.

    You’re on the right track though. Any other guesses?


  3. Dean Harding says:

    Well, if the username/password supplied is more privileged than you are, and an exception occurs in DoSomeWorkWhileImpersonating, then you don’t restore the original context either.

    Also, when you impersonate, the impersonated user’s registry hive isn’t loaded (i.e. HKEY_CURRENT_USER still points to the impersonating user’s hive, not the impersonatee) so that might be a problem if you try to access the registry.

  4. Eric Lippert says:

    Ah, this is one of my favourites. I wrote about this issue in my blog a few months ago:

    If an exception is thrown in DoSomeWorkWhileImpersonating then the caller up the stack — which might be less-privileged hostile code — gets to handle the exception. The caller then gets its privileges elevated.

    The obvious thing to do is use a finally block to ensure that the cleanup happens, but actually that is not sufficient either. The hostile caller could register an exception filter which runs BEFORE the finally block.

    You’ve got to be SUPER CAREFUL when impersonating in managed code if your caller can be partially trusted.

  5. Steve Dinn says:

    Something like this is begging for a little utility object that implements IDisposable so that you can use it with a <i>using</i> block. That way you <b>can’t</b> forget to set things back.

  6. kevin s says:

    can someone confirm that the impersonation context is on a per thread basis and not a per process basis. thx.

  7. Yes, impersonation is per-thread.


  8. Ali says:


    i do impersonation according to Microsoft Recommend .

    i use impersonation to access a file that it’s

    Folder have Acls permission for one user.

    the impersonation is ok and impersonate anonymous to user that have permission to access the file ,but again a popoup appear

    to enter username and password eo view file.

    my code is :

    Dim LOGON32_LOGON_INTERACTIVE As Integer = 2

    Dim LOGON32_PROVIDER_DEFAULT As Integer = 0

    Dim impersonationContext As WindowsImpersonationContext

    Declare Function LogonUserA Lib "advapi32.dll" (ByVal lpszUsername As String, _

    ByVal lpszDomain As String, _

    ByVal lpszPassword As String, _

    ByVal dwLogonType As Integer, _

    ByVal dwLogonProvider As Integer, _

    ByRef phToken As IntPtr) As Integer

    Declare Auto Function DuplicateToken Lib "advapi32.dll" ( _

    ByVal ExistingTokenHandle As IntPtr, _

    ByVal ImpersonationLevel As Integer, _

    ByRef DuplicateTokenHandle As IntPtr) As Integer

    Declare Auto Function RevertToSelf Lib "advapi32.dll" () As Long

    Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Long

    Public Sub Page_Load(ByVal s As Object, ByVal e As EventArgs)

    If impersonateValidUser("Doroudian", "ws9", "123") Then



    ‘Insert your code that runs under the security context of a specific user here.



    ‘Your impersonation failed. Therefore, include a fail-safe mechanism here.

    End If

    End Sub

    Private Function impersonateValidUser(ByVal userName As String, _

    ByVal domain As String, ByVal password As String) As Boolean

    Dim tempWindowsIdentity As WindowsIdentity

    Dim token As IntPtr = IntPtr.Zero

    Dim tokenDuplicate As IntPtr = IntPtr.Zero

    Dim princs As GenericPrincipal

    Dim rAdmin(0) As String

    impersonateValidUser = False

    If RevertToSelf() Then

    If LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT, token) <> 0 Then

    If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then

    tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)

    impersonationContext = tempWindowsIdentity.Impersonate()

    If Not impersonationContext Is Nothing Then

    impersonateValidUser = True

    End If

    End If

    End If

    End If

    End Function

    Many thanks for any guides



  9. Klaus says:

    (I am a newbie in VB 2005)

    I tried the code from Ali, however I cannot get it work. I did run it with ClientPC1LocalUser and tried to stop a service by WMI on RemotePC1 with RemotePC1User1.

    It always result in Login failed.

    What is wrong? I have too less knowledge to find the error.

    Thanks in advance


  10. Collin Roth says:

    So, can you tell me which friendly security policy name is associated with SeBatchNetworkRight?

  11. Joel says:

    How does this work across active directory, or does it?

    I have a user in active directory that I need to impersonate in Sharepoint, but cannot seem to use LogonUser for this.

  12. Agha Usman says:

    FileStream data type is a very important feature of SQL Server 2008 and gradually getting popular amongst