Проверьте, является ли группа AD членом другой группы (рекурсивно) - PullRequest
1 голос
/ 19 июня 2019

Представьте, что у меня есть структура

RootGroup <- Group{x} .... <- Group{x+n} <- Group100 

Как я могу проверить, что Group100 является членом RootGroup

У меня есть это, и оно всегда возвращает false

private bool IsMemberOfInternal(string userOrGroupDistinguishedName, string groupMembershipDistinguishedName)
        {
            GroupPrincipal principal = null;
            GroupPrincipal target = null;
            try
            {
                principal = _getUserGroupPrincipalFunc(principalContext, userOrGroupDistinguishedName);
                target = _getUserGroupPrincipalFunc(principalContext, groupMembershipDistinguishedName);

                if (principal != default(GroupPrincipal)
                    && target != default(GroupPrincipal))
                {
                    return principal.IsMemberOf(target);
                }
            }
            catch
            {
            }

            return false;
        }

1 Ответ

1 голос
/ 19 июня 2019

Вам лучше не использовать GroupPrincipal для этого.В AD действительно есть встроенный способ выполнять такой поиск, который намного быстрее, чем любая вещь, которую GroupPrincipal может сделать.Вы можете использовать это, используя DirectoryEntry и DirectorySearcher напрямую (это то, что GroupPrincipal и PrincipalSearcher используют в любом случае за кулисами).

Я написал статью о выяснении, если пользователь является членом определенной группы, но это относится и к группам.У меня есть пример метода , который вы можете использовать для этого:

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

Этот метод также обрабатывает случай, когда user (или ваша дочерняя группа) находится на внешнем доверенномдомен из корневой группы.Это может или не может быть проблемой, о которой вам нужно беспокоиться.

Просто передайте DirectoryEntry для вашего Group100 в качестве параметра user.Примерно так:

var isMemberOf = IsUserInGroup(
    new DirectoryEntry($"LDAP://{userOrGroupDistinguishedName}"),
    new DirectoryEntry($"LDAP://{groupMembershipDistinguishedName}"),
    true);

Для рекурсивных поисков (когда вы передаете true для параметра recursive), он использует LDAP_MATCHING_RULE_IN_CHAIN "OID правила соответствия" (как объяснено здесь *)1029 *):

Это правило ограничено фильтрами, которые применяются к DN.Это специальный «расширенный» оператор сопоставления, который проходит цепочку предков в объектах вплоть до корня, пока не найдет совпадение.

...