Skip to content

Instantly share code, notes, and snippets.

@lski
Created December 24, 2014 14:59
Show Gist options
  • Save lski/c7d60af59272236b6fdd to your computer and use it in GitHub Desktop.
Save lski/c7d60af59272236b6fdd to your computer and use it in GitHub Desktop.
IDisposible wrapper for running code as a different user. Designed to be using in an using statement.
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
/// <summary>
/// IDisposible wrapper for running code as a different user. Designed to be using in an using statement.
///
/// An adaptation of a sample from Msdn.
/// </summary>
public class Impersonate : IDisposable {
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
private WindowsImpersonationContext impersonationContext;
private String Domain;
private String Username;
private String Password;
[DllImport("advapi32.dll")]
public 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)]
public static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
/// <summary>
/// States whether impersonation has been successful and is running. If not handle the issue.
/// </summary>
public Boolean IsImpersonated { get; set; }
/// <summary>
/// Creates a new impersonation object, that means code run between this constructor and being disposed (undone) is run as the user passed
/// </summary>
/// <param name="username">Username to impersonate</param>
/// <param name="domain">The domain the user lives in</param>
/// <param name="password">The users password</param>
public Impersonate(String username, String domain, String password) {
this.Username = username;
this.Password = password;
this.Domain = domain;
this.IsImpersonated = this.RunImpersonation();
}
/// <summary>
/// Creates a new impersonation object, that means code run between this constructor OR the the run command and being disposed (undone) is run as the user passed
/// </summary>
/// <param name="username">Username to impersonate</param>
/// <param name="domain">The domain the user lives in</param>
/// <param name="password">The users password</param>
/// <param name="impersonateNow">If true, calls RunImpersonate automatically, true by default</param>
public Impersonate(String username, String domain, String password, Boolean impersonateNow) {
this.IsImpersonated = false;
this.Username = username;
this.Password = password;
this.Domain = domain;
if (impersonateNow)
this.IsImpersonated = this.RunImpersonation();
}
/// <summary>
/// When called it means the code is run as the user stated in the constructor
/// </summary>
/// <param name="Username"></param>
/// <param name="Domain"></param>
/// <param name="Password"></param>
/// <returns></returns>
public bool RunImpersonation() {
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;
}
// Calls UndoImpersonation to end the impersonation
public void Dispose() {
UndoImpersonation();
}
/// <summary>
/// Undo the added impersonation, created when the object was created
/// </summary>
public void UndoImpersonation() {
this.IsImpersonated = false;
if (impersonationContext != null)
impersonationContext.Undo();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment