Browse Source

SEC-558: Combine user mapping implementations into a single interface and make more use of DirContextOperations in SS LDAP APIs.

Luke Taylor 18 năm trước cách đây
mục cha
commit
8a35f7da75
20 tập tin đã thay đổi với 189 bổ sung327 xóa
  1. 3 3
      core/src/main/java/org/acegisecurity/ldap/LdapUserSearch.java
  2. 2 2
      core/src/main/java/org/acegisecurity/ldap/LdapUtils.java
  3. 8 14
      core/src/main/java/org/acegisecurity/ldap/SpringSecurityLdapTemplate.java
  4. 3 16
      core/src/main/java/org/acegisecurity/ldap/search/FilterBasedLdapUserSearch.java
  5. 21 36
      core/src/main/java/org/acegisecurity/providers/ldap/LdapAuthenticationProvider.java
  6. 2 1
      core/src/main/java/org/acegisecurity/providers/ldap/LdapAuthenticator.java
  7. 3 3
      core/src/main/java/org/acegisecurity/providers/ldap/LdapAuthoritiesPopulator.java
  8. 0 13
      core/src/main/java/org/acegisecurity/providers/ldap/authenticator/AbstractLdapAuthenticator.java
  9. 10 11
      core/src/main/java/org/acegisecurity/providers/ldap/authenticator/BindAuthenticator.java
  10. 7 0
      core/src/main/java/org/acegisecurity/providers/ldap/authenticator/LdapShaPasswordEncoder.java
  11. 16 14
      core/src/main/java/org/acegisecurity/providers/ldap/authenticator/PasswordComparisonAuthenticator.java
  12. 8 40
      core/src/main/java/org/acegisecurity/providers/ldap/populator/DefaultLdapAuthoritiesPopulator.java
  13. 24 47
      core/src/main/java/org/acegisecurity/userdetails/ldap/LdapUserDetailsMapper.java
  14. 7 7
      core/src/test/java/org/acegisecurity/ldap/search/FilterBasedLdapUserSearchTests.java
  15. 29 23
      core/src/test/java/org/acegisecurity/providers/ldap/LdapAuthenticationProviderTests.java
  16. 7 24
      core/src/test/java/org/acegisecurity/providers/ldap/authenticator/BindAuthenticatorTests.java
  17. 5 5
      core/src/test/java/org/acegisecurity/providers/ldap/authenticator/MockUserSearch.java
  18. 15 20
      core/src/test/java/org/acegisecurity/providers/ldap/authenticator/PasswordComparisonAuthenticatorTests.java
  19. 15 45
      core/src/test/java/org/acegisecurity/providers/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java
  20. 4 3
      core/src/test/java/org/acegisecurity/userdetails/ldap/LdapUserDetailsMapperTests.java

+ 3 - 3
core/src/main/java/org/acegisecurity/ldap/LdapUserSearch.java

@@ -15,7 +15,7 @@
 
 package org.acegisecurity.ldap;
 
-import org.acegisecurity.userdetails.ldap.LdapUserDetails;
+import org.springframework.ldap.core.DirContextOperations;
 
 
 /**
@@ -37,7 +37,7 @@ public interface LdapUserSearch {
      *
      * @param username the login name supplied to the authentication service.
      *
-     * @return an LdapUserDetailsImpl object containing the user's full DN and requested attributes.
+     * @return a DirContextOperations object containing the user's full DN and requested attributes.
      */
-    LdapUserDetails searchForUser(String username);
+    DirContextOperations searchForUser(String username);
 }

+ 2 - 2
core/src/main/java/org/acegisecurity/ldap/LdapUtils.java

@@ -26,6 +26,7 @@ import java.io.UnsupportedEncodingException;
 
 import javax.naming.Context;
 import javax.naming.NamingException;
+import javax.naming.Name;
 
 
 /**
@@ -73,8 +74,7 @@ public final class LdapUtils {
      *
      * @throws NamingException any exceptions thrown by the context are propagated.
      */
-    public static String getRelativeName(String fullDn, Context baseCtx)
-            throws NamingException {
+    public static String getRelativeName(String fullDn, Context baseCtx) throws NamingException {
 
         String baseDn = baseCtx.getNameInNamespace();
 

+ 8 - 14
core/src/main/java/org/acegisecurity/ldap/SpringSecurityLdapTemplate.java

@@ -27,6 +27,7 @@ import org.springframework.ldap.core.ContextMapper;
 import org.springframework.ldap.core.DistinguishedName;
 import org.springframework.ldap.core.AttributesMapper;
 import org.springframework.ldap.core.AttributesMapperCallbackHandler;
+import org.springframework.ldap.core.DirContextOperations;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -41,6 +42,7 @@ import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 import javax.naming.Context;
 import javax.naming.NameClassPair;
+import javax.naming.Name;
 import javax.naming.directory.Attribute;
 import javax.naming.directory.Attributes;
 import javax.naming.directory.DirContext;
@@ -136,22 +138,19 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld
      * Composes an object from the attributes of the given DN.
      *
      * @param dn the directory entry which will be read
-     * @param mapper maps the attributes to the required object
      * @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 ContextMapper mapper, final String[] attributesToRetrieve) {
+    public DirContextOperations retrieveEntry(final String dn, final String[] attributesToRetrieve) {
 
-        return executeReadOnly(new ContextExecutor() {
+        return (DirContextOperations) executeReadOnly(new ContextExecutor() {
                 public Object executeWithContext(DirContext ctx) throws NamingException {
                     Attributes attrs = ctx.getAttributes(LdapUtils.getRelativeName(dn, ctx), attributesToRetrieve);
 
                     // Object object = ctx.lookup(LdapUtils.getRelativeName(dn, ctx));
 
-                    DirContextAdapter ctxAdapter = new DirContextAdapter(attrs, new DistinguishedName(dn));
-
-                    return mapper.mapFromContext(ctxAdapter);
+                    return new DirContextAdapter(attrs, new DistinguishedName(dn));
                 }
             });
     }
@@ -227,17 +226,15 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld
      * @param base
      * @param filter
      * @param params
-     * @param mapper
      *
      * @return the object created by the mapper from the matching entry
      *
      * @throws IncorrectResultSizeDataAccessException if no results are found or the search returns more than one
      *         result.
      */
-    public Object searchForSingleEntry(final String base, final String filter, final Object[] params,
-        final ContextMapper mapper) {
+    public DirContextOperations searchForSingleEntry(final String base, final String filter, final Object[] params) {
 
-        return executeReadOnly(new ContextExecutor() {
+        return (DirContextOperations) executeReadOnly(new ContextExecutor() {
                 public Object executeWithContext(DirContext ctx)
                     throws NamingException {
 
@@ -269,10 +266,7 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld
                         dn.append(nameInNamespace);
                     }
 
-                    DirContextAdapter ctxAdapter = new DirContextAdapter(
-                            searchResult.getAttributes(), new DistinguishedName(dn.toString()));
-
-                    return mapper.mapFromContext(ctxAdapter);
+                    return new DirContextAdapter(searchResult.getAttributes(), new DistinguishedName(dn.toString()));
                 }
             });
     }

+ 3 - 16
core/src/main/java/org/acegisecurity/ldap/search/FilterBasedLdapUserSearch.java

@@ -20,9 +20,6 @@ import org.acegisecurity.ldap.SpringSecurityLdapTemplate;
 import org.acegisecurity.ldap.LdapUserSearch;
 
 import org.acegisecurity.userdetails.UsernameNotFoundException;
-import org.acegisecurity.userdetails.ldap.LdapUserDetails;
-import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
-import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -32,6 +29,7 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException;
 import org.springframework.util.Assert;
 
 import org.springframework.ldap.core.ContextSource;
+import org.springframework.ldap.core.DirContextOperations;
 
 import javax.naming.directory.SearchControls;
 
@@ -53,7 +51,6 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch {
     //~ Instance fields ================================================================================================
 
     private ContextSource initialDirContextFactory;
-    private LdapUserDetailsMapper userDetailsMapper = new LdapUserDetailsMapper();
 
     /**
      * The LDAP SearchControls object used for the search. Shared between searches so shouldn't be modified
@@ -105,7 +102,7 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch {
      *
      * @throws UsernameNotFoundException if no matching entry is found.
      */
-    public LdapUserDetails searchForUser(String username) {
+    public DirContextOperations searchForUser(String username) {
         if (logger.isDebugEnabled()) {
             logger.debug("Searching for user '" + username + "', with user search "
                 + this.toString());
@@ -117,14 +114,8 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch {
 
         try {
 
-            LdapUserDetailsImpl user = (LdapUserDetailsImpl) template.searchForSingleEntry(
-                    searchBase, searchFilter, new String[] {username}, userDetailsMapper);
+            return template.searchForSingleEntry(searchBase, searchFilter, new String[] {username});
 
-            if (!username.equals(user.getUsername())) {
-                logger.debug("Search returned user object with different username: " + user.getUsername());
-            }
-
-            return user;
         } catch (IncorrectResultSizeDataAccessException notFound) {
             if (notFound.getActualSize() == 0) {
                 throw new UsernameNotFoundException("User " + username + " not found in directory.");
@@ -163,10 +154,6 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch {
         searchControls.setTimeLimit(searchTimeLimit);
     }
 
-    public void setUserDetailsMapper(LdapUserDetailsMapper userDetailsMapper) {
-        this.userDetailsMapper = userDetailsMapper;
-    }
-
     public String toString() {
         StringBuffer sb = new StringBuffer();
 

+ 21 - 36
core/src/main/java/org/acegisecurity/providers/ldap/LdapAuthenticationProvider.java

@@ -19,14 +19,15 @@ import org.acegisecurity.AuthenticationException;
 import org.acegisecurity.BadCredentialsException;
 import org.acegisecurity.GrantedAuthority;
 import org.acegisecurity.AuthenticationServiceException;
-import org.acegisecurity.ldap.LdapDataAccessException;
 
 import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+import org.acegisecurity.providers.ldap.authenticator.LdapShaPasswordEncoder;
+import org.acegisecurity.providers.encoding.PasswordEncoder;
 import org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider;
 
 import org.acegisecurity.userdetails.UserDetails;
-import org.acegisecurity.userdetails.ldap.LdapUserDetails;
-import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
+import org.acegisecurity.userdetails.ldap.UserDetailsContextMapper;
+import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -34,6 +35,7 @@ import org.apache.commons.logging.LogFactory;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
 import org.springframework.dao.DataAccessException;
+import org.springframework.ldap.core.DirContextOperations;
 
 
 /**
@@ -123,6 +125,8 @@ public class LdapAuthenticationProvider extends AbstractUserDetailsAuthenticatio
 
     private LdapAuthenticator authenticator;
     private LdapAuthoritiesPopulator authoritiesPopulator;
+    private UserDetailsContextMapper userDetailsContextMapper = new LdapUserDetailsMapper();
+    private PasswordEncoder passwordEncoder = new LdapShaPasswordEncoder();
     private boolean includeDetailsObject = true;
 
     //~ Constructors ===================================================================================================
@@ -149,7 +153,7 @@ public class LdapAuthenticationProvider extends AbstractUserDetailsAuthenticatio
     public LdapAuthenticationProvider(LdapAuthenticator authenticator) {
         this.setAuthenticator(authenticator);
         this.setAuthoritiesPopulator(new NullAuthoritiesPopulator());
-    }    
+    }
 
     //~ Methods ========================================================================================================
 
@@ -171,44 +175,23 @@ public class LdapAuthenticationProvider extends AbstractUserDetailsAuthenticatio
         return authoritiesPopulator;
     }
 
+    public void setUserDetailsContextMapper(UserDetailsContextMapper userDetailsContextMapper) {
+        Assert.notNull(userDetailsContextMapper, "UserDetailsContextMapper must not be null");
+        this.userDetailsContextMapper = userDetailsContextMapper;
+    }
+
     protected void additionalAuthenticationChecks(UserDetails userDetails,
                                                   UsernamePasswordAuthenticationToken authentication)
         throws AuthenticationException {
-        if (!userDetails.getPassword().equals(authentication.getCredentials().toString())) {
+		String presentedPassword = authentication.getCredentials() == null ? "" :
+                authentication.getCredentials().toString();
+        if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, null)) { 
             throw new BadCredentialsException(messages.getMessage(
                     "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
                     includeDetailsObject ? userDetails : null);
         }
     }
 
-    /**
-     * 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 creation of the final UserDetails instance. The default will
-     * merge any additional authorities retrieved from the populator with the propertis of original <tt>ldapUser</tt>
-     * object and set the values of the username and password.</p>
-     *
-     * @param ldapUser The intermediate LdapUserDetails instance returned by the authenticator.
-     * @param username the username submitted to the provider
-     * @param password the password submitted to the provider
-     *
-     * @return The UserDetails for the successfully authenticated user.
-     */
-    protected UserDetails createUserDetails(LdapUserDetails ldapUser, String username, String password) {
-        LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence(ldapUser);
-        user.setUsername(username);
-        user.setPassword(password);
-
-        GrantedAuthority[] extraAuthorities = getAuthoritiesPopulator().getGrantedAuthorities(ldapUser);
-
-        for (int i = 0; i < extraAuthorities.length; i++) {
-            user.addAuthority(extraAuthorities[i]);
-        }
-
-        return user.createUserDetails();
-    }
-
     protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
         throws AuthenticationException {
         if (!StringUtils.hasLength(username)) {
@@ -230,9 +213,11 @@ public class LdapAuthenticationProvider extends AbstractUserDetailsAuthenticatio
         }
 
         try {
-            LdapUserDetails ldapUser = getAuthenticator().authenticate(username, password);
+            DirContextOperations user = getAuthenticator().authenticate(username, password);
+
+            GrantedAuthority[] extraAuthorities = getAuthoritiesPopulator().getGrantedAuthorities(user, username);
 
-            return createUserDetails(ldapUser, username, password);
+            return userDetailsContextMapper.mapUserFromContext(user, username, extraAuthorities);
 
         } catch (DataAccessException ldapAccessFailure) {
             throw new AuthenticationServiceException(ldapAccessFailure.getMessage(), ldapAccessFailure);
@@ -250,7 +235,7 @@ public class LdapAuthenticationProvider extends AbstractUserDetailsAuthenticatio
     //~ Inner Classes ==================================================================================================
 
     private static class NullAuthoritiesPopulator implements LdapAuthoritiesPopulator {
-        public GrantedAuthority[] getGrantedAuthorities(LdapUserDetails userDetails) throws LdapDataAccessException {
+        public GrantedAuthority[] getGrantedAuthorities(DirContextOperations userDetails, String username) {
             return new GrantedAuthority[0];
         }
     }

+ 2 - 1
core/src/main/java/org/acegisecurity/providers/ldap/LdapAuthenticator.java

@@ -16,6 +16,7 @@
 package org.acegisecurity.providers.ldap;
 
 import org.acegisecurity.userdetails.ldap.LdapUserDetails;
+import org.springframework.ldap.core.DirContextOperations;
 
 
 /**
@@ -40,5 +41,5 @@ public interface LdapAuthenticator {
      *
      * @return the details of the successfully authenticated user.
      */
-    LdapUserDetails authenticate(String username, String password);
+    DirContextOperations authenticate(String username, String password);
 }

+ 3 - 3
core/src/main/java/org/acegisecurity/providers/ldap/LdapAuthoritiesPopulator.java

@@ -20,6 +20,7 @@ import org.acegisecurity.GrantedAuthority;
 import org.acegisecurity.ldap.LdapDataAccessException;
 
 import org.acegisecurity.userdetails.ldap.LdapUserDetails;
+import org.springframework.ldap.core.DirContextOperations;
 
 
 /**
@@ -38,12 +39,11 @@ public interface LdapAuthoritiesPopulator {
     /**
      * Get the list of authorities for the user.
      *
-     * @param userDetails the user details object which was returned by the LDAP authenticator.
+     * @param user the context object which was returned by the LDAP authenticator.
      *
      * @return the granted authorities for the given user.
      *
      * @throws LdapDataAccessException if there is a problem accessing the directory.
      */
-    GrantedAuthority[] getGrantedAuthorities(LdapUserDetails userDetails)
-        throws LdapDataAccessException;
+    GrantedAuthority[] getGrantedAuthorities(DirContextOperations user, String username) throws LdapDataAccessException;
 }

+ 0 - 13
core/src/main/java/org/acegisecurity/providers/ldap/authenticator/AbstractLdapAuthenticator.java

@@ -22,8 +22,6 @@ import org.acegisecurity.ldap.LdapUserSearch;
 
 import org.acegisecurity.providers.ldap.LdapAuthenticator;
 
-import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
-
 import org.springframework.beans.factory.InitializingBean;
 
 import org.springframework.context.MessageSource;
@@ -31,7 +29,6 @@ import org.springframework.context.MessageSourceAware;
 import org.springframework.context.support.MessageSourceAccessor;
 
 import org.springframework.util.Assert;
-import org.springframework.ldap.core.ContextMapper;
 
 import java.text.MessageFormat;
 
@@ -49,7 +46,6 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator, In
     //~ Instance fields ================================================================================================
 
     private InitialDirContextFactory initialDirContextFactory;
-    private LdapUserDetailsMapper userDetailsMapper = new LdapUserDetailsMapper();
 
     /** Optional search object which can be used to locate a user when a simple DN match isn't sufficient */
     private LdapUserSearch userSearch;
@@ -110,10 +106,6 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator, In
         return userAttributes;
     }
 
-    protected ContextMapper getUserDetailsMapper() {
-        return userDetailsMapper;
-    }
-
     /**
      * Builds list of possible DNs for the user, worked out from the <tt>userDnPatterns</tt> property. The
      * returned value includes the root DN of the provider URL used to configure the
@@ -159,11 +151,6 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator, In
         this.userAttributes = userAttributes;
     }
 
-    public void setUserDetailsMapper(LdapUserDetailsMapper userDetailsMapper) {
-        Assert.notNull("userDetailsMapper must not be null");
-        this.userDetailsMapper = userDetailsMapper;
-    }
-
     /**
      * Sets the pattern which will be used to supply a DN for the user. The pattern should be the name relative
      * to the root DN. The pattern argument {0} will contain the username. An example would be "cn={0},ou=people".

+ 10 - 11
core/src/main/java/org/acegisecurity/providers/ldap/authenticator/BindAuthenticator.java

@@ -27,8 +27,10 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.dao.DataAccessException;
 import org.springframework.ldap.core.ContextSource;
+import org.springframework.ldap.core.DirContextOperations;
 
 import javax.naming.directory.DirContext;
+import javax.naming.Name;
 import java.util.Iterator;
 
 
@@ -58,21 +60,21 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
 
     //~ Methods ========================================================================================================
 
-    public LdapUserDetails authenticate(String username, String password) {
-        LdapUserDetails user = null;
+    public DirContextOperations authenticate(String username, String password) {
+        DirContextOperations user = null;
 
         // If DN patterns are configured, try authenticating with them directly
         Iterator dns = getUserDns(username).iterator();
 
-        while (dns.hasNext() && (user == null)) {
+        while (dns.hasNext() && user == null) {
             user = bindWithDn((String) dns.next(), username, password);
         }
 
         // Otherwise use the configured locator to find the user
         // and authenticate with the returned DN.
-        if ((user == null) && (getUserSearch() != null)) {
-            LdapUserDetails userFromSearch = getUserSearch().searchForUser(username);
-            user = bindWithDn(userFromSearch.getDn(), username, password);
+        if (user == null && getUserSearch() != null) {
+            DirContextOperations userFromSearch = getUserSearch().searchForUser(username);
+            user = bindWithDn(userFromSearch.getDn().toString(), username, password);
         }
 
         if (user == null) {
@@ -83,15 +85,13 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
         return user;
     }
 
-    private LdapUserDetails bindWithDn(String userDn, String username, String password) {
+    private DirContextOperations bindWithDn(String userDn, String username, String password) {
         SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(
                 new BindWithSpecificDnContextSource(getInitialDirContextFactory(), userDn, password));
 
         try {
-            LdapUserDetailsImpl user = (LdapUserDetailsImpl) template.retrieveEntry(userDn,
-                    getUserDetailsMapper(), getUserAttributes());
+            return template.retrieveEntry(userDn, getUserAttributes());
 
-            return user;
         } catch (BadCredentialsException e) {
             // This will be thrown if an invalid user name is used and the method may
             // be called multiple times to try different names, so we trap the exception
@@ -117,7 +117,6 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
         private String userDn;
         private String password;
 
-
         public BindWithSpecificDnContextSource(InitialDirContextFactory ctxFactory, String userDn, String password) {
             this.ctxFactory = ctxFactory;
             this.userDn = userDn;

+ 7 - 0
core/src/main/java/org/acegisecurity/providers/ldap/authenticator/LdapShaPasswordEncoder.java

@@ -32,6 +32,9 @@ import java.security.MessageDigest;
  * base-64 encoded and have the label "{SHA}" (or "{SSHA}") prepended to the encoded hash. These can be made lower-case
  * in the encoded password, if required, by setting the <tt>forceLowerCasePrefix</tt> property to true.
  *
+ * Also supports plain text passwords, so can safely be used in cases when both encoded and non-encoded passwords are in
+ * use or when a null implementation is required.
+ *
  * @author Luke Taylor
  * @version $Id$
  */
@@ -129,6 +132,10 @@ public class LdapShaPasswordEncoder implements PasswordEncoder {
     public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
         String encPassWithoutPrefix;
 
+        if (!encPass.startsWith("{")) {
+            return encPass.equals(rawPass);
+        }
+
         if (encPass.startsWith(SSHA_PREFIX) || encPass.startsWith(SSHA_PREFIX_LC)) {
             encPassWithoutPrefix = encPass.substring(6);
             salt = extractSalt(encPass);

+ 16 - 14
core/src/main/java/org/acegisecurity/providers/ldap/authenticator/PasswordComparisonAuthenticator.java

@@ -24,13 +24,12 @@ import org.acegisecurity.ldap.LdapUtils;
 import org.acegisecurity.providers.encoding.PasswordEncoder;
 
 import org.acegisecurity.userdetails.UsernameNotFoundException;
-import org.acegisecurity.userdetails.ldap.LdapUserDetails;
-import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import org.springframework.util.Assert;
+import org.springframework.ldap.core.DirContextOperations;
 
 import java.util.Iterator;
 
@@ -70,20 +69,19 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
 
     //~ Methods ========================================================================================================
 
-    public LdapUserDetails authenticate(final String username, final String password) {
+    public DirContextOperations authenticate(final String username, final String password) {
         // locate the user and check the password
-        LdapUserDetails user = null;
+        DirContextOperations user = null;
 
         Iterator dns = getUserDns(username).iterator();
 
         SpringSecurityLdapTemplate ldapTemplate = new SpringSecurityLdapTemplate(getInitialDirContextFactory());
 
-        while (dns.hasNext() && (user == null)) {
+        while (dns.hasNext() && user == null) {
             final String userDn = (String) dns.next();
 
             if (ldapTemplate.nameExists(userDn)) {
-                user = (LdapUserDetailsImpl)
-                        ldapTemplate.retrieveEntry(userDn, getUserDetailsMapper(), getUserAttributes());
+                user = ldapTemplate.retrieveEntry(userDn, getUserAttributes());
             }
         }
 
@@ -95,7 +93,7 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
             throw new UsernameNotFoundException(username);
         }
 
-        String retrievedPassword = user.getPassword();
+        Object retrievedPassword = user.getObjectAttribute(passwordAttributeName);
 
         if (retrievedPassword != null) {
             if (!verifyPassword(password, retrievedPassword)) {
@@ -107,15 +105,14 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
         }
 
         if (logger.isDebugEnabled()) {
-            logger.debug("Password attribute wasn't retrieved for user '" + username + "' using mapper "
-                + getUserDetailsMapper() + ". Performing LDAP compare of password attribute '" + passwordAttributeName
-                + "'");
+            logger.debug("Password attribute wasn't retrieved for user '" + username
+                    + "'. 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)) {
+        if (!ldapTemplate.compare(user.getDn().toString(), passwordAttributeName, passwordBytes)) {
             throw new BadCredentialsException(messages.getMessage("PasswordComparisonAuthenticator.badCredentials",
                     "Bad credentials"));
         }
@@ -141,12 +138,17 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic
      *
      * @return true if they match
      */
-    private boolean verifyPassword(String password, String ldapPassword) {
+    protected boolean verifyPassword(String password, Object ldapPassword) {
+        if (!(ldapPassword instanceof String)) {
+            // Assume it's binary
+            ldapPassword = new String((byte[]) ldapPassword);
+        }
+
         if (ldapPassword.equals(password)) {
             return true;
         }
 
-        if (passwordEncoder.isPasswordValid(ldapPassword, password, null)) {
+        if (passwordEncoder.isPasswordValid((String)ldapPassword, password, null)) {
             return true;
         }
 

+ 8 - 40
core/src/main/java/org/acegisecurity/providers/ldap/populator/DefaultLdapAuthoritiesPopulator.java

@@ -29,6 +29,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import org.springframework.util.Assert;
+import org.springframework.ldap.core.DirContextOperations;
 
 import java.util.HashSet;
 import java.util.Iterator;
@@ -156,11 +157,11 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
      * roles for the given user (on top of those obtained from the standard
      * search implemented by this class).
      *
-     * @param ldapUser the user who's roles are required
+     * @param user the context representing the user who's roles are required
      * @return the extra roles which will be merged with those returned by the group search
      */
 
-    protected Set getAdditionalRoles(LdapUserDetails ldapUser) {
+    protected Set getAdditionalRoles(DirContextOperations user, String username) {
         return null;
     }
 
@@ -168,26 +169,19 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
      * Obtains the authorities for the user who's directory entry is represented by
      * the supplied LdapUserDetails object.
      *
-     * @param userDetails the user who's authorities are required
+     * @param user the user who's authorities are required
      * @return the set of roles granted to the user.
      */
-    public final GrantedAuthority[] getGrantedAuthorities(LdapUserDetails userDetails) {
-        String userDn = userDetails.getDn();
+    public final GrantedAuthority[] getGrantedAuthorities(DirContextOperations user, String username) {
+        String userDn = user.getDn().toString();
 
         if (logger.isDebugEnabled()) {
             logger.debug("Getting authorities for user " + userDn);
         }
 
-        Set roles = getGroupMembershipRoles(userDn, userDetails.getUsername());
+        Set roles = getGroupMembershipRoles(userDn, username);
 
-        // Temporary use of deprecated method
-        Set oldGroupRoles = getGroupMembershipRoles(userDn, userDetails.getAttributes());
-
-        if (oldGroupRoles != null) {
-            roles.addAll(oldGroupRoles);
-        }
-
-        Set extraRoles = getAdditionalRoles(userDetails);
+        Set extraRoles = getAdditionalRoles(user, username);
 
         if (extraRoles != null) {
             roles.addAll(extraRoles);
@@ -200,19 +194,6 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
         return (GrantedAuthority[]) roles.toArray(new GrantedAuthority[roles.size()]);
     }
 
-//    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;
-//    }
-
-
     public Set getGroupMembershipRoles(String userDn, String username) {
         Set authorities = new HashSet();
 
@@ -247,19 +228,6 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
         return authorities;
     }
 
-    /**
-     * 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.
-     * @deprecated Subclasses should implement <tt>getAdditionalRoles</tt> instead.
-     */
-    protected Set getGroupMembershipRoles(String userDn, Attributes userAttributes) {
-        return new HashSet();
-    }
-
     protected InitialDirContextFactory getInitialDirContextFactory() {
         return initialDirContextFactory;
     }

+ 24 - 47
core/src/main/java/org/acegisecurity/userdetails/ldap/LdapUserDetailsMapper.java

@@ -17,6 +17,7 @@ package org.acegisecurity.userdetails.ldap;
 
 import org.acegisecurity.GrantedAuthorityImpl;
 import org.acegisecurity.GrantedAuthority;
+import org.acegisecurity.userdetails.UserDetails;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -25,6 +26,7 @@ import org.springframework.util.Assert;
 import org.springframework.ldap.UncategorizedLdapException;
 import org.springframework.ldap.core.ContextMapper;
 import org.springframework.ldap.core.DirContextAdapter;
+import org.springframework.ldap.core.DirContextOperations;
 
 import javax.naming.NamingException;
 import javax.naming.directory.Attribute;
@@ -36,11 +38,10 @@ import javax.naming.directory.Attribute;
  * @author Luke Taylor
  * @version $Id$
  */
-public class LdapUserDetailsMapper implements ContextMapper {
+public class LdapUserDetailsMapper implements UserDetailsContextMapper {
     //~ Instance fields ================================================================================================
 
     private final Log logger = LogFactory.getLog(LdapUserDetailsMapper.class);
-    private String usernameAttributeName = "uid";
     private String passwordAttributeName = "userPassword";
     private String rolePrefix = "ROLE_";
     private String[] roleAttributes = null;
@@ -48,25 +49,21 @@ public class LdapUserDetailsMapper implements ContextMapper {
 
     //~ Methods ========================================================================================================
 
-    public Object mapFromContext(Object ctxObj) {
-        Assert.isInstanceOf(DirContextAdapter.class, ctxObj, "Can only map from DirContextAdapter instances");
-
-        DirContextAdapter ctx = (DirContextAdapter)ctxObj;
+    public UserDetails mapUserFromContext(DirContextOperations ctx, String username, GrantedAuthority[] authorities) {
         String dn = ctx.getNameInNamespace();
 
         logger.debug("Mapping user details from context with DN: " + dn);
 
         LdapUserDetailsImpl.Essence essence = new LdapUserDetailsImpl.Essence();
         essence.setDn(dn);
-        essence.setAttributes(ctx.getAttributes());
 
-        Attribute passwordAttribute = ctx.getAttributes().get(passwordAttributeName);
+        Object passwordValue = ctx.getObjectAttribute(passwordAttributeName);
 
-        if (passwordAttribute != null) {
-            essence.setPassword(mapPassword(passwordAttribute));
+        if (passwordValue != null) {
+            essence.setPassword(mapPassword(passwordValue));
         }
 
-        essence.setUsername(mapUsername(ctx));
+        essence.setUsername(username);
 
         // Map the roles
         for (int i = 0; (roleAttributes != null) && (i < roleAttributes.length); i++) {
@@ -86,53 +83,38 @@ public class LdapUserDetailsMapper implements ContextMapper {
             }
         }
 
+        // Add the supplied authorities
+
+        for (int i=0; i < authorities.length; i++) {
+            essence.addAuthority(authorities[i]);
+        }
+
         return essence.createUserDetails();
-        //return essence;
+
+    }
+
+    public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
+
     }
 
     /**
      * Extension point to allow customized creation of the user's password from
      * the attribute stored in the directory.
      *
-     * @param passwordAttribute the attribute instance containing the password
+     * @param passwordValue the value of the password attribute
      * @return a String representation of the password.
      */
-    protected String mapPassword(Attribute passwordAttribute) {
-        Object retrievedPassword = null;
-
-        try {
-            retrievedPassword = passwordAttribute.get();
-        } catch (NamingException e) {
-            throw new UncategorizedLdapException("Failed to get password attribute", e);
-        }
+    protected String mapPassword(Object passwordValue) {
 
-        if (!(retrievedPassword instanceof String)) {
+        if (!(passwordValue instanceof String)) {
             // Assume it's binary
-            retrievedPassword = new String((byte[]) retrievedPassword);
+            passwordValue = new String((byte[]) passwordValue);
         }
 
-        return (String) retrievedPassword;
+        return (String) passwordValue;
 
     }
 
-    protected String mapUsername(DirContextAdapter ctx) {
-        Attribute usernameAttribute = ctx.getAttributes().get(usernameAttributeName);
-        String username;
-
-        if (usernameAttribute == null) {
-            throw new UncategorizedLdapException(
-                    "Failed to get attribute " + usernameAttributeName + " from context");
-        }
-
-        try {
-            username = (String) usernameAttribute.get();
-        } catch (NamingException e) {
-            throw new UncategorizedLdapException("Failed to get username from attribute " + usernameAttributeName, e);
-        }
-
-        return username;
-    }
-
     /**
      * Creates a GrantedAuthority from a role attribute. Override to customize
      * authority object creation.
@@ -175,11 +157,6 @@ public class LdapUserDetailsMapper implements ContextMapper {
         this.passwordAttributeName = passwordAttributeName;
     }
 
-
-    public void setUsernameAttributeName(String usernameAttributeName) {
-        this.usernameAttributeName = usernameAttributeName;
-    }
-
     /**
      * The names of any attributes in the user's  entry which represent application
      * roles. These will be converted to <tt>GrantedAuthority</tt>s and added to the

+ 7 - 7
core/src/test/java/org/acegisecurity/ldap/search/FilterBasedLdapUserSearchTests.java

@@ -22,6 +22,7 @@ import org.acegisecurity.userdetails.UsernameNotFoundException;
 import org.acegisecurity.userdetails.ldap.LdapUserDetails;
 
 import org.springframework.dao.IncorrectResultSizeDataAccessException;
+import org.springframework.ldap.core.DirContextOperations;
 
 
 /**
@@ -48,8 +49,8 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapIntegrationTests
         locator.setSearchTimeLimit(0);
         locator.setDerefLinkFlag(false);
 
-        LdapUserDetails bob = locator.searchForUser("bob");
-        assertEquals("bob", bob.getUsername());
+        DirContextOperations bob = locator.searchForUser("bob");
+        assertEquals("bob", bob.getStringAttribute("uid"));
 
         // name is wrong with embedded apacheDS
 //        assertEquals("uid=bob,ou=people,dc=acegisecurity,dc=org", bob.getDn());
@@ -61,9 +62,8 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapIntegrationTests
                 "(&(cn=*)(!(|(uid={0})(uid=marissa))))", dirCtxFactory);
 
         // Search for bob, get back ben...
-        LdapUserDetails ben = locator.searchForUser("bob");
-        String cn = (String) ben.getAttributes().get("cn").get();
-        assertEquals("Ben Alex", cn);
+        DirContextOperations ben = locator.searchForUser("bob");
+        assertEquals("Ben Alex", ben.getStringAttribute("cn"));
 
 //        assertEquals("uid=ben,ou=people,"+ROOT_DN, ben.getDn());
     }
@@ -91,8 +91,8 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapIntegrationTests
         FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("", "(cn={0})", dirCtxFactory);
         locator.setSearchSubtree(true);
 
-        LdapUserDetails ben = locator.searchForUser("Ben Alex");
-        assertEquals("ben", ben.getUsername());
+        DirContextOperations ben = locator.searchForUser("Ben Alex");
+        assertEquals("ben", ben.getStringAttribute("uid"));
 
 //        assertEquals("uid=ben,ou=people,dc=acegisecurity,dc=org", ben.getDn());
     }

+ 29 - 23
core/src/test/java/org/acegisecurity/providers/ldap/LdapAuthenticationProviderTests.java

@@ -24,8 +24,11 @@ import org.acegisecurity.GrantedAuthorityImpl;
 import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
 
 import org.acegisecurity.userdetails.UserDetails;
-import org.acegisecurity.userdetails.ldap.LdapUserDetails;
 import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
+import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
+import org.springframework.ldap.core.DirContextOperations;
+import org.springframework.ldap.core.DirContextAdapter;
+import org.springframework.ldap.core.DistinguishedName;
 
 import java.util.ArrayList;
 
@@ -54,14 +57,14 @@ public class LdapAuthenticationProviderTests extends TestCase {
     public void testDifferentCacheValueCausesException() {
         LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
                 new MockAuthoritiesPopulator());
-        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken("bob", "bobspassword");
+        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken("ben", "benspassword");
 
         // User is authenticated here
-        UserDetails user = ldapProvider.retrieveUser("bob", authRequest);
+        UserDetails user = ldapProvider.retrieveUser("ben", authRequest);
         // Assume the user details object is cached...
 
         // And a subsequent authentication request comes in on the cached data
-        authRequest = new UsernamePasswordAuthenticationToken("bob", "wrongpassword");
+        authRequest = new UsernamePasswordAuthenticationToken("ben", "wrongpassword");
 
         try {
             ldapProvider.additionalAuthenticationChecks(user, authRequest);
@@ -95,14 +98,17 @@ public class LdapAuthenticationProviderTests extends TestCase {
     public void testNormalUsage() {
         LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
                 new MockAuthoritiesPopulator());
+        LdapUserDetailsMapper userMapper = new LdapUserDetailsMapper();
+        userMapper.setRoleAttributes(new String[] {"ou"});
+        ldapProvider.setUserDetailsContextMapper(userMapper);
 
         assertNotNull(ldapProvider.getAuthoritiesPopulator());
 
-        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken("bob", "bobspassword");
-        UserDetails user = ldapProvider.retrieveUser("bob", authRequest);
+        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken("ben", "benspassword");
+        UserDetails user = ldapProvider.retrieveUser("ben", authRequest);
         assertEquals(2, user.getAuthorities().length);
-        assertEquals("bobspassword", user.getPassword());
-        assertEquals("bob", user.getUsername());
+        assertEquals("{SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=", user.getPassword());
+        assertEquals("ben", user.getUsername());
 
         ArrayList authorities = new ArrayList();
         authorities.add(user.getAuthorities()[0].getAuthority());
@@ -116,8 +122,11 @@ public class LdapAuthenticationProviderTests extends TestCase {
 
     public void testUseWithNullAuthoritiesPopulatorReturnsCorrectRole() {
         LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator());
-        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken("bob", "bobspassword");
-        UserDetails user = ldapProvider.retrieveUser("bob", authRequest);
+        LdapUserDetailsMapper userMapper = new LdapUserDetailsMapper();
+        userMapper.setRoleAttributes(new String[] {"ou"});
+        ldapProvider.setUserDetailsContextMapper(userMapper);        
+        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken("ben", "benspassword");
+        UserDetails user = ldapProvider.retrieveUser("ben", authRequest);
         assertEquals(1, user.getAuthorities().length);
         assertEquals("ROLE_FROM_ENTRY", user.getAuthorities()[0].getAuthority());
     }
@@ -125,23 +134,20 @@ public class LdapAuthenticationProviderTests extends TestCase {
     //~ Inner Classes ==================================================================================================
 
     class MockAuthenticator implements LdapAuthenticator {
-        Attributes userAttributes = new BasicAttributes("cn", "bob");
 
-        public LdapUserDetails authenticate(String username, String password) {
-            LdapUserDetailsImpl.Essence userEssence = new LdapUserDetailsImpl.Essence();
-            userEssence.setPassword("{SHA}anencodedpassword");
-            userEssence.setAttributes(userAttributes);
+        public DirContextOperations authenticate(String username, String password) {
+            DirContextAdapter ctx = new DirContextAdapter();
+            ctx.setAttributeValue("ou", "FROM_ENTRY");
 
-            if (username.equals("bob") && password.equals("bobspassword")) {
-                userEssence.setDn("cn=bob,ou=people,dc=acegisecurity,dc=org");
-                userEssence.addAuthority(new GrantedAuthorityImpl("ROLE_FROM_ENTRY"));
+            if (username.equals("ben") && password.equals("benspassword")) {
+                ctx.setDn(new DistinguishedName("cn=ben,ou=people,dc=acegisecurity,dc=org"));
+                ctx.setAttributeValue("userPassword","{SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=");
 
-                return userEssence.createUserDetails();
+                return ctx;
             } else if (username.equals("jen") && password.equals("")) {
-                userEssence.setDn("cn=jen,ou=people,dc=acegisecurity,dc=org");
-                userEssence.addAuthority(new GrantedAuthorityImpl("ROLE_FROM_ENTRY"));
+                ctx.setDn(new DistinguishedName("cn=jen,ou=people,dc=acegisecurity,dc=org"));
 
-                return userEssence.createUserDetails();
+                return ctx;
             }
 
             throw new BadCredentialsException("Authentication failed.");
@@ -169,7 +175,7 @@ public class LdapAuthenticationProviderTests extends TestCase {
 //        assertEquals(2, auth.getAuthorities().length);
 //    }
     class MockAuthoritiesPopulator implements LdapAuthoritiesPopulator {
-        public GrantedAuthority[] getGrantedAuthorities(LdapUserDetails userDetailsll) {
+        public GrantedAuthority[] getGrantedAuthorities(DirContextOperations userCtx, String username) {
             return new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_FROM_POPULATOR")};
         }
     }

+ 7 - 24
core/src/test/java/org/acegisecurity/providers/ldap/authenticator/BindAuthenticatorTests.java

@@ -17,14 +17,13 @@ package org.acegisecurity.providers.ldap.authenticator;
 
 import org.acegisecurity.AcegiMessageSource;
 import org.acegisecurity.BadCredentialsException;
-import org.acegisecurity.GrantedAuthorityImpl;
 
 import org.acegisecurity.ldap.AbstractLdapIntegrationTests;
 import org.acegisecurity.ldap.InitialDirContextFactory;
 
-import org.acegisecurity.userdetails.ldap.LdapUserDetails;
-import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
-import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
+import org.springframework.ldap.core.DirContextAdapter;
+import org.springframework.ldap.core.DistinguishedName;
+import org.springframework.ldap.core.DirContextOperations;
 
 
 /**
@@ -48,8 +47,8 @@ public class BindAuthenticatorTests extends AbstractLdapIntegrationTests {
     public void testAuthenticationWithCorrectPasswordSucceeds() {
         authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
 
-        LdapUserDetails user = authenticator.authenticate("bob", "bobspassword");
-        assertEquals("bob", user.getUsername());
+        DirContextOperations user = authenticator.authenticate("bob", "bobspassword");
+        assertEquals("bob", user.getStringAttribute("uid"));
     }
 
     public void testAuthenticationWithInvalidUserNameFails() {
@@ -62,10 +61,9 @@ public class BindAuthenticatorTests extends AbstractLdapIntegrationTests {
     }
 
     public void testAuthenticationWithUserSearch() throws Exception {
-        LdapUserDetailsImpl.Essence userEssence = new LdapUserDetailsImpl.Essence();
-        userEssence.setDn("uid=bob,ou=people,dc=acegisecurity,dc=org");
+        DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=bob,ou=people,dc=acegisecurity,dc=org"));
 
-        authenticator.setUserSearch(new MockUserSearch(userEssence.createUserDetails()));
+        authenticator.setUserSearch(new MockUserSearch(ctx));
         authenticator.afterPropertiesSet();
         authenticator.authenticate("bob", "bobspassword");
     }
@@ -79,21 +77,6 @@ public class BindAuthenticatorTests extends AbstractLdapIntegrationTests {
         } 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]);
-    }
-
     public void testUserDnPatternReturnsCorrectDn() {
         authenticator.setUserDnPatterns(new String[] {"cn={0},ou=people"});
         assertEquals("cn=Joe,ou=people," + ((InitialDirContextFactory)getContextSource()).getRootDn(), authenticator.getUserDns("Joe").get(0));

+ 5 - 5
core/src/test/java/org/acegisecurity/providers/ldap/authenticator/MockUserSearch.java

@@ -18,11 +18,11 @@ package org.acegisecurity.providers.ldap.authenticator;
 import org.acegisecurity.ldap.LdapUserSearch;
 
 import org.acegisecurity.userdetails.ldap.LdapUserDetails;
+import org.springframework.ldap.core.DirContextOperations;
 
 
 /**
- * 
-DOCUMENT ME!
+ *
  *
  * @author Luke Taylor
  * @version $Id$
@@ -30,17 +30,17 @@ DOCUMENT ME!
 public class MockUserSearch implements LdapUserSearch {
     //~ Instance fields ================================================================================================
 
-    LdapUserDetails user;
+    DirContextOperations user;
 
     //~ Constructors ===================================================================================================
 
-    public MockUserSearch(LdapUserDetails user) {
+    public MockUserSearch(DirContextOperations user) {
         this.user = user;
     }
 
     //~ Methods ========================================================================================================
 
-    public LdapUserDetails searchForUser(String username) {
+    public DirContextOperations searchForUser(String username) {
         return user;
     }
 }

+ 15 - 20
core/src/test/java/org/acegisecurity/providers/ldap/authenticator/PasswordComparisonAuthenticatorTests.java

@@ -23,9 +23,9 @@ import org.acegisecurity.ldap.InitialDirContextFactory;
 import org.acegisecurity.providers.encoding.PlaintextPasswordEncoder;
 
 import org.acegisecurity.userdetails.UsernameNotFoundException;
-import org.acegisecurity.userdetails.ldap.LdapUserDetails;
-import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
-import org.acegisecurity.userdetails.ldap.LdapUserDetailsMapper;
+import org.springframework.ldap.core.DirContextAdapter;
+import org.springframework.ldap.core.DistinguishedName;
+import org.springframework.ldap.core.DirContextOperations;
 
 
 /**
@@ -52,14 +52,13 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapIntegratio
         // com.sun.jndi.ldap.LdapPoolManager.showStats(System.out);
     }
 
-    public void testAllAttributesAreRetrivedByDefault() {
-        LdapUserDetails user = authenticator.authenticate("bob", "bobspassword");
+    public void testAllAttributesAreRetrievedByDefault() {
+        DirContextAdapter user = (DirContextAdapter) authenticator.authenticate("bob", "bobspassword");
         //System.out.println(user.getAttributes().toString());
         assertEquals("User should have 5 attributes", 5, user.getAttributes().size());
     }
 
-    public void testFailedSearchGivesUserNotFoundException()
-        throws Exception {
+    public void testFailedSearchGivesUserNotFoundException() throws Exception {
         authenticator = new PasswordComparisonAuthenticator((InitialDirContextFactory) getContextSource());
         assertTrue("User DN matches shouldn't be available", authenticator.getUserDns("Bob").isEmpty());
         authenticator.setUserSearch(new MockUserSearch(null));
@@ -95,10 +94,11 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapIntegratio
    }
 
     public void testLocalPasswordComparisonSucceedsWithCorrectPassword() {
-        LdapUserDetails user = authenticator.authenticate("bob", "bobspassword");
+        DirContextOperations user = authenticator.authenticate("bob", "bobspassword");
         // check username is retrieved.
-        assertEquals("bob", user.getUsername());
-        assertEquals("bobspassword", user.getPassword());
+        assertEquals("bob", user.getStringAttribute("uid"));
+        String password = new String((byte[])user.getObjectAttribute("userPassword"));
+        assertEquals("bobspassword", password);
     }
 
     public void testMultipleDnPatternsWorkOk() {
@@ -110,7 +110,7 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapIntegratio
         authenticator.setUserAttributes(new String[] {"uid", "userPassword"});
         authenticator.setPasswordEncoder(new PlaintextPasswordEncoder());
 
-        LdapUserDetails user = authenticator.authenticate("Bob", "bobspassword");
+        DirContextAdapter user = (DirContextAdapter) authenticator.authenticate("Bob", "bobspassword");
         assertEquals("Should have retrieved 2 attribute (uid, userPassword)", 2, user.getAttributes().size());
     }
 
@@ -136,12 +136,8 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapIntegratio
     }
 
     public void testUseOfDifferentPasswordAttribute() {
-        LdapUserDetailsMapper mapper = new LdapUserDetailsMapper();
-        mapper.setPasswordAttributeName("uid");
         authenticator.setPasswordAttributeName("uid");
-        authenticator.setUserDetailsMapper(mapper);
-
-        LdapUserDetails bob = authenticator.authenticate("bob", "bob");
+        authenticator.authenticate("bob", "bob");
     }
 
    public void testLdapCompareWithDifferentPasswordAttributeSucceeds() {
@@ -155,11 +151,10 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapIntegratio
         authenticator = new PasswordComparisonAuthenticator((InitialDirContextFactory) getContextSource());
         assertTrue("User DN matches shouldn't be available", authenticator.getUserDns("Bob").isEmpty());
 
-        LdapUserDetailsImpl.Essence userEssence = new LdapUserDetailsImpl.Essence();
-        userEssence.setDn("uid=Bob,ou=people,dc=acegisecurity,dc=org");
-        userEssence.setPassword("bobspassword");
+        DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=Bob,ou=people,dc=acegisecurity,dc=org"));
+        ctx.setAttributeValue("userPassword", "bobspassword");
 
-        authenticator.setUserSearch(new MockUserSearch(userEssence.createUserDetails()));
+        authenticator.setUserSearch(new MockUserSearch(ctx));
         authenticator.authenticate("ShouldntBeUsed", "bobspassword");
     }
 }

+ 15 - 45
core/src/test/java/org/acegisecurity/providers/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java

@@ -21,6 +21,8 @@ import org.acegisecurity.ldap.AbstractLdapIntegrationTests;
 import org.acegisecurity.ldap.InitialDirContextFactory;
 
 import org.acegisecurity.userdetails.ldap.LdapUserDetailsImpl;
+import org.springframework.ldap.core.DirContextAdapter;
+import org.springframework.ldap.core.DistinguishedName;
 
 import java.util.HashSet;
 import java.util.Set;
@@ -45,39 +47,13 @@ public class DefaultLdapAuthoritiesPopulatorTests extends AbstractLdapIntegratio
 
     }
 
-//    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() {
 
         populator.setDefaultRole("ROLE_USER");
 
-        LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence();
-        user.setDn("cn=notfound");
-        user.setUsername("notfound");
-        user.setAttributes(new BasicAttributes());
+        DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("cn=notfound"));
 
-        GrantedAuthority[] authorities = populator.getGrantedAuthorities(user.createUserDetails());
+        GrantedAuthority[] authorities = populator.getGrantedAuthorities(ctx, "notfound");
         assertEquals(1, authorities.length);
         assertEquals("ROLE_USER", authorities[0].getAuthority());
     }
@@ -90,12 +66,9 @@ public class DefaultLdapAuthoritiesPopulatorTests extends AbstractLdapIntegratio
         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());
+        DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=ben,ou=people,dc=acegisecurity,dc=org"));
 
-        GrantedAuthority[] authorities = populator.getGrantedAuthorities(user.createUserDetails());
+        GrantedAuthority[] authorities = populator.getGrantedAuthorities(ctx, "ben");
 
         assertEquals("Should have 2 roles", 2, authorities.length);
 
@@ -111,11 +84,10 @@ public class DefaultLdapAuthoritiesPopulatorTests extends AbstractLdapIntegratio
         populator.setConvertToUpperCase(true);
         populator.setGroupSearchFilter("(ou={1})");
 
-        LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence();
-        user.setUsername("manager");
-        user.setDn("uid=ben,ou=people,dc=acegisecurity,dc=org");
+        DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=ben,ou=people,dc=acegisecurity,dc=org"));
+
+        GrantedAuthority[] authorities = populator.getGrantedAuthorities(ctx, "manager");
 
-        GrantedAuthority[] authorities = populator.getGrantedAuthorities(user.createUserDetails());
         assertEquals("Should have 1 role", 1, authorities.length);
         assertEquals("ROLE_MANAGER", authorities[0].getAuthority());
     }
@@ -124,11 +96,10 @@ public class DefaultLdapAuthoritiesPopulatorTests extends AbstractLdapIntegratio
         populator.setGroupRoleAttribute("ou");
         populator.setConvertToUpperCase(true);
 
-        LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence();
-        user.setUsername("manager");
-        user.setDn("uid=ben,ou=people,dc=acegisecurity,dc=org");
+        DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=ben,ou=people,dc=acegisecurity,dc=org"));
+
+        GrantedAuthority[] authorities = populator.getGrantedAuthorities(ctx, "manager");
 
-        GrantedAuthority[] authorities = populator.getGrantedAuthorities(user.createUserDetails());
         assertEquals("Should have 2 roles", 2, authorities.length);
         Set roles = new HashSet(2);
         roles.add(authorities[0].getAuthority());
@@ -142,11 +113,10 @@ public class DefaultLdapAuthoritiesPopulatorTests extends AbstractLdapIntegratio
         populator.setConvertToUpperCase(true);
         populator.setSearchSubtree(true);
 
-        LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence();
-        user.setUsername("manager");
-        user.setDn("uid=ben,ou=people,dc=acegisecurity,dc=org");
+        DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=ben,ou=people,dc=acegisecurity,dc=org"));
+
+        GrantedAuthority[] authorities = populator.getGrantedAuthorities(ctx, "manager");
 
-        GrantedAuthority[] authorities = populator.getGrantedAuthorities(user.createUserDetails());
         assertEquals("Should have 3 roles", 3, authorities.length);
         Set roles = new HashSet(3);
         roles.add(authorities[0].getAuthority());

+ 4 - 3
core/src/test/java/org/acegisecurity/userdetails/ldap/LdapUserDetailsMapperTests.java

@@ -22,6 +22,7 @@ import javax.naming.directory.BasicAttribute;
 
 import org.springframework.ldap.core.DirContextAdapter;
 import org.springframework.ldap.core.DistinguishedName;
+import org.acegisecurity.GrantedAuthority;
 
 /**
  * Tests {@link LdapUserDetailsMapper}.
@@ -44,7 +45,7 @@ public class LdapUserDetailsMapperTests extends TestCase {
         ctx.setAttributeValues("userRole", new String[] {"X", "Y", "Z"});
         ctx.setAttributeValue("uid", "ani");
 
-        LdapUserDetailsImpl user = (LdapUserDetailsImpl) mapper.mapFromContext(ctx);
+        LdapUserDetailsImpl user = (LdapUserDetailsImpl) mapper.mapUserFromContext(ctx, "ani", new GrantedAuthority[0]);
 
         assertEquals(3, user.getAuthorities().length);
     }
@@ -63,7 +64,7 @@ public class LdapUserDetailsMapperTests extends TestCase {
         DirContextAdapter ctx = new DirContextAdapter(attrs, new DistinguishedName("cn=someName"));
         ctx.setAttributeValue("uid", "ani");
 
-        LdapUserDetailsImpl user = (LdapUserDetailsImpl) mapper.mapFromContext(ctx);
+        LdapUserDetailsImpl user = (LdapUserDetailsImpl) mapper.mapUserFromContext(ctx, "ani", new GrantedAuthority[0]);
 
         assertEquals(1, user.getAuthorities().length);
         assertEquals("ROLE_X", user.getAuthorities()[0].getAuthority());
@@ -94,7 +95,7 @@ public class LdapUserDetailsMapperTests extends TestCase {
         DirContextAdapter ctx = new DirContextAdapter(attrs, new DistinguishedName("cn=someName"));
         ctx.setAttributeValue("uid", "ani");
 
-        LdapUserDetails user = (LdapUserDetailsImpl) mapper.mapFromContext(ctx);
+        LdapUserDetails user = (LdapUserDetailsImpl) mapper.mapUserFromContext(ctx, "ani", new GrantedAuthority[0]);
 
         assertEquals("mypassword", user.getPassword());
     }