The Code Slinger

November 12, 2008

Impersonation & IDisposable

Filed under: .NET,C#,IDisposable,Impersonation — Pete @ 11:25 am

I’ve used an impersonation helper class for a while now, basically to encapsulate changing the current identity context while executing certain code.  This worked well, however I always got sick of having to remember to call the “undo()” method of my current implementation once I was done with executing my code under whatever login I was impersonating.

So, I updated the class to implement IDisposable so that I can now utilize this within the using() construct provided in C#.   Here’s the class in it’s entirety:

using System;

using System.Runtime.InteropServices;

using System.Security.Principal;

 

namespace Support.Win32

{

    public class Impersonate : IDisposable

    {

        public const int LOGON32_LOGON_INTERACTIVE = 2;

        public const int LOGON32_PROVIDER_DEFAULT = 0;

 

        WindowsImpersonationContext impersonationContext;

 

        public Impersonate()

        {

            //Default login is used.

            this.impersonateValidUser(“username”, “domain”, “password”);

        }

 

        public Impersonate(string username, string domain, string password)

        {

            this.impersonateValidUser(username, domain, password);

        }

 

        [DllImport(“advapi32.dll”)]

        private static extern int LogonUserA(String lpszUserName,

            String lpszDomain,

            String lpszPassword,

            int dwLogonType,

            int dwLogonProvider,

            ref IntPtr phToken);

        [DllImport(“advapi32.dll”, CharSet = CharSet.Auto, SetLastError = true)]

        private static extern int DuplicateToken(IntPtr hToken,

            int impersonationLevel,

            ref IntPtr hNewToken);

 

        [DllImport(“advapi32.dll”, CharSet = CharSet.Auto, SetLastError = true)]

        private static extern bool RevertToSelf();

 

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

        private static extern bool CloseHandle(IntPtr handle);

 

        private bool impersonateValidUser(string userName, string domain, string password)

        {

            WindowsIdentity tempWindowsIdentity;

            IntPtr token = IntPtr.Zero;

            IntPtr tokenDuplicate = IntPtr.Zero;

 

            if (RevertToSelf())

            {

                if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,

                    LOGON32_PROVIDER_DEFAULT, ref token) != 0)

                {

                    if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)

                    {

                        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);

                        impersonationContext = tempWindowsIdentity.Impersonate();

                        if (impersonationContext != null)

                        {

                            CloseHandle(token);

                            CloseHandle(tokenDuplicate);

                            return true;

                        }

                    }

                }

            }

            if (token != IntPtr.Zero)

                CloseHandle(token);

            if (tokenDuplicate != IntPtr.Zero)

                CloseHandle(tokenDuplicate);

            return false;

        }

 

        private void undoImpersonation()

        {

            impersonationContext.Undo();

        }

 

        public void Dispose()

        {

            Dispose(true);

            GC.SuppressFinalize(this);

        }

 

        ~Impersonate()

        {

            Dispose(false);

        }

 

        protected virtual void Dispose(bool disposing)

        {

            if(disposing)

            {

                //Dispose of managed resources.

                if(impersonationContext != null)

                {

                    this.undoImpersonation();

                    impersonationContext.Dispose();

                    impersonationContext = null;

                }

            }

        }

    }

}

 

Basically, now my code can use the following construct in order to execute code in an impersonated context:

 

                using(var imp = new Impersonate(“username”, “domain”, “password”))

                {

                    //Code that I want to run under this account.

                }

 
That’s it! Now I can be lazy and not have to worry about everything getting “cleaned up”.  What’s more, is I’ve made private the actual calls to impersonateValidUser expressly so that it forces me to use this with the using construct. 
 
Til next time…..keep on slangin!
Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: