LDAP Password Changes in Active Directory

I’ve never really been a big fan of Active Directory. Microsoft tends to treat standards more like suggestions than rules, and Active Directory has some good examples of that. I was recently asked a question about how you can change a password in Active Directory over LDAP. In most directory servers, you would either use the LDAP password modify extended operation (as described in RFC 3062), or you would perform a simple modify operation to replace the userPassword attribute with the clear-text password (and the server would automatically perform any necessary encoding to obscure the value). However, Active Directory has a number of very unusual requirements, so it’s probably worth making a note of them. They include:

  • Active Directory doesn’t appear to support the password modify extended operation, so you must change passwords using a normal LDAP modify operation.
  • Active Directory stores passwords in the unicodePwd attribute, rather than userPassword.
  • Active Directory will only accept password changes over secure connections. I have only ever used SSL. It may be that you can also use StartTLS, or perhaps SASL with confidentiality, but I’m not sure about that.
  • The new password must be enclosed in quotation marks, and it must use a UTF-16 little-endian encoding.
  • Active Directory may impose some strength requirements on the password, although exactly what those requirements are may vary from one instance to another.

Knowing these requirements, you should be able to write code using any LDAP API that will allow you to perform password changes in Active Directory. The following code demonstrates how to do it using the UnboundID LDAP SDK for Java:

import java.io.UnsupportedEncodingException;
import javax.net.ssl.SSLSocketFactory;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.Modification;
import com.unboundid.ldap.sdk.ModificationType;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ssl.SSLUtil;
import com.unboundid.util.ssl.TrustAllTrustManager;
/**
* This class provides a simple utility method that may be used to change the
* password of a user stored in an Active Directory server instance.
*/
public class ADPasswordChange
{
/**
* Perform the complete set of processing required to change a user's
* password in an Active Directory server.
*
* @param  adHost        The address of the Active Directory server.
* @param  adSSLPort     The SSL-based port of the Active Directory server
*                       (typically 636).
* @param  bindDN        The DN to use when binding to the Active Directory
*                       server instance.  It must have sufficient permission
*                       to change user passwords.
* @param  bindPassword  The clear-text password to use when binding to the
*                       Active Directory server instance.
* @param  userDN        The DN of the user whose password should be changed.
* @param  newPassword   The clear-text new password to assign to the user.
*
* @throws  LDAPException  If a problem is encountered while performing any
*                         of the required processing.
*/
public static void changePasswordInAD(final String adHost,
final int adSSLPort,
final String bindDN,
final String bindPassword,
final String userDN,
final String newPassword)
throws LDAPException
{
// Properly encode the password.  It must be enclosed in quotation marks,
// and it must use a UTF-16LE encoding.
System.out.println("Going to encode the password.");
final byte[] quotedPasswordBytes;
try
{
final String quotedPassword = '"' + newPassword + '"';
quotedPasswordBytes = quotedPassword.getBytes("UTF-16LE");
}
catch (final UnsupportedEncodingException uee)
{
throw new LDAPException(ResultCode.LOCAL_ERROR,
"Unable to encode the quoted password in UTF-16LE:  " +
StaticUtils.getExceptionMessage(uee),
uee);
}
// Create an SSL socket factory to use during the course of establishing
// an SSL-based connection to the server.  For simplicity, we'll cheat and
// use a trust manager that will trust any certificate that the server
// presents, but in production environments you should validate the
// certificate more carefully.
System.out.println("Going to create the SSL socket factory.");
final SSLSocketFactory socketFactory;
final SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
try
{
socketFactory = sslUtil.createSSLSocketFactory();
}
catch (final Exception e)
{
throw new LDAPException(ResultCode.LOCAL_ERROR,
"Unable to create an SSL socket factory to use for establishing " +
"a secure connection:  " + StaticUtils.getExceptionMessage(e),
e);
}
// Create a secure connection to the Active Directory server.
System.out.println("Going to establish the secure connection.");
final LDAPConnection connection = new LDAPConnection(socketFactory, adHost,
adSSLPort, bindDN, bindPassword);
try
{
// Attempt to modify the user password.
System.out.println("Going to replace the user's password.");
final Modification mod = new Modification(ModificationType.REPLACE,
"unicodePwd", quotedPasswordBytes);
connection.modify(userDN, mod);
}
finally
{
System.out.println("Closing the connection.");
connection.close();
}
}
}

3 thoughts on “LDAP Password Changes in Active Directory

  1. Having trouble creating an object from your class – could provide a sample class/main as an example using your ADPasswordChange class?

    Like

  2. there is no "unicodePwd" attibute in my Active directory. could i not change AD password this reason? my object classes:organizational Personpersontopuseri m gettin this errorException in thread "main" LDAPException(resultCode=53 (unwilling to perform), errorMessage='0000052D: SvcErr: DSID-031A11E5, problem 5003 (WILL_NOT_PERFORM), data 0

    Like

  3. Active Directory will never return the unicodePwd attribute, so it won't appear to be there. However, that doesn't mean that it isn't there.Unfortunately, Active Directory is extremely bad at telling you what's wrong and "problem 5003". Are you sure you're connecting over SSL? Are you sure that the password you're sending is surrounded by quotation marks? Are you sure it is encoded using UTF-16 with a little endian ordering (which is an extremely unusual encoding)? Are you sure that the password is complex enough to satisfy Active Directory's strength requirements (e.g., it's long enough and has a mix of uppercase and lowercase characters, digits, and symbols)?If you still can't figure out what the problem is, I'd recommend working with Microsoft.

    Like

Comments are closed.