Impersonation with Network Credentials in C# .Net

(Mostly) unmodified code, courtesy of Phil Harding (see references below for original post).

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace Tools.Network
{
public enum LogonType
{
LOGON32_LOGON_INTERACTIVE = 2,
LOGON32_LOGON_NETWORK = 3,
LOGON32_LOGON_BATCH = 4,
LOGON32_LOGON_SERVICE = 5,
LOGON32_LOGON_UNLOCK = 7,
LOGON32_LOGON_NETWORK_CLEARTEXT = 8,// Win2K or higher
LOGON32_LOGON_NEW_CREDENTIALS = 9// Win2K or higher
};

public enum LogonProvider
{
LOGON32_PROVIDER_DEFAULT = 0,
LOGON32_PROVIDER_WINNT35 = 1,
LOGON32_PROVIDER_WINNT40 = 2,
LOGON32_PROVIDER_WINNT50 = 3
};

public enum ImpersonationLevel
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3
}

class Win32NativeMethods
{
[DllImport("advapi32.dll", SetLastError = true)]
public 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)]
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>
/// Allows code to be executed under the security context of a specified user account.
/// </summary>
/// <remarks>
///
/// Implements IDispose, so can be used via a using-directive or method calls;
///...
///
///var imp = new Impersonator( "myUsername", "myDomainname", "myPassword" );
///imp.UndoImpersonation();
///
///...
///
/// var imp = new Impersonator();
///imp.Impersonate("myUsername", "myDomainname", "myPassword");
///imp.UndoImpersonation();
///
///...
///
///using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
///{
///...
///
///...
///}
///
///...
/// </remarks>
public class Impersonator : IDisposable
{
private WindowsImpersonationContext _wic;

/// <summary>
/// Begins impersonation with the given credentials, Logon type and Logon provider.
/// </summary>
/// <param name="userName">Name of the user.</param>
/// <param name="domainName">Name of the domain.</param>
/// <param name="password">The password. <see cref="System.String"/></param>
/// <param name="logonType">Type of the logon.</param>
/// <param name="logonProvider">The logon provider. <see cref="Mit.Sharepoint.WebParts.EventLogQuery.Network.LogonProvider"/></param>
public Impersonator(string userName, string domainName, string password, LogonType logonType, LogonProvider logonProvider)
{
Impersonate(userName, domainName, password, logonType, logonProvider);
}

/// <summary>
/// Begins impersonation with the given credentials.
/// </summary>
/// <param name="userName">Name of the user.</param>
/// <param name="domainName">Name of the domain.</param>
/// <param name="password">The password. <see cref="System.String"/></param>
public Impersonator(string userName, string domainName, string password)
{
Impersonate(userName, domainName, password, LogonType.LOGON32_LOGON_INTERACTIVE, LogonProvider.LOGON32_PROVIDER_DEFAULT);
}

/// <summary>
/// Initializes a new instance of the <see cref="Impersonator"/> class.
/// </summary>
public Impersonator()
{}

/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
UndoImpersonation();
}

/// <summary>
/// Impersonates the specified user account.
/// </summary>
/// <param name="userName">Name of the user.</param>
/// <param name="domainName">Name of the domain.</param>
/// <param name="password">The password. <see cref="System.String"/></param>
public void Impersonate(string userName, string domainName, string password)
{
Impersonate(userName, domainName, password, LogonType.LOGON32_LOGON_INTERACTIVE, LogonProvider.LOGON32_PROVIDER_DEFAULT);
}

/// <summary>
/// Impersonates the specified user account.
/// </summary>
/// <param name="userName">Name of the user.</param>
/// <param name="domainName">Name of the domain.</param>
/// <param name="password">The password. <see cref="System.String"/></param>
/// <param name="logonType">Type of the logon.</param>
/// <param name="logonProvider">The logon provider. <see cref="Mit.Sharepoint.WebParts.EventLogQuery.Network.LogonProvider"/></param>
public void Impersonate(string userName, string domainName, string password, LogonType logonType, LogonProvider logonProvider)
{
UndoImpersonation();

IntPtr logonToken = IntPtr.Zero;
IntPtr logonTokenDuplicate = IntPtr.Zero;
try
{
// revert to the application pool identity, saving the identity of the current requestor
_wic = WindowsIdentity.Impersonate(IntPtr.Zero);

// do logon & impersonate
if (Win32NativeMethods.LogonUser(userName,
domainName,
password,
(int)logonType,
(int)logonProvider,
ref logonToken) != 0)
{
if (Win32NativeMethods.DuplicateToken(logonToken, (int)ImpersonationLevel.SecurityImpersonation, ref logonTokenDuplicate) != 0)
{
var wi = new WindowsIdentity(logonTokenDuplicate);
wi.Impersonate();// discard the returned identity context (which is the context of the application pool)
}
else
throw new Win32Exception(Marshal.GetLastWin32Error());
}
else
throw new Win32Exception(Marshal.GetLastWin32Error());
}
finally
{
if (logonToken != IntPtr.Zero)
Win32NativeMethods.CloseHandle(logonToken);

if (logonTokenDuplicate != IntPtr.Zero)
Win32NativeMethods.CloseHandle(logonTokenDuplicate);
}
}

/// <summary>
/// Stops impersonation.
/// </summary>
private void UndoImpersonation()
{
// restore saved requestor identity
if (_wic != null)
_wic.Undo();
_wic = null;
}
}
}

References
http://platinumdogs.wordpress.com/2008/10/30/net-c-impersonation-with-network-credentials/

About Ronnie Diaz

Ronnie Diaz is a software engineer and tech consultant. Ronnie started his career in front-end and back-end development for companies in ecommerce, service industries and remote education. This work transitioned from traditional desktop client-server applications through early cloud development. Software included human resource management and service technician workflows, online retail e-commerce and electronic ordering and fulfillment, IVR customer relational systems, and video streaming remote learning SCORM web applications. Hands on server experience and software performance optimization led to creation of a startup business focused on collocated data center services and continued experience with video streaming hardware and software. This led to a career in Amazon Prime Video where Ronnie is currently employed, building software and systems which stream live sports and events for millions of viewers around the world.

Posted on March 9, 2011, in Programming & Development, Security & Cryptography and tagged , , , , , , , , , , . Bookmark the permalink. Leave a comment.

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

%d bloggers like this: