Home
    Shop
    Advertise
    Write For Us
    Affiliate
    Newsletter
    Contact

Using Forms Authentication with Active Directory

Forms Authentication

Forms Authentication is a system in which unauthenticated requests are redirected to a Web form where users are required to provide their credentials.

 

Upon submitting the form, and being properly verified by your application, an authorization ticket is issued by Web application, in the form of a cookie. This authorization cookie contains the user's credentials or a key for reacquiring the user's identity (therefore making the user's identity persistent). In essence, Forms Authentication is a means for wrapping your Web application with a thin security layer, allowing you to have your own custom login interface and verification functionality.

Active Directory

Active Directory is an essential and inseparable element of the Windows 2000 network architecture that lets organizations efficiently share and manage information about network resources and users. It's essentially a single point of management for Windows-based user accounts, clients, and applications. It also helps organizations integrate non-Windows application with Windows-based applications and devices, thus consolidating directories and easing management of the entire network operating system. Organizations also use Active Directory to extend systems securely to the Internet by forcing their Web application users to authenticate them against their single-point Active Directory.

Requirements

Microsoft Windows® 2000
Microsoft Visual Studio® .NET
Knowledge of Microsoft Visual C#™

Brief

In this article I'll show how to implement form authentication using Active Directory warehouse credentials. The ASP.NET forms authentication allows users write their credentials (user name and password) in a web form to identify themselves. The Web application receives the credential, and it can authenticate the user verifying his user name and password in a data set available. This article describes how to authenticate users in Microsoft® Active Directory® directory service using the protocol LDAP (Light Data Access Protocol). It also describes how to store that information in a GenericPrincipal object and how to store it in HttpContext.Current.User property that follows the request throw the ASP.NET Web application.

Creating the Login Page

The first thing we have to do is to create a new solution in Visual Studio 2005. And add a new web site (if you like, you can download sample User Authentication with Active Directory Visual Studio 2005 project, used in this tutorial). The website must have a simple login page, like the one I show in the next image. The objective of this page is like every login page, to validate the username and password in a domain, the difference is that the validation process will validate against Active Directory.

On the page load event of the login page you can add the following code to display the identity domain and username associated with the current Web request.

if(!Page.IsPostback())
{
    string domainUser = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
    string[] paramsLogin = domainUser.Split('\\');
    txtUser.Text = paramsLogin[1].ToString();
    txtDomain.Text = paramsLogin[0].ToString();
}

Configuring the application

Now we have to configure the application in order that admits the authentication by Forms. You can do this trough the web.config file. You have to change the authentication mode in the web.config and add a secondary element to set the login page, the session timeout and the cookie that contains the authentication info.

Also, you must add the <authorization> tag to allow only the authenticated users have access to the application. If the login process was not successful the user will be redirected to the login page.

For that go to the application's virtual directory Properties, then on the security tab click on Anonymous access and authentication control group and clear the Anonymous access check box.

After that a little modification in the web.config is needed. You will have to add an <identity> element beneath the <authorization> element in Web.config and set the impersonate attribute to true. This causes ASP.NET to impersonate the anonymous account specified earlier.

So your configuration file should looks like this one:

      <authentication mode="Forms">
        <forms loginUrl="logon.aspx" name="adAuthCookie" timeout="60" path="/" />
      </authentication>
 
      <authorization>
        <deny users="?" />
        <allow users="*" />
      </authorization>
 
      <identity impersonate="true" />

As result of this configuration, every request directed to the application will be executed in the configured anonymous account security context. The user will provide credentials through the Web form to authenticate itself in Active Directory, but the account that will be used to have access to Active Directory will be the configured anonymous account.

Implementing the Active directory validation

Now it is time to implement the active directory authentication code. You will create a new class that will provide a method that receives a domain name, user name and password as parameter and returns a Boolean value indicating if there is a matching record in Active Directory.

Yow could start creating a class library with a class that implements an authentication method against AD. You will have to add a new assembly reference to System.DirectoryServices.dll. This provides access to the namespace System.DirectoryServices which contains administered types as it helps in the consultation and treatment in Activate Directory.

The connection to active directory is through LDAP. You have to specify the connection path, it is highly recommended to store this path in a configuration file so the application's administrator could change anytime he wants. For the searching process AD will need a filter attribute.

Initially, the method tries to connect with Active Directory using the provided credentials. If it is successful, the method uses the administered class DirectorySearcher to search the specified user object. If exists, the path is updated so that it aims at the user object, and the filter attribute is updated with the user object's common name attribute.

Your class should looks like the next one

using System.Text;
using System.Collections;
using System.DirectoryServices;
 
private string _path;
private string _filterAttribute;
 
public Class LdapAuthentication
{
 
public LdapAuthentication(string path)
{
      _path = path;
}
 
public bool IsAuthenticated(string domain, string username, string pwd)
{
      string domainAndUsername = domain + @"\" + username;
      DirectoryEntry entry = new DirectoryEntry( _path,
      domainAndUsername, pwd);
      try
      {
      // Bind to the native AdsObject to force authentication.
      Object obj = entry.NativeObject;
      DirectorySearcher search = new DirectorySearcher(entry);
      search.Filter = "(SAMAccountName=" + username + ")";
      search.PropertiesToLoad.Add("cn");
      SearchResult result = search.FindOne();
      if(null == result)
      {
      return false;
      }
      // Update the new path to the user in the directory
      _path = result.Path;
      _filterAttribute = (String)result.Properties["cn"][0];
      }
      catch (Exception ex)
      {
      throw new Exception("Error authenticating user. " + ex.Message);
      }
      return true;
}
 
}

Implementing the authentication process

In this step you are going to develop the fully authentication process that will be launched when the user clicks on the login button using the class you build up before.

For the authenticated users, a form authentication credential will be created and the user will be redirected to the original page that he asked for.

You should add on the login button event handler some code to create a new active directory validation class instance so that it aims at Active Directory in LDAP server. The authentication process will do the following:

a. Authenticate the user against Activates Directory.
b. Create a FormsAuthenticationTicket credential that identifies the user.
c. Encrypt the credential.
d. Create a new cookie that contains the ticket.
e. Add the cookie to the list of cookies that are given back to the user's explorer.

// Path to you LDAP directory server.
// Contact your network administrator to obtain a valid path.
string adPath = "LDAP://localhost”;
LdapAuthentication adAuth = new LdapAuthentication(adPath);
 
 
try
{
      if(true == adAuth.IsAuthenticated(txtDomainName.Text,                        txtUserName.Text,txtPassword.Text))
      {
            // Create the authetication ticket
            FormsAuthenticationTicket authTicket =
            new FormsAuthenticationTicket(1, // version
            txtUserName.Text,
            DateTime.Now,
            DateTime.Now.AddMinutes(60), False , groups);
            // 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);
            // Add the cookie to the outgoing cookies collection.
            Response.Cookies.Add(authCookie);
            // Redirect the user to the originally requested page
            Response.Redirect(
            FormsAuthentication.GetRedirectUrl(txtUserName.Text,false));
      }
      else
      {
            lblError.Text = ”Authentication failed, check username and password.";
      }
}
catch (Exception ex)
{
      lblError.Text = "Error authenticating. " + ex.Message;
}

Remember that you must change the access path so that aims at the AD Server, and the cookie's name must be the same name that you specified before in the web.config file.

Implementing an authentication request controller

Now the question is how the application to knows if the user is authenticated or not every time the application makes a request.

You can do this procedure in the global.asax file. You have to implement an event handler named Application_AuthenticateRequest on it. Remember that in previous steps we generate a cookie whit an authentication ticket on it. In this event handler you must extract that cookie information and create a GenericPrincipal object identifying the authenticated user.

Finally, the GenericPrincipal object will be associated with the current HttpContext object created for each web request.

using System.Web.Security;
using System.Security.Principal;
 
// Extract the forms authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if(null == authCookie)
{
// There is no authentication cookie.
return;
}
 
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;
}
 
// Create an Identity object
GenericIdentity id = new GenericIdentity(authTicket.Name,"LdapAuthentication");
 
// This principal will flow throughout the request.
GenericPrincipal principal = new GenericPrincipal(id, null);
 
// Attach the new principal object to the current HttpContext object
Context.User = principal;

Testing the application

We already finished the authentication process and it is time to test it. Enter a valid domain name, user name, and password and then click Log On, if you are successfully authenticated, you should be redirected back to the page you set as default. If you try to change the url manually before login, you will get the same result as a invalid login, the application will note that there is no authenticated user so it will be redirected to login page again.

I suggest you to debug the application so you can understand how it is working.


Tutorial toolbar:  Tell A Friend  |  Add to favorites  |  Feedback  |