How a user can change his password in Active Directory when user must reset password

112 Views Asked by At

I use unboundid ldap sdk library. I want to change user password in Active Directory LDAP server. The problem is that user must reset password so binding throw exception with 773 code.

I read in this documentation that there are two ways to change password. First way is executing modify request that contains delete and add operations. This way requires old password and I want to use this way. Second way is executing modify request that contains replace operation. This way does not need old password but it requires user binding. It means that some other user (admin user) has to be used because my user can not bind because my user must reset his password and binding throw exception. I do not want to use this way because I do not want to use any other user. Password has to be properly encoded in both ways. I have developed following code:

LDAPConnection connection=...
final byte[] oldQuotedPasswordBytes = encodeValue( aOldPassword );
final byte[] newQuotedPasswordBytes = encodeValue( aNewPassword );
final Modification modificationDel = new Modification( ModificationType.DELETE, "unicodePwd", oldQuotedPasswordBytes );
final Modification modificationAdd = new Modification( ModificationType.ADD, "unicodePwd", newQuotedPasswordBytes );
    
connection.modify( aUserDn, modificationDel, modificationAdd );


private byte[] encodeValue( char[] aNewPassword )
{
   final String quotedPassword = '"' + new String( aNewPassword ) + '"';
   return quotedPassword.getBytes( StandardCharsets.UTF_16LE );
}

Unfortunately this code throws exception:

0000052D: DSID-03190FC9, problem 1005 (CONSTRAINT_ATT_TYPE), data 0, Att 9005a (unicodePwd)

I do not understand this exception. I think that passwords (old and new) are properly encoded because I tested second way described in documentation where password is replaced. I tested two cases, binding admin user and binding my user that does not need to reset password. It works properly in both cases.

LDAPConnection connection=...
//bind admin or bind my user that does not need to reset password
final byte[] quotedPasswordBytes = encodeValue(aNewPassword);
final Modification modification = new Modification( ModificationType.REPLACE,"unicodePwd", quotedPasswordBytes );
connection.modify( aUserDn, modification );

This code works properly and changes user's password. This solution requires some admin user and I do not want to use this solution. I want that user can reset his password himself. It means that I have to use first way. How to do it?

===UPDATE===

I found what error code 0000052D means but the issue is still not resolved because binding is required to make my app working.

0000052D is 1325 in decimal.

Windows debug system error codes: https://learn.microsoft.com/pl-pl/windows/win32/debug/system-error-codes?redirectedfrom=MSDN

1325 error: https://learn.microsoft.com/pl-pl/windows/win32/debug/system-error-codes--1300-1699-?redirectedfrom=MSDN

ERROR_PASSWORD_RESTRICTION

1325 (0x52D)

Unable to update the password. The value provided for the new password does not meet the length, complexity, or history requirements of the domain.

Password that I used is strong but it was repeated (history requirement). I changed password many times in Windows using admin user in Active Directory Users and Computers app. I also changed password from my java application using my user when user did not need reset password. In this case my user is bind and modification request contain only replace operation. I have not noticed that there is any password history policy. My current code is :

    LDAPConnection connection=...
    //admin user binding
    final byte[] oldQuotedPasswordBytes = encodeValue( aOldPassword );
    final byte[] newQuotedPasswordBytes = encodeValue( aNewPassword );
    final Modification modificationDel = new Modification( ModificationType.DELETE, "unicodePwd", oldQuotedPasswordBytes );
    final Modification modificationAdd = new Modification( ModificationType.ADD, "unicodePwd", newQuotedPasswordBytes );
        
    connection.modify( aUserDn, modificationDel, modificationAdd );

It works if password is strong enough and password was not set earlier (history requirement). It turns out that password history policy is only activated when user must reset password and I use above code. It is very strange.

However, the problem is still not resolved. Binding is required to make my code working. As I wrote my user cannot bind because he must reset password and binding throws expectation with 773 code. I do not want to use any admin user.

1

There are 1 best solutions below

4
ErkinD39 On

https://learn.microsoft.com/en-us/windows/win32/adsi/user-must-change-password-at-next-logon

"user-must-change-password-at-next-logon" attribute should be cleared before the user changes/resets password. This uncheck should be done via other privileged user.