views:

239

answers:

1

I need to "impersonate" a user in a VB.NET 2008 WinForms application, so that the application can accept the Active Directory login of any user on a PC regardless of who is actually logged in to Windows. I want the application's My.User to be the AD account of the person who logged in to the application. I succeeded in this with the following code:

Private Declare Auto Function LogonUser 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 Boolean

Const LOGON32_LOGON_INTERACTIVE As Long = 2
Const LOGON32_LOGON_NETWORK As Long = 3

Const LOGON32_PROVIDER_DEFAULT As Long = 0
Const LOGON32_PROVIDER_WINNT35 As Long = 1
Const LOGON32_PROVIDER_WINNT40 As Long = 2
Const LOGON32_PROVIDER_WINNT50 As Long = 3


' Influenced from the example at http://aspalliance.com/39
Public Shared Function Login(ByVal uid As String, ByVal pwd As String) As Boolean

    ' Get the user's domain name.
    Dim domainName As String = My.User.Name.Substring(0, My.User.Name.IndexOf("\"))

    ' This token is returned by the LogonUser API call (variable is passed ByRef).
    Dim token As IntPtr

    If LogonUser(uid, domainName, pwd, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, token) Then

        ' Added this line per response to this question:
        WindowsIdentity.Impersonate(token)

        ' If the login succeeds, then impersonate that user by changing CurrentPrincipal.
        Dim wi As New Principal.WindowsIdentity(token)
        Dim wp As New Principal.WindowsPrincipal(wi)

        My.User.CurrentPrincipal = wp
        Return True

    Else
        Return False
    End If

End Function

However, the application uses a .DLL with the Data Access Layer which is connecting to SQL Server 2000. It appears that SQL Server, using "Integrated Security=SSPI" in the connection string, is receiving the login of the account logged in to Windows and not the account returned My.User.CurrentPrincipal.Identity, when stepping through the code, in both the WinForms app code and the .DLL's app code.

Both the WinForms app and .DLL code properly recognize My.User.CurrentPrincipal.Identity as the account logged in to the app, not Windows. It's just not propagating to SQL Server. This is evidenced by Stored procedures writing SUSER_SNAME() to a table's column in T-SQL.

Can anyone see what I'm going wrong?

EDIT: I've added the line WindowsIdentity.Impersonate(token) as stated, but now when my .DLL tries to create an SQL Server connection it throws this error:

Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'.

+1  A: 

You need to call WindowsIdentity.Impersonate();:

If LogonUser(...) Then             
   WindowsIdentity.Impersonate(token)
Remus Rusanu
I added the line above, but I'm getting an Exception thrown, as stated in my edited question above.
HardCode
So it means now you're truly impersonating. You need to find out why is the impersonated user not authenticated by the database. Most likely you impersonate a user in a domain that is not trusted by the database (perhaps a local user?)
Remus Rusanu