Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.att.research.xacml.std.pip.engines.ldap.LDAPEngine Maven / Gradle / Ivy
/*
*
* Copyright (c) 2013,2019 AT&T Knowledge Ventures
* SPDX-License-Identifier: MIT
*/
package com.att.research.xacml.std.pip.engines.ldap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.att.research.xacml.api.Attribute;
import com.att.research.xacml.api.pip.PIPException;
import com.att.research.xacml.api.pip.PIPFinder;
import com.att.research.xacml.api.pip.PIPRequest;
import com.att.research.xacml.api.pip.PIPResponse;
import com.att.research.xacml.std.pip.StdMutablePIPResponse;
import com.att.research.xacml.std.pip.StdPIPResponse;
import com.att.research.xacml.std.pip.engines.StdConfigurableEngine;
import com.google.common.base.Splitter;
import com.google.common.cache.Cache;
/**
* LDAPEngine extends {@link com.att.research.xacml.std.pip.engines.StdConfigurableEngine} to implement a generic PIP for accessing
* data from and LDAP server, including a configurable cache to avoid repeat queries.
*
* @author car
* @version $Revision$
*/
public class LDAPEngine extends StdConfigurableEngine {
public static final String PROP_RESOLVERS = "resolvers";
public static final String PROP_RESOLVER = "resolver";
public static final String PROP_LDAP_SCOPE = "scope";
private static final String LDAP_SCOPE_SUBTREE = "subtree";
private static final String LDAP_SCOPE_OBJECT = "object";
private static final String LDAP_SCOPE_ONELEVEL = "onelevel";
private static final String DEFAULT_CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
private static final String DEFAULT_SCOPE = LDAP_SCOPE_SUBTREE;
private Logger logger = LoggerFactory.getLogger(this.getClass());
private Hashtable ldapEnvironment = new Hashtable();
private List ldapResolvers = new ArrayList();
private int ldapScope;
/*
* In addition, we pull the following standard LDAP properties from the configuration
* Context.AUTHORITATIVE: boolean
* Context.BATCHSIZE: integer
* Context.DNSURL: String
* Context.INITIAL_CONTEXT_FACTORY: String
* Context.LANGUAGE: String
* Context.OBJECT_FACTORIES: String
* Context.PROVIDER_URL: String
* Context.REFERRAL: String
* Context.SECURITY_AUTHENTICATION: String
* Context.SECURITY_CREDENTIALS: String
* Context.SECURITY_PRINCIPAL: String
* Context.SECURITY_PROTOCOL: String
* Context.STATE_FACTORIES: String
* Context.URL_PKG_PREFIXES: String
*/
public LDAPEngine() {
}
private boolean configureStringProperty(String propertyPrefix, String property, Properties properties, String defaultValue) {
String propertyValue = properties.getProperty(propertyPrefix + property, defaultValue);
if (propertyValue != null) {
this.ldapEnvironment.put(property, propertyValue);
return true;
} else {
return false;
}
}
private boolean configureIntegerProperty(String propertyPrefix, String property, Properties properties, Integer defaultValue) {
String propertyValue = properties.getProperty(propertyPrefix + property);
if (propertyValue == null) {
if (defaultValue != null) {
this.ldapEnvironment.put(property, defaultValue);
return true;
} else {
return false;
}
} else {
try {
this.ldapEnvironment.put(property, Integer.parseInt(propertyValue));
return true;
} catch (NumberFormatException ex) {
this.logger.error("Invalid Integer '" + propertyValue + "' for '" + property + "' property");
return false;
}
}
}
@Override
public void configure(String id, Properties properties) throws PIPException {
/*
* Handle the standard properties
*/
super.configure(id, properties);
String propertyPrefix = id + ".";
/*
* Configure the LDAP environment: I think the only required property is the provider_url
*/
if (!this.configureStringProperty(propertyPrefix, Context.PROVIDER_URL, properties, null)) {
throw new PIPException("Invalid configuration for " + this.getClass().getName() + ": No " + propertyPrefix + Context.PROVIDER_URL);
}
this.configureStringProperty(propertyPrefix, Context.AUTHORITATIVE, properties, null);
this.configureIntegerProperty(propertyPrefix, Context.BATCHSIZE, properties, null);
this.configureStringProperty(propertyPrefix, Context.DNS_URL, properties, null);
this.configureStringProperty(propertyPrefix, Context.INITIAL_CONTEXT_FACTORY, properties, DEFAULT_CONTEXT_FACTORY);
this.configureStringProperty(propertyPrefix, Context.LANGUAGE, properties, null);
this.configureStringProperty(propertyPrefix, Context.OBJECT_FACTORIES, properties, null);
this.configureStringProperty(propertyPrefix, Context.REFERRAL, properties, null);
this.configureStringProperty(propertyPrefix, Context.SECURITY_AUTHENTICATION, properties, null);
this.configureStringProperty(propertyPrefix, Context.SECURITY_CREDENTIALS, properties, null);
this.configureStringProperty(propertyPrefix, Context.SECURITY_PRINCIPAL, properties, null);
this.configureStringProperty(propertyPrefix, Context.SECURITY_PROTOCOL, properties, null);
this.configureStringProperty(propertyPrefix, Context.STATE_FACTORIES, properties, null);
this.configureStringProperty(propertyPrefix, Context.URL_PKG_PREFIXES, properties, null);
String ldapScopeValue = properties.getProperty(propertyPrefix + PROP_LDAP_SCOPE, DEFAULT_SCOPE);
if (LDAP_SCOPE_SUBTREE.equals(ldapScopeValue)) {
this.ldapScope = SearchControls.SUBTREE_SCOPE;
} else if (LDAP_SCOPE_OBJECT.equals(ldapScopeValue)) {
this.ldapScope = SearchControls.OBJECT_SCOPE;
} else if (LDAP_SCOPE_ONELEVEL.equals(ldapScopeValue)) {
this.ldapScope = SearchControls.ONELEVEL_SCOPE;
} else {
this.logger.warn("Invalid LDAP Scope value '" + ldapScopeValue + "'; using " + DEFAULT_SCOPE);
this.ldapScope = SearchControls.SUBTREE_SCOPE;
}
/*
* Get list of resolvers defined for this LDAP Engine
*/
String resolversList = properties.getProperty(propertyPrefix + PROP_RESOLVERS);
if (resolversList == null || resolversList.isEmpty()) {
throw new PIPException("Invalid configuration for " + this.getClass().getName() + ": No " + propertyPrefix + PROP_RESOLVERS);
}
/*
* Iterate the resolvers
*/
for (String resolver : Splitter.on(',').trimResults().omitEmptyStrings().split(resolversList)) {
/*
* Get the LDAPResolver for this LDAPEngine
*/
String resolverClassName = properties.getProperty(propertyPrefix + PROP_RESOLVER + "." + resolver + ".classname");
if (resolverClassName == null) {
throw new PIPException("Invalid configuration for " + this.getClass().getName() + ": No " + propertyPrefix + PROP_RESOLVER + "." + resolver + ".classname");
}
LDAPResolver ldapResolverNew = null;
try {
Class> classResolver = Class.forName(resolverClassName);
if (!LDAPResolver.class.isAssignableFrom(classResolver)) {
this.logger.error("LDAPResolver class " + resolverClassName + " does not implement " + LDAPResolver.class.getCanonicalName());
throw new PIPException("LDAPResolver class " + resolverClassName + " does not implement " + LDAPResolver.class.getCanonicalName());
}
ldapResolverNew = LDAPResolver.class.cast(classResolver.newInstance());
} catch (Exception ex) {
this.logger.error("Exception instantiating LDAPResolver for class '" + resolverClassName + "': " + ex.getMessage(), ex);
throw new PIPException("Exception instantiating LDAPResolver for class '" + resolverClassName + "'", ex);
}
assert(ldapResolverNew != null);
ldapResolverNew.configure(propertyPrefix + PROP_RESOLVER + "." + resolver, properties, this.getIssuer());
this.ldapResolvers.add(ldapResolverNew);
}
}
@Override
public PIPResponse getAttributes(PIPRequest pipRequest, PIPFinder pipFinder) throws PIPException {
/*
* Make sure we have at least one resolver.
*/
if (this.ldapResolvers.size() == 0) {
throw new IllegalStateException(this.getClass().getCanonicalName() + " is not configured");
}
StdMutablePIPResponse mutablePIPResponse = new StdMutablePIPResponse();
for (LDAPResolver ldapResolver : this.ldapResolvers) {
this.getAttributes(pipRequest, pipFinder, mutablePIPResponse, ldapResolver);
}
if (mutablePIPResponse.getAttributes().size() == 0) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("returning empty response");
}
return StdPIPResponse.PIP_RESPONSE_EMPTY;
} else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Returning " + mutablePIPResponse.getAttributes().size() + " attributes");
this.logger.debug("Attributes: {}", mutablePIPResponse.getAttributes());
}
return new StdPIPResponse(mutablePIPResponse);
}
}
public void getAttributes(PIPRequest pipRequest, PIPFinder pipFinder, StdMutablePIPResponse mutablePIPResponse, LDAPResolver ldapResolver) throws PIPException {
/*
* Check with the resolver to get the base string
*/
String stringBase = ldapResolver.getBase(this, pipRequest, pipFinder);
if (stringBase == null) {
this.logger.warn(this.getName() + " does not handle " + pipRequest.toString());
return;
}
/*
* Get the filter string
*/
String stringFilter = ldapResolver.getFilterString(this, pipRequest, pipFinder);
/*
* Check the cache
*/
Cache cache = this.getCache();
String cacheKey = stringBase + "::" + (stringFilter == null ? "" : stringFilter);
if (cache != null) {
PIPResponse pipResponse = cache.getIfPresent(cacheKey);
if (pipResponse != null) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Returning cached response: " + pipResponse);
}
mutablePIPResponse.addAttributes(pipResponse.getAttributes());
return;
}
}
/*
* Not in the cache, so set up the LDAP query session
*/
DirContext dirContext = null;
PIPResponse pipResponse = null;
try {
/*
* Create the DirContext
*/
dirContext = new InitialDirContext(this.ldapEnvironment);
/*
* Set up the search controls
*/
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(this.ldapScope);
/*
* Do the search
*/
NamingEnumeration namingEnumeration = dirContext.search(stringBase, stringFilter, searchControls);
if (namingEnumeration != null && namingEnumeration.hasMore()) {
while (namingEnumeration.hasMore()) {
List listAttributes = ldapResolver.decodeResult(namingEnumeration.next());
if (listAttributes != null && listAttributes.size() > 0) {
mutablePIPResponse.addAttributes(listAttributes);
}
}
}
/*
* Put in the cache
*/
if (cache != null) {
cache.put(cacheKey, pipResponse);
}
} catch (NamingException ex) {
this.logger.error("NamingException creating the DirContext: " + ex.getMessage(), ex);
} finally {
if (dirContext != null) {
try {
dirContext.close();
} catch (Exception ex) {
this.logger.warn("Exception closing DirContext: " + ex.getMessage(), ex);
}
}
}
}
@Override
public Collection attributesRequired() {
Set requiredAttributes = new HashSet();
for (LDAPResolver resolver : this.ldapResolvers) {
resolver.attributesRequired(requiredAttributes);
}
return requiredAttributes;
}
@Override
public Collection attributesProvided() {
Set providedAttributes = new HashSet();
for (LDAPResolver resolver : this.ldapResolvers) {
resolver.attributesProvided(providedAttributes);
}
return providedAttributes;
}
}