为什么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
我从这里得到了这段代码:
根据Active Directory验证用户名和密码?
这与上一次密码过期有关吗?或者验证应该如何工作?
您看到这种情况的原因与特定于NTLM网络身份验证的特殊行为有关。
在PrincipalContext
实例上调用ValidateCredentials
方法会导致建立安全的LDAP连接,然后使用ldap_bind_s
函数调用在该连接上执行绑定操作。
调用ValidateCredentials
时使用的身份验证方法是AuthType.Negotiate
。 使用这个结果会导致正在尝试使用Kerberos的绑定操作,该Kerberos(当然不是NTLM)不会显示上述特殊行为。 但是,使用Kerberos的绑定尝试将失败(密码错误且全部),这将导致另一次尝试,这次使用NTLM。
你有两种方法来解决这个问题:
PrincipleContext
类来验证凭据。 既然您已经(大致)了解了ValidateCredentials
工作原理,那么您手动执行该过程应该不会太困难。 你需要做的是创建一个新的LDAP连接( LdapConnection
),设置其网络凭据,将AuthType显式设置为AuthType.Kerberos
,然后调用Bind()
。 如果证书不好,你会得到一个异常。 以下代码显示了如何仅使用Kerberos执行凭据验证。 发生故障时,正在使用的身份验证方法不会回退到NTLM。
private const int ERROR_LOGON_FAILURE = 0x31;
private bool ValidateCredentials(string username, string password, string domain)
{
NetworkCredential credentials
= new NetworkCredential(username, password, domain);
LdapDirectoryIdentifier id = new LdapDirectoryIdentifier(domain);
using (LdapConnection connection = new LdapConnection(id, credentials, AuthType.Kerberos))
{
connection.SessionOptions.Sealing = true;
connection.SessionOptions.Signing = true;
try
{
connection.Bind();
}
catch (LdapException lEx)
{
if (ERROR_LOGON_FAILURE == lEx.ErrorCode)
{
return false;
}
throw;
}
}
return true;
}
我尽量不使用异常来处理我的代码的流量控制; 但是,在这个特定的实例中,测试LDAP连接上凭据的唯一方法似乎是尝试绑定操作,如果证书不正确,将会引发异常。 PrincipalContext
采用相同的方法。
根据你如何运行它的上下文,它可能需要处理一些叫做“缓存凭据”的东西。
我找到了一种验证用户当前凭据的方法。 它利用了ChangePassword
不使用缓存凭据的事实。 通过尝试将密码更改为当前值(首先验证密码),我们可以确定密码是不正确的还是存在策略问题(无法重复使用相同的密码两次)。
请注意:如果您的保单的历史记录要求至少不允许重复最近的密码,则这可能只适用。
var isPasswordValid = PrincipalContext.ValidateCredentials(
userName,
password);
// use ChangePassword to test credentials as it doesn't use caching, unlike ValidateCredentials
if (isPasswordValid)
{
try
{
user.ChangePassword(password, password);
}
catch (PasswordException ex)
{
if (ex.InnerException != null && ex.InnerException.HResult == -2147024810)
{
// Password is wrong - must be using a cached password
isPasswordValid = false;
}
else
{
// Password policy problem - this is expected, as we can't change a password to itself for history reasons
}
}
catch (Exception)
{
// ignored, we only want to check wrong password. Other AD related exceptions should occure in ValidateCredentials
}
}
链接地址: http://www.djcxy.com/p/36073.html
上一篇: Why does Active Directory validate last password?
下一篇: Get local IP address