Recently, I had need to programmatically impersonate a Windows account which has elevated permissions. In my case, only one step in a multi-step process required the extended permissions so the impersonation was temporary.
To do so in .NET a P/Invoke call into unmanaged code is required. The detail of which can be found here: WindowsIdentity.Impersonate
A call into unmanaged code is made in order to retrieve a user token. The token is then passed to a framework class which facilitates the impersonation.
I've written a small class which wraps this functionality and thought it may be of use to other people:
To do so in .NET a P/Invoke call into unmanaged code is required. The detail of which can be found here: WindowsIdentity.Impersonate
A call into unmanaged code is made in order to retrieve a user token. The token is then passed to a framework class which facilitates the impersonation.
I've written a small class which wraps this functionality and thought it may be of use to other people:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.ComponentModel; | |
using System.Runtime.InteropServices; | |
using System.Security; | |
using System.Security.Permissions; | |
using System.Security.Principal; | |
namespace ImpersonationTesting | |
{ | |
public class Impersonate : IDisposable | |
{ | |
private const int LOGON32_PROVIDER_DEFAULT = 0; | |
private const int LOGON32_LOGON_INTERACTIVE = 2; | |
private readonly string _domain; | |
private readonly string _username; | |
private readonly SecureString _password; | |
private IntPtr _userToken; | |
private bool _isDisposed; | |
public Impersonate(string domain, string username, SecureString password) | |
{ | |
_domain = domain; | |
_username = username; | |
_password = password; | |
} | |
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")] | |
public void RunAsImpersonatedUser(Action action) | |
{ | |
_userToken = IntPtr.Zero; | |
bool logonSuccessfull = LogonUser(_username, _domain, _password.ToPlainString(), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref _userToken); | |
if (logonSuccessfull == false) | |
{ | |
int error = Marshal.GetLastWin32Error(); | |
throw new Win32Exception(error); | |
} | |
using (var impersonationIdentity = new WindowsIdentity(_userToken)) | |
using (WindowsImpersonationContext context = impersonationIdentity.Impersonate()) | |
{ | |
action(); | |
} | |
} | |
public void Dispose() | |
{ | |
DisposeOfUserToken(); | |
} | |
private void DisposeOfUserToken() | |
{ | |
if (_isDisposed) | |
{ | |
return; | |
} | |
_isDisposed = true; | |
CloseHandle(_userToken); | |
} | |
~Impersonate() | |
{ | |
DisposeOfUserToken(); | |
} | |
#region P/Invoke Methods | |
[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); | |
#endregion | |
} | |
} |
No comments:
Post a Comment