Check group membership from AD with Foreign Security Principals

The following code will check if a user is a member of a specific group. This will work with a domain trust and Foreign Security Principals.

See the update below!

groupName = The sAMAccountName of the group you want to check the members of.
SearchDomain = This is the FQDN that you will be searching for the group. Ex: contoso.com
userName = This is the sAMAccountName of the user that you are checking if they are part of the group.
userDomain = This is the NetBIOS name of the domain of the user that you are checking. This really only comes into play when you are checking a user from a domain trust. Ex. CONTOSO
UserIsNativeDomain = This is true if the user you are checking is in the SearchDomain. If this is false, the user is in a domain trust and the code should be looking for the Foreign Security Principal and matching it to the userDomain and userName.

static bool CheckIfGroupMember(string groupName, string SearchDomain, string userName, string userDomain, bool UserIsNativeDomain)

        {

            bool GroupMember = false;                         

            string UserDN = string.Empty;           

            string FullLogonName = userDomain + "\\" + userName;

 

           if (UserIsNativeDomain == true)               

            {

                try //Get User's distinguishedName

                {                    

                    System.DirectoryServices.DirectoryEntry entry2 = new System.DirectoryServices.DirectoryEntry("LDAP://" + SearchDomain);

                    System.DirectoryServices.DirectorySearcher mySearcher2 = new System.DirectoryServices.DirectorySearcher(entry2);

                    mySearcher2.Filter = "(&(objectCategory=person)(ObjectClass=user)(sAMAccountName=" + userName + "))";

                    mySearcher2.PageSize = 1000;

                    System.DirectoryServices.SearchResult sr2 = mySearcher2.FindOne();

                    if (sr2 != null)

                    {

                        System.DirectoryServices.DirectoryEntry de2 = sr2.GetDirectoryEntry();

                        UserDN = de2.Properties["distinguishedName"].Value.ToString();

                        de2.Close();

                    }

                }

                catch (DirectoryServicesCOMException e2) { Console.Write(e2.Message); }

            }

 

            try //Check Group Membership

            {

                System.DirectoryServices.DirectoryEntry entry = new System.DirectoryServices.DirectoryEntry("LDAP://" + SearchDomain);

                System.DirectoryServices.DirectorySearcher mySearcher = new System.DirectoryServices.DirectorySearcher(entry);

                mySearcher.Filter = "(&(objectCategory=group)(sAMAccountName=" + groupName + "))";

                mySearcher.PageSize = 1000;

                System.DirectoryServices.SearchResult sr = mySearcher.FindOne();

                System.DirectoryServices.DirectoryEntry de = sr.GetDirectoryEntry();

 

                object[] members = (object[])de.Properties["member"].Value;

                foreach (object member in members)

                {

                    if (UserIsNativeDomain == false &&

                        member.ToString().Contains("CN=S-1-5"))   //If group member is a Foreign Security Principal

                    {

                        if (GetUserNameOfFSP(member.ToString()).ToLower() == FullLogonName.ToLower())

                        {

                            GroupMember = true;

                            break;

                        }

 

                    }

                    else

                    {

                        if (member.ToString().ToLower() == UserDN)

                        {

                            GroupMember = true;

                            break;

                        }

                    }

                }

                de.Close();

                return GroupMember;

            }

            catch (DirectoryServicesCOMException e) { Console.Write(e.Message); }

            return GroupMember;

        }

UPDATE 5/19/14: While working on an Active Directory Migration project using ADMT I found an issue with the code above. If you’re migrating a user from the source domain who is a member in a group in the target domain already it uses a Foreign Security Principal. Well after the ADMT migrates the user to the target domain, the user still shows as a Foreign Security Principal in the target domains group but with an updated domain name in the ForeignSecurityPrincipal OU. This new code will resolve that issue and handle it as necessary.

groupName = The sAMAccountName of the group you want to check the members of.

groupDomain = This is the FQDN that you will be searching for the group. Ex: contoso.com

userName = This is the sAMAccountName of the user that you are checking if they are part of the group.

userDomain = This is the NetBIOS name of the domain of the user that you are checking. Ex. CONTOSO

static bool CheckIfGroupMember(string groupName, string groupDomain, string userName, string userDomain)

{          

    bool GroupMember = false;

    string UserDN = string.Empty;

    string FullLogonName = userDomain + "\\" + userName;

 

    try //Get User's distinguishedName

    {

        DirectoryEntry entry2 = new DirectoryEntry("LDAP://" + userDomain);

        DirectorySearcher mySearcher2 = new DirectorySearcher(entry2);

        mySearcher2.Filter = "(&(objectCategory=person)(ObjectClass=user)(sAMAccountName=" + userName + "))";

        mySearcher2.PageSize = 1000;

        SearchResult sr2 = mySearcher2.FindOne();

        if (sr2 != null)

        {

            DirectoryEntry de2 = sr2.GetDirectoryEntry();

            UserDN = de2.Properties["distinguishedName"].Value.ToString();

            de2.Close();

        }

        entry2.Close();

    }

    catch (DirectoryServicesCOMException e2) { Console.Write(e2.Message); }

  

 

    try //Check Group Membership

    {

        DirectoryEntry entry = new DirectoryEntry("LDAP://" + groupDomain);

        DirectorySearcher mySearcher = new DirectorySearcher(entry);

        mySearcher.Filter = "(&(objectCategory=group)(sAMAccountName=" + groupName + "))";

        mySearcher.PageSize = 1000;

        SearchResult sr = mySearcher.FindOne();

        DirectoryEntry de = sr.GetDirectoryEntry();

 

        object[] members = (object[])de.Properties["member"].Value;

        foreach (object member in members)

        {

            if (member.ToString().Contains("CN=S-1-5"))

            {

                string FSPName = GetUserNameOfFSP(member.ToString().ToLower());

                if (FSPName.ToLower() == FullLogonName.ToLower())

                {

                    GroupMember = true;

                    break;

                }

            }

            else

            {

                if (member.ToString().ToLower() == UserDN.ToLower())

                {

                    GroupMember = true;

                    break;

                }

            }                

        }             

    }

    catch (DirectoryServicesCOMException e) { Console.Write(e.Message); }

 

    return GroupMember;

}

4 Comments

  • Alex says:

    Hi Brandon,

    I found this blog post really useful, so thank you – it took me a while to realise that FSPs do not have a memberOf attribute and I had been doing my searches with a filter like “(&(objectCategory=user)(memberOf=))”

    One thing I’d like to ask is what your implementation of GetUserNameOfFSP() looks like. How do you match the SID in the FSP to actual sAMAccountNames in the domain?

    Thanks,
    Alex

    • Brandon says:

      Hi Alex, hope this helps.

      static string GetUserNameOfFSP(string ForeignSecurityPrincipal)
      {
      //Returns with syntax of "DOMAIN\logonname"
      try
      {
      DirectoryEntry user = new DirectoryEntry("LDAP://" + ForeignSecurityPrincipal);
      SecurityIdentifier sid = new SecurityIdentifier((byte[])user.InvokeGet("objectSid"), 0);
      NTAccount account = (NTAccount)sid.Translate(typeof(NTAccount));
      user.Close();
      return account.ToString();
      }
      catch (DirectoryServicesCOMException e) { Console.Write(e.Message); return "Error"; }
      }

      • Alex says:

        Thanks, Brandon. It’s that sid.Translate() method I was looking for. Unfortunately, I’m not sure the Python module I’m using (python-ldap) actually supports that at the moment.

        Is there any way other of performing the same mapping/lookup, from sid to account?

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>