How to set Active Directory Password from Java application

 

This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at https://www.microsoft.com/info/cpyright.htm

Business Scenario

Many Java applications now utilize Active Directory as a source of authentication, in some situations it may be required to set Active Directory password from within Java applications. I encountered a scenario where majority of the users of a Java application were on Active Directory, but for a small percentage of users that do not log-in to Active Directory from their desktops we needed to provide a functionality within the application to set user passwords.

Prerequisites

  • This scenario was only tested against a Windows 2003 Domain
  • JKD 1.5.0_03 was used to run the sample code
  • You will need to connect to Active Directory with a user account that has permissions to reset passwords
  • PKI Certificates used in this scenario were issued by Microsoft Certificate Server configured in Active Directory integrated mode

Setup SSL trust between Active Directory Domain Controller(s) and Java application

Active Directory Domain Controllers will only allow password set operations over an SSL channel, therefore both parties should have a common trusted root certificate in their certificate stores. The simplest way to accomplish this is to export a trusted root certificate from a Domain Controller and import it into Java certificate store on the client machine.

Configuring SSL on Active Directory Domain Controllers

Active Directory Domain Controllers automatically enroll for domain controller certificate and utilize it for secure LDAP communications if Active Directory integrated Microsoft Certificate Server is deployed within the Forest. So in other words, if you deployed Microsoft Certificate Server in Active Directory integrated mode, then you don't need to do anything else on Active Directory side, all domain controllers will use SSL on port 636.

For instructions on how to setup Microsoft Certificate Server follow this link.

Importing Trusted Root Certificate on a Java client machine

On the client side we need to import a mutually trusted root certificate into Java certificate store. In our case we will export the root certificate issued by Microsoft Certificate Server and import it into Java store on the client.

1. On a Domain Controller log-in as an administrator and open Internet Explorer. Go to Tools->Internet Options->Content and click on Certificates

2. Switch to Trusted Root Certificate Authorities Tab and Select the certificate issued by your Active Directory integrated Certificate Server. Click on Export

3. Choose Base-64 encoded X.509(.CER)

4. Specify file name for the exported certificate

5. Finish the export and copy the exported .cer file to the Java client machine

6. At the client machine execute the following command.

Note the location of the jks file, you will need to reference it later on in the code.

Alias and keystore password are arbitrary values

Sample program to change Active Directory user password from Java

Now that SSL staff is out of the way compile this sample code and run it from the Java client

This code was developed by Jeremy Mortis here is link to the original code

import javax.naming.*;
import javax.naming.directory.*;
import javax.naming.ldap.*;
import java.util.*;
import java.security.*;
public class ADConnection {
DirContext ldapContext;
String baseName = ",cn=users,DC=fabrikam,DC=com";
String serverIP = "10.1.1.7";
public ADConnection() {
try {
Hashtable ldapEnv = new Hashtable(11);
ldapEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
ldapEnv.put(Context.PROVIDER_URL, "ldap://" + serverIP + ":636");
ldapEnv.put(Context.SECURITY_AUTHENTICATION, "simple");
ldapEnv.put(Context.SECURITY_PRINCIPAL, "cn=administrator" + baseName);
ldapEnv.put(Context.SECURITY_CREDENTIALS, "PA$$w0rd");
ldapEnv.put(Context.SECURITY_PROTOCOL, "ssl");
ldapContext = new InitialDirContext(ldapEnv);
}
catch (Exception e) {
System.out.println(" bind error: " + e);
e.printStackTrace();
System.exit(-1);
}
}
public void updatePassword(String username, String password) {
try {
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);
}
ModificationItem[] mods = new ModificationItem[1];
mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
new BasicAttribute("UnicodePwd", pwdArray));
ldapContext.modifyAttributes("cn=" + username + baseName, mods);
}
catch (Exception e) {
System.out.println("update password error: " + e);
System.exit(-1);
}
}
public static void main(String[] args) {
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
// the keystore that holds trusted root certificates
System.setProperty("javax.net.ssl.trustStore", "c:\\myCaCerts.jks");
System.setProperty("javax.net.debug", "all");
ADConnection adc = new ADConnection();
adc.updatePassword("Java User2", pass@word3);
}
}