PRB: "Unable to Impersonate User" Error Message When You Use WindowsIdentity.Impersonate Method

Article translations Article translations
Article ID: 319615 - View products that this article applies to.
This article was previously published under Q319615
Expand all | Collapse all

SYMPTOMS

When you use the System.Security.Principal.WindowsIdentity.Impersonate method, you may receive the following error message:
Unable to impersonate user.

CAUSE

This problem occurs because of the type of token that is used when the WindowsIdentity object is created. You receive the error message that is listed in the "Symptoms" section if the token is not a primary token when you try to impersonate. You must have an impersonation token for the WindowsIdentity.Impersonate method to work.

RESOLUTION

To obtain a primary token from an impersonation token, use the DuplicateToken Win32 function.

STATUS

This bug was corrected in Microsoft .NET Framework Class Libraries 1.1.

MORE INFORMATION

Use the Visual C# sample code that follows to reproduce the error message. This code passes the LOGON32_LOGON_INTERACTIVE value to the LogonUser function, which causes the token that is being created to be a primary token. This code also passes the SecurityImpersonation element to the DuplicateToken function. This allows the token that is being duplicated to be an impersonation token.
using System;
using System.Security.Principal;
using System.Runtime.InteropServices;

public class LogonUserNS
{
    [DllImport("advapi32.dll", SetLastError=true)]
    public extern static bool LogonUser(String lpszUsername, String lpszDomain, 
        String lpszPassword, int dwLogonType, 
        int dwLogonProvider, ref IntPtr phToken);
    
    [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);

    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, 
        int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

    public static void Main(string[] args)
    {               
        IntPtr tokenHandle = new IntPtr(0);
        IntPtr dupeTokenHandle = new IntPtr(0);

        try
        {
            if (args.Length < 3)
            {
                Console.WriteLine("Usage: DomainName UserName Password");
                return;
            }
            // args[0] - DomainName
            // args[1] - UserName
            // args[2] - Password

            const int LOGON32_PROVIDER_DEFAULT = 0;
            //This parameter causes LogonUser to create a primary token.
            const int LOGON32_LOGON_INTERACTIVE = 2;
            const int SecurityImpersonation = 2;

            tokenHandle = IntPtr.Zero;
            dupeTokenHandle = IntPtr.Zero;

            // Call LogonUser to obtain an handle to an access token.
            bool returnValue = LogonUser(args[1], args[0], args[2], 
                LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                ref tokenHandle);
            
            if (false == returnValue)
            {
                Console.WriteLine("LogonUser failed with error code : {0}",
                    Marshal.GetLastWin32Error());
                return;
            }

            // Check the identity.
            Console.WriteLine("Before impersonation: "
                + WindowsIdentity.GetCurrent().Name);
        
            // The token that is passed to the following constructor must 
            // be a primary token to impersonate.
            WindowsIdentity newId = new WindowsIdentity(tokenHandle);
            WindowsImpersonationContext impersonatedUser = newId.Impersonate();

            // Check the identity.
            Console.WriteLine("After impersonation: "
                + WindowsIdentity.GetCurrent().Name);
    
            // Stop impersonating.
            impersonatedUser.Undo();

            // Check the identity.
            Console.WriteLine("After Undo: " + WindowsIdentity.GetCurrent().Name);
        
            // Free the tokens.
            if (tokenHandle != IntPtr.Zero)
                CloseHandle(tokenHandle);
            if (dupeTokenHandle != IntPtr.Zero) 
                CloseHandle(dupeTokenHandle);
        }
        catch(Exception ex)
        {
            Console.WriteLine("Exception occurred. " + ex.Message);
        }
    }
}
				
To resolve this problem, call the code that follows before you create the WindowsIdentity object. You can then pass the duplicated token to the constructor of the WindowsIdentity object.
bool retVal = DuplicateToken(tokenHandle, SecurityImpersonation, ref dupeTokenHandle);
if (false == retVal)
{
  CloseHandle(tokenHandle);
  Console.WriteLine("Exception in token duplication.");		
  return;
}
				

REFERENCES

For more information, visit the following MSDN Web sites:
LogonUser
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/Security/logonuser.asp

DuplicateToken
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/Security/duplicatetoken.asp

Properties

Article ID: 319615 - Last Review: February 12, 2007 - Revision: 3.3
APPLIES TO
  • Microsoft .NET Framework Class Libraries 1.0
Keywords: 
kbkernbase kbprb kbsecurity KB319615
Retired KB Content Disclaimer
This article was written about products for which Microsoft no longer offers support. Therefore, this article is offered "as is" and will no longer be updated.

Give Feedback

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com