C# 如何检查用户是否是ldap中跨域组的成员?

C# 如何检查用户是否是ldap中跨域组的成员?,c#,active-directory,ldap,C#,Active Directory,Ldap,我有两个广告域名:域名1和域名2。 我在domain1中创建了组GlobalGroup,并在GlobalGroup中添加了另一个组Domain1Group 我有两个用户:user1 imk user2和domain2中的groupdomain2group。 域1和域2之间设置了双向信任。我在GlobalGroup中添加了Domain2Group。 User1是Domain1Group的成员,user2是Domain2Group的成员。 所以现在我需要检查他们是否都是GlobalGroup的成员。

我有两个广告域名:域名1和域名2。
我在domain1中创建了组GlobalGroup,并在GlobalGroup中添加了另一个组Domain1Group
我有两个用户:user1 imk user2和domain2中的groupdomain2group。
域1和域2之间设置了双向信任。我在GlobalGroup中添加了Domain2Group。
User1是Domain1Group的成员,user2是Domain2Group的成员。
所以现在我需要检查他们是否都是GlobalGroup的成员。

我找到了如何查找用户是否是来自另一个域的某个组的成员。 我的函数(如下)非常适合user1。对于user2,它返回false。

GroupPrincipal.GetMemebers(true)将返回user2,但它非常慢(prod上的分钟数),我无法使用它。

我错过了什么?它是在代码中还是在域的设置中?

代码示例:

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

我是你找到的那篇文章的作者。:)

您的父组的范围是什么?您称之为
GlobalGroup
,但全局组不能有来自其他域的成员。因此,它必须是通用的(如果两个域位于同一个AD林中)或域本地的。在每种情况下,答案都是不同的

我将假设这两个域不在同一个林中,并且组是域本地的

当外部用户是组的直接成员时,代码将仅返回true

如果使用该代码检查
Domain2Group
是否是
GlobalGroup
的成员,它将返回
true
。但是,当您使用它检查
user2
是否是成员时,它不会查看
Domain2Group
中的用户是否在那里

这是我应该解决的问题,因此我在文章中更新了代码。我们可以使用用户的
tokenGroups
属性来获取用户所在的所有组的递归列表。这给了我们一份小岛屿发展中国家的名单。因此,我们可以使用它在另一个域的父组中查找这些组中的任何一个

我看到您的
user
对象是
UserPrincipal
。要将其传递到此方法中,您可以使用,如下所示:

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

哇!我没想到你会回答。非常感谢!我是Active Directory新手,不知道“令牌组”,所以我特别感谢您的解释。“tokenGroups”是否总是返回完整的SID列表?这里可能有一些隐藏的问题吗?
tokenGroups
用于权限。因此,它拥有用户应该从中获得权限的所有组。它包含用户所属的所有组,以及这些组所属的任何组等。唯一的技巧是它不会显示通讯组列表(其中“组类型”是“通讯组”)。它将只显示安全组。如果您有一些通讯组,您可以使用而不是
令牌组
,因为它将包括通讯组。但这可能只在您使用Exchange时存在,我不确定。是的,我想我更喜欢使用
tokenGroupsGlobalAndUniversal
。我更新了它。我还意识到它应该只在
recursive
true
时使用,所以我也解决了这个问题。