blob: 18dddeb3fdbe466922587f3afb106e00085e9950 [file] [log] [blame]
/*
* Copyright 2005-2008 Jeremy Haile
*
* 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.jsecurity.realm.ldap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import java.util.Hashtable;
import java.util.Map;
/**
* <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>
*
* @since 0.2
* @author Jeremy Haile
*/
public class DefaultLdapContextFactory implements LdapContextFactory {
/*--------------------------------------------
| 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 |
============================================*/
protected transient final Log log = LogFactory.getLog( getClass() );
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( principalSuffix != null ) {
username += principalSuffix;
}
Hashtable<String, String> env = new Hashtable<String, String>();
env.put( Context.SECURITY_AUTHENTICATION, authentication );
env.put( Context.SECURITY_PRINCIPAL, username );
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.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 );
}
}