DirectoryServices用户主体.SetPassword忽略密码策略(密码历史记录)

4
如标题所示,我在设置用户密码时遇到了关于密码策略的问题,特别是密码历史记录限制。
场景是用户忘记当前密码时进行密码重置。我使用以下方式来完成这个过程:
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, "XXXX", "ADMINUSER", "ADMINPASSWORD")) {
    using (UserPrincipal user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username)) {
        user.SetPassword(password);
    }
}

这违反了除了密码历史记录限制以外的所有策略。
现在来看一个场景,当用户想要更改他们的密码并且知道他们的当前密码,我正在使用的是:
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, "XXXX.XXX.com")) {
    using (UserPrincipal user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username)) {
        user.ChangePassword(currentPassword, newPassword);
    }
}

...这个功能运作正常,并符合所有密码策略限制。

有没有人遇到过这种情况?

谢谢 :)

3个回答

6

据我使用的经验,这是有意设计的。SetPassword的作用是像管理员一样重置用户密码-复杂性策略保持不变,但是历史记录没有限制。假设管理员重置您的密码,看到“无法设置相同的密码”-您的某个密码已被泄露。

我们的解决方法是允许管理只通过我们的一个Web子系统,并持久化哈希历史记录,这样验证历史记录的责任就落在了自定义子系统而非广告上。


我非常确定这是设计上的问题,如果没有其他的绕过方法,那么这就是我的计划解决方案。谢谢快速提供的见解 :) - nokturnal
好奇。我正在处理一些.NET代码,用于创建新的域用户,并使用UserPrincipal.SetPassword()设置他们的密码。当密码不符合域的密码复杂性要求时,调用UserPrincipal.Save()会抛出一个System.Runtime.InteropServices.COMException异常,其中包含一个消息,指出“密码不符合密码策略要求。请检查最小密码长度、密码复杂度和密码历史记录要求。(HRESULT 异常: 0x800708C5)”。疯狂的是,账户仍然被创建了! - STLDev
@wiktor-zychla 我也遇到了同样的问题。然而,关于这个行为是否有官方文档?我只是想检查一下这是否在任何 Microsoft 的文档中提到过?先谢谢了! - Pranay
1
@Pranay:这篇文章明确了一些内容 https://blogs.technet.microsoft.com/fieldcoding/2013/01/09/resetting-passwords-honoring-password-history-or-whats-happening-under-the-hood-when-changing-resetting-passwords/ - Wiktor Zychla
感谢@Wiktor。在您提供的链接中,有一点说可以使用LDAP API应用历史检查。这是否适用于当前软件版本,因为该帖子似乎已经过时了。我只是在寻找.NET框架4.0+中尊重历史检查的密码重置功能的解决方案。再次感谢! - Pranay
@Pranay:虽然我已经有一段时间没有检查过它了,但如果我是你,我肯定会尝试博客文章提供的代码。 - Wiktor Zychla

2

我知道这是一个旧帖子,但我们从未找到一个可接受的答案。我们的系统人员不喜欢为历史记录存储我们自己的哈希值的想法。最终我们采用了以下解决方案:

using (PrincipalContext context = new PrincipalContext(ContextType.Domain, 
        "XXXX","ADMINUSER", "ADMINPASSWORD"))
{
    using (UserPrincipal user = 
        UserPrincipal.FindByIdentity(context,IdentityType.SamAccountName, username)) 
    {
        string tempPassword = Guid.NewGuid().ToString();
        user.SetPassword(tempPassword);
        user.ChangePassword(tempPassword, password);
    }
}

我们将用户的密码重置为一个随机且足够长和复杂的密码,我们的代码知道这个密码。然后,我们使用该密码作为旧密码,在更改过程中使用用户输入的新密码。如果该过程失败,包括密码历史记录在内的策略检查,我们将该错误返回给最终用户,他们必须再试一次。

0
如果通过 FindByIdentify 没有找到用户名,您可能会想先检查它是否为 null!
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "XXXX.XXX.com")) {
    using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, username))
    {
        if (user != null)
        {
            user.ChangePassword(currentPassword, newPassword);
        }
        else
        {
            throw new Exception(string.Format("Username not found: {0}", username));
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接