浏览代码

SEC-9 and SEC-55: Refactor DaoAuthenticationProvider and deprecate PasswordDaoAuthenticationProvider.

Ben Alex 20 年之前
父节点
当前提交
e9b1d9452f

+ 280 - 0
core/src/main/java/org/acegisecurity/providers/dao/AbstractUserDetailsAuthenticationProvider.java

@@ -0,0 +1,280 @@
+/* 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 net.sf.acegisecurity.providers.dao;
+
+import net.sf.acegisecurity.AccountExpiredException;
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.AuthenticationException;
+import net.sf.acegisecurity.CredentialsExpiredException;
+import net.sf.acegisecurity.DisabledException;
+import net.sf.acegisecurity.LockedException;
+import net.sf.acegisecurity.UserDetails;
+import net.sf.acegisecurity.providers.AuthenticationProvider;
+import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
+
+import org.springframework.beans.factory.InitializingBean;
+
+import org.springframework.util.Assert;
+
+
+/**
+ * A base {@link AuthenticationProvider} that allows subclasses to override and
+ * work with {@link net.sf.acegisecurity.UserDetails} objects. The class is
+ * designed to respond to {@link UsernamePasswordAuthenticationToken}
+ * authentication requests.
+ * 
+ * <p>
+ * Upon successful validation, a
+ * <code>UsernamePasswordAuthenticationToken</code> will be created and
+ * returned to the caller. The token will include as its principal either a
+ * <code>String</code> representation of the username, or the {@link
+ * UserDetails} that was returned from the authentication repository. Using
+ * <code>String</code> is appropriate if a container adapter is being used, as
+ * it expects <code>String</code> representations of the username. Using
+ * <code>UserDetails</code> is appropriate if you require access to additional
+ * properties of the authenticated user, such as email addresses,
+ * human-friendly names etc. As container adapters are not recommended to be
+ * used, and <code>UserDetails</code> implementations provide additional
+ * flexibility, by default a <code>UserDetails</code> is returned. To override
+ * this default, set the {@link #setForcePrincipalAsString} to
+ * <code>true</code>.
+ * </p>
+ * 
+ * <P>
+ * Caching is handled via the <code>UserDetails</code> object being placed in
+ * the {@link UserCache}. This ensures that subsequent requests with the same
+ * username can be validated without needing to query the {@link
+ * AuthenticationDao}. It should be noted that if a user appears to present an
+ * incorrect password, the {@link AuthenticationDao} will be queried to
+ * confirm the most up-to-date password was used for comparison.
+ * </p>
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public abstract class AbstractUserDetailsAuthenticationProvider
+    implements AuthenticationProvider, InitializingBean {
+    //~ Instance fields ========================================================
+
+    private UserCache userCache = new NullUserCache();
+    private boolean forcePrincipalAsString = false;
+
+    //~ Methods ================================================================
+
+    public void setForcePrincipalAsString(boolean forcePrincipalAsString) {
+        this.forcePrincipalAsString = forcePrincipalAsString;
+    }
+
+    public boolean isForcePrincipalAsString() {
+        return forcePrincipalAsString;
+    }
+
+    public void setUserCache(UserCache userCache) {
+        this.userCache = userCache;
+    }
+
+    public UserCache getUserCache() {
+        return userCache;
+    }
+
+    public final void afterPropertiesSet() throws Exception {
+        Assert.notNull(this.userCache, "A user cache must be set");
+        doAfterPropertiesSet();
+    }
+
+    public Authentication authenticate(Authentication authentication)
+        throws AuthenticationException {
+        Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class,
+            authentication,
+            "Only UsernamePasswordAuthenticationToken is supported");
+
+        // Determine username
+        String username = (authentication.getPrincipal() == null)
+            ? "NONE_PROVIDED" : authentication.getName();
+
+        boolean cacheWasUsed = true;
+        UserDetails user = this.userCache.getUserFromCache(username);
+
+        if (user == null) {
+            cacheWasUsed = false;
+            user = retrieveUser(username,
+                    (UsernamePasswordAuthenticationToken) authentication);
+            Assert.notNull(user,
+                "retrieveUser returned null - a violation of the interface contract");
+        }
+
+        if (!user.isAccountNonLocked()) {
+            throw new LockedException("User account is locked");
+        }
+
+        if (!user.isEnabled()) {
+            throw new DisabledException("User is disabled");
+        }
+
+        if (!user.isAccountNonExpired()) {
+            throw new AccountExpiredException("User account has expired");
+        }
+
+        // This check must come here, as we don't want to tell users
+        // about account status unless they presented the correct credentials
+        try {
+            additionalAuthenticationChecks(user,
+                (UsernamePasswordAuthenticationToken) authentication);
+        } catch (AuthenticationException exception) {
+            // There was a problem, so try again after checking we're using latest data
+            cacheWasUsed = false;
+            user = retrieveUser(username,
+                    (UsernamePasswordAuthenticationToken) authentication);
+            additionalAuthenticationChecks(user,
+                (UsernamePasswordAuthenticationToken) authentication);
+        }
+
+        if (!user.isCredentialsNonExpired()) {
+            throw new CredentialsExpiredException(
+                "User credentials have expired");
+        }
+
+        if (!cacheWasUsed) {
+            this.userCache.putUserInCache(user);
+        }
+
+        Object principalToReturn = user;
+
+        if (forcePrincipalAsString) {
+            principalToReturn = user.getUsername();
+        }
+
+        return createSuccessAuthentication(principalToReturn, authentication,
+            user);
+    }
+
+    public boolean supports(Class authentication) {
+        return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
+    }
+
+    /**
+     * Allows subclasses to perform any additional checks of a returned (or
+     * cached) <code>UserDetails</code> for a given authentication request.
+     * Generally a subclass will at least compare the {@link
+     * Authentication#getCredentials()} with a {@link
+     * UserDetails#getPassword()}. If custom logic is needed to compare
+     * additional properties of <code>UserDetails</code> and/or
+     * <code>UsernamePasswordAuthenticationToken</code>, these should also
+     * appear in this method.
+     *
+     * @param userDetails as retrieved from the {@link #retrieveUser(String,
+     *        UsernamePasswordAuthenticationToken)} or <code>UserCache</code>
+     * @param authentication the current request that needs to be authenticated
+     *
+     * @throws AuthenticationException AuthenticationException if the
+     *         credentials could not be validated (generally a
+     *         <code>BadCredentialsException</code>, an
+     *         <code>AuthenticationServiceException</code>)
+     */
+    protected abstract void additionalAuthenticationChecks(
+        UserDetails userDetails,
+        UsernamePasswordAuthenticationToken authentication)
+        throws AuthenticationException;
+
+    protected void doAfterPropertiesSet() throws Exception {}
+
+    /**
+     * Allows subclasses to actually retrieve the <code>UserDetails</code> from
+     * an implementation-specific location, with the option of throwing an
+     * <code>AuthenticationException</code> immediately if the presented
+     * credentials are incorrect (this is especially useful if it is necessary
+     * to bind to a resource as the user in order to obtain or generate a
+     * <code>UserDetails</code>).
+     * 
+     * <p>
+     * Subclasses are not required to perform any caching, as the
+     * <code>AbstractUserDetailsAuthenticationProvider</code> will by default
+     * cache the <code>UserDetails</code>. The caching of
+     * <code>UserDetails</code> does present additional complexity as this
+     * means subsequent requests that rely on the cache will need to still
+     * have their credentials validated, even if the correctness of
+     * credentials was assured by subclasses adopting a binding-based strategy
+     * in this method. Accordingly it is important that subclasses either
+     * disable caching (if they want to ensure that this method is the only
+     * method that is capable of authenticating a request, as no
+     * <code>UserDetails</code> will ever be cached) or ensure subclasses
+     * implement {@link #additionalAuthenticationChecks(UserDetails,
+     * UsernamePasswordAuthenticationToken)} to compare the credentials of a
+     * cached <code>UserDetails</code> with subsequent authentication
+     * requests.
+     * </p>
+     * 
+     * <p>
+     * Most of the time subclasses will not perform credentials inspection in
+     * this method, instead performing it in {@link
+     * #additionalAuthenticationChecks(UserDetails,
+     * UsernamePasswordAuthenticationToken)} so that code related to
+     * credentials validation need not be duplicated across two methods.
+     * </p>
+     *
+     * @param username The username to retrieve
+     * @param authentication The authentication request, which subclasses
+     *        <em>may</em> need to perform a binding-based retrieval of the
+     *        <code>UserDetails</code>
+     *
+     * @return the user information (never <code>null</code> - instead an
+     *         exception should the thrown)
+     *
+     * @throws AuthenticationException if the credentials could not be
+     *         validated (generally a <code>BadCredentialsException</code>, an
+     *         <code>AuthenticationServiceException</code> or
+     *         <code>UserNotFoundException</code>)
+     */
+    protected abstract UserDetails retrieveUser(String username,
+        UsernamePasswordAuthenticationToken authentication)
+        throws AuthenticationException;
+
+    /**
+     * Creates a successful {@link Authentication} object.
+     * 
+     * <P>
+     * Protected so subclasses can override.
+     * </p>
+     * 
+     * <P>
+     * Subclasses will usually store the original credentials the user supplied
+     * (not salted or encoded passwords) in the returned
+     * <code>Authentication</code> object.
+     * </p>
+     *
+     * @param principal that should be the principal in the returned object
+     *        (defined by the {@link #isForcePrincipalAsString()} method)
+     * @param authentication that was presented to the
+     *        <code>DaoAuthenticationProvider</code> for validation
+     * @param user that was loaded by the <code>AuthenticationDao</code>
+     *
+     * @return the successful authentication token
+     */
+    protected Authentication createSuccessAuthentication(Object principal,
+        Authentication authentication, UserDetails user) {
+        // Ensure we return the original credentials the user supplied,
+        // so subsequent attempts are successful even with encoded passwords.
+        // Also ensure we return the original getDetails(), so that future
+        // authentication events after cache expiry contain the details
+        UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal,
+                authentication.getCredentials(), user.getAuthorities());
+        result.setDetails((authentication.getDetails() != null)
+            ? authentication.getDetails() : null);
+
+        return result;
+    }
+}

+ 15 - 194
core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java

@@ -15,23 +15,15 @@
 
 package net.sf.acegisecurity.providers.dao;
 
-import net.sf.acegisecurity.AccountExpiredException;
-import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.AuthenticationException;
 import net.sf.acegisecurity.AuthenticationServiceException;
 import net.sf.acegisecurity.BadCredentialsException;
-import net.sf.acegisecurity.CredentialsExpiredException;
-import net.sf.acegisecurity.DisabledException;
-import net.sf.acegisecurity.LockedException;
 import net.sf.acegisecurity.UserDetails;
 import net.sf.acegisecurity.providers.AuthenticationProvider;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
-import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
 import net.sf.acegisecurity.providers.encoding.PasswordEncoder;
 import net.sf.acegisecurity.providers.encoding.PlaintextPasswordEncoder;
 
-import org.springframework.beans.factory.InitializingBean;
-
 import org.springframework.dao.DataAccessException;
 
 import org.springframework.util.Assert;
@@ -40,51 +32,17 @@ import org.springframework.util.Assert;
 /**
  * An {@link AuthenticationProvider} implementation that retrieves user details
  * from an {@link AuthenticationDao}.
- * 
- * <p>
- * This <code>AuthenticationProvider</code> is capable of validating {@link
- * UsernamePasswordAuthenticationToken} requests contain the correct username,
- * password and the user is not disabled.
- * </p>
- * 
- * <p>
- * Upon successful validation, a
- * <code>UsernamePasswordAuthenticationToken</code> will be created and
- * returned to the caller. The token will include as its principal either a
- * <code>String</code> representation of the username, or the {@link
- * UserDetails} that was returned from the authentication repository. Using
- * <code>String</code> is appropriate if a container adapter is being used, as
- * it expects <code>String</code> representations of the username. Using
- * <code>UserDetails</code> is appropriate if you require access to additional
- * properties of the authenticated user, such as email addresses,
- * human-friendly names etc. As container adapters are not recommended to be
- * used, and <code>UserDetails</code> implementations provide additional
- * flexibility, by default a <code>UserDetails</code> is returned. To override
- * this default, set the {@link #setForcePrincipalAsString} to
- * <code>true</code>.
- * </p>
- * 
- * <P>
- * Caching is handled via the <code>UserDetails</code> object being placed in
- * the {@link UserCache}. This ensures that subsequent requests with the same
- * username can be validated without needing to query the {@link
- * AuthenticationDao}. It should be noted that if a user appears to present an
- * incorrect password, the {@link AuthenticationDao} will be queried to
- * confirm the most up-to-date password was used for comparison.
- * </p>
  *
  * @author Ben Alex
  * @version $Id$
  */
-public class DaoAuthenticationProvider implements AuthenticationProvider,
-    InitializingBean {
+public class DaoAuthenticationProvider
+    extends AbstractUserDetailsAuthenticationProvider {
     //~ Instance fields ========================================================
 
     private AuthenticationDao authenticationDao;
     private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
     private SaltSource saltSource;
-    private UserCache userCache = new NullUserCache();
-    private boolean forcePrincipalAsString = false;
     private boolean hideUserNotFoundExceptions = true;
 
     //~ Methods ================================================================
@@ -97,14 +55,6 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
         return authenticationDao;
     }
 
-    public void setForcePrincipalAsString(boolean forcePrincipalAsString) {
-        this.forcePrincipalAsString = forcePrincipalAsString;
-    }
-
-    public boolean isForcePrincipalAsString() {
-        return forcePrincipalAsString;
-    }
-
     /**
      * By default the <code>DaoAuthenticationProvider</code> throws a
      * <code>BadCredentialsException</code> if a username is not found or the
@@ -159,158 +109,29 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
         return saltSource;
     }
 
-    public void setUserCache(UserCache userCache) {
-        this.userCache = userCache;
-    }
-
-    public UserCache getUserCache() {
-        return userCache;
-    }
-
-    public void afterPropertiesSet() throws Exception {
-        Assert.notNull(this.authenticationDao,
-            "An Authentication DAO must be set");
-        Assert.notNull(this.userCache, "A user cache must be set");
-    }
-
-    public Authentication authenticate(Authentication authentication)
+    protected void additionalAuthenticationChecks(UserDetails userDetails,
+        UsernamePasswordAuthenticationToken authentication)
         throws AuthenticationException {
-        // Determine username
-        String username = "NONE_PROVIDED";
-
-        if (authentication.getPrincipal() != null) {
-            username = authentication.getPrincipal().toString();
-        }
-
-        if (authentication.getPrincipal() instanceof UserDetails) {
-            username = ((UserDetails) authentication.getPrincipal())
-                .getUsername();
-        }
-
-        boolean cacheWasUsed = true;
-        UserDetails user = this.userCache.getUserFromCache(username);
-
-        if (user == null) {
-            cacheWasUsed = false;
-            user = getUserFromBackend(username);
-        }
-
-        if (!user.isAccountNonLocked()) {
-            throw new LockedException("User account is locked");
-        }
-
-        if (!isPasswordCorrect(authentication, user)) {
-            // Password incorrect, so ensure we're using most current password
-            if (cacheWasUsed) {
-                cacheWasUsed = false;
-                user = getUserFromBackend(username);
-            }
-
-            if (!isPasswordCorrect(authentication, user)) {
-                throw new BadCredentialsException("Bad credentials presented");
-            }
-        }
-
-        if (!user.isEnabled()) {
-            throw new DisabledException("User is disabled");
-        }
-
-        if (!user.isAccountNonExpired()) {
-            throw new AccountExpiredException("User account has expired");
-        }
-
-        if (!user.isCredentialsNonExpired()) {
-            throw new CredentialsExpiredException(
-                "User credentials have expired");
-        }
-
-        if (!cacheWasUsed) {
-            // Put into cache
-            this.userCache.putUserInCache(user);
-        }
-
-        Object principalToReturn = user;
-
-        if (forcePrincipalAsString) {
-            principalToReturn = user.getUsername();
-        }
-
-        return createSuccessAuthentication(principalToReturn, authentication,
-            user);
-    }
-
-    public boolean supports(Class authentication) {
-        if (UsernamePasswordAuthenticationToken.class.isAssignableFrom(
-                authentication)) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Indicates whether the supplied <code>Authentication</code> object
-     * provided appropriate credentials. This method can be called several
-     * times throughout a single authentication request.
-     * 
-     * <P>
-     * Protected so subclasses can override.
-     * </p>
-     *
-     * @param authentication that was presented to the
-     *        <code>DaoAuthenticationProvider</code> for validation
-     * @param user that was loaded by the <code>AuthenticationDao</code>
-     *
-     * @return a boolean indicating whether the credentials were correct
-     */
-    protected boolean isPasswordCorrect(Authentication authentication,
-        UserDetails user) {
         Object salt = null;
 
         if (this.saltSource != null) {
-            salt = this.saltSource.getSalt(user);
+            salt = this.saltSource.getSalt(userDetails);
         }
 
-        return passwordEncoder.isPasswordValid(user.getPassword(),
-            authentication.getCredentials().toString(), salt);
+        if (!passwordEncoder.isPasswordValid(userDetails.getPassword(),
+                authentication.getCredentials().toString(), salt)) {
+            throw new BadCredentialsException("Bad credentials");
+        }
     }
 
-    /**
-     * Creates a successful {@link Authentication} object.
-     * 
-     * <P>
-     * Protected so subclasses can override.
-     * </p>
-     * 
-     * <P>
-     * Subclasses will usually store the original credentials the user supplied
-     * (not salted or encoded passwords) in the returned
-     * <code>Authentication</code> object.
-     * </p>
-     *
-     * @param principal that should be the principal in the returned object
-     *        (defined by the {@link #isForcePrincipalAsString()} method)
-     * @param authentication that was presented to the
-     *        <code>DaoAuthenticationProvider</code> for validation
-     * @param user that was loaded by the <code>AuthenticationDao</code>
-     *
-     * @return the successful authentication token
-     */
-    protected Authentication createSuccessAuthentication(Object principal,
-        Authentication authentication, UserDetails user) {
-        // Ensure we return the original credentials the user supplied,
-        // so subsequent attempts are successful even with encoded passwords.
-        // Also ensure we return the original getDetails(), so that future
-        // authentication events after cache expiry contain the details
-        UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal,
-                authentication.getCredentials(), user.getAuthorities());
-        result.setDetails((authentication.getDetails() != null)
-            ? authentication.getDetails() : null);
-
-        return result;
+    protected void doAfterPropertiesSet() throws Exception {
+        Assert.notNull(this.authenticationDao,
+            "An Authentication DAO must be set");
     }
 
-    private UserDetails getUserFromBackend(String username) {
+    protected final UserDetails retrieveUser(String username,
+        UsernamePasswordAuthenticationToken authentication)
+        throws AuthenticationException {
         UserDetails loadedUser;
 
         try {

+ 0 - 1
sandbox/src/main/java/org/acegisecurity/providers/dao/ldap/LdapPasswordAuthenticationDao.java

@@ -24,7 +24,6 @@ import net.sf.acegisecurity.BadCredentialsException;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.UserDetails;
-import net.sf.acegisecurity.providers.dao.PasswordAuthenticationDao;
 import net.sf.acegisecurity.providers.dao.User;
 
 /** 

+ 3 - 2
core/src/main/java/org/acegisecurity/providers/dao/PasswordAuthenticationDao.java → sandbox/src/main/java/org/acegisecurity/providers/dao/ldap/PasswordAuthenticationDao.java

@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package net.sf.acegisecurity.providers.dao;
+package net.sf.acegisecurity.providers.dao.ldap;
 
 import net.sf.acegisecurity.BadCredentialsException;
 import net.sf.acegisecurity.UserDetails;
@@ -33,7 +33,8 @@ import org.springframework.dao.DataAccessException;
  * The interface requires only one read-only method, which simplifies support
  * of new data access strategies.
  * </p>
- *
+ * 
+ * @deprecated instead subclass {@link net.sf.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider}
  * @author Karel Miarka
  */
 public interface PasswordAuthenticationDao {

+ 4 - 1
core/src/main/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProvider.java → sandbox/src/main/java/org/acegisecurity/providers/dao/ldap/PasswordDaoAuthenticationProvider.java

@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package net.sf.acegisecurity.providers.dao;
+package net.sf.acegisecurity.providers.dao.ldap;
 
 import net.sf.acegisecurity.AccountExpiredException;
 import net.sf.acegisecurity.Authentication;
@@ -25,6 +25,8 @@ import net.sf.acegisecurity.LockedException;
 import net.sf.acegisecurity.UserDetails;
 import net.sf.acegisecurity.providers.AuthenticationProvider;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+import net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider;
+import net.sf.acegisecurity.providers.dao.UserCache;
 import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
 
 import org.springframework.beans.factory.InitializingBean;
@@ -83,6 +85,7 @@ import org.springframework.util.Assert;
  * further information.
  * </p>
  *
+ * @deprecated instead subclass {@link net.sf.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider}
  * @author Karel Miarka
  */
 public class PasswordDaoAuthenticationProvider implements AuthenticationProvider,

+ 1 - 1
sandbox/src/main/java/org/acegisecurity/providers/dao/ldap/revised/LdapPassword2AuthenticationDao.java

@@ -24,7 +24,7 @@ import net.sf.acegisecurity.BadCredentialsException;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.UserDetails;
-import net.sf.acegisecurity.providers.dao.PasswordAuthenticationDao;
+import net.sf.acegisecurity.providers.dao.ldap.PasswordAuthenticationDao;
 
 /**
  * Re-written version of the ACEGI LDAP code, 

+ 7 - 5
core/src/test/java/org/acegisecurity/providers/dao/PasswordDaoAuthenticationProviderTests.java → sandbox/src/test/java/org/acegisecurity/providers/dao/ldap/PasswordDaoAuthenticationProviderTests.java

@@ -13,10 +13,12 @@
  * limitations under the License.
  */
 
-package net.sf.acegisecurity.providers.dao;
+package net.sf.acegisecurity.providers.dao.ldap;
 
-import junit.framework.TestCase;
+import java.util.HashMap;
+import java.util.Map;
 
+import junit.framework.TestCase;
 import net.sf.acegisecurity.AccountExpiredException;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.AuthenticationServiceException;
@@ -29,15 +31,15 @@ import net.sf.acegisecurity.LockedException;
 import net.sf.acegisecurity.UserDetails;
 import net.sf.acegisecurity.providers.TestingAuthenticationToken;
 import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
+import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserCache;
+import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 import net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache;
 import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
 
 import org.springframework.dao.DataAccessException;
 import org.springframework.dao.DataRetrievalFailureException;
 
-import java.util.HashMap;
-import java.util.Map;
-
 
 /**
  * Tests {@link PasswordDaoAuthenticationProvider}.