0

If I have the following AD domains path:

AD Paths :

  • LDAP://AAA.CORP.XX.COM
  • LDAP://BBB.CORP.XX.COM
  • LDAP://CCC.BBB.CORP.XX.COM
  • LDAP://DDD.CORP.XX.COM
  • LDAP://EEE.CORP.XX.COM
  • LDAP://FFF.CORP.XX.COM

I need to search in the above domains for user if exist in one of them or not .

My current solution:

I looped via all domains above and for each domain I check if the user existed or not and at one of domains above it took from 6-7 seconds and the rest took less than 1 second.

Proposed solutions to enhance performance:

  1. Try to search for user in the parent domain that should be LDAP://CORP.XX.COM so It will save number of searching instead of 5 searches for each domain to be 1 search for parent domain
  2. Try to use the "Global Catalog" ==> I need guid here (tutorial with C# code)

Which solution is better to enhance performance issue ?

Terry Gardner
  • 10,957
  • 2
  • 28
  • 38
Mohammed Thabet
  • 21,387
  • 7
  • 27
  • 43
  • what code do you have..? what does your connection cn= dn= ect... look like.. are you creating a DirectorySearcher Object...? also when searching for users what Attribute are you planning to search / check on..? SAMAccount... ect.. – MethodMan Dec 20 '11 at 20:14
  • DirectoryEntry de = new DirectoryEntry() ; de.Path ="LDAP://AAA.CORP.XX.COM"; Search Filter format=(&(objectClass=user)(sAMAccountName={0})) – Mohammed Thabet Dec 20 '11 at 20:46
  • hold on let me see if I can send you some code snippets that you will be able to follow give me 2 mins ok the public String GetName(string username) will also work for you ..alter anyway you like I – MethodMan Dec 20 '11 at 20:47
  • Thanks DJ ,I moved throu your code but it seems to be search for user based on domain path . so I still have the same issue that I will search for each domain and it my main issue I need to hit search 1 time instead of 5 times – Mohammed Thabet Dec 20 '11 at 21:18
  • you should be able to use the existing code as well to get at other things.. have you tried to get any of the attributes and within the directoryEntry variable see what's available.. the entry variable should yield a lot – MethodMan Dec 20 '11 at 21:20
  • try this link as well for examples http://geekswithblogs.net/mhamilton/archive/2005/10/04/55920.aspx – MethodMan Dec 20 '11 at 21:41
  • http://www.java2s.com/Code/CSharp/Web-Services/DirectoryServicesDirectoryEntry.htm – MethodMan Dec 20 '11 at 21:42

3 Answers3

2

If you're using .NET 3.5 or newer, you should be able to use a PrincipalSearcher and a "query-by-example" principal to do your searching:

// create your domain context
// here, you could also include a specific domain, if needed
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);

// define a "query-by-example" principal - here, we search for a UserPrincipal 
UserPrincipal qbeUser = new UserPrincipal(ctx);

// if you're looking for a particular user - you can limit the search by specifying
// e.g. a SAMAccountName, a first name - whatever criteria you are looking for
qbeUser.SamAccountName = "johndoe";

// create your principal searcher passing in the QBE principal    
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);

// find all matches
foreach(var found in srch.FindAll())
{
    // do whatever here - "found" is of type "Principal" - it could be user, group, computer.....          
}

You can specify any of the properties on the UserPrincipal and use those as "query-by-example" for your PrincipalSearcher. This is a lot easier than using the older DirectorySearcher approach.

If you haven't already - absolutely read the MSDN article Managing Directory Security Principals in the .NET Framework 3.5 which shows nicely how to make the best use of the new features in System.DirectoryServices.AccountManagement

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • Thanks marc_s : I missed the piece of code that determine parent domain name (I guess in my case should be: CORP.XX.COM) Should I pass this name in principalContext() ???? – Mohammed Thabet Dec 20 '11 at 21:42
  • @thabet084: I would try to start without passing anything in - just to see where you end up and where it searches first. Once that's up and running, then start to play with passing in various LDAP paths as starting points. – marc_s Dec 20 '11 at 21:44
  • good point Marc I totally forgot about that.. I personally was so use to using what I posted because of LDAP, AD and one of the Java Tools I had to query once which looks familiar now that I see context lol I voted you up – MethodMan Dec 20 '11 at 22:18
0

Here is a Class that I wrote and used at several places look thru the methods to see what you can use..

using System;
using System.Text;
using System.Collections;
using System.DirectoryServices;
using System.Diagnostics;
using System.Data.Common;

namespace Vertex_VVIS.SourceCode
{
    public class LdapAuthentication
    {
        private String _path;
        private String _filterAttribute;

        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;
        }

        public String GetName(string username)
        {

            String thename = null;

            try
            {
                DirectoryEntry de = new DirectoryEntry(_path);
                DirectorySearcher ds = new DirectorySearcher(de);
                ds.Filter = String.Format("(SAMAccountName={0})", username);
                ds.PropertiesToLoad.Add("displayName");
                SearchResult result = ds.FindOne();
                if (result.Properties["displayName"].Count > 0)
                {
                    thename = result.Properties["displayName"][0].ToString();
                }
                else
                {
                    thename = "NA";
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error Getting Name. " + ex.Message);
            }

            return thename.ToString();
        }

        public String GetEmailAddress(string username)
        {
            String theaddress = null;
            try
            {
                DirectoryEntry de = new DirectoryEntry(_path);
                DirectorySearcher ds = new DirectorySearcher(de);
                ds.Filter = String.Format("(SAMAccountName={0})", username);
                ds.PropertiesToLoad.Add("mail");
                SearchResult result = ds.FindOne();
                theaddress = result.Properties["mail"][0].ToString();
                de.Close();
            }
            catch (Exception ex)
            {
                throw new Exception("Error Getting Email Address. " + ex.Message);
            }

            return theaddress.ToString();
        }
        public String GetTitle(string username)
        {
            String thetitle = null;
            try
            {
                DirectoryEntry de = new DirectoryEntry(_path);
                DirectorySearcher ds = new DirectorySearcher(de);
                ds.Filter = String.Format("(SAMAccountName={0})", username);
                ds.PropertiesToLoad.Add("title");
                SearchResult result = ds.FindOne();
                result.GetDirectoryEntry();
                if (result.Properties["title"].Count > 0)
                {
                    thetitle = result.Properties["title"][0].ToString();
                }
                else
                {
                    thetitle = "NA";
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error Getting the Title. " + ex.Message);
            }

            return thetitle.ToString();
        }

        public String GetPhone(string username)
        {
            String thephone = null;
            try
            {
                DirectoryEntry de = new DirectoryEntry(_path);
                DirectorySearcher ds = new DirectorySearcher(de);
                ds.Filter = String.Format("(SAMAccountName={0})", username);
                ds.PropertiesToLoad.Add("mobile");
                SearchResult result = ds.FindOne();
                result.GetDirectoryEntry();
                if (result.Properties["mobile"].Count > 0)
                {
                    thephone = result.Properties["mobile"][0].ToString();
                }
                else
                {
                    thephone = "NA";
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error Getting Phone Number. " + ex.Message);
            }

            return thephone.ToString();
        }

        public String GetGroups()
        {
            DirectorySearcher search = new DirectorySearcher(_path);
           search.Filter = "(cn=" + _filterAttribute + ")";
           search.PropertiesToLoad.Add("memberOf");
            StringBuilder groupNames = new StringBuilder();

            try
            {
                SearchResult result = search.FindOne();

                int propertyCount = result.Properties["memberOf"].Count;

                String dn;
                int equalsIndex, commaIndex;

                for (int propertyCounter = 0; propertyCounter < propertyCount; propertyCounter++)
                {
                    dn = (String)result.Properties["memberOf"][propertyCounter];

                    equalsIndex = dn.IndexOf("=", 1);
                    commaIndex = dn.IndexOf(",", 1);
                    if (-1 == equalsIndex)
                    {
                        return null;
                    }

                    groupNames.Append(dn.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1));
                    groupNames.Append("|");

                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error obtaining group names. " + ex.Message);
            }
            return groupNames.ToString();
        }

        public bool IsUserGroupMember(string strUserName, string strGroupString)
        {
            bool bMemberOf = false;
            ResultPropertyValueCollection rpvcResult = null; 
            try
            {
                DirectoryEntry de = new DirectoryEntry(_path);
                DirectorySearcher ds = new DirectorySearcher(de);
                ds.Filter = String.Format("(SAMAccountName={0})", strUserName);
                ds.PropertiesToLoad.Add("memberOf");
                SearchResult result = ds.FindOne();
                string propertyName = "memberOf";  
                rpvcResult = result.Properties[propertyName];  

                foreach (Object propertyValue in rpvcResult)  
                 {
                     if (propertyValue.ToString().ToUpper() == strGroupString.ToUpper())
                     {  
                         bMemberOf = true;
                         break;
                     }  
                 }  
            }
            catch (Exception ex)
            {
                throw new Exception("Error Getting member of. " + ex.Message);
            }

            return bMemberOf;

        }
    }
}
MethodMan
  • 18,625
  • 6
  • 34
  • 52
  • Thanks DJ ,I moved throu your code but it seems to be search for user based on domain path . so I still have the same issue that I will search for each domain and it my main issue I need to hit search 1 time instead of 5 times – – Mohammed Thabet Dec 20 '11 at 22:07
0

I answered a similary question (Can I match a user to a group accross different domains) and the answer is close to @Marc_s, but at the end of the answer you can see where to place the domain.

Community
  • 1
  • 1
JPBlanc
  • 70,406
  • 17
  • 130
  • 175