Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Bypass Forms Authentication to Use Active Directory User Authentication in ASP.NET

0.00/5 (No votes)
9 Oct 2011 1  
This article describes how to keep form based and active directory user based authentication process in parallel in ASP.NET.

Introduction

This article describes how to use active directory user authentication process on top of forms authentication in ASP.NET application.

User Scenario

Let's say I have a large ASP.NET application where I have used forms authentication for user authentication process. Suddenly one requirement came up to use an existing active directory for the user authentication process. I found two solutions of it.

  • Replace forms authentication with Windows authentication
  • Bypass forms authentication to use active directory

The first option won't work if foreign key references exist for aspnet_Users.UserId or aspnet_Membership.UserId column.

Bypass Form Authentication

If ASP.NET login control is used for the user login process, then "OnAuthenticate" event can be used to bypass form authentication.

protected void LoginUser_Authenticate(object sender, AuthenticateEventArgs e)
        {
            try
            {
                if (IsActiveDirectoryEnabled)
                {
                    if (ActiveDirectoryConnector.IsUserLoggedIn
			(LoginUser.UserName, LoginUser.Password))
                    {
                        e.Authenticated = true;
                    }
                    else
                    {
                        e.Authenticated = false;
                    }
                }
            }
            catch (Exception ex)
            {
                e.Authenticated = false;
                LoginUser.FailureText = ex.Message;
            }
        }		

The event is registered in page load event of the login page as:

protected void Page_Load(object sender, EventArgs e)
        {
            if (IsActiveDirectoryEnabled)
            {
                LoginUser.Authenticate += new AuthenticateEventHandler
					(LoginUser_Authenticate);
            }
        }

Active Directory Settings

The following configuration section has been used to control the active directory connection and user search criteria.

<ldapConfiguration 
    enabled="true" 
    pageLevelSecurityCheck="false" 
    server="192.168.246.128" 
    domain="test.com" 
    directoryPath="DC=test,DC=com" 
    groupName="elixtrauser" 
    filter="(and(objectCategory=person)(objectClass=user)(samaccountname=usertosearch))" 
    filterReplace="usertosearch">    
  </ldapConfiguration>
  • enabled: This enables active directory authentication process by registering "OnAuthenticate" event in page load of login page.
  • pageLevelSecurityCheck: This indicates if the user authentication check is needed in every page level or no.
  • server: LDAP server name or IP address
  • domain: Domain name
  • directoryPath: The path of the directory where the users reside.
  • groupName: Only the indicated user group will be able to login.
  • filter and filterReplace: Used to search user in the specified directory.

"ActiveDirectoryConfiguration" class is designed and used to map and use this configuration.

Active Directory Connector

This class talks to active directory and searches for user depending on the configuration set in web.config file. "IsUserLoggedIn" method is used for this purpose.

public static bool IsUserLoggedIn(string userName, string password)
        {
            try
            {
                if (ActiveDirectorySettings.Enabled)
                {
                    int startIndex = userName.IndexOf("@");
                    if (startIndex >= 0)
                    {
                        userName = userName.Substring(0, startIndex);
                    }
                    DirectoryEntry ldapConnection = new DirectoryEntry("LDAP://" 
			+ ActiveDirectorySettings.Server + "/" 
			+ ActiveDirectorySettings.DirectoryPath, 
				userName, password);
                    DirectorySearcher searcher = new DirectorySearcher(ldapConnection);
                    searcher.Filter = ActiveDirectorySettings.Filter.Replace("and", "&");
                    searcher.Filter = searcher.Filter.Replace
			(ActiveDirectorySettings.FilterReplace, userName);
                    searcher.PropertiesToLoad.Add("memberOf");
                    searcher.PropertiesToLoad.Add("userAccountControl");

                    SearchResult directoryUser = searcher.FindOne();
                    if (directoryUser != null)
                    {
                        int flags = Convert.ToInt32(directoryUser.Properties
				["userAccountControl"][0].ToString());
                        if (!Convert.ToBoolean(flags & 0x0002))
                        {
                            string desiredGroupName = 
				ActiveDirectorySettings.GroupName.ToLower();
                            if (desiredGroupName!=string.Empty)
                            {
                                desiredGroupName = "cn=" + desiredGroupName + ",";
                                int numberOfGroups = directoryUser.Properties
						["memberOf"].Count;
                                bool isWithinGroup = false;
                                for (int i = 0; i < numberOfGroups; i++)
                                {
                                    string groupName = directoryUser.Properties
					["memberOf"][i].ToString().ToLower();
                                    if (groupName.Contains(desiredGroupName))
                                    {
                                        isWithinGroup = true;
                                        break;
                                    }
                                }
                                if (!isWithinGroup)
                                {
                                    throw new Exception("User [" + userName + "] 
					is not a member of the desired group.");
                                }
                            }
                            return true;
                        }
                        else
                        {
                            throw new Exception("User [" + userName + "] is inactive.");
                        }
                    }
                    else
                    {
                        throw new Exception("User [" + userName + "] 
			not found in the specified active directory path.");
                    }
                }
                else
                {
                    return true;
                }
            }
            catch (LdapException ex)
            {
                if (ex.ErrorCode == 49)
                {
                    throw new Exception("Invalid user authentication. 
		    Please input a valid user name & password and try again.",ex);
                }
                else
                {
                    throw new Exception("Active directory server not found.", ex);
                }
            }
            catch (DirectoryOperationException ex)
            {
                throw new Exception("Invalid active directory path.", ex);
            }
            catch (DirectoryServicesCOMException ex)
            {
                if (ex.ExtendedError == 8333)
                {
                    throw new Exception("Invalid active directory path.", ex);
                }
                else
                {
                    throw new Exception("Invalid user authentication. 
		    Please input a valid user name & password and try again.", ex);
                }
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {
                throw new Exception("Active directory server not found.", ex);
            }
            catch (ArgumentException ex)
            {
                if (ex.Source == "System.DirectoryServices")
                {
                    throw new Exception("Invalid search filter expression.", ex);
                }
                else
                {
                    throw new Exception("Unhandled exception occurred 
			while authenticating user using active directory.", ex);
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Unhandled exception occurred while 
			authenticating user using active directory.", ex);
            }
        }

This method is used in "OnAuthenticate" event by passing the user name and password to check the existence of the user and if the user has the access right. If it's true, then a forms authentication ticket is issued and registered in cookie to create the user login session.

Conclusion

So user authentication from active directory can be achieved easily on top of form authentication.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here