Introduction
IIS6 and previous versions allowed the development of .NET application components via the ASP.NET platform. ASP.NET integrated with IIS via an ISAPI extension, and exposed its own application and request processing model. This effectively exposed two separate server pipelines, one for native ISAPI filters and extension components, and another for managed application components. ASP.NET components would execute entirely inside the ASP.NET ISAPI extension bubble and only for requests mapped to ASP.NET in the IIS script map configuration.
IIS7 integrates the ASP.NET runtime with the core web server, providing a unified request processing pipeline that is exposed to both native and managed components known as modules. The many benefits of integration include:
- Allowing services provided by both native and managed modules to apply to all requests, regardless of handler. For example, managed Forms Authentication can be used for all content, including ASP pages, CGIs, and static files.
- Empowering ASP.NET components to provide functionality that was previously unavailable to them due to their placement in the server pipeline. For example, a managed module providing request rewriting functionality can rewrite the request prior to any server processing, including authentication, takes place.
- A single place to implement, configure, monitor and support server features. For example, single module and handler mapping configuration, single custom errors configuration, single url authorization configuration.
This article examines how the ASP.NET applications can take advantage of the integrated mode in IIS7, and illustrates the following tasks:
- Enabling/disabling modules on a per-application level.
- Adding managed application modules to the server, and enabling them to apply to all request types.
- Adding managed handlers.
You can learn more about building IIS7 modules by reading Developing IIS7 modules and handlers with the .NET framework.
Also check out my blog, www.mvolo.com, for more tips on taking advantage of Integrated mode and developing IIS7 modules that leverage the ASP.NET integration in IIS7. There, you can also download a number of such modules including Redirecting requests to your application with the HttpRedirection module, Nice looking directory listings for your IIS website with DirectoryListingModule, Displaying pretty file icons in your ASP.NET applications with IconHandler, and Stopping hot-linking with IIS and ASP.NET.
Prerequisites
To follow the steps in this document you have to have the following IIS features installed
ASP.NET
Install ASP.NET via the Windows Vista Control Panel. Select "Programs and Features" - "Turn on or off Windows features". Then open "Internet Information Services" - "World Wide Web Services" - "Application Development Features" and check "ASP.NET".
If you have a Longhorn Server build please open "Server Manager" - "Manage Roles" <Issue: here should be "Roles" to match current product UI>and select "Web Server (IIS)". Click "Add role services". Under "Application Development" check "ASP.NET".
Classic ASP
Because we want to show how ASP.NET modules now work with all content and not just ASP.NET pages we'd like you to install classic ASP. Install classic ASP via the Windows Vista Control Panel. Select "Programs" - "Turn on or off Windows features". Then open "Internet Information Services" - "World Wide Web Services" - "Application Development Features" and check "ASP".
If you have a Longhorn Server build please open "Server Manager" - "Manage Roles" <Issue: change "Manage Roles" to "Roles">and select "Web Server (IIS)". Click "Add role services". Under "Application Development" check "ASP".
Adding Forms Authentication to Your Application
As part of this task, we will enable the ASP.NET Forms-based Authentication for the application. In the next task, we will enable the Forms Authentication module to run for all requests to your application, regardless of content type.
First, let's configure forms authentication as you would for a normal ASP.NET application.
Creating a sample page
To illustrate the feature in action, we will add a default.aspx page to your web root directory. Open notepad (To make sure you have access to the wwwroot directory below, you need to run as administrator by right clicking on Programs\Accessories\Notepad icon, and clicking "Run as administrator"), and create the following file: %systemdrive%\inetpub\wwwroot\default.aspx. Paste the following lines into it:
<%=Datetime.Now%>
<BR>
Login Name: <asp:LoginName runat="server"/>
All default.aspx does is display the current time and the name of the logged in user. We will use this page later to show forms authentication in action.
Configuring forms authentication and access control rules
Now, let's protect default.aspx with forms authentication. You can do this by creating a web.config file in the %systemdrive%\inetpub\wwwroot directory and adding the configuration shown below:
<configuration>
<system.web>
<!--membership provider entry goes here-->
<authorization>
<deny users="?"/>
<allow users="*"/>
</authorization>
<authentication mode="Forms"/>
</system.web>
</configuration>
This configuration sets the ASP.NET authentication mode to use forms-based authentication, and adds authorization settings to control access to your application. These setting will deny access to anonymous users (?) and only allow authenticated users (*).
Creating a membership provider
Step 1: We need to provide an authentication store against which the user credentials will be verified. To illustrate the deep integration between ASP.NET and IIS we will use our own XML-based Membership provider (you can also use the default SQL Server Membership Provider if you have SQL Server installed).
Add the following entry right after the initial <configuration>/<system.web> configuration element in the web.config file:
<membership defaultProvider="AspNetReadOnlyXmlMembershipProvider">
<providers>
<add name="AspNetReadOnlyXmlMembershipProvider" type="AspNetReadOnlyXmlMembershipProvider" description="Read-only XML membership provider" xmlFileName="~/App_Data/MembershipUsers.xml"/>
</providers>
</membership>
Step 2: After the configuration entry is added, you have to save the Membership provider code provided in Appendix as XmlMembershipProvider.cs in your %systemdrive%\inetpub\wwwroot\App_Code directory. If this directory doesn't exist you will have to create it. Note - be sure to set Save As: All Files if using Notepad to prevent the file from being saved as XmlMembershipProvider.cs.txt.
Step 3: All that's left is the actual credential store. To do this save the xml snippet below as MembershipUsers.xml file in the %systemdrive%\inetpub\wwwroot\App_Data directory. Note - be sure to set Save As: All Files if using Notepad to prevent the file from being saved as MembershipUsers.xml.txt.
<Users>
<User>
<UserName>Bob</UserName>
<Password>contoso!</Password>
<Email>bob@contoso.com</Email>
</User>
<User>
<UserName>Alice</UserName>
<Password>contoso!</Password>
<Email>alice@contoso.com</Email>
</User>
</Users>
If the App_Data directory doesn't exist you have to create it.
NOTE: Due to security changes in Windows Server 2003 and Windows Vista SP1, you can no longer use the IIS7 Administration tool to create Membership user accounts for non-GACed Membership providers. After completing this task, you can go to the IIS Administration tool and add or delete users for your application. Start "INETMGR" from the "Run…" menu. Open the "+" signs in the tree view on your left until the "Default Web Site" shows up. Select "Default Web Site" and then move to the right and click the "Security" category. The remaining features will show "Users". Click "Users" and add one or more user accounts of your choice. If you look into MembershipUsers.xml you will find the newly created users.
Creating a login page
In order to use forms authentication, we will need to create a login page. Open notepad (To make sure you have access to the wwwroot directory below, you need to run as administrator by right clicking on Programs\Accessories\Notepad icon, and clicking "Run as administrator"), and create the login.aspx file in the %systemdrive%\inetpub\wwwroot directory. Note - be sure to set Save As: All Files to prevent the file from being saved as login.aspx.txt. Paste the following lines into it:
<%@ Page language="c#" %>
<form id="Form1" runat="server">
<asp:LoginStatus runat="server" />
<asp:Login runat="server" />
</form>
This is the login page that you will be redirected to when access to a particular resource is denied by your authorization rules.
Time to try it
Open an Internet Explorer Window and request http://localhost/default.aspx. You will see that you are redirected to login.aspx, because initially your are not authenticated, and we withheld access to unauthenticated users earlier. If you successfully log in with one of the username/password pairs specified in MembershipUsers.xml, you will get redirected back to default.aspx page you originally requested. This page will then show the current time and the user identity you authenticated with.
At this point, we have successfully deployed a custom authentication solution using Forms Authentication, Login controls, and Membership. This functionality is not new in IIS7 – it has been available since ASP.NET 2.0 on previous IIS releases.
However, the problem is that only content handled by ASP.NET is protected.
If you close and re-open the browser window, and request http://localhost/iisstart.htm, you won't be prompted for credentials. ASP.NET doesn't participate in a request for a static file like iisstart.htm and therefore it can't protect it with forms authentication. You would see the same behavior with classic ASP pages, CGI programs, PHP or Perl scripts. Forms authentication is an ASP.NET feature, and just isn't available during requests to those resources.
Enabling Forms Authentication for the Entire Application
In this task, we will eliminate the limitation of ASP.NET on previous releases, and enable the ASP.NET Forms Authentication and Url Authorization functionality for our entire application.
In order to take advantage of ASP.NET integration, our application needs to be configured to run in Integrated mode. The ASP.NET integration mode is configurable per application pool, enabling ASP.NET applications in different modes to be hosted side by side on the same server. The default application pool in which our application lives already uses Integrated mode by default, so we don't need to do anything here.
So, why did we fail to experience the benefits of Integrated mode when we tried to access the static page earlier? The answer lies in the default settings for all ASP.NET modules shipped with IIS7.
Taking Advantage of the Integrated Pipeline
The default configuration for all managed modules shipped with IIS, including the Forms Authentication and Url Authorization modules, uses a precondition so that these modules only apply to content that is handled by a managed (ASP.NET) handler. This is done for backwards compatibility reasons.
By removing the precondition, we can make the desired managed module execute for all requests to the application, regardless of content. This will be necessary in order to protect our static files, and any other application content with Forms-based authentication.
To do this, open the application's web.config file located in the %systemdrive%\inetpub\wwwroot directory, and paste the following lines immediately below the first <configuration> element:
<system.webServer>
<modules>
<remove name="FormsAuthenticationModule" />
<add name="FormsAuthenticationModule" type="System.Web.Security.FormsAuthenticationModule" />
<remove name="UrlAuthorization" />
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
<remove name="DefaultAuthentication" />
<add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" />
</modules>
</system.webServer>
This configuration re-adds the module elements without the precondition, enabling them to execute for all requests to the application.
Let's try it now!
Close all instances of Internet Explorer so that the credentials you entered before are not cached anymore. Open Internet Explorer, and make a request to the application at the following url:
http://localhost/iisstart.htm
You will be redirected to the login.aspx page so you can log in.
Log in with a username/password pair you used previously. When you successfully log in, you will be redirected back to the original resource, displaying the IIS welcome page.
Note that even though you requested a static file, the managed forms authentication module and the url authorization module were able to provide their services in order to protect your resource.
To illustrate this even further, let's add a classic ASP page and protect it with Forms Authentication.
Open notepad (To make sure you have access to the wwwroot directory below, you need to run as administrator by right clicking on Programs\Accessories\Notepad icon, and clicking "Run as administrator"), and create a page.asp file in your %systemdrive%\inetpub\wwwroot directory. Note - be sure to set Save As: All Files if using Notepad to prevent the file from being saved as page.asp.txt. Paste the lines below into it:
<%
for each s in Request.ServerVariables
Response.Write s & ": "&Request.ServerVariables(s) & VbCrLf
next
%>
Close all Internet Explorer instances again, otherwise your credentials are still cached and request http://localhost/page.asp. You will again be redirected to the login page, and after successful authentication, be able to display the ASP page.
Congratulations – you have successfully added managed services to the server, enabling them for all requests to the server regardless of handler!
Summary
In this walkthrough, you saw how the ASP.NET Integrated mode can be leveraged to make powerful ASP.NET features available to not just ASP.NET pages, but to the entire application.
More importantly, you can now build new managed modules using the familiar ASP.NET 2.0 APIs that have the ability to execute for all application content, and provided an enhanced set of request processing services to your application.
Related Links
You can also learn more about the basics of building IIS7 modules by reading Developing IIS7 modules and handlers with the .NET framework.
Feel free to check out my blog, www.mvolo.com, for more tips on taking advantage of Integrated mode and developing IIS7 modules that leverage the ASP.NET integration in IIS7. There, you can also download a number of such modules including Redirecting requests to your application with the HttpRedirection module, Nice looking directory listings for your IIS website with DirectoryListingModule, Displaying pretty file icons in your ASP.NET applications with IconHandler, and Stopping hot-linking with IIS and ASP.NET.
Related Content