Querying LDAP from C#

Here's a class that will bring you up to speed in querying LDAP servers from C#. It allows you to configure some common settings (root path, and account information for Impersonation) and facilitates some common actions, like verifying if a user or a group exists, enumerating all users and groups, enumerating all group members, and validating a userid/password combination.

Here's how you might use the LDAPHelper:

// Point to Root [Optional]
LDAPHelper.RootPath = @"LDAP://myLDAPServer";
 
// Impersonate [Optional]
LDAPHelper.UserName = "aUserId";
LDAPHelper.Password = "aPassword";
 
// Typical Method Calls, with COMException Catch
try
{
    Console.WriteLine(LDAPHelper.UserExists("Diederik"));
    Console.WriteLine(LDAPHelper.GroupExists("Bloggers"));
}
catch (COMException ex)
{
    Console.WriteLine(ex.ErrorCode + "\t" + ex.Message);
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}


Here's the whole helper class:

//-----------------------------------------------------------------------
// <copyright file="LDAPHelper.cs" company="DockOfTheBay">
//     http://www.dotbay.be
// </copyright>
// <summary>Defines the LDAPHelper class.</summary>
//-----------------------------------------------------------------------
 
namespace DockOfTheBay
{
    using System;
    using System.Collections.Generic;
    using System.DirectoryServices;
 
    /// <summary>
    /// Facilitates commonly used actions against Active Directory.
    /// </summary>
    /// <remarks>
    /// Typical COMExceptions that may be returned are:
    ///     -2147016646: LDAP Server Down
    ///     -2147023570: Login failure
    ///     -2147463168: Bad Path Name 
    /// </remarks>
    public static class LDAPHelper
    {
        /// <summary>
        /// Initializes static members of the LDAPHelper class.
        /// </summary>
        static LDAPHelper()
        {
            RootPath = @"LDAP:\\";
        }
 
        /// <summary>
        /// Gets or sets the Path to the Active Directory server [Optional].
        /// </summary>
        /// <value>The Path to the Active Directory server.</value>
        /// <remarks>The value "LDAP:\\" will be used by default.</remarks>
        public static string RootPath { get; set; }
 
        /// <summary>
        /// Gets or sets the UserName to be used for authentication [Optional].
        /// </summary>
        /// <value>The UserName to be used for authentication [Optional].</value>
        /// <remarks>
        /// When the code is running on a remote machine, set this value to 
        /// impersonate a user of the domain that you're querying.
        /// </remarks>
        public static string UserName { get; set; }
 
        /// <summary>
        /// Gets or sets the PassWord to be used for authentication [Optional].
        /// </summary>
        /// <value>The PassWord to be used for authentication [Optional].</value>
        /// <remarks>
        /// When the code is running on a remote machine, set this value to 
        /// impersonate a user of the domain that you're querying.
        /// </remarks>
        public static string Password { get; set; }
 
        /// <summary>
        /// Checks if a full object path is valid.
        /// </summary>
        /// <param name="fullObjectPath">The full object path.</param>
        /// <returns>True if the path is valid.</returns>
        /// <remarks>Impersonation is not possible here.</remarks>
        public static bool Exists(string fullObjectPath)
        {
            bool found = false;
            if (DirectoryEntry.Exists(fullObjectPath))
            {
                found = true;
            }
 
            return found;
        }
 
        /// <summary>
        /// Verifies if a User exists.
        /// </summary>
        /// <param name="userName">The UserName to verify.</param>
        /// <returns>True if the UserName exists in Active Directory, false if not.</returns>
        public static bool UserExists(string userName)
        {
            using (DirectorySearcher searcher = GetDirectorySearcher())
            {
                searcher.Filter = "(&(ObjectClass=user)(sAMAccountName=" + userName.Substring(userName.IndexOf('\\') + 1) + "))";
 
                // for performance reasons only request needed properties
                searcher.PropertiesToLoad.AddRange(new string[] { "sAMAccountName" });
 
                SearchResult result = searcher.FindOne();
 
                return result != null;
            }
        }
 
        /// <summary>
        /// Verifies if a Group exists.
        /// </summary>
        /// <param name="groupName">The GroupName to verify.</param>
        /// <returns>True if the GroupName exists in Active Directory, false if not.</returns>
        public static bool GroupExists(string groupName)
        {
            using (DirectorySearcher searcher = GetDirectorySearcher())
            {
                searcher.Filter = "(&(objectClass=Group)(sAMAccountName=" + groupName + "))";
 
                // for performance reasons only request needed properties
                searcher.PropertiesToLoad.AddRange(new string[] { "sAMAccountName" });
 
                SearchResult result = searcher.FindOne();
 
                return result != null;
            }
        }
 
        /// <summary>
        /// Returns all stored UserIds.
        /// </summary>
        /// <returns>A list of all UserIds.</returns>
        public static List<string> GetAllUserNames()
        {
            DirectoryEntry de = GetDirectoryEntry();
            List<string> result = new List<string>();
            using (DirectorySearcher srch = new DirectorySearcher(de, "(objectClass=user)"))
            {
                SearchResultCollection results = srch.FindAll();
 
                foreach (SearchResult item in results)
                {
                    result.Add(item.Properties["sAMAccountName"][0].ToString());
                }
            }
 
            return result;
        }
 
        /// <summary>
        /// Returns all stored GroupNames.
        /// </summary>
        /// <returns>A list of all GroupNames.</returns>
        public static List<string> GetAllGroupNames()
        {
            DirectoryEntry de = GetDirectoryEntry();
            List<string> result = new List<string>();
            using (DirectorySearcher srch = new DirectorySearcher(de, "(objectClass=Group)"))
            {
                SearchResultCollection results = srch.FindAll();
 
                foreach (SearchResult item in results)
                {
                    result.Add(item.Properties["sAMAccountName"][0].ToString());
                }
            }
 
            return result;
        }
 
        /// <summary>
        /// Returns all UserIds in a Group.
        /// </summary>
        /// <param name="groupName">The Group.</param>
        /// <returns>A list of all UserIds in the Group.</returns>
        public static List<string> GetAllGroupMembers(string groupName)
        {
            List<string> result = new List<string>();
            DirectorySearcher searcher = GetDirectorySearcher();
            searcher.Filter = "(CN=" + groupName + ")";
            SearchResultCollection groups = searcher.FindAll();
            foreach (SearchResult group in groups)
            {
                ResultPropertyCollection props = group.Properties;
                foreach (object member in props["member"])
                {
                    DirectoryEntry memberEntry = GetDirectoryEntry();
                    memberEntry.Path = RootPath + @"/" + member;
                    PropertyCollection userProps = memberEntry.Properties;
                    object userName = userProps["sAMAccountName"].Value;
                    if (null != userName)
                    {
                        result.Add(userName.ToString());
                    }
                }
            }
 
            return result;
        }
 
        /// <summary>
        /// Validates a UserId / Password combination.
        /// </summary>
        /// <param name="userName">The userid.</param>
        /// <param name="password">The password.</param>
        /// <returns>True if the user can be authenticated, False if not.</returns>
        public static bool IsValidUser(string userName, string password)
        {
            bool authenticated = false;
            try
            {
                DirectoryEntry entry = new DirectoryEntry(RootPath, userName, password);
 
                object nativeObject = entry.NativeObject;
                authenticated = true;
            }
            catch (Exception)
            {
                // not authenticated  
            }
 
            return authenticated;
        }
 
        /// <summary>
        /// Returns a properly configured DirectoryEntry.
        /// </summary>
        /// <returns>A properly configured DirectoryEntry.</returns>
        private static DirectoryEntry GetDirectoryEntry()
        {
            if (string.IsNullOrEmpty(UserName))
            {
                // No Impersonation
                return new DirectoryEntry(RootPath);
            }
            else
            {
                // Impersonation
                return new DirectoryEntry(RootPath, UserName, Password);
            }
        }
 
        /// <summary>
        /// Returns a properly configured DirectorySearcher.
        /// </summary>
        /// <returns>A properly configured DirectorySearcher.</returns>
        private static DirectorySearcher GetDirectorySearcher()
        {
            return new DirectorySearcher(GetDirectoryEntry());
        }
    }
}

3 comments:

  1. this solution doesn't work properly. if the user doesn't exists the exception will throw. No one catch there....

    ReplyDelete
  2. Stop complaining,
    better to have something to start with than nothing.

    ReplyDelete
  3. Hi, thanks for the topic helped me allot

    ReplyDelete