LDAP-263: authentication methods for LdapQuery. Documentation updated to reflect fluent API changes.
This commit is contained in:
@@ -28,4 +28,8 @@ public class AuthenticationException extends NamingSecurityException {
|
||||
public AuthenticationException(javax.naming.AuthenticationException cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public AuthenticationException() {
|
||||
this(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2005-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ldap.core;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
/**
|
||||
* Callback interface to be used in the authentication methods in
|
||||
* {@link LdapOperations} for performing operations on individually
|
||||
* authenticated contexts.
|
||||
*
|
||||
* @author Mattias Hellborg Arthursson
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface AuthenticatedLdapEntryContextMapper<T> {
|
||||
/**
|
||||
* Perform some LDAP operation on the supplied authenticated
|
||||
* <code>DirContext</code> instance. The target context will be
|
||||
* automatically closed.
|
||||
*
|
||||
* @param ctx the <code>DirContext</code> instance to perform an operation
|
||||
* on.
|
||||
* @param ldapEntryIdentification the identification of the LDAP entry used
|
||||
* to authenticate the supplied <code>DirContext</code>.
|
||||
* @return the result of the operation, if any.
|
||||
*/
|
||||
T mapWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification);
|
||||
}
|
||||
@@ -13,9 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.ldap.core.support;
|
||||
|
||||
import org.springframework.ldap.core.AuthenticationErrorCallback;
|
||||
package org.springframework.ldap.core;
|
||||
|
||||
/**
|
||||
* Convenience implementation of AuthenticationErrorCallback that stores the
|
||||
@@ -47,4 +45,13 @@ public final class CollectingAuthenticationErrorCallback implements Authenticati
|
||||
public Exception getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this callback has collected an error.
|
||||
*
|
||||
* @return <code>true</code> if an error has been collected, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean hasError() {
|
||||
return error != null;
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ import java.util.List;
|
||||
* @author Mattias Hellborg Arthursson
|
||||
* @since 1.3.2
|
||||
* @see <a href="http://www.watersprings.org/pub/id/draft-kashi-incremental-00.txt">Incremental Retrieval of Multi-valued Properties</a>
|
||||
* @see {@link org.springframework.ldap.core.support.DefaultIncrementalAttributesMapper}
|
||||
* @see org.springframework.ldap.core.support.DefaultIncrementalAttributesMapper
|
||||
*/
|
||||
public interface IncrementalAttributesMapper<T extends IncrementalAttributesMapper> extends AttributesMapper<T> {
|
||||
/**
|
||||
|
||||
@@ -1323,10 +1323,12 @@ public interface LdapOperations {
|
||||
* @return <code>true</code> if the authentication was successful,
|
||||
* <code>false</code> otherwise.
|
||||
* @since 1.3
|
||||
* @deprecated use {@link #authenticate(org.springframework.ldap.query.LdapQuery, String)}
|
||||
* or {@link #authenticate(org.springframework.ldap.query.LdapQuery, String, AuthenticatedLdapEntryContextMapper)}
|
||||
*/
|
||||
boolean authenticate(Name base, String filter, String password);
|
||||
|
||||
/**
|
||||
/**
|
||||
* 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
|
||||
@@ -1347,6 +1349,8 @@ public interface LdapOperations {
|
||||
* @return <code>true</code> if the authentication was successful,
|
||||
* <code>false</code> otherwise.
|
||||
* @since 1.3
|
||||
* @deprecated use {@link #authenticate(org.springframework.ldap.query.LdapQuery, String)}
|
||||
* or {@link #authenticate(org.springframework.ldap.query.LdapQuery, String, AuthenticatedLdapEntryContextMapper)}
|
||||
*/
|
||||
boolean authenticate(String base, String filter, String password);
|
||||
|
||||
@@ -1368,6 +1372,8 @@ public interface LdapOperations {
|
||||
* <code>false</code> otherwise.
|
||||
* @see #authenticate(Name, String, String)
|
||||
* @since 1.3
|
||||
* @deprecated use {@link #authenticate(org.springframework.ldap.query.LdapQuery, String)}
|
||||
* or {@link #authenticate(org.springframework.ldap.query.LdapQuery, String, AuthenticatedLdapEntryContextMapper)}
|
||||
*/
|
||||
boolean authenticate(Name base, String filter, String password, AuthenticatedLdapEntryContextCallback callback);
|
||||
|
||||
@@ -1389,6 +1395,8 @@ public interface LdapOperations {
|
||||
* <code>false</code> otherwise.
|
||||
* @see #authenticate(String, String, String)
|
||||
* @since 1.3
|
||||
* @deprecated use {@link #authenticate(org.springframework.ldap.query.LdapQuery, String)}
|
||||
* or {@link #authenticate(org.springframework.ldap.query.LdapQuery, String, AuthenticatedLdapEntryContextMapper)}
|
||||
*/
|
||||
boolean authenticate(String base, String filter, String password, AuthenticatedLdapEntryContextCallback callback);
|
||||
|
||||
@@ -1414,6 +1422,8 @@ public interface LdapOperations {
|
||||
* <code>false</code> otherwise.
|
||||
* @see #authenticate(Name, String, String, AuthenticatedLdapEntryContextCallback)
|
||||
* @since 1.3.1
|
||||
* @deprecated use {@link #authenticate(org.springframework.ldap.query.LdapQuery, String)}
|
||||
* or {@link #authenticate(org.springframework.ldap.query.LdapQuery, String, AuthenticatedLdapEntryContextMapper)}
|
||||
*/
|
||||
boolean authenticate(Name base, String filter, String password,
|
||||
AuthenticatedLdapEntryContextCallback callback,
|
||||
@@ -1441,29 +1451,33 @@ public interface LdapOperations {
|
||||
* <code>false</code> otherwise.
|
||||
* @see #authenticate(String, String, String, AuthenticatedLdapEntryContextCallback)
|
||||
* @since 1.3.1
|
||||
* @deprecated use {@link #authenticate(org.springframework.ldap.query.LdapQuery, String)}
|
||||
* or {@link #authenticate(org.springframework.ldap.query.LdapQuery, String, AuthenticatedLdapEntryContextMapper)}
|
||||
*/
|
||||
boolean authenticate(String 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. 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 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, AuthenticationErrorCallback)
|
||||
* @since 1.3.1
|
||||
*/
|
||||
/**
|
||||
* 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. 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 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, AuthenticationErrorCallback)
|
||||
* @since 1.3.1
|
||||
* @deprecated use {@link #authenticate(org.springframework.ldap.query.LdapQuery, String)}
|
||||
* or {@link #authenticate(org.springframework.ldap.query.LdapQuery, String, AuthenticatedLdapEntryContextMapper)}
|
||||
*/
|
||||
boolean authenticate(Name base, String filter, String password,
|
||||
AuthenticationErrorCallback errorCallback);
|
||||
|
||||
@@ -1483,12 +1497,64 @@ public interface LdapOperations {
|
||||
* @return <code>true</code> if the authentication was successful,
|
||||
* <code>false</code> otherwise.
|
||||
* @throws IncorrectResultSizeDataAccessException if more than one users were found
|
||||
* @see #authenticate(String, String, String, AuthenticatedLdapEntryContextCallback, AuthenticationErrorCallback)
|
||||
* @since 1.3.1
|
||||
* @deprecated use {@link #authenticate(org.springframework.ldap.query.LdapQuery, String)}
|
||||
* or {@link #authenticate(org.springframework.ldap.query.LdapQuery, String, AuthenticatedLdapEntryContextMapper)}
|
||||
*/
|
||||
boolean authenticate(String base, String filter, String password,
|
||||
AuthenticationErrorCallback errorCallback);
|
||||
|
||||
|
||||
/**
|
||||
* Utility method to perform a simple LDAP 'bind' authentication. Search for
|
||||
* the LDAP entry to authenticate using the supplied LdapQuery; use
|
||||
* the DN of the found entry together with the password as input to
|
||||
* {@link ContextSource#getContext(String, String)}, thus authenticating the
|
||||
* entry.
|
||||
* <p>
|
||||
* <b>Note:</b> This method differs from the older authenticate methods in that encountered
|
||||
* exceptions are thrown rather than supplied to a callback for handling.
|
||||
* </p>
|
||||
*
|
||||
* @param query the LdapQuery specifying the details of the search.
|
||||
* @param password the password to use for authentication.
|
||||
* @param mapper the callback that will be called to perform operations
|
||||
* on the DirContext authenticated with the found user.
|
||||
* <code>false</code> otherwise.
|
||||
* @return the result from the callback.
|
||||
* @throws IncorrectResultSizeDataAccessException if more than one users were found
|
||||
* @throws org.springframework.dao.EmptyResultDataAccessException if only one user was found
|
||||
* @throws NamingException if something went wrong in authentication.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
<T> T authenticate(LdapQuery query, String password, AuthenticatedLdapEntryContextMapper<T> mapper);
|
||||
|
||||
/**
|
||||
* 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. 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.
|
||||
* <p>
|
||||
* <b>Note:</b> This method differs from the older authenticate methods in that encountered
|
||||
* exceptions are thrown rather than supplied to a callback for handling.
|
||||
* </p>
|
||||
*
|
||||
* @param query the LdapQuery specifying the details of the search.
|
||||
* @param password the password to use for authentication.
|
||||
* <code>false</code> otherwise.
|
||||
* @throws IncorrectResultSizeDataAccessException if more than one users were found
|
||||
* @throws org.springframework.dao.EmptyResultDataAccessException if only one user was found
|
||||
* @throws NamingException if something went wrong in authentication.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
void authenticate(LdapQuery query, String password);
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -20,7 +20,9 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.ldap.AuthenticationException;
|
||||
import org.springframework.ldap.NamingException;
|
||||
import org.springframework.ldap.UncategorizedLdapException;
|
||||
import org.springframework.ldap.query.LdapQuery;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -1491,42 +1493,94 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
|
||||
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() == 0) {
|
||||
String msg = "No results found for search, base: '" + base + "'; filter: '" + filter + "'.";
|
||||
log.info(msg);
|
||||
return false;
|
||||
} else if (result.size() > 1) {
|
||||
String msg = "base: '" + base + "'; filter: '" + filter + "'.";
|
||||
throw new IncorrectResultSizeDataAccessException(msg, 1, result.size());
|
||||
}
|
||||
|
||||
final LdapEntryIdentification entryIdentification = (LdapEntryIdentification) result.get(0);
|
||||
|
||||
try {
|
||||
DirContext ctx = contextSource.getContext(entryIdentification.getAbsoluteDn().toString(), password);
|
||||
executeWithContext(new ContextExecutor<Object>() {
|
||||
public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException {
|
||||
callback.executeWithContext(ctx, entryIdentification);
|
||||
return null;
|
||||
}
|
||||
}, ctx);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.info("Authentication failed for entry with DN '" + entryIdentification.getAbsoluteDn() + "'", e);
|
||||
errorCallback.execute(e);
|
||||
return false;
|
||||
}
|
||||
return authenticate(base,
|
||||
filter,
|
||||
password,
|
||||
getDefaultSearchControls(defaultSearchScope, RETURN_OBJ_FLAG, null),
|
||||
callback,
|
||||
errorCallback);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.ldap.core.LdapOperations#searchForObject(javax.naming
|
||||
* .Name, java.lang.String, org.springframework.ldap.core.ContextMapper)
|
||||
*/
|
||||
private boolean authenticate(Name base,
|
||||
String filter,
|
||||
String password,
|
||||
SearchControls searchControls,
|
||||
final AuthenticatedLdapEntryContextCallback callback,
|
||||
final AuthenticationErrorCallback errorCallback) {
|
||||
|
||||
List<LdapEntryIdentification> result = search(base, filter, searchControls, new LdapEntryIdentificationContextMapper());
|
||||
if (result.size() == 0) {
|
||||
String msg = "No results found for search, base: '" + base + "'; filter: '" + filter + "'.";
|
||||
log.info(msg);
|
||||
return false;
|
||||
} else if (result.size() > 1) {
|
||||
String msg = "base: '" + base + "'; filter: '" + filter + "'.";
|
||||
throw new IncorrectResultSizeDataAccessException(msg, 1, result.size());
|
||||
}
|
||||
|
||||
final LdapEntryIdentification entryIdentification = result.get(0);
|
||||
|
||||
try {
|
||||
DirContext ctx = contextSource.getContext(entryIdentification.getAbsoluteName().toString(), password);
|
||||
executeWithContext(new ContextExecutor<Object>() {
|
||||
public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException {
|
||||
callback.executeWithContext(ctx, entryIdentification);
|
||||
return null;
|
||||
}
|
||||
}, ctx);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.info("Authentication failed for entry with DN '" + entryIdentification.getAbsoluteName() + "'", e);
|
||||
errorCallback.execute(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T authenticate(LdapQuery query, String password, AuthenticatedLdapEntryContextMapper<T> mapper) {
|
||||
SearchControls searchControls = searchControlsForQuery(query, RETURN_OBJ_FLAG);
|
||||
ReturningAuthenticatedLdapEntryContext<T> mapperCallback =
|
||||
new ReturningAuthenticatedLdapEntryContext<T>(mapper);
|
||||
CollectingAuthenticationErrorCallback errorCallback =
|
||||
new CollectingAuthenticationErrorCallback();
|
||||
|
||||
boolean succeeded = authenticate(query.base(),
|
||||
query.filter().encode(),
|
||||
password,
|
||||
searchControls,
|
||||
mapperCallback,
|
||||
errorCallback);
|
||||
|
||||
if(errorCallback.hasError()) {
|
||||
Exception error = errorCallback.getError();
|
||||
|
||||
if (error instanceof NamingException) {
|
||||
throw (NamingException) error;
|
||||
} else {
|
||||
throw new UncategorizedLdapException(error);
|
||||
}
|
||||
} else if(!succeeded) {
|
||||
throw new AuthenticationException();
|
||||
}
|
||||
|
||||
return mapperCallback.collectedObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticate(LdapQuery query, String password) {
|
||||
authenticate(query,
|
||||
password,
|
||||
new NullAuthenticatedLdapEntryContextCallback());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.ldap.core.LdapOperations#searchForObject(javax.naming
|
||||
* .Name, java.lang.String, org.springframework.ldap.core.ContextMapper)
|
||||
*/
|
||||
public <T> T searchForObject(Name base, String filter, ContextMapper<T> mapper) {
|
||||
return searchForObject(base,
|
||||
filter,
|
||||
@@ -1564,12 +1618,17 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
|
||||
}
|
||||
|
||||
private static final class NullAuthenticatedLdapEntryContextCallback
|
||||
implements AuthenticatedLdapEntryContextCallback {
|
||||
implements AuthenticatedLdapEntryContextCallback, AuthenticatedLdapEntryContextMapper<Object>{
|
||||
public void executeWithContext(DirContext ctx,
|
||||
LdapEntryIdentification ldapEntryIdentification) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object mapWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class NullAuthenticationErrorCallback
|
||||
implements AuthenticationErrorCallback {
|
||||
@@ -1578,6 +1637,22 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ReturningAuthenticatedLdapEntryContext<T>
|
||||
implements AuthenticatedLdapEntryContextCallback {
|
||||
private final AuthenticatedLdapEntryContextMapper<T> mapper;
|
||||
|
||||
private T collectedObject;
|
||||
|
||||
private ReturningAuthenticatedLdapEntryContext(AuthenticatedLdapEntryContextMapper<T> mapper) {
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) {
|
||||
collectedObject = mapper.mapWithContext(ctx, ldapEntryIdentification);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> search(LdapQuery query, ContextMapper<T> mapper) {
|
||||
SearchControls searchControls = searchControlsForQuery(query, RETURN_OBJ_FLAG);
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package org.springframework.ldap.core.support;
|
||||
|
||||
import org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback;
|
||||
import org.springframework.ldap.core.AuthenticatedLdapEntryContextMapper;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.LdapEntryIdentification;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
|
||||
@@ -27,19 +29,29 @@ import javax.naming.directory.DirContext;
|
||||
* Attempts to perform an LDAP operation in the authenticated context, because
|
||||
* Active Directory might allow bind with incorrect password (specifically empty
|
||||
* password), and later refuse operations. We want to fail fast when
|
||||
* authenticating.
|
||||
* authenticating. {@link #mapWithContext(javax.naming.directory.DirContext, org.springframework.ldap.core.LdapEntryIdentification)}
|
||||
* returns the {@link DirContextOperations} instance that results from the lookup operation. This instance
|
||||
* can be used to obtain information regarding the authenticated user.
|
||||
*
|
||||
* @author Hugo Josefson
|
||||
* @author Mattias Hellborg Arthursson
|
||||
* @since 1.3.1
|
||||
*/
|
||||
public class LookupAttemptingCallback implements AuthenticatedLdapEntryContextCallback {
|
||||
public class LookupAttemptingCallback implements
|
||||
AuthenticatedLdapEntryContextCallback, AuthenticatedLdapEntryContextMapper<DirContextOperations> {
|
||||
@Override
|
||||
public void executeWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) {
|
||||
try {
|
||||
ctx.lookup(ldapEntryIdentification.getRelativeName());
|
||||
}
|
||||
catch (NamingException e) {
|
||||
// rethrow, because we aren't allowed to throw checked exceptions.
|
||||
throw LdapUtils.convertLdapException(e);
|
||||
}
|
||||
mapWithContext(ctx, ldapEntryIdentification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DirContextOperations mapWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) {
|
||||
try {
|
||||
return (DirContextOperations) ctx.lookup(ldapEntryIdentification.getRelativeName());
|
||||
}
|
||||
catch (NamingException e) {
|
||||
// rethrow, because we aren't allowed to throw checked exceptions.
|
||||
throw LdapUtils.convertLdapException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.springframework.ldap.query;
|
||||
|
||||
/**
|
||||
* Builder for and/or filters.
|
||||
* And/or filter builder support for LdapQuery.
|
||||
*
|
||||
* @author Mattias Hellborg Arthursson
|
||||
* @since 2.0
|
||||
|
||||
@@ -94,8 +94,8 @@ class DefaultContainerCriteria implements ContainerCriteria {
|
||||
|
||||
@Override
|
||||
public Filter filter() {
|
||||
|
||||
if(filters.size() == 1) {
|
||||
// No need to wrap in And/OrFilter if there's just one condition.
|
||||
return filters.iterator().next();
|
||||
}
|
||||
|
||||
|
||||
@@ -126,4 +126,8 @@ public class LdapQueryBuilderTest {
|
||||
query.base("dc=261consulting,dc=com");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void verifyThatOperatorChangeIsIllegal() {
|
||||
query().where("cn").is("John Doe").and("sn").is("Doe").or("objectclass").is("person");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ import javax.naming.directory.Attributes;
|
||||
import javax.naming.ldap.LdapName;
|
||||
import java.util.List;
|
||||
|
||||
import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
|
||||
/**
|
||||
* Default implementation of PersonDao. This implementation uses
|
||||
* DirContextAdapter for managing attribute values. We use a ContextMapper
|
||||
@@ -84,8 +86,9 @@ public class PersonDaoImpl implements PersonDao {
|
||||
|
||||
@Override
|
||||
public List<Person> findAll() {
|
||||
EqualsFilter filter = new EqualsFilter("objectclass", "person");
|
||||
return ldapTemplate.search(LdapUtils.emptyLdapName(), filter.encode(), PERSON_CONTEXT_MAPPER);
|
||||
return ldapTemplate.search(query()
|
||||
.where("objectclass").is("person"),
|
||||
PERSON_CONTEXT_MAPPER);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
111
src/docbkx/advancedqueries.xml
Normal file
111
src/docbkx/advancedqueries.xml
Normal file
@@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<chapter id="query-builder-advanced">
|
||||
<title>Advanced LDAP Queries</title>
|
||||
|
||||
<sect1>
|
||||
<title>LDAP Query Builder Parameters</title>
|
||||
|
||||
<para>The <literal>LdapQueryBuilder</literal> and its associated classes is intended to support all parameters
|
||||
that can be supplied to an LDAP search. The following parameters are supported:
|
||||
<itemizedlist>
|
||||
<listitem><literal>base</literal> - specifies the root DN in the LDAP tree where the search should start.</listitem>
|
||||
<listitem><literal>searchScope</literal> - specifies how deep into the LDAP tree the search should traverse.</listitem>
|
||||
<listitem><literal>attributes</literal> - specifies the attributes to return from the search. Default is all.</listitem>
|
||||
<listitem><literal>countLimit</literal> - specifies the maximum number of entries to return from the search.</listitem>
|
||||
<listitem><literal>timeLimit</literal> - specifies the maximum time that the search may take.</listitem>
|
||||
<listitem>Search filter - the conditions that the entries we are looking for must meet.</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
An <literal>LdapQueryBuilder</literal> is created with a call to the <literal>query</literal> method of
|
||||
<literal>LdapQueryBuilder</literal>. It's intended as a fluent builder API, where the base parameters are defined first,
|
||||
followed by the filter specification calls. Once filter conditions have been started to be defined with a call to the
|
||||
<literal>where</literal> method of <literal>LdapQueryBuilder</literal>, later attempts to call e.g. <literal>base</literal>
|
||||
will be rejected. The base search parameters are optional, but at least one filter specification call is required.
|
||||
</para>
|
||||
<example>
|
||||
<title>Search for all entries with objectclass person</title>
|
||||
<programlisting>import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
...
|
||||
|
||||
List<Person> persons = ldapTemplate.search(
|
||||
query().where("objectclass").is("person"),
|
||||
new PersonAttributesMapper());
|
||||
</programlisting>
|
||||
</example>
|
||||
<example>
|
||||
<title>Search for all entries with objectclass person and cn=John Doe</title>
|
||||
<programlisting>import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
...
|
||||
|
||||
List<Person> persons = ldapTemplate.search(
|
||||
query().where("objectclass").is("person")
|
||||
.and("cn").is("John Doe"),
|
||||
new PersonAttributesMapper());
|
||||
</programlisting>
|
||||
</example>
|
||||
<example>
|
||||
<title>Search for all entries with objectclass person starting at <literal>dc=261consulting,dc=com</literal></title>
|
||||
<programlisting>import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
...
|
||||
|
||||
List<Person> persons = ldapTemplate.search(
|
||||
query().base("dc=261consulting,dc=com")
|
||||
.where("objectclass").is("person"),
|
||||
new PersonAttributesMapper());
|
||||
</programlisting>
|
||||
</example>
|
||||
<example>
|
||||
<title>Search for all entries with objectclass person starting at <literal>dc=261consulting,dc=com</literal>,
|
||||
only returning the cn attribute</title>
|
||||
<programlisting>import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
...
|
||||
|
||||
List<Person> persons = ldapTemplate.search(
|
||||
query().base("dc=261consulting,dc=com")
|
||||
.attributes("cn")
|
||||
.where("objectclass").is("person"),
|
||||
new PersonAttributesMapper());
|
||||
</programlisting>
|
||||
</example>
|
||||
<example>
|
||||
<title>Search for all entries with objectclass person where sn=Doe or Doo (nested query)</title>
|
||||
<programlisting>import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
...
|
||||
List<Person> persons = ldapTemplate.search(
|
||||
query().where("objectclass").is("person"),
|
||||
.and(query().where("cn").is("Doe").or("cn").is("Doo));
|
||||
new PersonAttributesMapper());
|
||||
</programlisting>
|
||||
</example>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>Filter Criteria</title>
|
||||
<para>
|
||||
The examples above demonstrates simple equals conditions in LDAP filters. The LDAP query builder has support
|
||||
for the following criteria types:
|
||||
<itemizedlist>
|
||||
<listitem><literal>is</literal> - specifies an equals condition (=).</listitem>
|
||||
<listitem><literal>gte</literal> - specifies a greater than or equals condition (>=).</listitem>
|
||||
<listitem><literal>lte</literal> - specifies a less than or equals condition (<=).</listitem>
|
||||
<listitem>
|
||||
<literal>like</literal> - specifies a "like" condition where wildcards can be included in the query,
|
||||
e.g. <literal>where("cn").like("J*hn Doe")</literal> will result int the filter <literal>(cn=J*hn Doe)</literal>.
|
||||
</listitem>
|
||||
<listitem>
|
||||
<literal>whitespaceWildcardsLike</literal> - specifies a condition where all whitespace is replaced with wildcards,
|
||||
e.g. <literal>where("cn").whitespaceWildcardsLike("John Doe")</literal> will result in the filter
|
||||
<literal>(cn=*John*Doe*)</literal>.
|
||||
</listitem>
|
||||
<listitem>
|
||||
<literal>isPresent</literal> - specifies condition that checks for the presence of an attribute,
|
||||
e.g. <literal>where("cn").isPresent()</literal> will result in the filter <literal>(cn=*)</literal>.
|
||||
</listitem>
|
||||
<listitem>
|
||||
<literal>not</literal> - specifies that the current condition should be negated, e.g.
|
||||
<literal>where("sn").not().is("Doe)</literal> will result in the filter <literal>(!(sn=Doe))</literal>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
@@ -12,6 +12,7 @@
|
||||
<title>AttributesMapper that returns a single attribute</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
@@ -20,13 +21,13 @@ public class PersonDaoImpl implements PersonDao {
|
||||
this.ldapTemplate = ldapTemplate;
|
||||
}
|
||||
|
||||
public List getAllPersonNames() {
|
||||
return ldapTemplate.search(
|
||||
"", "(objectclass=person)",
|
||||
<emphasis role="bold"> new AttributesMapper() {
|
||||
public Object mapFromAttributes(Attributes attrs)
|
||||
public List<String> getAllPersonNames() {
|
||||
return ldapTemplate.search(query()
|
||||
.where("objectclass").is("person"),
|
||||
<emphasis role="bold"> new AttributesMapper<String>() {
|
||||
public String mapFromAttributes(Attributes attrs)
|
||||
throws NamingException {
|
||||
return attrs.get("cn").get();
|
||||
return (String) attrs.get("cn").get();
|
||||
}
|
||||
}</emphasis>);
|
||||
}
|
||||
@@ -49,12 +50,13 @@ public class PersonDaoImpl implements PersonDao {
|
||||
<title>AttributesMapper that returns a Person object</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
...
|
||||
<emphasis role="bold"> private class PersonAttributesMapper implements AttributesMapper {
|
||||
public Object mapFromAttributes(Attributes attrs) throws NamingException {
|
||||
<emphasis role="bold"> private class PersonAttributesMapper implements AttributesMapper<Person> {
|
||||
public Person mapFromAttributes(Attributes attrs) throws NamingException {
|
||||
Person person = new Person();
|
||||
person.setFullName((String)attrs.get("cn").get());
|
||||
person.setLastName((String)attrs.get("sn").get());
|
||||
@@ -63,8 +65,9 @@ public class PersonDaoImpl implements PersonDao {
|
||||
}
|
||||
}
|
||||
</emphasis>
|
||||
public List getAllPersons() {
|
||||
return ldapTemplate.search("", "(objectclass=person)", <emphasis
|
||||
public List<Person> getAllPersons() {
|
||||
return ldapTemplate.search(query()
|
||||
.where("objectclass").is("person"), <emphasis
|
||||
role="bold">new PersonAttributesMapper()</emphasis>);
|
||||
}
|
||||
}</programlisting>
|
||||
@@ -85,7 +88,7 @@ public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
...
|
||||
public Person findPerson(String dn) {
|
||||
return (Person) ldapTemplate.lookup(dn, new PersonAttributesMapper());
|
||||
return ldapTemplate.lookup(dn, new PersonAttributesMapper());
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
@@ -95,31 +98,37 @@ public class PersonDaoImpl implements PersonDao {
|
||||
this case resulting in a <literal>Person</literal> object.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="basic-filters">
|
||||
<title>Building Dynamic Filters</title>
|
||||
|
||||
<para>We can build dynamic filters to use in searches, using the classes
|
||||
from the <literal>org.springframework.ldap.filter</literal>
|
||||
package. Let's say that we want the following filter:
|
||||
<sect1 id="basic-queries">
|
||||
<title>Building LDAP Queries</title>
|
||||
<para>LDAP searches involve a number of parameters, e.g. Base LDAP path,
|
||||
search scope, attributes to return, and search filters.</para>
|
||||
<para>Spring LDAP provides an <literal>LdapQueryBuilder</literal> with a fluent
|
||||
API for building LDAP Queries.</para>
|
||||
<para>Let's say that we want to perform a search starting at the
|
||||
base DN <literal>dc=261consulting,dc=com</literal>, limiting the returned attributes to "cn"
|
||||
and "sn", with the following filter:
|
||||
<literal>(&(objectclass=person)(sn=?))</literal>, where we want the
|
||||
<literal>?</literal> to be replaced with the value of the parameter
|
||||
<literal>lastName</literal>. This is how we do it using the filter support
|
||||
classes:</para>
|
||||
<literal>lastName</literal>. This is how we do it using the LdapQueryBuilder:</para>
|
||||
|
||||
<example>
|
||||
<title>Building a search filter dynamically</title>
|
||||
|
||||
<programlisting>package com.example.dao;
|
||||
import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
...
|
||||
public List getPersonNamesByLastName(String lastName) {
|
||||
<emphasis role="bold"> AndFilter filter = new AndFilter();
|
||||
filter.and(new EqualsFilter("objectclass", "person"));
|
||||
filter.and(new EqualsFilter("sn", lastName));
|
||||
</emphasis> return ldapTemplate.search(
|
||||
"", <emphasis role="bold">filter.encode()</emphasis>,
|
||||
<emphasis role="bold">
|
||||
LdapQuery query = query()
|
||||
.base("dc=261consulting,dc=com")
|
||||
.attributes("cn", "sn")
|
||||
.where("objectclass").is("person")
|
||||
.and("sn").is(lastName);
|
||||
</emphasis>
|
||||
return ldapTemplate.search(query,
|
||||
new AttributesMapper() {
|
||||
public Object mapFromAttributes(Attributes attrs)
|
||||
throws NamingException {
|
||||
@@ -129,30 +138,31 @@ public class PersonDaoImpl implements PersonDao {
|
||||
}
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>To perform a wildcard search, it's possible to use the
|
||||
<literal>WhitespaceWildcardsFilter</literal>:</para>
|
||||
|
||||
<example>
|
||||
<title>Building a wildcard search filter</title>
|
||||
|
||||
<programlisting>AndFilter filter = new AndFilter();
|
||||
filter.and(new EqualsFilter("objectclass", "person"));
|
||||
filter.and(new WhitespaceWildcardsFilter("cn", cn));</programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
<note>
|
||||
In addition to simplifying building of complex search filters,
|
||||
the <literal>Filter</literal> classes also provide proper escaping
|
||||
of any unsafe characters. This prevents "ldap injection",
|
||||
where a user might use such characters to inject unwanted operations
|
||||
into your LDAP operations.
|
||||
In addition to simplifying building of complex search parameters,
|
||||
the <literal>LdapQueryBuilder</literal> and its associated classes
|
||||
also provide proper escaping of any unsafe characters in search filters.
|
||||
This prevents "ldap injection", where a user might use such
|
||||
characters to inject unwanted operations into your LDAP operations.
|
||||
</note>
|
||||
<note>
|
||||
There are many overloaded methods in <literal>LdapTemplate</literal> for
|
||||
performing LDAP searches. This is in order to accommodate for as many different use cases
|
||||
and programming style preferences as possible. For the vast majority of use cases the ones that
|
||||
take an <literal>LdapQuery</literal> as input will be the recommended methods to use.
|
||||
</note>
|
||||
<note>
|
||||
The <literal>AttributesMapper</literal> is just one of the available callback interfaces to use
|
||||
when handling search and lookup data. See <xref linkend="dirobjectfactory" /> for alternatives.
|
||||
</note>
|
||||
</para>
|
||||
<para>
|
||||
For more information on the <literal>LdapQueryBuilder</literal> see <xref linkend="query-builder-advanced" />.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<sect1 id="ldap-names">
|
||||
<title>Dynamically Building Distinguished Names</title>
|
||||
<para>
|
||||
The standard Java implementation of Distinguished Name, <ulink
|
||||
@@ -242,9 +252,9 @@ public class PersonDaoImpl implements PersonDao {
|
||||
...
|
||||
protected Person buildPerson(Name dn, Attributes attrs) {
|
||||
Person person = new Person();
|
||||
person.setCountry(<emphasis>LdapUtils.getStringValue(dn, "c")</emphasis>);
|
||||
person.setCompany(<emphasis>LdapUtils.getStringValue(dn, "ou")</emphasis>);
|
||||
person.setFullname(<emphasis>LdapUtils.getStringValue(dn, "cn")</emphasis>);
|
||||
person.setCountry(<emphasis role="bold">LdapUtils.getStringValue(dn, "c")</emphasis>);
|
||||
person.setCompany(<emphasis role="bold">LdapUtils.getStringValue(dn, "ou")</emphasis>);
|
||||
person.setFullname(<emphasis role="bold">LdapUtils.getStringValue(dn, "cn")</emphasis>);
|
||||
// Populate rest of person object using attributes.
|
||||
|
||||
return person;
|
||||
@@ -253,7 +263,7 @@ protected Person buildPerson(Name dn, Attributes attrs) {
|
||||
</example>
|
||||
Since Java version <=1.4 didn't provide any public Distinguished Name implementation at all, Spring LDAP
|
||||
1.3.2 and lower provided its own implementation, <literal>DistinguishedName</literal>. This implementation
|
||||
suffered from a couple of shortcomings of its own, and have been deprecated in version 2.0.
|
||||
suffered from a couple of shortcomings of its own, and has been deprecated in version 2.0.
|
||||
Users are now recommended to use <literal>LdapName</literal> along with the utilities described above instead.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Mattias</firstname>
|
||||
<surname>Arthursson</surname>
|
||||
<surname>Hellborg Arthursson</surname>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Ulrik</firstname>
|
||||
@@ -41,6 +41,7 @@
|
||||
<xi:include href="overview.xml" />
|
||||
<xi:include href="basic.xml" />
|
||||
<xi:include href="dirobjectfactory.xml" />
|
||||
<xi:include href="advancedqueries.xml" />
|
||||
<xi:include href="executors.xml" />
|
||||
<xi:include href="contextprocessor.xml" />
|
||||
<xi:include href="transactions.xml" />
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<literal>NamingEnumeration</literal>. It also provides a more
|
||||
comprehensive unchecked Exception hierarchy, built on Spring's
|
||||
<literal>DataAccessException</literal>. As a bonus, it also contains
|
||||
classes for dynamically building LDAP filters and DNs (Distinguished
|
||||
classes for dynamically building LDAP queries and DNs (Distinguished
|
||||
Names), LDAP attribute management, and client-side LDAP transaction management.</para>
|
||||
|
||||
<para>Consider, for example, a method that should search some storage for
|
||||
@@ -96,6 +96,7 @@ public class TraditionalPersonDaoImpl implements PersonDao {
|
||||
|
||||
<informalexample>
|
||||
<programlisting>package com.example.dao;
|
||||
import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
|
||||
public class PersonDaoImpl implements PersonDao {
|
||||
private LdapTemplate ldapTemplate;
|
||||
@@ -106,7 +107,7 @@ public class PersonDaoImpl implements PersonDao {
|
||||
|
||||
public List getAllPersonNames() {
|
||||
return ldapTemplate.<emphasis role="bold">search(
|
||||
"", "(objectclass=person)"</emphasis>,
|
||||
query().where("objectclass").is("person")</emphasis>,
|
||||
new AttributesMapper() {
|
||||
public Object mapFromAttributes(Attributes attrs)
|
||||
throws NamingException {
|
||||
@@ -202,10 +203,6 @@ public class PersonDaoImpl implements PersonDao {
|
||||
<listitem>
|
||||
<para><emphasis>spring-jdbc</emphasis> (If you are planning to use the client side compensating transaction support)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>ldapbp</emphasis> (Sun LDAP Booster Pack - if you will use the LDAP v3 Server controls integration
|
||||
and you're not using Java5 or higher)</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>commons-pool</emphasis> (If you are planning to use the pooling functionality)</para>
|
||||
</listitem>
|
||||
@@ -216,330 +213,63 @@ public class PersonDaoImpl implements PersonDao {
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1 id="introduction-package-structure">
|
||||
<title>Package structure</title>
|
||||
|
||||
<para>This section provides an overview of the logical package structure
|
||||
of the Spring LDAP codebase. The dependencies for each package are clearly
|
||||
noted.</para>
|
||||
|
||||
<figure>
|
||||
<title>Spring LDAP package structure</title>
|
||||
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="src/docbkx/resources/images/package-dependencies.png"
|
||||
format="PNG" align="center" />
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="images/package-dependencies.png"
|
||||
format="PNG" align="center" />
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</figure>
|
||||
|
||||
<sect2 id="transaction.compensating">
|
||||
<title>org.springframework.transaction.compensating</title>
|
||||
|
||||
<para>The <emphasis>transaction.compensating</emphasis> package contains
|
||||
the generic compensating transaction support. This is not LDAP-specific
|
||||
or JNDI-specific in any way.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: commons-logging</para>
|
||||
</listitem>
|
||||
<sect1 id="new-in-20">
|
||||
<title>What's new in Spring LDAP 2.0?</title>
|
||||
<para>
|
||||
While quite significant modernizations have been made to the Spring LDAP APi in version 2.0, great care has been
|
||||
taken to ensure backward compatibility as far as possible.
|
||||
Code that works with Spring LDAP 1.3.x should with very few exceptions still compile and run using the 2.0 libraries
|
||||
without any modifications whatsoever.
|
||||
</para>
|
||||
<para>
|
||||
The exception is a small number of classes that have been moved to new packages in order to make
|
||||
a couple of important refactorings possible. The moved classes are usually not part of the intended
|
||||
public API, and the migration procedure should be very smooth - wherever a Spring LDAP class cannot be found
|
||||
after upgrade, just organize the imports in your IDE.
|
||||
</para>
|
||||
<para>
|
||||
You will probably encounter some deprecation warnings though, and there are also a lot of other API improvements.
|
||||
The recommendation for getting as much as possible out of the 2.0 version is to move away from the deprecated
|
||||
classes and methods and migrate to the new, improved API utilities.
|
||||
</para>
|
||||
<para>
|
||||
Below is a list of the most important changes in Spring LDAP 2.0.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>Java 1.6 is now required when using Spring LDAP. Spring versions starting at 2.0 and up are still supported.</listitem>
|
||||
<listitem>
|
||||
The central API has been updated with Java 5 features such as generics and varargs. As a consequence,
|
||||
the entire <literal>spring-ldap-tiger</literal> module has been deprecated and users are encouraged to migrate
|
||||
to use the core Spring LDAP classes. The parameterization of the core interfaces will most likely cause
|
||||
lots of compilation warnings, and you are obviously encouraged to take appropriate action to get rid
|
||||
of these warning.
|
||||
</listitem>
|
||||
<listitem>
|
||||
<literal>DistinguishedName</literal> and associated classes have been deprecated in favor of standard
|
||||
Java <literal>LdapName</literal>. See <xref linkend="ldap-names" /> for information on how the library
|
||||
helps working with <literal>LdapNames</literal>.
|
||||
</listitem>
|
||||
<listitem>
|
||||
Fluent LDAP query support has been added. This makes for a more pleasant programming experience when
|
||||
working with LDAP searches in Spring LDAP. See <xref linkend="basic-queries" /> and
|
||||
<xref linkend="query-builder-advanced" /> for more information about the LDAP query builder support.
|
||||
</listitem>
|
||||
<listitem>
|
||||
The old <literal>authenticate</literal> methods in <literal>LdapTemplate</literal> have been deprecated
|
||||
in favor of a couple of new <literal>authenticate</literal> methods that work with
|
||||
<literal>LdapQuery</literal> objects and <emphasis>throw exceptions</emphasis> on authentication failure,
|
||||
making it easier for the user to find out what caused an authentication attempt to fail.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap">
|
||||
<title>org.springframework.ldap</title>
|
||||
|
||||
<para>The <emphasis>ldap</emphasis> package contains the exceptions of
|
||||
the library. These exceptions form an unchecked hierarchy that mirrors
|
||||
the NamingException hierarchy.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: spring-core</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.core">
|
||||
<title>org.springframework.ldap.core</title>
|
||||
|
||||
<para>The <emphasis>ldap.core</emphasis> package contains the central
|
||||
abstractions of the library. These abstractions include
|
||||
AuthenticationSource, ContextSource, DirContextProcessor, and
|
||||
NameClassPairCallbackHandler. This package also contains the central
|
||||
class LdapTemplate, plus various mappers and executors.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap, ldap.support, spring-beans,
|
||||
spring-core, spring-tx, commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.core.support">
|
||||
<title>org.springframework.ldap.core.support</title>
|
||||
|
||||
<para>The <emphasis>ldap.core.support</emphasis> package contains
|
||||
supporting implementations of some of the core interfaces.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap, ldap.core, ldap.support, spring-core,
|
||||
spring-beans, spring-context, commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.core.simple">
|
||||
<title>org.springframework.ldap.core.simple</title>
|
||||
|
||||
<para>The <emphasis>ldap.core.simple</emphasis> package contains
|
||||
Java5-specific parts of Spring LDAP. It's mainly a simplification
|
||||
layer that takes advantage of the generics support in Java5, in
|
||||
order to get typesafe context mappers as well as typesafe search
|
||||
and lookup methods.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.pool">
|
||||
<title>org.springframework.ldap.pool</title>
|
||||
|
||||
<para>The <emphasis>ldap.pool</emphasis> package contains
|
||||
support for detailed pool configuration on a per-ContextSource
|
||||
basis. Pooling support is provided by PoolingContextSource which
|
||||
can wrap any ContextSource and pool both read-only and read-write
|
||||
DirContext objects. Jakarta Commons-Pool is used to provide the
|
||||
underlying pool implementation.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core, commons-lang, commons-pool</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.pool.factory">
|
||||
<title>org.springframework.ldap.pool.factory</title>
|
||||
|
||||
<para>The <emphasis>ldap.pool.factory</emphasis> package contains
|
||||
the actual pooling context source and other classes for context creation.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap, ldap.core, ldap.pool, ldap.pool.validation,
|
||||
spring-beans, spring-tx, commons-lang, commons-logging, commons-pool</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.pool.validation">
|
||||
<title>org.springframework.ldap.pool.validation</title>
|
||||
|
||||
<para>The <emphasis>ldap.pool.validation</emphasis> package contains
|
||||
the connection validation support.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.pool, commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.support">
|
||||
<title>org.springframework.ldap.support</title>
|
||||
|
||||
<para>The <emphasis>ldap.support</emphasis> package contains supporting
|
||||
utilities, like the exception translation mechanism.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap, spring-core, commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.authentication">
|
||||
<title>org.springframework.ldap.authentication</title>
|
||||
|
||||
<para>The <emphasis>ldap.authentication</emphasis> package contains an
|
||||
implementation of the AuthenticationSource interface that can be used
|
||||
if the user should be allowed to read some information even though not
|
||||
logged in.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core, spring-beans, commons-lang</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.control">
|
||||
<title>org.springframework.ldap.control</title>
|
||||
|
||||
<para>The <emphasis>ldap.control</emphasis> package contains an abstract
|
||||
implementation of the DirContextProcessor interface that can be used as
|
||||
a basis for processing RequestControls and ResponseControls. There is
|
||||
also a concrete implementation that handles paged search results and one
|
||||
that handles sorting. The
|
||||
<ulink url="http://java.sun.com/products/jndi/">LDAP Booster
|
||||
Pack</ulink> is used to get support for controls, unless Java5 is used.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap, ldap.core, LDAP booster pack (optional), spring-core,
|
||||
commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.filter">
|
||||
<title>org.springframework.ldap.filter</title>
|
||||
|
||||
<para>The <emphasis>ldap.filter</emphasis> package contains the Filter
|
||||
abstraction and several implementations of it.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core, spring-core, commons-lang</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.transaction.compensating">
|
||||
<title>org.springframework.ldap.transaction.compensating</title>
|
||||
|
||||
<para>The <emphasis>ldap.transaction.compensating</emphasis> package contains the
|
||||
core LDAP-specific implementation of compensating transactions.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core, ldap.core.support, transaction.compensating,
|
||||
spring-core, commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.transaction.compensating.manager">
|
||||
<title>org.springframework.ldap.transaction.compensating.manager</title>
|
||||
|
||||
<para>The <emphasis>ldap.transaction.compensating.manager</emphasis> package contains the
|
||||
core implementation classes for client-side compensating transactions.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap, ldap.core, ldap.support, ldap.transaction.compensating,
|
||||
ldap.transaction.compensating.support, transaction.compensating,
|
||||
spring-tx, spring-jdbc, spring-orm, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.transaction.compensating.support">
|
||||
<title>org.springframework.ldap.transaction.compensating.support</title>
|
||||
|
||||
<para>The <emphasis>ldap.transaction.compensating.support</emphasis> package contains
|
||||
useful helper classes for client-side compensating transactions.</para>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core, ldap.transaction.compensating</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.ldif">
|
||||
<title>org.springframework.ldap.ldif</title>
|
||||
|
||||
<para>The ldap.ldif package provides support for parsing LDIF
|
||||
files.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.ldif.batch">
|
||||
<title>org.springframework.ldap.ldif.batch</title>
|
||||
|
||||
<para>The ldap.ldif.batch package provides the classes necessary to
|
||||
use the LDIF parser in the Spring Batch framework.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core, ldap.ldif.parser, spring-batch,
|
||||
spring-core, spring-beans, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.ldif.parser">
|
||||
<title>org.springframework.ldap.ldif.parser</title>
|
||||
|
||||
<para>The ldap.ldif.parser package provides the parser classes
|
||||
and interfaces.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core, ldap.schema, ldap.ldif, ldap.ldif.support,
|
||||
spring-core, spring-beans, commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.ldif.support">
|
||||
<title>org.springframework.ldap.ldif.support</title>
|
||||
|
||||
<para>The ldap.ldif.support package provides the necessary auxiliary
|
||||
classes utilized by the LDIF Parser.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Dependencies: ldap.core, ldap.ldif, commons-lang, commons-logging</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="ldap.odm">
|
||||
<title>org.springframework.ldap.odm</title>
|
||||
|
||||
<para>The ldap.odm package provides the classes and interfaces
|
||||
enabling
|
||||
annotation based object-directory mapping.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Dependencies: ldap, ldap.core, ldap.core.simple, ldap.filter, spring-beans,
|
||||
commons-cli, commons-logging, freemarker</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2>
|
||||
|
||||
<para>For the exact list of jar dependencies, see the Spring LDAP Maven2
|
||||
Project Object Model (POM) files in the source tree.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="introduction-support">
|
||||
<title>Support</title>
|
||||
|
||||
<para>Spring LDAP 1.3 is supported on Spring 2.0 and later.</para>
|
||||
<para>Spring LDAP 2.0 is supported on Spring 2.0 and later.</para>
|
||||
|
||||
<para>The community support forum is located at <ulink
|
||||
url="http://forum.springframework.org">http://forum.springframework.org</ulink>,
|
||||
url="http://forum.spring.io/forum/spring-projects/data/ldap">http://forum.spring.io/forum/spring-projects/data/ldap</ulink>,
|
||||
and the project web page is <ulink
|
||||
url="http://www.springframework.org/ldap">http://www.springframework.org/ldap</ulink>.</para>
|
||||
url="http://projects.spring.io/spring-ldap/">http://projects.spring.io/spring-ldap/</ulink>.</para>
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
<property name="ldapTemplate" ref="ldapTemplate" />
|
||||
</bean>
|
||||
|
||||
<tx:annotation-driven>
|
||||
<tx:annotation-driven />
|
||||
|
||||
...</programlisting>
|
||||
<note>While the this setup will work fine for most simple use cases, some more complex scenarios will
|
||||
|
||||
@@ -35,8 +35,7 @@
|
||||
LDAP search based on e.g. the user name to get this DN:</para>
|
||||
|
||||
<para><programlisting>private String getDnForUser(String uid) {
|
||||
Filter f = new EqualsFilter("uid", uid);
|
||||
List result = ldapTemplate.search(LdapUtils.emptyLdapName(), f.toString(),
|
||||
List result = ldapTemplate.search(query().where("uid").is(uid),
|
||||
new AbstractContextMapper() {
|
||||
protected Object doMapFromContext(DirContextOperations ctx) {
|
||||
return ctx.getNameInNamespace();
|
||||
@@ -52,29 +51,15 @@
|
||||
forced to concern herself with the DN of the user, she can only search for
|
||||
the user's uid, and the search always starts at the root of the tree (the
|
||||
empty path). A more flexible method would let the user specify the search
|
||||
base, the search filter, and the credentials. Spring LDAP 1.3.0 introduced
|
||||
new authenticate methods in LdapTemplate that provide this
|
||||
functionality:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>boolean authenticate(Name base, String filter, String
|
||||
password);</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>boolean authenticate(String base, String filter, String
|
||||
password);</literal></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Using one of these methods, authentication becomes as simple as
|
||||
this:</para>
|
||||
base, the search filter, and the credentials. Spring LDAP includes an authenticate
|
||||
method in LdapTemplate that provide this functionality: <literal>boolean authenticate(LdapQuery query, String password);</literal>
|
||||
</para>
|
||||
<para>Using this method authentication becomes as simple as this:</para>
|
||||
|
||||
<para><example>
|
||||
<title>Authenticating a user using Spring LDAP.</title>
|
||||
|
||||
<programlisting>boolean authenticated = ldapTemplate.authenticate("", "(uid=john.doe)", "secret");</programlisting>
|
||||
<programlisting>ldapTemplate.authenticate(query().where("uid").is("john.doe"), "secret");</programlisting>
|
||||
</example>
|
||||
<note>
|
||||
As described in below, some setups may require additional operations to be performed
|
||||
@@ -116,25 +101,18 @@
|
||||
// It is imperative that the created DirContext instance is always closed
|
||||
LdapUtils.closeContext(ctx);
|
||||
}
|
||||
}</programlisting>It would be better if the operation could be provided as an
|
||||
}</programlisting>
|
||||
It would be better if the operation could be provided as an
|
||||
implementation of a callback interface, thus not limiting the operation to
|
||||
always be a <literal>lookup</literal>. Spring LDAP 1.3.0 introduced the
|
||||
callback interface
|
||||
<literal>AuthenticatedLdapEntryContextCallback</literal> and a few
|
||||
corresponding <literal>authenticate</literal> methods:</para>
|
||||
always be a <literal>lookup</literal>. Spring LDAP includes the callback interface
|
||||
<literal>AuthenticatedLdapEntryContextMapper</literal> and a
|
||||
corresponding <literal>authenticate</literal> method:
|
||||
<literal><T> T authenticate(LdapQuery query, String password, AuthenticatedLdapEntryContextMapper<T> mapper);</literal></para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>boolean authenticate(Name base, String filter, String
|
||||
password, AuthenticatedLdapEntryContextCallback
|
||||
callback);</literal></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>boolean authenticate(String base, String filter, String
|
||||
password, AuthenticatedLdapEntryContextCallback
|
||||
callback);</literal></para>
|
||||
</listitem>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>This opens up for any operation to be performed on the authenticated
|
||||
@@ -144,83 +122,30 @@
|
||||
<title>Performing an LDAP operation on the authenticated context using
|
||||
Spring LDAP.</title>
|
||||
|
||||
<programlisting>AuthenticatedLdapEntryContextCallback contextCallback = new AuthenticatedLdapEntryContextCallback() {
|
||||
public void executeWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) {
|
||||
<programlisting>AuthenticatedLdapEntryContextMapper<DirContextOperations> mapper = new AuthenticatedLdapEntryContextMapper<DirContextOperations>() {
|
||||
public DirContextOperations mapWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) {
|
||||
try {
|
||||
ctx.lookup(ldapEntryIdentification.getRelativeDn());
|
||||
return (DirContextOperations) ctx.lookup(ldapEntryIdentification.getRelativeName());
|
||||
}
|
||||
catch (NamingException e) {
|
||||
throw new RuntimeException("Failed to lookup " + ldapEntryIdentification.getRelativeDn(), e);
|
||||
throw new RuntimeException("Failed to lookup " + ldapEntryIdentification.getRelativeName(), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ldapTemplate.authenticate("", "(uid=john.doe)", "secret", contextCallback));</programlisting>
|
||||
ldapTemplate.authenticate(query().where("uid").is("john.doe"), "secret", mapper);</programlisting>
|
||||
</example>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Retrieving the Authentication Exception</title>
|
||||
<title>Obsolete authentication methods</title>
|
||||
|
||||
<para>So far, the methods have only been able to tell the user whether or
|
||||
not the authentication succeeded. There has been no way of retrieving the
|
||||
actual exception. Spring LDAP 1.3.1 introduced the
|
||||
<literal>AuthenticationErrorCallback</literal> and a few more
|
||||
<literal>authenticate</literal> methods:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>boolean authenticate(Name base, String filter, String
|
||||
password, AuthenticationErrorCallback errorCallback);</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>boolean authenticate(String base, String filter, String
|
||||
password, AuthenticationErrorCallback errorCallback);</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>boolean authenticate(Name base, String filter, String
|
||||
password, AuthenticatedLdapEntryContextCallback callback,
|
||||
AuthenticationErrorCallback errorCallback);</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>boolean authenticate(String base, String filter, String
|
||||
password, AuthenticatedLdapEntryContextCallback callback,
|
||||
AuthenticationErrorCallback errorCallback);</literal></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>A convenient collecting implementation of the error callback
|
||||
interface is also provided:</para>
|
||||
|
||||
<para><programlisting>public final class CollectingAuthenticationErrorCallback implements AuthenticationErrorCallback {
|
||||
private Exception error;
|
||||
|
||||
public void execute(Exception e) {
|
||||
this.error = e;
|
||||
}
|
||||
|
||||
public Exception getError() {
|
||||
return error;
|
||||
}
|
||||
}</programlisting>The code needed for authenticating a user and retrieving the
|
||||
authentication exception in case of an error boils down to this:</para>
|
||||
|
||||
<para><example>
|
||||
<title>Authenticating a user and retrieving the authentication
|
||||
exception.</title>
|
||||
|
||||
<programlisting>import org.springframework.ldap.core.support.CollectingAuthenticationErrorCallback;
|
||||
...
|
||||
CollectingAuthenticationErrorCallback errorCallback = new CollectingAuthenticationErrorCallback();
|
||||
boolean result = ldapTemplate.authenticate("", filter.toString(), "invalidpassword", errorCallback);
|
||||
if (!result) {
|
||||
Exception error = errorCallback.getError();
|
||||
// error is likely of type org.springframework.ldap.AuthenticationException
|
||||
}</programlisting>
|
||||
</example></para>
|
||||
<para>
|
||||
In addition to the <literal>authenticate</literal> methods described above
|
||||
there are a number of deprecated methods that can be used for authentication.
|
||||
While these will work fine, the recommendation is to use the
|
||||
<literal>LdapQuery</literal> methods instead.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
|
||||
@@ -16,29 +16,31 @@
|
||||
|
||||
package org.springframework.ldap.itest;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.ldap.AuthenticationException;
|
||||
import org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback;
|
||||
import org.springframework.ldap.core.CollectingAuthenticationErrorCallback;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.LdapEntryIdentification;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.ldap.core.support.CollectingAuthenticationErrorCallback;
|
||||
import org.springframework.ldap.core.support.LookupAttemptingCallback;
|
||||
import org.springframework.ldap.filter.AndFilter;
|
||||
import org.springframework.ldap.filter.EqualsFilter;
|
||||
import org.springframework.ldap.filter.WhitespaceWildcardsFilter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.ldap.query.LdapQueryBuilder.query;
|
||||
|
||||
/**
|
||||
* Tests the authenticate methods of LdapTemplate.
|
||||
*
|
||||
@@ -58,14 +60,34 @@ public class LdapTemplateAuthenticationITest extends AbstractLdapTemplateIntegra
|
||||
assertTrue(tested.authenticate("", filter.toString(), "password"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test
|
||||
public void testAuthenticateWithLdapQuery() {
|
||||
AndFilter filter = new AndFilter();
|
||||
filter.and(new EqualsFilter("objectclass", "person")).and(new EqualsFilter("uid", "some.person3"));
|
||||
tested.authenticate(query()
|
||||
.where("objectclass").is("person")
|
||||
.and("uid").is("some.person3"),
|
||||
"password");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateWithInvalidPassword() {
|
||||
AndFilter filter = new AndFilter();
|
||||
filter.and(new EqualsFilter("objectclass", "person")).and(new EqualsFilter("uid", "some.person3"));
|
||||
assertFalse(tested.authenticate("", filter.toString(), "invalidpassword"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected = AuthenticationException.class)
|
||||
public void testAuthenticateWithLdapQueryAndInvalidPassword() {
|
||||
AndFilter filter = new AndFilter();
|
||||
filter.and(new EqualsFilter("objectclass", "person")).and(new EqualsFilter("uid", "some.person3"));
|
||||
tested.authenticate(query()
|
||||
.where("objectclass").is("person")
|
||||
.and("uid").is("some.person3"),
|
||||
"invalidpassword");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateWithLookupOperationPerformedOnAuthenticatedContext() {
|
||||
AndFilter filter = new AndFilter();
|
||||
filter.and(new EqualsFilter("objectclass", "person")).and(new EqualsFilter("uid", "some.person3"));
|
||||
@@ -83,7 +105,28 @@ public class LdapTemplateAuthenticationITest extends AbstractLdapTemplateIntegra
|
||||
assertTrue(tested.authenticate("", filter.toString(), "password", contextCallback));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test
|
||||
public void testAuthenticateWithLdapQueryAndMapper() {
|
||||
DirContextOperations ctx = tested.authenticate(query()
|
||||
.where("objectclass").is("person")
|
||||
.and("uid").is("some.person3"),
|
||||
"password",
|
||||
new LookupAttemptingCallback());
|
||||
|
||||
Assert.assertNotNull(ctx);
|
||||
assertEquals("some.person3", ctx.getStringAttribute("uid"));
|
||||
}
|
||||
|
||||
@Test(expected = AuthenticationException.class)
|
||||
public void testAuthenticateWithLdapQueryAndMapperAndInvalidPassword() {
|
||||
DirContextOperations ctx = tested.authenticate(query()
|
||||
.where("objectclass").is("person")
|
||||
.and("uid").is("some.person3"),
|
||||
"invalidpassword",
|
||||
new LookupAttemptingCallback());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticateWithInvalidPasswordAndCollectedException() {
|
||||
AndFilter filter = new AndFilter();
|
||||
filter.and(new EqualsFilter("objectclass", "person")).and(new EqualsFilter("uid", "some.person3"));
|
||||
|
||||
Reference in New Issue
Block a user