blob: ed3a4cf1ab7b989e5450a6111e55ac5335d7f9d6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.ki.realm.ldap;
import java.util.Hashtable;
import java.util.Map;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>Default implementation of {@link LdapContextFactory} that can be configured or extended to
* customize the way {@link javax.naming.ldap.LdapContext} objects are retrieved.</p>
*
* <p>This implementation of {@link LdapContextFactory} is used by the {@link AbstractLdapRealm} if a
* factory is not explictly configured.</p>
*
* <p>Connection pooling is enabled by default on this factory, but can be disabled using the
* {@link #usePooling} property.</p>
*
* @author Jeremy Haile
* @since 0.2
*/
public class DefaultLdapContextFactory implements LdapContextFactory {
//TODO - complete JavaDoc
/*--------------------------------------------
| C O N S T A N T S |
============================================*/
/**
* The Sun LDAP property used to enable connection pooling. This is used in the default implementation
* to enable LDAP connection pooling.
*/
protected static final String SUN_CONNECTION_POOLING_PROPERTY = "com.sun.jndi.ldap.connect.pool";
/*--------------------------------------------
| I N S T A N C E V A R I A B L E S |
============================================*/
private static final Logger log = LoggerFactory.getLogger(DefaultLdapContextFactory.class);
protected String authentication = "simple";
protected String principalSuffix = null;
protected String searchBase = null;
protected String contextFactoryClassName = "com.sun.jndi.ldap.LdapCtxFactory";
protected String url = null;
protected String referral = "follow";
protected String systemUsername = null;
protected String systemPassword = null;
private boolean usePooling = true;
private Map<String, String> additionalEnvironment;
/*--------------------------------------------
| C O N S T R U C T O R S |
============================================*/
/*--------------------------------------------
| A C C E S S O R S / M O D I F I E R S |
============================================*/
/**
* Sets the type of LDAP authentication to perform when connecting to the LDAP server. Defaults to "simple"
*
* @param authentication the type of LDAP authentication to perform.
*/
public void setAuthentication(String authentication) {
this.authentication = authentication;
}
/**
* A suffix appended to the username. This is typically for
* domain names. (e.g. "@MyDomain.local")
*
* @param principalSuffix the suffix.
*/
public void setPrincipalSuffix(String principalSuffix) {
this.principalSuffix = principalSuffix;
}
/**
* The search base for the search to perform in the LDAP server.
* (e.g. OU=OrganizationName,DC=MyDomain,DC=local )
*
* @param searchBase the search base.
*/
public void setSearchBase(String searchBase) {
this.searchBase = searchBase;
}
/**
* The context factory to use. This defaults to the SUN LDAP JNDI implementation
* but can be overridden to use custom LDAP factories.
*
* @param contextFactoryClassName the context factory that should be used.
*/
public void setContextFactoryClassName(String contextFactoryClassName) {
this.contextFactoryClassName = contextFactoryClassName;
}
/**
* The LDAP url to connect to. (e.g. ldap://<ldapDirectoryHostname>:<port>)
*
* @param url the LDAP url.
*/
public void setUrl(String url) {
this.url = url;
}
/**
* Sets the LDAP referral property. Defaults to "follow"
*
* @param referral the referral property.
*/
public void setReferral(String referral) {
this.referral = referral;
}
/**
* The system username that will be used when connecting to the LDAP server to retrieve authorization
* information about a user. This must be specified for LDAP authorization to work, but is not required for
* only authentication.
*
* @param systemUsername the username to use when logging into the LDAP server for authorization.
*/
public void setSystemUsername(String systemUsername) {
this.systemUsername = systemUsername;
}
/**
* The system password that will be used when connecting to the LDAP server to retrieve authorization
* information about a user. This must be specified for LDAP authorization to work, but is not required for
* only authentication.
*
* @param systemPassword the password to use when logging into the LDAP server for authorization.
*/
public void setSystemPassword(String systemPassword) {
this.systemPassword = systemPassword;
}
/**
* Determines whether or not LdapContext pooling is enabled for connections made using the system
* user account. In the default implementation, this simply
* sets the <tt>com.sun.jndi.ldap.connect.pool</tt> property in the LDAP context environment. If you use an
* LDAP Context Factory that is not Sun's default implementation, you will need to override the
* default behavior to use this setting in whatever way your underlying LDAP ContextFactory
* supports. By default, pooling is enabled.
*
* @param usePooling true to enable pooling, or false to disable it.
*/
public void setUsePooling(boolean usePooling) {
this.usePooling = usePooling;
}
/**
* These entries are added to the environment map before initializing the LDAP context.
*
* @param additionalEnvironment additional environment entries to be configured on the LDAP context.
*/
public void setAdditionalEnvironment(Map<String, String> additionalEnvironment) {
this.additionalEnvironment = additionalEnvironment;
}
/*--------------------------------------------
| M E T H O D S |
============================================*/
public LdapContext getSystemLdapContext() throws NamingException {
return getLdapContext(systemUsername, systemPassword);
}
public LdapContext getLdapContext(String username, String password) throws NamingException {
if (searchBase == null) {
throw new IllegalStateException("A search base must be specified.");
}
if (url == null) {
throw new IllegalStateException("An LDAP URL must be specified of the form ldap://<hostname>:<port>");
}
if (username != null && principalSuffix != null) {
username += principalSuffix;
}
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.SECURITY_AUTHENTICATION, authentication);
if (username != null) {
env.put(Context.SECURITY_PRINCIPAL, username);
}
if (password != null) {
env.put(Context.SECURITY_CREDENTIALS, password);
}
env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactoryClassName);
env.put(Context.PROVIDER_URL, url);
env.put(Context.REFERRAL, referral);
// Only pool connections for system contexts
if (usePooling && username != null && username.equals(systemUsername)) {
// Enable connection pooling
env.put(SUN_CONNECTION_POOLING_PROPERTY, "true");
}
if (additionalEnvironment != null) {
env.putAll(additionalEnvironment);
}
if (log.isDebugEnabled()) {
log.debug("Initializing LDAP context using URL [" + url + "] and username [" + systemUsername + "] " +
"with pooling [" + (usePooling ? "enabled" : "disabled") + "]");
}
return new InitialLdapContext(env, null);
}
}