This impersonate class has been designed to enable the running of code segment a user under different security context to that which is the norm. The typical example is allowing the ASP.NET account to have access to network drives while the running in the context of the ASP.NET account. This class by design implements the IDisposable interface allowing the context to automatically revert with a using statement.

Namespace:  CA.Common.Security
Assembly:  CA.Common (in CA.Common.dll) Version: 1.0.0.0 (1.0.0.0)

Remarks

Using the dispose method makes it possible to use the Impersonate class with a using class in c#
CopyQuick Example of using Impersonate class using the C# using statement
using (new Impersonate(User, Domain, Password))
{ 
 //.. do work with new security context
}
CopyFull source code for the Impersonate class
//Source code from the Code Associate C# code library, Full documentation and latest updates can be found
//@ http://www.codeassociate.com/caapi/
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace CA.Common.Security
{
    public class ImpersonateException : Exception
    {
        public ImpersonateException(string Message) : base(Message)
        {

        }
    }

    public class Impersonate : IDisposable
    {
        private const int LOGON32_LOGON_INTERACTIVE = 2;
        private const int LOGON32_PROVIDER_DEFAULT = 0;
-        #region windows API calls
         [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);
         #endregion

        readonly WindowsImpersonationContext impersonationContext;

        public Impersonate(string userName, string domain, string password)
        {
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;
            // firstly force any current Impersonation to revert to the default security context  
            if(RevertToSelf())
            {
                // Call the LogonUserA to authenticate the user and get the users token
                if(LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
                    LOGON32_PROVIDER_DEFAULT, ref token) != 0)
                {

                    //The DuplicateToken function creates an impersonation token which can be used when creating a new windows identity 
                    if(DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                    {
                        WindowsIdentity tempWindowsIdentity;
                        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                        impersonationContext = tempWindowsIdentity.Impersonate();
                        // we have the impersonationContext so we can close the handles to the tokens
                        if (impersonationContext != null)
                        {
                            CloseHandle(token);
                            CloseHandle(tokenDuplicate);
                        }
                    }
                    else
                    {
                        if (token != IntPtr.Zero)
                            CloseHandle(token);
                        if(tokenDuplicate!=IntPtr.Zero)
                            CloseHandle(tokenDuplicate);
                        throw new ImpersonateException(string.Format("Impersonation Failed - DuplicateToken ({0})", userName));
                    }
                }
                else
                {
                    if(token!= IntPtr.Zero)
                        CloseHandle(token);
                    throw new ImpersonateException(string.Format("Impersonation Failed - LogonUserA ({0})", userName));
                }
            }
            else
            {
                throw new ImpersonateException("Impersonation Failed - RevertToSelf");
            }
        }

        public void Dispose()
        {       
            impersonationContext.Undo();
        }
    }
}

Examples

CopyUnit Tests source code showing useage of the Impersonate class
//Source code from the Code Associate C# code library, Full documentation and latest updates can be found
//@ http://www.codeassociate.com/caapi/
using System.Configuration;
using System.Diagnostics;
using System.Security.Principal;
using CA.Common.Security;
using NUnit.Framework;

namespace CA.Common.UnitTest.Security
{
    [TestFixture]
    public class Impersonate_UnitTest
    {

        [Test]
        public void TestValidImpersonate()
        {
            // get the user name password and domain from the config file
            string User = ConfigurationManager.AppSettings["ImpersonateTestUser"].ToString();
            string Password = ConfigurationManager.AppSettings["ImpersonateTestPassword"].ToString();
            string Domain = ConfigurationManager.AppSettings["ImpersonateTestDomain"].ToString();

            // Now get the  user name currently running
            string BeforeImpersonateorIdentityName = WindowsIdentity.GetCurrent().Name;
            Trace.WriteLine(BeforeImpersonateorIdentityName);
            // Now begin the Impersonate under a new account
            using (new Impersonate(User, Domain, Password))
            {
                // this is is expected name after the Impersonate
                string ExpectedIdentityName = Domain + "\\" + User;
                // Now get the current WindowsIdentity name inside the Impersonate
                string ActualIdentityNameInImpersonate = WindowsIdentity.GetCurrent().Name;
                Trace.WriteLine(ActualIdentityNameInImpersonate);
                // test that the expected is the same as the ActualIdentityNameInImpersonate do ToLower as names and domains are case insensitive 
                Assert.AreEqual(ExpectedIdentityName.ToLower(), ActualIdentityNameInImpersonate.ToLower());
            }
            // get the Name after the Impersonate section is done.. this should revert the identity 
            string AfterImpersonateorIdentityName = WindowsIdentity.GetCurrent().Name;
            Trace.WriteLine(AfterImpersonateorIdentityName);
            // do the test the the BeforeImpersonateorIdentityName is the same as the AfterImpersonateorIdentityName
            Assert.AreEqual(BeforeImpersonateorIdentityName.ToLower(), AfterImpersonateorIdentityName.ToLower());
        }


        [Test]
        [ExpectedException(typeof(ImpersonateException))]
        public void TestInvalidImpersonate()
        {

            using (Impersonate Impersonateor = new Impersonate("baduser", "workgroup", "badPassword"))
            {
                // This should should never get executed as Impersonate should fail
                // and raise the expected ImpersonateException unless you have the user password domain combo as hard coded

            }
        } 
    }
}

Inheritance Hierarchy

System..::.Object
  CA.Common.Security..::.Impersonate

See Also