/*
* Copyright (c) 2010 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.server.service.actions.strategies.ldap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.logging.Log;
import org.eurekastreams.commons.logging.LogFactory;
import org.eurekastreams.server.domain.Person;
import org.eurekastreams.server.persistence.mappers.ldap.LdapGroup;
import org.eurekastreams.server.persistence.mappers.ldap.LdapLookup;
import org.eurekastreams.server.persistence.mappers.requests.LdapLookupRequest;
import org.eurekastreams.server.service.actions.strategies.PersonLookupStrategy;
import org.springframework.ldap.core.DistinguishedName;
/**
* Person lookup strategy that, given an ldap group, returns all members of that group and subgroups.
*
*/
public class PersonLookupViaMembership implements PersonLookupStrategy
{
/**
* Logger.
*/
private Log log = LogFactory.make();
/**
* Finds group(s) by name.
*/
private LdapLookup<LdapGroup> groupMapper;
/**
* Finds group(s) by membership.
*/
private LdapLookup<LdapGroup> subGroupMapper;
/**
* Finds people by membership.
*/
private LdapLookup<Person> directGroupMemberMapper;
/**
* Base DN for LDAP queries.
*/
private String baseLdapPath;
/**
* Constructor.
*
* @param inGroupMapper
* Finds group(s) by name.
* @param inSubGroupMapper
* Finds group(s) by membership.
* @param inDirectGroupMemberMapper
* Finds people by membership.
* @param inBaseLdapPath
* Base DN for LDAP queries.
*/
public PersonLookupViaMembership(final LdapLookup<LdapGroup> inGroupMapper,
final LdapLookup<LdapGroup> inSubGroupMapper, final LdapLookup<Person> inDirectGroupMemberMapper,
final String inBaseLdapPath)
{
groupMapper = inGroupMapper;
subGroupMapper = inSubGroupMapper;
directGroupMemberMapper = inDirectGroupMemberMapper;
baseLdapPath = inBaseLdapPath;
}
/**
* Returns a list of people based on membership of provided ldap group. Returns all people in given group and
* subgroups recursively.
*
* @param inSearchString
* the value to be matched to an ldap attribue.
* @param inResultsUpperBound
* Max number of results.
* @return List of Person objects.
*/
@Override
public List<Person> findPeople(final String inSearchString, final int inResultsUpperBound)
{
// get all groups (recursively) to search for direct members.
Collection<LdapGroup> allGroups = getGroups(inSearchString);
// Person collecting "bucket" to eliminate duplicate results.
HashMap<String, Person> personBucket = new HashMap<String, Person>();
// search each group for direct members and add them to bucket.
for (LdapGroup lg : allGroups)
{
List<Person> people = directGroupMemberMapper.execute(new LdapLookupRequest(getFullDnAsString(lg), lg
.getDistinguishedName().toCompactString()));
// throw all results into map to eliminate duplicates.
for (Person p : people)
{
personBucket.put(p.getAccountId(), p);
}
}
if (log.isInfoEnabled())
{
log.info("Found " + personBucket.size() + " unique people from searching " + allGroups.size() + " groups.");
}
return new ArrayList<Person>(personBucket.values());
}
/**
* Method to return {@link LdapGroup}s and subgroups for given searchString.
*
* @param inSearchString
* search string for groups.
* @return Map<String, {@link LdapGroup}> result of query, where String is {@link LdapGroup} distinguished name.
*/
private Collection<LdapGroup> getGroups(final String inSearchString)
{
// map used to collect all groups keyed by their dn. this eliminates duplicates in results.
HashMap<String, LdapGroup> allGroups = new HashMap<String, LdapGroup>();
// get the groups by name.
List<LdapGroup> topLevelGroups = groupMapper.execute(new LdapLookupRequest(inSearchString));
if (log.isDebugEnabled())
{
for (LdapGroup lg : topLevelGroups)
{
log.debug("Found " + lg.getDistinguishedName().toCompactString() + " as top level group.");
}
}
// for each group found add to list of groups then find all subgroups and add them.
for (LdapGroup lg : topLevelGroups)
{
allGroups.put(lg.getDistinguishedName().toCompactString(), lg);
addSubGroups(lg, allGroups);
}
return allGroups.values();
}
/**
* Recursive method that finds all subgroups for given {@link LdapGroup}.
*
* @param inParentGroup
* {@link LdapGroup} to find subgroups for.
* @param inAllGroups
* The map of {@link LdapGroup}s to add subgroups to.
*/
private void addSubGroups(final LdapGroup inParentGroup, final HashMap<String, LdapGroup> inAllGroups)
{
// get template key from relative path (pre-base ldap path prepend).
String templateKey = inParentGroup.getDistinguishedName().toCompactString();
List<LdapGroup> subGroups = subGroupMapper.execute(new LdapLookupRequest(getFullDnAsString(inParentGroup),
templateKey));
// call once here to avoid multiple calls in loop.
boolean logDebug = log.isDebugEnabled();
for (LdapGroup lg : subGroups)
{
inAllGroups.put(lg.getDistinguishedName().toCompactString(), lg);
if (logDebug)
{
log.debug("Found " + lg.getDistinguishedName().toCompactString() + " as direct subGroup of "
+ inParentGroup.getDistinguishedName().toCompactString());
}
addSubGroups(lg, inAllGroups);
}
return;
}
/**
* returns relative dn with base ldap path prepended.
*
* @param inLdapGroup
* {@link LdapGroup} to get full dn for.
* @return relative dn with base ldap path prepended.
*/
private String getFullDnAsString(final LdapGroup inLdapGroup)
{
DistinguishedName dn = new DistinguishedName(inLdapGroup.getDistinguishedName());
dn.prepend(new DistinguishedName(baseLdapPath));
return dn.toCompactString();
}
}