How To: Use Forms Authentication with Active Directory in Multiple Domains

 

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

patterns & practices Developer Center

J.D. Meier, Alex Mackman, Blaine Wastell, Prashant Bansode, Andy Wigley, Kishore Gopalan

Microsoft Corporation

August 2005

Applies to

  • ASP.NET version 2.0

Summary

This How To shows you how to use the ASP.NET 2.0 membership feature with multiple Active Directory domains. It shows you how to configure an ActiveDirectoryMembershipProvider for each domain and the corresponding connection strings. It also shows how to get an instance of MembershipProvider corresponding to a specific domain and how to call membership APIs, such as ValidateUser, through the relevant provider.

Contents

Objectives
Overview
Summary of Steps
Step 1. Create a Web Application with a Login Page
Step 2. Configure the Web Application for Forms Authentication
Step 3. Configure the Web Application to Use ActiveDirectoryMembershipProvider
Step 4. Use Membership APIs for Authentication
Security Considerations
Additional Considerations
Additional Resources

Objectives

  • Use the ActiveDirectoryMembershipProvider with forms authentication.
  • Learn how to configure the ActiveDirectoryMembershipProvider when using multiple domains.
  • Learn key production considerations when using membership and forms authentication.
  • Learn key security considerations when using membership and forms authentication.

Overview

ASP.NET version 2.0 introduces a membership feature that you can use with forms authentication. The membership feature provides an abstraction for the underlying data store used to maintain user credentials, such as user names and passwords, and provides an API that enables you to validate user credentials and manage the user database. Supported membership providers include SqlServerMembershipProvider for SQL Server user store databases and ActiveDirectoryMembershipProvider for Active Directory and Active Directory Application Mode (ADAM) user stores.

This How To shows you how to develop a simple Web site that uses forms authentication against Active Directory in a multiple domain scenario. It shows you how to configure the ActiveDirectoryMembershipProvider when using multiple domains and how to authenticate users against the relevant domain controller.

Summary of Steps

To develop a simple application that uses forms authentication with the Active Directory membership provider in a multiple domain scenario, perform the following steps:

  • Step 1. Create a Web application with a login page.
  • Step 2. Configure the Web application for forms authentication.
  • Step 3. Configure the Web application to use ActiveDirectoryMembershipProvider.
  • Step 4. Use Membership APIs for Authentication.

Step 1. Create a Web Application with a Login page

When implementing forms authentication with membership in a multiple domain scenario, you cannot use the login controls provided in ASP.NET version 2.0. Instead, you must directly call the membership APIs. You must create your own custom login page using the server controls like TextBox and Button. The login page enables the existing user to login and new users to register by creating new accounts.

To create a Web application with a login page

  1. Start Microsoft Visual Studio .NET development system, and then create a new ASP.NET Web site named FormsAuthAD.
  2. Use Solution Explorer to add a new Web form named Login.aspx to the site.
  3. Add a Label and a TextBox server control to accept the user ID.
  4. Add a Label and a TextBox server control to accept the password. Make sure that you set the TextMode property of the TextBox to Password.
  5. Add a Button server control and set its Text property to Login.

Step 2. Configure the Web application for Forms Authentication

In this step, you configure your ASP.NET application to use forms authentication.

To configure the Web application for forms authentication

  1. Use Solution Explorer to add a Web.config file to your project.

  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 name and timeout attributes as follows.

    <authentication mode="Forms">
      <forms
          name=".ADAuthCookie"       
          timeout="10" />
    </authentication>
    
    

    If you only set the mode attribute on the <authentication> element and omit setting the attribute on the <forms> element, default settings are used for the <forms> configuration. You should configure only those attributes that you want to overwrite. The default settings for forms authentication as defined in the Machine.config.comments file are shown here.

    <forms name=".ASPXAUTH" loginUrl="login.aspx" 
           defaultUrl="default.aspx" protection="All" timeout="30" path="/" 
           requireSSL="false" slidingExpiration="true"
           cookieless="UseDeviceProfile" domain="" 
           enableCrossAppRedirects="false">
      <credentials passwordFormat="SHA1" />
    </forms>
    
    
  4. Add the following <authorization> element beneath the <authentication> element in your Web.config file, which allows all authenticated users to access the Web page.

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

    This configuration allows only authenticated users to access the application. The "?" indicates unauthenticated users and the "*" indicates all users. By denying unauthenticated users, any requests made by unauthenticated users are redirected to your login page. The loginUrl attribute on the <forms> element determines the name of the login page. The default setting of this attribute in Machine.config.comments is Login.aspx.

Step 3. Configure the Web Application to Use ActiveDirectoryMembershipProvider

Identify all the domains that your application supports in your Active Directory forest and then configure ActiveDirectoryMembershipProvider instances for each domain.

To configure ASP.NET Membership providers for multiple domains

  1. In the Web.config file, add connection strings similar to those shown in the following example that point to your Active Directory user database for each domain.

    <connectionStrings>
      <add name="TestDomain1ConnectionString" connectionString="LDAP://testdomain1.test.com/CN=Users,DC=testdomain1,DC=test,DC=com" />
      <add name="TestDomain2ConnectionString" connectionString="LDAP://testdomain2.test.com/CN=Users,DC=testdomain2,DC=test,DC=com" />
      <add name="TestDomain3ConnectionString" connectionString="LDAP://testdomain3.test.com/CN=Users,DC=testdomain3,DC=test,DC=com" />
    
    </connectionStrings>
    
    

    Note   The connection strings shown here connect to the Users container within three test domains. Update these strings to point to the relevant Users container within your domains.

  2. In the Web.config file, configure the <membership> element with ActiveDirectoryMembershipProvider instances pointing to each domain as shown here.

    <membership >
      <providers>
        <add
          name="TestDomain1ADMembershipProvider"
          type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, 
                Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
          connectionStringName="TestDomain1ConnectionString"
          connectionUsername="testdomain1\administrator" 
          connectionPassword="password"/>
        <add
          name="TestDomain2ADMembershipProvider"
          type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, 
                Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
          connectionStringName="TestDomain2ConnectionString"  
          connectionUsername="testdomain2\administrator" 
          connectionPassword="password"/>
          <add
            name="TestDomain3ADMembershipProvider"
            type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, 
                Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
            connectionStringName="TestDomain3ConnectionString"
            connectionUsername="testdomain3\administrator" 
            connectionPassword="password"/>
      </providers>
    </membership>
    
    

    Make sure you set the connectionStringName attribute to the correct connection string name specified earlier in your <connectionStrings> section.

Note   In the preceding example, it is assumed that you are working in a test domain and have the password of an administrator account capable of creating new accounts. The domain administrator name and password have to be supplied in plaintext. As a result, you should encrypt this configuration section along with the <connectionStrings> section. For more information, see How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI and How To: Encrypt Configuration Sections in ASP.NET 2.0 Using RSA.

Connecting to Active Directory

When the ActiveDirectoryMembership provider connects to Active Directory, it uses the account whose credentials are specified on the connectionUsername property (note the lower-case n, which is different from the connectionStringName property). If you specify the connectionUsername property, you must also specify the connectionPassword property, otherwise an exception is thrown.

If you do not specify account credentials, Active Directory uses your ASP.NET Web application's process account.

Note   The service account that you use to connect to Active Directory must have sufficient permissions in Active Directory. If you place your user accounts in an Active Directory organizational unit (OU), you can create and use a service account that has only read, write, and delete access on that OU (and, optionally, reset password privilege).

Step 4. Use Membership APIs for Authentication

The format of the user name you use when validating users depends on the attributeMapUsername attribute of the <membership> element. The default configuration for the ActiveDirectoryMembershipProvider uses user principal names (UPNs) for name mapping as shown here.

attributeMapUsername="userPrincipalName"
  

Because of this, all user names must have the format UserName@DomainName; for example, mary@testdomain.com or steve@testdomain.com.

You can change the name mapping so that it uses simple user name format by setting the following attribute in the membership provider configuration in the Web.config file.

attributeMapUsername="sAMAccountName"
  

With this configuration, you can use simple user names; for example, Mary or Steve.

To extract username and domain from a UPN

This procedure assumes you want to capture usernames of the format username@domainname.

  1. Add code to your login form to validate input and ensure that the user name is entered in the format username@domainName. For example, you could use a RegularExpressionValidator control like the one shown here.

    <asp:RegularExpressionValidator id="unameRegex"  
       ErrorMessage="Invalid user name. Format: username@domainName" 
       ValidationExpression="^[\w-]+([\. ][\w-]+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"
       ControlToValidate="UserNameTextBox">
    </asp:RegularExpressionValidator>
    
    
  2. Add code similar to the following to your login button click event handler.

    string[] partsOfUserName = UserNameTextBox.Text.Split("@".ToCharArray());
    string domainName = partsOfUserName[1];
    
    

To extract username and domain from a simple user name

This procedure assumes you want to capture user names of the format domainName\userName. You only need a simple user name to perform authentication, but you must still know the correct domain for the user so that you can select the correct ActiveDirectoryMembershipProvider instance with which to validate. There are two ways you can do this:

  • Add another TextBox with a suitable prompt Label to the login form where the user enters the domain
  • Require the user to enter his or her user name using the format domainName\userName.

The next steps assume the second approach.

  1. Add code to your login form to validate input and ensure that the user name is entered in the format domainName\userName. For example, you can use a RegularExpressionValidator control like the one shown here.

    <asp:RegularExpressionValidator id="unameRegex"  
           ErrorMessage="Invalid user name. Format: domainName\username" 
           ValidationExpression="^\w+([-.]\w+)*\\[\w-]+([\. ][\w-]+)*"
           ControlToValidate="UserNameTextBox">
      </asp:RegularExpressionValidator>
    
    
  2. Add code similar to the following to your login button click event handler.

    string[] partsOfUserName = UserNameTextBox.Text.Split("\\".ToCharArray());
    string domainName = partsOfUserName[0];
    string userName = partsofUserName[1];
    
    

To authenticate users

  1. Add code to your login form to validate input and ensure that the user name is entered in the format username@domainName. For example, use a RegularExpressionValidator control. For more information, see How To: Use Regular Expressions to Constrain Input in ASP.NET.

  2. After the code you just entered to extract the username and domain, add code similar to the following to your login button click event handler.

    MembershipProvider domainProvider;
    switch (domainName)
    {
      case "TestDomain1.test.com":
            domainProvider = Membership.Providers["TestDomain1ADMembershipProvider"];
            break;
      case "TestDomain2.test.com":
            domainProvider = Membership.Providers["TestDomain2ADMembershipProvider"];
            break;
      case "TestDomain3.test.com":
            domainProvider = Membership.Providers["TestDomain3ADMembershipProvider"];
            break;
      default:
          throw(new Exception("This domain is not supported"));
    }
    
    // Validate the user with the membership system.
    if(domainProvider.ValidateUser(UserNameTextBox.Text, PasswordTextBox.Text))
    {
        // If there is a RequestUrl query string attribute, the user has
        // been redirected to the login page by forms authentication after
        // requesting another page while not authenticated.
        if (Request.QueryString["ReturnUrl"] != null)
        {
            // RedirectFromLoginPage sets the authorization cookie and then
            // redirects to the page the user originally requested.
            // Set second parameter to false so cookie is not persistent
            // across sessions.
            FormsAuthentication.RedirectFromLoginPage(
                UserNameTextBox.Text, false);
        }
        else
        {
            // If there is no RequestUrl query string attribute, just set
            // the authentication cookie. Provide navigation on the login page
            // to pages that require authentication, or user can use browser
            // to navigate to protected pages. 
            // Set second parameter to false so cookie is not persistent
            // across sessions.
            FormsAuthentication.SetAuthCookie(UserNameTextBox.Text, false);
        }
    }
    else
    {
      Response.Write("Invalid UserID and Password");
    }
    
    

Security Considerations

Failing to protect authentication tickets is a common vulnerability that can lead to unauthorized spoofing and impersonation, session hijacking, and elevation of privilege. When you use forms authentication, consider the following recommendations to help ensure a secure authentication approach:

  • Restrict the authentication cookie to HTTPS connections. To prevent forms authentication cookies from being captured and tampered with while crossing the network, ensure that you use Secure Sockets Layer (SSL) with all pages that require authenticated access and restrict forms authentication tickets to SSL channels.
  • Partition the site for SSL. This allows you to avoid using SSL for the entire site.
  • Do not persist forms authentication cookies. Do not persist authentication cookies because they are stored in the user's profile on the client computer and can be stolen if an attacker gets physical access to the user's computer
  • Consider reducing ticket lifetime. Consider reducing the cookie lifetime to reduce the time window in which an attacker can use a captured cookie to gain access to your application with a spoofed identity.
  • Consider using a fixed expiration. In scenarios where you cannot use SSL, consider setting slidingExpiration="false".
  • Enforce strong user management policies. Use and enforce strong passwords for all user accounts to ensure that people cannot guess one another's passwords and to mitigate the risk posed by dictionary attacks.
  • Enforce password complexity rules. Validate passwords entered through the CreateUserWizard control, by setting its PasswordRegularExpression property to an appropriate regular expression. Also configure the membership provider on the server to use the same regular expression.
  • Perform effective data validation on all requests. Perform strict data validation to minimize the possibilities of SQL injection and cross-site scripting.
  • Use distinct cookie names and paths. By ensuring unique cookie names and paths, you prevent possible problems that can occur when hosting multiple applications on the same server.
  • Keep authentication and personalization cookies separate. Keep personalization cookies that contain user-specific preferences and non-sensitive data separate from authentication cookies.
  • Use absolute URLs for navigation. This is to avoid potential issues caused by redirecting from HTTP to HTTPS pages.

For more information about these additional security considerations, see How To: Protect Forms Authentication in ASP.NET 2.0.

When using forms authentication with Active Directory, you should also consider password reset and account lockout. For more information about these security measures see, How To: Use Forms Authentication with Active Directory in ASP.NET 2.0.

Additional Considerations

The ActiveDirectoryMembershipProvider supports many more attributes than those described in this How To. For more information about all the attributes and about supporting password reset and handling account lockout, see How To: Use Forms Authentication with Active Directory in ASP.NET 2.0.

Additional Resources

Feedback

Provide feedback by using either a Wiki or e-mail:

We are particularly interested in feedback regarding the following:

  • Technical issues specific to recommendations
  • Usefulness and usability issues

Technical Support

Technical support for the Microsoft products and technologies referenced in this guidance is provided by Microsoft Support Services. For product support information, please visit the Microsoft Support Web site at https://support.microsoft.com.

Community and Newsgroups

Community support is provided in the forums and newsgroups:

To get the most benefit, find the newsgroup that corresponds to your technology or problem. For example, if you have a problem with ASP.NET security features, you would use the ASP.NET Security forum.

Contributors and Reviewers

  • External Contributors and Reviewers: Jason Taylor, Security Innovation; Rudolph Araujo, Foundstone Professional Services
  • Microsoft Consulting Services and PSS Contributors and Reviewers: Adam Semel, Tom Christian, Wade Mascia
  • Microsoft Product Group Contributors and Reviewers: Stefan Schackow
  • Test team: Larry Brader, Microsoft Corporation; Nadupalli Venkata Surya Sateesh, Sivanthapatham Shanmugasundaram, Infosys Technologies Ltd.
  • Edit team: Nelly Delgado, Microsoft Corporation; Tina Burden McGrayne, TinaTech Inc.
  • Release Management: Sanjeev Garg, Microsoft Corporation

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.