ASP.NET 2.0 (and better) provide excellent built-in functionality for managing users, memberships, and roles which we've used in many of our projects for securing site administration portals, intranets, and more. However there is one major problem.
The Problem
ASP.NET does not handle folder based security properly. By default ASP.NET's httphandler only handles certain file types (a list of the file types and descriptions can be found here). The web.config file allows you to specify specific users and roles that can access the files within a specific director; however, because of the deficiency in the httphandler file type support, non-supported file types are not protected. For example: we used forms authentication to deny unauthenticated users access from our /Secure directory. Thus http://www.XeroOne.com/secure/default.aspx is protected, but http://www.XeroOne.com/secure/not-secure.html is still accessible by anyone.
On Linux and Apache servers, the .htaccess file is a good solution for
protecting entire directories, and it can be used in a Windows
environment, but it is not a good solution in our case as it takes the
user authentcation control away from ASP.NET Membership. What we
needed was a solution that allowed us to continue to use ASP.NET
Membership to manage and authenticate our users, but to also protect
Non-ASP.NET files for an entire directy.
The Solution
There is no catch-all solution that will work in every scenario. What we've developed is a GOOD system that handles the most common cases, and even a few of the more uncommon. Our solution does require that you have access to IIS 6.0 administation in order to implement. If you're using a shared hosting environment, then our solution simply isn't for you.
In short, all we're doing is creating additional entries in IIS' httphandler. You'll need to determine ahead of time, what file types you will need to protect, for simplicity, this example will show you how to add proction for .html, .pdf, and .doc.
Step 1: Add the IIS entries
- Open IIS 6.0, choose your virtual director, and open the configuration properties window (right-click, choose properties).
- Click on the "Home Directory" tab and click on "Configuration".
- Select the ".aspx" extension in the list, and click on the "Edit" button. Copy the path found in the "Executible" textbox (path to aspnet_isapi.dll).
- Click on the "Cancel" button to clode the "Add/Edit Application Extension Mapping" window.
- Click on the "Add" button in the "Application Configuration" window.
- Paste the coppied path to aspnet_isapi.dll in the executable text area.
- Type the extension you are adding in the extention text area. This can be any extention you want. ie: .html, .pdf, .doc, etc...
- Choose the "Limit to" radio button and type "GET,HEAD,POST,DEBUG" in the textbox.
- Ensure the "Script engine" checkbox is selected, and the "Check that file exists" checkbox is deselected.
- Click on the "Ok" button to finalize the process and close the window.
- Repeat steps 5 - 10 for each file extetion you will be adding.
Step 2: Update the application's web.config
- Open the web.config file for your application to edit
- Find the section of xml for <httpHandlers>
- Within this section add the following entry for each file extention you added to IIS:
<add verb="GET,HEAD,POST,DEBUG" path="*.html"
type="System.Web.UI.PageHandlerFactory"/>
- Note: replace "*.html" with whatever extention you are adding
- Find the section of xml for <compilation> and ensure the definiton appears as below:
<compilation debug="false" strict="false" explicit="true">
- Within the <buildProviders> section, add the following entry for each file extention you added in IIS:
<add extension=".html" type="System.Web.Compilation.PageBuildProvider" />
When you are complete, your web.config sections should appear as follows:
<httpHandlers>
<add verb="GET, HEAD, POST, DEBUG" path="*.html" type="System.Web.UI.PageHandlerFactory"/>
<add verb="GET, HEAD, POST, DEBUG" path="*.pdf" type="System.Web.UI.PageHandlerFactory"/>
<add verb="GET, HEAD, POST, DEBUG" path="*.doc" type="System.Web.UI.PageHandlerFactory"/>
</httpHandlers>
and
<compilation debug="false" strict="false" explicit="true">
<buildProviders>
<add extension=".html" type="System.Web.Compilation.PageBuildProvider" />
<add extension=".pdf" type="System.Web.Compilation.PageBuildProvider" />
<add extension=".doc" type="System.Web.Compilation.PageBuildProvider" />
</buildProviders>
</compilation>
That's it. You're done!