Как проверить, входит ли пользователь в междоменную группу в ldap? - PullRequest
0 голосов
/ 22 января 2019

У меня два домена AD: домен1 и домен2.
Я создал группу GlobalGroup внутри domain1 и добавил еще одну группу Domain1Group внутри GlobalGroup.
У меня есть два пользователя: user1 и user2 и группа Domain2Group в domain2.
Между доменом 1 и доменом 2 было установлено двустороннее доверие. И я добавил Domain2Group в GlobalGroup.
Пользователь1 является членом Domain1Group, а пользователь2 является членом Domain2Group.
Поэтому теперь мне нужно проверить, являются ли они оба членами GlobalGroup.

Здесь Я нашел, как узнать, является ли пользователь членом какой-либо группы из другого домена. Моя функция (ниже) отлично работает для user1. Для user2 возвращается false.

GroupPrincipal.GetMemebers (true) вернет user2, но он очень медленный (минуты на продукт), и я не могу его использовать.

Что я пропустил? Это в коде или в настройках домена?

Пример кода:

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

1 Ответ

0 голосов
/ 23 января 2019

Я автор той статьи, которую вы нашли.:)

Каков охват вашей родительской группы?Вы называете это GlobalGroup, но у глобальных групп не может быть участников из других доменов.Таким образом, он должен быть универсальным (если два домена находятся в одном лесу AD) или локальным.Ответ будет отличаться в каждом случае.

Я предполагаю, что два домена не находятся в одном и том же лесу, а группа - Локальный домен.

Код вернет только значение true, если внешний пользовательявляется прямым членом группы.

Если вы используете этот код, чтобы проверить, является ли Domain2Group членом GlobalGroup, он вернет true.Но когда вы используете его, чтобы проверить, является ли user2 членом, он не заглядывает внутрь Domain2Group, чтобы увидеть, есть ли там пользователь.

Это то, к чему я должен обратиться, поэтому я обновил код вмоя статьяМы можем использовать атрибут tokenGroups пользователя, чтобы получить рекурсивный список всех групп, в которых он находится. Это дает нам список идентификаторов безопасности.Таким образом, мы можем использовать это для поиска любой из этих групп в нашей родительской группе в другом домене.

Я вижу, что у вас есть user объект как UserPrincipal.Чтобы передать его в этот метод, вы можете использовать user.GetUnderlyingObject(), например:

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

Вот обновленный метод:

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