How to get a token as a step of Programmatic Impersonation in C#

Configured impersonation, described in the article How to use Configured Impersonation in ASP.NET, allows you to impersonate a user for the entire duration of a request. By using programmatic impersonation (based on the WindowsIdentity.Impersonate() method) , you have more control, such  as the ability to impersonate a user for only part of the page request. This method sets up impersonation for a specific account. You identify the account you want to impersonate by using its account token. Account tokens are what Windows uses to track users once their credentials are approved. If you have the token for a user, you can impersonate that user.

 

The general process is as follows:

1. Obtain an account token for the account you want to impersonate.

2. Use WindowsIdentity.Impersonate() to start impersonation. This method returns a WindowsImpersonationContext object.

3. Call the Undo() method of the WindowsImpersonationContext object to revert to the original identity.

You can get an account token in two main ways:

1. The most common approach is to retrieve the token for the currently authenticated user, by using the WindowsIdentity.Token property.  Tokens are represented in .NET as IntPtr objects, which are representations of pointers to unmanaged memory locations, but you never need to interact with this directly. You need to pass the token to the WindowsIdentity.Impersonate() method:

IntPtr token = ((WindowsIdentity)User.Identity).Token;

2. You can get a user token by logging in with a specific user name and password. Unfortunately, .NET does not provide managed classes for logging a user in and you  must use the LogonUser() function from the unmanaged Win32 security API.

2.1. You must first declare it as shown:

 

[DllImport(@”c:\Windows\System32\advapi32.dll”)]

public static extern bool LogonUser(string lpszUserName,

string lpszDomain, string lpszPassword, int dwLogonType,

int dwLogonProvider, out int phToken);

 

This code uses the DllImport attribute, which tells the runtime that you are going to access a native Windows API located in the native DLL advapi32.dll in the Windows system directory. The types of the parameters in the function prototype where this attribute is applied to need to map to the types of the functions encapsulated into the native DLL. Although every call to this method in your code looks like a call to any other static method of a .NET class, in reality the call gets routed to the native method encapsulated in the DLL specified in the DllImport attribute, and the information transmitted gets marshaled accordingly.

2.2. You can use the LoginUser() function it in your code to log the user in, as shown:

 

using System.Runtime.InteropServices;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

 

 

public partial class ImpersonationVC : System.Web.UI.Page

{

// You should include System.Runtime.InteropServices

[DllImport(@”c:\Windows\System32\advapi32.dll”)]

public static extern bool LogonUser(string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType,int dwLogonProvider, out int phToken);

 

protected void Page_Load(object sender, EventArgs e)

{

Test1();

}

protected void Test1()

{

// Define required variables.

string user = “test”;

string password = “password”;

string machine = “thepc”;

int returnedToken;

// Try to log on.

if (LogonUser(user,machine,password,3,0,out returnedToken))

{

IntPtr token = new IntPtr(returnedToken);

lblLegend.Text = “Token = ” + token.ToString();

}

}

}

 

2.3. You must convert the integer value returned by LogonUser() into an IntPtr in order to use it with the WindowsIdentity.Impersonate() method.