org.kuali.rice.kim.dao.impl.LdapPrincipalDaoImpl Maven / Gradle / Ivy
/**
* Copyright 2005-2016 The Kuali Foundation
*
* Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
*
* 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.kuali.rice.kim.dao.impl;
import org.apache.commons.lang.StringUtils;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.kim.api.identity.entity.Entity;
import org.kuali.rice.kim.api.identity.entity.EntityDefault;
import org.kuali.rice.kim.api.identity.principal.EntityNamePrincipalName;
import org.kuali.rice.kim.api.identity.principal.Principal;
import org.kuali.rice.kim.api.identity.privacy.EntityPrivacyPreferences;
import org.kuali.rice.kim.dao.LdapPrincipalDao;
import org.kuali.rice.kim.impl.identity.PersonImpl;
import org.kuali.rice.kim.util.Constants;
import org.springframework.ldap.SizeLimitExceededException;
import org.springframework.ldap.core.ContextMapper;
import org.springframework.ldap.core.ContextMapperCallbackHandler;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.LikeFilter;
import org.springframework.ldap.filter.NotFilter;
import org.springframework.ldap.filter.OrFilter;
import javax.naming.directory.SearchControls;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.kuali.rice.core.util.BufferedLogger.*;
import static org.kuali.rice.kns.lookup.LookupUtils.getSearchResultsLimit;
/**
* Integrated Data Access via LDAP to EDS. Provides implementation to interface method
* for using Spring-LDAP to communicate with EDS.
*
* @author Kuali Rice Team ([email protected])
*/
public class LdapPrincipalDaoImpl implements LdapPrincipalDao {
private Constants kimConstants;
private LdapTemplate template;
private ParameterService parameterService;
private Map contextMappers;
public LdapPrincipalDaoImpl() {
}
/**
* In EDS, the principalId, principalName, and entityId will all be the same.
*/
public Principal getPrincipal(String principalId) {
if (principalId == null) {
return null;
}
Map criteria = new HashMap();
criteria.put(getKimConstants().getKimLdapIdProperty(), principalId);
List results = search(Principal.class, criteria);
if (results.size() > 0) {
return results.get(0);
}
return null;
}
/**
* Assuming he principalId, principalName, and entityId will all be the same.
*/
public Principal getPrincipalByName(String principalName) {
if (principalName == null) {
return null;
}
Map criteria = new HashMap();
criteria.put(getKimConstants().getKimLdapNameProperty(), principalName);
List results = search(Principal.class, criteria);
if (results.size() > 0) {
return results.get(0);
}
return null;
}
public List search(Class type, Map criteria) {
AndFilter filter = new AndFilter();
for (Map.Entry entry : criteria.entrySet()) {
//attempting to handle null values to prevent NPEs in this code.
if (entry.getValue() == null) {
entry.setValue("null");
}
if (entry.getValue() instanceof Iterable) {
OrFilter orFilter = new OrFilter();
for (String value : (Iterable) entry.getValue()) {
if (value.startsWith("!")) {
orFilter.or(new NotFilter(new LikeFilter(entry.getKey(), value.substring(1))));
} else {
orFilter.or(new LikeFilter(entry.getKey(), value));
}
}
filter.and(orFilter);
}
else {
if (((String)entry.getValue()).startsWith("!")) {
filter.and(new NotFilter(new LikeFilter(entry.getKey(), ((String)entry.getValue()).substring(1))));
} else {
filter.and(new LikeFilter(entry.getKey(), (String) entry.getValue()));
}
}
};
info("Using filter ", filter);
debug("Looking up mapper for ", type.getSimpleName());
final ContextMapper customMapper = contextMappers.get(type.getSimpleName());
ContextMapperCallbackHandler callbackHandler = new CustomContextMapperCallbackHandler(customMapper);
try {
getLdapTemplate().search(DistinguishedName.EMPTY_PATH,
filter.encode(),
getSearchControls(), callbackHandler);
}
catch (SizeLimitExceededException e) {
// Ignore this. We want to limit our results.
}
return callbackHandler.getList();
}
protected SearchControls getSearchControls() {
SearchControls retval = new SearchControls();
retval.setCountLimit(getSearchResultsLimit(PersonImpl.class).longValue());
retval.setSearchScope(SearchControls.SUBTREE_SCOPE);
return retval;
}
/**
* FIND entity objects based on the given criteria.
*
* @param entityId of user/person to grab entity information for
* @return {@link Entity}
*/
public Entity getEntity(String entityId) {
if (entityId == null) {
return null;
}
Map criteria = new HashMap();
criteria.put(getKimConstants().getKimLdapIdProperty(), entityId);
List results = search(Entity.class, criteria);
debug("Got results from info lookup ", results, " with size ", results.size());
if (results.size() > 0) {
return results.get(0);
}
return null;
}
/**
* Fetches full entity info, populated from EDS, based on the Entity's principal id
* @param principalId the principal id to look the entity up for
* @return the corresponding entity info
*/
public Entity getEntityByPrincipalId(String principalId) {
if (principalId == null) {
return null;
}
final Principal principal = getPrincipal(principalId);
if (principal != null && !StringUtils.isBlank(principal.getEntityId())) {
return getEntity(principal.getEntityId());
}
return null;
}
public EntityDefault getEntityDefault(String entityId) {
if (entityId == null) {
return null;
}
Map criteria = new HashMap();
criteria.put(getKimConstants().getKimLdapIdProperty(), entityId);
List results = search(EntityDefault.class, criteria);
debug("Got results from info lookup ", results, " with size ", results.size());
if (results.size() > 0) {
return results.get(0);
}
return null;
}
/**
* entityid and principalId are treated as the same.
*
* @see #getEntityDefaultInfo(String)
*/
public EntityDefault getEntityDefaultByPrincipalId(String principalId) {
return getEntityDefault(principalId);
}
public EntityDefault getEntityDefaultByPrincipalName(String principalName) {
Map criteria = new HashMap();
criteria.put(getKimConstants().getKimLdapNameProperty(), principalName);
List results = search(EntityDefault.class, criteria);
if (results.size() > 0) {
return results.get(0);
}
return null;
}
public Entity getEntityByPrincipalName(String principalName) {
Map criteria = new HashMap();
criteria.put(getKimConstants().getKimLdapNameProperty(), principalName);
List results = search(Entity.class, criteria);
if (results.size() > 0) {
return results.get(0);
}
return null;
}
public List lookupEntityDefault(Map searchCriteria, boolean unbounded) {
List results = new ArrayList();
Map criteria = getLdapLookupCriteria(searchCriteria);
results = search(EntityDefault.class, criteria);
return results;
}
public List lookupEntityIds(Map searchCriteria) {
final List results = new ArrayList();
final Map criteria = getLdapLookupCriteria(searchCriteria);
for (final Entity entity : search(Entity.class, criteria)) {
results.add(entity.getId());
}
return results;
}
/**
* Converts Kuali Lookup parameters into LDAP query parameters
* @param searchCriteria kuali lookup info
* @return {@link Map} of LDAP query info
*/
protected Map getLdapLookupCriteria(Map searchCriteria) {
Map criteria = new HashMap();
boolean hasTaxId = false;
for (Map.Entry criteriaEntry : searchCriteria.entrySet()) {
debug(String.format("Searching with criteria %s = %s", criteriaEntry.getKey(), criteriaEntry.getValue()));
String valueName = criteriaEntry.getKey();
Object value = criteriaEntry.getValue();
if (!criteriaEntry.getValue().equals("*")) {
valueName = String.format("%s.%s", criteriaEntry.getKey(), criteriaEntry.getValue());
}
if (!value.equals("*") && isMapped(valueName)) {
value = getLdapValue(valueName);
debug(value, " mapped to valueName ", valueName);
}
if (isMapped(criteriaEntry.getKey())) {
debug(String.format("Setting attribute to (%s, %s)",
getLdapAttribute(criteriaEntry.getKey()),
value));
final String key = getLdapAttribute(criteriaEntry.getKey());
if (!criteria.containsKey(key)) {
criteria.put(key, value);
}
}
else if (criteriaEntry.getKey().equalsIgnoreCase(getKimConstants().getExternalIdProperty())) {
criteria.put(getKimConstants().getKimLdapIdProperty(), value);
}
else if (criteriaEntry.getKey().equalsIgnoreCase(getKimConstants().getExternalIdTypeProperty())
&& value.toString().equals(getKimConstants().getTaxExternalIdTypeCode())) {
hasTaxId = true;
}
}
return criteria;
}
public EntityPrivacyPreferences getEntityPrivacyPreferences(String entityId) {
if (entityId == null) {
return null;
}
Map criteria = new HashMap();
criteria.put(getKimConstants().getKimLdapIdProperty(), entityId);
List results = search(EntityPrivacyPreferences.class, criteria);
if (results.size() > 0) {
return results.get(0);
}
return null;
}
public Map getDefaultNamesForPrincipalIds(List principalIds) {
Map criteria = new HashMap();
Map retval = new HashMap();
criteria.put(getKimConstants().getKimLdapIdProperty(), principalIds);
List results = search(EntityNamePrincipalName.class, criteria);
for (EntityNamePrincipalName nameInfo : results) {
retval.put(nameInfo.getPrincipalName(), nameInfo);
}
return retval;
}
public Map getDefaultNamesForEntityIds(List entityIds) {
return getDefaultNamesForPrincipalIds(entityIds);
}
protected Matcher getKimAttributeMatcher(String kimAttribute) {
String mappedParamValue = getParameterService().getParameterValueAsString(getKimConstants().getParameterNamespaceCode(),
getKimConstants().getParameterDetailTypeCode(),
getKimConstants().getMappedParameterName());
String regexStr = String.format("(%s|.*;%s)=([^=;]*).*", kimAttribute, kimAttribute);
debug("Matching KIM attribute with regex ", regexStr);
Matcher retval = Pattern.compile(regexStr).matcher(mappedParamValue);
if (!retval.matches()) {
mappedParamValue = getParameterService().getParameterValueAsString(getKimConstants().getParameterNamespaceCode(),
getKimConstants().getParameterDetailTypeCode(),
getKimConstants().getMappedValuesName());
retval = Pattern.compile(regexStr).matcher(mappedParamValue);
}
return retval;
}
protected boolean isMapped(String kimAttribute) {
debug("Matching " + kimAttribute);
debug("Does ", kimAttribute, " match? ", getKimAttributeMatcher(kimAttribute).matches());
return getKimAttributeMatcher(kimAttribute).matches();
}
protected String getLdapAttribute(String kimAttribute) {
Matcher matcher = getKimAttributeMatcher(kimAttribute);
debug("Does ", kimAttribute, " match? ", matcher.matches());
if (matcher.matches()) {
return matcher.group(2);
} else {
return null;
}
}
protected Object getLdapValue(String kimAttribute) {
Matcher matcher = getKimAttributeMatcher(kimAttribute);
debug("Does ", kimAttribute, " match? ", matcher.matches());
if (!matcher.matches()) {
return null;
}
String value = matcher.group(2);
// If it's actually a list. It can only be a list if there are commas
if (value.contains(",")) {
return Arrays.asList(value.split(","));
}
return value;
}
public void setKimConstants(Constants constants) {
this.kimConstants = constants;
}
public Constants getKimConstants() {
return kimConstants;
}
public ParameterService getParameterService() {
return this.parameterService;
}
public void setParameterService(ParameterService service) {
this.parameterService = service;
}
public LdapTemplate getLdapTemplate() {
return template;
}
public void setLdapTemplate(LdapTemplate template) {
this.template = template;
}
public Map getContextMappers() {
return this.contextMappers;
}
public void setContextMappers(final Map contextMappers) {
this.contextMappers = contextMappers;
}
/**
* Overrides the existing {@link ContextMapperCallbackHandler} because we want to
* intercede when there is invalid results from EDS.
*
* @author Leo Przybylski ([email protected])
*/
private static final class CustomContextMapperCallbackHandler extends ContextMapperCallbackHandler {
public CustomContextMapperCallbackHandler(ContextMapper mapper) {
super(mapper);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy