Impersonation Utility class

Below is a class I use when I need to do particular actions using impersionation. You create an instance of the class, attach an event handler to the ExecuteImpersonatedAction event and then call the Impersonate function passing the domain username and password for the user to impersonate. This will then do the impersonation raise the event to run your handler, then undo the impersonation.
Its not rocket science but it does stop you having to reinvent this wheel all the time.
 
Let me know what you think.
 
/// <summary>
/// Manages the execution of client code in the context of an impersonated user.
/// </summary>
public class ImpersonatedAction : IDisposable
{
[
DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(
string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[
DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(IntPtr handle);
 
private static IntPtr tokenHandle = IntPtr.Zero;
private static WindowsImpersonationContext impersonatedUser;
/// <summary>
/// Raises an event that can execute code in the impersonated user’s context.
/// </summary>
public event EventHandler<EventArgs> ExecuteImpersonatedAction;
/// <summary>
/// Creates a new instance of the <see cref="ImpersonatedAction"/> class,
/// </summary>
public ImpersonatedAction()
{
}

/// <summary>
/// Impersonates a specified user account and raises the <see cref="ExecuteImpersonatedAction"/>
/// event for client actions running unde the impersonated context.
/// </summary>
/// <param name="domain">The impersonating user’s account domain.</param>
/// <param name="userName">The impersonating user’s account name.</param>
/// <param name="password">The impersonating user’s account password.</param>
/// <remarks></remarks>
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public void Impersonate(string domain, string userName, SecureString password)
{
try
{
const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;
const int LOGON32_LOGON_NETWORK = 3;
const int LOGON32_LOGON_BATCH = 4;
const int LOGON32_LOGON_SERVICE = 5;
const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
tokenHandle =
IntPtr.Zero;
// Get password
IntPtr ptr = Marshal.SecureStringToBSTR(password);
string pw = Marshal.PtrToStringUni(ptr);
Marshal.ZeroFreeBSTR(ptr);
// Logon impersonation user
bool returnValue = LogonUser(
userName,
domain,
pw,
LOGON32_LOGON_NETWORK_CLEARTEXT,
LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);
if (!returnValue)
{
int ret = Marshal.GetLastWin32Error();
Trace.WriteLine(String.Format("LogonUser call failed with error code {0}.", ret));
throw new Win32Exception(ret);
}
// Create impersonated context
impersonatedUser = WindowsIdentity.Impersonate(tokenHandle);
// Execute client action
this.OnExecuteImpersonatedAction();
}
finally
{
// Undo impersonation
if (impersonatedUser != null)
{
impersonatedUser.Undo();
}
impersonatedUser =
null;
// Release pointer
if (tokenHandle != IntPtr.Zero)
{
CloseHandle(tokenHandle);
}
tokenHandle =
IntPtr.Zero;
}
}
/// <summary>
/// Raises the <see cref="ExecuteImpersonatedAction"/> event.
/// </summary>
protected virtual void OnExecuteImpersonatedAction()
{
if (ExecuteImpersonatedAction != null)
{
this.ExecuteImpersonatedAction(this, EventArgs.Empty);
}
}
#region IDisposable Members

// Track whether Dispose has been called
private bool disposed = false;
/// <summary>
/// Releases all resources used by the <see cref="ImpersonatedAction"/>.
/// </summary>
public void Dispose()
{
this.Dispose(true);
// Remove this object from the Finalization queue to prevent second execution of finalization code
GC.SuppressFinalize(this);
}
/// <summary>
/// Disposes the instance’s managed and unmanaged resources.
/// </summary>
/// <param name="disposing">Set true to indicate that the method has been called directly
/// or indirectly by a user’s code.
/// Set false to indicate that the method has been called by the runtime from inside the
/// finalizer</param>
protected virtual void Dispose(bool disposing)
{
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user’s code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
// Check to see if Dispose has already been called.
if (!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
// Dispose managed resources
if (impersonatedUser != null)
{
impersonatedUser.Undo();
}
}
// Dispose unmanaged resources
if (tokenHandle != IntPtr.Zero)
{
CloseHandle(tokenHandle);
}
}
disposed =
true;
}
/// <summary>
/// The class destructor.
/// </summary>
~ImpersonatedAction()
{
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
this.Dispose(false);
}
#endregion
}

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

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