Building Secure ASP.NET Applications: Authentication, Authorization, and Secure Communication

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

 

patterns & practices Developer Center

How To: Create GenericPrincipal Objects with Forms Authentication in ASP.NET 1.1

J.D. Meier, Alex Mackman, Michael Dunner, and Srinath Vasireddy
Microsoft Corporation

Published: November 2002

Last Revised: January 2006

Applies to:

  • ASP.NET 1.1
  • .NET Framework 1.1

See the "patterns & practices Security Guidance for Applications Index" for links to additional security resources.

See the Landing Page for a starting point and complete overview of Building Secure ASP.NET Applications.

Summary: This How To shows you how to create and handle GenericPrincipal and FormsIdentity objects when using Forms authentication. (9 printed pages)

Contents

Summary of Steps Step 1. Create a Web Application with a Logon Page Step 2. Configure the Web Application for Forms Authentication Step 3. Generate an Authentication Ticket for Authenticated Users Step 4. Construct GenericPrincipal and FormsIdentity Objects Step 5. Test the Application
Additional Resources

Applications that use Forms authentication will often want to use the GenericPrincipal class (in conjunction with the FormsIdentity class), to create a non-Windows specific authorization scheme, independent of a Windows domain.

For example, an application may:

  • Use Forms authentication to obtain user credentials (user name and password).
  • Validate the supplied credentials against a data store; for example, a database or Microsoft® Active Directory® directory service.
  • Create GenericPrincipal and FormsIdentity objects based on values retrieved from the data store. These may include a user's role membership details.
  • Use these objects to make authorization decisions.

This How To describes how to create a Forms-based Web application that authenticates users and creates a custom Forms authentication ticket that contains user and role information. It also shows you how to map this information into GenericPrincipal and FormsIdentity objects and associate the new objects with the HTTP Web request context (HttpContext), allowing them to be used for authorization logic within your application.

This How To focuses on the construction of the GenericPrincipal and FormsIdentity objects together with the processing of the forms authentication ticket. For details about how to authenticate users against Active Directory and SQL Server, see the following related How Tos in this guide:

Summary of Steps

This How To includes the following steps:

  • Step 1. Create a Web Application with a Logon Page
  • Step 2. Configure the Web Application for Forms Authentication
  • Step 3. Generate an Authentication Ticket for Authenticated Users
  • Step 4. Construct GenericPrincipal and FormsIdentity Objects
  • Step 5. Test the Application

Step 1. Create a Web Application with a Logon Page

This procedure creates a new ASP.NET Web application. The application will contain two pages; a default page that only authenticated users are allowed to access, and a logon page used to collect user credentials.

To create a Web application with a logon page

  1. Start Visual Studio .NET and create a new C# ASP.NET Web Application called GenericPrincipalApp.

  2. Rename WebForm1.aspx to Logon.aspx.

  3. Add the following controls to Logon.aspx to create a logon form.

    Table 1: Logon.aspx controls

    Control Type Text ID
    Label User Name: -
    Label Password -
    Text Box - txtUserName
    Text Box - txtPassword
    Button Logon btnLogon
  4. Set the TextMode property of the password Text Box control to Password.

  5. In Solution Explorer, right-click GenericPrincipalApp, point to Add, and then click Add Web Form.

  6. Enter default.aspx as the new form's name, and then click Open.

Step 2. Configure the Web Application for Forms Authentication

To edit the application's Web.config file to configure the application for Forms authentication

  1. Use Solution Explorer to open Web.config.

  2. Locate the <authentication> element and change the mode attribute to Forms.

  3. Add the following <forms> element as a child of the <authentication> element and set the loginUrl, name, timeout, and path attributes as follows:

    <authentication mode="Forms">
      <forms loginUrl="logon.aspx" name="AuthCookie" timeout="60"
        path="/">
      </forms>
    </authentication>
    
  4. Add the following <authorization> element beneath the <authentication> element. This allows only authenticated users to access the application. The previously established loginUrl attribute of the <authentication> element redirects unauthenticated requests to the Logon.aspx page.

    <authorization> 
      <deny users="?" />
      <allow users="*" />
    </authorization>
    

Step 3. Generate an Authentication Ticket for Authenticated Users

This procedure writes code to generate an authentication ticket for authenticated users. The authentication ticket is contained within the authentication cookie used by the ASP.NET FormsAuthenticationModule.

The authentication code typically involves looking up the supplied user name and password against either a custom database or against Active Directory.

For information about performing these lookups, see the following How To articles in this guide:

To generate an authentication ticket for authenticated users

  1. Open the Logon.aspx.cs file and the following using statement to the top of the file beneath the existing using statements:

    using System.Web.Security;
    
  2. Add the following private helper method to the WebForm1 class called IsAuthenticated, which is used to validate user names and passwords to authenticate users. This code assumes that all user name and password combinations are valid.

    private bool IsAuthenticated( string username, string password )
    {
      // Lookup code omitted for clarity
      // This code would typically validate the user name and password
      // combination against a SQL database or Active Directory
      // Simulate an authenticated user
      return true;
    }
    
  3. Add the following private helper method called GetRoles, which is used to obtain the set of roles that the user belongs to.

    private string GetRoles( string username)
    {
      // Lookup code omitted for clarity
      // This code would typically look up the role list from a database
      // table.
      // If the user was being authenticated against Active Directory,
      // the Security groups and/or distribution lists that the user
      // belongs to may be used instead
    
      // This GetRoles method returns a pipe delimited string containing
      // roles rather than returning an array, because the string format
      // is convenient for storing in the authentication ticket /
      // cookie, as user data
      return "Senior Manager|Manager|Employee";
    }
    
  4. Display the Logon.aspx form in Designer mode and double-click the Logon button to create a click event handler.

  5. Add a call to the IsAuthenticated method, supplying the user name and password captured through the logon form. Assign the return value to a variable of type bool, which indicates whether or not the user is authenticated.

    bool isAuthenticated = IsAuthenticated( txtUserName.Text,
                                            txtPassword.Text );
    
  6. If the user is authenticated, add a call to the GetRoles method to obtain the user's role list.

    if (isAuthenticated == true )
    {
      string roles = GetRoles( txtUserName.Text);
    
  7. Create a new forms authentication ticket that contains the user name, an expiration time, and the list of roles that the user belongs to. Note that the user data property of the authentication ticket is used to store the user's role list. Also note that the following code creates a non-persistent ticket, although whether or not the ticket / cookie is persistent is dependent upon your application scenario. Persisting authentication cookies is not recommended because they are vulnerable to attacks.

      // Create the authentication ticket
      FormsAuthenticationTicket authTicket = new
           FormsAuthenticationTicket(1,                          // 
             version
                                     txtUserName.Text,           // user 
                                       name
                                     DateTime.Now,               // 
                                       creation
                                     DateTime.Now.AddMinutes(60),// 
                                       Expiration
                                     false,                      // 
                                       Persistent
                                     roles );                    // User 
                                       data
    
  8. Add code to create an encrypted string representation of the ticket and store it as data within an HttpCookie object.

      // Now encrypt the ticket.
      string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
      // Create a cookie and add the encrypted ticket to the
      // cookie as data.
      HttpCookie authCookie = 
                   new HttpCookie(FormsAuthentication.FormsCookieName,
                                  encryptedTicket);
    
  9. Add the cookie to the cookies collection returned to the user's browser.

      // Add the cookie to the outgoing cookies collection.
      Response.Cookies.Add(authCookie);
    
  10. Redirect the user to the originally requested page

      // Redirect the user to the originally requested page
      Response.Redirect( FormsAuthentication.GetRedirectUrl(
                                                    txtUserName.Text,
                                                    false ));
    }
    

Step 4. Construct GenericPrincipal and FormsIdentity Objects

This procedure implements an application authentication event handler and constructs GenericPrincipal and FormsIdentity objects based on information contained within the authentication ticket.

To construct GenericPrincipal and FormsIdentity objects

  1. From Solution Explorer, open global.asax.

  2. Switch to code view and add the following using statements to the top of the file:

    using System.Web.Security;
    using System.Security.Principal;
    
  3. Locate the Application_AuthenticateRequest event handler and add the following code to obtain the forms authentication cookie from the cookie collection passed with the request.

    // Extract the forms authentication cookie
    string cookieName = FormsAuthentication.FormsCookieName;
    HttpCookie authCookie = Context.Request.Cookies[cookieName];
    
    if(null == authCookie)
    {
      // There is no authentication cookie.
      return;
    } 
    
  4. Add the following code to extract and decrypt the authentication ticket from the forms authentication cookie.

    FormsAuthenticationTicket authTicket = null;
    try
    {
      authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    }
    catch(Exception ex)
    {
      // Log exception details (omitted for simplicity)
      return;
    }
    
    if (null == authTicket)
    {
      // Cookie failed to decrypt.
      return; 
    } 
    
  5. Add the following code to parse out the pipe separate list of role names attached to the ticket when the user was originally authenticated.

    // When the ticket was created, the UserData property was assigned a
    // pipe delimited string of role names.
    string[] roles = authTicket.UserData.Split(new char[]{'|'});
    
  6. Add the following code to create a FormsIdentity object with the user name obtained from the ticket name and a GenericPrincipal object that contains this identity together with the user's role list.

    // Create an Identity object
    FormsIdentity id = new FormsIdentity( authTicket ); 
    
    // This principal will flow throughout the request.
    GenericPrincipal principal = new GenericPrincipal(id, roles);
    // Attach the new principal object to the current HttpContext object
    Context.User = principal;
    

Step 5. Test the Application

This procedure adds code to the default.aspx page to display information from the GenericPrincipal object attached to the current HttpContext object, to confirm that the object has been correctly constructed and assigned to the current Web request. You will then build and test the application.

To test the application

  1. In Solution Explorer, double-click default.aspx.

  2. Double-click the default.aspx Web form to display the page load event handler.

  3. Scroll to the top of the file and add the following using statement beneath the existing using statements.

    using System.Security.Principal;
    
  4. Return to the page load event handler and add the following code to display the identity name attached to the GenericPrincipal associated with the current Web request.

    IPrincipal p = HttpContext.Current.User;
    Response.Write( "Authenticated Identity is: " +
                    p.Identity.Name );
    Response.Write( "<p>" );
    
  5. Add the following code to test role membership for the current authenticated identity.

    if ( p.IsInRole("Senior Manager") )
      Response.Write( "User is in Senior Manager role<p>" );
    else
      Response.Write( "User is not in Senior Manager role<p>" );
    
    if ( p.IsInRole("Manager") )
      Response.Write( "User is in Manager role<p>" );
    else
      Response.Write( "User is not in Manager role<p>" );
    
    if ( p.IsInRole("Employee") )
      Response.Write( "User is in Employee role<p>" );
    else
      Response.Write( "User is not in Employee role<p>" );
    
    if ( p.IsInRole("Sales") )
      Response.Write( "User is in Sales role<p>" );
    else
      Response.Write( "User is not in Sales role<p>" );
    
  6. In Solution Explorer, right-click default.aspx, and then click Set As Start Page.

  7. On the Build menu, click Build Solution. Eliminate any build errors.

  8. Press Ctrl+F5 to run the application. Because default.aspx is configured as the start up page, this is the initially requested page.

  9. When you are redirected to the logon page (because you do not initially have an authentication ticket), enter a user name and password (any will do), and then click Logon.

  10. Confirm that you are redirected to default.aspx and that the user identity and the correct role details are displayed. The user should be a member of the Senior Manager, Manager, and Employee role, but not a member of the Sales role.

Additional Resources

For more information, see the following related How Tos in this guide:

patterns & practices Developer Center

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

© Microsoft Corporation. All rights reserved.