How to get a token as a step of Programmatic Impersonation in VB.NET

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:

 

If TypeOf (User) Is WindowsPrincipal Then

Dim Principal As WindowsPrincipal = DirectCast(User, WindowsPrincipal)

Dim Identity As WindowsIdentity = DirectCast(Principal.Identity, WindowsIdentity)

Dim Token As IntPtr = Identity.Token

End If

 

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 Shared Function LogonUser(lpszUserName As String, lpszDomain As String, lpszPassword As String, dwLogonType As Integer, dwLogonProvider As Integer, ByRef phToken As Integer) As Boolean

End Function

 

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:

 

Imports System

Imports System.Runtime.InteropServices

Imports System.Collections.Generic

Imports System.Linq

Imports System.Web

Imports System.Web.UI

Imports System.Web.UI.WebControls

 

Partial Class ImpersonationVB

Inherits System.Web.UI.Page

‘ You should include System.Runtime.InteropServices

<DllImport(“c:\Windows\System32\advapi32.dll”)> _

Public Shared Function LogonUser(lpszUserName As String, lpszDomain As String, lpszPassword As String, dwLogonType As Integer, dwLogonProvider As Integer, ByRef phToken As Integer) As Boolean

End Function

 

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles LblLegend.Load

Test1()

End Sub

Protected Sub Test1()

Dim User As String = “user”

Dim Password As String = “password”

Dim Machine As String = “thepc”

Dim ReturnedToken As Integer

If LogonUser(User, Machine, Password, 3, 0, ReturnedToken) Then

Dim Token As IntPtr = New IntPtr(ReturnedToken)

LblLegend.Text = “Token = ” + Token.ToString()

End If

End Sub

End Class

 

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