简体   繁体   中英

How to check if user is a member of crossdomain group in ldap?

I have two AD domain: domain1 и domain2.
I created group GlobalGroup inside domain1, and added another group Domain1Group inside GlobalGroup.
I have two users: user1 и user2 and group Domain2Group in domain2.
Between domain1 and domain2 was set two-way trust. And I added Domain2Group in GlobalGroup.
User1 is a member of Domain1Group, and user2 is a member of Domain2Group.
So now I need to check if they both are members of GlobalGroup.

Here I found how to find if user is member of some group from another domain. My function (below) works perfectly for user1. For user2 it returns false.

GroupPrincipal.GetMemebers(true) will return user2, but it is very slow (minutes on prod) and I can't use it.

What did I miss? Is it in code or in domain's settings?

Code sample:

private static bool IsUserInGroup(UserPrincipal user, DirectoryEntry group, bool recursive)
        {
            group.RefreshCache(new[] {"distinguishedName", "groupType"});
            var recursiveFilter = recursive ? ":1.2.840.113556.1.4.1941:" : "";
            var filter = string.Format("(member{0}={1})", recursiveFilter, user.DistinguishedName);
            var groupDN = (string)group.Properties["distinguishedName"].Value;

            if (((int)group.Properties["groupType"].Value & 8) == 0)
            {
                var groupDomainDN = groupDN.Substring(groupDN.IndexOf(",DC=", StringComparison.Ordinal));
                filter = string.Format("(|{0}(member{1}=CN={2}, CN=ForeignSecurityPrincipals{3}))", filter, recursiveFilter, user.Sid, groupDomainDN);
            }

            var searcher = new DirectorySearcher
            {
                Filter = filter,
                SearchRoot = group,
                PageSize = 1,
                SearchScope = SearchScope.Base
            };

            searcher.PropertiesToLoad.Add("cn");
            return searcher.FindOne() != null;
        }

I'm the author of that article you found. :)

What is the scope of your parent group? You call it GlobalGroup , but Global groups cannot have members from other domains. So it must be either Universal (if the two domains are in the same AD forest) or Domain Local. The answer will be different in each case.

I will assume the two domains are not in the same forest and the group is Domain Local.

The code will only return true is the external user is a direct member of the group.

If you use that code to check if Domain2Group is a member of GlobalGroup , it would return true . But when you use it to check if user2 is a member, it's not looking inside Domain2Group to see if the user is there.

This is something I should address, so I have updated the code in my article. We can use the tokenGroups attribute of the user to get a recursive list of all groups the user is in. That gives us a list of SIDs. So we can use that to look for any of those groups in our parent group on the other domain.

I see you have your user object as a UserPrincipal . To pass it into this method, you can use user.GetUnderlyingObject() , like this:

IsUserInGroup((DirectoryEntry) user.GetUnderlyingObject(), group, true)

Here is the updated method:

private static bool IsUserInGroup(DirectoryEntry user, DirectoryEntry group, bool recursive) {

    //fetch the attributes we're going to need
    user.RefreshCache(new [] {"distinguishedName", "objectSid"});
    group.RefreshCache(new [] {"distinguishedName", "groupType"});

    //This magic number tells AD to look for the user recursively through any nested groups
    var recursiveFilter = recursive ? ":1.2.840.113556.1.4.1941:" : "";

    var userDn = (string) user.Properties["distinguishedName"].Value;
    var groupDn = (string) group.Properties["distinguishedName"].Value;

    var filter = $"(member{recursiveFilter}={userDn})";

    if (((int) group.Properties["groupType"].Value & 8) == 0) {
        var groupDomainDn = groupDn.Substring(
            groupDn.IndexOf(",DC=", StringComparison.Ordinal));
        var userDomainDn = userDn.Substring(
            userDn.IndexOf(",DC=", StringComparison.Ordinal));
        if (groupDomainDn != userDomainDn) {
            //It's a Domain Local group, and the user and group are on
            //different domains, so the account might show up as a Foreign
            //Security Principal. So construct a list of SID's that could
            //appear in the group for this user
            var fspFilters = new StringBuilder();

            var userSid =
                new SecurityIdentifier((byte[]) user.Properties["objectSid"].Value, 0);
            fspFilters.Append(
                $"(member{recursiveFilter}=CN={userSid},CN=ForeignSecurityPrincipals{groupDomainDn})");

            if (recursive) {
                //Any of the groups the user is in could show up as an FSP,
                //so we need to check for them all
                user.RefreshCache(new [] {"tokenGroupsGlobalAndUniversal"});
                var tokenGroups = user.Properties["tokenGroupsGlobalAndUniversal"];
                foreach (byte[] token in tokenGroups) {
                    var groupSid = new SecurityIdentifier(token, 0);
                    fspFilters.Append(
                        $"(member{recursiveFilter}=CN={groupSid},CN=ForeignSecurityPrincipals{groupDomainDn})");
                }
            }
            filter = $"(|{filter}{fspFilters})";
        }
    }

    var searcher = new DirectorySearcher {
        Filter = filter,
        SearchRoot = group,
        PageSize = 1, //we're only looking for one object
        SearchScope = SearchScope.Base
    };

    searcher.PropertiesToLoad.Add("cn"); //just so it doesn't load every property

    return searcher.FindOne() != null;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM