Forms Authentication

for RuBoard

The previous section showed how easy it is to use Windows authentication in ASP.NET. ASP.NET provides another security mechanism as well: forms authentication. Why would you want to use it? One reason is because Windows authentication, although easy to use, makes a couple significant assumptions.

Windows Versus Forms Authentication

For one thing, Windows authentication assumes you have a scalable Windows domain implementation already in place. However, this is not always a safe assumption. Many Web site administrators prefer not to go to the trouble of designing, implementing, and maintaining the Active Directory implementation on which domain-based security rests. Others may not have the expertise or budget to figure out how to get Active Directory to scale into the millions of users. Without an Active Directory implementation, you can authenticate against the account database that every Windows 2000 server maintains. However, this approach means that this account database must be replicated in some fashion among servers in a cluster or you are limited to a single server.

Ultimately, what all of this comes down to is that you may want to authenticate users against a credential store other than a Windows 2000 domain. Forms authentication provides one way to do this.

Windows authentication also assumes you want only minimal control over the user interface presented to the user. By default, Windows-based authentication uses a standard browser dialog box to collect the user's credentials. If you want to integrate the form to collect credentials into an existing Web page or provide your own login form, you are out of luck. Forms authentication provides a way for you, the developer, to determine what interface the user receives.

All the advantages of forms authentication are not free, however. First, forms authentication requires that the user has cookies enabled. Although ASP.NET has provided a way to track Session state without cookies, it has not provided a way to track forms authentication without cookies. Hopefully, this will come in a future version of ASP.NET. Second, you, the developer, need to create a login page and write some code to make this all work. ASP.NET provides the infrastructure, but you need to provide the specific implementation.

Other Advantages

Maybe you already do this type of authentication. So what's the big deal with forms authentication? Perhaps the most common security mechanism in place today among ASP developers provides many of the same advantages. I provide a customized login page for my users and authenticate them against my credential store. After they are authenticated, I either write a cookie or save their authentication into a session variable. In every page, I have an include file that looks for the Session() value or cookie. If it isn't there, I redirect the user back to the login page. This can be very effective but it has two big problems:

  1. What if I forget the include file?

  2. How do I protect PDF, ZIP, or JPG files? There is no place to put the code!

Forms authentication enables me to do all this without having to include code in every page to check whether the user was properly authenticated.

NOTE

ASP.NET authentication and authorization is applied only to files that are mapped to the ASP.NET ISAPI filter. This means that, by default, it will not be applied to any file that is loaded, other than the built-in ASP.NET file types listed in Chapter 2, "Page Framework" ”for example, a JPG or a ZIP file. If you add these file types to the ISAPI filter, they can participate in the security model.


Process

When forms authentication is enabled and a request is made for a page, ASP.NET first determines whether authentication is needed. If it is, ASP.NET then checks for an authentication cookie in the request. If it is not present, ASP.NET redirects the user to the login page and passes the URL of the original page as a query string parameter, named ReturnURL, to the login page.

NOTE

The user is sent to the login page using a 302 location-moved redirection. This means that any form data that may have been included with the request is lost.


The login page collects users' credentials and is responsible for validating them against a credential store. This is where you as the developer get control. The credential store could consist of an LDAP directory, a database, or even something as simple as an XML file. When the credentials have been verified , RedirectFromLoginPage() is called to write an authentication ticket into a cookie and redirect the user to the original content that the user requested . A diagram of this process is shown in Figure 7.1.

Figure 7.1. A process flow for the forms authentication process.

graphics/07fig01.gif

NOTE

Forms authentication is implemented in ASP.NET, not IIS. This means that before forms authentication can even begin the authentication process, the request from the user must be passed to ASP.NET. For this to work, you need to make sure that anonymous authentication is enabled in IIS. If it is not, the user might first be asked to authenticate against a Windows-based account before your login page is shown!


Settings

Forms authentication is enabled in the web.config file by setting the mode attribute of the authentication element to Forms. When the authentication mode is set to Forms, the authentication element may contain a forms element with additional information specific to forms authentication.

 <authentication mode="Forms">     <forms name="FORMURL" loginUrl="login.aspx" protection="All"          timeout="30" path="/" /> </authentication> 

The path attribute specifies the path that should be used to set the cookie. The default value is a slash (/). It is best to stick with the default here because many browsers use case-sensitive paths. Depending on the URL requested, the cookie may not be available, preventing you from ever authenticating successfully.

The name attribute specifies the name of the cookie that should be used to store the authentication ticket. Varying the name is useful if you have more than one authenticated area in your Web site, but you still want to leave the path set to / to avoid the case-sensitivity issue. The default value for the name is .ASPXAUTH.

The loginurl attribute specifies the URL of the login page used to authenticate the user. The default value is default.aspx, which in most cases doesn't make much sense. You will probably want to set this to login.aspx or something similar.

The protection attribute determines what type of protection is applied to the authentication ticket. Two options are available for protecting the authentication ticket: encryption and validation. Encryption encrypts the authentication ticket using Triple DES or DES, depending on the length of the encryption key. If the key is more than 48 bytes in length, Triple DES is used. Validation verifies that an encrypted ticket has not been altered in transit between the client and the server. This is done by concatenating a validation key onto the cookie data, computing a Message Authentication Code, and appending the Message Authentication Code to the cookie. The method used for creating the Message Authentication Code is set in the machine.config file as part of the <machineKey> element and includes options for SHA1, MD5, or Triple DES. Both the encryption key and validation key are also set in this config file. By default, both are autogenerated. This is fine for a site that consists of a single Web server, but if you have load-balanced Web servers, it is important to set this to a manual value to ensure that all Web servers can properly encrypt and validate keys.

The timeout attribute determines the amount of time (in minutes) that the authentication ticket is good for. This is a sliding expiration value; that is, the timeout clock is reset each time the user requests a page successfully. If the time between page requests exceeds this value, the user is automatically logged out. This is sometimes confusing, so let's look at an example. Assume that the timeout value is set to 5 minutes. You make a page request and authenticate yourself via the login page. You then request a new page once every 2 minutes for the next 20 minutes. You will not be asked to log in again 5 minutes after the first page you requested. In fact, in this scenario, you will not be requested to log in again until after 26 minutes have passed. However, if you make a page request and authenticate yourself via the login page and then wait 6 minutes to request the next page, you will be asked to log in again. The interval between the page requests has exceeded the timeout value.

The timeout is implemented by specifying an expiration date for the cookie that is written to the browser. When the cookie is initially written it is given an absolute expiration date timeout minutes in the future. If I don't make a request within timeout minutes of when the cookie was set, it expires and the browser gets rid of it, thus logging me out.

There is one small wrinkle. For performance reasons, ASP.NET doesn't write the cookie to the browser on every request. Instead, it writes the cookie only when more than half the timeout value has elapsed. Revisiting the earlier example, this means that if I log in, wait 2 minutes, request a page, and then wait 4 minutes and request another page, I will be asked to log in again. At no point did the interval between my requests exceed 5 minutes, but when I made my initial request at 0:00, the cookie was written out with an expiration of 5:00. When I made my second request at 2:00, because I was not halfway to the timeout, the cookie was not rewritten and its expiration remained 5:00 from the first page request (not the most recent one). When I then made my third request at 6:00, although it was only 4 minutes from my second request, the cookie had expired because its expiration was set to 5:00. The real takeaway here is to realize that the sliding timeout value means that the interval between requests could be anywhere from timeout /2 to timeout because of the algorithm for rewriting cookies.

Now that you know how it works, let's take a look at an example. First, you need to ensure that anonymous authentication is on in the IIS.

Second, you need to change the authentication element's mode attribute in your application's web.config to Forms and add the Forms element. To force authentication, you also need to change the <authorization> element to contain a <deny users="?"> . More about this last setting is in the section "File Authorization." The web.config should look like Listing 7.3.

Listing 7.3 Web.config for Simple Forms Authentication
 <?xml version="1.0" encoding="utf-8" ?> <configuration>     <system.web>         <!--  AUTHENTICATION           This section sets the authentication policies of the application.           Possible modes are "Windows","Forms", "Passport" and "None"     -->         <authentication mode="Forms">             <forms loginUrl="login.aspx" timeout="5" protection="All" />         </authentication>         <!--  AUTHORIZATION           This section sets the authorization policies of the application.           You can allow or deny access           to application resources by user or role. Wildcards:           "*" mean everyone, "?" means anonymous           (unauthenticated) users.     -->         <authorization>             <deny users="?" /> <!-- Allow all users -->             <!--  <allow     users="[comma separated list of users]"                               roles="[comma separated list of roles]"/>                    <deny      users="[comma separated list of users]"                              roles="[comma separated list of roles]"/>             -->         </authorization>     </system.web> </configuration> 

Next, you need to create a login form. Listings 7.4 and 7.5 contain a sample login page that collects a username and password. If the username equals "Chris" and the password equals "Kinsman", the authentication ticket is written. The user is directed to the page she initially requested by calling RedirectFromLoginPage() and passing it the username.

Listing 7.4 Simple Login Page
 <%@ Page language="c#" Codebehind="login.aspx.cs" AutoEventWireup="false" Inherits="SimpleForm.login" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <HTML>     <HEAD>         <meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">         <meta name="CODE_LANGUAGE" Content="C#">         <meta name="vs_defaultClientScript" content="JavaScript (ECMAScript)">         <meta name="vs_targetSchema" content="http://schemas.microsoft.com/ intellisense/ie5">     </HEAD>     <body MS_POSITIONING="GridLayout">         <form id="login" method="post" runat="server">             <asp:Label id="Label1" style="Z-INDEX: 101; LEFT: 8px; POSITION: absolute; TOP: 8px" runat="server">User Name:</asp:Label>             <asp:Button id="btnLogin" style="Z-INDEX: 105; LEFT: 254px; POSITION: absolute; TOP: 7px" runat="server" Text="Login"></asp:Button>             <asp:TextBox id="txtPassword" style="Z-INDEX: 104; LEFT: 89px; POSITION: absolute; TOP: 38px" runat="server"></asp:TextBox>             <asp:Label id="Label2" style="Z-INDEX: 103; LEFT: 8px; POSITION: absolute; TOP: 41px" runat="server">Password:</asp:Label>             <asp:TextBox id="txtUserName" style="Z-INDEX: 102; LEFT: 89px; POSITION: absolute; TOP: 5px" runat="server"></asp:TextBox>             <asp:Label id="lblMessage" style="Z-INDEX: 106; LEFT: 15px; POSITION: absolute; TOP: 81px" runat="server" Width="281px" Height="19px" ForeColor="Red" Visible="False">Invalid Login!</asp:Label>         </form>     </body> </HTML> 
Listing 7.5 Class File for ASP.NET Page in Listing 7.4
 using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Drawing; using System.Web; using System.Web.SessionState; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; namespace SimpleForm {     /// <summary>     /// Summary description for login.     /// </summary>     public class login : System.Web.UI.Page     {         protected System.Web.UI.WebControls.Label Label1;         protected System.Web.UI.WebControls.Button btnLogin;         protected System.Web.UI.WebControls.TextBox txtPassword;         protected System.Web.UI.WebControls.Label Label2;         protected System.Web.UI.WebControls.TextBox txtUserName;         protected System.Web.UI.WebControls.Label lblMessage;         public login()         {             Page.Init += new System.EventHandler(Page_Init);         }         private void Page_Load(object sender, System.EventArgs e)         {             // Put user code to initialize the page here         }         private void Page_Init(object sender, EventArgs e)         {             //             // CODEGEN: This call is required by the ASP.NET Web Form Designer.             //             InitializeComponent();         }         #region Web Form Designer generated code         /// <summary>         /// Required method for Designer support - do not modify         /// the contents of this method with the code editor.         /// </summary>         private void InitializeComponent()         {             this.btnLogin.Click += new System.EventHandler(this.btnLogin_Click);             this.Load += new System.EventHandler(this.Page_Load);         }         #endregion         private void btnLogin_Click(object sender, System.EventArgs e)         {             if(txtUserName.Text == "Chris" && txtPassword.Text == "Kinsman")             {                 // Authenticate the user                 System.Web.Security.FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, false);             }             else             {                 // Show the invalid login message                 lblMessage.Visible = true;             }         }     } } 

Now, if you hit the URL for this application, you should be redirected to the login page. When you enter Username: Chris and Password: Kinsman, you will be redirected to the default page for the application.

for RuBoard


C# Developer[ap]s Guide to ASP. NET, XML, and ADO. NET
C# Developer[ap]s Guide to ASP. NET, XML, and ADO. NET
ISBN: 672321556
EAN: N/A
Year: 2005
Pages: 103

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net