Sunday, 16 September 2018

Getting groups (including nested) for AD user - AccountManagement vs DirectorySearcher vs WindowsIdentity


Testing to see what is fastest to get all groups (i.e. include nested groups, not just top level groups) => WindowsIdentity appears to easily be the fastest, followed by directorysearcher and then accountManagement.

Over 50 tests:
WindowsIdentity average of .3 seconds
DirectorySearcher average of  1.2 seconds
AccountManagement average of 2.3 seconds


Suspect there is a reason why not to use WindowsIdentity because it is so much faster, but not sure what its restrictions are yet.



    class Program
    {
        static AccountManagementService ams = new AccountManagementService();
        static DirectorySearcherService dss = new DirectorySearcherService();
        static WindowsIdentityService wis = new WindowsIdentityService();

        static void Main(string[] args)
        {
            var userId = ConfigurationManager.AppSettings["UsernameToFind"];
            var iterations = 50;
            var amsTimeTaken = new List<long>();
            var dssTimeTaken = new List<long>();
            var wisTimeTaken = new List<long>();

            for (var i = 0; i < iterations; i++)
            {
                amsTimeTaken.Add(CallAms(userId));
                dssTimeTaken.Add(CallDss(userId));
                wisTimeTaken.Add(CallWis(userId));
                Console.WriteLine($"iteration {i} done");
            }

            Console.WriteLine($"AMS average is {(amsTimeTaken.Sum() / iterations)}");
            Console.WriteLine($"DSS average is {(dssTimeTaken.Sum() / iterations)}");
            Console.WriteLine($"WIS average is {(wisTimeTaken.Sum() / iterations)}");

            Console.ReadKey();
        }

        static long CallAms(string userId)
        {
            var watch = System.Diagnostics.Stopwatch.StartNew();
            ams.Lookup(userId);
            watch.Stop();
            return watch.ElapsedMilliseconds;
        }
        static long CallDss(string userId)
        {
            var watch = System.Diagnostics.Stopwatch.StartNew();
            dss.Lookup(userId);
            watch.Stop();
            return watch.ElapsedMilliseconds;
        }
        static long CallWis(string userId)
        {
            var watch = System.Diagnostics.Stopwatch.StartNew();
            wis.Lookup(userId);
            watch.Stop();
            return watch.ElapsedMilliseconds;
        }
    }


    public class WindowsIdentityService
    {
        public List<string> Lookup(string userName)
        {
            List<string> result = new List<string>();
            WindowsIdentity wi = new WindowsIdentity(userName);

            foreach (IdentityReference group in wi.Groups)
            {
                try
                {
                    result.Add(group.Translate(typeof(NTAccount)).ToString().Replace("HIQ\\",""));
                }
                catch (Exception ex) { }
            }
            return result;
        }
    }

    public class AccountManagementService
    {
        string _domain = ConfigurationManager.AppSettings["AmsDomain"];
        public List<string> Lookup(string userId)
        {
            var output = new List<string>();

            using (var ctx = new PrincipalContext(ContextType.Domain, _domain))
            {
                using (var user = UserPrincipal.FindByIdentity(ctx, userId))
                {
                    if (user != null)
                    {
                        output = user.GetAuthorizationGroups() //this returns a collection of principal objects
                            .Select(x => x.SamAccountName)
                            .ToList();
                    }
                }
            }
            return output;
        }
    }


    public class DirectorySearcherService
    {

        public List<string> Lookup(string userId)
        {
            List<string> userNestedMembership = new List<string>();
           
            DirectoryEntry domainConnection = new DirectoryEntry();
            domainConnection.Path = ConfigurationManager.AppSettings["DssDomainPath"];

            DirectorySearcher samSearcher = new DirectorySearcher();
           
            samSearcher.SearchRoot = domainConnection;
            samSearcher.Filter = "(samAccountName=" + userId + ")";
            samSearcher.PropertiesToLoad.Add("displayName");

            SearchResult samResult = samSearcher.FindOne();

            if (samResult != null)
            {
                DirectoryEntry theUser = samResult.GetDirectoryEntry();
                theUser.RefreshCache(new string[] { "tokenGroups" });

                foreach (byte[] resultBytes in theUser.Properties["tokenGroups"])
                {
                    System.Security.Principal.SecurityIdentifier mySID = new System.Security.Principal.SecurityIdentifier(resultBytes, 0);

                    DirectorySearcher sidSearcher = new DirectorySearcher();

                    sidSearcher.SearchRoot = domainConnection;
                    sidSearcher.Filter = "(objectSid=" + mySID.Value + ")";
                    sidSearcher.PropertiesToLoad.Add("distinguishedName");
                    sidSearcher.PropertiesToLoad.Add("name");

                    SearchResult sidResult = sidSearcher.FindOne();

                    if (sidResult != null)
                    {
                        userNestedMembership.Add((string)sidResult.Properties["name"][0]);
                    }
                }
               
            }
            else
            {
                Console.WriteLine("The user doesn't exist");
            }

            return userNestedMembership;

        }

    }