package org.akaza.openclinica.service.user;
import java.text.MessageFormat;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import org.akaza.openclinica.domain.user.LdapUser;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
import org.springframework.stereotype.Service;
/**
* Provides access to user information retrieved from LDAP/Active Directory.
*
* @author Doug Rodrigues (drodrigues@openclinica.com)
*/
@Service
public class LdapUserService {
@Autowired
private ContextSource contextSource;
@Value("s[ldap.enabled]")
private String ldapEnabledProperty;
@Value("s[ldap.loginQuery]")
private String loginQuery;
@Value("s[ldap.passwordRecoveryURL]")
private String passwordRecoveryURL;
@Value("s[ldap.userSearch.query]")
private String userSearchQuery;
@Value("s[ldap.userSearch.baseDn]")
private String userSearchBase;
@Value("s[ldap.userData.distinguishedName]")
private String keyDistinguishedName;
@Value("s[ldap.userData.username]")
private String keyUsername;
@Value("s[ldap.userData.firstName]")
private String keyFirstName;
@Value("s[ldap.userData.lastName]")
private String keyLastname;
@Value("s[ldap.userData.email]")
private String keyEmail;
@Value("s[ldap.userData.organization]")
private String keyOrganization;
private SpringSecurityLdapTemplate ldapTemplate;
@PostConstruct // Eclipse warning here is an Eclipse bug, not an issue with the code
public void init() {
ldapTemplate = new SpringSecurityLdapTemplate(contextSource);
ldapTemplate.setIgnorePartialResultException(true);
}
private final AttributesMapper ldapUserAttributesMapper = new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes) throws NamingException {
LdapUser u = new LdapUser();
u.setDistinguishedName(attToString(attributes, keyDistinguishedName));
u.setUsername(attToString(attributes, keyUsername));
u.setFirstName(attToString(attributes, keyFirstName));
u.setLastName(attToString(attributes, keyLastname));
u.setEmail(attToString(attributes, keyEmail));
u.setOrganization(attToString(attributes, keyOrganization));
return u;
}
private String attToString(Attributes a, String key) throws NamingException {
if (!StringUtils.isEmpty(key)) { // Check if the key for this attribute was defined in the properties file
Attribute att = a.get(key);
if (att != null) {
return a.get(key).get().toString();
}
}
return null;
}
};
/**
* Retrieves a list of users matching a <code>filter</code>. The filter must be a
* non-empty string.
*
* @param filter
* @return
*/
@SuppressWarnings("unchecked")
public List<LdapUser> listUsers(String filter) {
assert(!StringUtils.isEmpty(filter));
String query = MessageFormat.format(userSearchQuery, filter);
return ldapTemplate.search(userSearchBase, query, ldapUserAttributesMapper);
}
/**
* Retrieves a list of users matching a <code>filter</code> which usernames are not present in
* <code>existingUsers</code>.
*
* @param filter
* @param existingUsers
* @return
*/
public List<LdapUser> listNewUsers(String filter, Set<String> existingUsers) {
List<LdapUser> result = listUsers(filter);
if (existingUsers != null) {
Iterator<LdapUser> it = result.iterator();
while (it.hasNext()) {
LdapUser user = it.next();
if (existingUsers.contains(user.getUsername())) {
it.remove();
}
}
}
return result;
}
/**
* Loads a user by its distinguished name
*
* @param dn
* @return
*/
public LdapUser loadUser(String dn) {
return (LdapUser) ldapTemplate.lookup(dn, ldapUserAttributesMapper);
}
public DirContextOperations searchForUser(String username) {
try {
return ldapTemplate.searchForSingleEntry(userSearchBase, loginQuery, new String[] { username });
} catch (IncorrectResultSizeDataAccessException e) {
return null;
}
}
public boolean isLdapServerConfigured() {
return Boolean.parseBoolean(ldapEnabledProperty);
}
public String getPasswordRecoveryURL() {
return passwordRecoveryURL;
}
}