WindowsIdentity Impersonation using C# Code


using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.Security.Permissions;


namespace Test
{
    public class ImpersonateUser
    {
        [DllImport(“advapi32.dll”, SetLastError = true)]
        public static extern 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);
        private static IntPtr tokenHandle = new IntPtr(0);
        private static WindowsImpersonationContext impersonatedUser;
        // If you incorporate this code into a DLL, be sure to demand that it
        // runs with FullTrust.
        [PermissionSetAttribute(SecurityAction.Demand, Name = “FullTrust”)]
        public void Impersonate(string domainName, string userName, string password)
        {
            //try
            {
                // Use the unmanaged LogonUser function to get the user token for
                // the specified user, domain, and password.
                const int LOGON32_PROVIDER_DEFAULT = 0;
                // Passing this parameter causes LogonUser to create a primary token.
                const int LOGON32_LOGON_INTERACTIVE = 2;
                tokenHandle = IntPtr.Zero;
                // —- Step – 1
                // Call LogonUser to obtain a handle to an access token.
                bool returnValue = LogonUser(
                userName,
                domainName,
                password,
                LOGON32_LOGON_INTERACTIVE,
                LOGON32_PROVIDER_DEFAULT,
                ref tokenHandle); // tokenHandle – new security token
                if (false == returnValue)
                {
                    int ret = Marshal.GetLastWin32Error();                   
                    throw new System.ComponentModel.Win32Exception(ret);
                }
                // —- Step – 2
                WindowsIdentity newId = new WindowsIdentity(tokenHandle);
                // —- Step – 3
                impersonatedUser = newId.Impersonate();
            }
        }
        // Stops impersonation
        public void Undo()
        {
            impersonatedUser.Undo();
            // Free the tokens.
            if (tokenHandle != IntPtr.Zero)
                CloseHandle(tokenHandle);
        }
    }
}


how to use it


             ImpersonateUser iu = new ImpersonateUser();
            iu.Impersonate(“domain”, “userName”, “password”);
            //your code
            iu.Undo();


Comments (21)

  1. mettlus shaw says:

    works! though how can I accomplish same thing via web.config on IIS7?

    Thanks

  2. Dylan Baxter says:

    A very useful addition to my class library! Thank you!

  3. Agha Usman says:

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

  4. hassan says:

    When program was performing,The error is shown:

    Logon failure: unknown user name or bad password.

    please help me

  5. Ron Laughton says:

    In answer to Mettlus:

    web.config

    <configuration>

      <system.web>

       <identity impersonate="true" userName="DOMAINUSERNAME" password="PASSWORD" />

      </system.web>

    </configuration>

    However, it may not be wise to let every session have impersonation.

  6. David says:

    I’ve been looking for some time for code that will allow me to perform an identity impersonate within a HttpModule and this code did exactly what I needed. Thanks.

  7. Adeel says:

    Please giuide me the domain name is the Server Machine name or Remote Machine name?

  8. Marten vanZwietering says:

    I rarely post in these things but I just wanted to let you know I really liked this code – and it did exactly what I needed.

  9. Usman says:

    Great Code; Works Perfectly. Thank you for that

  10. Dodge says:

    Excellent code, helped me a lot

  11. felixperro says:

    Thanks for sharing.  This helped me out.

    I was having trouble impersonating with WindowsIdentity(sUserPrincipleName) and kept getting an "Invalid Function" error message.  This method, although requiring an explicit password, seems to work better.

  12. PRMan says:

    If you want to use it in a using block, use this code instead:

       public class ImpersonatedUser : IDisposable

       {

           private string _domain = "";

           private string _username = "";

           private string _password = "";

           public ImpersonatedUser(string Domain, string Username, string Password)

           {

               _domain = Domain;

               _username = Username;

               _password = Password;

               Impersonate();

           }

           [DllImport("advapi32.dll", SetLastError = true)]

           public static extern bool LogonUser(string User, string Domain, string Password, int LogonType, int LogonProvider, ref IntPtr Token);

           [DllImport("kernel32.dll", CharSet = CharSet.Auto)]

           public extern static bool CloseHandle(IntPtr handle);

           private static IntPtr tokenHandle = new IntPtr(0);

           private static WindowsImpersonationContext impersonatedUser;

           // If you incorporate this code into a DLL, be sure to demand that it

           // runs with FullTrust.

           /// <summary>

           /// Impersonates another Windows user

           /// </summary>

           /// <param name="Domain">The domain of the user to impersonate</param>

           /// <param name="Username">The username of the user to impersonate</param>

           /// <param name="Password">The password of the user to impersonate</param>

           [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]

           private void Impersonate()

           {

               //try

               {

                   // Use the unmanaged LogonUser function to get the user token for

                   // the specified user, domain, and password.

                   const int defaultProvider = 0;

                   // Passing this parameter causes LogonUser to create a primary token.

                   const int interactive = 2;

                   tokenHandle = IntPtr.Zero;

                   // —- Step – 1

                   // Call LogonUser to obtain a handle to an access token.

                   bool returnValue = LogonUser(_username, _domain, _password, interactive, defaultProvider, ref tokenHandle);

                   if (false == returnValue)

                   {

                       int ret = Marshal.GetLastWin32Error();

                       throw new System.ComponentModel.Win32Exception(ret);

                   }

                   // —- Step – 2

                   WindowsIdentity newId = new WindowsIdentity(tokenHandle);

                   // —- Step – 3

                   impersonatedUser = newId.Impersonate();

               }

           }

           // Stops impersonation

           public void Undo()

           {

               impersonatedUser.Undo();

               // Free the tokens.

               if (tokenHandle != IntPtr.Zero)

                   CloseHandle(tokenHandle);

           }

           #region IDisposable Members

           public void Dispose()

           {

               Dispose(true);

               GC.SuppressFinalize(this);

           }

           protected virtual void Dispose(bool Disposing)

           {

               if (Disposing)

               {

                   _domain = null;

                   _username = null;

                   _password = null;

               }

               if (impersonatedUser != null)

                   Undo();

               impersonatedUser = null;

           }

           ~ImpersonatedUser()

           {

               Dispose(false);

           }

           #endregion

       }

    Then you can say:

    using (new ImpersonatedUser(domain, username, password))

    {

       // You are the impersonated user inside here

    }

  13. Mike O'Meara says:

    Yes perfect! Just what I was looking for! Thanks

  14. Mike OMeara says:

    Yes perfect! Just what I was looking for! Thanks

  15. Pawan Kumar says:

    thanx lott… After 2 days my problem is solved… thank you. perfect Code.  

  16. taralex says:

    Exactly what I need, but LogonUser returns false every time, I'm sure the credentials are correct…

  17. Flame says:

    Thank you, Sir! Thank you, thank you, thank you!!

  18. SJ says:

    I am using this code, it's working fine but intermittently I get following error:

    Invalid token for impersonation – it cannot be duplicated.  or The handle is invalid.

    Any help will be appreciated.

  19. YS says:

    Hi.

    Regarding:

           private static IntPtr tokenHandle = new IntPtr(0);

           private static WindowsImpersonationContext impersonatedUser;

    Those two fields are declared static. I'd like to know (if anyone's still checking this blog):-

    01. Are there any benefits in declaring those variables as  static ?

    02. Are there any consequences (ie: danger) by having those two as static ? I'm talking about using this in ASP.NET environment.

    Cheers.

  20. is it possible without providing password says:

    have a requirement, where I need to impersonate a logon user using the database account (the database account has access to system tables). I don't want to expose the password, by providing in a web.config file. is there a way to impersonate the logon user using database account without providing the password.