3

I have a webpage that allows a user to upload a file to a network share. When I run the webpage locally (within VS 2008) and try to upload the file, it works! However, when I deploy the website to the webserver and try to upload the file through the webpage, it doesn't work!

The error being returned to me on the webserver says "Access to the path '\05prd1\emp\test.txt' is denied. So, obviously, this is a permissions issue.

The network share is configured to allow full access both to me (NT authentication) and to the NETWORK SERVICE (which is .NET's default account and what we have set in our IIS application pool as the default user for this website).

I have tried this with and without impersonation upon the webserver and neither way works, yet both ways work on my local machine (in other words, with and without impersonation works on my local machine).

The code that does the file upload is below. Please note that the code below includes impersonation, but like I said above, I've tried it with and without impersonation and it's made no difference.

if (fuCourses.PostedFile != null && fuCourses.PostedFile.ContentLength > 0) {
    System.Security.Principal.WindowsImpersonationContext impCtx;
    impCtx =
        ((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();

    try {
        lblMsg.Visible = true;

        // The courses file to be uploaded
        HttpPostedFile file = fuCourses.PostedFile;
        string fName = file.FileName;
        string uploadPath = "\\\\05prd1\\emp\\";

        // Get the file name
        if (fName.Contains("\\")) {
            fName = fName.Substring(
                fName.LastIndexOf("\\") + 1);
        }

        // Delete the courses file if it is already on \\05prd1\emp
        FileInfo fi = new FileInfo(uploadPath + fName);
        if (fi != null && fi.Exists) {
            fi.Delete();
        }

        // Open new file stream on \\05prd1\emp and read bytes into it from file upload
        FileStream fs = File.Create(uploadPath + fName, file.ContentLength);

        using (Stream stream = file.InputStream) {
            byte[] b = new byte[4096];
            int read;

            while ((read = stream.Read(b, 0, b.Length)) > 0) {
                fs.Write(b, 0, read);
            }
        }

        fs.Close();

        lblMsg.Text = "File Successfully Uploaded";
        lblMsg.ForeColor = System.Drawing.Color.Green;
    }
    catch (Exception ex) {
        lblMsg.Text = ex.Message;
        lblMsg.ForeColor = System.Drawing.Color.Red;
    }
    finally {
        impCtx.Undo();
    }
}

Any help on this would be very appreciated!

Jagd
  • 7,169
  • 22
  • 74
  • 107
  • I don't have much useful to add, except that I've tried to do this many times. I've never managed to get IIS to handle access to network shares from ASP.Net apps. It will work fine in the dev server, though. – jsight Mar 30 '10 at 18:14
  • What are you using to host the site on the webserver? IIS6 or IIS7 or something else? Have you tried running your site on IIS locally? – David McEwing Mar 30 '10 at 18:15
  • Yep, I'm right with you on that. This is not the first time that I've tried to tackle this issue. In the past, I've had to do silly hacks like write the binary to a database, and then have a stored procedure read from the database and rewrite it to file on the disk. However, I know that it is possible to do this because I've used some of the Telerik controls that allow a person to embed an image file within some text, and ultimately what the telerik controls do is write the image file to a predefined network share. – Jagd Mar 30 '10 at 18:19
  • @David - Sorry, I missed your last question. No, I have not tried to run it upon my local IIS. I would assume that the behavior would be the same as upon the webserver. But even were it successful, I'm not sure what that would prove to me. Any ideas? – Jagd Mar 30 '10 at 20:42
  • Wow... it would appear that I've stumped everyone. – Jagd Mar 30 '10 at 23:29
  • Are you certain that the user on the server side is your network service user? Maybe put in a Response.Write(((System.Security.Principal.WindowsIdentity)User.Identity).Name) – Biff MaGriff Mar 30 '10 at 23:35
  • @Biff - yeah, been there, done that. However, I think I've found the answer. It was given to me by an astute member of a different forum. Apparently, the probem occurs due to Kerberos not being properly delegated. The following URL explains the problem in detail-- http://blogs.msdn.com/knowledgecast/archive/2007/01/31/the-double-hop-problem.aspx – Jagd Mar 31 '10 at 15:37

2 Answers2

1

You don't mention what kind of authentication you are using in IIS.

If you are relying on Windows Integrated/NTLM authentication then I think you will have a problem in that unless you can configure Kerberos on your servers, the user's authentication token can't be used beyond the current (web) server - the "double-hop" problem.

If you use Basic (in IIS) or Forms (via ASP.NET), then you will have access to the user's password in clear text. You can then call the Impersonation code using the username/password and should be able to access the shared folder as that user.

I'm also pretty certain that if you use Basic authentication, then the <identity impersonate="true"> tag will work for network share access.

Check out KB 306158 for some more info and code samples too.

David Gardiner
  • 16,892
  • 20
  • 80
  • 117
  • Yes, our domain uses NTLM for authentication, and within my website I use Windows authentication as well. I tried using programmatic impersonation in order to authenticate the user at the file server (on the 2nd hop), but it didn't work. I was able to verify this by going to the security logs on the file server. The security logs showed that the request came from the webserver and that it tried to use the webserver to authenticate and not the user that was being impersonated. – Jagd Apr 01 '10 at 15:56
  • Just to clarify, impersonation doesn't work on the 2nd hop. It works up to the webserver, but after that it gets shot down. And I believe this happens because, as we said earlier, Kerberos is not being delegated properly (which is out of my control). – Jagd Apr 01 '10 at 15:58
  • That's correct. If you're stuck with NTLM then the second hop will bite you. – David Gardiner Apr 03 '10 at 05:54
1

The problem exists in the fact that Kerberos is not being delegated from the webserver to the file server. The ideal solution would be to delegate Kerberos to the file server. Unfortunately, this is not something that I have the power to change. Too much red tape and too much politics. However, I have come up with a hack of sorts.

I created a temporary folder located at the root of the website. Using impersonation, I write the file to this temporary folder (it gets uploaded to this temp folder, in other words).

Having wrote the file to the temp folder, I then copy the file to the file server UNC. This is the 2nd hop, and this is where it makes no difference whether I'm using impersonation or not - because the credentials being sent to the file server are those of the webserver itself. So, what this forced me to do was to give read/write access to the webserver on the UNC share. After doing all of this, the file copy worked as expected.

Jagd
  • 7,169
  • 22
  • 74
  • 107