/*
* RHQ Management Platform
* Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.enterprise.server.resource.group;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.naming.CompositeName;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.InvalidSearchFilterException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.PagedResultsControl;
import javax.naming.ldap.PagedResultsResponseControl;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.authz.Permission;
import org.rhq.core.domain.authz.Role;
import org.rhq.core.domain.common.composite.SystemSetting;
import org.rhq.core.domain.common.composite.SystemSettings;
import org.rhq.core.domain.resource.group.LdapGroup;
import org.rhq.core.domain.server.PersistenceUtility;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.server.RHQConstants;
import org.rhq.enterprise.server.auth.SubjectManagerLocal;
import org.rhq.enterprise.server.authz.RequiredPermission;
import org.rhq.enterprise.server.exception.LdapCommunicationException;
import org.rhq.enterprise.server.exception.LdapFilterException;
import org.rhq.enterprise.server.system.SystemManagerLocal;
import org.rhq.enterprise.server.util.security.UntrustedSSLSocketFactory;
/**
* This bean provides functionality to manipulate the ldap auth/authz functionality.
* That is, adding/modifying/deleting ldap group/users and their
* associated subjects and permissions are performed by this manager.
*
* @author paji
* @author Simeon Pinder
*/
@Stateless
public class LdapGroupManagerBean implements LdapGroupManagerLocal {
private Log log = LogFactory.getLog(LdapGroupManagerBean.class);
private static final String BASEDN_DELIMITER = ";";
@PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME)
private EntityManager entityManager;
@EJB
private SubjectManagerLocal subjectManager;
@EJB
private SystemManagerLocal systemManager;
private static boolean groupQueryComplete = false;
private static int groupQueryResultCount = 0;
private static long groupQueryStartTime = -1;
private static long groupQueryCurrentTime = -1;
private static int groupQueryPageCount = 0;
private static final int LDAP_GROUP_QUERY_LIMIT = 20000;//start to see a lot of ui responsiveness issues beyond this.
private void resetGroupQueryDetails() {
groupQueryComplete = false;
groupQueryResultCount = 0;
groupQueryStartTime = -1;
groupQueryCurrentTime = -1;
groupQueryPageCount = 0;
}
public Set<Map<String, String>> findAvailableGroups() {
//load current system properties
Properties systemConfig = populateProperties(systemManager.getUnmaskedSystemSettings(true));
//reset group query details
resetGroupQueryDetails();
//retrieve the filters.
String groupFilter = (String) systemConfig.get(SystemSetting.LDAP_GROUP_FILTER.name());
if ((groupFilter != null) && (!groupFilter.trim().isEmpty())) {
String filter;
if (groupFilter.startsWith("(") && groupFilter.endsWith(")")) {
filter = groupFilter; // RFC 2254 does not allow for ((expression))
} else {
filter = String.format("(%s)", groupFilter); // not wrapped in (), wrap it
}
return buildGroup(systemConfig, filter);
}
Set<Map<String, String>> emptyAvailableGroups = new HashSet<Map<String, String>>();
return emptyAvailableGroups;
}
public Set<Map<String, String>> findAvailableGroupsStatus() {
Set<Map<String, String>> availableGroupsQueryStatus = new HashSet<Map<String, String>>();
//query.complete => true|false
availableGroupsQueryStatus.add(buildStatusEntry("query.complete", String.valueOf(groupQueryComplete)));
//query.results.parsed => 0...N
availableGroupsQueryStatus.add(buildStatusEntry("query.results.parsed", String.valueOf(groupQueryResultCount)));
//query.start.time => timestamp
availableGroupsQueryStatus.add(buildStatusEntry("query.start.time", String.valueOf(groupQueryStartTime)));
//query.current.time => timestamp|-1
availableGroupsQueryStatus.add(buildStatusEntry("query.current.time", String.valueOf(groupQueryCurrentTime)));
//query.page.count => 0...N
availableGroupsQueryStatus.add(buildStatusEntry("query.page.count", String.valueOf(groupQueryPageCount)));
return availableGroupsQueryStatus;
}
private Map<String, String> buildStatusEntry(String key, String value) {
HashMap<String, String> status = new HashMap<String, String>();
status.put(key, value);
return status;
}
public Set<String> findAvailableGroupsFor(String userName) {
Properties options = populateProperties(systemManager.getUnmaskedSystemSettings(true));
String groupFilter = options.getProperty(SystemSetting.LDAP_GROUP_FILTER.name(), "");
String groupMember = options.getProperty(SystemSetting.LDAP_GROUP_MEMBER.name(), "");
String groupUsePosix = options.getProperty(SystemSetting.LDAP_GROUP_USE_POSIX.name(), "false");
if (groupUsePosix == null) {
groupUsePosix = Boolean.toString(false);//default to false
}
boolean usePosixGroups = Boolean.valueOf(groupUsePosix);
String userAttribute = getUserAttribute(options, userName, usePosixGroups);
Set<String> ldapSet = new HashSet<String>();
if (groupFilter.trim().isEmpty() || groupMember.trim().isEmpty()) {
log.warn("The ldap group filter defined is invalid. Group Filter: " + groupFilter + ", Group Member: "
+ groupMember);
return ldapSet;
}
if (userAttribute != null && userAttribute.trim().length() > 0) {
//TODO: spinder 4/21/10 put in error/debug logging messages for badly formatted filter combinations
String filter = "";
//form assumes examples where groupFilter is like 'objectclass=groupOfNames' and groupMember is 'member'
// to produce ldap filter like (&(objectclass=groupOfNames)(member=cn=Administrator,ou=People,dc=test,dc=com))
// or like (&(objectclass=groupOfNames)(memberUid=Administrator)) for posixGroups.
filter = String.format("(&(%s)(%s=%s))", groupFilter, groupMember, LDAPStringUtil.encodeForFilter(userAttribute));
Set<Map<String, String>> matched = buildGroup(options, filter);
log.trace("Located '" + matched.size() + "' LDAP groups for user '" + userName
+ "' using following ldap filter '" + filter + "'.");
//iterate to extract just the group names.
for (Map<String, String> match : matched) {
ldapSet.add(match.get("id"));
}
} else {
log.debug("Group lookup will not be performed due to no UserDN found for user " + userName);
}
return ldapSet;
}
@RequiredPermission(Permission.MANAGE_SECURITY)
public void setLdapGroupsOnRole(Subject subject, int roleId, Set<LdapGroup> groups) {
Role role = entityManager.find(Role.class, roleId);
if (role == null) {
throw new IllegalArgumentException("Role with id [" + roleId + "] does not exist.");
}
//add some code to synch up the current list of ldap groups.
Set<LdapGroup> currentGroups = role.getLdapGroups();
List<String> currentGroupNames = new ArrayList<String>(currentGroups.size());
for (LdapGroup group : currentGroups) {
currentGroupNames.add(group.getName());
}
List<String> newGroupNames = new ArrayList<String>(groups.size());
for (LdapGroup group : groups) {
newGroupNames.add(group.getName());
}
//figure out which ones are new then add them.
List<String> namesOfGroupsToBeAdded = new ArrayList<String>(newGroupNames);
namesOfGroupsToBeAdded.removeAll(currentGroupNames);
addLdapGroupsToRole(subject, roleId, namesOfGroupsToBeAdded);
//figure out which ones need to be removed. then remove them.
List<String> namesOfGroupsToBeRemoved = new ArrayList<String>(currentGroupNames);
namesOfGroupsToBeRemoved.removeAll(newGroupNames);
int[] idsOfGroupsToBeRemoved = new int[namesOfGroupsToBeRemoved.size()];
int i = 0;
for (LdapGroup group : currentGroups) {
if (namesOfGroupsToBeRemoved.contains(group.getName())) {
idsOfGroupsToBeRemoved[i++] = group.getId();
}
}
removeLdapGroupsFromRole(subject, roleId, idsOfGroupsToBeRemoved);
}
@RequiredPermission(Permission.MANAGE_SECURITY)
public void addLdapGroupsToRole(Subject subject, int roleId, List<String> groupNames) {
if ((groupNames != null) && (groupNames.size() > 0)) {
Role role = entityManager.find(Role.class, roleId);
if (role == null) {
throw new IllegalArgumentException("Could not find role[" + roleId + "] to add LDAP groups to.");
}
role.getLdapGroups().size(); // load them in
for (String groupId : groupNames) {
LdapGroup group = new LdapGroup();
group.setName(groupId);
role.addLdapGroup(group);
}
}
}
@RequiredPermission(Permission.MANAGE_SECURITY)
public void removeLdapGroupsFromRole(Subject subject, int roleId, int[] groupIds) {
if ((groupIds != null) && (groupIds.length > 0)) {
Role role = entityManager.find(Role.class, roleId);
if (role == null) {
throw new IllegalArgumentException("Could not find role[" + roleId + "] to remove LDAP groups from.");
}
role.getLdapGroups().size(); // load them in
for (Integer groupId : groupIds) {
LdapGroup doomedGroup = entityManager.find(LdapGroup.class, groupId);
if (doomedGroup == null) {
throw new IllegalArgumentException("Tried to remove doomedGroup[" + groupId + "] from role["
+ roleId + "], but doomedGroup was not found.");
}
role.removeLdapGroup(doomedGroup);
}
Query purgeQuery = entityManager.createNamedQuery(LdapGroup.DELETE_BY_ID);
List<Integer> ids = new LinkedList<Integer>();
for (int i : groupIds) {
ids.add(i);
}
purgeQuery.setParameter("ids", ids);
purgeQuery.executeUpdate();
}
}
private List<Role> findRolesByLdapGroupNames(List<String> ldapGroupNames) {
if (ldapGroupNames.isEmpty()) {
return Collections.EMPTY_LIST;
}
Query query = entityManager.createNamedQuery(LdapGroup.FIND_BY_ROLES_GROUP_NAMES);
query.setParameter("names", ldapGroupNames);
return query.getResultList();
}
public void assignRolesToLdapSubject(int subjectId, List<String> ldapGroupNames) {
Subject sub = entityManager.find(Subject.class, subjectId);
List<Role> roles = findRolesByLdapGroupNames(ldapGroupNames);
sub.getRoles().clear();
sub.getLdapRoles().clear();
for (Role role : roles) {
sub.addRole(role);
sub.addLdapRole(role);
}
}
public PageList<LdapGroup> findLdapGroupsByRole(int roleId, PageControl pageControl) {
Role role = entityManager.find(Role.class, roleId);
if (role == null) {
throw new IllegalArgumentException("Could not find role[" + roleId + "] to lookup ldap Groups on");
}
return new PageList<LdapGroup>(role.getLdapGroups(), role.getLdapGroups().size(), pageControl);
}
public PageList<LdapGroup> findLdapGroups(PageControl pc) {
pc.initDefaultOrderingField("g.name");
String queryName = LdapGroup.QUERY_FIND_ALL;
Query queryCount = PersistenceUtility.createCountQuery(entityManager, queryName);
Query query = PersistenceUtility.createQueryWithOrderBy(entityManager, queryName, pc);
long count = (Long) queryCount.getSingleResult();
List<LdapGroup> groups = query.getResultList();
return new PageList<LdapGroup>(groups, (int) count, pc);
}
/**Build/retrieve the user DN. Not usually a property.
*
* @param options
* @param userName
* @param usePosixGroups boolean indicating whether we search for groups with posixGroup format
* @return
*/
private String getUserAttribute(Properties options, String userName, boolean usePosixGroups) {
Map<String, String> details = findLdapUserDetails(userName);
String userAttribute = null;
if (usePosixGroups) {//return just the username as posixGroup member search uses (&(%s)(memberUid=username))
userAttribute = userName;
} else {//this is the default where group search uses (&(%s)(uniqueMember={userDn}))
userAttribute = details.get("dn");
}
return userAttribute;
}
public Map<String, String> findLdapUserDetails(String userName) {
// Load our LDAP specific properties
Properties systemConfig = populateProperties(systemManager.getUnmaskedSystemSettings(true));
HashMap<String, String> userDetails = new HashMap<String, String>();
// Load the BaseDN
String baseDN = (String) systemConfig.get(SystemSetting.LDAP_BASE_DN.name());
// Load the LoginProperty
String loginProperty = (String) systemConfig.get(SystemSetting.LDAP_LOGIN_PROPERTY.name());
if (loginProperty == null) {
// Use the default
loginProperty = "cn";
}
// Load any information we may need to bind
String bindDN = (String) systemConfig.get(SystemSetting.LDAP_BIND_DN.name());
String bindPW = (String) systemConfig.get(SystemSetting.LDAP_BIND_PW.name());
// Load any search filter
String searchFilter = (String) systemConfig.get(SystemSetting.LDAP_FILTER.name());
if (bindDN != null) {
systemConfig.setProperty(Context.SECURITY_PRINCIPAL, bindDN);
systemConfig.setProperty(Context.SECURITY_CREDENTIALS, bindPW);
systemConfig.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
}
try {
InitialLdapContext ctx = new InitialLdapContext(systemConfig, null);
SearchControls searchControls = getSearchControls();
// Add the search filter if specified. This only allows for a single search filter.. i.e. foo=bar.
String filter;
if ((searchFilter != null) && (searchFilter.length() != 0)) {
filter = "(&(" + loginProperty + "=" + userName + ")" + "(" + searchFilter + "))";
} else {
filter = "(" + loginProperty + "=" + userName + ")";
}
log.debug("Using LDAP filter [" + filter + "] to locate user details for " + userName);
// Loop through each configured base DN. It may be useful
// in the future to allow for a filter to be configured for
// each BaseDN, but for now the filter will apply to all.
String[] baseDNs = baseDN.split(BASEDN_DELIMITER);
for (int x = 0; x < baseDNs.length; x++) {
NamingEnumeration<SearchResult> answer = ctx.search(baseDNs[x], filter, searchControls);
if (!answer.hasMoreElements()) { //BZ:582471- ldap api bug change
log.debug("User " + userName + " not found for BaseDN " + baseDNs[x]);
// Nothing found for this DN, move to the next one if we have one.
continue;
}
// We use the first match
SearchResult si = answer.next();
//generate the DN
String userDN = null;
try {
userDN = si.getNameInNamespace();
} catch (UnsupportedOperationException use) {
userDN = new CompositeName(si.getName()).get(0);
if (si.isRelative()) {
userDN += "," + baseDNs[x];
}
}
userDetails.put("dn", userDN);
// Construct the UserDN
NamingEnumeration<String> keys = si.getAttributes().getIDs();
while (keys.hasMore()) {
String key = keys.next();
Attribute value = si.getAttributes().get(key);
if ((value != null) && (value.get() != null)) {
userDetails.put(key, value.get().toString());
}
}
return userDetails;
}
return userDetails;
} catch (NamingException e) {
throw new RuntimeException(e);
}
}
/** Returns boolean status about whether LDAP server
* requires attention. If server is:
* -not enabled
* -is enabled but communications appear fine
*
* false is returned, otherwise true.
*/
public Boolean ldapServerRequiresAttention() {
boolean requiresAttention = false;
//load current system properties
Properties systemConfig = populateProperties(systemManager.getUnmaskedSystemSettings(true));
// Load the LoginProperty
String loginProperty = (String) systemConfig.get(SystemSetting.LDAP_LOGIN_PROPERTY.name());
if (loginProperty == null) {
// Use the default
loginProperty = "cn";
}
// Load any information we may need to bind
String bindDN = (String) systemConfig.get(SystemSetting.LDAP_BIND_DN.name());
String bindPW = (String) systemConfig.get(SystemSetting.LDAP_BIND_PW.name());
if (bindDN != null) {
systemConfig.setProperty(Context.SECURITY_PRINCIPAL, bindDN);
systemConfig.setProperty(Context.SECURITY_CREDENTIALS, bindPW);
systemConfig.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
}
try {
InitialLdapContext ctx = new InitialLdapContext(systemConfig, null);
ctx.close();
} catch (NamingException e) {
requiresAttention = true;
log.error("LDAP communication error: " + e.getMessage(), e);
}
return requiresAttention;
}
/**
* @throws NamingException
* @see org.jboss.security.auth.spi.UsernamePasswordLoginModule#validatePassword(java.lang.String,java.lang.String)
*/
protected Set<Map<String, String>> buildGroup(Properties systemConfig, String filter) {
Set<Map<String, String>> groupDetailsMap = new HashSet<Map<String, String>>();
//Load our LDAP specific properties
// Load the BaseDN
String baseDN = (String) systemConfig.get(SystemSetting.LDAP_BASE_DN.name());
// Load the LoginProperty
String loginProperty = (String) systemConfig.get(SystemSetting.LDAP_LOGIN_PROPERTY.name());
if (loginProperty == null) {
// Use the default
loginProperty = "cn";
}
// Load any information we may need to bind
String bindDN = (String) systemConfig.get(SystemSetting.LDAP_BIND_DN.name());
String bindPW = (String) systemConfig.get(SystemSetting.LDAP_BIND_PW.name());
if (bindDN != null) {
systemConfig.setProperty(Context.SECURITY_PRINCIPAL, bindDN);
systemConfig.setProperty(Context.SECURITY_CREDENTIALS, bindPW);
systemConfig.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
}
try {
InitialLdapContext ctx = new InitialLdapContext(systemConfig, null);
SearchControls searchControls = getSearchControls();
/*String filter = "(&(objectclass=groupOfUniqueNames)(uniqueMember=uid=" + userName
+ ",ou=People, dc=rhndev, dc=redhat, dc=com))";*/
//modify the search control to only include the attributes we will use
String[] attributes = { "cn", "description" };
searchControls.setReturningAttributes(attributes);
//detect whether to use Query Page Control
String groupUseQueryPaging = systemConfig.getProperty(SystemSetting.LDAP_GROUP_PAGING.name(),
"false");
if (groupUseQueryPaging == null) {
groupUseQueryPaging = Boolean.toString(false);//default to false
}
boolean useQueryPaging = Boolean.valueOf(groupUseQueryPaging);
//BZ:964250: add rfc 2696
//default to 1000 results. System setting page size from UI should be non-negative integer > 0.
//additionally as system settings are modifiable via CLI which may not have param checking enabled do some
//more checking.
int defaultPageSize = 1000;
// only if they're enabled in the UI.
if (useQueryPaging) {
String groupPageSize = systemConfig.getProperty(
SystemSetting.LDAP_GROUP_QUERY_PAGE_SIZE.name(), ""
+ defaultPageSize);
if ((groupPageSize != null) && (!groupPageSize.trim().isEmpty())) {
int passedInPageSize = -1;
try {
passedInPageSize = Integer.valueOf(groupPageSize.trim());
if ((passedInPageSize > 0) && (passedInPageSize <= LDAP_GROUP_QUERY_LIMIT)) {
defaultPageSize = passedInPageSize;
} else {//keep defaults and log actual value being used.
log.debug("LDAP Group Page Size passed '" + groupPageSize
+ "' was ignored. Defaulting to 1000.");
}
} catch (NumberFormatException nfe) {
//log issue and do nothing. Go with the default.
log.debug("LDAP Group Page Size passed '" + groupPageSize
+ "' in is invalid. Defaulting to 1000." + nfe.getMessage());
}
}
ctx.setRequestControls(new Control[] { new PagedResultsControl(defaultPageSize, Control.CRITICAL) });
}
// Loop through each configured base DN. It may be useful
// in the future to allow for a filter to be configured for
// each BaseDN, but for now the filter will apply to all.
String[] baseDNs = baseDN.split(BASEDN_DELIMITER);
for (int x = 0; x < baseDNs.length; x++) {
//update query start time
groupQueryStartTime = System.currentTimeMillis();
executeGroupSearch(filter, groupDetailsMap, ctx, searchControls, baseDNs, x);
//update queryResultCount
groupQueryResultCount = groupDetailsMap.size();
groupQueryCurrentTime = System.currentTimeMillis();
// continually parsing pages of results until we're done.
// only if they're enabled in the UI.
if (useQueryPaging) {
//handle paged results if they're being used here
byte[] cookie = null;
Control[] controls = ctx.getResponseControls();
if (controls != null) {
for (Control control : controls) {
if (control instanceof PagedResultsResponseControl) {
PagedResultsResponseControl pagedResult = (PagedResultsResponseControl) control;
cookie = pagedResult.getCookie();
}
}
}
//continually parsing pages of results until we're done.
while ((groupQueryResultCount <= LDAP_GROUP_QUERY_LIMIT) && (cookie != null)) {
//ensure the next requests contains the session/cookie details
ctx.setRequestControls(new Control[] { new PagedResultsControl(defaultPageSize, cookie,
Control.CRITICAL) });
executeGroupSearch(filter, groupDetailsMap, ctx, searchControls, baseDNs, x);
//update Query state after each page
groupQueryResultCount = groupDetailsMap.size();
groupQueryPageCount++;
groupQueryCurrentTime = System.currentTimeMillis();
//empty out cookie
cookie = null;
//insert group query throttle.
//test for further iterations
controls = ctx.getResponseControls();
if (controls != null) {
for (Control control : controls) {
if (control instanceof PagedResultsResponseControl) {
PagedResultsResponseControl pagedResult = (PagedResultsResponseControl) control;
cookie = pagedResult.getCookie();
}
}
}
}
}
}
} catch (NamingException e) {
if (e instanceof InvalidSearchFilterException) {
InvalidSearchFilterException fException = (InvalidSearchFilterException) e;
String message = "The ldap group filter defined is invalid ";
log.error(message, fException);
throw new LdapFilterException(message + " " + fException.getMessage());
}
//TODO: check for ldap connection/unavailable/etc. exceptions.
else {
log.error("LDAP communication error: " + e.getMessage(), e);
throw new LdapCommunicationException(e);
}
} catch (IOException iex) {
log.error("Unexpected LDAP communciation error:" + iex.getMessage(), iex);
throw new LdapCommunicationException(iex);
}
//update end of query information
groupQueryCurrentTime = System.currentTimeMillis();
groupQueryComplete = true;
return groupDetailsMap;
}
/** Executes the LDAP group query using the filters, context and search controls, etc. parameters passed in.
* The matching groups located during processing this pages of results are added as new entries to the
* groupDetailsMap passed in.
*
* @param filter
* @param groupDetailsMap
* @param ctx
* @param searchControls
* @param baseDNs
* @param x
* @throws NamingException
*/
private void executeGroupSearch(String filter, Set<Map<String, String>> groupDetailsMap, InitialLdapContext ctx,
SearchControls searchControls, String[] baseDNs, int x) throws NamingException {
//execute search based on controls and context passed in.
NamingEnumeration<SearchResult> answer = ctx.search(baseDNs[x], filter, searchControls);
boolean ldapApiEnumerationBugEncountered = false;
int resultCount = 0;
while ((resultCount <= LDAP_GROUP_QUERY_LIMIT) && (groupDetailsMap.size() <= LDAP_GROUP_QUERY_LIMIT)
&& (!ldapApiEnumerationBugEncountered) && answer.hasMoreElements()) {//BZ:582471- ldap api bug change
// We use the first match
SearchResult si = null;
try {
si = answer.next();
} catch (NullPointerException npe) {
ldapApiEnumerationBugEncountered = true;
break;
}
//
Map<String, String> entry = new HashMap<String, String>();
String name = (String) si.getAttributes().get("cn").get();
name = name.trim();
Attribute desc = si.getAttributes().get("description");
String description = desc != null ? (String) desc.get() : "";
description = description.trim();
entry.put("id", name);
entry.put("name", name);
entry.put("description", description);
groupDetailsMap.add(entry);
resultCount++;//monitor the number of groups returned during this query.
groupQueryResultCount = resultCount;//update result count
if (groupQueryPageCount == 0) {
groupQueryPageCount++;
}
groupQueryCurrentTime = System.currentTimeMillis();
}
}
/** Translate SystemSettings to familiar Properties instance since we're
* passing not one but multiple values.
*
* @param systemSettings
* @return
*/
private Properties populateProperties(SystemSettings systemSettings) {
Properties properties = null;
if (systemSettings != null) {
properties = new Properties();
Set<Entry<SystemSetting, String>> entries = systemSettings.entrySet();
for (Entry<SystemSetting, String> entry : entries) {
SystemSetting key = entry.getKey();
if (key != null) {
String value = entry.getValue();
if (value != null) {
properties.put(key.name(), value);
}
}
}
//now load default/shared LDAP properties as we always have
// Set our default factory name if one is not given
String factoryName = properties.getProperty(SystemSetting.LDAP_NAMING_FACTORY.name());
properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, factoryName);
// Setup SSL if requested
String value = properties.getProperty(SystemSetting.USE_SSL_FOR_LDAP.name());
boolean ldapSsl = "ssl".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value);
if (ldapSsl) {
String ldapSocketFactory = properties.getProperty("java.naming.ldap.factory.socket");
if (ldapSocketFactory == null) {
properties.put("java.naming.ldap.factory.socket", UntrustedSSLSocketFactory.class.getName());
}
properties.put(Context.SECURITY_PROTOCOL, "ssl");
}
// Set the LDAP url
String providerUrl = properties.getProperty(SystemSetting.LDAP_NAMING_PROVIDER_URL.name());
if (providerUrl == null) {
int port = (ldapSsl) ? 636 : 389;
providerUrl = "ldap://localhost:" + port;
}
properties.setProperty(Context.PROVIDER_URL, providerUrl);
}
return properties;
}
/**
* Load a default set of properties to use when connecting to the LDAP server. If basic authentication is needed,
* the caller must set Context.SECURITY_PRINCIPAL, Context.SECURITY_CREDENTIALS and Context.SECURITY_AUTHENTICATION
* appropriately.
*
* @return properties that are to be used when connecting to LDAP server
* @deprecated use {@link #populateProperties(SystemSettings)} instead
*/
@Deprecated
private Properties getProperties(Properties systemConfig) {
Properties env = new Properties(systemConfig);
// Set our default factory name if one is not given
String factoryName = env.getProperty(SystemSetting.LDAP_NAMING_FACTORY.name());
env.setProperty(Context.INITIAL_CONTEXT_FACTORY, factoryName);
// Setup SSL if requested
String value = env.getProperty(SystemSetting.USE_SSL_FOR_LDAP.getInternalName());
boolean ldapSsl = "ssl".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value);
if (ldapSsl) {
String ldapSocketFactory = env.getProperty("java.naming.ldap.factory.socket");
if (ldapSocketFactory == null) {
env.put("java.naming.ldap.factory.socket", UntrustedSSLSocketFactory.class.getName());
}
env.put(Context.SECURITY_PROTOCOL, "ssl");
}
// Set the LDAP url
String providerUrl = env.getProperty(SystemSetting.LDAP_NAMING_PROVIDER_URL.name());
if (providerUrl == null) {
int port = (ldapSsl) ? 636 : 389;
providerUrl = "ldap://localhost:" + port;
}
env.setProperty(Context.PROVIDER_URL, providerUrl);
return env;
}
/**
* A simple method to construct a SearchControls object for use when doing LDAP searches. All of the defaults are
* used, with the exception of the scope, which is set to SUBTREE rather than the default of ONE_LEVEL
*
* @return controls what is searched in LDAP
*/
private SearchControls getSearchControls() {
// Set the scope to subtree, default is one-level
int scope = SearchControls.SUBTREE_SCOPE;
// No limit on the time waiting for a response
int timeLimit = 0;
// No limit on the number of entries returned
long countLimit = 0;
// Attributes to return.
String[] returnedAttributes = null;
// Don't return the object
boolean returnObject = false;
// No dereferencing during the search
boolean deference = false;
SearchControls constraints = new SearchControls(scope, countLimit, timeLimit, returnedAttributes, returnObject,
deference);
return constraints;
}
}