Return to
ASPNET2SecurityHowTos
How To: Use Forms Authentication with Active Directory (AD) in ASP.NET 2.0
J.D. Meier, Alex Mackman, Blaine Wastell, Prashant Bansode, Andy Wigley
Microsoft Corporation
May 2005
Applies To
* ASP.NET 2.0
* Active Directory
Summary
This How To explains how to use Forms authentication with the Active Directory membership provider. It explains how to configure the Active Directory membership provider, create users, and authenticate users. It also shows you how to enforce the password complexity rules defined by your domain policy and how to handle forgotten passwords by using questions and answers.
Contents
* 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 ASP.NET for Membership
* Step 4: Test Forms authentication
* Additional Considerations
* Additional Resources
Overview
ASP.NET 2.0 introduces a membership feature which you can use with Forms authentication. The membership feature provides an abstraction for the underlying data store used to maintain user credentials such as usernames and passwords and provides an API that enables you to easily validate user credentials and manage the user database. Supported membership providers include
SqlServerMembershipProvider for SQL Server user store databases and
ActiveDirectoryMembersipProvider 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 an Active Directory store. It shows you how to configure the Active Directory Server membership provider, create users, authenticate users and establish password complexity rules. It also shows you how to use questions and answers to enable users who have forgotten their passwords to reset them.
Summary of Steps
To develop a simple application that uses Forms authentication with the Active Directory membership provider, 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 ASP.NET for membership
* Step 4: Test Forms authentication
Step 1: Create a Web Application with a Login Page
In this step, you create a simple Web application with a default page and a login page. The login page enables existing users to login and new users to register by creating new accounts.
To create a Web application with a login page
1. Start Visual Studio .NET and create a new ASP.NET Web site called
FormsAuthAD.
2. Use Solution Explorer to add a new Web form to the site called Login.aspx.
3. Add a Login control to Login.aspx.
By default, this control displays user name and password fields and a Remember me next time checkbox. If the user selects this checkbox, a persistent authentication cookie is created and the user's browser stores it on the user's hard disk.
To disable this feature, set the
DisplayRememberMe property of the Login control to false.
Note that when a user clicks Login on the Login control, it automatically validates the user by calling the configured membership provider, creates a Forms authentication ticket, and then redirects the user back to the originally requested page.
4. If you are working in a test environment and have an account with permissions to create new accounts in Active Directory, add a
CreateUserWizard control beneath the Login control to enable new users to register with your site and create new accounts.
Note: If you do not have the permissions to create new users, you will need to test authentication with an existing account.
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 just set the mode attribute on the <authentication> element, and omit the <forms> element, this results in default settings being used for the <forms> configuration. You should configure only those attributes that you need to overwrite. The default settings for Forms authentication as defined in the Machine.config.comments file is shown below.
<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 ASP.NET for Membership
In this step, you configure the Active Directory membership provider by specifying membership settings in your application's Web.Config file.
To configure ASP.NET for membership:
1. In Web.config, add a connection string similar to the one below that points to your Active Directory user's container.
<connectionStrings>
<add name="ADConnectionString" connectionString="LDAP://testdomain.test.com/CN=Users,DC=testdomain,DC=test,DC=com" />
</connectionStrings>
Note: The connection string shown above connects to the user's container within a domain called testdomain.test.com. Update this string to point to the relevant user's container within your domain.
2. Add a <membership> element after your <authorization> element.
<membership defaultProvider="MyADMembershipProvider">
<providers>
<add
name="MyADMembershipProvider"
type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ADConnectionString"
connectionUsername="testdomain\administrator"
connectionPassword="password"/>
</providers>
</membership>
Make sure you set the
connectionStringName attribute to the same name ("ADConnectionString") you specified earlier in your connectionStrings section.
Make sure to set the defaultProvider attribute value to
MyADMembershipProvider, as this needs to be overwritten. The machine-level default value points to
SQLMembershipProvider type, using the local
SqlExpress instance. If you do not overwrite this attribute, the platform default provider is used.
The connectionUsername property (note the lower case "n", which is contrary to the
connectionStringName property) requires a domain name followed by a backslash, followed by the user account name. If the connectionUsername property is specified, the connectionPassword property must also be specified otherwise an error will result. The specified user account requires sufficient permissions to be able to create users and groups in Active Directory.
Note: In the example above, 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 administrator name and password have to be supplied in plain text. 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 the RSA Provider."
In addition to the above attributes the
ActiveDirectoryMembershipProvider has the following attributes, which you can optionally overwrite.
Table 1 ActiveDirectoryMembershipProvider Attributes and Default Values
| Attribute | Default Value | Description |
| currentConnectionProtection | Secure | Specifies the transport layer security options that are used when opening connections to the directory. This attribute can either be: “Secure” or “None”. If it is set to “Secure”, then the provider will attempt to select the highest level of connection security available. |
| enablePasswordReset | true | Specifies whether the provider is configured to let users reset their passwords |
| enablePasswordRetrieval | false | Specifies whether provider is configured to let users retrieve their passwords |
| enableSearchMethods | false | Allows an administrator to set whether or not search-oriented methods can be called on in the provider instance. |
| requiresQuestionAndAnswer | true | Specifies whether or not a security question and answer need to be provided |
| applicationName | / | The name of the application that is using the membership provider |
| requiresUniqueEmail | false | Specifies whether a unique email address is required from the user when logging in |
| maxInvalidPasswordAttempts | 5 | The number of attempts a user is allowed before they are locked out |
| passwordAttemptWindow | 10 | The number of minutes in which a user is allowed to make attempts to login before they are locked out |
| passwordAnswerAttemptLockoutDuration | 30 | The length of time a user is locked out after exceeding the maximum number of invalid Password attempts |
| passwordFormat | hashed | Gets a value indicating a how passwords are stored in the membership data store, this can be hashed, encrypted or clear |
| minRequiredPasswordLength | 7 | The minimum length a password has to be, before it can be accepted. |
| minRequiredNonAlphanumericCharacters | 1 | The minimum number of non-alphanumeric characters a password must contain |
| passwordStrengthRegularExpression | "" | A regular expression which can be used to create a strong password, by default a strong password should be at least 7 characters with one non alphanumeric character |
| attributeMapUsername | userPrincipalName | Defines the mapping from a property on a MembershipUser object to an attribute within the directory. Must map to either userPrincipalName or sAMAAccountName. |
| attributeMapEmail | mail | Defines the mapping from a property on a MembershipUser object to an attribute within the directory. |
| attributeMapPasswordQuestion | | Defines the mapping from a property on a MembershipUser object to an attribute within the directory. |
| attributeMapPasswordAnswer | | Defines the mapping from a property on a MembershipUser object to an attribute within the directory. |
| attributeMapFailedPasswordAnswerCount | | Defines the mapping from a property on a MembershipUser object to an attribute within the directory. |
| attributeMapFailedPasswordAnswerTime | | Defines the mapping from a property on a MembershipUser object to an attribute within the directory. |
| attributeMapFailedPasswordAnswerLockoutTime | | Defines the mapping from a property on a MembershipUser object to an attribute within the directory. |
Password Resets
The
ActiveDirectoryMembershipProvider class supports password reset security by requiring the user to answer a predetermined question. To enable users to reset their own passwords, you need to set a minimum of four attributes.
* Set
enablePasswordReset to true.
* Set
requiresQuestionAndAnswer to true.
* Set
attributeMapPasswordQuestion to the name of the Active Directory attribute that contains the password question.
* Set
attributeMapPasswordAnswer this to the name of the Active Directory attribute that contains the password answer.
By default, Windows Server 2003 Active Directory schema does not contain attributes for password questions and answers. <<Need to explain how to get these attributes in the schema>>
Your provider configuration to support password resets should look similar to the one below.
<providers>
<add
name="MyADMembershipProvider"
type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ADConnectionString"
connectionUsername="testdomain\administrator"
connectionPassword="password"
requiresQuestionAndAnswer="true"
enablePasswordReset="true"
attributeMapPasswordQuestion="PasswordQuestionADAttribute"
attributeMapPasswordAnswer="PasswordAnswerADAttribute"/>
</providers>
Note: You should also set the optional attribute requiresUniqueEmail="true", to ensure that users have unique email ids.
Beta 2 Note: At present (build 45) the attributeMapXXX attributes are not supported in Beta 2 (they're all missing in IL Dasm), so any attempt to reset the Password will fail with the aforementioned error.
Step 4: Test Forms Authentication
In this step, you test Forms authentication.
Add a Page_Load Event Handler
Add the following code to the Page_Load event handler of your Default.aspx page. This page should only be displayed to authenticated users. To prove that this is the case, the code displays information obtained from the Forms authentication ticket issued to authenticated users.
protected void Page_Load(object sender, [EventArgs] e)
{
Response.Write("Hello, " + [Server.HtmlEncode(User.Identity.Name));]
[FormsIdentity] id = [(FormsIdentity)User.Identity;]
[FormsAuthenticationTicket] ticket = id.Ticket;
Response.Write("<p/>TicketName: " + ticket.Name );
Response.Write("<br/>Cookie Path: " + [ticket.CookiePath);]
Response.Write("<br/>Ticket Expiration: " +
[ticket.Expiration.ToString());]
Response.Write("<br/>Expired: " + [ticket.Expired.ToString());]
Response.Write("<br/>Persistent: " + [ticket.IsPersistent.ToString());]
Response.Write("<br/>IssueDate: " + [ticket.IssueDate.ToString());]
Response.Write("<br/>UserData: " + [ticket.UserData);]
Response.Write("<br/>Version: " + [ticket.Version.ToString());]
}
Logon with an Exiting User
In this step, you test the authentication by logging on with an existing domain account.
To logon with an existing user:
1. Browse to your application's Default.aspx page.
The earlier configuration of the <authorization> element prevents unauthenticated users accessing any pages in your application and causes you to be redirected to your Login.aspx page.
2. Enter valid credentials for an account within your domain and then click Login.
The format of the user name is dependant on the
attributeMapUsername attribute of the <membership> element. The default configuration for the
ActiveDirectoryMembershipProvider uses User Principal Names (
UPNs) for name mapping as shown below:
attributeMapUsername="userPrincipalName"
Therefore all user names must have the format:
[UserName@DomainName]
For example:
mary@testdomain.com
steve@testdomain.com
You can change the mapping for user by setting following attribute in Membership Provider configuration in Web.config file.
attributeMapUsername="sAMAccountName"
With this configuration, supply user names with format
UserName, for example:
mary
steve
Create a New User
In this step, you create a new user to test the login functionality. You will only be able to perform this step if you are working in a test domain environment or where you have configured an administration account that has the privileges to create new users within Active Directory.
To create a new user
1. Browse to your application's Default.aspx page.
2. Create a new user with a strong password. The default rules applied by the Active Directory membership provider for the password are as follows:
* Must be at least seven characters in length.
* Must contain at least one non alphanumeric character.
You must supply a password that conforms to the stronger of the two password policies; the one defined by the provider and the one defined within your Active Directory. The membership password policy is checked first and if that succeeds the provider attempts to create the account in Active Directory. If the supplied password doesn't meet the domain password policy criteria, then the creation fails at this point.
3. Login with your new user account. If successful, you should be redirected back to the Default.aspx page that you initially requested and details from the Forms authentication ticket should be displayed.
Note that if you used the default settings at the time when the user account was created, then you will need to supply the user name in following format.
[UserName@DomainName.]
Additional Considerations
When using Forms authentication, also consider the following:
* Account lockout
Account Lockout
You can configure the account lockout policy. To do so, use the following two provider attributes:
*
maxInvalidPasswordAttempts. This defines the number of failed password attempts, or failed password answer attempts that are allowed before locking out a user’s account. When the number of failed attempts equals the value set in this attribute, the user’s account is locked out. The default value is five.
*
passwordAttemptWindow. This defines the time window, in minutes, during which failed password attempts and failed password answer attempts are tracked. The default value is ten.
With these defaults, if there are five failed login attempts within ten minutes, the account will be locked out.
Additional Resources
* "How To: Protect Forms Authentication"
* "How To: Use Forms Authentication with SQL Server in ASP.NET 2.0"
* "How To: Use the Membership Feature in ASP.NET 2.0"
Return to
ASPNET2SecurityHowTos