I have always had problems with my current app as it has to impersonate a user to consume various different components and databases. Testing components in isolation is tricky with this setup. I did find a handy way to have a test impersonate a user for a test run:
Imports System.Runtime.InteropServices
Imports System.Security.Principal
Public Class
Impersonation
Implements
IDisposable
Dim
impersonationContext As
WindowsImpersonationContext
<DllImport("advapi32.dll",
SetLastError:=True)> _
Shared Function LogonUser(ByVal
principal As String,
ByVal authority As
String, ByVal
password As String,
ByVal logonType As
LogonTypes, ByVal logonProvider As LogonProviders, ByRef
token As IntPtr) As
Boolean
End Function
<DllImport("kernel32.dll",
SetLastError:=True)> _
Shared Function CloseHandle(ByVal
handle As IntPtr) As
Boolean
End Function
Public Enum LogonTypes
Interactive = 2
Network
Batch
Service
NetworkCleartext = 8
NewCredentials
End Enum
Public Enum LogonProviders
[Default] = 0
WinNT35
WinNT40
WinNT50
End Enum
Private
user As String
Private
domain As String
Private
password As String
Public Sub New(ByVal user As String, ByVal domain As String, ByVal password As String)
Me.user
= user
Me.domain
= domain
Me.password
= password
impersonationContext = Impersonate()
End Sub
Private Function GetUserToken() As
IntPtr
Dim
token As IntPtr
Dim result
As Boolean =
LogonUser(user, domain, password, LogonTypes.Interactive,
LogonProviders.Default, token)
If (Not result) Then Throw New Exception(String.Format("LogonUser failed: {0}. User:
{1}", Marshal.GetLastWin32Error(), user))
Return
token
End Function
Private Function Impersonate() As
WindowsImpersonationContext
Dim
token As IntPtr = GetUserToken()
Dim
identity As WindowsIdentity = New WindowsIdentity(token)
CloseHandle(token)
System.Threading.Thread.CurrentPrincipal
= New WindowsPrincipal(identity)
Return
identity.Impersonate()
End Function
Private Sub UndoImpersonation()
If (Not impersonationContext Is
Nothing) Then
impersonationContext.Undo()
System.Threading.Thread.CurrentPrincipal = New
WindowsPrincipal(WindowsIdentity.GetCurrent())
End Sub
Public Sub Dispose() Implements
IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(True)
End Sub
Protected Sub Dispose(ByVal
disposing As Boolean)
If (Not disposing) Then
Exit
Sub
Else
UndoImpersonation()
End If
End Sub
End
Class
From there its easy for a test to use it:
Private
identity As impersonation
<SetUp()> _
Public Sub Setup()
identity = New
Impersonation("User", "Domain", "Password")
End Sub
<TearDown()> _
Public Sub Teardown()
identity.Dispose()
End Sub
The dispose call will undo the impersonation and return it to be the current user.