SEC-264: changes to LDAP services.

This commit is contained in:
Luke Taylor 2006-05-15 20:53:10 +00:00
parent db042046e9
commit 65fe641900
22 changed files with 441 additions and 387 deletions

View File

@ -0,0 +1,31 @@
/* Copyright 2004, 2005 Acegi Technology Pty Limited
*
* 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.acegisecurity.ldap;
import javax.naming.directory.Attributes;
import javax.naming.NamingException;
/**
* A mapper for use with {@link LdapTemplate}. Creates a customized object from
* a set of attributes retrieved from a directory entry.
*
* @author Luke Taylor
* @version $Id$
*/
public interface LdapEntryMapper {
public Object mapAttributes(String dn, Attributes attributes) throws NamingException;
}

View File

@ -25,7 +25,10 @@ import javax.naming.directory.Attributes;
import javax.naming.directory.Attribute;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.util.Set;
import java.util.HashSet;
@ -45,37 +48,66 @@ public class LdapTemplate {
public static final String[] NO_ATTRS = new String[0];
private InitialDirContextFactory dirContextFactory;
private String managerDn = null;
private String principalDn = null;
private String password = null;
/** Default search scope */
private int searchScope = SearchControls.SUBTREE_SCOPE;
/** Default search controls */
private SearchControls searchControls = new SearchControls();
public LdapTemplate(InitialDirContextFactory dirContextFactory) {
Assert.notNull(dirContextFactory, "An InitialDirContextFactory is required");
this.dirContextFactory = dirContextFactory;
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
}
/**
*
* @param dirContextFactory the source of DirContexts
* @param userDn the user name to authenticate as when obtaining new contexts
* @param password the user's password
*/
public LdapTemplate(InitialDirContextFactory dirContextFactory, String userDn, String password) {
this(dirContextFactory);
Assert.hasLength(userDn, "managerDn must not be null or empty");
Assert.hasLength(userDn, "userDn must not be null or empty");
Assert.notNull(password, "password cannot be null");
this.managerDn = userDn;
this.principalDn = userDn;
this.password = password;
}
public void setSearchScope(int searchScope) {
this.searchScope = searchScope;
searchControls.setSearchScope(searchScope);
}
/**
* The time (in milliseconds) which to wait before the search fails;
* the default is zero, meaning forever.
*/
public void setSearchTimeLimit(int searchTimeLimit) {
searchControls.setTimeLimit(searchTimeLimit);
}
/**
* Sets the corresponding property on the SearchControls instance used
* in the search.
*
*/
public void setDerefLinkFlag(boolean deref) {
searchControls.setDerefLinkFlag(deref);
}
public void setSearchControls(SearchControls searchControls) {
this.searchControls = searchControls;
}
public Object execute(LdapCallback callback) throws DataAccessException {
DirContext ctx = null;
try {
ctx = (managerDn == null) ?
ctx = (principalDn == null) ?
dirContextFactory.newInitialDirContext() :
dirContextFactory.newInitialDirContext(managerDn, password);
dirContextFactory.newInitialDirContext(principalDn, password);
return callback.execute(ctx);
@ -98,8 +130,10 @@ public class LdapTemplate {
ctls.setReturningAttributes(NO_ATTRS);
ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
String relativeName = LdapUtils.getRelativeName(dn, ctx);
NamingEnumeration results =
ctx.search(dn, comparisonFilter, new Object[]{value}, ctls);
ctx.search(relativeName, comparisonFilter, new Object[]{value}, ctls);
return Boolean.valueOf(results.hasMore());
}
@ -132,7 +166,9 @@ public class LdapTemplate {
SearchControls ctls = new SearchControls();
ctls.setSearchScope(searchScope);
ctls.setSearchScope(searchControls.getSearchScope());
ctls.setTimeLimit(searchControls.getTimeLimit());
ctls.setDerefLinkFlag(searchControls.getDerefLinkFlag());
ctls.setReturningAttributes(new String[] {attributeName});
NamingEnumeration matchingEntries =
@ -191,13 +227,65 @@ public class LdapTemplate {
* @param attributesToRetrieve the named attributes which will be retrieved from the directory entry.
* @return the object created by the mapper
*/
public Object retrieveEntry(final String dn, final AttributesMapper mapper, final String[] attributesToRetrieve) {
public Object retrieveEntry(final String dn, final LdapEntryMapper mapper, final String[] attributesToRetrieve) {
return execute ( new LdapCallback() {
public Object execute(DirContext ctx) throws NamingException {
return mapper.mapAttributes( ctx.getAttributes(LdapUtils.getRelativeName(dn, ctx), attributesToRetrieve) );
return mapper.mapAttributes(dn, ctx.getAttributes(LdapUtils.getRelativeName(dn, ctx), attributesToRetrieve) );
}
} );
}
/**
* Performs a search, with the requirement that the search shall return a single directory entry, and
* uses the supplied mapper to create the object from that entry.
*
* @param base
* @param filter
* @param params
* @param mapper
* @return the object created by the mapper from the matching entry
* @throws EmptyResultDataAccessException if no results are found.
* @throws IncorrectResultSizeDataAccessException if the search returns more than one result.
*/
public Object searchForSingleEntry(final String base, final String filter, final Object[] params, final LdapEntryMapper mapper) {
return execute ( new LdapCallback() {
public Object execute(DirContext ctx) throws NamingException {
NamingEnumeration results = ctx.search(base, filter, params, searchControls);
if (!results.hasMore()) {
throw new EmptyResultDataAccessException(1);
}
SearchResult searchResult = (SearchResult)results.next();
if (results.hasMore()) {
throw new IncorrectResultSizeDataAccessException(1);
}
// Work out the DN of the matched entry
StringBuffer dn = new StringBuffer(searchResult.getName());
if (base.length() > 0) {
dn.append(",");
dn.append(base);
}
String nameInNamespace = ctx.getNameInNamespace();
if(StringUtils.hasLength(nameInNamespace)) {
dn.append(",");
dn.append(nameInNamespace);
}
return mapper.mapAttributes(dn.toString(), searchResult.getAttributes());
}
}
);
}
}

View File

@ -22,16 +22,9 @@ import javax.naming.NamingException;
/**
* A user representation which is used internally by the Ldap provider.
*
* It contains the user's distinguished name and a set of attributes that
* have been retrieved from the Ldap server.
* <p>
* An instance may be created as the result of a search, or when user information
* is retrieved during authentication.
* </p>
* <p>
* An instance of this class will be used by the <tt>LdapAuthenticationProvider</tt>
* to construct the final user details object that it returns.
* </p>
*
* @deprecated in favour of {@link org.acegisecurity.userdetails.ldap.LdapUserDetails}
*
*
* @author Luke Taylor
* @version $Id$

View File

@ -15,6 +15,8 @@
package org.acegisecurity.ldap;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
/**
* Obtains a user's information from the LDAP directory given a login name.
* <p>
@ -33,9 +35,8 @@ public interface LdapUserSearch {
* for that user.
*
* @param username the login name supplied to the authentication service.
* @return an LdapUserInfo object containing the user's full DN and requested attributes.
* TODO: Need to optionally supply required attributes here for the search.
* @return an LdapUserDetailsImpl object containing the user's full DN and requested attributes.
*/
LdapUserInfo searchForUser(String username);
LdapUserDetails searchForUser(String username);
}

View File

@ -16,24 +16,22 @@
package org.acegisecurity.ldap.search;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
import org.acegisecurity.ldap.LdapUserSearch;
import org.acegisecurity.ldap.LdapUtils;
import org.acegisecurity.ldap.InitialDirContextFactory;
import org.acegisecurity.ldap.LdapUserInfo;
import org.acegisecurity.ldap.LdapDataAccessException;
import org.acegisecurity.ldap.LdapTemplate;
import org.acegisecurity.ldap.LdapEntryMapper;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.dao.EmptyResultDataAccessException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.directory.DirContext;
import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
/**
* LdapUserSearch implementation which uses an Ldap filter to locate the user.
@ -82,6 +80,8 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch {
private InitialDirContextFactory initialDirContextFactory;
private LdapEntryMapper userDetailsMapper = new LdapUserDetailsMapper();
//~ Methods ================================================================
public FilterBasedLdapUserSearch(String searchBase,
@ -104,12 +104,12 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch {
//~ Methods ================================================================
/**
* Return the LdapUserInfo containing the user's information, or null if
* no SearchResult is found.
* Return the LdapUserDetailsImpl containing the user's information
*
* @param username the username to search for.
* @throws UsernameNotFoundException if no matching entry is found.
*/
public LdapUserInfo searchForUser(String username) {
public LdapUserDetails searchForUser(String username) {
DirContext ctx = initialDirContextFactory.newInitialDirContext();
if (logger.isDebugEnabled()) {
@ -117,42 +117,20 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch {
", with user search " + this.toString());
}
LdapTemplate template = new LdapTemplate(initialDirContextFactory);
template.setSearchControls(searchControls);
try {
String[] args = new String[] { LdapUtils.escapeNameForFilter(username) };
Object user = template.searchForSingleEntry(searchBase, searchFilter, new String[] { username }, userDetailsMapper);
Assert.isInstanceOf(LdapUserDetails.class, user, "Entry mapper must return an LdapUserDetailsImpl instance");
NamingEnumeration results = ctx.search(searchBase, searchFilter, args, searchControls);
return (LdapUserDetails)user;
if (!results.hasMore()) {
throw new UsernameNotFoundException("User " + username + " not found in directory.");
}
SearchResult searchResult = (SearchResult)results.next();
if (results.hasMore()) {
throw new BadCredentialsException("Expected a single user but search returned multiple results");
}
StringBuffer userDn = new StringBuffer(searchResult.getName());
if (searchBase.length() > 0) {
userDn.append(",");
userDn.append(searchBase);
}
String nameInNamespace = ctx.getNameInNamespace();
if(StringUtils.hasLength(nameInNamespace)) {
userDn.append(",");
userDn.append(nameInNamespace);
}
return new LdapUserInfo(userDn.toString(), searchResult.getAttributes());
} catch(NamingException ne) {
throw new LdapDataAccessException("User Couldn't be found due to exception", ne);
} finally {
LdapUtils.closeContext(ctx);
} catch(EmptyResultDataAccessException notFound) {
throw new UsernameNotFoundException("User " + username + " not found in directory.");
}
}
/**

View File

@ -17,9 +17,9 @@ package org.acegisecurity.providers.ldap;
import org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ldap.LdapUserInfo;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.User;
import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.BadCredentialsException;
@ -29,8 +29,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import javax.naming.directory.Attributes;
/**
* An {@link org.acegisecurity.providers.AuthenticationProvider} implementation that
* provides integration with an LDAP server.
@ -156,33 +154,35 @@ public class LdapAuthenticationProvider extends AbstractUserDetailsAuthenticatio
String password = (String)authentication.getCredentials();
Assert.notNull(password, "Null password was supplied in authentication token");
LdapUserInfo ldapUser = authenticator.authenticate(username, password);
LdapUserDetails ldapUser = authenticator.authenticate(username, password);
return createUserDetails(username, password, ldapUser.getDn(), ldapUser.getAttributes());
return createUserDetails(ldapUser);
}
/**
* Creates the user final <tt>UserDetails</tt> object that will be returned by the provider
* Creates the final <tt>UserDetails</tt> object that will be returned by the provider
* once the user has been authenticated.
* <p>
* The <tt>LdapAuthoritiesPopulator</tt> will be used to create the granted authorites for the
* user.
* </p>
* <p>
* Can be overridden to customize the mapping of user attributes to additional user information.
* Can be overridden to customize the creation of the final UserDetails instance. The
* default will merge any additional authorities retrieved from the populator with the
* original <tt>ldapUser</tt> object.
* </p>
*
* @param username The user login, as passed to the provider
* @param password The submitted password
* @param userDn The DN of the user in the Ldap system.
* @param attributes The user attributes retrieved from the Ldap system.
* @param ldapUser The intermediate LdapUserDetails instance returned from the authenticator.
*
* @return The UserDetails for the successfully authenticated user.
*/
protected UserDetails createUserDetails(String username, String password, String userDn, Attributes attributes) {
protected UserDetails createUserDetails(LdapUserDetails ldapUser) {
return new User(username, password, true, true, true, true,
authoritiesPopulator.getGrantedAuthorities(username, userDn, attributes));
LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence(ldapUser);
user.setAuthorities(authoritiesPopulator.getGrantedAuthorities(ldapUser));
return user.createUserDetails();
}
protected LdapAuthoritiesPopulator getAuthoritiesPoulator() {

View File

@ -15,7 +15,7 @@
package org.acegisecurity.providers.ldap;
import org.acegisecurity.ldap.LdapUserInfo;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
/**
* The strategy interface for locating and authenticating an Ldap user.
@ -37,5 +37,5 @@ public interface LdapAuthenticator {
* @param password the user's password supplied at login.
* @return the details of the successfully authenticated user.
*/
LdapUserInfo authenticate(String username, String password);
LdapUserDetails authenticate(String username, String password);
}

View File

@ -16,10 +16,9 @@
package org.acegisecurity.providers.ldap;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
import org.acegisecurity.ldap.LdapDataAccessException;
import javax.naming.directory.Attributes;
/**
* Obtains a list of granted authorities for an Ldap user.
* <p>
@ -35,13 +34,11 @@ public interface LdapAuthoritiesPopulator {
/**
* Get the list of authorities for the user.
*
* @param username the login name which was passed to the LDAP provider.
* @param userDn the full DN of the user
* @param userAttributes the user's LDAP attributes that were retrieved from the directory.
* @param userDetails the user details object which was returned by the LDAP authenticator.
* @return the granted authorities for the given user.
* @throws org.acegisecurity.ldap.LdapDataAccessException if there is a problem accessing the directory.
*/
GrantedAuthority[] getGrantedAuthorities(String username, String userDn, Attributes userAttributes)
GrantedAuthority[] getGrantedAuthorities(LdapUserDetails userDetails)
throws LdapDataAccessException;
}

View File

@ -18,7 +18,9 @@ package org.acegisecurity.providers.ldap.authenticator;
import org.acegisecurity.providers.ldap.LdapAuthenticator;
import org.acegisecurity.ldap.InitialDirContextFactory;
import org.acegisecurity.ldap.LdapUserSearch;
import org.acegisecurity.ldap.LdapEntryMapper;
import org.acegisecurity.AcegiMessageSource;
import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
@ -55,6 +57,8 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator,
/** The attributes which will be retrieved from the directory. Null means all attributes */
private String[] userAttributes = null;
private LdapEntryMapper userDetailsMapper = new LdapUserDetailsMapper();
/**
* The suffix to be added to the DN patterns, worked out internally from the root DN of the
* configured InitialDirContextFactory.
@ -137,6 +141,15 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator,
this.userSearch = userSearch;
}
public void setUserDetailsMapper(LdapEntryMapper userDetailsMapper) {
Assert.notNull("userDetailsMapper must not be null");
this.userDetailsMapper = userDetailsMapper;
}
protected LdapEntryMapper getUserDetailsMapper() {
return userDetailsMapper;
}
protected LdapUserSearch getUserSearch() {
return userSearch;
}

View File

@ -15,18 +15,14 @@
package org.acegisecurity.providers.ldap.authenticator;
import org.acegisecurity.ldap.LdapUtils;
import org.acegisecurity.ldap.LdapUserInfo;
import org.acegisecurity.ldap.LdapDataAccessException;
import org.acegisecurity.ldap.InitialDirContextFactory;
import org.acegisecurity.ldap.LdapTemplate;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.naming.directory.DirContext;
import javax.naming.directory.Attributes;
import javax.naming.NamingException;
import org.springframework.util.Assert;
import java.util.Iterator;
@ -44,6 +40,7 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
private static final Log logger = LogFactory.getLog(BindAuthenticator.class);
//~ Constructors ===========================================================
public BindAuthenticator(InitialDirContextFactory initialDirContextFactory) {
@ -52,9 +49,9 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
//~ Methods ================================================================
public LdapUserInfo authenticate(String username, String password) {
public LdapUserDetails authenticate(String username, String password) {
LdapUserInfo user = null;
LdapUserDetails user = null;
// If DN patterns are configured, try authenticating with them directly
Iterator dns = getUserDns(username).iterator();
@ -66,7 +63,7 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
// Otherwise use the configured locator to find the user
// and authenticate with the returned DN.
if (user == null && getUserSearch() != null) {
LdapUserInfo userFromSearch = getUserSearch().searchForUser(username);
LdapUserDetails userFromSearch = getUserSearch().searchForUser(username);
user = bindWithDn(userFromSearch.getDn(), password);
}
@ -80,18 +77,19 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
}
LdapUserInfo bindWithDn(String userDn, String password) {
DirContext ctx = null;
LdapUserInfo user = null;
LdapUserDetails bindWithDn(String userDn, String password) {
LdapTemplate template = new LdapTemplate(getInitialDirContextFactory(), userDn, password);
if (logger.isDebugEnabled()) {
logger.debug("Attempting to bind with DN = " + userDn);
}
try {
ctx = getInitialDirContextFactory().newInitialDirContext(userDn, password);
Attributes attributes = loadAttributes(ctx, userDn);
user = new LdapUserInfo(userDn, attributes);
Object user = (LdapUserDetails)template.retrieveEntry(userDn, getUserDetailsMapper(), getUserAttributes());
Assert.isInstanceOf(LdapUserDetails.class, user, "Entry mapper must return an LdapUserDetails instance");
return (LdapUserDetails) user;
} catch(BadCredentialsException e) {
// This will be thrown if an invalid user name is used and the method may
@ -99,24 +97,8 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
if (logger.isDebugEnabled()) {
logger.debug("Failed to bind as " + userDn + ": " + e.getCause());
}
} finally {
LdapUtils.closeContext(ctx);
}
return user;
return null;
}
Attributes loadAttributes(DirContext ctx, String userDn) {
try {
return ctx.getAttributes(
LdapUtils.getRelativeName(userDn, ctx),
getUserAttributes());
} catch(NamingException ne) {
throw new LdapDataAccessException(messages.getMessage(
"BindAuthenticator.failedToLoadAttributes", new String[] {userDn},
"Failed to load attributes for user {0}"), ne);
}
}
}

View File

@ -15,11 +15,10 @@
package org.acegisecurity.providers.ldap.authenticator;
import org.acegisecurity.ldap.LdapUserInfo;
import org.acegisecurity.ldap.LdapUtils;
import org.acegisecurity.ldap.InitialDirContextFactory;
import org.acegisecurity.ldap.LdapTemplate;
import org.acegisecurity.ldap.AttributesMapper;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
import org.acegisecurity.providers.encoding.PasswordEncoder;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.userdetails.UsernameNotFoundException;
@ -29,13 +28,6 @@ import org.springframework.util.Assert;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.DirContext;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import java.util.Iterator;
/**
@ -62,14 +54,10 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
private static final Log logger = LogFactory.getLog(PasswordComparisonAuthenticator.class);
private static final String[] NO_ATTRS = new String[0];
//~ Instance fields ========================================================
private String passwordAttributeName = "userPassword";
private String passwordCompareFilter = "(userPassword={0})";
private PasswordEncoder passwordEncoder = new LdapShaPasswordEncoder();
//~ Constructors ===========================================================
@ -80,10 +68,10 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
//~ Methods ================================================================
public LdapUserInfo authenticate(String username, String password) {
public LdapUserDetails authenticate(final String username, final String password) {
// locate the user and check the password
LdapUserInfo user = null;
LdapUserDetails user = null;
Iterator dns = getUserDns(username).iterator();
@ -93,13 +81,7 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
final String userDn = (String)dns.next();
if(ldapTemplate.nameExists(userDn)) {
AttributesMapper mapper = new AttributesMapper() {
public Object mapAttributes(Attributes attributes) {
return new LdapUserInfo(userDn, attributes);
}
};
user = (LdapUserInfo)ldapTemplate.retrieveEntry(userDn, mapper, getUserAttributes());
user = (LdapUserDetails)ldapTemplate.retrieveEntry(userDn, getUserDetailsMapper(), getUserAttributes());
}
}
@ -111,40 +93,36 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
throw new UsernameNotFoundException(username);
}
DirContext ctx = getInitialDirContextFactory().newInitialDirContext();
String retrievedPassword = user.getPassword();
try {
Attribute passwordAttribute = user.getAttributes().get(passwordAttributeName);
if(passwordAttribute != null) {
Object retrievedPassword = passwordAttribute.get();
if (!(retrievedPassword instanceof String)) {
// Assume it's binary
retrievedPassword = new String((byte[])retrievedPassword);
}
if (!verifyPassword(password, (String)retrievedPassword)) {
throw new BadCredentialsException(messages.getMessage(
"PasswordComparisonAuthenticator.badCredentials",
"Bad credentials"));
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Password attribute " + passwordAttributeName
+ " wasn't retrieved for user " + username);
}
doPasswordCompare(ctx, user.getRelativeName(ctx), password);
if(retrievedPassword != null) {
if (!verifyPassword(password, retrievedPassword)) {
throw new BadCredentialsException(messages.getMessage(
"PasswordComparisonAuthenticator.badCredentials",
"Bad credentials"));
}
return user;
} catch(NamingException ne) {
throw new BadCredentialsException("Authentication failed due to exception ", ne);
} finally {
LdapUtils.closeContext(ctx);
}
if (logger.isDebugEnabled()) {
logger.debug("Password attribute wasn't retrieved for user '" + username
+ "' using mapper " + getUserDetailsMapper()
+ ". Performing LDAP compare of password attribute '"
+ passwordAttributeName + "'" );
}
String encodedPassword = passwordEncoder.encodePassword(password, null);
byte[] passwordBytes = LdapUtils.getUtf8Bytes(encodedPassword);
if(!ldapTemplate.compare(user.getDn(), passwordAttributeName, passwordBytes)) {
throw new BadCredentialsException(messages.getMessage(
"PasswordComparisonAuthenticator.badCredentials",
"Bad credentials"));
}
return user;
}
/**
@ -162,32 +140,9 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
return false;
}
private void doPasswordCompare(DirContext ctx, String name, String password) throws NamingException {
if (logger.isDebugEnabled()) {
logger.debug("Performing LDAP compare of password for " + name);
}
password = passwordEncoder.encodePassword(password, null);
byte[] passwordBytes = LdapUtils.getUtf8Bytes(password);
SearchControls ctls = new SearchControls();
ctls.setReturningAttributes(NO_ATTRS);
ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
NamingEnumeration results = ctx.search(name, passwordCompareFilter,
new Object[]{passwordBytes}, ctls);
if(!results.hasMore()) {
throw new BadCredentialsException(messages.getMessage(
"PasswordComparisonAuthenticator.badCredentials",
"Bad credentials"));
}
}
public void setPasswordAttributeName(String passwordAttribute) {
Assert.hasLength(passwordAttribute, "passwordAttributeName must not be empty or null");
this.passwordAttributeName = passwordAttribute;
this.passwordCompareFilter = "(" + passwordAttributeName + "={0})";
}
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {

View File

@ -16,24 +16,20 @@
package org.acegisecurity.providers.ldap.populator;
import org.acegisecurity.providers.ldap.LdapAuthoritiesPopulator;
import org.acegisecurity.ldap.LdapDataAccessException;
import org.acegisecurity.ldap.InitialDirContextFactory;
import org.acegisecurity.ldap.LdapUtils;
import org.acegisecurity.ldap.LdapTemplate;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import javax.naming.directory.Attributes;
import javax.naming.directory.Attribute;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.directory.DirContext;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
/**
* The default strategy for obtaining user role information from the directory.
@ -114,7 +110,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
//~ Instance fields ========================================================
/** Attributes of the User's LDAP Object that contain role name information. */
private String[] userRoleAttributes = null;
// private String[] userRoleAttributes = null;
private String rolePrefix = "ROLE_";
@ -175,21 +171,26 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
//~ Methods ================================================================
/**
*
* @param username the login name passed to the authentication provider.
* @param userDn the user's DN.
* @param userAttributes the attributes retrieved from the user's directory entry.
* @return the full set of roles granted to the user.
* @return the set of roles granted to the user.
*/
public GrantedAuthority[] getGrantedAuthorities(String username, String userDn, Attributes userAttributes) {
public final GrantedAuthority[] getGrantedAuthorities(LdapUserDetails userDetails) {
String userDn = userDetails.getDn();
logger.debug("Getting authorities for user " + userDn);
Set roles = getRolesFromUserAttributes(userDn, userAttributes);
Set roles = getGroupMembershipRoles(userDn);
Set groupRoles = getGroupMembershipRoles(userDn, userAttributes);
// Temporary use of deprecated method
Set oldGroupRoles = getGroupMembershipRoles(userDn, userDetails.getAttributes());
if(groupRoles != null) {
roles.addAll(groupRoles);
if(oldGroupRoles != null) {
roles.addAll(oldGroupRoles);
}
Set extraRoles = getAdditionalRoles(userDetails);
if(extraRoles != null) {
roles.addAll(extraRoles);
}
if(defaultRole != null) {
@ -199,31 +200,23 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
return (GrantedAuthority[])roles.toArray(new GrantedAuthority[roles.size()]);
}
protected Set getRolesFromUserAttributes(String userDn, Attributes userAttributes) {
Set userRoles = new HashSet();
// protected Set getRolesFromUserAttributes(String userDn, Attributes userAttributes) {
// Set userRoles = new HashSet();
//
// for(int i=0; userRoleAttributes != null && i < userRoleAttributes.length; i++) {
// Attribute roleAttribute = userAttributes.get(userRoleAttributes[i]);
//
// addAttributeValuesToRoleSet(roleAttribute, userRoles);
// }
//
// return userRoles;
// }
for(int i=0; userRoleAttributes != null && i < userRoleAttributes.length; i++) {
Attribute roleAttribute = userAttributes.get(userRoleAttributes[i]);
addAttributeValuesToRoleSet(roleAttribute, userRoles);
}
return userRoles;
}
/**
* Searches for groups the user is a member of.
*
* @param userDn the user's distinguished name.
* @param userAttributes the retrieved user's attributes (unused by default).
* @return the set of roles obtained from a group membership search, or null if
* <tt>groupSearchBase</tt> has been set.
*/
protected Set getGroupMembershipRoles(String userDn, Attributes userAttributes) {
Set userRoles = new HashSet();
private Set getGroupMembershipRoles(String userDn) {
Set authorities = new HashSet();
if (groupSearchBase == null) {
return null;
return authorities;
}
if (logger.isDebugEnabled()) {
@ -232,82 +225,60 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
+ " in search base '" + groupSearchBase + "'");
}
DirContext ctx = initialDirContextFactory.newInitialDirContext();
SearchControls ctls = new SearchControls();
LdapTemplate template = new LdapTemplate(initialDirContextFactory);
ctls.setSearchScope(searchScope);
ctls.setReturningAttributes(new String[] {groupRoleAttribute});
template.setSearchScope(searchScope);
try {
NamingEnumeration groups =
ctx.search(groupSearchBase, groupSearchFilter, new String[]{userDn}, ctls);
while (groups.hasMore()) {
SearchResult result = (SearchResult) groups.next();
Attributes attrs = result.getAttributes();
// There should only be one role attribute.
NamingEnumeration groupRoleAttributes = attrs.getAll();
while(groupRoleAttributes.hasMore()) {
Attribute roleAttribute = (Attribute) groupRoleAttributes.next();
addAttributeValuesToRoleSet(roleAttribute, userRoles);
}
}
} catch (NamingException e) {
throw new LdapDataAccessException("Group search failed for user " + userDn, e);
} finally {
LdapUtils.closeContext(ctx);
}
Set userRoles = template.searchForSingleAttributeValues(groupSearchBase, groupSearchFilter, new String[]{userDn}, groupRoleAttribute);
if (logger.isDebugEnabled()) {
logger.debug("Roles from search: " + userRoles);
}
return userRoles;
Iterator it = userRoles.iterator();
while(it.hasNext()) {
Object role = it.next();
// We only handle Strings for the time being
if(role instanceof String) {
if(convertToUpperCase) {
role = ((String)role).toUpperCase();
}
authorities.add(new GrantedAuthorityImpl(rolePrefix + role));
} else {
logger.warn("Non-String value found for role: " + role);
}
}
return authorities;
}
private void addAttributeValuesToRoleSet(Attribute roleAttribute, Set roles) {
if (roleAttribute == null) {
return;
}
try {
NamingEnumeration attributeRoles = roleAttribute.getAll();
protected Set getAdditionalRoles(LdapUserDetails ldapUser) {
return null;
}
while(attributeRoles.hasMore()) {
Object role = attributeRoles.next();
// We only handle Strings for the time being
if(role instanceof String) {
if(convertToUpperCase) {
role = ((String)role).toUpperCase();
}
roles.add(new GrantedAuthorityImpl(rolePrefix + role));
} else {
logger.warn("Non-String value found for role attribute " + roleAttribute.getID());
}
}
} catch(NamingException ne) {
throw new LdapDataAccessException("Error retrieving values for role attribute " +
roleAttribute.getID(), ne);
}
/**
* Searches for groups the user is a member of.
*
* @deprecated Subclasses should implement <tt>getAdditionalRoles</tt> instead.
*
* @param userDn the user's distinguished name.
* @param userAttributes the retrieved user's attributes (unused by default).
* @return the set of roles obtained from a group membership search, or null if
* <tt>groupSearchBase</tt> has been set.
*/
protected Set getGroupMembershipRoles(String userDn, Attributes userAttributes) {
return new HashSet();
}
protected InitialDirContextFactory getInitialDirContextFactory() {
return initialDirContextFactory;
}
protected String[] getUserRoleAttributes() {
return userRoleAttributes;
}
public void setUserRoleAttributes(String[] userRoleAttributes) {
this.userRoleAttributes = userRoleAttributes;
}
public void setRolePrefix(String rolePrefix) {
Assert.notNull(rolePrefix, "rolePrefix must not be null");
this.rolePrefix = rolePrefix;

View File

@ -163,13 +163,26 @@ public class FilterChainProxy implements Filter, InitializingBean,
}
chain.doFilter(request, response);
} else {
Filter[] filters = obtainAllDefinedFilters(cad);
VirtualFilterChain virtualFilterChain = new VirtualFilterChain(fi,
filters);
virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse());
return;
}
Filter[] filters = obtainAllDefinedFilters(cad);
if(filters.length == 0) {
if (logger.isDebugEnabled()) {
logger.debug(fi.getRequestUrl() + " has an empty filter list");
}
chain.doFilter(request, response);
return;
}
VirtualFilterChain virtualFilterChain = new VirtualFilterChain(fi,
filters);
virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse());
}
public FilterInvocationDefinitionSource getFilterInvocationDefinitionSource() {
@ -224,7 +237,7 @@ public class FilterChainProxy implements Filter, InitializingBean,
}
}
return (Filter[]) list.toArray(new Filter[] {null});
return (Filter[]) list.toArray(new Filter[0]);
}
/**
@ -247,9 +260,10 @@ public class FilterChainProxy implements Filter, InitializingBean,
ConfigAttribute attr = (ConfigAttribute) attributes.next();
String filterName = attr.getAttribute();
Assert.notNull(filterName,
"Configuration attribute: '" + attr
if(filterName == null) {
throw new IllegalArgumentException("Configuration attribute: '" + attr
+ "' returned null to the getAttribute() method, which is invalid when used with FilterChainProxy");
}
if (!filterName.equals(TOKEN_NONE)) {
list.add(this.applicationContext.getBean(filterName,
@ -257,7 +271,7 @@ public class FilterChainProxy implements Filter, InitializingBean,
}
}
return (Filter[]) list.toArray(new Filter[] {null});
return (Filter[]) list.toArray(new Filter[list.size()]);
}
public void setApplicationContext(ApplicationContext applicationContext)

View File

@ -19,8 +19,6 @@ import junit.framework.TestCase;
import java.util.Hashtable;
import org.apache.directory.server.core.jndi.CoreContextFactory;
/**
* @author Luke Taylor
* @version $Id$
@ -31,16 +29,16 @@ public abstract class AbstractLdapServerTestCase extends TestCase {
protected static final String MANAGER_PASSWORD = "acegisecurity";
// External server config
// private static final String PROVIDER_URL = "ldap://monkeymachine:389/"+ROOT_DN;
// private static final String CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
// private static final Hashtable EXTRA_ENV = new Hashtable();
private static final String PROVIDER_URL = "ldap://monkeymachine:389/"+ROOT_DN;
private static final String CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
private static final Hashtable EXTRA_ENV = new Hashtable();
// Embedded (non-networked) server config
private static final LdapTestServer SERVER = new LdapTestServer();
private static final String PROVIDER_URL = ROOT_DN;
private static final String CONTEXT_FACTORY = CoreContextFactory.class.getName();
private static final Hashtable EXTRA_ENV = SERVER.getConfiguration().toJndiEnvironment();
// private static final LdapTestServer SERVER = new LdapTestServer();
// private static final String PROVIDER_URL = ROOT_DN;
// private static final String CONTEXT_FACTORY = CoreContextFactory.class.getName();
// private static final Hashtable EXTRA_ENV = SERVER.getConfiguration().toJndiEnvironment();
protected AbstractLdapServerTestCase() {
}

View File

@ -33,27 +33,27 @@ public class LdapTemplateTests extends AbstractLdapServerTestCase {
public void testCompareOfCorrectValueSucceeds() {
assertTrue(template.compare("uid=bob,ou=people", "uid", "bob"));
assertTrue(template.compare("uid=bob,ou=people,dc=acegisecurity,dc=org", "uid", "bob"));
}
public void testCompareOfWrongValueFails() {
assertFalse(template.compare("uid=bob,ou=people", "uid", "wrongvalue"));
assertFalse(template.compare("uid=bob,ou=people,dc=acegisecurity,dc=org", "uid", "wrongvalue"));
}
public void testCompareOfCorrectByteValueSucceeds() {
// Doesn't work with embedded server due to bugs in apacheds
// assertTrue(template.compare("uid=bob,ou=people", "userPassword", LdapUtils.getUtf8Bytes("bobspassword")));
// assertTrue(template.compare("uid=bob,ou=people,dc=acegisecurity,dc=org", "userPassword", LdapUtils.getUtf8Bytes("bobspassword")));
}
public void testCompareOfWrongByteValueFails() {
// Doesn't work with embedded server due to bugs in apacheds
// assertFalse(template.compare("uid=bob,ou=people", "userPassword", LdapUtils.getUtf8Bytes("wrongvalue")));
// assertFalse(template.compare("uid=bob,ou=people,dc=acegisecurity,dc=org", "userPassword", LdapUtils.getUtf8Bytes("wrongvalue")));
}
public void testSearchForSingleAttributeValues() {
String param = "uid=ben,ou=people," + getInitialCtxFactory().getRootDn();
String param = "uid=ben,ou=people,dc=acegisecurity,dc=org";
Set values = template.searchForSingleAttributeValues("ou=groups", "(member={0})", new String[] {param}, "ou");

View File

@ -2,9 +2,9 @@ package org.acegisecurity.ldap.search;
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
import org.acegisecurity.ldap.DefaultInitialDirContextFactory;
import org.acegisecurity.ldap.LdapUserInfo;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
/**
* Tests for FilterBasedLdapUserSearch.
@ -32,7 +32,7 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapServerTestCase {
public void testBasicSearch() throws Exception {
FilterBasedLdapUserSearch locator =
new FilterBasedLdapUserSearch("ou=people", "(uid={0})", dirCtxFactory);
LdapUserInfo bob = locator.searchForUser("bob");
LdapUserDetails bob = locator.searchForUser("bob");
locator.setSearchSubtree(false);
locator.setSearchTimeLimit(0);
// name is wrong with embedded apacheDS
@ -45,7 +45,7 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapServerTestCase {
new FilterBasedLdapUserSearch("", "(cn={0})", dirCtxFactory);
locator.setSearchSubtree(true);
LdapUserInfo ben = locator.searchForUser("Ben Alex");
LdapUserDetails ben = locator.searchForUser("Ben Alex");
// assertEquals("uid=ben,ou=people,"+ROOT_DN, bob.getDn());
}
@ -67,7 +67,7 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapServerTestCase {
try {
locator.searchForUser("Ignored");
fail("Expected exception for multiple search matches.");
} catch (BadCredentialsException expected) {
} catch (IncorrectResultSizeDataAccessException expected) {
}
}
@ -80,7 +80,7 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapServerTestCase {
dirCtxFactory);
// Search for bob, get back ben...
LdapUserInfo ben = locator.searchForUser("bob");
LdapUserDetails ben = locator.searchForUser("bob");
String cn = (String)ben.getAttributes().get("cn").get();
assertEquals("Ben Alex", cn);
// assertEquals("uid=ben,ou=people,"+ROOT_DN, ben.getDn());

View File

@ -6,11 +6,12 @@ import javax.naming.directory.BasicAttributes;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.ldap.LdapUserInfo;
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
import org.acegisecurity.ldap.*;
import org.acegisecurity.ldap.DefaultInitialDirContextFactory;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
/**
* @author Luke Taylor
@ -82,18 +83,20 @@ public class LdapAuthenticationProviderTests extends AbstractLdapServerTestCase
*/
class MockAuthoritiesPopulator implements LdapAuthoritiesPopulator {
public GrantedAuthority[] getGrantedAuthorities(String userDn, String dn, Attributes userAttributes) {
return new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_USER") };
public GrantedAuthority[] getGrantedAuthorities(LdapUserDetails userDetailsll) {
return new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_USER") };
}
}
class MockAuthenticator implements LdapAuthenticator {
Attributes userAttributes = new BasicAttributes("cn","bob");
public LdapUserInfo authenticate(String username, String password) {
public LdapUserDetails authenticate(String username, String password) {
if(username.equals("bob") && password.equals("bobspassword")) {
return new LdapUserInfo("cn=bob,ou=people,dc=acegisecurity,dc=org", userAttributes);
LdapUserDetailsImpl.Essence creator = new LdapUserDetailsImpl.Essence();
creator.setDn("cn=bob,ou=people,dc=acegisecurity,dc=org");
creator.setAttributes(userAttributes);
return creator.createUserDetails();
}
throw new BadCredentialsException("Authentication of Bob failed.");
}

View File

@ -1,8 +1,11 @@
package org.acegisecurity.providers.ldap.authenticator;
import org.acegisecurity.ldap.LdapUserInfo;
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
/**
* Tests for {@link BindAuthenticator}.
@ -26,12 +29,10 @@ public class BindAuthenticatorTests extends AbstractLdapServerTestCase {
public void testAuthenticationWithCorrectPasswordSucceeds() throws Exception {
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
LdapUserInfo user = authenticator.authenticate("bob","bobspassword");
LdapUserDetails user = authenticator.authenticate("bob","bobspassword");
}
public void testAuthenticationWithWrongPasswordFails() {
// BindAuthenticator authenticator = new BindAuthenticator(dirCtxFactory);
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
try {
@ -42,25 +43,36 @@ public class BindAuthenticatorTests extends AbstractLdapServerTestCase {
}
public void testAuthenticationWithUserSearch() throws Exception {
LdapUserInfo user = new LdapUserInfo("uid=bob,ou=people," + getInitialCtxFactory().getRootDn(), null);
authenticator.setUserSearch(new MockUserSearch(user));
LdapUserDetailsImpl.Essence userEssence = new LdapUserDetailsImpl.Essence();
userEssence.setDn("uid=bob,ou=people,dc=acegisecurity,dc=org");
authenticator.setUserSearch(new MockUserSearch(userEssence.createUserDetails()));
authenticator.afterPropertiesSet();
authenticator.authenticate("bob","bobspassword");
}
public void testAuthenticationWithInvalidUserNameFails() {
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
// Apache DS falls apart with unknown DNs.
//
// public void testAuthenticationWithInvalidUserNameFails() {
// BindAuthenticator authenticator = new BindAuthenticator();
//
// authenticator.setInitialDirContextFactory(dirCtxFactory);
// authenticator.setUserDnPatterns("cn={0},ou=people");
// try {
// authenticator.authenticate("Baz","bobspassword");
// fail("Shouldn't be able to bind with invalid username");
// } catch(BadCredentialsException expected) {
// }
// }
try {
authenticator.authenticate("nonexistentsuser","bobspassword");
fail("Shouldn't be able to bind with invalid username");
} catch(BadCredentialsException expected) {
}
}
// TODO: Create separate tests for base class
public void testRoleRetrieval() {
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
LdapUserDetailsMapper userMapper = new LdapUserDetailsMapper();
userMapper.setRoleAttributes(new String[] {"uid"});
authenticator.setUserDetailsMapper(userMapper);
LdapUserDetails user = authenticator.authenticate("bob","bobspassword");
assertEquals(1, user.getAuthorities().length);
assertEquals(new GrantedAuthorityImpl("ROLE_BOB"), user.getAuthorities()[0]);
}
}

View File

@ -1,20 +1,20 @@
package org.acegisecurity.providers.ldap.authenticator;
import org.acegisecurity.ldap.LdapUserInfo;
import org.acegisecurity.ldap.LdapUserSearch;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
/**
* @author Luke Taylor
* @version $Id$
*/
public class MockUserSearch implements LdapUserSearch {
LdapUserInfo user;
LdapUserDetails user;
public MockUserSearch(LdapUserInfo user) {
public MockUserSearch(LdapUserDetails user) {
this.user = user;
}
public LdapUserInfo searchForUser(String username) {
public LdapUserDetails searchForUser(String username) {
return user;
}
}

View File

@ -27,12 +27,13 @@ public class PasswordComparisonAuthenticatorMockTests extends MockObjectTestCase
// Get the mock to return an empty attribute set
mockCtx.expects(atLeastOnce()).method("getNameInNamespace").will(returnValue("dc=acegisecurity,dc=org"));
mockCtx.expects(once()).method("lookup").with(eq("cn=Bob,ou=people")).will(returnValue(true));
mockCtx.expects(once()).method("getAttributes").with(eq("cn=Bob,ou=people"), NULL).will(returnValue(new BasicAttributes()));
// Setup a single return value (i.e. success)
Attributes searchResults = new BasicAttributes("", null);
mockCtx.expects(once()).method("search").with(eq("cn=Bob,ou=people"),
eq("(userPassword={0})"), NOT_NULL, NOT_NULL).will(returnValue(searchResults.getAll()));
mockCtx.expects(once()).method("close");
mockCtx.expects(atLeastOnce()).method("close");
authenticator.authenticate("Bob", "bobspassword");
}

View File

@ -1,11 +1,11 @@
package org.acegisecurity.providers.ldap.authenticator;
import org.acegisecurity.ldap.LdapUserInfo;
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import javax.naming.directory.BasicAttributes;
import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
/**
* Tests for {@link PasswordComparisonAuthenticator}.
@ -87,7 +87,7 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapServerTest
}
public void testAllAttributesAreRetrivedByDefault() {
LdapUserInfo user = authenticator.authenticate("Bob", "bobspassword");
LdapUserDetails user = authenticator.authenticate("Bob", "bobspassword");
System.out.println(user.getAttributes().toString());
assertEquals("User should have 5 attributes", 5, user.getAttributes().size());
@ -103,7 +103,10 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapServerTest
}
*/
public void testUseOfDifferentPasswordAttribute() {
LdapUserDetailsMapper mapper = new LdapUserDetailsMapper();
mapper.setPasswordAttributeName("uid");
authenticator.setPasswordAttributeName("uid");
authenticator.setUserDetailsMapper(mapper);
authenticator.authenticate("bob", "bob");
}
/*
@ -119,10 +122,11 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapServerTest
authenticator = new PasswordComparisonAuthenticator(getInitialCtxFactory());
assertTrue("User DN matches shouldn't be available",
authenticator.getUserDns("Bob").isEmpty());
LdapUserInfo user = new LdapUserInfo("uid=Bob,ou=people" +
getInitialCtxFactory().getRootDn(),
new BasicAttributes("userPassword","bobspassword"));
authenticator.setUserSearch(new MockUserSearch(user));
LdapUserDetailsImpl.Essence userEssence = new LdapUserDetailsImpl.Essence();
userEssence.setDn("uid=Bob,ou=people,dc=acegisecurity,dc=org");
userEssence.setPassword("bobspassword");
authenticator.setUserSearch(new MockUserSearch(userEssence.createUserDetails()));
authenticator.authenticate("ShouldntBeUsed","bobspassword");
}

View File

@ -1,10 +1,9 @@
package org.acegisecurity.providers.ldap.populator;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.BasicAttribute;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
import java.util.Set;
@ -21,30 +20,39 @@ public class DefaultLdapAuthoritiesPopulatorTests extends AbstractLdapServerTest
getInitialCtxFactory().setManagerPassword(MANAGER_PASSWORD);
}
public void testUserAttributeMappingToRoles() {
DefaultLdapAuthoritiesPopulator populator = new DefaultLdapAuthoritiesPopulator();
populator.setUserRoleAttributes(new String[] {"userRole", "otherUserRole"});
populator.getUserRoleAttributes();
Attributes userAttrs = new BasicAttributes();
BasicAttribute attr = new BasicAttribute("userRole", "role1");
attr.add("role2");
userAttrs.put(attr);
attr = new BasicAttribute("otherUserRole", "role3");
attr.add("role2"); // duplicate
userAttrs.put(attr);
GrantedAuthority[] authorities =
populator.getGrantedAuthorities("Ignored", "Ignored", userAttrs);
assertEquals("User should have three roles", 3, authorities.length);
}
// public void testUserAttributeMappingToRoles() {
// DefaultLdapAuthoritiesPopulator populator = new DefaultLdapAuthoritiesPopulator();
// populator.setUserRoleAttributes(new String[] {"userRole", "otherUserRole"});
// populator.getUserRoleAttributes();
//
// Attributes userAttrs = new BasicAttributes();
// BasicAttribute attr = new BasicAttribute("userRole", "role1");
// attr.add("role2");
// userAttrs.put(attr);
// attr = new BasicAttribute("otherUserRole", "role3");
// attr.add("role2"); // duplicate
// userAttrs.put(attr);
//
// LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence();
// user.setDn("Ignored");
// user.setUsername("Ignored");
// user.setAttributes(userAttrs);
//
// GrantedAuthority[] authorities =
// populator.getGrantedAuthorities(user.createUserDetails());
// assertEquals("User should have three roles", 3, authorities.length);
// }
public void testDefaultRoleIsAssignedWhenSet() {
DefaultLdapAuthoritiesPopulator populator = new DefaultLdapAuthoritiesPopulator();
populator.setDefaultRole("ROLE_USER");
LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence();
user.setDn("Ignored");
user.setUsername("Ignored");
user.setAttributes(new BasicAttributes());
GrantedAuthority[] authorities =
populator.getGrantedAuthorities("Ignored", "Ignored", new BasicAttributes());
populator.getGrantedAuthorities(user.createUserDetails());
assertEquals(1, authorities.length);
assertEquals("ROLE_USER", authorities[0].getAuthority());
}
@ -59,9 +67,14 @@ public class DefaultLdapAuthoritiesPopulatorTests extends AbstractLdapServerTest
populator.setConvertToUpperCase(true);
populator.setGroupSearchFilter("(member={0})");
LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence();
user.setUsername("ben");
user.setDn("uid=ben,ou=people,dc=acegisecurity,dc=org");
user.setAttributes(new BasicAttributes());
GrantedAuthority[] authorities =
populator.getGrantedAuthorities("ben", "uid=ben,ou=people,"+
getInitialCtxFactory().getRootDn(), new BasicAttributes());
populator.getGrantedAuthorities(user.createUserDetails());
assertEquals("Should have 2 roles", 2, authorities.length);
Set roles = new HashSet();
roles.add(authorities[0].toString());