Impersonate a Windows Identity Easily!

Not Me

Why would you want to do Windows Identity impersonation?

Because it’s cool. Really. You can run a program as someone other than who you are. This is especially useful for services, websites, and pretty much anything where you want to run an application in a mode that has different privileges. Do you want more permissions than normal? Use an application in a domain? Lock it down? The sky is the limit!

How is it done?

That part is pretty simple. In fact it’s outlined on this MSDN page. I’ve also got it wrapped up in a much easier to use class here:

using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;
using Microsoft.Win32.SafeHandles;
 
namespace ConsoleApplication1
{
    /// Impersonates a windows identity.
    /// Based on: http://msdn.microsoft.com/en-us/library/w070t6ka.aspx
    public class WindowsIdentityImpersonator : IDisposable
    {
        WindowsIdentity _newId;
        SafeTokenHandle _safeTokenHandle;
        WindowsImpersonationContext _impersonatedUser;
 
        public WindowsIdentity Identity { get { return _newId; } }
 
        [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
        public WindowsIdentityImpersonator(string Domain, string Username, string Password)
        {
            bool returnValue = LogonUser(Username, Domain, Password, 2, 0, out _safeTokenHandle);
 
            if (returnValue == false)
            {
                throw new UnauthorizedAccessException("Could not login as " + Domain + "\\" + Username + ".",
                    new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()));
            }
        }
 
        public void BeginImpersonate()
        {
            _newId = new WindowsIdentity(_safeTokenHandle.DangerousGetHandle());
            _impersonatedUser = _newId.Impersonate();
        }
 
        public void EndImpersonate()
        {
            if (_newId != null)
            {
                _newId.Dispose();
            }
 
            if (_impersonatedUser != null)
            {
                _impersonatedUser.Dispose();
            }
        }
 
        public void Dispose()
        {
            this.EndImpersonate();
 
            if (_safeTokenHandle != null)
            {
                _safeTokenHandle.Dispose();
            }
        }
 
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
            int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);
    }
 
    public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        private SafeTokenHandle() : base(true)
        {
        }
 
        [DllImport("kernel32.dll")]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);
 
        protected override bool ReleaseHandle()
        {
            return CloseHandle(handle);
        }
    }
}

Using this class is simple:

using (var wim = new WindowsIdentityImpersonator("domain", "username", "password"))
{
    wim.BeginImpersonate();
    {
        Console.WriteLine("Thread B: {0}", WindowsIdentity.GetCurrent().Name);
    }
    wim.EndImpersonate();
}

For domain if you want to use your local machine just put in “.”

Ok, that’s cool but what else have you got?

You want more? Okay wise guy, throw this bad boy in a separate thread (even a ThreadPool will work) and you can run that thread under this identity. Want another one? Start another thread. It’s that easy! One application can perform actions under a hundred different identities!

Happy coding!