Click here to Skip to main content
15,888,968 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm successfully impersonating a network account and accessing a network share in my web application. What I need to do is allow the user to select one of the available files and pop it open for them--or ideally, use the standard open dialog to allow them to open or save the file. When I use Response.Write with the filepath, it works on my machine, because I have that share path mapped. It does not work on a different client machine where the share is not mapped. I can access the files on the server and provide a list to the users, but how do I get the files to the client? Is there a simple alternative to Response.Write, or do I have to go another route (like copying to file into my application path and opening the copy)?
Posted

You confused, you are mixing thing.
Let's state, that you are building a web application, that involves at lest two parties: a client, that is a web browser and a web server - let's assume you are using IIS. As I understood, you have a third party: a file server.
Now, you can set up IIS, to impersonate the user running the client browser (using NTLM or basic authentication - the exact scenario depends on the windows network you are in). But impersonation allows the working thread to access only local resources on the web server, but does not allow it to access resources (files) on the third party server (file server). To do that you need delegation (see the differences in detail: http://msdn.microsoft.com/en-us/library/ff647248.aspx[^]). But NTLM is not supporting this, neither is Basic authentication capable of giving you this by default.
You have several to get a token (http://msdn.microsoft.com/en-us/library/ff647404.aspx#paght000023_delegation[^]):
  • Use Kerberos authentication and delegation. If you use Kerberos to authenticate your users, you can impersonate the original caller by using the techniques described in the sections "Impersonating the Original Caller" and "Impersonating the Original Caller Temporarily" and use Kerberos delegation to gain access to network resources. To do so:
    If your application runs under the Network Service account, you need to configure your computer account in Active Directory to be trusted for delegation.
    If your application runs under a custom domain account, you need to configure your domain account in Active Directory to be trusted for delegation. You must also register a service principal name in Active Directory to associate the domain account with the HTTP service on your Web server.
    If you use domain accounts to run your Web application or the downstream service that you are accessing, you must also ensure that appropriate service principal names (SPNs) are created in Active Directory for those accounts.
  • Call LogonUser and request an Interactive logon session. An interactive logon session has network credentials that allow you to authenticate against network servers. Use this approach when you cannot use Kerberos authentication to authenticate your users, and when you cannot use protocol transition.
    Note that you must have access to both the user name and password to call LogonUser. You can only use the token to access network resources over a single hop, whereas Kerberos delegation allows the impersonated identity to flow across multiple tiers.
  • Use protocol transition. With this approach, you use a non-Kerberos authentication mechanism to authenticate your users, and then use the new WindowsIdentity constructor to obtain a Windows token for the user on the server. Use this approach when you cannot use Kerberos authentication to authenticate your users, for example because they connect to your application over the Internet, but your users do have Windows domain accounts. To get a delegate-level token with this approach, you must be running on a Windows Server 2003 in a Windows 2003 domain and you need to configure your computer or process account in Active Directory as trusted for delegation and protocol transition.
  • Use basic authentication and impersonation. With basic authentication, the user name and password of the user are available in clear text on the server. When IIS authenticates a caller by using basic authentication, it creates a token that contains these credentials. The token can be used for network access. As result, if you configure your application to impersonate the original caller by using the <identity> element or impersonate programmatically by using WindowsIdentity.Impersonate, you can access network resources while impersonating.
    Use basic authentication if you cannot use Kerberos authentication and delegation, and you cannot use LogonUser or protocol transition. For example, if you configure IIS to use integrated Windows authentication, it will use Kerberos authentication if possible, but otherwise default to NTLM authentication—which does not allow access to network resources with an impersonated identity. If you cannot use the new WindowsIdentity constructor because you are not running on a Windows Server 2003 in a Windows 2003 domain, and you do not have access to the users password to call LogonUser, then basic authentication provides a solution. However, with basic authentication, the user's credentials pass through the network in clear text. Therefore, you should be sure that all network connections are secured with SSL or IPSEC.
 
Share this answer
 
Comments
woopsydoozy 6-Sep-13 12:35pm    
I am neither confused nor mixing things, but thanks for the detailed response. Unfortunately, your response is all about impersonation, which I am already doing successfully. What I need is a way to transmit/stream/whatever the file down to the user. My initial attempt using Response.Write(SharePath) does not work because it attempts to open the file from the client, and the client doesn't know anything about the need for impersonation in accessing the file. It appears that Response.TransmitFile should work, but I have a UNC to the file, so maybe I can't do that either? It also looks like opening the file as a stream and then writing it to Response.OutputStream will work, but that seems messy. Any other solutions? (sorry, don't know why there's no button to "reply" to your comment Zoltan--hope you see this)
Zoltán Zörgő 6-Sep-13 14:15pm    
The client should not be aware of the resource's physical path, and that is normal.
Not the UNC path is your problem, but the fact that you have impersonation and not delegation, as you should in this case - all the details I have pasted above are about delegation and not about impersonation. Please see the first link. Impersonation will be enough only if the file you want to send as response is local to IIS - mapping won't work either, since that are specific to the user that maps the remote share, and it needs interactive logon and some other session stuff you don't have with impersonation or delegation.

It should be done with UNC path and delegation.

There are other possibilities though, but those can mess up your application security.
woopsydoozy 6-Sep-13 14:53pm    
By the definitions provided, I'd say I'm doing delegation, and it follows the second pattern in your details, but I'm using a fixed account rather than "flowing" the original caller. I don't want to use the original caller, because most of those people should not have direct access to the share. TransmitFile should have worked, but many report problems with it and UNC; I got it to work locally, but not on the server--perhaps there is something missing that Kerberos delegation would fix? Not thrilled with handling the stream myself, but it worked--see my solution.
Ended up with this:
VB
Dim userpass() As String = My.Settings.FileAccessUP.Split("~")
Using impUser As System.Security.Principal.WindowsImpersonationContext = LocalUtilities.impersonateValidUser(userpass(0), userpass(1))
    Dim endResponse as Boolean
    Try
        If lbFiles.SelectedValue IsNot Nothing Then
            Dim b() As Byte
            Using fs As IO.FileStream = IO.File.OpenRead(lbFiles.SelectedValue)
                ReDim b(fs.Length - 1)
                fs.Read(b, 0, b.Length)
            End Using

            Response.AddHeader("Content-Type", "application/pdf")
            Response.AddHeader("Content-Disposition", "attachment;filename=Report.pdf")
            Response.OutputStream.Write(b, 0, b.Length)  'this works
            'Response.BinaryWrite(b)  'and this works
            'Response.TransmitFile(lbFiles.SelectedValue.Replace("\", "\\"))  'this works locally, but on the server gets a "handle is invalid" error for some reason
            endResponse = True  'need this, or PDF is corrupt
        End If
    Catch ex As Exception
        Throw
    Finally
        LocalUtilities.undoImpersonation(impUser)
    End Try
    If endResponse Then Response.End()
End Using
 
Share this answer
 
v3
We have implemented this in one of our solutions. Maybe your situation is similar so want to cross check.

We have a web-app which needs to identify its users, so we have windows authentication turned on. However users will need to get files on a network share which is ideally password protected. Now you cannot give read access to 'Everyone' on the share (as required by enterprise security). Ideally you will have a Service Account granted read access to this network share and some admin user having Write access for modification.

Solution 1: Use COM Interop and LogOnUser/LogOnUserA APIs to impersonate the service account for the File-Get request.
This will mark the assembly as COMVisible and have other implications. Also the code is quite complicated and debugging intensive.

Solution 2: Create a separate webservice which runs under the context of the service account. This webservice can be either ASMX or WCF. The webservice will take in the FileID (stored in some database to identify each file) and perform read operations, returning either text (File.ReadAllLines) or actual Stream (WCF transferMode=Streaming)
Good thing is that this is all .NET and no COM issues, hence easily understandable and maintainable. And you can use this in some other application as well.

I chose the second one for my case and hope it works out for you as well. :)
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900