Fri
Apr 20
2007

Impersonate User

/// <summary>
/// Impersonate a user within the current thread.
/// This class will automatically revert the user to the original user 
/// identity when this class is disposed. Use this class with the 
/// C# using or a try/catch block to ensure the user is reverted
/// after an exception.
/// 
/// Suggested usage:
/// using (new ImpersonateHelper("domain", "joe", "password"))
/// {
///     ...code to run as joe
/// }
/// ...code to run as orignial user
/// 
/// Note, this implementation is vulnerable to "exception filter" attacks
/// as described below. Evaluate it against the risk of other attacks
/// such as the credential store used to impersonate.
/// http://blogs.msdn.com/shawnfa/archive/2005/03/22/400749.aspx
/// </summary>
public class ImpersonationHelper : IDisposable
{
    IntPtr m_tokenHandle = new IntPtr(0);
    WindowsImpersonationContext m_impersonatedUser;
 
    #region Win32 API Declarations
 
    const int LOGON32_PROVIDER_DEFAULT = 0;
    const int LOGON32_LOGON_INTERACTIVE = 2;    //This parameter causes LogonUser to create a primary token.
 
    [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);
 
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, 
    int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
 
    #endregion
 
    /// <summary>
    /// Constructor. Impersonates the requested user. Impersonation lasts until
    /// the instance is disposed.
    /// </summary>
    public ImpersonationHelper(string domain, string user, string password)
    {
        // Call LogonUser to obtain a handle to an access token.
        bool returnValue = LogonUser(user, domain, password,
            LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
            ref m_tokenHandle);
        if (false == returnValue)
        {
            int ret = Marshal.GetLastWin32Error();
            throw new System.ComponentModel.Win32Exception(ret);
        }
 
        // Impersonate
        m_impersonatedUser = new WindowsIdentity(m_tokenHandle).Impersonate();
    }
 
    #region IDisposable Pattern
 
    /// <summary>
    /// Revert to original user and cleanup.
    /// </summary>
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // Revert to original user identity
            if (m_impersonatedUser != null)
                m_impersonatedUser.Undo();
        }
 
        // Free the tokens.
        if (m_tokenHandle != IntPtr.Zero)
            CloseHandle(m_tokenHandle);
    }
 
    /// <summary>
    /// Explicit dispose.
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
 
    /// <summary>
    /// Destructor
    /// </summary>
    ~ImpersonationHelper()
    {
        Dispose(false);
    }
 
    #endregion
}

Leave a reply

© 2006 Brian Low. All rights reserved.