First shot at authentication methods that provide the actual exception (LDAP-192).

This commit is contained in:
Ulrik Sandberg
2009-12-14 20:45:30 +00:00
parent 499d07fdce
commit f02cf43c95
5 changed files with 152 additions and 7 deletions

View File

@@ -0,0 +1,20 @@
package org.springframework.ldap.core;
/**
* Callback interface to be used in the authentication methods in
* {@link LdapOperations} for performing operations when there
* are authentication errors. Can be useful when the cause of the
* authentication failure needs to be retrieved.
*
* @author Ulrik Sandberg
* @since 1.3.1
*/
public interface AuthenticationErrorCallback {
/**
* This method will be called with the authentication exception in
* case there is a problem with the authentication.
*
* @param e the exception that was caught in the authentication method
*/
void execute(Exception e);
}

View File

@@ -1392,6 +1392,60 @@ public interface LdapOperations {
*/
boolean authenticate(String base, String filter, String password, AuthenticatedLdapEntryContextCallback callback);
/**
* Utility method to perform a simple LDAP 'bind' authentication. Search for
* the LDAP entry to authenticate using the supplied base DN and filter; use
* the DN of the found entry together with the password as input to
* {@link ContextSource#getContext(String, String)}, thus authenticating the
* entry. The resulting DirContext instance is then used as input to the
* supplied {@link AuthenticatedLdapEntryContextCallback} to perform any
* additional LDAP operations against the authenticated DirContext. If an
* exception is caught, the same exception is passed on to the given
* {@link AuthenticationErrorCallback}. This enables the caller to provide a
* callback that, for example, collects the exception for later processing.
*
* @param base the DN to use as the base of the search.
* @param filter the search filter - must result in a unique result.
* @param password the password to use for authentication.
* @param callback the callback that will be called to perform operations
* on the DirContext authenticated with the found user.
* @param errorCallback the callback that will be called if an exception is caught.
* @return <code>true</code> if the authentication was successful,
* <code>false</code> otherwise.
* @see #authenticate(Name, String, String, AuthenticatedLdapEntryContextCallback)
* @since 1.3.1
*/
boolean authenticate(Name base, String filter, String password,
AuthenticatedLdapEntryContextCallback callback,
AuthenticationErrorCallback errorCallback);
/**
* Utility method to perform a simple LDAP 'bind' authentication. Search for
* the LDAP entry to authenticate using the supplied base DN and filter; use
* the DN of the found entry together with the password as input to
* {@link ContextSource#getContext(String, String)}, thus authenticating the
* entry. The resulting DirContext instance is then used as input to the
* supplied {@link AuthenticatedLdapEntryContextCallback} to perform any
* additional LDAP operations against the authenticated DirContext. If an
* exception is caught, the same exception is passed on to the given
* {@link AuthenticationErrorCallback}. This enables the caller to provide a
* callback that, for example, collects the exception for later processing.
*
* @param base the DN to use as the base of the search.
* @param filter the search filter - must result in a unique result.
* @param password the password to use for authentication.
* @param callback the callback that will be called to perform operations
* on the DirContext authenticated with the found user.
* @param errorCallback the callback that will be called if an exception is caught.
* @return <code>true</code> if the authentication was successful,
* <code>false</code> otherwise.
* @see #authenticate(String, String, String, AuthenticatedLdapEntryContextCallback)
* @since 1.3.1
*/
boolean authenticate(String base, String filter, String password,
AuthenticatedLdapEntryContextCallback callback,
AuthenticationErrorCallback errorCallback);
/**
* Perform a search for a unique entry matching the specified search
* criteria and return the found object. If no entry is found or if there

View File

@@ -1383,7 +1383,9 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
* .Name, java.lang.String, java.lang.String)
*/
public boolean authenticate(Name base, String filter, String password) {
return authenticate(base, filter, password, new NullAuthenticatedLdapEntryContextCallback());
return authenticate(base, filter, password,
new NullAuthenticatedLdapEntryContextCallback(),
new NullAuthenticationErrorCallback());
}
/*
@@ -1394,7 +1396,9 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
* , java.lang.String, java.lang.String)
*/
public boolean authenticate(String base, String filter, String password) {
return authenticate(base, filter, password, new NullAuthenticatedLdapEntryContextCallback());
return authenticate(new DistinguishedName(base), filter, password,
new NullAuthenticatedLdapEntryContextCallback(),
new NullAuthenticationErrorCallback());
}
/*
@@ -1407,7 +1411,7 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
*/
public boolean authenticate(String base, String filter, String password,
AuthenticatedLdapEntryContextCallback callback) {
return authenticate(new DistinguishedName(base), filter, password, callback);
return authenticate(new DistinguishedName(base), filter, password, callback, new NullAuthenticationErrorCallback());
}
/*
@@ -1420,6 +1424,34 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
*/
public boolean authenticate(Name base, String filter, String password,
final AuthenticatedLdapEntryContextCallback callback) {
return authenticate(base, filter, password, callback, new NullAuthenticationErrorCallback());
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.ldap.core.LdapOperations#authenticate(java.lang.String
* , java.lang.String, java.lang.String,
* org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback,
* org.springframework.ldap.core.AuthenticationErrorCallback)
*/
public boolean authenticate(String base, String filter, String password,
final AuthenticatedLdapEntryContextCallback callback, final AuthenticationErrorCallback errorCallback) {
return authenticate(new DistinguishedName(base), filter, password, callback, errorCallback);
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.ldap.core.LdapOperations#authenticate(javax.naming
* .Name, java.lang.String, java.lang.String,
* org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback,
* org.springframework.ldap.core.AuthenticationErrorCallback)
*/
public boolean authenticate(Name base, String filter, String password,
final AuthenticatedLdapEntryContextCallback callback, final AuthenticationErrorCallback errorCallback) {
List result = search(base, filter, new LdapEntryIdentificationContextMapper());
if (result.size() != 1) {
@@ -1442,6 +1474,7 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
}
catch (Exception e) {
log.error("Authentication failed for entry with DN '" + entryIdentification.getAbsoluteDn() + "'", e);
errorCallback.execute(e);
return false;
}
}
@@ -1476,10 +1509,31 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
return searchForObject(new DistinguishedName(base), filter, mapper);
}
private static final class NullAuthenticatedLdapEntryContextCallback implements
AuthenticatedLdapEntryContextCallback {
public void executeWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) {
public static final class NullAuthenticatedLdapEntryContextCallback
implements AuthenticatedLdapEntryContextCallback {
public void executeWithContext(DirContext ctx,
LdapEntryIdentification ldapEntryIdentification) {
// Do nothing
}
}
public static final class NullAuthenticationErrorCallback
implements AuthenticationErrorCallback {
public void execute(Exception e) {
// Do nothing
}
}
public static final class CollectingErrorCallback implements
AuthenticationErrorCallback {
private Exception error;
public void execute(Exception e) {
this.error = e;
}
public Exception getError() {
return error;
}
}
}

View File

@@ -401,7 +401,7 @@ public final class LdapUtils {
* href="http://blogs.msdn.com/oldnewthing/archive/2004/03/15/89753.aspx"
* >here</a>.
*
* @param sid SID in readable format
* @param string SID in readable format
* @return Binary version of the given sid
* @see LdapUtils#convertBinarySidToString(byte[])
* @since 1.3.1

View File

@@ -18,10 +18,14 @@ package org.springframework.ldap;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.LdapTemplate.CollectingErrorCallback;
import org.springframework.ldap.core.LdapTemplate.NullAuthenticatedLdapEntryContextCallback;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.filter.WhitespaceWildcardsFilter;
@@ -53,6 +57,19 @@ public class LdapTemplateAuthenticationITest extends AbstractLdapTemplateIntegra
assertFalse(tested.authenticate("", filter.toString(), "invalidpassword"));
}
@Test
public void testAuthenticateWithInvalidPasswordAndCollectedException() {
AndFilter filter = new AndFilter();
filter.and(new EqualsFilter("objectclass", "person")).and(new EqualsFilter("uid", "some.person3"));
final CollectingErrorCallback errorCallback = new CollectingErrorCallback();
final AuthenticatedLdapEntryContextCallback callback = new NullAuthenticatedLdapEntryContextCallback();
assertFalse(tested.authenticate("", filter.toString(), "invalidpassword", callback, errorCallback));
final Exception error = errorCallback.getError();
assertNotNull("collected error should not be null", error);
assertTrue("expected org.springframework.ldap.AuthenticationException", error instanceof AuthenticationException);
assertTrue("expected javax.naming.AuthenticationException", error.getCause() instanceof javax.naming.AuthenticationException);
}
@Test
public void testAuthenticateWithFilterThatDoesNotMatchAnything() {
AndFilter filter = new AndFilter();