diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/core/support/AbstractTlsDirContextAuthenticationStrategy.java b/mvn-build/core/src/main/java/org/springframework/ldap/core/support/AbstractTlsDirContextAuthenticationStrategy.java
new file mode 100755
index 00000000..2d1df9cf
--- /dev/null
+++ b/mvn-build/core/src/main/java/org/springframework/ldap/core/support/AbstractTlsDirContextAuthenticationStrategy.java
@@ -0,0 +1,119 @@
+package org.springframework.ldap.core.support;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Hashtable;
+
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.naming.ldap.LdapContext;
+import javax.naming.ldap.StartTlsRequest;
+import javax.naming.ldap.StartTlsResponse;
+import javax.net.ssl.HostnameVerifier;
+
+import org.springframework.ldap.UncategorizedLdapException;
+import org.springframework.ldap.core.DirContextProxy;
+import org.springframework.ldap.support.LdapUtils;
+
+public abstract class AbstractTlsDirContextAuthenticationStrategy implements DirContextAuthenticationStrategy {
+
+ private HostnameVerifier hostnameVerifier;
+
+ private boolean shutdownTlsGracefully = false;
+
+ public void setShutdownTlsGracefully(boolean shutdownTlsGracefully) {
+ this.shutdownTlsGracefully = shutdownTlsGracefully;
+ }
+
+ public void setHostnameVerifier(HostnameVerifier hostnameVerifier) {
+ this.hostnameVerifier = hostnameVerifier;
+ }
+
+ public final void setupEnvironment(Hashtable env, String userDn, String password) {
+ // Nothing to do in this implementation - authentication should take
+ // place after TLS has been negotiated.
+ }
+
+ public final DirContext processContextAfterCreation(DirContext ctx, String userDn, String password)
+ throws NamingException {
+
+ if (ctx instanceof LdapContext) {
+ LdapContext ldapCtx = (LdapContext) ctx;
+ StartTlsResponse tlsResponse = (StartTlsResponse) ldapCtx.extendedOperation(new StartTlsRequest());
+ try {
+ if (hostnameVerifier != null) {
+ tlsResponse.setHostnameVerifier(hostnameVerifier);
+ }
+ tlsResponse.negotiate();
+ applyAuthentication(ldapCtx, userDn, password);
+
+ if (shutdownTlsGracefully) {
+ // Wrap the target context in a proxy to intercept any calls
+ // to 'close', so that we can shut down the TLS connection
+ // gracefully first.
+ return (DirContext) Proxy.newProxyInstance(DirContextProxy.class.getClassLoader(), new Class[] {
+ LdapContext.class, DirContextProxy.class }, new TlsAwareDirContextProxy(ldapCtx,
+ tlsResponse));
+ }
+ else {
+ return ctx;
+ }
+ }
+ catch (IOException e) {
+ LdapUtils.closeContext(ctx);
+ throw new UncategorizedLdapException("Failed to negitiate tls session", e);
+ }
+ }
+ else {
+ throw new IllegalArgumentException(
+ "Processed Context must be an LDAPv3 context, i.e. an LdapContext implementation");
+ }
+
+ }
+
+ /**
+ * Apply the actual authentication to the specified LdapContext.
+ * Typically, this will involve adding stuff to the environment.
+ *
+ * @param ctx the LdapContext instance.
+ * @param userDn the user dn of the user to authenticate.
+ * @param password the password of the user to authenticate.
+ * @throws NamingException if any error occurs.
+ */
+ protected abstract void applyAuthentication(LdapContext ctx, String userDn, String password) throws NamingException;
+
+ private static final class TlsAwareDirContextProxy implements DirContextProxy, InvocationHandler {
+
+ private static final String GET_TARGET_CONTEXT_METHOD_NAME = "getTargetContext";
+
+ private static final String CLOSE_METHOD_NAME = "close";
+
+ private final LdapContext target;
+
+ private final StartTlsResponse tlsResponse;
+
+ public TlsAwareDirContextProxy(LdapContext target, StartTlsResponse tlsResponse) {
+ this.target = target;
+ this.tlsResponse = tlsResponse;
+ }
+
+ public DirContext getTargetContext() {
+ return target;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (method.getName().equals(CLOSE_METHOD_NAME)) {
+ tlsResponse.close();
+ return method.invoke(target, args);
+ }
+ else if (method.getName().equals(GET_TARGET_CONTEXT_METHOD_NAME)) {
+ return target;
+ }
+ else {
+ return method.invoke(target, args);
+ }
+ }
+ }
+}
diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/core/support/DefaultTlsDirContextAuthenticationStrategy.java b/mvn-build/core/src/main/java/org/springframework/ldap/core/support/DefaultTlsDirContextAuthenticationStrategy.java
new file mode 100755
index 00000000..164f75ce
--- /dev/null
+++ b/mvn-build/core/src/main/java/org/springframework/ldap/core/support/DefaultTlsDirContextAuthenticationStrategy.java
@@ -0,0 +1,16 @@
+package org.springframework.ldap.core.support;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.ldap.LdapContext;
+
+public class DefaultTlsDirContextAuthenticationStrategy extends AbstractTlsDirContextAuthenticationStrategy {
+ private static final String SIMPLE_AUTHENTICATION = "simple";
+
+ protected void applyAuthentication(LdapContext ctx, String userDn, String password) throws NamingException {
+ ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, SIMPLE_AUTHENTICATION);
+ ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDn);
+ ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
+ }
+
+}
diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/core/support/DirContextAuthenticationStrategy.java b/mvn-build/core/src/main/java/org/springframework/ldap/core/support/DirContextAuthenticationStrategy.java
index 467b52b4..5fab9473 100755
--- a/mvn-build/core/src/main/java/org/springframework/ldap/core/support/DirContextAuthenticationStrategy.java
+++ b/mvn-build/core/src/main/java/org/springframework/ldap/core/support/DirContextAuthenticationStrategy.java
@@ -62,7 +62,11 @@ public interface DirContextAuthenticationStrategy {
/**
* This method is responsible for post-processing the
* DirContext instance after it has been created. It will be
- * called immediately after the instance has been created.
+ * called immediately after the instance has been created. Some
+ * authentication mechanisms, e.g. TLS, require particular stuff to happen
+ * before the actual target Context is closed. This method provides the
+ * possibility to replace or wrap the actual DirContext with a proxy so that
+ * any calls on it may be intercepted.
*
* @param ctx the freshly created DirContext instance. The
* actual implementation class (e.g. InitialLdapContext)
@@ -71,10 +75,12 @@ public interface DirContextAuthenticationStrategy {
* {@link AuthenticationSource} of the {@link ContextSource}.
* @param password the password to authenticate with, as received from the
* {@link AuthenticationSource} of the {@link ContextSource}.
+ * @return the DirContext, possibly modified, replaced or wrapped.
* @throws NamingException if anything goes wrong. This will cause the
* DirContext creation to be aborted and the exception to be
* translated and rethrown.
*/
- public void processContextAfterCreation(DirContext ctx, String userDn, String password) throws NamingException;
+ public DirContext processContextAfterCreation(DirContext ctx, String userDn, String password)
+ throws NamingException;
}
diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/core/support/ExternalTlsDirContextAuthenticationStrategy.java b/mvn-build/core/src/main/java/org/springframework/ldap/core/support/ExternalTlsDirContextAuthenticationStrategy.java
new file mode 100755
index 00000000..68dedd04
--- /dev/null
+++ b/mvn-build/core/src/main/java/org/springframework/ldap/core/support/ExternalTlsDirContextAuthenticationStrategy.java
@@ -0,0 +1,21 @@
+package org.springframework.ldap.core.support;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.ldap.LdapContext;
+
+/**
+ * {@link DirContextAuthenticationStrategy} for using TLS and external (SASL)
+ * authentication.
+ *
+ * @author Mattias Hellborg Arthursson
+ */
+public class ExternalTlsDirContextAuthenticationStrategy extends AbstractTlsDirContextAuthenticationStrategy {
+
+ private static final String EXTERNAL_AUTHENTICATION = "EXTERNAL";
+
+ protected void applyAuthentication(LdapContext ctx, String userDn, String password) throws NamingException {
+ ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, EXTERNAL_AUTHENTICATION);
+ }
+
+}
diff --git a/mvn-build/core/src/main/java/org/springframework/ldap/core/support/SimpleDirContextAuthenticationStrategy.java b/mvn-build/core/src/main/java/org/springframework/ldap/core/support/SimpleDirContextAuthenticationStrategy.java
index 9770b15b..9e74fa70 100755
--- a/mvn-build/core/src/main/java/org/springframework/ldap/core/support/SimpleDirContextAuthenticationStrategy.java
+++ b/mvn-build/core/src/main/java/org/springframework/ldap/core/support/SimpleDirContextAuthenticationStrategy.java
@@ -49,8 +49,8 @@ public class SimpleDirContextAuthenticationStrategy implements DirContextAuthent
* @see org.springframework.ldap.core.support.DirContextAuthenticationStrategy#processContextAfterCreation(javax.naming.directory.DirContext,
* java.lang.String, java.lang.String)
*/
- public void processContextAfterCreation(DirContext ctx, String userDn, String password) {
- // Nothing to do here
+ public DirContext processContextAfterCreation(DirContext ctx, String userDn, String password) {
+ return ctx;
}
}