How to impersonate a user in managed code?

Given the username and password, how do I impersonate this user and run some kind of code as this user.

And by running I mean without pinvokes or dllimports

+6
impersonation
source share
5 answers

This is the shell class we created that worked on several different Windows platforms:

public class Impersonator { // constants from winbase.h public const int LOGON32_LOGON_INTERACTIVE = 2; public const int LOGON32_LOGON_NETWORK = 3; public const int LOGON32_LOGON_BATCH = 4; public const int LOGON32_LOGON_SERVICE = 5; public const int LOGON32_LOGON_UNLOCK = 7; public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8; public const int LOGON32_LOGON_NEW_CREDENTIALS = 9; public const int LOGON32_PROVIDER_DEFAULT = 0; public const int LOGON32_PROVIDER_WINNT35 = 1; public const int LOGON32_PROVIDER_WINNT40 = 2; public const int LOGON32_PROVIDER_WINNT50 = 3; [DllImport("advapi32.dll", SetLastError=true)] 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); public static WindowsImpersonationContext LogOn(string userName, string password) { return LogOn(userName, password, ""); } public static WindowsImpersonationContext LogOn(string userName, string password, string domain) { WindowsIdentity tempWindowsIdentity; WindowsImpersonationContext impersonationContext; IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; if(RevertToSelf()) { if (LogonUserA(userName, domain, password, LOGON32_LOGON_NEW_CREDENTIALS, 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 impersonationContext; } } } else { var win32 = new Win32Exception(Marshal.GetLastWin32Error()); //throw new Exception(string.Format("{0}, Domain:{1}, User:{2}, Password:{3}", // win32.Message, domain, userName, password)); throw new Exception(win32.Message); } } if(token!= IntPtr.Zero) CloseHandle(token); if(tokenDuplicate!=IntPtr.Zero) CloseHandle(tokenDuplicate); return null; // Failed to impersonate } public static bool LogOff(WindowsImpersonationContext context) { bool result = false; try { if (context != null) { context.Undo(); result = true; } } catch { result = false; } return result; } } 
+13
source share

I have welded this into two simple methods:

 public bool ImpersonateValidUser(String userName, String domain, String password) public void UndoImpersonation() 

You can directly copy / paste the class below and use it in your project:

  class ImpersonationContext { [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); public const int LOGON32_LOGON_NEW_CREDENTIALS = 9; public const int LOGON32_LOGON_INTERACTIVE = 2; public const int LOGON32_PROVIDER_DEFAULT = 0; public const int LOGON32_PROVIDER_WINNT50 = 3; WindowsImpersonationContext impersonationContext; public bool ImpersonateValidUser(String userName, String domain, String password) { WindowsIdentity tempWindowsIdentity; IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; if (RevertToSelf()) { if (LogonUserA(userName, domain, password, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50, 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; } public void UndoImpersonation() { impersonationContext.Undo(); } } 
+2
source share

All the examples I saw do not take into account the fact that the input type is not the only size suitable for the whole solution.

For example, this will work only if the user to whom you impersonate rights has permission to enter the target system. Not always when accessing a remote SQL Server mailbox. LOGON32_LOGON_INTERACTIVE

NetworkClearText is the only one that runs sequentially for use with SQL Server connections. - The lack of clear text does not mean that the transfer of credentials is unsafe.

When in a workgroup and you must impersonate a domain user, NewCredentials is the one that works. (not tested with SQL Server connection)

+2
source share

There is a similar question here with a great answer here .

Take a look at WindowsImpersonationContext for more information (there is also another great example code there)

+1
source share

See ImpersonationHelper Is it safe to get the SecureString value from VB.NET? . The code is production-ready and reliable.

It supports IDisposable , contains the RunAs method (which is invaluable), passwords are processed as SecureString and other useful useful properties. I also provided testing code for the ImpersonationHelper class with very useful troubleshooting tools, and their SecureString extenstion methods, which come in handy.

0
source share

All Articles