Search code examples
asp.net.netvb.netdllimpersonation

AppPool identity instead of Current User only when Impersonating from Class Library (dll)


We have a class library of some common methods we use throughout multiple web apps and we are having an issue with our Impersonation class. When using impersonation with LogonUser in each individual application, Environment.UserName returns the user who is using the application. But when we call it within our class library's impersonation using block, it returns as the AppPool identity.

Returns username of client:

Declare 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 Integer

If (LogonUser(Config.AdminUser, Config.AdminDomain, Config.AdminPassword, 9, 0, token) <> 0) Then
    Dim newIdentity As WindowsIdentity = New WindowsIdentity(token)
    Using impersonatedUser As WindowsImpersonationContext = newIdentity.Impersonate()
        name = Environment.UserName
    End Using
End If

Returns app pool username:

Imports Class.Library    

Using admin As New Impersonation
    name = Environment.UserName
End Using

HttpContext.Current.User.Identity.Name seems to return the username we are looking for but we cannot see why Environment.UserName works effectively when on the server, but only when it doesn't use our custom class library's dll reference. Here is a look at our impersonation class:

Public Class Impersonation : Implements IDisposable
    Private impersonationContext As WindowsImpersonationContext = Nothing

    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 Integer
    Declare Auto Function RevertToSelf Lib "advapi32.dll" () As Boolean
    Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Boolean
    Declare Auto Function DuplicateToken Lib "advapi32.dll" (ByVal hToken As IntPtr, ByVal impersonationLevel As Integer, ByRef hNewToken As IntPtr) As Integer

    Private Shared newIdentity As WindowsIdentity
    Private Shared token As New IntPtr(0)

    Public Sub New(Optional ByVal userName As String = "", Optional ByVal password As String = "", Optional ByVal domainName As String = Config.AdminDomain)
        If userName = "" Then
            userName = Config.AdminUser
        End If

        If password = "" Then
            password = Config.AdminPassword
        End If

        Dim logonType As Integer = 9 
        impersonationContext = ImpersonateUser(userName, domainName, password, logonType)
    End Sub

    Private Sub Undo()
        If impersonationContext IsNot Nothing Then
            impersonationContext.Undo()
        End If
    End Sub

    Private Shared Function ImpersonateUser(ByVal userName As String, ByVal domain As String, ByVal password As String, ByVal logonType As Integer) As WindowsImpersonationContext
        Dim res As WindowsImpersonationContext = Nothing
        Dim tempWindowsIdentity As WindowsIdentity = Nothing
        Dim token As IntPtr = IntPtr.Zero
        Dim tokenDuplicate As IntPtr = IntPtr.Zero
        Try
            If (RevertToSelf()) Then
                If LogonUser(userName, domain, password, logonType, 0, token) Then
                    If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
                        tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
                        Return tempWindowsIdentity.Impersonate()
                    Else
                        Throw New Win32Exception(Marshal.GetLastWin32Error())
                    End If
                Else
                    Throw New Win32Exception(Marshal.GetLastWin32Error())
                End If
            Else
                Throw New Win32Exception(Marshal.GetLastWin32Error())
            End If
        Finally
            If token <> IntPtr.Zero Then
                CloseHandle(token)
            End If
            If tokenDuplicate <> IntPtr.Zero Then
                CloseHandle(tokenDuplicate)
            End If
        End Try
        Return res
    End Function

    Private disposedValue As Boolean = False        

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            Undo()
        End If
        Me.disposedValue = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

End Class

I have a feeling that it has something to do with the dll file being on the server and when we use the using block, Environment.UserName gets the username from where the process is running on the server. But I can't see why it would work initially when creating a New WindowsIdentity() within the method that uses the impersonation not when we reference it from our dll since they are both running on the server.

Essentially, HttpContext.Current.User.Identity.Name has become an issue for us when we are running things locally and trying to debug issues that arise. We would like, 1. an answer to why this is happening for knowledge purposes and 2. a possible resolution if their even is any beyond HttpContext.Current.User.Identity.Name. (answers in VB or C# are welcomed.)


Solution

  • I resolved my issue by creating a new method in my class library:

    Public Shared Function Current() As String
        If Not HttpContext.Current.Request.IsLocal Then
            Dim id As String = HttpContext.Current.User.Identity.Name
            Return id.Substring(4)
        Else
            Return Environment.UserName
        End If
    End Function
    

    If the code is run on the server, it uses HttpContext to pull the domain\username. Then I substringed out the domain (our domain is only three chars).

    If it is run locally, I return Environment.UserName I call this string within my web app by simply referencing the class and method (Employees.Current)