Processing files in a virtual directory under IIS is successful when the client is on the server but fails when the client is on another PC on the network.
We have an ASP.NET Web Forms application (c#) that accesses TIF files via a virtual directory pointing at a network location. For example, virtual directory named corpfiles
points at \FileServershare
. The application is an intranet site using Windows Authentication, and the users have access to the file share.
The web site is passed a number of URLs for TIF files on a page, e.g., ./corpfiles/file1.tif
, ./corpfiles/file2.tif
, etc. For each URL that ends in .tif
the page (this code is in the page.aspx.cs
code behind file):
- Gets the physical file path:
var filePath = Server.MapPath(docUrl);
- Ensures the file exists:
if (File.Exists(filePath))
- Converts the TIF to an in-memory PDF and presents it on the web page.
This all works testing from Visual Studio 2022 (I added the virtual directory to my applicationhost.config
file for IIS Express), and when testing from the server hosting the site. However, the File.Exists call fails when the site is connected to from another box on the network.
The filePath returned by Server.MapPath is valid; the user is able to access the original file directly using it.
If I don’t try to access the file and just past the original URL to the user they are able to download the .tif
file without trouble. This isn’t very useful since viewing the file outside of the application is clunky, but it does demonstrate they have access to the original file share.
Is this a multi-hop authentication issue? We have tried supplying specific credentials on the virtual directory and using the client’s credentials.
What am I missing?
2
Answers
The problem was the delegation of credentials was not properly configured. The Domain Admin had to:
The real-time conversion of TIFs to PDFs now works with the result being the users can view the PDFs within the application.
Well, keep in mind the following:
Any time code behind touches or uses a file: a plain full legal path name is used.
Any time a URL resolves to a file, then it not code behind, and you are NOT using a full Windows path name.
But, with code behind, yes, a full regular Windows file name and path is used and CAN be used.
So, what does the above mean?
You actually don’t need to map a virtual folder to the web site, but can use 100% code behind to retrieve such files.
This actually is often a VERY good approach, since then no valid URL’s to folders are mapped though the web site. That enhances security by a LARGE margin.
So, it is not clear at all why the
file.Exists()
is failing, but do keep in mind that is code behind, so File.Exists("full legal Windows path and file name goes here") is required.So, if you need to say present some files (or even folders + files) to the user?
Then you don’t actually have to map or use a virtual folder.
However, the web site WILL most certainly need rights to those folders on the network – but the users don’t!
So, say I wanted to display some files (or folders).
And say I don’t want a mapped virtual folder (since that is a big security hole anyway).
So, remember, code behind DOES NOT use the IIS security model! In other words, you don’t even have to have/use a web.config for that virtual folder, and you don’t even need the virtual folder!
So, there are 2 issues left here to deal with:
First up, how you going to display the files to the user.
A simple GridView is fine if this is just one folder, or better yet consider a TreeView if you have a bunch of folders (say nested folders).
The next issue is security. Remember, code behind does NOT care about the logged on user – it is the web site user that will (or will not) have rights to those files. This is due to for this discussion we are going to DUMP the use of a virtual folder, and NOT use IIS folder mapping here (and that means we by-pass IIS security here).
This DOES mean the web server has to be on that network, and this DOES mean the web server will need rights to that folder – could even be some other server or network storage device (only requirement is those folders/files are on the same network that running the web server).
Of course, we will have to "setup" the context of the web site. As I pointed out, code behind DOES NOT care about the logged on user, and the security enforced by IIS is 100% ignored.
You don’t mention if the web server is part of your company domain or not. Let’s assume it is NOT, and again a good idea to NOT have the web server as part of your company network domain anyway for reasons of security.
However, this THEN does mean that you need a user on the web server, one that you can create – and create a user that is NOT a domain user.
You will THEN need to create a user (same name, same password) on the server with the folders in question. (And again, NOT a domain user, but a user created on that server with the folders + files).
Now, all you have to do is ensure that the code behind runs with this user context.
You can right click on the app-pool, and choose this:
So, we set the app pool to run now as this local created user (called Web in this example).
And we assume you now gone to the server with the shared folders, and ALSO add this user to that server (again, same name, same password).
So, now, without a virtual folder, without caring about who logged into the site, you can now with code behind get/grab/see/use/browse those files with code behind. However, web users can not in ANY way enter a URL or in ANY way get or grab a file. So, it is a nice secure setup.
The only part left is for you to present some type of UI here.
So, say a tree view, might be like this:
And any file you click on, it will be downloaded, but we use code behind – NOT a legal or valid URL path name! (when I say legal path name, I mean a NON virtual and NON URL path name here!).
So, we get say this:
Now, in above I do have check box(s) for each file – probably should not.
So, when user clicks on a file, then I do this:
So, code behind is free to get folders, traverse folders, and all such code is using plain valid full Windows path names. You never have to use any
Server.MapPath()
, since we never using a valid URL, and translating into a full Windows file name (that’s whatServer.MapPath
does) is not required any more.So, your file.exists should work, but I would for several reasons, and one being security. I would not map those folders to the server using a Virtual folder, but ONLY use code behind, and by-pass IIS and such file mapping.
The code to display folders in a tree view: it is in fact not even recursive, and is quite easy to write.