diff --git a/core/src/main/java/org/springframework/ldap/core/ContextSource.java b/core/src/main/java/org/springframework/ldap/core/ContextSource.java
index bbcbcc09..28099c66 100644
--- a/core/src/main/java/org/springframework/ldap/core/ContextSource.java
+++ b/core/src/main/java/org/springframework/ldap/core/ContextSource.java
@@ -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 ContextSource is responsible for configuring and creating
* DirContext instances. It is typically used from
@@ -54,8 +54,12 @@ public interface ContextSource {
/**
* Gets a DirContext instance authenticated using the supplied
- * principal and credentials.
- *
+ * principal and credentials. Typically to be used for plain authentication
+ * purposes. Note 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.
diff --git a/core/src/main/java/org/springframework/ldap/core/support/AbstractContextSource.java b/core/src/main/java/org/springframework/ldap/core/support/AbstractContextSource.java
index c6cf377d..fd5dc489 100644
--- a/core/src/main/java/org/springframework/ldap/core/support/AbstractContextSource.java
+++ b/core/src/main/java/org/springframework/ldap/core/support/AbstractContextSource.java
@@ -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);
}
/**
diff --git a/src/docbkx/configuration.xml b/src/docbkx/configuration.xml
index 1629a453..528b1f3d 100644
--- a/src/docbkx/configuration.xml
+++ b/src/docbkx/configuration.xml
@@ -218,6 +218,11 @@
which is why Spring LDAP provides a more sophisticated approach to LDAP connection pooling,
described in . If pooling functionality is required, this is the
recommended approach.
+
+ Regardless of the pooling configuration, the ContextSource#getContext(String principal, String credentials)
+ method will always explicitly not use native Java LDAP Pooling, in order for
+ reset passwords to take effect as soon as possible.
+
Advanced ContextSource Configuration
diff --git a/test/integration-tests/src/test/java/org/springframework/ldap/core/support/LdapContextSourceIntegrationTest.java b/test/integration-tests/src/test/java/org/springframework/ldap/core/support/LdapContextSourceIntegrationTest.java
index 080d889e..f7ff704d 100644
--- a/test/integration-tests/src/test/java/org/springframework/ldap/core/support/LdapContextSourceIntegrationTest.java
+++ b/test/integration-tests/src/test/java/org/springframework/ldap/core/support/LdapContextSourceIntegrationTest.java
@@ -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));
}