First shot at authentication methods that provide the actual exception (LDAP-192).
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user