I'm getting a very strange InvalidOperationException whenever I try to refer to Environment.MachineName after I do an impersonation. Environment.UserName correctly reports the new user name and everything else seems to be functioning correctly. Does anyone have any ideas?
Here's my stripped down impersonation class (VB.NET 2.0
)
Here's a sample tester:
Dave
Here's my stripped down impersonation class (VB.NET 2.0
Code:
Option Explicit On
Option Strict On
Imports System.Security.Principal
Imports System.Runtime.InteropServices
Public Class Impersonation
'These constants are based on values in the Win32 API file WINBASE.H
'Refer to http://msdn.microsoft.com/en-us/library/aa378184(VS.85).aspx for their meanings
Const LOGON32_LOGON_INTERACTIVE As Integer = 2
Const LOGON32_PROVIDER_DEFAULT As Integer = 0
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 SECURITY_IMPERSONATION_LEVEL, _
ByRef DuplicateTokenHandle As IntPtr) As Integer
Private Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Long
Private Enum SECURITY_IMPERSONATION_LEVEL As Integer
SecurityAnonymous = 0
SecurityIdentification = 1
SecurityImpersonation = 2
SecurityDelegation = 3
End Enum
Private m_oImpersonationContext As WindowsImpersonationContext
Private m_bImpersonationActive As Boolean
Public Sub New()
End Sub
Public ReadOnly Property ImpersonationActive() As Boolean
Get
Return m_bImpersonationActive
End Get
End Property
Public Function StartImpersonation(ByVal sUserName As String, ByVal sDomain As String, ByVal sPassword As String) As Boolean
Dim bResults As Boolean = False
Dim sErrorMessage As String
Dim oWindowsIdentity As WindowsIdentity
Dim hPrimaryToken As IntPtr = IntPtr.Zero 'a Win32 handle to our authentication token
Dim hImpersonationToken As IntPtr = IntPtr.Zero 'a Win32 handle to our impersonation token
If String.IsNullOrEmpty(sUserName) Then
Throw New ArgumentException("UserName may not be MULL or String.Empty")
End If
'If no domain is given, assume the account is a local one
If sDomain = String.Empty Then
sDomain = Environment.MachineName
End If
Try
'Validate the provided userid, password and domain.
If LogonUserA(sUserName, sDomain, sPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, hPrimaryToken) <> 0 Then
'Convert our token to one whos handle has TOKEN_IMPERSONATE set
If DuplicateToken(hPrimaryToken, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, hImpersonationToken) <> 0 Then
'Create a new identity object based on our impersonation token
oWindowsIdentity = New WindowsIdentity(hImpersonationToken)
'Switch to our new identity
m_oImpersonationContext = oWindowsIdentity.Impersonate()
If m_oImpersonationContext IsNot Nothing Then
m_bImpersonationActive = True
bResults = True
End If
Else
sErrorMessage = String.Format("DuplicateToken failed (rc={0})", Runtime.InteropServices.Marshal.GetLastWin32Error)
Throw New Security.Authentication.AuthenticationException(sErrorMessage)
End If
Else
sErrorMessage = String.Format("LogonUser failed (rc={0})", Runtime.InteropServices.Marshal.GetLastWin32Error)
Throw New Security.Authentication.AuthenticationException(sErrorMessage)
End If
Finally
If Not hImpersonationToken.Equals(IntPtr.Zero) Then
CloseHandle(hImpersonationToken)
hImpersonationToken = IntPtr.Zero
End If
If Not hPrimaryToken.Equals(IntPtr.Zero) Then
CloseHandle(hPrimaryToken)
hPrimaryToken = IntPtr.Zero
End If
End Try
Return bResults
End Function
Public Sub EndImpersonation()
If m_oImpersonationContext IsNot Nothing AndAlso m_bImpersonationActive Then
m_oImpersonationContext.Undo()
m_oImpersonationContext.Dispose()
m_oImpersonationContext = Nothing
m_bImpersonationActive = False
End If
End Sub
End Class
Here's a sample tester:
Code:
Dim oImp1 As Impersonation
Dim oImp2 As Impersonation
MessageBox.Show("User " & Environment.UserName, "", MessageBoxButtons.OK)
oImp1 = New Impersonation("some_domain_user", "some_domain", "some_pw")
oImp2 = New Impersonation("some_local_user", "", "some_pw")
oImp1.StartImpersonation()
MessageBox.Show("User = " & Environment.UserName, "", MessageBoxButtons.OK)
oImp2.StartImpersonation()
MessageBox.Show("User = " & Environment.UserName, "", MessageBoxButtons.OK)
oImp2.EndImpersonation()
MessageBox.Show("User = " & Environment.UserName, "", MessageBoxButtons.OK)
oImp1.EndImpersonation()
MessageBox.Show("User = " & Environment.UserName, "", MessageBoxButtons.OK)
Dave
Last edited: