tl;博士
在我们的例子中,这开始随机发生。原来是因为我们的自签名 SSL 证书已经过期。在 IIS 中新建一个后,问题就解决了。
解释
这个线程引导我找到原因。
我将简要回顾一下SetPassword
这里的作用,以便您了解为什么需要它。该特定的 ADSI 方法实际上包含了 3 种方法。它首先尝试使用 LDAP 通过安全 SSL 通道设置密码。接下来,它尝试使用 Kerberos 设置密码协议进行设置。最后,它NetUserSetInfo
用来尝试设置它。
主要问题是只有前两种方法通常会尊重您放在DirectoryEntry
. 例如,如果您提供正确的凭据和 SSL 通道,LDAP 更改密码机制将使用这些凭据...
如果您检查 NetUserSetInfo 方法,您会注意到没有地方放置用户名/密码以进行授权。换句话说,它只能使用非托管线程的安全上下文。这意味着为了让它工作,它必须首先模拟您以编程方式提供的用户名/密码组合......
LDAP over SSL 显然是最好的方法(也是我们一直在使用的方法),并且似乎(欢迎澄清)一旦我们的自签名 SSL 证书过期,它会跳过 Kerberos 并退回到NetUserSetInfo
,但失败了因为它没有使用我们提供的凭据。(或者它只是在 Kerberos 上失败了,因为发布者说他从未见过为 Kerberos 传递的凭据)
所以在创建新的自签名证书(for COMPUTER.DOMAIN.local
)后,问题就解决了。
这是代码(以防有人在寻找它):
DirectoryEntry myDE = new DirectoryEntry(@"LDAP://OU=GroupName,DC=DOMAIN,DC=local");
myDE.Username = "administrator";
myDE.Password = "adminPassword";
DirectoryEntries myEntries = myDE.Children;
DirectoryEntry myDEUser = myEntries.Find("CN=UserName");
myDEUser.Invoke("SetPassword", new object[] { "NewPassword" });
myDEUser.Properties["LockOutTime"].Value = 0;
// the following 2 lines are free =)
myDEUser.Properties["userAccountControl"].Value = (int)myDEUser.Properties["userAccountControl"].Value | 0x10000; // don't expire password
myDEUser.Properties["userAccountControl"].Value = (int)myDEUser.Properties["userAccountControl"].Value & ~0x0002; // ensure account is enabled
myDEUser.CommitChanges();