Accessing network shares with ASP.NET

by Marcel Wijnands 5. August 2008 23:51

Recently, I had to develop a web application that had to grab pictures off a network share, manipulate them, and show them on a page. The users of this application would log in automatically with their Windows user credentials and based on the groups they were a member of, they would or would not see certain content.

To do this, I had to use the 'Integrated Windows Authentication' option in IIS and add <identity impersonate="true"/> to the Web.config.

The thing I noticed is that even though the logged on user had the required rights to access the network share, I would be getting 'Access denied' or  'Path not found' error messages.

After some research I found out that, using impersonation like this, the IIS worker process would get a so called 'impersonation token' of the logged on user, while the token needed to access network resources has to be a 'primary token'. One workaround is to add credentials to the impersonation tag, like <identity impersonation="true" userName="DOMAIN\User" password="Pass"/>. This would cause the IIS worker process to run all code in the security context of 'User' using a primary token.

This workaround was useless for my application because I needed to run most code in the context of the logged on user. What I needed was to get a primary token of a user that has access to the network share, and run pieces of code under the security context of this user.

To do this I wrote a little function to get a WindowsIndentity containing a primary token;

Dim LOGON32_LOGON_INTERACTIVE As Integer = 2
Dim LOGON32_PROVIDER_DEFAULT As Integer = 0

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

Declare Auto Function DuplicateToken Lib "advapi32.dll" ( _
                        ByVal ExistingTokenHandle As IntPtr, _
                        ByVal ImpersonationLevel As Integer, _
                        ByRef DuplicateTokenHandle As IntPtr) As Integer

Declare Auto Function RevertToSelf Lib "advapi32.dll" () As Long
Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Long

Public Function GetFixedIdentity(ByVal Domain As String, _
                                 ByVal UserName As String, _
                                 ByVal Password As String) As WindowsIdentity

    Dim tempIdentity As WindowsIdentity = Nothing
    Dim token As IntPtr = IntPtr.Zero
    Dim tokenDuplicate As IntPtr = IntPtr.Zero

    If RevertToSelf() Then
        If LogonUserA(UserName, Domain, Password, LOGON32_LOGON_INTERACTIVE, _
                      LOGON32_PROVIDER_DEFAULT, token) <> 0 Then

            If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
                tempIdentity = New WindowsIdentity(tokenDuplicate)
            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 tempIdentity

End Function

Now, this piece of unmanaged code could be a performance hit if it is used often, because it will validate the user credentials against the domain controller every single time. I figured I only get this WindowsIdentity on application startup and keep it in the Application Class, so I added this in Global.asax.vb;

Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)

    Application("FixedIdentity") = GetFixedIdentity("DOMAIN", "user", "pass")

End Sub

So whenever I needed access to a network share, I would run that piece of code in the ImpersonationContext of the WindowsIdentity I kept in the Application Class, like this;

Dim ImpersonationContext As WindowsImpersonationContext = Nothing

Try

    If Not Application("FixedIdentity") Is Nothing Then _
        ImpersonationContext = CType(Application("FixedIdentity"),  _
                                        WindowsIdentity).Impersonate

    'This code is executed by the Fixed Identity
    For Each File In Directory.GetFiles("\\SERVER02\D$\Images")

        Debug.WriteLine(File)

    Next

Catch ex As Exception

    Debug.WriteLine(ex.Message)

Finally

    ' This always has to be executed, so put it in Finally. Otherwise
    ' you will keep executing code as the Fixed Identity.
    If Not ImpersonationContext Is Nothing Then ImpersonationContext.Undo()

End Try

Now you will be able to access the share, and be happy! :D

Tags:

ASP.NET | IIS 6 | VB.NET

Comments

10/3/2009 1:04:52 AM #

shyNET|Reviews

..

shyNET|Reviews United Kingdom

Comments are closed

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen | Modified by Mooglegiant