| Home | | | Article List | | | Downloads | | | VB Notebook Archive Site (VB6) |
In today's business environment more and more companies are securing the PC's of many employees to prevent damage to their systems via malware downloaded over the Internet or user mistakes. On web servers running publicly available web services, administrators wisely don't want to expose resources to just anyone. However, as we develop software we may find it necessary to access forbidden resources like certain areas of the registry or a file store on a network server. How can we do this and still keep the application and the system secure? Fortunately, we can use impersonation to solve this problem.
The code below is a simple class I wrote for this purpose. The class is declared as a Friend class rather than Public to avoid any accidential exposure to outside processes. The New method is overloaded so that an unintialized instance can be created as well as one that has credentials passed into it. The empty new method also allows easy subclassing so that other methods for initialization could be added as desired. Impersonation is started in the StartImpersonation method. EndImpersonation ends the session and the Finalize method helps insure that impersonation is ended when the instance is destroyed. The current state of impersonation can be checked in the ImpersonationActive read-only property.
This method is not without risks. First of all, the complete user login credentials have to be passed in as clear text. This means that you will need to use some type of encryption to protect this information at the very least. To protect these credentials further you may want to look into using secure strings.
Imports Microsoft.VisualBasic
Imports System.Web
Imports System.Web.Security
Imports System.Security.Principal
Imports System.Runtime.InteropServices
''' <summary>
''' Provides impersonation to allow access to resources
''' </summary>
''' <remarks></remarks>
Friend Class Impersonate
Private LOGON32_LOGON_INTERACTIVE As Integer = 2
Private LOGON32_PROVIDER_DEFAULT As Integer = 0
Private impersonationContext As WindowsImpersonationContext
Private Declare Function LogonUserA Lib "advapi32.dll" (ByVal lpszUsername As String, _
ByVal lpszDomain As String, _
ByVal lpszPassword As String, _
ByVal dwLogonType As Integer, _
ByVal dwLogonProvider As Integer, _
ByRef phToken As IntPtr) As Integer
Private Declare Auto Function DuplicateToken Lib "advapi32.dll" ( _
ByVal ExistingTokenHandle As IntPtr, _
ByVal ImpersonationLevel As Integer, _
ByRef DuplicateTokenHandle As IntPtr) As Integer
Private Declare Auto Function RevertToSelf Lib "advapi32.dll" () As Long
Private Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Long
Private _impersonationActive As Boolean
''' <summary>
''' Allows creation of a new instance without starting impersonation
''' </summary>
''' <remarks></remarks>
Public Sub New()
End Sub
''' <summary>
''' starts impersonation with specified parameters
''' </summary>
''' <param name="userName">username to impersonate</param>
''' <param name="domain">domain for user</param>
''' <param name="password">password for user</param>
''' <remarks></remarks>
Public Sub New(ByVal userName As String, ByVal domain As String, ByVal password As String)
StartImpersonation(userName, domain, password)
End Sub
''' <summary>
''' starts impersonation with specified parameters
''' </summary>
''' <param name="userName">username to impersonate</param>
''' <param name="domain">domain for user</param>
''' <param name="password">password for user</param>
''' <remarks></remarks>
Public Function StartImpersonation(ByVal userName As String, ByVal domain As String, ByVal password As String) As Boolean
Dim ReturnValue As Boolean = False
Dim tempWindowsIdentity As WindowsIdentity
Dim token As IntPtr = IntPtr.Zero
Dim tokenDuplicate As IntPtr = IntPtr.Zero
StartImpersonation = False
If CBool(RevertToSelf()) Then
If LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, token) <> 0 Then
If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
impersonationContext = tempWindowsIdentity.Impersonate()
If Not impersonationContext Is Nothing Then
ReturnValue = True
_impersonationActive = True
End If
End If
End If
End If
If Not tokenDuplicate.Equals(IntPtr.Zero) Then
CloseHandle(tokenDuplicate)
End If
If Not token.Equals(IntPtr.Zero) Then
CloseHandle(token)
End If
Return ReturnValue
End Function
''' <summary>
''' Ends impersonation session and returns thread back to original user
''' </summary>
''' <remarks></remarks>
Public Sub EndImpersonation()
impersonationContext.Undo()
_impersonationActive = False
End Sub
Protected Overrides Sub Finalize()
If _impersonationActive Then
impersonationContext.Undo()
_impersonationActive = False
End If
MyBase.Finalize()
End Sub
Public ReadOnly Property ImpersonationActive() As Boolean
Get
Return _impersonationActive
End Get
End Property
End Class