Browse Source

Refactor User to an interface.

Ben Alex 21 năm trước cách đây
mục cha
commit
6314aa4efa
32 tập tin đã thay đổi với 248 bổ sung124 xóa
  1. 2 0
      changelog.txt
  2. 16 13
      core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java
  3. 2 2
      core/src/main/java/org/acegisecurity/providers/dao/SaltSource.java
  4. 9 8
      core/src/main/java/org/acegisecurity/providers/dao/UserCache.java
  5. 70 0
      core/src/main/java/org/acegisecurity/providers/dao/UserDetails.java
  6. 5 5
      core/src/main/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCache.java
  7. 3 3
      core/src/main/java/org/acegisecurity/providers/dao/cache/NullUserCache.java
  8. 4 3
      core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationEvent.java
  9. 2 2
      core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailureDisabledEvent.java
  10. 2 2
      core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailurePasswordEvent.java
  11. 3 2
      core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationSuccessEvent.java
  12. 2 1
      core/src/main/java/org/acegisecurity/providers/dao/salt/ReflectionSaltSource.java
  13. 2 1
      core/src/main/java/org/acegisecurity/providers/dao/salt/SystemWideSaltSource.java
  14. 12 4
      core/src/main/java/org/acegisecurity/userdetails/User.java
  15. 3 3
      core/src/main/java/org/acegisecurity/userdetails/UserDetailsService.java
  16. 4 3
      core/src/main/java/org/acegisecurity/userdetails/jdbc/JdbcDaoImpl.java
  17. 2 2
      core/src/main/java/org/acegisecurity/userdetails/memory/InMemoryDaoImpl.java
  18. 2 1
      core/src/main/java/org/acegisecurity/userdetails/memory/UserMap.java
  19. 2 1
      core/src/main/java/org/acegisecurity/userdetails/memory/UserMapEditor.java
  20. 3 2
      core/src/test/java/org/acegisecurity/providers/cas/populator/DaoCasAuthoritiesPopulatorTests.java
  21. 6 6
      core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.java
  22. 7 7
      core/src/test/java/org/acegisecurity/providers/dao/UserTests.java
  23. 5 5
      core/src/test/java/org/acegisecurity/providers/dao/jdbc/JdbcDaoTests.java
  24. 5 4
      core/src/test/java/org/acegisecurity/providers/dao/memory/UserMapTests.java
  25. 3 2
      core/src/test/java/org/acegisecurity/providers/dao/salt/ReflectionSaltSourceTests.java
  26. 5 5
      core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java
  27. 35 25
      docs/reference/src/index.xml
  28. 3 3
      samples/contacts/src/main/java/sample/contact/ContactManagerFacade.java
  29. 3 3
      samples/contacts/src/main/java/sample/contact/ContactSecurityVoter.java
  30. 3 3
      samples/contacts/src/main/java/sample/contact/SecureIndexController.java
  31. 3 3
      samples/contacts/src/main/java/sample/contact/WebContactAddController.java
  32. 20 0
      upgrade-05-06.txt

+ 2 - 0
changelog.txt

@@ -2,7 +2,9 @@ Changes in version 0.6 (2004-xx-xx)
 -----------------------------------
 -----------------------------------
 
 
 * Added feature so DaoAuthenticationProvider returns User in Authentication
 * Added feature so DaoAuthenticationProvider returns User in Authentication
+* Refactored User to UserDetails interface
 * Fixed Linux compatibility issues (directory case sensitivity etc)
 * Fixed Linux compatibility issues (directory case sensitivity etc)
+* Fixed AbstractProcessingFilter to handle servlet spec container differences
 * Documentation improvements
 * Documentation improvements
 
 
 Changes in version 0.51 (2004-06-06)
 Changes in version 0.51 (2004-06-06)

+ 16 - 13
core/src/main/java/org/acegisecurity/providers/dao/DaoAuthenticationProvider.java

@@ -52,21 +52,22 @@ import org.springframework.dao.DataAccessException;
  * Upon successful validation, a
  * Upon successful validation, a
  * <code>UsernamePasswordAuthenticationToken</code> will be created and
  * <code>UsernamePasswordAuthenticationToken</code> will be created and
  * returned to the caller. The token will include as its principal either a
  * returned to the caller. The token will include as its principal either a
- * <code>String</code> representation of the username, or the {@link User}
- * that was returned from the authentication repository. Using
+ * <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
  * <code>String</code> is appropriate if a container adapter is being used, as
  * it expects <code>String</code> representations of the username. Using
  * it expects <code>String</code> representations of the username. Using
- * <code>User</code> is appropriate if you require access to additional
+ * <code>UserDetails</code> is appropriate if you require access to additional
  * properties of the authenticated user, such as email addresses,
  * properties of the authenticated user, such as email addresses,
  * human-friendly names etc. As container adapters are not recommended to be
  * human-friendly names etc. As container adapters are not recommended to be
- * used, and <code>User</code> provides additional flexibility, by default a
- * <code>User</code> is returned. To override this default, set the {@link
- * #setForcePrincipalAsString} to <code>true</code>.
+ * 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>
  * 
  * 
  * <P>
  * <P>
- * Caching is handled via the <code>User</code> object being placed in the
- * {@link UserCache}. This ensures that subsequent requests with the same
+ * 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
  * username can be validated without needing to query the {@link
  * AuthenticationDao}. It should be noted that if a user appears to present an
  * AuthenticationDao}. It should be noted that if a user appears to present an
  * incorrect password, the {@link AuthenticationDao} will be queried to
  * incorrect password, the {@link AuthenticationDao} will be queried to
@@ -174,12 +175,13 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
         // Determine username
         // Determine username
         String username = authentication.getPrincipal().toString();
         String username = authentication.getPrincipal().toString();
 
 
-        if (authentication.getPrincipal() instanceof User) {
-            username = ((User) authentication.getPrincipal()).getUsername();
+        if (authentication.getPrincipal() instanceof UserDetails) {
+            username = ((UserDetails) authentication.getPrincipal())
+                .getUsername();
         }
         }
 
 
         boolean cacheWasUsed = true;
         boolean cacheWasUsed = true;
-        User user = this.userCache.getUserFromCache(username);
+        UserDetails user = this.userCache.getUserFromCache(username);
 
 
         if (user == null) {
         if (user == null) {
             cacheWasUsed = false;
             cacheWasUsed = false;
@@ -244,7 +246,8 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
         }
         }
     }
     }
 
 
-    protected boolean isPasswordCorrect(Authentication authentication, User user) {
+    protected boolean isPasswordCorrect(Authentication authentication,
+        UserDetails user) {
         Object salt = null;
         Object salt = null;
 
 
         if (this.saltSource != null) {
         if (this.saltSource != null) {
@@ -255,7 +258,7 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
             authentication.getCredentials().toString(), salt);
             authentication.getCredentials().toString(), salt);
     }
     }
 
 
-    private User getUserFromBackend(String username) {
+    private UserDetails getUserFromBackend(String username) {
         try {
         try {
             return this.authenticationDao.loadUserByUsername(username);
             return this.authenticationDao.loadUserByUsername(username);
         } catch (UsernameNotFoundException notFound) {
         } catch (UsernameNotFoundException notFound) {

+ 2 - 2
core/src/main/java/org/acegisecurity/providers/dao/SaltSource.java

@@ -29,7 +29,7 @@ public interface SaltSource {
      *
      *
      * @param user from the <code>AuthenticationDao</code>
      * @param user from the <code>AuthenticationDao</code>
      *
      *
-     * @return the salt to use for this <code>USer</code>
+     * @return the salt to use for this <code>UserDetails</code>
      */
      */
-    public Object getSalt(User user);
+    public Object getSalt(UserDetails user);
 }
 }

+ 9 - 8
core/src/main/java/org/acegisecurity/providers/dao/UserCache.java

@@ -33,21 +33,22 @@ public interface UserCache {
     //~ Methods ================================================================
     //~ Methods ================================================================
 
 
     /**
     /**
-     * Obtains a {@link User} from the cache.
+     * Obtains a {@link UserDetails} from the cache.
      *
      *
      * @param username the {@link User#getUsername()} used to place the user in
      * @param username the {@link User#getUsername()} used to place the user in
      *        the cache
      *        the cache
      *
      *
-     * @return the populated <code>User</code> or <code>null</code> if the user
-     *         could not be found or if the cache entry has expired
+     * @return the populated <code>UserDetails</code> or <code>null</code> if
+     *         the user could not be found or if the cache entry has expired
      */
      */
-    public User getUserFromCache(String username);
+    public UserDetails getUserFromCache(String username);
 
 
     /**
     /**
-     * Places a {@link User} in the cache. The <code>username</code> is the key
-     * used to subsequently retrieve the <code>User</code>.
+     * Places a {@link UserDetails} in the cache. The <code>username</code> is
+     * the key used to subsequently retrieve the <code>UserDetails</code>.
      *
      *
-     * @param user the fully populated <code>User</code> to place in the cache
+     * @param user the fully populated <code>UserDetails</code> to place in the
+     *        cache
      */
      */
-    public void putUserInCache(User user);
+    public void putUserInCache(UserDetails user);
 }
 }

+ 70 - 0
core/src/main/java/org/acegisecurity/providers/dao/UserDetails.java

@@ -0,0 +1,70 @@
+/* Copyright 2004 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.GrantedAuthority;
+
+import java.io.Serializable;
+
+
+/**
+ * Provides core user information required by the package.
+ * 
+ * <P>
+ * Concrete implementations must take particular care to ensure the non-null
+ * contract detailed for each method is enforced. See {@link User} for a
+ * reference implementation (which you might like to extend).
+ * </p>
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public interface UserDetails extends Serializable {
+    //~ Methods ================================================================
+
+    /**
+     * Returns the authorities granted to the user. Cannot return
+     * <code>null</code>.
+     *
+     * @return the authorities (never <code>null</code>)
+     */
+    public GrantedAuthority[] getAuthorities();
+
+    /**
+     * Indicates whether the user is enabled or disabled. A disabled user
+     * cannot be authenticated.
+     *
+     * @return <code>true</code> if the user is enabled, <code>false</code>
+     *         otherwise
+     */
+    public boolean isEnabled();
+
+    /**
+     * Returns the password used to authenticate the user. Cannot return
+     * <code>null</code>.
+     *
+     * @return the password (never <code>null</code>)
+     */
+    public String getPassword();
+
+    /**
+     * Returns the username used to authenticate the user. Cannot return
+     * <code>null</code>.
+     *
+     * @return the username (never <code>null</code>)
+     */
+    public String getUsername();
+}

+ 5 - 5
core/src/main/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCache.java

@@ -15,8 +15,8 @@
 
 
 package net.sf.acegisecurity.providers.dao.cache;
 package net.sf.acegisecurity.providers.dao.cache;
 
 
-import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.providers.dao.UserCache;
 import net.sf.acegisecurity.providers.dao.UserCache;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 import net.sf.ehcache.Cache;
 import net.sf.ehcache.Cache;
 import net.sf.ehcache.CacheException;
 import net.sf.ehcache.CacheException;
@@ -72,7 +72,7 @@ public class EhCacheBasedUserCache implements UserCache, InitializingBean,
         return minutesToIdle;
         return minutesToIdle;
     }
     }
 
 
-    public User getUserFromCache(String username) {
+    public UserDetails getUserFromCache(String username) {
         Element element = null;
         Element element = null;
 
 
         try {
         try {
@@ -90,7 +90,7 @@ public class EhCacheBasedUserCache implements UserCache, InitializingBean,
         if (element == null) {
         if (element == null) {
             return null;
             return null;
         } else {
         } else {
-            return (User) element.getValue();
+            return (UserDetails) element.getValue();
         }
         }
     }
     }
 
 
@@ -111,7 +111,7 @@ public class EhCacheBasedUserCache implements UserCache, InitializingBean,
         manager.removeCache(CACHE_NAME);
         manager.removeCache(CACHE_NAME);
     }
     }
 
 
-    public void putUserInCache(User user) {
+    public void putUserInCache(UserDetails user) {
         Element element = new Element(user.getUsername(), user);
         Element element = new Element(user.getUsername(), user);
 
 
         if (logger.isDebugEnabled()) {
         if (logger.isDebugEnabled()) {
@@ -121,7 +121,7 @@ public class EhCacheBasedUserCache implements UserCache, InitializingBean,
         cache.put(element);
         cache.put(element);
     }
     }
 
 
-    public void removeUserFromCache(User user) {
+    public void removeUserFromCache(UserDetails user) {
         if (logger.isDebugEnabled()) {
         if (logger.isDebugEnabled()) {
             logger.debug("Cache remove: " + user.getUsername());
             logger.debug("Cache remove: " + user.getUsername());
         }
         }

+ 3 - 3
core/src/main/java/org/acegisecurity/providers/dao/cache/NullUserCache.java

@@ -15,8 +15,8 @@
 
 
 package net.sf.acegisecurity.providers.dao.cache;
 package net.sf.acegisecurity.providers.dao.cache;
 
 
-import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.providers.dao.UserCache;
 import net.sf.acegisecurity.providers.dao.UserCache;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 
 
 /**
 /**
@@ -28,9 +28,9 @@ import net.sf.acegisecurity.providers.dao.UserCache;
 public class NullUserCache implements UserCache {
 public class NullUserCache implements UserCache {
     //~ Methods ================================================================
     //~ Methods ================================================================
 
 
-    public User getUserFromCache(String username) {
+    public UserDetails getUserFromCache(String username) {
         return null;
         return null;
     }
     }
 
 
-    public void putUserInCache(User user) {}
+    public void putUserInCache(UserDetails user) {}
 }
 }

+ 4 - 3
core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationEvent.java

@@ -17,6 +17,7 @@ package net.sf.acegisecurity.providers.dao.event;
 
 
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 import org.springframework.context.ApplicationEvent;
 import org.springframework.context.ApplicationEvent;
 
 
@@ -44,11 +45,11 @@ import org.springframework.context.ApplicationEvent;
 public abstract class AuthenticationEvent extends ApplicationEvent {
 public abstract class AuthenticationEvent extends ApplicationEvent {
     //~ Instance fields ========================================================
     //~ Instance fields ========================================================
 
 
-    private User user;
+    private UserDetails user;
 
 
     //~ Constructors ===========================================================
     //~ Constructors ===========================================================
 
 
-    public AuthenticationEvent(Authentication authentication, User user) {
+    public AuthenticationEvent(Authentication authentication, UserDetails user) {
         super(authentication);
         super(authentication);
 
 
         // No need to check authentication isn't null, as done by super
         // No need to check authentication isn't null, as done by super
@@ -77,7 +78,7 @@ public abstract class AuthenticationEvent extends ApplicationEvent {
      *
      *
      * @return the user
      * @return the user
      */
      */
-    public User getUser() {
+    public UserDetails getUser() {
         return user;
         return user;
     }
     }
 }
 }

+ 2 - 2
core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailureDisabledEvent.java

@@ -16,7 +16,7 @@
 package net.sf.acegisecurity.providers.dao.event;
 package net.sf.acegisecurity.providers.dao.event;
 
 
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.Authentication;
-import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 
 
 /**
 /**
@@ -30,7 +30,7 @@ public class AuthenticationFailureDisabledEvent extends AuthenticationEvent {
     //~ Constructors ===========================================================
     //~ Constructors ===========================================================
 
 
     public AuthenticationFailureDisabledEvent(Authentication authentication,
     public AuthenticationFailureDisabledEvent(Authentication authentication,
-        User user) {
+        UserDetails user) {
         super(authentication, user);
         super(authentication, user);
     }
     }
 }
 }

+ 2 - 2
core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationFailurePasswordEvent.java

@@ -16,7 +16,7 @@
 package net.sf.acegisecurity.providers.dao.event;
 package net.sf.acegisecurity.providers.dao.event;
 
 
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.Authentication;
-import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 
 
 /**
 /**
@@ -30,7 +30,7 @@ public class AuthenticationFailurePasswordEvent extends AuthenticationEvent {
     //~ Constructors ===========================================================
     //~ Constructors ===========================================================
 
 
     public AuthenticationFailurePasswordEvent(Authentication authentication,
     public AuthenticationFailurePasswordEvent(Authentication authentication,
-        User user) {
+        UserDetails user) {
         super(authentication, user);
         super(authentication, user);
     }
     }
 }
 }

+ 3 - 2
core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationSuccessEvent.java

@@ -16,7 +16,7 @@
 package net.sf.acegisecurity.providers.dao.event;
 package net.sf.acegisecurity.providers.dao.event;
 
 
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.Authentication;
-import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 
 
 /**
 /**
@@ -28,7 +28,8 @@ import net.sf.acegisecurity.providers.dao.User;
 public class AuthenticationSuccessEvent extends AuthenticationEvent {
 public class AuthenticationSuccessEvent extends AuthenticationEvent {
     //~ Constructors ===========================================================
     //~ Constructors ===========================================================
 
 
-    public AuthenticationSuccessEvent(Authentication authentication, User user) {
+    public AuthenticationSuccessEvent(Authentication authentication,
+        UserDetails user) {
         super(authentication, user);
         super(authentication, user);
     }
     }
 }
 }

+ 2 - 1
core/src/main/java/org/acegisecurity/providers/dao/salt/ReflectionSaltSource.java

@@ -18,6 +18,7 @@ package net.sf.acegisecurity.providers.dao.salt;
 import net.sf.acegisecurity.AuthenticationServiceException;
 import net.sf.acegisecurity.AuthenticationServiceException;
 import net.sf.acegisecurity.providers.dao.SaltSource;
 import net.sf.acegisecurity.providers.dao.SaltSource;
 import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.InitializingBean;
 
 
@@ -60,7 +61,7 @@ public class ReflectionSaltSource implements SaltSource, InitializingBean {
      *
      *
      * @throws AuthenticationServiceException if reflection fails
      * @throws AuthenticationServiceException if reflection fails
      */
      */
-    public Object getSalt(User user) {
+    public Object getSalt(UserDetails user) {
         try {
         try {
             Method reflectionMethod = user.getClass().getMethod(this.userPropertyToUse,
             Method reflectionMethod = user.getClass().getMethod(this.userPropertyToUse,
                     null);
                     null);

+ 2 - 1
core/src/main/java/org/acegisecurity/providers/dao/salt/SystemWideSaltSource.java

@@ -17,6 +17,7 @@ package net.sf.acegisecurity.providers.dao.salt;
 
 
 import net.sf.acegisecurity.providers.dao.SaltSource;
 import net.sf.acegisecurity.providers.dao.SaltSource;
 import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.InitializingBean;
 
 
@@ -41,7 +42,7 @@ public class SystemWideSaltSource implements SaltSource, InitializingBean {
 
 
     //~ Methods ================================================================
     //~ Methods ================================================================
 
 
-    public Object getSalt(User user) {
+    public Object getSalt(UserDetails user) {
         return this.systemWideSalt;
         return this.systemWideSalt;
     }
     }
 
 

+ 12 - 4
core/src/main/java/org/acegisecurity/userdetails/User.java

@@ -17,16 +17,20 @@ package net.sf.acegisecurity.providers.dao;
 
 
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthority;
 
 
-import java.io.Serializable;
-
 
 
 /**
 /**
  * Models core user information retieved by an {@link AuthenticationDao}.
  * Models core user information retieved by an {@link AuthenticationDao}.
+ * 
+ * <P>
+ * Implemented with value object semantics (immutable after construction, like
+ * a <code>String</code>). Developers may use this class directly, subclass
+ * it, or write their own {@link UserDetails} implementation from scratch.
+ * </p>
  *
  *
  * @author Ben Alex
  * @author Ben Alex
  * @version $Id$
  * @version $Id$
  */
  */
-public class User implements Serializable {
+public class User implements UserDetails {
     //~ Instance fields ========================================================
     //~ Instance fields ========================================================
 
 
     private String password;
     private String password;
@@ -37,7 +41,7 @@ public class User implements Serializable {
     //~ Constructors ===========================================================
     //~ Constructors ===========================================================
 
 
     /**
     /**
-     * Construct the <code>User</code> with the details required by  {@link
+     * Construct the <code>User</code> with the details required by {@link
      * DaoAuthenticationProvider}.
      * DaoAuthenticationProvider}.
      *
      *
      * @param username the username presented to the
      * @param username the username presented to the
@@ -96,4 +100,8 @@ public class User implements Serializable {
     public String getUsername() {
     public String getUsername() {
         return username;
         return username;
     }
     }
+
+    public String toString() {
+        return username;
+    }
 }
 }

+ 3 - 3
core/src/main/java/org/acegisecurity/userdetails/UserDetailsService.java

@@ -37,8 +37,8 @@ public interface AuthenticationDao {
      * Locates the user based on the username. In the actual implementation,
      * Locates the user based on the username. In the actual implementation,
      * the search may possibly be case insensitive, or case insensitive
      * the search may possibly be case insensitive, or case insensitive
      * depending on how the implementaion instance is configured. In this
      * depending on how the implementaion instance is configured. In this
-     * case, the User object that comes back may have a username that is of a
-     * different case than what was actually requested..
+     * case, the <code>UserDetails</code> object that comes back may have a
+     * username that is of a different case than what was actually requested..
      *
      *
      * @param username the username presented to the {@link
      * @param username the username presented to the {@link
      *        DaoAuthenticationProvider}
      *        DaoAuthenticationProvider}
@@ -50,6 +50,6 @@ public interface AuthenticationDao {
      * @throws DataAccessException if user could not be found for a
      * @throws DataAccessException if user could not be found for a
      *         repository-specific reason
      *         repository-specific reason
      */
      */
-    public User loadUserByUsername(String username)
+    public UserDetails loadUserByUsername(String username)
         throws UsernameNotFoundException, DataAccessException;
         throws UsernameNotFoundException, DataAccessException;
 }
 }

+ 4 - 3
core/src/main/java/org/acegisecurity/userdetails/jdbc/JdbcDaoImpl.java

@@ -19,6 +19,7 @@ import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.providers.dao.AuthenticationDao;
 import net.sf.acegisecurity.providers.dao.AuthenticationDao;
 import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.Log;
@@ -161,7 +162,7 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
         return usersByUsernameQuery;
         return usersByUsernameQuery;
     }
     }
 
 
-    public User loadUserByUsername(String username)
+    public UserDetails loadUserByUsername(String username)
         throws UsernameNotFoundException, DataAccessException {
         throws UsernameNotFoundException, DataAccessException {
         List users = usersByUsernameMapping.execute(username);
         List users = usersByUsernameMapping.execute(username);
 
 
@@ -169,7 +170,7 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
             throw new UsernameNotFoundException("User not found");
             throw new UsernameNotFoundException("User not found");
         }
         }
 
 
-        User user = (User) users.get(0); // contains no GrantedAuthority[]
+        UserDetails user = (UserDetails) users.get(0); // contains no GrantedAuthority[]
 
 
         List dbAuths = authoritiesByUsernameMapping.execute(user.getUsername());
         List dbAuths = authoritiesByUsernameMapping.execute(user.getUsername());
 
 
@@ -234,7 +235,7 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
             String username = rs.getString(1);
             String username = rs.getString(1);
             String password = rs.getString(2);
             String password = rs.getString(2);
             boolean enabled = rs.getBoolean(3);
             boolean enabled = rs.getBoolean(3);
-            User user = new User(username, password, enabled,
+            UserDetails user = new User(username, password, enabled,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
                     new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
 
 
             return user;
             return user;

+ 2 - 2
core/src/main/java/org/acegisecurity/userdetails/memory/InMemoryDaoImpl.java

@@ -16,7 +16,7 @@
 package net.sf.acegisecurity.providers.dao.memory;
 package net.sf.acegisecurity.providers.dao.memory;
 
 
 import net.sf.acegisecurity.providers.dao.AuthenticationDao;
 import net.sf.acegisecurity.providers.dao.AuthenticationDao;
-import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 
 
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.InitializingBean;
@@ -52,7 +52,7 @@ public class InMemoryDaoImpl implements AuthenticationDao, InitializingBean {
         }
         }
     }
     }
 
 
-    public User loadUserByUsername(String username)
+    public UserDetails loadUserByUsername(String username)
         throws UsernameNotFoundException, DataAccessException {
         throws UsernameNotFoundException, DataAccessException {
         return userMap.getUser(username);
         return userMap.getUser(username);
     }
     }

+ 2 - 1
core/src/main/java/org/acegisecurity/userdetails/memory/UserMap.java

@@ -16,6 +16,7 @@
 package net.sf.acegisecurity.providers.dao.memory;
 package net.sf.acegisecurity.providers.dao.memory;
 
 
 import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.Log;
@@ -80,7 +81,7 @@ public class UserMap {
      *
      *
      * @throws IllegalArgumentException if a null User was passed
      * @throws IllegalArgumentException if a null User was passed
      */
      */
-    public void addUser(User user) throws IllegalArgumentException {
+    public void addUser(UserDetails user) throws IllegalArgumentException {
         if (user == null) {
         if (user == null) {
             throw new IllegalArgumentException("Must be a valid User");
             throw new IllegalArgumentException("Must be a valid User");
         }
         }

+ 2 - 1
core/src/main/java/org/acegisecurity/userdetails/memory/UserMapEditor.java

@@ -16,6 +16,7 @@
 package net.sf.acegisecurity.providers.dao.memory;
 package net.sf.acegisecurity.providers.dao.memory;
 
 
 import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 import org.springframework.beans.propertyeditors.PropertiesEditor;
 import org.springframework.beans.propertyeditors.PropertiesEditor;
 
 
@@ -89,7 +90,7 @@ public class UserMapEditor extends PropertyEditorSupport {
 
 
                 // Make a user object, assuming the properties were properly provided
                 // Make a user object, assuming the properties were properly provided
                 if (attr != null) {
                 if (attr != null) {
-                    User user = new User(username, attr.getPassword(),
+                    UserDetails user = new User(username, attr.getPassword(),
                             attr.isEnabled(), attr.getAuthorities());
                             attr.isEnabled(), attr.getAuthorities());
                     userMap.addUser(user);
                     userMap.addUser(user);
                 }
                 }

+ 3 - 2
core/src/test/java/org/acegisecurity/providers/cas/populator/DaoCasAuthoritiesPopulatorTests.java

@@ -21,6 +21,7 @@ import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.providers.dao.AuthenticationDao;
 import net.sf.acegisecurity.providers.dao.AuthenticationDao;
 import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 
 
 import org.springframework.dao.DataAccessException;
 import org.springframework.dao.DataAccessException;
@@ -121,7 +122,7 @@ public class DaoCasAuthoritiesPopulatorTests extends TestCase {
             return 0;
             return 0;
         }
         }
 
 
-        public User loadUserByUsername(String username)
+        public UserDetails loadUserByUsername(String username)
             throws UsernameNotFoundException, DataAccessException {
             throws UsernameNotFoundException, DataAccessException {
             throw new DataRetrievalFailureException(
             throw new DataRetrievalFailureException(
                 "This mock simulator is designed to fail");
                 "This mock simulator is designed to fail");
@@ -133,7 +134,7 @@ public class DaoCasAuthoritiesPopulatorTests extends TestCase {
             return 0;
             return 0;
         }
         }
 
 
-        public User loadUserByUsername(String username)
+        public UserDetails loadUserByUsername(String username)
             throws UsernameNotFoundException, DataAccessException {
             throws UsernameNotFoundException, DataAccessException {
             if ("marissa".equals(username)) {
             if ("marissa".equals(username)) {
                 return new User("marissa", "koala", true,
                 return new User("marissa", "koala", true,

+ 6 - 6
core/src/test/java/org/acegisecurity/providers/dao/DaoAuthenticationProviderTests.java

@@ -261,7 +261,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
 
 
     private class MockAuthenticationDaoSimulateBackendError
     private class MockAuthenticationDaoSimulateBackendError
         implements AuthenticationDao {
         implements AuthenticationDao {
-        public User loadUserByUsername(String username)
+        public UserDetails loadUserByUsername(String username)
             throws UsernameNotFoundException, DataAccessException {
             throws UsernameNotFoundException, DataAccessException {
             throw new DataRetrievalFailureException(
             throw new DataRetrievalFailureException(
                 "This mock simulator is designed to fail");
                 "This mock simulator is designed to fail");
@@ -269,7 +269,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
     }
     }
 
 
     private class MockAuthenticationDaoUserMarissa implements AuthenticationDao {
     private class MockAuthenticationDaoUserMarissa implements AuthenticationDao {
-        public User loadUserByUsername(String username)
+        public UserDetails loadUserByUsername(String username)
             throws UsernameNotFoundException, DataAccessException {
             throws UsernameNotFoundException, DataAccessException {
             if ("marissa".equals(username)) {
             if ("marissa".equals(username)) {
                 return new User("marissa", "koala", true,
                 return new User("marissa", "koala", true,
@@ -284,7 +284,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
 
 
     private class MockAuthenticationDaoUserMarissaWithSalt
     private class MockAuthenticationDaoUserMarissaWithSalt
         implements AuthenticationDao {
         implements AuthenticationDao {
-        public User loadUserByUsername(String username)
+        public UserDetails loadUserByUsername(String username)
             throws UsernameNotFoundException, DataAccessException {
             throws UsernameNotFoundException, DataAccessException {
             if ("marissa".equals(username)) {
             if ("marissa".equals(username)) {
                 return new User("marissa", "koala{SYSTEM_SALT_VALUE}", true,
                 return new User("marissa", "koala{SYSTEM_SALT_VALUE}", true,
@@ -298,7 +298,7 @@ public class DaoAuthenticationProviderTests extends TestCase {
     }
     }
 
 
     private class MockAuthenticationDaoUserPeter implements AuthenticationDao {
     private class MockAuthenticationDaoUserPeter implements AuthenticationDao {
-        public User loadUserByUsername(String username)
+        public UserDetails loadUserByUsername(String username)
             throws UsernameNotFoundException, DataAccessException {
             throws UsernameNotFoundException, DataAccessException {
             if ("peter".equals(username)) {
             if ("peter".equals(username)) {
                 return new User("peter", "opal", false,
                 return new User("peter", "opal", false,
@@ -314,11 +314,11 @@ public class DaoAuthenticationProviderTests extends TestCase {
     private class MockUserCache implements UserCache {
     private class MockUserCache implements UserCache {
         private Map cache = new HashMap();
         private Map cache = new HashMap();
 
 
-        public User getUserFromCache(String username) {
+        public UserDetails getUserFromCache(String username) {
             return (User) cache.get(username);
             return (User) cache.get(username);
         }
         }
 
 
-        public void putUserInCache(User user) {
+        public void putUserInCache(UserDetails user) {
             cache.put(user.getUsername(), user);
             cache.put(user.getUsername(), user);
         }
         }
     }
     }

+ 7 - 7
core/src/test/java/org/acegisecurity/providers/dao/UserTests.java

@@ -59,7 +59,7 @@ public class UserTests extends TestCase {
 
 
     public void testNullValuesRejected() throws Exception {
     public void testNullValuesRejected() throws Exception {
         try {
         try {
-            User user = new User(null, "koala", true,
+            UserDetails user = new User(null, "koala", true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
                             "ROLE_TWO")});
             fail("Should have thrown IllegalArgumentException");
             fail("Should have thrown IllegalArgumentException");
@@ -68,7 +68,7 @@ public class UserTests extends TestCase {
         }
         }
 
 
         try {
         try {
-            User user = new User("marissa", null, true,
+            UserDetails user = new User("marissa", null, true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO")});
                             "ROLE_TWO")});
             fail("Should have thrown IllegalArgumentException");
             fail("Should have thrown IllegalArgumentException");
@@ -77,14 +77,14 @@ public class UserTests extends TestCase {
         }
         }
 
 
         try {
         try {
-            User user = new User("marissa", "koala", true, null);
+            UserDetails user = new User("marissa", "koala", true, null);
             fail("Should have thrown IllegalArgumentException");
             fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException expected) {
         } catch (IllegalArgumentException expected) {
             assertTrue(true);
             assertTrue(true);
         }
         }
 
 
         try {
         try {
-            User user = new User("marissa", "koala", true,
+            UserDetails user = new User("marissa", "koala", true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), null});
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), null});
             fail("Should have thrown IllegalArgumentException");
             fail("Should have thrown IllegalArgumentException");
         } catch (IllegalArgumentException expected) {
         } catch (IllegalArgumentException expected) {
@@ -95,7 +95,7 @@ public class UserTests extends TestCase {
     public void testNullWithinGrantedAuthorityElementIsRejected()
     public void testNullWithinGrantedAuthorityElementIsRejected()
         throws Exception {
         throws Exception {
         try {
         try {
-            User user = new User(null, "koala", true,
+            UserDetails user = new User(null, "koala", true,
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                     new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                             "ROLE_TWO"), null, new GrantedAuthorityImpl(
                             "ROLE_TWO"), null, new GrantedAuthorityImpl(
                             "ROLE_THREE")});
                             "ROLE_THREE")});
@@ -106,7 +106,7 @@ public class UserTests extends TestCase {
     }
     }
 
 
     public void testUserGettersSetter() throws Exception {
     public void testUserGettersSetter() throws Exception {
-        User user = new User("marissa", "koala", true,
+        UserDetails user = new User("marissa", "koala", true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_TWO")});
                         "ROLE_TWO")});
         assertEquals("marissa", user.getUsername());
         assertEquals("marissa", user.getUsername());
@@ -119,7 +119,7 @@ public class UserTests extends TestCase {
     }
     }
 
 
     public void testUserIsEnabled() throws Exception {
     public void testUserIsEnabled() throws Exception {
-        User user = new User("marissa", "koala", false,
+        UserDetails user = new User("marissa", "koala", false,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_TWO")});
                         "ROLE_TWO")});
         assertTrue(!user.isEnabled());
         assertTrue(!user.isEnabled());

+ 5 - 5
core/src/test/java/org/acegisecurity/providers/dao/jdbc/JdbcDaoTests.java

@@ -17,7 +17,7 @@ package net.sf.acegisecurity.providers.dao.jdbc;
 
 
 import junit.framework.TestCase;
 import junit.framework.TestCase;
 
 
-import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 
 
 import org.springframework.jdbc.datasource.DriverManagerDataSource;
 import org.springframework.jdbc.datasource.DriverManagerDataSource;
@@ -56,7 +56,7 @@ public class JdbcDaoTests extends TestCase {
 
 
     public void testCheckDaoAccessUserSuccess() throws Exception {
     public void testCheckDaoAccessUserSuccess() throws Exception {
         JdbcDaoImpl dao = makePopulatedJdbcDao();
         JdbcDaoImpl dao = makePopulatedJdbcDao();
-        User user = dao.loadUserByUsername("marissa");
+        UserDetails user = dao.loadUserByUsername("marissa");
         assertEquals("marissa", user.getUsername());
         assertEquals("marissa", user.getUsername());
         assertEquals("koala", user.getPassword());
         assertEquals("koala", user.getPassword());
         assertTrue(user.isEnabled());
         assertTrue(user.isEnabled());
@@ -68,7 +68,7 @@ public class JdbcDaoTests extends TestCase {
     public void testCheckDaoOnlyReturnsGrantedAuthoritiesGrantedToUser()
     public void testCheckDaoOnlyReturnsGrantedAuthoritiesGrantedToUser()
         throws Exception {
         throws Exception {
         JdbcDaoImpl dao = makePopulatedJdbcDao();
         JdbcDaoImpl dao = makePopulatedJdbcDao();
-        User user = dao.loadUserByUsername("scott");
+        UserDetails user = dao.loadUserByUsername("scott");
         assertEquals("ROLE_TELLER", user.getAuthorities()[0].getAuthority());
         assertEquals("ROLE_TELLER", user.getAuthorities()[0].getAuthority());
         assertEquals(1, user.getAuthorities().length);
         assertEquals(1, user.getAuthorities().length);
     }
     }
@@ -76,7 +76,7 @@ public class JdbcDaoTests extends TestCase {
     public void testCheckDaoReturnsCorrectDisabledProperty()
     public void testCheckDaoReturnsCorrectDisabledProperty()
         throws Exception {
         throws Exception {
         JdbcDaoImpl dao = makePopulatedJdbcDao();
         JdbcDaoImpl dao = makePopulatedJdbcDao();
-        User user = dao.loadUserByUsername("peter");
+        UserDetails user = dao.loadUserByUsername("peter");
         assertTrue(!user.isEnabled());
         assertTrue(!user.isEnabled());
     }
     }
 
 
@@ -128,7 +128,7 @@ public class JdbcDaoTests extends TestCase {
         JdbcDaoImpl dao = makePopulatedJdbcDaoWithRolePrefix();
         JdbcDaoImpl dao = makePopulatedJdbcDaoWithRolePrefix();
         assertEquals("ARBITRARY_PREFIX_", dao.getRolePrefix());
         assertEquals("ARBITRARY_PREFIX_", dao.getRolePrefix());
 
 
-        User user = dao.loadUserByUsername("marissa");
+        UserDetails user = dao.loadUserByUsername("marissa");
         assertEquals("marissa", user.getUsername());
         assertEquals("marissa", user.getUsername());
         assertEquals("ARBITRARY_PREFIX_ROLE_TELLER",
         assertEquals("ARBITRARY_PREFIX_ROLE_TELLER",
             user.getAuthorities()[0].getAuthority());
             user.getAuthorities()[0].getAuthority());

+ 5 - 4
core/src/test/java/org/acegisecurity/providers/dao/memory/UserMapTests.java

@@ -20,6 +20,7 @@ import junit.framework.TestCase;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
 
 
 
 
@@ -51,13 +52,13 @@ public class UserMapTests extends TestCase {
     }
     }
 
 
     public void testAddAndRetrieveUser() {
     public void testAddAndRetrieveUser() {
-        User marissa = new User("marissa", "koala", true,
+        UserDetails marissa = new User("marissa", "koala", true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_TWO")});
                         "ROLE_TWO")});
-        User scott = new User("scott", "wombat", true,
+        UserDetails scott = new User("scott", "wombat", true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_THREE")});
                         "ROLE_THREE")});
-        User peter = new User("peter", "opal", true,
+        UserDetails peter = new User("peter", "opal", true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_FOUR")});
                         "ROLE_FOUR")});
         UserMap map = new UserMap();
         UserMap map = new UserMap();
@@ -84,7 +85,7 @@ public class UserMapTests extends TestCase {
     }
     }
 
 
     public void testUnknownUserIsNotRetrieved() {
     public void testUnknownUserIsNotRetrieved() {
-        User marissa = new User("marissa", "koala", true,
+        UserDetails marissa = new User("marissa", "koala", true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
                         "ROLE_TWO")});
                         "ROLE_TWO")});
         UserMap map = new UserMap();
         UserMap map = new UserMap();

+ 3 - 2
core/src/test/java/org/acegisecurity/providers/dao/salt/ReflectionSaltSourceTests.java

@@ -21,6 +21,7 @@ import net.sf.acegisecurity.AuthenticationServiceException;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.GrantedAuthorityImpl;
 import net.sf.acegisecurity.providers.dao.User;
 import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 
 
 /**
 /**
@@ -66,7 +67,7 @@ public class ReflectionSaltSourceTests extends TestCase {
         ReflectionSaltSource saltSource = new ReflectionSaltSource();
         ReflectionSaltSource saltSource = new ReflectionSaltSource();
         saltSource.setUserPropertyToUse("getDoesNotExist");
         saltSource.setUserPropertyToUse("getDoesNotExist");
 
 
-        User user = new User("scott", "wombat", true,
+        UserDetails user = new User("scott", "wombat", true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
                 new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
 
 
         try {
         try {
@@ -88,7 +89,7 @@ public class ReflectionSaltSourceTests extends TestCase {
         saltSource.setUserPropertyToUse("getUsername");
         saltSource.setUserPropertyToUse("getUsername");
         saltSource.afterPropertiesSet();
         saltSource.afterPropertiesSet();
 
 
-        User user = new User("scott", "wombat", true,
+        UserDetails user = new User("scott", "wombat", true,
                 new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
                 new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
         assertEquals("scott", saltSource.getSalt(user));
         assertEquals("scott", saltSource.getSalt(user));
     }
     }

+ 5 - 5
core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java

@@ -24,7 +24,7 @@ import net.sf.acegisecurity.MockFilterConfig;
 import net.sf.acegisecurity.MockHttpServletRequest;
 import net.sf.acegisecurity.MockHttpServletRequest;
 import net.sf.acegisecurity.MockHttpServletResponse;
 import net.sf.acegisecurity.MockHttpServletResponse;
 import net.sf.acegisecurity.MockHttpSession;
 import net.sf.acegisecurity.MockHttpSession;
-import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 import net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter;
 import net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter;
 
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.codec.binary.Base64;
@@ -200,8 +200,8 @@ public class BasicProcessingFilterTests extends TestCase {
 
 
         assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null);
         assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null);
         assertEquals("marissa",
         assertEquals("marissa",
-            ((User) ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal())
-             .getUsername());
+            ((UserDetails) ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY))
+            .getPrincipal()).getUsername());
     }
     }
 
 
     public void testOtherAuthorizationSchemeIsIgnored()
     public void testOtherAuthorizationSchemeIsIgnored()
@@ -292,8 +292,8 @@ public class BasicProcessingFilterTests extends TestCase {
 
 
         assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null);
         assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null);
         assertEquals("marissa",
         assertEquals("marissa",
-                ((User) ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY)).getPrincipal())
-                 .getUsername());
+            ((UserDetails) ((Authentication) request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY))
+            .getPrincipal()).getUsername());
 
 
         // NOW PERFORM FAILED AUTHENTICATION
         // NOW PERFORM FAILED AUTHENTICATION
         // Setup our HTTP request
         // Setup our HTTP request

+ 35 - 25
docs/reference/src/index.xml

@@ -901,15 +901,16 @@
         <literal>SaltSource</literal> implementations are also provided:
         <literal>SaltSource</literal> implementations are also provided:
         <literal>SystemWideSaltSource</literal> which encodes all passwords
         <literal>SystemWideSaltSource</literal> which encodes all passwords
         with the same salt, and <literal>ReflectionSaltSource</literal>, which
         with the same salt, and <literal>ReflectionSaltSource</literal>, which
-        inspects a given property of the returned <literal>User</literal>
-        object to obtain the salt. Please refer to the JavaDocs for further
-        details on these optional features.</para>
+        inspects a given property of the returned
+        <literal>UserDetails</literal> object to obtain the salt. Please refer
+        to the JavaDocs for further details on these optional features.</para>
 
 
         <para>In addition to the properties above, the
         <para>In addition to the properties above, the
         <literal>DaoAuthenticationProvider</literal> supports optional caching
         <literal>DaoAuthenticationProvider</literal> supports optional caching
-        of <literal>User</literal> objects. The <literal>UserCache</literal>
-        interface enables the <literal>DaoAuthenticationProvider</literal> to
-        place a <literal>User</literal> object into the cache, and retrieve it
+        of <literal>UserDetails</literal> objects. The
+        <literal>UserCache</literal> interface enables the
+        <literal>DaoAuthenticationProvider</literal> to place a
+        <literal>UserDetails</literal> object into the cache, and retrieve it
         from the cache upon subsequent authentication attempts for the same
         from the cache upon subsequent authentication attempts for the same
         username. By default the <literal>DaoAuthenticationProvider</literal>
         username. By default the <literal>DaoAuthenticationProvider</literal>
         uses the <literal>NullUserCache</literal>, which performs no caching.
         uses the <literal>NullUserCache</literal>, which performs no caching.
@@ -931,11 +932,19 @@
         authentication repository, it must implement the
         authentication repository, it must implement the
         <literal>AuthenticationDao</literal> interface:</para>
         <literal>AuthenticationDao</literal> interface:</para>
 
 
-        <para><programlisting>public User loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException;</programlisting></para>
+        <para><programlisting>public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException;</programlisting></para>
 
 
-        <para>The <literal>User</literal> object holds basic information such
-        as the username, password, granted authorities and whether the user is
-        enabled or disabled.</para>
+        <para>The <literal>UserDetails</literal> is an interface that provides
+        getters that guarantee non-null provision of basic authentication
+        information such as the username, password, granted authorities and
+        whether the user is enabled or disabled. A concrete implementation,
+        <literal>User</literal>, is also provided. Acegi Security users will
+        need to decide when writing their <literal>AuthenticationDao</literal>
+        what type of <literal>UserDetails</literal> to return. In most cases
+        <literal>User</literal> will be used directly or subclassed, although
+        special circumstances (such as object relational mappers) may require
+        users to write their own <literal>UserDetails</literal> implementation
+        from scratch.</para>
 
 
         <para>Given <literal>AuthenticationDao</literal> is so simple to
         <para>Given <literal>AuthenticationDao</literal> is so simple to
         implement, it should be easy for users to retrieve authentication
         implement, it should be easy for users to retrieve authentication
@@ -953,14 +962,14 @@
         <literal>Authentication</literal> object which in turn has its
         <literal>Authentication</literal> object which in turn has its
         <literal>principal</literal> property set. The principal will be
         <literal>principal</literal> property set. The principal will be
         either a <literal>String</literal> (which is essentially the username)
         either a <literal>String</literal> (which is essentially the username)
-        or a <literal>User</literal> object (which was looked up from the
-        <literal>AuthenticationDao</literal>). By default the
-        <literal>User</literal> is returned, as this enables applications to
-        subclass <literal>User</literal> and add extra properties potentially
-        of use in applications, such as the user's full name, email address
-        etc. If using container adapters, or if your applications were written
-        to operate with <literal>String</literal>s (as was the case for
-        releases prior to Acegi Security 0.6), you should set the
+        or a <literal>UserDetails</literal> object (which was looked up from
+        the <literal>AuthenticationDao</literal>). By default the
+        <literal>UserDetails</literal> is returned, as this enables
+        applications to add extra properties potentially of use in
+        applications, such as the user's full name, email address etc. If
+        using container adapters, or if your applications were written to
+        operate with <literal>String</literal>s (as was the case for releases
+        prior to Acegi Security 0.6), you should set the
         <literal>DaoAuthenticationProvider.forcePrincipalAsString</literal>
         <literal>DaoAuthenticationProvider.forcePrincipalAsString</literal>
         property to <literal>true</literal> in your application
         property to <literal>true</literal> in your application
         context.</para>
         context.</para>
@@ -998,8 +1007,8 @@
 
 
         <para>Each event contains two objects: the
         <para>Each event contains two objects: the
         <literal>Authentication</literal> object that represented the
         <literal>Authentication</literal> object that represented the
-        authentication request, and the <literal>User</literal> object that
-        was found in response to the authentication request. The
+        authentication request, and the <literal>UserDetails</literal> object
+        that was found in response to the authentication request. The
         <literal>Authentication</literal> interface provides a
         <literal>Authentication</literal> interface provides a
         <literal>getDetails()</literal> method which often includes
         <literal>getDetails()</literal> method which often includes
         information that event consumers may find useful (eg the TCP/IP
         information that event consumers may find useful (eg the TCP/IP
@@ -2455,11 +2464,12 @@ $CATALINA_HOME/bin/startup.sh</programlisting></para>
             contained in the <literal>TicketResponse</literal>. Acegi Security
             contained in the <literal>TicketResponse</literal>. Acegi Security
             includes a <literal>DaoCasAuthoritiesPopulator</literal> which
             includes a <literal>DaoCasAuthoritiesPopulator</literal> which
             simply uses the <literal>AuthenticationDao</literal>
             simply uses the <literal>AuthenticationDao</literal>
-            infrastructure to find the <literal>User</literal> and their
-            associated <literal>GrantedAuthority</literal>s. Note that the
-            password and enabled/disabled status of <literal>User</literal>s
-            returned by the <literal>AuthenticationDao</literal> are ignored,
-            as the CAS server is responsible for authentication decisions.
+            infrastructure to find the <literal>UserDetails</literal> and
+            their associated <literal>GrantedAuthority</literal>s. Note that
+            the password and enabled/disabled status of
+            <literal>UserDetails</literal> returned by the
+            <literal>AuthenticationDao</literal> are ignored, as the CAS
+            server is responsible for authentication decisions.
             <literal>DaoCasAuthoritiesPopulator</literal> is only concerned
             <literal>DaoCasAuthoritiesPopulator</literal> is only concerned
             with retrieving the <literal>GrantedAuthority</literal>s.</para>
             with retrieving the <literal>GrantedAuthority</literal>s.</para>
           </listitem>
           </listitem>

+ 3 - 3
samples/contacts/src/main/java/sample/contact/ContactManagerFacade.java

@@ -19,7 +19,7 @@ import net.sf.acegisecurity.AccessDeniedException;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.SecureContext;
 import net.sf.acegisecurity.context.SecureContext;
-import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.InitializingBean;
 
 
@@ -91,8 +91,8 @@ public class ContactManagerFacade implements ContactManager, InitializingBean {
 
 
         String username = auth.getPrincipal().toString();
         String username = auth.getPrincipal().toString();
 
 
-        if (auth.getPrincipal() instanceof User) {
-            username = ((User) auth.getPrincipal()).getUsername();
+        if (auth.getPrincipal() instanceof UserDetails) {
+            username = ((UserDetails) auth.getPrincipal()).getUsername();
         }
         }
 
 
         if (username.equals(result.getOwner())) {
         if (username.equals(result.getOwner())) {

+ 3 - 3
samples/contacts/src/main/java/sample/contact/ContactSecurityVoter.java

@@ -18,7 +18,7 @@ package sample.contact;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.ConfigAttribute;
 import net.sf.acegisecurity.ConfigAttribute;
 import net.sf.acegisecurity.ConfigAttributeDefinition;
 import net.sf.acegisecurity.ConfigAttributeDefinition;
-import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 import net.sf.acegisecurity.vote.AccessDecisionVoter;
 import net.sf.acegisecurity.vote.AccessDecisionVoter;
 
 
 import org.aopalliance.intercept.MethodInvocation;
 import org.aopalliance.intercept.MethodInvocation;
@@ -99,8 +99,8 @@ public class ContactSecurityVoter implements AccessDecisionVoter {
                 if (passedOwner != null) {
                 if (passedOwner != null) {
                     String username = authentication.getPrincipal().toString();
                     String username = authentication.getPrincipal().toString();
 
 
-                    if (authentication.getPrincipal() instanceof User) {
-                        username = ((User) authentication.getPrincipal())
+                    if (authentication.getPrincipal() instanceof UserDetails) {
+                        username = ((UserDetails) authentication.getPrincipal())
                             .getUsername();
                             .getUsername();
                     }
                     }
 
 

+ 3 - 3
samples/contacts/src/main/java/sample/contact/SecureIndexController.java

@@ -20,7 +20,7 @@ import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.GrantedAuthority;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.SecureContext;
 import net.sf.acegisecurity.context.SecureContext;
-import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.InitializingBean;
 
 
@@ -80,8 +80,8 @@ public class SecureIndexController implements Controller, InitializingBean {
         Authentication auth = secureContext.getAuthentication();
         Authentication auth = secureContext.getAuthentication();
         String username = auth.getPrincipal().toString();
         String username = auth.getPrincipal().toString();
 
 
-        if (auth.getPrincipal() instanceof User) {
-            username = ((User) auth.getPrincipal()).getUsername();
+        if (auth.getPrincipal() instanceof UserDetails) {
+            username = ((UserDetails) auth.getPrincipal()).getUsername();
         }
         }
 
 
         boolean supervisor = false;
         boolean supervisor = false;

+ 3 - 3
samples/contacts/src/main/java/sample/contact/WebContactAddController.java

@@ -18,7 +18,7 @@ package sample.contact;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.Authentication;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.ContextHolder;
 import net.sf.acegisecurity.context.SecureContext;
 import net.sf.acegisecurity.context.SecureContext;
-import net.sf.acegisecurity.providers.dao.User;
+import net.sf.acegisecurity.providers.dao.UserDetails;
 
 
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.mvc.SimpleFormController;
 import org.springframework.web.servlet.mvc.SimpleFormController;
@@ -61,8 +61,8 @@ public class WebContactAddController extends SimpleFormController {
             .getAuthentication();
             .getAuthentication();
         String owner = auth.getPrincipal().toString();
         String owner = auth.getPrincipal().toString();
 
 
-        if (auth.getPrincipal() instanceof User) {
-            owner = ((User) auth.getPrincipal()).getUsername();
+        if (auth.getPrincipal() instanceof UserDetails) {
+            owner = ((UserDetails) auth.getPrincipal()).getUsername();
         }
         }
 
 
         Contact contact = new Contact(contactManager.getNextId(), name, email,
         Contact contact = new Contact(contactManager.getNextId(), name, email,

+ 20 - 0
upgrade-05-06.txt

@@ -23,5 +23,25 @@ applications:
       username = ((User) authentication.getPrincipal()).getUsername();
       username = ((User) authentication.getPrincipal()).getUsername();
     }
     }
 
 
+- The signature of AuthenticationDaos have changed. In concrete
+  implementations, modify the User to UserDetails, as shown below:
+
+    public User loadUserByUsername(String username)
+        throws UsernameNotFoundException, DataAccessException {
+
+    to:
+  
+    public UserDetails loadUserByUsername(String username)
+        throws UsernameNotFoundException, DataAccessException {
+
+  Existing concrete implementations would be returning User, which implements
+  UserDetails, so no further code changes should be required.
+
+- Similar signature changes (User -> UserDetails) are also required to any
+  custom implementations of UserCache and SaltSource.
+
+- Any custom event listeners relying on AuthenticationEvent should note a
+  UserDetails is now provided in the AuthenticationEvent (not a User).
+
 
 
 $Id$
 $Id$