为什么 Active Directory 验证最后一个密码?
我正在研究一个简单的解决方案来更新 Active Directory 中的用户密码。
我可以成功更新用户密码。更新密码效果很好。假设用户已将密码从 MyPass1 更新为 MyPass2
现在,当我运行自定义代码来验证用户凭据时,使用:
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "TheDomain"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "MyPass2");
}
//returns true - which is good
现在,当我输入一些错误的密码时,它会很好地验证:
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "TheDomain"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "wrongPass");
}
//returns false - which is good
现在由于一些奇怪的原因,它会验证之前的最后一个密码,即 MyPass1,还记得吗?
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "TheDomain"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "MyPass1");
}
//returns true - but why? we have updated password to Mypass2
我从以下位置获取此代码:
这与上次密码过期有关还是验证应该如何工作?
I am working on a simple solution to update a user's password in Active Directory.
I can successfully update the users password. Updating the password works fine. Lets say the user has updated the password from MyPass1 to MyPass2
Now when I run my custom code to validate users credential using:
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "TheDomain"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "MyPass2");
}
//returns true - which is good
Now when I enter some wrong password it validates very nicely:
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "TheDomain"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "wrongPass");
}
//returns false - which is good
Now for some odd reasons, it validates the previous last password which was MyPass1 remember?
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "TheDomain"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "MyPass1");
}
//returns true - but why? we have updated password to Mypass2
I got this code from:
Validate a username and password against Active Directory?
Is it something to do with last password expiry or is this how the validation supposed to work?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您看到此情况的原因与特定于 NTLM 网络身份验证的特殊行为有关。
在
PrincipalContext
实例上调用ValidateCredentials
方法会导致建立安全 LDAP 连接,然后使用ldap_bind_s
函数调用。调用
ValidateCredentials
时使用的身份验证方法是AuthType.Negotiate
。使用此结果会导致尝试使用 Kerberos 进行绑定操作,这(当然不是 NTLM)不会表现出上述特殊行为。但是,使用 Kerberos 的绑定尝试将失败(密码全部错误),这将导致进行另一次尝试,这次使用 NTLM。您有两种方法可以解决此问题:
PrincipleContext
类来验证凭据。既然您(大致)了解了ValidateCredentials
的工作原理,那么手动执行该过程应该不会太困难。您需要做的是创建一个新的 LDAP 连接 (LdapConnection
),设置其网络凭据,将 AuthType 显式设置为AuthType.Kerberos
,然后调用绑定()
。如果凭据错误,您将得到一个例外。以下代码显示如何仅使用 Kerberos 执行凭据验证。如果发生失败,所使用的身份验证方法不会回退到 NTLM。
我尽量不使用异常来处理代码的流程控制;但是,在此特定实例中,测试 LDAP 连接上的凭据的唯一方法似乎是尝试绑定操作,如果凭据错误,该操作将引发异常。
PrincipalContext
采用相同的方法。The reason why you are seeing this has to do with special behavior specific to NTLM network authentication.
Calling the
ValidateCredentials
method on aPrincipalContext
instance results in a secure LDAP connection being made, followed by a bind operation being performed on that connection using aldap_bind_s
function call.The authentication method used when calling
ValidateCredentials
isAuthType.Negotiate
. Using this results in the bind operation being attempted using Kerberos, which (being not NTLM of course) will not exhibit the special behavior described above. However, the bind attempt using Kerberos will fail (the password being wrong and all), which will result in another attempt being made, this time using NTLM.You have two ways to approach this:
PrincipleContext
class to validate credentials. Now that you know (roughly) howValidateCredentials
works, it shouldn't be too difficult for you to do the process manually. What you'll want to do is create a new LDAP connection (LdapConnection
), set its network credentials, set the AuthType explicitly toAuthType.Kerberos
, and then callBind()
. You'll get an exception if the credentials are bad.The following code shows how you can perform credential validation using only Kerberos. The authentication method at use will not fall back to NTLM in the event of failure.
I try to never use exceptions to handle the flow control of my code; however, in this particular instance, the only way to test credentials on a LDAP connection seems to be to attempt a Bind operation, which will throw an exception if the credentials are bad.
PrincipalContext
takes the same approach.我找到了一种仅验证用户当前凭据的方法。它利用了
ChangePassword
不使用缓存凭据的事实。通过尝试将密码更改为其当前值,这首先会验证密码,我们可以确定密码是否不正确或存在策略问题(不能重复使用同一密码两次)。注意:这可能仅在您的策略具有至少不允许重复最近密码的历史记录要求时才有效。
I've found a way to validate the user's current credentials only. It leverages the fact that
ChangePassword
does not use cached credentials. By attempting to change the password to its current value, which first validates the password, we can determine if the password is incorrect or there is a policy problem (can't reuse the same password twice).Note: this will probably only work if your policy has a history requirement of at least not allowing to repeat the most recent password.
根据您运行此程序的上下文,它可能与名为“缓存凭据”的内容有关”。
Depending on the context of how you run this, it may have to do with something called "cached credentials."