Skip to content
Advertisement

Windows AD unable to reset password from code

From code trying to reset AD user password and using the same  password further to login from other services. But AD is not authenticating the user.  In AD we are updating userPassword, holcimIsRegistered and userAccountControl attributes from our code to reset the password.

When we are manually resetting AD user password from ADSI (right click on user -> go to reset password → reset the password) then AD is authenticating the user with the new password. Neither userPassword nor unicodePwd attributes are getting updated.

We tried to update unicodePwd attribute from ADSI and code also but it’s not allowing user to update it’s value, from code we have observed

[LDAP: error code 53 - 0000001F: SvcErr: DSID-031A12D2, problem 5003 (WILL_NOT_PERFORM)]

We compared user details before and resetting password from ADSI and observed that few details are getting updated (BadLogonCount:0, badPasswordTime:0, badPwdCount:0, lastLogoff:0, lastLogon:0, logonCount:0, Modified, modifyTimeStamp, msDS-User-Account-Control-Computed, PasswordExpired:false, PasswordLastSet, uSNChanged and whenChanged).

When we tried to modify usnChanged, msDS-User-Account-Control-Computed from ADSI then observed that these two attributes were not editable from ADSI and from code it was giving SchemaViolationException. For passwordExpired and badLogonCount attributes , we faced NoSuchAttributeException while modifying it from code and from ADSI these two attributes were missing.

How else we can make this work?

Advertisement

Answer

To reset the password, you update the unicodePwd attribute. The documentation tells you about a couple requirements:

  1. The new password has to be in a specific format: enclosed in double-quotes and then converted to UTF-16 encoding, and
  2. The connection must be encrypted.

This page has an example of how to do this in Java, which I’ve pasted below. It doesn’t talk about the encryption, but you can use LDAP over SSL (LDAPS), which you can do by using LDAPS:// instead of just LDAP://. That assumes that the AD server is setup for LDAPS correctly and you don’t have a firewall blocking the LDAPS port (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);
    }
}
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement