Tip/Trick: Integrating ASP.NET Security with Classic ASP and Non-ASP.NET URLs
One of the questions I am often asked is "How can I integrate ASP.NET security with Classic ASP other non-ASP.NET URLs?". Specifically, people want to know if they can integrate ASP.NET's Forms Authentication, Role Based Security, and URL Authorization features with Classic ASP, PHP, JSP, .HTM, .JPG and other non-ASP.NET URLs.
The good news is that this is pretty easy with ASP.NET 2.0 and IIS 6.0 today, and will get even easier in the IIS 7.0 timeframe. The below blog post demonstrates how to integrate ASP.NET 2.0's Forms Authentication and Login/Membership features with classic ASP and static .HTML files.
For a much more detailed walkthrough of how to achieve this (as well as how to integrate features like ASP.NET role based authorization with classic ASP applications), please read Chapter 6 of Stefan Schackow's excellent ASP.NET 2.0 Security, Membership, and Role Management book.
Some Background on IIS 6.0 Wildcard Mappings
IIS 6.0 with Windows Server 2003 added support for an ISAPI feature called "wildcard mappings". Wildcard mappings provide a way to configure IIS to cause all requests coming into the server to first be routed to one or more ISAPI extensions for processing. What is cool about wildcard mappings in IIS 6.0 is that after the ISAPI extension that is processing the wildcard extension is finished, it can then cause IIS to pass control of the request to the extension or internal handler within IIS that normally would process the request.
ASP.NET 2.0 includes built-in support to take advantage of this wildcard mapping feature. This enables you to run ASP.NET code (or your own custom code) before and after the existing ISAPI extension that processes a non-ASP.NET URL (for example: a .asp, .php or .htm request) executes.
We can use this feature to enable a bunch of cool integration features - including using ASP.NET authentication and authorization features to secure all URLs on a web-server.
How to Configure an IIS 6.0 Wildcard Mapping
For this sample I've created a new IIS application within the IIS 6.0 admin tool called "wildcardtest". It points to a directory that will contain a few files: "default.aspx", "login.aspx", "test.asp" and "test.htm" (these last two files being resources not usually handled by ASP.NET):
By default when a URL request for a .aspx page comes to the application, the ASP.NET ISAPI will process the request. By default when a URL request for test.asp comes to the application, the classic ASP ISAPI will process the request - and no ASP.NET code will run. When a URL request for test.htm comes to the application, IIS6 will process the request internally - and again no ASP.NET code will ever run.
We'll change this by enabling wildcard mappings for this application, and configure ASP.NET to run code before and after all requests to the server. To-do this, right-click on the application within the IIS Admin Tool and select the "properties" context menu item on it. This will bring up the application properties dialog:
You can then click the "configuration" button to pull up the URL mapping rules for the application:
Note how the top of this dialog lists the default ISAPI extension mappings (each URL extension is mapped to an ISAPI responsible for processing it). The bottom half of the dialog lists the "wildcard application map" rules. We can add a application wildcard mapping to the ASP.NET ISAPI by clicking the "insert" button, and pointing at the ASP.NET 2.0 ISAPI extension on disk:
Very, Very Important: Make sure that you uncheck the "Verify this file exists" checkbox. If you don't do this ASP.NET URL resources like WebResource.axd and other URL's handled by ASP.NET that aren't backed by a physical file won't work anymore. This will lead to errors within your pages.
Now close out all of the dialogs by clicking "ok" to accept the changes. You've now configured ASP.NET to be able to run code before and after each URL request into the application.
Enabling Forms Authentication and Url Authorization for non-ASP.NET resources
Once we've completed the above steps to register ASP.NET 2.0 as a wild-card mapping for all URLs into our IIS application, we can then use the standard ASP.NET authentication and authorization techniques to identify users in our application and grant/deny them access to it.
For example, we could add a web.config file to our application that enables ASP.NET's forms authentication feature for this application, and sets up two URL Authorization rules that deny "anonymous" users access to both the test.asp and test.htm URLs:
<configuration>
<system.web>
<authentication mode="Forms" />
</system.web>
<location path="test.asp">
<system.web>
<authorization>
<deny users="?"/>
<allow users="*"/>
</authorization>
</system.web>
</location>
<location path="test.htm">
<system.web>
<authorization>
<deny users="?"/>
<allow users="*"/>
</authorization>
</system.web>
</location>
</configuration>
Now, when I attempt to access either "test.asp" or "test.htm", the ASP.NET authentication and authorization system will execute first to check whether I'm logged into the application with forms-authentication, and if not redirect me to the login.aspx page within my application for me to login:
Note how the "ReturnUrl" used by ASP.NET's forms authentication system above has automatically set the "test.asp" url to redirect back to once I'm logged in (this works just like it would for a .aspx page). Once I successfully enter a username/password, I'll then have access to the test.asp page:
Since the above page is a classic ASP file, I obviously don't have a "User.Identity.Name" property that I can use to identify the logged in user like I would in an ASP.NET page. However, I can retrieve the "AUTH_USER" ServerVariable value within classic ASP to obtain the username (ASP.NET automatically populates this before delegating the processing back to the classic ASP ISAPI).
The code to use this from within classic ASP would look like below:
<body>
<h1>Classic ASP Page</h1>
<h3>
You are logged in as:
<u>
<%=Request.ServerVariables("AUTH_USER") %>
</u>
</h3>
</body>
</html>
Click here to download a complete sample application that implements the above solution. By default it will use a SQL Express database to store ASP.NET 2.0's Membership and Role Management data. Alternatively, you can create and register a SQL 2000 or SQL 2005 database to store the membership and role management values. This older ASP.NET Security tutorial I did shows how to-do this.
How to Learn More about ASP.NET Security
I highly recommend buying a copy of Stefan Schackow's excellent ASP.NET 2.0 Security, Membership, and Role Management book. Stefan is a key member of the ASP.NET team, and owned and designed the security features in the ASP.NET 2.0 release. As such, he really, really, really knows what he is writing about.
Chapter 6 of his book is titled "Integrating ASP.NET Security with Classic ASP" and contains much more detail about the solution I demonstrated above (as well as how to use role security with it, and pass data back and forth between ASP.NET and classic ASP).
Click here to learn more about the book and/or buy it online.
Other Online ASP.NET Security Resources
I've published a number of ASP.NET Tips, Tricks, Recipes and Tutorials in the past that cover ASP.NET 2.0 security. Below is a short-list of them that you might want to review:
- Resource: ASP.NET 2.0 Membership, Roles, Forms Authentication, and Security Resources
- Recipe: Enabling Windows Authentication within an Intranet ASP.NET Web application
- Recipe: Implementing Role Based Security with ASP.NET using Windows Authentication and SQL Server
- Recipe: Configuring ASP.NET 2.0 Application Services to use SQL Server 2000 or SQL Server 2005
- Gotcha: Always set the "applicationName" property when configuring ASP.NET 2.0 Membership and other Providers
- Common Gotcha: Don't forget to <clear/> when adding providers
- Tip/Trick: Source/Documentation for Simple ASP.NET 2.0 SQL Providers Published
- Tip/Trick: Guard Against SQL Injection Attacks
- Tip/Trick: Gathering Custom User Registration Information
- Recipe: How to add a Login, Roles and Profile system to an ASP.NET 2.0 app in only 24 lines of code
- Gotcha: Authorization with the built-in VS 2005 Web Server (aka Cassini)
- Gotcha: Forms Authentication timeout default changed between ASP.NET 1.1 -> ASP.NET 2.0
- Tip/Trick: How To Share Authentication Cookies across ASP.NET V1.1 and ASP.NET V2.0 Applications
For more free ASP.NET Tips, Tricks, and Tutorials I've written, please check out my ASP.NET Tips, Tricks and Tutorials listing.
Hope this helps,
Scott