Wednesday, April 29, 2015

Active Directory password changes in Java

I'd been tasked with some changes to support another project.  The changes include making self-service and administrative password changes against MS Active Directory.  I also needed to cause users to change their passwords on next login.

Here are a few comments/notes from the experience.
  • I'm using Java for this
  • I'm currently using Spring-ldap (1.3.x); works "ok sort of".  I'm probably going to have to rip it out and do this manually though.  See note after this list for info on the problem.
  • When using a service account to make administrative password changes; make sure the service account has the correct rights for setting passwords.  The example here is using a service account to make the changes.
  • You can set pwdLastSet to "0" to force a user to set their password on next login.  This requires its own rights in MS AD.
  • You MUST use LDAPS connections to change the password; it will not work otherwise. 
Ok, so I can execute the code below and it works - most of the time.  I keep running into an occasional error on setting pwdLastSet though.  It isn't consistently repeatable though.  I have a thought that it is related to Spring LDAP closing/opening connections per operation and maybe something with AD replication since we have a number of AD servers which replicate - basically a timing/race condition is my thought.  After some research, it looks like a few people have experienced something similar.  Others indicated that using the built-in pooling worked but their use case allowed plain LDAP (not LDAPS).  The built-in pooling per documentation indicates that it won't work for LDAPS.  The idea behind their use of the pooling appeared to be the continued use of a single persistent connection.  I reviewed some options using Spring LDAP but have not found a useful method of making it work reliably in some initial attempts.  I found some recommendation to use the Spring SingleContextSource in place of the LdapContextSource class but lack of a useful constructor pretty much destroyed that idea.  It just seems like the class was poorly designed.  I considered just reimplementing something from the Spring code but that just seems more convoluted.  So doing it manually is likely in my future.  Not a huge problem.

The following is how it is setup right now though - using Spring LdAP..  There are a number of examples like this floating around the internet.

Once you have a Spring LdapTemplate instance, the code for a password change is like this;

final ModificationItem [] mods = new ModificationItem[]
                {
                    new ModificationItem(DirContext.REPLACE_ATTRIBUTE, 

                        new BasicAttribute("unicodePwd", ("\"" + password + "\"").getBytes("UTF-16LE")))
                };
ldapTemplate.modifyAttributes(userDN, mods);


The code to cause a user to require changing their password on next login is;

final ModificationItem[] mods = new ModificationItem[]
                {
                    new ModificationItem(DirContext.REPLACE_ATTRIBUTE, 

                          new BasicAttribute("pwdLastSet", "0"))
                };

ldapTemplate.modifyAttributes(userDN, mods);

There are only 2 values you can set for pwdLastset; 0 and -1.  Using 0 basically forces a user to change their password and a -1 seems to make it seem like it was just set.

Nothing real exciting with this but it does help us move into best practices.


No comments:

Post a Comment