Added DirContextAuthenticationStratety for use with TLS connections.

This commit is contained in:
Mattias Arthursson
2008-08-13 17:12:18 +00:00
parent 89947a13e6
commit 2997844258
5 changed files with 166 additions and 4 deletions

View File

@@ -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 <code>LdapContext</code>.
* Typically, this will involve adding stuff to the environment.
*
* @param ctx the <code>LdapContext</code> 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);
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -62,7 +62,11 @@ public interface DirContextAuthenticationStrategy {
/**
* This method is responsible for post-processing the
* <code>DirContext</code> 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 <code>DirContext</code> instance. The
* actual implementation class (e.g. <code>InitialLdapContext</code>)
@@ -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
* <code>DirContext</code> 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;
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}