【问题标题】:Is there a way to make UserPrincipal.GetGroups() and UserPrincipal.GetAuthorizationGroups() calls use LDAPS (port 636) instead of LDAP (port 389)?有没有办法让 UserPrincipal.GetGroups() 和 UserPrincipal.GetAuthorizationGroups() 调用使用 LDAPS(端口 636)而不是 LDAP(端口 389)?
【发布时间】:2020-02-12 16:27:09
【问题描述】:

我们正在为 Microsoft 的 3 月 AD 更新做准备,只允许使用 LDAPS 进行安全调用,在检查我们的 .Net 代码时,我发现对 UserPrincipal.GetGroups() 和 UserPrincipal.GetAuthorizationGroups() 的调用似乎使用 LDAP(端口 389 ) 而不是 LDAPS(端口 636),即使 UserPrincipal 对象是使用通过 LDAPS 建立的 PrincipalContext 创建的,如下所示:

    // Explicitly using LDAPS (port 636)
    PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, "our.corpdomain.com:636", "DC=our,DC=corpdomain,DC=com", ContextOptions.Negotiate);
    UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(principalContext, "someuser");

    // These calls still use LDAP (port 389)
    var groups = userPrincipal.GetAuthorizationGroups();
    var groups2 = userPrincipal.GetGroups();

有谁知道为什么会发生这种情况,如果是,如何强制这些调用使用 LDAPS?如果不能强制,有什么变通办法吗?

【问题讨论】:

    标签: .net active-directory ldap active-directory-group


    【解决方案1】:

    这肯定是 .NET 代码中的一个错误,我会回答您的问题,但就像我在您的另一个问题中提到的那样,3 月更新将不会“仅允许使用 LDAPS 进行安全调用”。更新后,正常的 LDAP 端口 389 仍然可以使用。我没有看到任何证据表明他们计划禁用它。

    但是如果你想确保它永远不会使用端口 389,你将没有不使用UserPrincipal。直接使用DirectoryEntry 和/或DirectorySearcher,这是UserPrincipal 在后台使用的。这不是 AccountManagement 命名空间中的 the first bug I've found

    我写了一篇关于finding all of a user's groups的文章,里面有一些针对不同场景的示例代码。您必须修改创建新 DirectoryEntry 对象并指定端口 636 的任何情况,如下所示:

    new DirectoryEntry("LDAP://example.com:636/CN=whatever,DC=example,DC=com")
    

    如果您愿意,您实际上可以省略域名(只需 :636 而不是 example.com:636)。

    我在那篇文章中没有涉及的一个案例相当于GetAuthorizationGroups,即读取tokenGroups 属性。这将为您提供组的 SID 列表,然后您可以查找该列表以查找组的名称。这是一个可以做到这一点的方法:

    private static IEnumerable<string> GetTokenGroups(DirectoryEntry de) {
        var groupsFound = 0;
    
        //retrieve only the tokenGroups attribute from the user
        de.RefreshCache(new[] {"tokenGroups"});
    
        while (true) {
            var tokenGroups = de.Properties["tokenGroups"];
            foreach (byte[] groupSidByte in tokenGroups) {
                groupsFound++;
                var groupSid = new SecurityIdentifier(groupSidByte, 0);
                var groupDe = new DirectoryEntry($"LDAP://:{de.Options.PasswordPort}/<SID={groupSid}>");
    
                groupDe.RefreshCache(new[] {"cn"});
                yield return (string) groupDe.Properties["cn"].Value;
            }
    
            //AD only gives us 1000 or 1500 at a time (depending on the server version)
            //so if we've hit that, go see if there are more
            if (tokenGroups.Count != 1500 && tokenGroups.Count != 1000) break;
    
            try {
                de.RefreshCache(new[] {$"memberOf;range={groupsFound}-*"});
            } catch (COMException e) {
                if (e.ErrorCode == unchecked((int) 0x80072020)) break; //no more results
    
                throw;
            }
        }
    }
    

    这将使用您用于创建您传入的DirectoryEntry 对象的任何端口。但是,如果您的环境中有多个域,这将中断。如果您想始终使用端口 636,在这种情况下事情会变得复杂。

    【讨论】:

    • 谢谢,加布里埃尔!我尝试了代码,但它没有找到与 GetAuthorizationGroups 一样多的组。试图找到一个共同的线索。额外的组都是本地的内置组(每个人、管理员、性能日志用户、经过身份验证的用户、本组织、安全声明身份和高强制级别)。我读了你的文章,我没有注意到任何可能是罪魁祸首的东西。我们有一个域,没有受信任的外部域。有什么想法吗?
    • 我给的代码只会返回AD组。你提到的那些组不是AD组。他们要么是well-known SIDs(如Everyone),要么是本地团体。每个存在的帐户都将被视为Everyone 的一部分。本地组将根据您运行此代码的计算机而变化。那是你真正需要的东西吗?
    • 如果你想为当前用户(代码运行的用户)做这个,你可以调用WindowsIdentity.GetCurrent()并查看Groups属性。
    • 奇怪的是,您的代码返回的“用户”似乎是众所周知的 SID (S-1-5-32-545)。实际上,如果您查看此MS link,它会将其中的每一个都列为组、别名、帐户或内置组。运行whoami /groups 显示相同的内容。我不认为我们需要这些团体,但我不能确定。我正在排除故障的代码是由其他人构建的,我只是对它或 AD 了解不够。
    • 不幸的是,我正在排除故障的那段代码不使用当前用户,所以我不能使用WindowsIdentity.GetCurrent()。顺便说一句,我喜欢你的文章。他们信息量很大!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 2013-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多