为什么在 DirectoryEntry 上调用 SetPassword 需要 60 秒才能成功?

Why does calling SetPassword on a DirectoryEntry takes 60 seconds to succeed?

我正在使用以下 C# 代码通过 DirectoryEntry 设置用户密码 class:

user.Invoke("SetPassword", password);

代码包含在 DLL 中。加载 DLL 并在 GMSA 下的服务 运行ning 中使用此代码需要 60 秒才能 return,但成功了。但是加载 DLL 并从命令行可执行文件使用此代码工作正常 - 即使我使用 psexec 到 运行 GMSA 下的命令行。

报告了一些类似的问题,我试图通过上述测试消除这些问题,例如accessing port 464, or the SetPassword function falling through different mechanisms.

为什么在 DirectoryEntry 上调用 SetPassword 需要 60 秒才能成功?或者,我可以进行哪些调试以确定发生这种情况的原因?

Remarks section of the SetPassword documentation 中,它列出了几种尝试设置密码的机制,因为您需要安全连接才能做到这一点。我猜第一个没有用,所以它必须尝试 2 个甚至三个。

用于创建 user 的 LDAP 字符串可以确定 SetPassword 必须 运行 多少圈才能找到可接受的安全方法。来自不同计算机的 运行 也会对哪些机制起作用产生影响,这取决于防火墙限制,或者其中一台计算机未加入同一域而另一台加入。

SetPassword 不是设置密码的唯一方法。您可以通过直接设置 unicodePwd 属性来实现,以 the documentation 描述的非常具体的方式。在 C# 中看起来像这样:

user.Properties["unicodePwd"].Value = Encoding.Unicode.GetBytes("\"NewPassword\"");
user.CommitChanges();

但是您必须确保以安全的方式进行连接。这不像 SetPassword 那样为您考虑周到。您可以使用 LDAPS(LDAP over SSL),这要求服务器使用受信任的证书(注意端口 636):

var user = new DirectoryEntry("LDAP://example.com:636/CN=SomePerson,OU=Users,DC=example,DC=com");

或者,如果您 运行 从中执行此操作的计算机已加入同一域或受信任的域,那么您可以使用 Kerberos,这是通过在构造函数中传递 AuthenticationTypes.Sealing 来完成的:

var user = new DirectoryEntry("LDAP://CN=SomePerson,OU=Users,DC=example,DC=com"
           , null, null, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);

这是一种明确告诉它如何安全连接的方法,而不是让 SetPassword 尝试不同的方法直到找到一个方法。这样可以节省时间。