Using the Active Directory from Java (AD Window Server 2008)

Source Code: Java Active Directory Source Code

We will show the needed steps in order to do a java program that interacts with the Active Directory. This program must allow the following:

  • Create user – with password that expired and does not expired.
  • Enable user
  • Disable user
  • Login user
  • Add user to a Group
  • Show all users

After checking these requirements it is clear that we need to do the following task in order to achieve the solution:

Configuration

Configure secure connection (ldaps) in Active Directory

To change anything in the Active Directory we must go via secure connection (ldaps://your.ldap.server:636) so it is needed to enable the “ldaps” that normally listen in the port: “636”. The easiest way to do this is to install the Online Responder (Go to "Deploying Microsoft Online Responder" Section).

After installing use the program “ldp.exe” to check if it is possible to connect to the AD using SSL.

Add the Server Certificate to our Java key Store

If we run our java program we will get the error "unable to find valid certification path to requested target" because our server certificate is not issued by a certification authority.

To solve this we need to add the server certificate to our trusted Java key store. The easiest way is to run the program: InstallCert check more details about how to do this here.

Development

We will use the Spring-Ldap.

Spring Configuration

   1: <?xml version="1.0" encoding="UTF-8"?>

   2: <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">

   3: <beans>

   4:     <bean id="contextSource"

   5:           class="org.springframework.ldap.core.support.LdapContextSource">

   6:         <!--<property name="url" value="ldap://192.168.1.102:389"/>-->

   7:         <property name="url" value="ldaps://192.168.1.102:636"/>

   8:         <property name="base" value="CN=Users,dc=agileworks,dc=com"/>

   9:         <property name="userDn" value="CN=Administrador,CN=Users,DC=agileworks,DC=com"/>

  10:         <property name="password" value="$awpassword191"/>

  11:         <property name="referral" value="follow"/>

  12:         <property name="baseEnvironmentProperties">

  13:             <map>

  14:                 <entry key="java.naming.security.authentication" value="simple"/>

  15:             </map>

  16:         </property>

  17:     </bean>

  18:     <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">

  19:         <constructor-arg ref="contextSource"/>

  20:     </bean>

  21:     <bean id="ldapUser" class="com.aw.ad.UserDaoImpl">

  22:         <property name="ldapTemplate" ref="ldapTemplate"/>

  23:     </bean>

  24: </beans>

Line 7: Using “ldaps” because we need to create users and change passwords.

Line 21: Configuring the DAO that will contain all the logic to interact with the AD

Getting reference to the UserDao

Resource resource = new ClassPathResource("springldap.xml");
BeanFactory factory = new XmlBeanFactory(resource);
UserDao userDao = (UserDaoImpl) factory.getBean("ldapUser");

Constants of the UserDao

// Attribute names
private static final String USER_ACCOUNT_CONTROL_ATTR_NAME = "userAccountControl";
private static final String PASSWORD_ATTR_NAME = "unicodepwd";
private static final String DISTINGUISHED_NAME_ATTR_NAME = "distinguishedname";
private static final String MEMBER_ATTR_NAME = "member";

// usercontrol params
private static final int FLAG_TO_DISABLE_USER = 0x2;
private static final int ADS_UF_DONT_EXPIRE_PASSWD = 0x10000;
private static final int USER_CONTROL_NORMAL_USER = 512;

Creating user

With password that expires

String userName = "Test18";
String pwd = "##12345xx";
User newUser = new User();
newUser.setUserName(userName);
newUser.setPassword(pwd);
userDao.createUser(newUser);

With password that does not expire

User newUser = new User();
newUser.setUserName(userName);
newUser.setPassword(pwd);
newUser.setExpirePasswd(false);
userDao.createUser(newUser);

UserDao.createUser method

   1: public void createUser(User user) {

   2:     try {

   3:         Attributes userAttributes = new BasicAttributes();

   4:         userAttributes.put("objectclass", "person");

   5:         userAttributes.put("objectclass", "user");

   6:         userAttributes.put("userPrincipalName", user.getEmailAddress());

   7:         userAttributes.put("sAMAccountName", user.getUserName());

   8:         userAttributes.put("givenName", user.getFirstName());

   9:         userAttributes.put("sn", user.getLastName());

  10:         userAttributes.put("displayName", user.getDisplayName());

  11:         int userAccounControl = getUserAccountControl(user);

  12:         userAttributes.put("userAccountControl", "" + userAccounControl);

  13:         userAttributes.put("unicodepwd", encodePassword(user.getPassword()));

  14:         ldapTemplate.bind(getDnFrom(user.getUserName()), null, userAttributes);

  15:     } catch (NameAlreadyBoundException e) {

  16:         throw new DuplicateUserException("User:[" + user.getUserName() + "] allready exists in AD.", e);

  17:     } catch (OperationNotSupportedException e) {

  18:         throw new PasswordStrengthException("Password:[" + user.getPassword() + "] does not pass the strength password validation.", e);

  19:     } catch (Throwable e) {

  20:         throw new LdapException("Problems creating user.", e);

  21:     }

  22: }

Line 1-13: Setting the user attributes.

Line 11: Getting the value of the userAccountControl that it is used to set different characteristics for the account. In our case we set here the type of the account and if the password will expire or not:

private int getUserAccountControl(User user) {
int userAccounControl = USER_CONTROL_NORMAL_USER;
if (!user.isExpirePasswd()) {
userAccounControl |= ADS_UF_DONT_EXPIRE_PASSWD;
}
return userAccounControl;
}
 
Line 13: The password is decorated in order to comply the AD conditions for passwords
private byte[] encodePassword(String password) throws UnsupportedEncodingException {
String newQuotedPassword = "\"" + password + "\"";
return newQuotedPassword.getBytes("UTF-16LE");
}

Line 14: Creating the user in the AD.

Enable User

userDao.enableUser(userName);

UserDao.enableUser method

In order to enable the user the value of the userAccountControl must be change.

public void enableUser(String userName) {
DirContextOperations userContextOperations = ldapTemplate.lookupContext(getDnFrom(userName));
String userAccountControlStr = userContextOperations.getStringAttribute(USER_ACCOUNT_CONTROL_ATTR_NAME);
int newUserAccountControl = Integer.parseInt(userAccountControlStr) & ~FLAG_TO_DISABLE_USER;
userContextOperations.setAttributeValue(USER_ACCOUNT_CONTROL_ATTR_NAME, "" + newUserAccountControl);
ldapTemplate.modifyAttributes(userContextOperations);
}

Disable user

userDao.disableUser(userName);

UserDao.disableUser method

In order to disable the user the value of the userAccountControl must be change.

public void disableUser(String userName) {
DirContextOperations userContextOperations = ldapTemplate.lookupContext(getDnFrom(userName));
String userAccountControlStr = userContextOperations.getStringAttribute(USER_ACCOUNT_CONTROL_ATTR_NAME);
int newUserAccountControl = Integer.parseInt(userAccountControlStr) | FLAG_TO_DISABLE_USER;
userContextOperations.setAttributeValue(USER_ACCOUNT_CONTROL_ATTR_NAME, "" + newUserAccountControl);
ldapTemplate.modifyAttributes(userContextOperations);
}

Login user

userDao.login(userName, pwd)

UserDao.login method

public boolean login(String userName, String password) {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectclass", "person")).and(new EqualsFilter("cn", userName));
return ldapTemplate.authenticate(DistinguishedName.EMPTY_PATH, filter.toString(), password);
}

Add user to a Group

userDao.addUserToGroup(userName, "AWGrupo1");

UserDao.addUserToGroup method

In order to assign a user to a specific Group in the AD we need to get a reference to the group and add the new user to its attribute “member”,

   1: public void addUserToGroup(String userName, String group) {

   2:     try {

   3:         DirContextAdapter dirContext = (DirContextAdapter) ldapTemplate.lookup(getDnFrom(userName));

   4:         String dnUserFull = dirContext.getStringAttribute(DISTINGUISHED_NAME_ATTR_NAME);

   5:         DirContextOperations groupContextOperations = ldapTemplate.lookupContext(getDnFrom(group));

   6:         String[] currentMembers = groupContextOperations.getStringAttributes(MEMBER_ATTR_NAME);

   7:         List<String> dnUserFullList = new ArrayList<String>();

   8:         if (currentMembers != null && currentMembers.length > 0) {

   9:             dnUserFullList.addAll(Arrays.asList(currentMembers));

  10:         }

  11:         dnUserFullList.add(dnUserFull);

  12:         groupContextOperations.setAttributeValues(MEMBER_ATTR_NAME, dnUserFullList.toArray(new String[dnUserFullList.size()]));

  13:         ldapTemplate.modifyAttributes(groupContextOperations);

  14:     } catch (Throwable e) {

  15:         throw new LdapException("Problem adding user:[" + userName + "] to Group:[" + group + "]", e);

  16:     }

  17: }

Line 4: Getting the full DN for the user that will be added to the group.

Line 5: Getting a reference to the Group

Line 6: Getting the list of current users of the Group

Line 11: Adding the user to the others users of the Group

Line 12: Setting the attribute “member” with the new list of users

Line 13: Saving the modifications.

Show all users

List<User> allUsers = userDao.getAllUsers();
System.out.println("There are:[" + allUsers.size() + "] users");
for (User user : allUsers) {
System.out.println(user);
}

UserDao.getAllUsers method

We will use a ContextMapper in order to populate the User info with the values that the AD will return.

public List<User> getAllUsers() {
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
return ldapTemplate.search("", "(objectclass=person)", controls, new UserContextMapper());
}
 
 
public class UserContextMapper extends AbstractContextMapper {
@Override
protected Object doMapFromContext(DirContextOperations context) {
User user = new User();
user.setUserName(context.getStringAttribute("cn"));
user.setFirstName(context.getStringAttribute("givenName"));
user.setLastName(context.getStringAttribute("sn"));
user.setEmailAddress(context.getStringAttribute("userPrincipalName"));
user.setMemberOf(context.getStringAttribute("memberOf"));
user.setDisplayName(context.getStringAttribute("displayName"));
return user;
}
}

Tags: , , ,

Una respuesta to “Using the Active Directory from Java (AD Window Server 2008)”