mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-28 06:42:49 +00:00
SEC-264: changes to LDAP services.
This commit is contained in:
parent
db042046e9
commit
65fe641900
@ -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;
|
||||||
|
}
|
@ -25,7 +25,10 @@ import javax.naming.directory.Attributes;
|
|||||||
import javax.naming.directory.Attribute;
|
import javax.naming.directory.Attribute;
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||||
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -45,37 +48,66 @@ public class LdapTemplate {
|
|||||||
public static final String[] NO_ATTRS = new String[0];
|
public static final String[] NO_ATTRS = new String[0];
|
||||||
|
|
||||||
private InitialDirContextFactory dirContextFactory;
|
private InitialDirContextFactory dirContextFactory;
|
||||||
private String managerDn = null;
|
private String principalDn = null;
|
||||||
private String password = null;
|
private String password = null;
|
||||||
/** Default search scope */
|
/** Default search controls */
|
||||||
private int searchScope = SearchControls.SUBTREE_SCOPE;
|
private SearchControls searchControls = new SearchControls();
|
||||||
|
|
||||||
public LdapTemplate(InitialDirContextFactory dirContextFactory) {
|
public LdapTemplate(InitialDirContextFactory dirContextFactory) {
|
||||||
Assert.notNull(dirContextFactory, "An InitialDirContextFactory is required");
|
Assert.notNull(dirContextFactory, "An InitialDirContextFactory is required");
|
||||||
this.dirContextFactory = dirContextFactory;
|
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) {
|
public LdapTemplate(InitialDirContextFactory dirContextFactory, String userDn, String password) {
|
||||||
this(dirContextFactory);
|
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");
|
Assert.notNull(password, "password cannot be null");
|
||||||
|
|
||||||
this.managerDn = userDn;
|
this.principalDn = userDn;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSearchScope(int searchScope) {
|
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 {
|
public Object execute(LdapCallback callback) throws DataAccessException {
|
||||||
DirContext ctx = null;
|
DirContext ctx = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ctx = (managerDn == null) ?
|
ctx = (principalDn == null) ?
|
||||||
dirContextFactory.newInitialDirContext() :
|
dirContextFactory.newInitialDirContext() :
|
||||||
dirContextFactory.newInitialDirContext(managerDn, password);
|
dirContextFactory.newInitialDirContext(principalDn, password);
|
||||||
|
|
||||||
return callback.execute(ctx);
|
return callback.execute(ctx);
|
||||||
|
|
||||||
@ -98,8 +130,10 @@ public class LdapTemplate {
|
|||||||
ctls.setReturningAttributes(NO_ATTRS);
|
ctls.setReturningAttributes(NO_ATTRS);
|
||||||
ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
|
ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
|
||||||
|
|
||||||
|
String relativeName = LdapUtils.getRelativeName(dn, ctx);
|
||||||
|
|
||||||
NamingEnumeration results =
|
NamingEnumeration results =
|
||||||
ctx.search(dn, comparisonFilter, new Object[]{value}, ctls);
|
ctx.search(relativeName, comparisonFilter, new Object[]{value}, ctls);
|
||||||
|
|
||||||
return Boolean.valueOf(results.hasMore());
|
return Boolean.valueOf(results.hasMore());
|
||||||
}
|
}
|
||||||
@ -132,7 +166,9 @@ public class LdapTemplate {
|
|||||||
|
|
||||||
SearchControls ctls = new SearchControls();
|
SearchControls ctls = new SearchControls();
|
||||||
|
|
||||||
ctls.setSearchScope(searchScope);
|
ctls.setSearchScope(searchControls.getSearchScope());
|
||||||
|
ctls.setTimeLimit(searchControls.getTimeLimit());
|
||||||
|
ctls.setDerefLinkFlag(searchControls.getDerefLinkFlag());
|
||||||
ctls.setReturningAttributes(new String[] {attributeName});
|
ctls.setReturningAttributes(new String[] {attributeName});
|
||||||
|
|
||||||
NamingEnumeration matchingEntries =
|
NamingEnumeration matchingEntries =
|
||||||
@ -191,13 +227,65 @@ public class LdapTemplate {
|
|||||||
* @param attributesToRetrieve the named attributes which will be retrieved from the directory entry.
|
* @param attributesToRetrieve the named attributes which will be retrieved from the directory entry.
|
||||||
* @return the object created by the mapper
|
* @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() {
|
return execute ( new LdapCallback() {
|
||||||
|
|
||||||
public Object execute(DirContext ctx) throws NamingException {
|
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());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,16 +22,9 @@ import javax.naming.NamingException;
|
|||||||
/**
|
/**
|
||||||
* A user representation which is used internally by the Ldap provider.
|
* 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.
|
* @deprecated in favour of {@link org.acegisecurity.userdetails.ldap.LdapUserDetails}
|
||||||
* <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>
|
|
||||||
*
|
*
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
package org.acegisecurity.ldap;
|
package org.acegisecurity.ldap;
|
||||||
|
|
||||||
|
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a user's information from the LDAP directory given a login name.
|
* Obtains a user's information from the LDAP directory given a login name.
|
||||||
* <p>
|
* <p>
|
||||||
@ -33,9 +35,8 @@ public interface LdapUserSearch {
|
|||||||
* for that user.
|
* for that user.
|
||||||
*
|
*
|
||||||
* @param username the login name supplied to the authentication service.
|
* @param username the login name supplied to the authentication service.
|
||||||
* @return an LdapUserInfo object containing the user's full DN and requested attributes.
|
* @return an LdapUserDetailsImpl object containing the user's full DN and requested attributes.
|
||||||
* TODO: Need to optionally supply required attributes here for the search.
|
|
||||||
*/
|
*/
|
||||||
LdapUserInfo searchForUser(String username);
|
LdapUserDetails searchForUser(String username);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,24 +16,22 @@
|
|||||||
package org.acegisecurity.ldap.search;
|
package org.acegisecurity.ldap.search;
|
||||||
|
|
||||||
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
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.LdapUserSearch;
|
||||||
import org.acegisecurity.ldap.LdapUtils;
|
|
||||||
import org.acegisecurity.ldap.InitialDirContextFactory;
|
import org.acegisecurity.ldap.InitialDirContextFactory;
|
||||||
import org.acegisecurity.ldap.LdapUserInfo;
|
import org.acegisecurity.ldap.LdapTemplate;
|
||||||
import org.acegisecurity.ldap.LdapDataAccessException;
|
import org.acegisecurity.ldap.LdapEntryMapper;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import javax.naming.directory.SearchControls;
|
import javax.naming.directory.SearchControls;
|
||||||
import javax.naming.directory.SearchResult;
|
|
||||||
import javax.naming.directory.DirContext;
|
import javax.naming.directory.DirContext;
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.naming.NamingEnumeration;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LdapUserSearch implementation which uses an Ldap filter to locate the user.
|
* LdapUserSearch implementation which uses an Ldap filter to locate the user.
|
||||||
@ -82,6 +80,8 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch {
|
|||||||
|
|
||||||
private InitialDirContextFactory initialDirContextFactory;
|
private InitialDirContextFactory initialDirContextFactory;
|
||||||
|
|
||||||
|
private LdapEntryMapper userDetailsMapper = new LdapUserDetailsMapper();
|
||||||
|
|
||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
|
||||||
public FilterBasedLdapUserSearch(String searchBase,
|
public FilterBasedLdapUserSearch(String searchBase,
|
||||||
@ -104,12 +104,12 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch {
|
|||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the LdapUserInfo containing the user's information, or null if
|
* Return the LdapUserDetailsImpl containing the user's information
|
||||||
* no SearchResult is found.
|
|
||||||
*
|
*
|
||||||
* @param username the username to search for.
|
* @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();
|
DirContext ctx = initialDirContextFactory.newInitialDirContext();
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
@ -117,42 +117,20 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch {
|
|||||||
", with user search " + this.toString());
|
", with user search " + this.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LdapTemplate template = new LdapTemplate(initialDirContextFactory);
|
||||||
|
|
||||||
|
template.setSearchControls(searchControls);
|
||||||
|
|
||||||
try {
|
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()) {
|
} catch(EmptyResultDataAccessException notFound) {
|
||||||
throw new UsernameNotFoundException("User " + username + " not found in directory.");
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,9 +17,9 @@ package org.acegisecurity.providers.ldap;
|
|||||||
|
|
||||||
import org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider;
|
import org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider;
|
||||||
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
import org.acegisecurity.ldap.LdapUserInfo;
|
|
||||||
import org.acegisecurity.userdetails.UserDetails;
|
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.AuthenticationException;
|
||||||
import org.acegisecurity.BadCredentialsException;
|
import org.acegisecurity.BadCredentialsException;
|
||||||
|
|
||||||
@ -29,8 +29,6 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import javax.naming.directory.Attributes;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link org.acegisecurity.providers.AuthenticationProvider} implementation that
|
* An {@link org.acegisecurity.providers.AuthenticationProvider} implementation that
|
||||||
* provides integration with an LDAP server.
|
* provides integration with an LDAP server.
|
||||||
@ -156,33 +154,35 @@ public class LdapAuthenticationProvider extends AbstractUserDetailsAuthenticatio
|
|||||||
String password = (String)authentication.getCredentials();
|
String password = (String)authentication.getCredentials();
|
||||||
Assert.notNull(password, "Null password was supplied in authentication token");
|
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.
|
* once the user has been authenticated.
|
||||||
* <p>
|
* <p>
|
||||||
* The <tt>LdapAuthoritiesPopulator</tt> will be used to create the granted authorites for the
|
* The <tt>LdapAuthoritiesPopulator</tt> will be used to create the granted authorites for the
|
||||||
* user.
|
* user.
|
||||||
* </p>
|
* </p>
|
||||||
* <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>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param username The user login, as passed to the provider
|
* @param ldapUser The intermediate LdapUserDetails instance returned from the authenticator.
|
||||||
* @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.
|
|
||||||
* @return The UserDetails for the successfully authenticated user.
|
* @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,
|
LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence(ldapUser);
|
||||||
authoritiesPopulator.getGrantedAuthorities(username, userDn, attributes));
|
|
||||||
|
|
||||||
|
user.setAuthorities(authoritiesPopulator.getGrantedAuthorities(ldapUser));
|
||||||
|
|
||||||
|
return user.createUserDetails();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected LdapAuthoritiesPopulator getAuthoritiesPoulator() {
|
protected LdapAuthoritiesPopulator getAuthoritiesPoulator() {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
package org.acegisecurity.providers.ldap;
|
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.
|
* 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.
|
* @param password the user's password supplied at login.
|
||||||
* @return the details of the successfully authenticated user.
|
* @return the details of the successfully authenticated user.
|
||||||
*/
|
*/
|
||||||
LdapUserInfo authenticate(String username, String password);
|
LdapUserDetails authenticate(String username, String password);
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,9 @@
|
|||||||
package org.acegisecurity.providers.ldap;
|
package org.acegisecurity.providers.ldap;
|
||||||
|
|
||||||
import org.acegisecurity.GrantedAuthority;
|
import org.acegisecurity.GrantedAuthority;
|
||||||
|
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
|
||||||
import org.acegisecurity.ldap.LdapDataAccessException;
|
import org.acegisecurity.ldap.LdapDataAccessException;
|
||||||
|
|
||||||
import javax.naming.directory.Attributes;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtains a list of granted authorities for an Ldap user.
|
* Obtains a list of granted authorities for an Ldap user.
|
||||||
* <p>
|
* <p>
|
||||||
@ -35,13 +34,11 @@ public interface LdapAuthoritiesPopulator {
|
|||||||
/**
|
/**
|
||||||
* Get the list of authorities for the user.
|
* Get the list of authorities for the user.
|
||||||
*
|
*
|
||||||
* @param username the login name which was passed to the LDAP provider.
|
* @param userDetails the user details object which was returned by the LDAP authenticator.
|
||||||
* @param userDn the full DN of the user
|
|
||||||
* @param userAttributes the user's LDAP attributes that were retrieved from the directory.
|
|
||||||
* @return the granted authorities for the given user.
|
* @return the granted authorities for the given user.
|
||||||
* @throws org.acegisecurity.ldap.LdapDataAccessException if there is a problem accessing the directory.
|
* @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;
|
throws LdapDataAccessException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,9 @@ package org.acegisecurity.providers.ldap.authenticator;
|
|||||||
import org.acegisecurity.providers.ldap.LdapAuthenticator;
|
import org.acegisecurity.providers.ldap.LdapAuthenticator;
|
||||||
import org.acegisecurity.ldap.InitialDirContextFactory;
|
import org.acegisecurity.ldap.InitialDirContextFactory;
|
||||||
import org.acegisecurity.ldap.LdapUserSearch;
|
import org.acegisecurity.ldap.LdapUserSearch;
|
||||||
|
import org.acegisecurity.ldap.LdapEntryMapper;
|
||||||
import org.acegisecurity.AcegiMessageSource;
|
import org.acegisecurity.AcegiMessageSource;
|
||||||
|
import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.util.Assert;
|
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 */
|
/** The attributes which will be retrieved from the directory. Null means all attributes */
|
||||||
private String[] userAttributes = null;
|
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
|
* The suffix to be added to the DN patterns, worked out internally from the root DN of the
|
||||||
* configured InitialDirContextFactory.
|
* configured InitialDirContextFactory.
|
||||||
@ -137,6 +141,15 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator,
|
|||||||
this.userSearch = userSearch;
|
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() {
|
protected LdapUserSearch getUserSearch() {
|
||||||
return userSearch;
|
return userSearch;
|
||||||
}
|
}
|
||||||
|
@ -15,18 +15,14 @@
|
|||||||
|
|
||||||
package org.acegisecurity.providers.ldap.authenticator;
|
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.InitialDirContextFactory;
|
||||||
|
import org.acegisecurity.ldap.LdapTemplate;
|
||||||
import org.acegisecurity.BadCredentialsException;
|
import org.acegisecurity.BadCredentialsException;
|
||||||
|
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import javax.naming.directory.DirContext;
|
|
||||||
import javax.naming.directory.Attributes;
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
@ -44,6 +40,7 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
|||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(BindAuthenticator.class);
|
private static final Log logger = LogFactory.getLog(BindAuthenticator.class);
|
||||||
|
|
||||||
|
|
||||||
//~ Constructors ===========================================================
|
//~ Constructors ===========================================================
|
||||||
|
|
||||||
public BindAuthenticator(InitialDirContextFactory initialDirContextFactory) {
|
public BindAuthenticator(InitialDirContextFactory initialDirContextFactory) {
|
||||||
@ -52,9 +49,9 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
|||||||
|
|
||||||
//~ Methods ================================================================
|
//~ 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
|
// If DN patterns are configured, try authenticating with them directly
|
||||||
Iterator dns = getUserDns(username).iterator();
|
Iterator dns = getUserDns(username).iterator();
|
||||||
@ -66,7 +63,7 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
|||||||
// Otherwise use the configured locator to find the user
|
// Otherwise use the configured locator to find the user
|
||||||
// and authenticate with the returned DN.
|
// and authenticate with the returned DN.
|
||||||
if (user == null && getUserSearch() != null) {
|
if (user == null && getUserSearch() != null) {
|
||||||
LdapUserInfo userFromSearch = getUserSearch().searchForUser(username);
|
LdapUserDetails userFromSearch = getUserSearch().searchForUser(username);
|
||||||
user = bindWithDn(userFromSearch.getDn(), password);
|
user = bindWithDn(userFromSearch.getDn(), password);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,18 +77,19 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LdapUserInfo bindWithDn(String userDn, String password) {
|
LdapUserDetails bindWithDn(String userDn, String password) {
|
||||||
DirContext ctx = null;
|
LdapTemplate template = new LdapTemplate(getInitialDirContextFactory(), userDn, password);
|
||||||
LdapUserInfo user = null;
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Attempting to bind with DN = " + userDn);
|
logger.debug("Attempting to bind with DN = " + userDn);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ctx = getInitialDirContextFactory().newInitialDirContext(userDn, password);
|
|
||||||
Attributes attributes = loadAttributes(ctx, userDn);
|
Object user = (LdapUserDetails)template.retrieveEntry(userDn, getUserDetailsMapper(), getUserAttributes());
|
||||||
user = new LdapUserInfo(userDn, attributes);
|
Assert.isInstanceOf(LdapUserDetails.class, user, "Entry mapper must return an LdapUserDetails instance");
|
||||||
|
|
||||||
|
return (LdapUserDetails) user;
|
||||||
|
|
||||||
} catch(BadCredentialsException e) {
|
} catch(BadCredentialsException e) {
|
||||||
// This will be thrown if an invalid user name is used and the method may
|
// 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()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Failed to bind as " + userDn + ": " + e.getCause());
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,10 @@
|
|||||||
|
|
||||||
package org.acegisecurity.providers.ldap.authenticator;
|
package org.acegisecurity.providers.ldap.authenticator;
|
||||||
|
|
||||||
import org.acegisecurity.ldap.LdapUserInfo;
|
|
||||||
import org.acegisecurity.ldap.LdapUtils;
|
import org.acegisecurity.ldap.LdapUtils;
|
||||||
import org.acegisecurity.ldap.InitialDirContextFactory;
|
import org.acegisecurity.ldap.InitialDirContextFactory;
|
||||||
import org.acegisecurity.ldap.LdapTemplate;
|
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.providers.encoding.PasswordEncoder;
|
||||||
import org.acegisecurity.BadCredentialsException;
|
import org.acegisecurity.BadCredentialsException;
|
||||||
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
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;
|
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 Log logger = LogFactory.getLog(PasswordComparisonAuthenticator.class);
|
||||||
|
|
||||||
private static final String[] NO_ATTRS = new String[0];
|
|
||||||
|
|
||||||
//~ Instance fields ========================================================
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
private String passwordAttributeName = "userPassword";
|
private String passwordAttributeName = "userPassword";
|
||||||
|
|
||||||
private String passwordCompareFilter = "(userPassword={0})";
|
|
||||||
|
|
||||||
private PasswordEncoder passwordEncoder = new LdapShaPasswordEncoder();
|
private PasswordEncoder passwordEncoder = new LdapShaPasswordEncoder();
|
||||||
|
|
||||||
//~ Constructors ===========================================================
|
//~ Constructors ===========================================================
|
||||||
@ -80,10 +68,10 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
|
|||||||
|
|
||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
|
||||||
public LdapUserInfo authenticate(String username, String password) {
|
public LdapUserDetails authenticate(final String username, final String password) {
|
||||||
|
|
||||||
// locate the user and check the password
|
// locate the user and check the password
|
||||||
LdapUserInfo user = null;
|
LdapUserDetails user = null;
|
||||||
|
|
||||||
Iterator dns = getUserDns(username).iterator();
|
Iterator dns = getUserDns(username).iterator();
|
||||||
|
|
||||||
@ -93,13 +81,7 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
|
|||||||
final String userDn = (String)dns.next();
|
final String userDn = (String)dns.next();
|
||||||
|
|
||||||
if(ldapTemplate.nameExists(userDn)) {
|
if(ldapTemplate.nameExists(userDn)) {
|
||||||
AttributesMapper mapper = new AttributesMapper() {
|
user = (LdapUserDetails)ldapTemplate.retrieveEntry(userDn, getUserDetailsMapper(), getUserAttributes());
|
||||||
public Object mapAttributes(Attributes attributes) {
|
|
||||||
return new LdapUserInfo(userDn, attributes);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
user = (LdapUserInfo)ldapTemplate.retrieveEntry(userDn, mapper, getUserAttributes());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,40 +93,36 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
|
|||||||
throw new UsernameNotFoundException(username);
|
throw new UsernameNotFoundException(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
DirContext ctx = getInitialDirContextFactory().newInitialDirContext();
|
String retrievedPassword = user.getPassword();
|
||||||
|
|
||||||
try {
|
if(retrievedPassword != null) {
|
||||||
Attribute passwordAttribute = user.getAttributes().get(passwordAttributeName);
|
if (!verifyPassword(password, retrievedPassword)) {
|
||||||
|
|
||||||
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(
|
throw new BadCredentialsException(messages.getMessage(
|
||||||
"PasswordComparisonAuthenticator.badCredentials",
|
"PasswordComparisonAuthenticator.badCredentials",
|
||||||
"Bad credentials"));
|
"Bad credentials"));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
return user;
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Password attribute " + passwordAttributeName
|
|
||||||
+ " wasn't retrieved for user " + username);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
doPasswordCompare(ctx, user.getRelativeName(ctx), password);
|
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;
|
return user;
|
||||||
} catch(NamingException ne) {
|
|
||||||
throw new BadCredentialsException("Authentication failed due to exception ", ne);
|
|
||||||
} finally {
|
|
||||||
LdapUtils.closeContext(ctx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,32 +140,9 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
|
|||||||
return false;
|
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) {
|
public void setPasswordAttributeName(String passwordAttribute) {
|
||||||
Assert.hasLength(passwordAttribute, "passwordAttributeName must not be empty or null");
|
Assert.hasLength(passwordAttribute, "passwordAttributeName must not be empty or null");
|
||||||
this.passwordAttributeName = passwordAttribute;
|
this.passwordAttributeName = passwordAttribute;
|
||||||
this.passwordCompareFilter = "(" + passwordAttributeName + "={0})";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
|
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
|
||||||
|
@ -16,24 +16,20 @@
|
|||||||
package org.acegisecurity.providers.ldap.populator;
|
package org.acegisecurity.providers.ldap.populator;
|
||||||
|
|
||||||
import org.acegisecurity.providers.ldap.LdapAuthoritiesPopulator;
|
import org.acegisecurity.providers.ldap.LdapAuthoritiesPopulator;
|
||||||
import org.acegisecurity.ldap.LdapDataAccessException;
|
|
||||||
import org.acegisecurity.ldap.InitialDirContextFactory;
|
import org.acegisecurity.ldap.InitialDirContextFactory;
|
||||||
import org.acegisecurity.ldap.LdapUtils;
|
import org.acegisecurity.ldap.LdapTemplate;
|
||||||
import org.acegisecurity.GrantedAuthority;
|
import org.acegisecurity.GrantedAuthority;
|
||||||
import org.acegisecurity.GrantedAuthorityImpl;
|
import org.acegisecurity.GrantedAuthorityImpl;
|
||||||
|
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import javax.naming.directory.Attributes;
|
import javax.naming.directory.Attributes;
|
||||||
import javax.naming.directory.Attribute;
|
|
||||||
import javax.naming.directory.SearchControls;
|
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.Set;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default strategy for obtaining user role information from the directory.
|
* The default strategy for obtaining user role information from the directory.
|
||||||
@ -114,7 +110,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
|||||||
//~ Instance fields ========================================================
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
/** Attributes of the User's LDAP Object that contain role name information. */
|
/** Attributes of the User's LDAP Object that contain role name information. */
|
||||||
private String[] userRoleAttributes = null;
|
// private String[] userRoleAttributes = null;
|
||||||
|
|
||||||
private String rolePrefix = "ROLE_";
|
private String rolePrefix = "ROLE_";
|
||||||
|
|
||||||
@ -175,21 +171,26 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
|||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @return the set of roles granted to the user.
|
||||||
* @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.
|
|
||||||
*/
|
*/
|
||||||
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);
|
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) {
|
if(oldGroupRoles != null) {
|
||||||
roles.addAll(groupRoles);
|
roles.addAll(oldGroupRoles);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set extraRoles = getAdditionalRoles(userDetails);
|
||||||
|
|
||||||
|
if(extraRoles != null) {
|
||||||
|
roles.addAll(extraRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(defaultRole != null) {
|
if(defaultRole != null) {
|
||||||
@ -199,31 +200,23 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
|||||||
return (GrantedAuthority[])roles.toArray(new GrantedAuthority[roles.size()]);
|
return (GrantedAuthority[])roles.toArray(new GrantedAuthority[roles.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Set getRolesFromUserAttributes(String userDn, Attributes userAttributes) {
|
// protected Set getRolesFromUserAttributes(String userDn, Attributes userAttributes) {
|
||||||
Set userRoles = new HashSet();
|
// 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++) {
|
private Set getGroupMembershipRoles(String userDn) {
|
||||||
Attribute roleAttribute = userAttributes.get(userRoleAttributes[i]);
|
Set authorities = new HashSet();
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
if (groupSearchBase == null) {
|
if (groupSearchBase == null) {
|
||||||
return null;
|
return authorities;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
@ -232,52 +225,20 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
|||||||
+ " in search base '" + groupSearchBase + "'");
|
+ " in search base '" + groupSearchBase + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
DirContext ctx = initialDirContextFactory.newInitialDirContext();
|
LdapTemplate template = new LdapTemplate(initialDirContextFactory);
|
||||||
SearchControls ctls = new SearchControls();
|
|
||||||
|
|
||||||
ctls.setSearchScope(searchScope);
|
template.setSearchScope(searchScope);
|
||||||
ctls.setReturningAttributes(new String[] {groupRoleAttribute});
|
|
||||||
|
|
||||||
try {
|
Set userRoles = template.searchForSingleAttributeValues(groupSearchBase, groupSearchFilter, new String[]{userDn}, groupRoleAttribute);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Roles from search: " + userRoles);
|
logger.debug("Roles from search: " + userRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
return userRoles;
|
Iterator it = userRoles.iterator();
|
||||||
}
|
|
||||||
|
|
||||||
private void addAttributeValuesToRoleSet(Attribute roleAttribute, Set roles) {
|
while(it.hasNext()) {
|
||||||
if (roleAttribute == null) {
|
Object role = it.next();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
NamingEnumeration attributeRoles = roleAttribute.getAll();
|
|
||||||
|
|
||||||
while(attributeRoles.hasMore()) {
|
|
||||||
Object role = attributeRoles.next();
|
|
||||||
|
|
||||||
// We only handle Strings for the time being
|
// We only handle Strings for the time being
|
||||||
if(role instanceof String) {
|
if(role instanceof String) {
|
||||||
@ -285,29 +246,39 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
|||||||
role = ((String)role).toUpperCase();
|
role = ((String)role).toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
roles.add(new GrantedAuthorityImpl(rolePrefix + role));
|
authorities.add(new GrantedAuthorityImpl(rolePrefix + role));
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Non-String value found for role attribute " + roleAttribute.getID());
|
logger.warn("Non-String value found for role: " + role);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(NamingException ne) {
|
|
||||||
throw new LdapDataAccessException("Error retrieving values for role attribute " +
|
return authorities;
|
||||||
roleAttribute.getID(), ne);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected Set getAdditionalRoles(LdapUserDetails ldapUser) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() {
|
protected InitialDirContextFactory getInitialDirContextFactory() {
|
||||||
return initialDirContextFactory;
|
return initialDirContextFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String[] getUserRoleAttributes() {
|
|
||||||
return userRoleAttributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserRoleAttributes(String[] userRoleAttributes) {
|
|
||||||
this.userRoleAttributes = userRoleAttributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRolePrefix(String rolePrefix) {
|
public void setRolePrefix(String rolePrefix) {
|
||||||
Assert.notNull(rolePrefix, "rolePrefix must not be null");
|
Assert.notNull(rolePrefix, "rolePrefix must not be null");
|
||||||
this.rolePrefix = rolePrefix;
|
this.rolePrefix = rolePrefix;
|
||||||
|
@ -163,14 +163,27 @@ public class FilterChainProxy implements Filter, InitializingBean,
|
|||||||
}
|
}
|
||||||
|
|
||||||
chain.doFilter(request, response);
|
chain.doFilter(request, response);
|
||||||
} else {
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Filter[] filters = obtainAllDefinedFilters(cad);
|
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,
|
VirtualFilterChain virtualFilterChain = new VirtualFilterChain(fi,
|
||||||
filters);
|
filters);
|
||||||
virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse());
|
virtualFilterChain.doFilter(fi.getRequest(), fi.getResponse());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public FilterInvocationDefinitionSource getFilterInvocationDefinitionSource() {
|
public FilterInvocationDefinitionSource getFilterInvocationDefinitionSource() {
|
||||||
return filterInvocationDefinitionSource;
|
return filterInvocationDefinitionSource;
|
||||||
@ -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();
|
ConfigAttribute attr = (ConfigAttribute) attributes.next();
|
||||||
String filterName = attr.getAttribute();
|
String filterName = attr.getAttribute();
|
||||||
|
|
||||||
Assert.notNull(filterName,
|
if(filterName == null) {
|
||||||
"Configuration attribute: '" + attr
|
throw new IllegalArgumentException("Configuration attribute: '" + attr
|
||||||
+ "' returned null to the getAttribute() method, which is invalid when used with FilterChainProxy");
|
+ "' returned null to the getAttribute() method, which is invalid when used with FilterChainProxy");
|
||||||
|
}
|
||||||
|
|
||||||
if (!filterName.equals(TOKEN_NONE)) {
|
if (!filterName.equals(TOKEN_NONE)) {
|
||||||
list.add(this.applicationContext.getBean(filterName,
|
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)
|
public void setApplicationContext(ApplicationContext applicationContext)
|
||||||
|
@ -19,8 +19,6 @@ import junit.framework.TestCase;
|
|||||||
|
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
|
||||||
import org.apache.directory.server.core.jndi.CoreContextFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
@ -31,16 +29,16 @@ public abstract class AbstractLdapServerTestCase extends TestCase {
|
|||||||
protected static final String MANAGER_PASSWORD = "acegisecurity";
|
protected static final String MANAGER_PASSWORD = "acegisecurity";
|
||||||
|
|
||||||
// External server config
|
// External server config
|
||||||
// private static final String PROVIDER_URL = "ldap://monkeymachine:389/"+ROOT_DN;
|
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 String CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
|
||||||
// private static final Hashtable EXTRA_ENV = new Hashtable();
|
private static final Hashtable EXTRA_ENV = new Hashtable();
|
||||||
|
|
||||||
|
|
||||||
// Embedded (non-networked) server config
|
// Embedded (non-networked) server config
|
||||||
private static final LdapTestServer SERVER = new LdapTestServer();
|
// private static final LdapTestServer SERVER = new LdapTestServer();
|
||||||
private static final String PROVIDER_URL = ROOT_DN;
|
// private static final String PROVIDER_URL = ROOT_DN;
|
||||||
private static final String CONTEXT_FACTORY = CoreContextFactory.class.getName();
|
// private static final String CONTEXT_FACTORY = CoreContextFactory.class.getName();
|
||||||
private static final Hashtable EXTRA_ENV = SERVER.getConfiguration().toJndiEnvironment();
|
// private static final Hashtable EXTRA_ENV = SERVER.getConfiguration().toJndiEnvironment();
|
||||||
|
|
||||||
protected AbstractLdapServerTestCase() {
|
protected AbstractLdapServerTestCase() {
|
||||||
}
|
}
|
||||||
|
@ -33,27 +33,27 @@ public class LdapTemplateTests extends AbstractLdapServerTestCase {
|
|||||||
|
|
||||||
|
|
||||||
public void testCompareOfCorrectValueSucceeds() {
|
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() {
|
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() {
|
public void testCompareOfCorrectByteValueSucceeds() {
|
||||||
|
|
||||||
// Doesn't work with embedded server due to bugs in apacheds
|
// 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() {
|
public void testCompareOfWrongByteValueFails() {
|
||||||
|
|
||||||
// Doesn't work with embedded server due to bugs in apacheds
|
// 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() {
|
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");
|
Set values = template.searchForSingleAttributeValues("ou=groups", "(member={0})", new String[] {param}, "ou");
|
||||||
|
|
||||||
|
@ -2,9 +2,9 @@ package org.acegisecurity.ldap.search;
|
|||||||
|
|
||||||
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
|
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
|
||||||
import org.acegisecurity.ldap.DefaultInitialDirContextFactory;
|
import org.acegisecurity.ldap.DefaultInitialDirContextFactory;
|
||||||
import org.acegisecurity.ldap.LdapUserInfo;
|
|
||||||
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
||||||
import org.acegisecurity.BadCredentialsException;
|
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
|
||||||
|
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for FilterBasedLdapUserSearch.
|
* Tests for FilterBasedLdapUserSearch.
|
||||||
@ -32,7 +32,7 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapServerTestCase {
|
|||||||
public void testBasicSearch() throws Exception {
|
public void testBasicSearch() throws Exception {
|
||||||
FilterBasedLdapUserSearch locator =
|
FilterBasedLdapUserSearch locator =
|
||||||
new FilterBasedLdapUserSearch("ou=people", "(uid={0})", dirCtxFactory);
|
new FilterBasedLdapUserSearch("ou=people", "(uid={0})", dirCtxFactory);
|
||||||
LdapUserInfo bob = locator.searchForUser("bob");
|
LdapUserDetails bob = locator.searchForUser("bob");
|
||||||
locator.setSearchSubtree(false);
|
locator.setSearchSubtree(false);
|
||||||
locator.setSearchTimeLimit(0);
|
locator.setSearchTimeLimit(0);
|
||||||
// name is wrong with embedded apacheDS
|
// name is wrong with embedded apacheDS
|
||||||
@ -45,7 +45,7 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapServerTestCase {
|
|||||||
new FilterBasedLdapUserSearch("", "(cn={0})", dirCtxFactory);
|
new FilterBasedLdapUserSearch("", "(cn={0})", dirCtxFactory);
|
||||||
locator.setSearchSubtree(true);
|
locator.setSearchSubtree(true);
|
||||||
|
|
||||||
LdapUserInfo ben = locator.searchForUser("Ben Alex");
|
LdapUserDetails ben = locator.searchForUser("Ben Alex");
|
||||||
// assertEquals("uid=ben,ou=people,"+ROOT_DN, bob.getDn());
|
// assertEquals("uid=ben,ou=people,"+ROOT_DN, bob.getDn());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapServerTestCase {
|
|||||||
try {
|
try {
|
||||||
locator.searchForUser("Ignored");
|
locator.searchForUser("Ignored");
|
||||||
fail("Expected exception for multiple search matches.");
|
fail("Expected exception for multiple search matches.");
|
||||||
} catch (BadCredentialsException expected) {
|
} catch (IncorrectResultSizeDataAccessException expected) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapServerTestCase {
|
|||||||
dirCtxFactory);
|
dirCtxFactory);
|
||||||
|
|
||||||
// Search for bob, get back ben...
|
// Search for bob, get back ben...
|
||||||
LdapUserInfo ben = locator.searchForUser("bob");
|
LdapUserDetails ben = locator.searchForUser("bob");
|
||||||
String cn = (String)ben.getAttributes().get("cn").get();
|
String cn = (String)ben.getAttributes().get("cn").get();
|
||||||
assertEquals("Ben Alex", cn);
|
assertEquals("Ben Alex", cn);
|
||||||
// assertEquals("uid=ben,ou=people,"+ROOT_DN, ben.getDn());
|
// assertEquals("uid=ben,ou=people,"+ROOT_DN, ben.getDn());
|
||||||
|
@ -6,11 +6,12 @@ import javax.naming.directory.BasicAttributes;
|
|||||||
import org.acegisecurity.GrantedAuthority;
|
import org.acegisecurity.GrantedAuthority;
|
||||||
import org.acegisecurity.GrantedAuthorityImpl;
|
import org.acegisecurity.GrantedAuthorityImpl;
|
||||||
import org.acegisecurity.BadCredentialsException;
|
import org.acegisecurity.BadCredentialsException;
|
||||||
import org.acegisecurity.ldap.LdapUserInfo;
|
import org.acegisecurity.ldap.*;
|
||||||
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
|
|
||||||
import org.acegisecurity.ldap.DefaultInitialDirContextFactory;
|
import org.acegisecurity.ldap.DefaultInitialDirContextFactory;
|
||||||
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
import org.acegisecurity.userdetails.UserDetails;
|
import org.acegisecurity.userdetails.UserDetails;
|
||||||
|
import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
|
||||||
|
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
@ -82,7 +83,7 @@ public class LdapAuthenticationProviderTests extends AbstractLdapServerTestCase
|
|||||||
*/
|
*/
|
||||||
class MockAuthoritiesPopulator implements LdapAuthoritiesPopulator {
|
class MockAuthoritiesPopulator implements LdapAuthoritiesPopulator {
|
||||||
|
|
||||||
public GrantedAuthority[] getGrantedAuthorities(String userDn, String dn, Attributes userAttributes) {
|
public GrantedAuthority[] getGrantedAuthorities(LdapUserDetails userDetailsll) {
|
||||||
return new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_USER") };
|
return new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_USER") };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,10 +91,12 @@ public class LdapAuthenticationProviderTests extends AbstractLdapServerTestCase
|
|||||||
class MockAuthenticator implements LdapAuthenticator {
|
class MockAuthenticator implements LdapAuthenticator {
|
||||||
Attributes userAttributes = new BasicAttributes("cn","bob");
|
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")) {
|
if(username.equals("bob") && password.equals("bobspassword")) {
|
||||||
|
LdapUserDetailsImpl.Essence creator = new LdapUserDetailsImpl.Essence();
|
||||||
return new LdapUserInfo("cn=bob,ou=people,dc=acegisecurity,dc=org", userAttributes);
|
creator.setDn("cn=bob,ou=people,dc=acegisecurity,dc=org");
|
||||||
|
creator.setAttributes(userAttributes);
|
||||||
|
return creator.createUserDetails();
|
||||||
}
|
}
|
||||||
throw new BadCredentialsException("Authentication of Bob failed.");
|
throw new BadCredentialsException("Authentication of Bob failed.");
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package org.acegisecurity.providers.ldap.authenticator;
|
package org.acegisecurity.providers.ldap.authenticator;
|
||||||
|
|
||||||
import org.acegisecurity.ldap.LdapUserInfo;
|
|
||||||
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
|
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
|
||||||
import org.acegisecurity.BadCredentialsException;
|
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}.
|
* Tests for {@link BindAuthenticator}.
|
||||||
@ -26,12 +29,10 @@ public class BindAuthenticatorTests extends AbstractLdapServerTestCase {
|
|||||||
|
|
||||||
public void testAuthenticationWithCorrectPasswordSucceeds() throws Exception {
|
public void testAuthenticationWithCorrectPasswordSucceeds() throws Exception {
|
||||||
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
|
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
|
||||||
LdapUserInfo user = authenticator.authenticate("bob","bobspassword");
|
LdapUserDetails user = authenticator.authenticate("bob","bobspassword");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAuthenticationWithWrongPasswordFails() {
|
public void testAuthenticationWithWrongPasswordFails() {
|
||||||
// BindAuthenticator authenticator = new BindAuthenticator(dirCtxFactory);
|
|
||||||
|
|
||||||
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
|
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -42,25 +43,36 @@ public class BindAuthenticatorTests extends AbstractLdapServerTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testAuthenticationWithUserSearch() throws Exception {
|
public void testAuthenticationWithUserSearch() throws Exception {
|
||||||
LdapUserInfo user = new LdapUserInfo("uid=bob,ou=people," + getInitialCtxFactory().getRootDn(), null);
|
LdapUserDetailsImpl.Essence userEssence = new LdapUserDetailsImpl.Essence();
|
||||||
authenticator.setUserSearch(new MockUserSearch(user));
|
userEssence.setDn("uid=bob,ou=people,dc=acegisecurity,dc=org");
|
||||||
|
|
||||||
|
authenticator.setUserSearch(new MockUserSearch(userEssence.createUserDetails()));
|
||||||
authenticator.afterPropertiesSet();
|
authenticator.afterPropertiesSet();
|
||||||
authenticator.authenticate("bob","bobspassword");
|
authenticator.authenticate("bob","bobspassword");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testAuthenticationWithInvalidUserNameFails() {
|
||||||
|
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
|
||||||
|
|
||||||
// Apache DS falls apart with unknown DNs.
|
try {
|
||||||
//
|
authenticator.authenticate("nonexistentsuser","bobspassword");
|
||||||
// public void testAuthenticationWithInvalidUserNameFails() {
|
fail("Shouldn't be able to bind with invalid username");
|
||||||
// BindAuthenticator authenticator = new BindAuthenticator();
|
} catch(BadCredentialsException expected) {
|
||||||
//
|
}
|
||||||
// authenticator.setInitialDirContextFactory(dirCtxFactory);
|
}
|
||||||
// authenticator.setUserDnPatterns("cn={0},ou=people");
|
|
||||||
// try {
|
// TODO: Create separate tests for base class
|
||||||
// authenticator.authenticate("Baz","bobspassword");
|
public void testRoleRetrieval() {
|
||||||
// fail("Shouldn't be able to bind with invalid username");
|
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
|
||||||
// } catch(BadCredentialsException expected) {
|
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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
package org.acegisecurity.providers.ldap.authenticator;
|
package org.acegisecurity.providers.ldap.authenticator;
|
||||||
|
|
||||||
import org.acegisecurity.ldap.LdapUserInfo;
|
|
||||||
import org.acegisecurity.ldap.LdapUserSearch;
|
import org.acegisecurity.ldap.LdapUserSearch;
|
||||||
|
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
public class MockUserSearch implements LdapUserSearch {
|
public class MockUserSearch implements LdapUserSearch {
|
||||||
LdapUserInfo user;
|
LdapUserDetails user;
|
||||||
|
|
||||||
public MockUserSearch(LdapUserInfo user) {
|
public MockUserSearch(LdapUserDetails user) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LdapUserInfo searchForUser(String username) {
|
public LdapUserDetails searchForUser(String username) {
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,12 +27,13 @@ public class PasswordComparisonAuthenticatorMockTests extends MockObjectTestCase
|
|||||||
|
|
||||||
// Get the mock to return an empty attribute set
|
// Get the mock to return an empty attribute set
|
||||||
mockCtx.expects(atLeastOnce()).method("getNameInNamespace").will(returnValue("dc=acegisecurity,dc=org"));
|
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()));
|
mockCtx.expects(once()).method("getAttributes").with(eq("cn=Bob,ou=people"), NULL).will(returnValue(new BasicAttributes()));
|
||||||
// Setup a single return value (i.e. success)
|
// Setup a single return value (i.e. success)
|
||||||
Attributes searchResults = new BasicAttributes("", null);
|
Attributes searchResults = new BasicAttributes("", null);
|
||||||
mockCtx.expects(once()).method("search").with(eq("cn=Bob,ou=people"),
|
mockCtx.expects(once()).method("search").with(eq("cn=Bob,ou=people"),
|
||||||
eq("(userPassword={0})"), NOT_NULL, NOT_NULL).will(returnValue(searchResults.getAll()));
|
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");
|
authenticator.authenticate("Bob", "bobspassword");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package org.acegisecurity.providers.ldap.authenticator;
|
package org.acegisecurity.providers.ldap.authenticator;
|
||||||
|
|
||||||
import org.acegisecurity.ldap.LdapUserInfo;
|
|
||||||
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
|
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
|
||||||
import org.acegisecurity.BadCredentialsException;
|
import org.acegisecurity.BadCredentialsException;
|
||||||
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
||||||
|
import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
|
||||||
import javax.naming.directory.BasicAttributes;
|
import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
|
||||||
|
import org.acegisecurity.userdetails.ldap.LdapUserDetails;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link PasswordComparisonAuthenticator}.
|
* Tests for {@link PasswordComparisonAuthenticator}.
|
||||||
@ -87,7 +87,7 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapServerTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testAllAttributesAreRetrivedByDefault() {
|
public void testAllAttributesAreRetrivedByDefault() {
|
||||||
LdapUserInfo user = authenticator.authenticate("Bob", "bobspassword");
|
LdapUserDetails user = authenticator.authenticate("Bob", "bobspassword");
|
||||||
System.out.println(user.getAttributes().toString());
|
System.out.println(user.getAttributes().toString());
|
||||||
assertEquals("User should have 5 attributes", 5, user.getAttributes().size());
|
assertEquals("User should have 5 attributes", 5, user.getAttributes().size());
|
||||||
|
|
||||||
@ -103,7 +103,10 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapServerTest
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
public void testUseOfDifferentPasswordAttribute() {
|
public void testUseOfDifferentPasswordAttribute() {
|
||||||
|
LdapUserDetailsMapper mapper = new LdapUserDetailsMapper();
|
||||||
|
mapper.setPasswordAttributeName("uid");
|
||||||
authenticator.setPasswordAttributeName("uid");
|
authenticator.setPasswordAttributeName("uid");
|
||||||
|
authenticator.setUserDetailsMapper(mapper);
|
||||||
authenticator.authenticate("bob", "bob");
|
authenticator.authenticate("bob", "bob");
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -119,10 +122,11 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapServerTest
|
|||||||
authenticator = new PasswordComparisonAuthenticator(getInitialCtxFactory());
|
authenticator = new PasswordComparisonAuthenticator(getInitialCtxFactory());
|
||||||
assertTrue("User DN matches shouldn't be available",
|
assertTrue("User DN matches shouldn't be available",
|
||||||
authenticator.getUserDns("Bob").isEmpty());
|
authenticator.getUserDns("Bob").isEmpty());
|
||||||
LdapUserInfo user = new LdapUserInfo("uid=Bob,ou=people" +
|
LdapUserDetailsImpl.Essence userEssence = new LdapUserDetailsImpl.Essence();
|
||||||
getInitialCtxFactory().getRootDn(),
|
userEssence.setDn("uid=Bob,ou=people,dc=acegisecurity,dc=org");
|
||||||
new BasicAttributes("userPassword","bobspassword"));
|
userEssence.setPassword("bobspassword");
|
||||||
authenticator.setUserSearch(new MockUserSearch(user));
|
|
||||||
|
authenticator.setUserSearch(new MockUserSearch(userEssence.createUserDetails()));
|
||||||
authenticator.authenticate("ShouldntBeUsed","bobspassword");
|
authenticator.authenticate("ShouldntBeUsed","bobspassword");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
package org.acegisecurity.providers.ldap.populator;
|
package org.acegisecurity.providers.ldap.populator;
|
||||||
|
|
||||||
import javax.naming.directory.Attributes;
|
|
||||||
import javax.naming.directory.BasicAttributes;
|
import javax.naming.directory.BasicAttributes;
|
||||||
import javax.naming.directory.BasicAttribute;
|
|
||||||
|
|
||||||
import org.acegisecurity.GrantedAuthority;
|
import org.acegisecurity.GrantedAuthority;
|
||||||
|
import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
|
||||||
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
|
import org.acegisecurity.ldap.AbstractLdapServerTestCase;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -21,30 +20,39 @@ public class DefaultLdapAuthoritiesPopulatorTests extends AbstractLdapServerTest
|
|||||||
getInitialCtxFactory().setManagerPassword(MANAGER_PASSWORD);
|
getInitialCtxFactory().setManagerPassword(MANAGER_PASSWORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUserAttributeMappingToRoles() {
|
// public void testUserAttributeMappingToRoles() {
|
||||||
DefaultLdapAuthoritiesPopulator populator = new DefaultLdapAuthoritiesPopulator();
|
// DefaultLdapAuthoritiesPopulator populator = new DefaultLdapAuthoritiesPopulator();
|
||||||
populator.setUserRoleAttributes(new String[] {"userRole", "otherUserRole"});
|
// populator.setUserRoleAttributes(new String[] {"userRole", "otherUserRole"});
|
||||||
populator.getUserRoleAttributes();
|
// populator.getUserRoleAttributes();
|
||||||
|
//
|
||||||
Attributes userAttrs = new BasicAttributes();
|
// Attributes userAttrs = new BasicAttributes();
|
||||||
BasicAttribute attr = new BasicAttribute("userRole", "role1");
|
// BasicAttribute attr = new BasicAttribute("userRole", "role1");
|
||||||
attr.add("role2");
|
// attr.add("role2");
|
||||||
userAttrs.put(attr);
|
// userAttrs.put(attr);
|
||||||
attr = new BasicAttribute("otherUserRole", "role3");
|
// attr = new BasicAttribute("otherUserRole", "role3");
|
||||||
attr.add("role2"); // duplicate
|
// attr.add("role2"); // duplicate
|
||||||
userAttrs.put(attr);
|
// userAttrs.put(attr);
|
||||||
|
//
|
||||||
GrantedAuthority[] authorities =
|
// LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence();
|
||||||
populator.getGrantedAuthorities("Ignored", "Ignored", userAttrs);
|
// user.setDn("Ignored");
|
||||||
assertEquals("User should have three roles", 3, authorities.length);
|
// user.setUsername("Ignored");
|
||||||
}
|
// user.setAttributes(userAttrs);
|
||||||
|
//
|
||||||
|
// GrantedAuthority[] authorities =
|
||||||
|
// populator.getGrantedAuthorities(user.createUserDetails());
|
||||||
|
// assertEquals("User should have three roles", 3, authorities.length);
|
||||||
|
// }
|
||||||
|
|
||||||
public void testDefaultRoleIsAssignedWhenSet() {
|
public void testDefaultRoleIsAssignedWhenSet() {
|
||||||
DefaultLdapAuthoritiesPopulator populator = new DefaultLdapAuthoritiesPopulator();
|
DefaultLdapAuthoritiesPopulator populator = new DefaultLdapAuthoritiesPopulator();
|
||||||
populator.setDefaultRole("ROLE_USER");
|
populator.setDefaultRole("ROLE_USER");
|
||||||
|
LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence();
|
||||||
|
user.setDn("Ignored");
|
||||||
|
user.setUsername("Ignored");
|
||||||
|
user.setAttributes(new BasicAttributes());
|
||||||
|
|
||||||
GrantedAuthority[] authorities =
|
GrantedAuthority[] authorities =
|
||||||
populator.getGrantedAuthorities("Ignored", "Ignored", new BasicAttributes());
|
populator.getGrantedAuthorities(user.createUserDetails());
|
||||||
assertEquals(1, authorities.length);
|
assertEquals(1, authorities.length);
|
||||||
assertEquals("ROLE_USER", authorities[0].getAuthority());
|
assertEquals("ROLE_USER", authorities[0].getAuthority());
|
||||||
}
|
}
|
||||||
@ -59,9 +67,14 @@ public class DefaultLdapAuthoritiesPopulatorTests extends AbstractLdapServerTest
|
|||||||
populator.setConvertToUpperCase(true);
|
populator.setConvertToUpperCase(true);
|
||||||
populator.setGroupSearchFilter("(member={0})");
|
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 =
|
GrantedAuthority[] authorities =
|
||||||
populator.getGrantedAuthorities("ben", "uid=ben,ou=people,"+
|
populator.getGrantedAuthorities(user.createUserDetails());
|
||||||
getInitialCtxFactory().getRootDn(), new BasicAttributes());
|
|
||||||
assertEquals("Should have 2 roles", 2, authorities.length);
|
assertEquals("Should have 2 roles", 2, authorities.length);
|
||||||
Set roles = new HashSet();
|
Set roles = new HashSet();
|
||||||
roles.add(authorities[0].toString());
|
roles.add(authorities[0].toString());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user