http://www.agile-works.com/blog/?p=447
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 userDisable userLogin userAdd user to a GroupShow all usersAfter checking these requirements it is clear that we need to do the following task in order to achieve the solution:
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.
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.
We will use the Spring-Ldap.
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
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.
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);}
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);}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.
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: ActiveDirectory, AD, java, SpringLDAP