Windows AD 无法通过代码重置密码
Windows AD unable to reset password from code
从尝试重置 AD 用户密码并使用相同密码进一步从其他服务登录的代码。但是 AD 没有对用户进行身份验证。
在 AD 中,我们正在更新代码中的 userPassword
、holcimIsRegistered
和 userAccountControl
属性以重置密码。
当我们从 ADSI 手动重置 AD 用户密码时(右键单击用户 -> 转到重置密码→重置密码)然后 AD 正在使用新密码对用户进行身份验证。 userPassword
和 unicodePwd
属性都没有更新。
我们尝试从 ADSI 和代码中更新 unicodePwd
属性,但它不允许用户从我们观察到的代码中更新它的值
[LDAP: error code 53 - 0000001F: SvcErr: DSID-031A12D2, problem 5003 (WILL_NOT_PERFORM)]
我们比较了之前的用户详细信息并从 ADSI 重置密码,发现很少有详细信息正在获取
已更新(BadLogonCount:0
、badPasswordTime:0
、badPwdCount:0
、lastLogoff:0
、lastLogon:0
、logonCount:0
、Modified
、modifyTimeStamp
、 msDS-User-Account-Control-Computed
、PasswordExpired:false
、PasswordLastSet
、uSNChanged
和 whenChanged
).
当我们尝试从 ADSI 修改 usnChanged
时,msDS-User-Account-Control-Computed
然后观察到这两个属性无法从 ADSI 和它提供的代码中编辑 SchemaViolationException
。对于 passwordExpired
和 badLogonCount
属性,我们在从代码和 ADSI 修改它时面临 NoSuchAttributeException
这两个属性丢失。
我们还可以怎样做?
要重置密码,请更新 unicodePwd
属性。 The documentation 告诉您一些要求:
- 新密码必须采用特定格式:包含在double-quotes中然后转换为UTF-16编码,以及
- 连接必须加密。
This page 在 Java 中有一个如何执行此操作的示例,我已将其粘贴在下方。它没有讨论加密,但您可以使用 LDAP over SSL (LDAPS),您可以使用 LDAPS://
而不是仅 LDAP://
来实现。这假定 AD 服务器已正确设置 LDAPS,并且您没有阻止 LDAPS 端口 (636) 的防火墙。
/**
* Update User Password in Microsoft Active Directory
* @param username
* @param password
*/
public void updateUserPassword(String username, String password)
{
try
{
System.out.println("updating password...\n");
String quotedPassword = "\"" + password + "\"";
char unicodePwd[] = quotedPassword.toCharArray();
byte pwdArray[] = new byte[unicodePwd.length * 2];
for (int i = 0; i < unicodePwd.length; i++)
{
pwdArray[i * 2 + 1] = (byte) (unicodePwd[i] >>> 8);
pwdArray[i * 2 + 0] = (byte) (unicodePwd[i] & 0xff);
}
System.out.print("encoded password: ");
for (int i = 0; i < pwdArray.length; i++)
{
System.out.print(pwdArray[i] + " ");
}
System.out.println();
ModificationItem[] mods = new ModificationItem[1];
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("UnicodePwd", pwdArray));
ldapContext.modifyAttributes("cn=" + username + BASE_NAME, mods);
}
catch (Exception e)
{
System.out.println("update password error: " + e);
}
}
从尝试重置 AD 用户密码并使用相同密码进一步从其他服务登录的代码。但是 AD 没有对用户进行身份验证。
在 AD 中,我们正在更新代码中的 userPassword
、holcimIsRegistered
和 userAccountControl
属性以重置密码。
当我们从 ADSI 手动重置 AD 用户密码时(右键单击用户 -> 转到重置密码→重置密码)然后 AD 正在使用新密码对用户进行身份验证。 userPassword
和 unicodePwd
属性都没有更新。
我们尝试从 ADSI 和代码中更新 unicodePwd
属性,但它不允许用户从我们观察到的代码中更新它的值
[LDAP: error code 53 - 0000001F: SvcErr: DSID-031A12D2, problem 5003 (WILL_NOT_PERFORM)]
我们比较了之前的用户详细信息并从 ADSI 重置密码,发现很少有详细信息正在获取
已更新(BadLogonCount:0
、badPasswordTime:0
、badPwdCount:0
、lastLogoff:0
、lastLogon:0
、logonCount:0
、Modified
、modifyTimeStamp
、 msDS-User-Account-Control-Computed
、PasswordExpired:false
、PasswordLastSet
、uSNChanged
和 whenChanged
).
当我们尝试从 ADSI 修改 usnChanged
时,msDS-User-Account-Control-Computed
然后观察到这两个属性无法从 ADSI 和它提供的代码中编辑 SchemaViolationException
。对于 passwordExpired
和 badLogonCount
属性,我们在从代码和 ADSI 修改它时面临 NoSuchAttributeException
这两个属性丢失。
我们还可以怎样做?
要重置密码,请更新 unicodePwd
属性。 The documentation 告诉您一些要求:
- 新密码必须采用特定格式:包含在double-quotes中然后转换为UTF-16编码,以及
- 连接必须加密。
This page 在 Java 中有一个如何执行此操作的示例,我已将其粘贴在下方。它没有讨论加密,但您可以使用 LDAP over SSL (LDAPS),您可以使用 LDAPS://
而不是仅 LDAP://
来实现。这假定 AD 服务器已正确设置 LDAPS,并且您没有阻止 LDAPS 端口 (636) 的防火墙。
/**
* Update User Password in Microsoft Active Directory
* @param username
* @param password
*/
public void updateUserPassword(String username, String password)
{
try
{
System.out.println("updating password...\n");
String quotedPassword = "\"" + password + "\"";
char unicodePwd[] = quotedPassword.toCharArray();
byte pwdArray[] = new byte[unicodePwd.length * 2];
for (int i = 0; i < unicodePwd.length; i++)
{
pwdArray[i * 2 + 1] = (byte) (unicodePwd[i] >>> 8);
pwdArray[i * 2 + 0] = (byte) (unicodePwd[i] & 0xff);
}
System.out.print("encoded password: ");
for (int i = 0; i < pwdArray.length; i++)
{
System.out.print(pwdArray[i] + " ");
}
System.out.println();
ModificationItem[] mods = new ModificationItem[1];
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("UnicodePwd", pwdArray));
ldapContext.modifyAttributes("cn=" + username + BASE_NAME, mods);
}
catch (Exception e)
{
System.out.println("update password error: " + e);
}
}