Click here to Skip to main content
15,867,453 members
Articles / Web Development / ASP.NET

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

Rate me:
Please Sign up or sign in to vote.
4.88/5 (13 votes)
9 Oct 2011CPOL2 min read 78.7K   3.6K   47   10
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.

C#
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:

C#
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.

XML
<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.

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead Ominto Inc
United Arab Emirates United Arab Emirates
I am Bachelor in CSE from Khulna University of Engineering & Technology,Bangladesh. I have more than 11 years experience in software design & development, data analysis & modeling, project management and currently working in a software company in Dubai,UAE as a Lead Software Engineer. I am MCAD(Microsoft Certified Application Developer) certified since 2005. Please feel free to contact with me at nill_akash_7@yahoo.com.


Comments and Discussions

 
QuestionAuto login not working Pin
Vikram Singh Rathaur15-Jun-17 21:51
Vikram Singh Rathaur15-Jun-17 21:51 
GeneralIt Works! Pin
Member 1123234519-Oct-15 17:39
Member 1123234519-Oct-15 17:39 
QuestionUser Authentication for All LDAP Groups Pin
fadi1117-Apr-15 14:00
fadi1117-Apr-15 14:00 
QuestionRedirect to another page after authentication Pin
BallJack22-Apr-14 10:14
BallJack22-Apr-14 10:14 
QuestionError in your code Pin
bluesathish21-Apr-14 22:47
bluesathish21-Apr-14 22:47 
QuestionExcellent Pin
Member 448758426-Mar-14 12:16
Member 448758426-Mar-14 12:16 
Questionhow to start with this ??? :confused: Pin
ravikhoda17-Feb-14 18:27
professionalravikhoda17-Feb-14 18:27 
BugIssues Pin
Brian Desmond [MVP]9-Oct-11 9:23
Brian Desmond [MVP]9-Oct-11 9:23 
GeneralRe: Issues Pin
nullpointer12-Aug-13 16:49
nullpointer12-Aug-13 16:49 
GeneralRe: Issues Pin
charbaugh4-Dec-13 19:01
charbaugh4-Dec-13 19:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.