C. Chen
C. Chen

Reputation: 123

LDAP - Use of wildcard on MemberOf filter

I need to get all users and their groups from a specific category.

Examples of users :

user  | memberof
user1 | CN=group_1,OU=Groupes,OU=CR 1,DC=zcam,DC=ztech
user1 | CN=group_2,OU=Groupes,OU=CR 1,DC=zcam,DC=ztech
user2 | CN=group_2,OU=Groupes,OU=CR 1,DC=zcam,DC=ztech
user3 | CN=group_3,OU=Groupes,OU=CR 2,DC=zcam,DC=ztech

I need to get every user where memberof contains OU=Groupes,OU=CR 1,DC=zcam,DC=ztech (user1 and user2 from my example)

Following this doc (https://learn.microsoft.com/fr-fr/windows/desktop/ADSI/search-filter-syntax) I tried the following syntaxes :

DirectoryEntry ldap = new DirectoryEntry("LDAP://xxx.xxx.xxx.xxx");
using (DirectorySearcher searcher = new DirectorySearcher(ldap))
{
    // Works but return everything
    searcher.Filter = "(&(objectClass=user)(memberof=*))";

    // Works but only for one group
    searcher.Filter = "(&(objectClass=user)(memberof=CN=group_1,OU=Groupes,OU=CR 1,DC=zcam,DC=ztechh))";

    // Doesn't work because searcher.FindAll().Count returns 0
    searcher.Filter = "(&(objectClass=user)(memberof=*,OU=Groupes,OU=CR 1,DC=zcam,DC=ztechh))";

    // searcher.FindAll().Count returns 0
    foreach (SearchResult result in searcher.FindAll()) 
    {
        [...]
    }

Following this (https://community.servicenow.com/community?id=community_question&sys_id=00d29fa1db101fc01dcaf3231f96197f) I tried to change the wildcard * by a % but it didn't changed the result.

Upvotes: 0

Views: 6907

Answers (3)

C. Chen
C. Chen

Reputation: 123

Finally I have found another way to do. In fact, this property OU=CR 1 in the memberof correspond to the division in my AD. So I just filter like this :

DirectoryEntry ldap = new DirectoryEntry("LDAP://xxx.xxx.xxx.xxx");
using (DirectorySearcher searcher = new DirectorySearcher(ldap))
{
    searcher.Filter = "(&(objectClass=user)(division=CR 1))";

    foreach (SearchResult result in searcher.FindAll()) 
    {
        [...]
    }

Thanks everyone for your help.

Upvotes: 0

Gabriel Luci
Gabriel Luci

Reputation: 40928

I need to get every user where memberof contains OU=Groupes,OU=CR 1,DC=zcam,DC=ztech (user1 and user2 from my example)

If I understand correctly, I think that sentence sums up what you're trying to do. You want to find all users who are a member of any group in that OU.

Active Directory doesn't let you use wildcards on any attribute that takes a distinguishedName. That includes member and memberOf. So the only way to do this is in two steps:

  1. Find the distinguishedName of all groups in that OU.
  2. Search for all users whose memberOf includes one of the values found in step 1.

Something like this (I haven't tested this against AD, so you might need to tweak it):

var groupSearch = new DirectorySearcher(
    new DirectoryEntry("LDAP://OU=Groupes,OU=CR 1,DC=zcam,DC=ztech"), //notice the OU
    "(objectClass=group)");

//if you don't do this, it will return *every* attribute, which is slower
groupSearch.PropertiesToLoad.Add("distinguishedName");

//build a user query with all the groups
var userFilter = new StringBuilder("(&(objectClass=user)(|");
using (var results = groupSearch.FindAll()) {
    foreach (SearchResult result in results) {
        userFilter.Append($"(memberOf={result.Properties["distinguishedName"][0]})");
    }
}
userFilter.Append(")");

var userSearch = new DirectorySearcher(
    new DirectoryEntry("LDAP://DC=zcam,DC=ztech"),
    userFilter.ToString());

//userSearch.PropertiesToLoad.Add(""); //add only the attributes you need to make it quicker

using (var results = userSearch.FindAll()) {
    foreach (SearchResult result in results) {
        //do something
    }
}

Note that this will only find direct members of those groups. It won't return users that are in nested groups (when a user is in a group that is a member of one of these groups). If you want that, you can adjust the filter to include a special flag that tells AD to search recursively:

userFilter.Append($"(memberOf:1.2.840.113556.1.4.1941:={result.Properties["distinguishedName"][0]})");

Depending on your domain, you might want to be aware of two things:

  1. This will not return users who have one of these groups as their primary group, since that relationship is not stored using member/memberOf.
  2. If these groups have members from external trusted domains, then you'll end up finding Foreign Security Principal objects, instead of their actual user objects. That's a whole other thing to deal with, if it's an issue for you.

I've written a few articles on the subject, if you're curious. Start with this one: Active Directory: What makes a member a member?

Upvotes: 2

edited version; extend for all your group_X

(
&(objectClass=user)
(|(memberof=CN=group_1,OU=Groupes,OU=CR 1,DC=zcam,DC=ztechh)
(memberof=CN=group_2,OU=Groupes,OU=CR 1,DC=zcam,DC=ztechh))
)

Upvotes: 1

Related Questions