简体   繁体   中英

IIS7 - Access Denied using System.IO.StreamWriter() ASP.net page to write to share

I am working on a few asp.net pages that reside is a huge intranet application, the intranet application pool runs as the Identity NetworkService (dont ask) & uses anonymous authentication as IUSR – IIS7.

Let's say the Intranet Home Dir is D:\\Intranet\\ - the asp.net pages in question reside in D:\\Intranet\\TimeSheets\\V2\\

My test script in question is D:\\Intranet\\TimeSheets\\V2\\Post.aspx and does something on these lines (Takes posted HTML [as a base 64 string]) - converts to HTML then attempts to write to a network share:

Dim TimeSheetInBase64 As String = Request.Form("HtmlToSave")
Dim HtmlToSave As String = ""
Dim SavePath As String = "\\DifferentFileServer\Public\Random Department\Posted Invoices\"

'#### Convert the HTML from base64 back into HTML
Try
    Dim decodedBytes As Byte()
    decodedBytes = Convert.FromBase64String(TimeSheetInBase64)
    HtmlToSave = Encoding.Default.GetString(decodedBytes)

Catch e As Exception
    echo("Error decoding HTML: " & e.Message)
    Exit Select
End Try

Try
    Dim objWriter As New System.IO.StreamWriter(SavePath & "text.htm", False)
    objWriter.WriteLine(HtmlToSave)
    objWriter.Close()
    echo("OK")

Catch ex As Exception
    Dim wi As WindowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent()
    Dim user As String = wi.Name
    echo("Error Saving Invoice To Disk (" & wi.Name & "): " & ex.Message)
End Try

The objWriter throws an error when attempting to write the file to a remote share:

Error Saving Invoice To Disk (NT AUTHORITY\NETWORK SERVICE): Access to the path '\\DifferentFileServer\Public\Random Department\Posted Invoices\text.htm' is denied.

Obviously this is because the pages in question are running under the scope of the application pool.

So, i tried changing the anonymous specific user on the V2 folder to use an AD account that has write access to the share in question - however, even after saving the config change, restarting IIS the page still gets an access denied error when trying to write the file (and WindowsIdentity.GetCurrent() still returns NT AUTHORITY\\NETWORK SERVICE (wich is the identiy of the application pool and NOT the account i set for anonymous access).

Just to confirm this is a problem with overriding the anonymous account i set the application pool to run with as the AD account i was trying to use on the anonymous specific user - this works fine and the file is written successfully to the remote share - so the credentials are good, it's just IIS not using them properly.

My question is this, is it possible to have some sub folders running with different windows credentials for anonymous users? If so, what else do i need to do apart from changing the anonymous account as that seems to have no effect?

My Second question is this: instead of relying on IIS to elevate the permissions, is there any way to do this from within the asp.net page, ie write the file with different credentials from what the page is running as? I've thought about moving this sub folder into it's own application pool – but that seems a little messy and I would like to avoid doing that if at all possible.

(Sorry for the wall of text)

Well, after banging my head against the wall with IIS, i gave up and went the code route, specifically, advapi32.dll and it's LogonUserA() , DuplicateToken() & RevertToSelf() and more importantly the WindowsImpersonationContext object:

http://msdn.microsoft.com/en-us/library/system.security.principal.windowsimpersonationcontext.aspx

First, declare functions to toggle impersonation on & off:

Private Function impersonateValidUser(ByVal userName As String, _
ByVal domain As String, ByVal password As String) As Boolean

    Dim tempWindowsIdentity As WindowsIdentity
    Dim token As IntPtr = IntPtr.Zero
    Dim tokenDuplicate As IntPtr = IntPtr.Zero
    impersonateValidUser = False

    If RevertToSelf() Then
        If LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, 
                     LOGON32_PROVIDER_DEFAULT, token) <> 0 Then
            If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
                tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
                impersonationContext = tempWindowsIdentity.Impersonate()
                If Not impersonationContext Is Nothing Then
                    impersonateValidUser = True
                End If
            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
End Function

Private Sub undoImpersonation()
    impersonationContext.Undo()
End Sub

The usage was then super easy:

If impersonateValidUser("username", "domain", "password") Then
    '#### Write the file then 'close' the Impersonation
    undoImpersonation()
End If

The following namespaces where required:

System.Web
System.Web.Security
System.Security.Principal
System.Runtime.InteropServices

Inspiration (Shame it took me so long to find this):

http://support.microsoft.com/kb/306158

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM