LDAP-183: LdapTemplate caches password with pooled connections
Now explicitly disabling native Java LDAP connection pooling for ContextSource#getContext(String principal, String credentials)
This commit is contained in:
@@ -16,10 +16,10 @@
|
||||
|
||||
package org.springframework.ldap.core;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import org.springframework.ldap.NamingException;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
/**
|
||||
* A <code>ContextSource</code> is responsible for configuring and creating
|
||||
* <code>DirContext</code> instances. It is typically used from
|
||||
@@ -54,8 +54,12 @@ public interface ContextSource {
|
||||
|
||||
/**
|
||||
* Gets a <code>DirContext</code> instance authenticated using the supplied
|
||||
* principal and credentials.
|
||||
*
|
||||
* principal and credentials. Typically to be used for plain authentication
|
||||
* purposes. <strong>Note</strong> that this method will never make use
|
||||
* of native Java LDAP pooling, even though this instance is configured to do so.
|
||||
* This is to force password changes in the target directory to take effect
|
||||
* as soon as possible.
|
||||
*
|
||||
* @param principal The principal (typically a distinguished name of a user
|
||||
* in the LDAP tree) to use for authentication.
|
||||
* @param credentials The credentials to use for authentication.
|
||||
|
||||
@@ -15,13 +15,6 @@
|
||||
*/
|
||||
package org.springframework.ldap.core.support;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -33,6 +26,12 @@ import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Abstract implementation of the {@link ContextSource} interface. By default,
|
||||
* returns an authenticated
|
||||
@@ -67,8 +66,10 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
|
||||
private static final Class DEFAULT_CONTEXT_FACTORY = com.sun.jndi.ldap.LdapCtxFactory.class;
|
||||
|
||||
private static final Class DEFAULT_DIR_OBJECT_FACTORY = DefaultDirObjectFactory.class;
|
||||
private static final boolean DONT_DISABLE_POOLING = false;
|
||||
private static final boolean EXPLICITLY_DISABLE_POOLING = true;
|
||||
|
||||
private Class dirObjectFactory = DEFAULT_DIR_OBJECT_FACTORY;
|
||||
private Class dirObjectFactory = DEFAULT_DIR_OBJECT_FACTORY;
|
||||
|
||||
private Class contextFactory = DEFAULT_CONTEXT_FACTORY;
|
||||
|
||||
@@ -103,26 +104,40 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
|
||||
private DirContextAuthenticationStrategy authenticationStrategy = new SimpleDirContextAuthenticationStrategy();
|
||||
|
||||
public DirContext getContext(String principal, String credentials) {
|
||||
DirContext ctx = createContext(getAuthenticatedEnv(principal, credentials));
|
||||
|
||||
try {
|
||||
authenticationStrategy.processContextAfterCreation(ctx, principal, credentials);
|
||||
return ctx;
|
||||
}
|
||||
catch (NamingException e) {
|
||||
closeContext(ctx);
|
||||
throw LdapUtils.convertLdapException(e);
|
||||
}
|
||||
// This method is typically called for authentication purposes, which means that we
|
||||
// should explicitly disable pooling in case passwords are changed (LDAP-183).
|
||||
return doGetContext(principal, credentials, EXPLICITLY_DISABLE_POOLING);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.ldap.core.ContextSource#getReadOnlyContext()
|
||||
*/
|
||||
private DirContext doGetContext(String principal, String credentials, boolean explicitlyDisablePooling) {
|
||||
Hashtable env = getAuthenticatedEnv(principal, credentials);
|
||||
if(explicitlyDisablePooling) {
|
||||
env.remove(SUN_LDAP_POOLING_FLAG);
|
||||
}
|
||||
|
||||
DirContext ctx = createContext(env);
|
||||
|
||||
try {
|
||||
authenticationStrategy.processContextAfterCreation(ctx, principal, credentials);
|
||||
return ctx;
|
||||
}
|
||||
catch (NamingException e) {
|
||||
closeContext(ctx);
|
||||
throw LdapUtils.convertLdapException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.ldap.core.ContextSource#getReadOnlyContext()
|
||||
*/
|
||||
public DirContext getReadOnlyContext() {
|
||||
if (!anonymousReadOnly) {
|
||||
return getContext(authenticationSource.getPrincipal(), authenticationSource.getCredentials());
|
||||
return doGetContext(
|
||||
authenticationSource.getPrincipal(),
|
||||
authenticationSource.getCredentials(),
|
||||
DONT_DISABLE_POOLING);
|
||||
}
|
||||
else {
|
||||
return createContext(getAnonymousEnv());
|
||||
@@ -135,7 +150,10 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
|
||||
* @see org.springframework.ldap.core.ContextSource#getReadWriteContext()
|
||||
*/
|
||||
public DirContext getReadWriteContext() {
|
||||
return getContext(authenticationSource.getPrincipal(), authenticationSource.getCredentials());
|
||||
return doGetContext(
|
||||
authenticationSource.getPrincipal(),
|
||||
authenticationSource.getCredentials(),
|
||||
DONT_DISABLE_POOLING);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -218,6 +218,11 @@
|
||||
which is why Spring LDAP provides a more sophisticated approach to LDAP connection pooling,
|
||||
described in <xref linkend="pooling" />. If pooling functionality is required, this is the
|
||||
recommended approach.</note></para>
|
||||
<para><note>
|
||||
Regardless of the pooling configuration, the <literal>ContextSource#getContext(String principal, String credentials)</literal>
|
||||
method will always explicitly <emphasis>not</emphasis> use native Java LDAP Pooling, in order for
|
||||
reset passwords to take effect as soon as possible.
|
||||
</note></para>
|
||||
</sect2>
|
||||
<sect2 id="context-source-advanced">
|
||||
<title>Advanced ContextSource Configuration</title>
|
||||
|
||||
@@ -15,18 +15,6 @@
|
||||
*/
|
||||
package org.springframework.ldap.core.support;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static junit.framework.Assert.fail;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
@@ -39,6 +27,18 @@ import org.springframework.ldap.filter.EqualsFilter;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static junit.framework.Assert.fail;
|
||||
|
||||
/**
|
||||
* Integration tests for LdapContextSource.
|
||||
*
|
||||
@@ -87,6 +87,7 @@ public class LdapContextSourceIntegrationTest extends AbstractLdapTemplateIntegr
|
||||
assertNotNull(ctx);
|
||||
// Double check to see that we are authenticated.
|
||||
Hashtable environment = ctx.getEnvironment();
|
||||
assertTrue(environment.containsKey(LdapContextSource.SUN_LDAP_POOLING_FLAG));
|
||||
assertTrue(environment.containsKey(Context.SECURITY_PRINCIPAL));
|
||||
assertTrue(environment.containsKey(Context.SECURITY_CREDENTIALS));
|
||||
}
|
||||
@@ -111,8 +112,10 @@ public class LdapContextSourceIntegrationTest extends AbstractLdapTemplateIntegr
|
||||
String expectedCredentials = "password";
|
||||
ctx = tested.getContext(expectedPrincipal, expectedCredentials);
|
||||
assertNotNull(ctx);
|
||||
// Double check to see that we are authenticated.
|
||||
// Double check to see that we are authenticated, and that we did not receive
|
||||
// a connection eligible for connection pooling.
|
||||
Hashtable environment = ctx.getEnvironment();
|
||||
assertFalse(environment.containsKey(LdapContextSource.SUN_LDAP_POOLING_FLAG));
|
||||
assertEquals(expectedPrincipal, environment.get(Context.SECURITY_PRINCIPAL));
|
||||
assertEquals(expectedCredentials, environment.get(Context.SECURITY_CREDENTIALS));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user