Sunday 24 September 2017

Impersonation for Windows User c#

Problem Statement:
Often we have to execute a code with elevated rights as the current user(Windows Account) might not have access to the resource. One scenario could be a console application trying to update a Sql Server database but the user might not have appropriate access.

The solution to this is WindowsIdentity.Impersonate() function available. But it turns out that it's not that easy to use. You might run into issue which make it tough to implement.

Solution: 
I have a class for you which will take care of all the implementation issues.

Class: 
public class ImpersonateUser
    {
        // Fields
        private WindowsImpersonationContext _impersonatedUser;
        private IntPtr _tokenHandle = new IntPtr(0);

        // Methods
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);

        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        public void Impersonate(NetworkCredential credentials)
        {
            this.Impersonate(credentials.Domain, credentials.UserName, credentials.Password);
        }

        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        public void Impersonate(string domainName, string userName, string password)
        {
            this._tokenHandle = IntPtr.Zero;
            if (!LogonUser(userName, domainName, password, 2, 0, ref this._tokenHandle))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
            this._impersonatedUser = new WindowsIdentity(this._tokenHandle).Impersonate();
        }

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        public void Undo()
        {
            if (this._impersonatedUser != null)
            {
                this._impersonatedUser.Undo();
            }
            if (this._tokenHandle != IntPtr.Zero)
            {
                CloseHandle(this._tokenHandle);
            }
        }
    }
==============================================================
How To Use This Class :
Step 1. Create Impersonate Class object

            ImpersonateUser impersonate = new ImpersonateUser();

Step 2. Call Impersonate Method (This will change the current WindowsIdentity)
            impersonate.Impersonate(new NetworkCredential("userid", "password"));

            OR
           
 impersonate.Impersonate("domainName", "userid", "password"));


Step 4. //Operation on your database.


Step 4. Undo the Impersonation After JOB is done
               if (impersonate != null)
               { impersonate.Undo(); }

Note: If You want to check the WindowsIdentity in between these steps : Use below code.
 using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
 {
       string windowsLoginName = identity.Name;
       Console.WriteLine(string.Format("Current User Login Name: {0}", windowsLoginName));
  }
================================================================
I am sure you will find this class useful in your implementation.
Happy Coding :)

No comments:

Post a Comment