Skip to content

Instantly share code, notes, and snippets.

@iamandycohen
Last active July 12, 2021 02:29
Show Gist options
  • Save iamandycohen/5020348 to your computer and use it in GitHub Desktop.
Save iamandycohen/5020348 to your computer and use it in GitHub Desktop.
Impersonation
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Security.Principal;
public class UserImpersonator : IDisposable
{
[DllImport("advapi32.dll", SetLastError = true)]
private static extern int LogonUser(
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 const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
enum LogonType
{
Interactive = 2,
Network = 3,
Batch = 4,
Service = 5,
Unlock = 7,
NetworkClearText = 8,
NewCredentials = 9
}
enum LogonProvider
{
Default = 0,
WinNT35 = 1,
WinNT40 = 2,
WinNT50 = 3
}
// If you incorporate this code into a DLL, be sure to demand that it
// runs with FullTrust.
public UserImpersonator(string userPrincipalName, string password)
{
var spn = userPrincipalName.Split('@');
string userName = spn[0];
string domainName = spn[1];
Impersonate(domainName, userName, password);
}
public UserImpersonator(string domainName, string userName, string password)
{
Impersonate(domainName, userName, password);
}
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public void Impersonate(string domainName, string userName, string password)
{
WindowsIdentity tempWindowsIdentity = null;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
try
{
if (RevertToSelf())
{
if (LogonUser(
userName,
domainName,
password,
//(int)LogonType.NewCredentials,
//(int)LogonProvider.WinNT50,
(int)LogonType.Interactive,
(int)LogonProvider.Default,
//LOGON32_LOGON_INTERACTIVE,
//LOGON32_PROVIDER_DEFAULT,
ref token) != 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
impersonationContext = tempWindowsIdentity.Impersonate();
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
if (token != IntPtr.Zero)
{
CloseHandle(token);
}
if (tokenDuplicate != IntPtr.Zero)
{
CloseHandle(tokenDuplicate);
}
}
}
///
/// Reverts the impersonation.
///
private void UndoImpersonation()
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
private WindowsImpersonationContext impersonationContext = null;
// Stops impersonation
public void Dispose()
{
UndoImpersonation();
}
}
public interface IElevatedUser : IDisposable
{
IElevatedUser Impersonate();
IElevatedUser Impersonate(string account, string password);
string Account
{
get;
set;
}
string Password
{
get;
set;
}
}
public class ElevatedUser : IElevatedUser
{
private UserImpersonator impersonator;
public ElevatedUser()
{
}
public IElevatedUser Impersonate()
{
return Impersonate(Account, Password);
}
public IElevatedUser Impersonate(string account, string password)
{
if (account == null)
{
throw new ArgumentNullException("account", "Account not set.");
}
if (password == null)
{
throw new ArgumentNullException("password", "Password not set.");
}
this.impersonator = new UserImpersonator(account, password);
return this;
}
public void Dispose()
{
impersonator.Dispose();
}
public string Account
{
get;
set;
}
public string Password
{
get;
set;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment