Refactor User to an interface.

This commit is contained in:
Ben Alex 2004-06-24 23:24:14 +00:00
parent 123ad907d1
commit 6314aa4efa
32 changed files with 248 additions and 124 deletions

View File

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

View File

@ -52,21 +52,22 @@ import org.springframework.dao.DataAccessException;
* 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 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
* 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,
* 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>
* 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
* AuthenticationDao}. It should be noted that if a user appears to present an
* incorrect password, the {@link AuthenticationDao} will be queried to
@ -174,12 +175,13 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
// Determine username
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;
User user = this.userCache.getUserFromCache(username);
UserDetails user = this.userCache.getUserFromCache(username);
if (user == null) {
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;
if (this.saltSource != null) {
@ -255,7 +258,7 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
authentication.getCredentials().toString(), salt);
}
private User getUserFromBackend(String username) {
private UserDetails getUserFromBackend(String username) {
try {
return this.authenticationDao.loadUserByUsername(username);
} catch (UsernameNotFoundException notFound) {

View File

@ -29,7 +29,7 @@ public interface SaltSource {
*
* @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);
}

View File

@ -33,21 +33,22 @@ public interface UserCache {
//~ 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
* 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);
}

View File

@ -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();
}

View File

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

View File

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

View File

@ -17,6 +17,7 @@ package net.sf.acegisecurity.providers.dao.event;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.providers.dao.User;
import net.sf.acegisecurity.providers.dao.UserDetails;
import org.springframework.context.ApplicationEvent;
@ -44,11 +45,11 @@ import org.springframework.context.ApplicationEvent;
public abstract class AuthenticationEvent extends ApplicationEvent {
//~ Instance fields ========================================================
private User user;
private UserDetails user;
//~ Constructors ===========================================================
public AuthenticationEvent(Authentication authentication, User user) {
public AuthenticationEvent(Authentication authentication, UserDetails user) {
super(authentication);
// 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
*/
public User getUser() {
public UserDetails getUser() {
return user;
}
}

View File

@ -16,7 +16,7 @@
package net.sf.acegisecurity.providers.dao.event;
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 ===========================================================
public AuthenticationFailureDisabledEvent(Authentication authentication,
User user) {
UserDetails user) {
super(authentication, user);
}
}

View File

@ -16,7 +16,7 @@
package net.sf.acegisecurity.providers.dao.event;
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 ===========================================================
public AuthenticationFailurePasswordEvent(Authentication authentication,
User user) {
UserDetails user) {
super(authentication, user);
}
}

View File

@ -16,7 +16,7 @@
package net.sf.acegisecurity.providers.dao.event;
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 {
//~ Constructors ===========================================================
public AuthenticationSuccessEvent(Authentication authentication, User user) {
public AuthenticationSuccessEvent(Authentication authentication,
UserDetails user) {
super(authentication, user);
}
}

View File

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

View File

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

View File

@ -17,16 +17,20 @@ package net.sf.acegisecurity.providers.dao;
import net.sf.acegisecurity.GrantedAuthority;
import java.io.Serializable;
/**
* 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
* @version $Id$
*/
public class User implements Serializable {
public class User implements UserDetails {
//~ Instance fields ========================================================
private String password;
@ -37,7 +41,7 @@ public class User implements Serializable {
//~ Constructors ===========================================================
/**
* Construct the <code>User</code> with the details required by {@link
* Construct the <code>User</code> with the details required by {@link
* DaoAuthenticationProvider}.
*
* @param username the username presented to the
@ -96,4 +100,8 @@ public class User implements Serializable {
public String getUsername() {
return username;
}
public String toString() {
return username;
}
}

View File

@ -37,8 +37,8 @@ public interface AuthenticationDao {
* Locates the user based on the username. In the actual implementation,
* the search may possibly be case insensitive, or case insensitive
* 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
* DaoAuthenticationProvider}
@ -50,6 +50,6 @@ public interface AuthenticationDao {
* @throws DataAccessException if user could not be found for a
* repository-specific reason
*/
public User loadUserByUsername(String username)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException;
}

View File

@ -19,6 +19,7 @@ import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
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 org.apache.commons.logging.Log;
@ -161,7 +162,7 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
return usersByUsernameQuery;
}
public User loadUserByUsername(String username)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
List users = usersByUsernameMapping.execute(username);
@ -169,7 +170,7 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
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());
@ -234,7 +235,7 @@ public class JdbcDaoImpl extends JdbcDaoSupport implements AuthenticationDao {
String username = rs.getString(1);
String password = rs.getString(2);
boolean enabled = rs.getBoolean(3);
User user = new User(username, password, enabled,
UserDetails user = new User(username, password, enabled,
new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
return user;

View File

@ -16,7 +16,7 @@
package net.sf.acegisecurity.providers.dao.memory;
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 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 {
return userMap.getUser(username);
}

View File

@ -16,6 +16,7 @@
package net.sf.acegisecurity.providers.dao.memory;
import net.sf.acegisecurity.providers.dao.User;
import net.sf.acegisecurity.providers.dao.UserDetails;
import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
import org.apache.commons.logging.Log;
@ -80,7 +81,7 @@ public class UserMap {
*
* @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) {
throw new IllegalArgumentException("Must be a valid User");
}

View File

@ -16,6 +16,7 @@
package net.sf.acegisecurity.providers.dao.memory;
import net.sf.acegisecurity.providers.dao.User;
import net.sf.acegisecurity.providers.dao.UserDetails;
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
if (attr != null) {
User user = new User(username, attr.getPassword(),
UserDetails user = new User(username, attr.getPassword(),
attr.isEnabled(), attr.getAuthorities());
userMap.addUser(user);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,6 +21,7 @@ import net.sf.acegisecurity.AuthenticationServiceException;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.GrantedAuthorityImpl;
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();
saltSource.setUserPropertyToUse("getDoesNotExist");
User user = new User("scott", "wombat", true,
UserDetails user = new User("scott", "wombat", true,
new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
try {
@ -88,7 +89,7 @@ public class ReflectionSaltSourceTests extends TestCase {
saltSource.setUserPropertyToUse("getUsername");
saltSource.afterPropertiesSet();
User user = new User("scott", "wombat", true,
UserDetails user = new User("scott", "wombat", true,
new GrantedAuthority[] {new GrantedAuthorityImpl("HOLDER")});
assertEquals("scott", saltSource.getSalt(user));
}

View File

@ -24,7 +24,7 @@ import net.sf.acegisecurity.MockFilterConfig;
import net.sf.acegisecurity.MockHttpServletRequest;
import net.sf.acegisecurity.MockHttpServletResponse;
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 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);
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()
@ -292,8 +292,8 @@ public class BasicProcessingFilterTests extends TestCase {
assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) != null);
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
// Setup our HTTP request

View File

@ -901,15 +901,16 @@
<literal>SaltSource</literal> implementations are also provided:
<literal>SystemWideSaltSource</literal> which encodes all passwords
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
<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
username. By default the <literal>DaoAuthenticationProvider</literal>
uses the <literal>NullUserCache</literal>, which performs no caching.
@ -931,11 +932,19 @@
authentication repository, it must implement the
<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
implement, it should be easy for users to retrieve authentication
@ -953,14 +962,14 @@
<literal>Authentication</literal> object which in turn has its
<literal>principal</literal> property set. The principal will be
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>
property to <literal>true</literal> in your application
context.</para>
@ -998,8 +1007,8 @@
<para>Each event contains two objects: 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>getDetails()</literal> method which often includes
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
includes a <literal>DaoCasAuthoritiesPopulator</literal> which
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
with retrieving the <literal>GrantedAuthority</literal>s.</para>
</listitem>

View File

@ -19,7 +19,7 @@ import net.sf.acegisecurity.AccessDeniedException;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.context.ContextHolder;
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;
@ -91,8 +91,8 @@ public class ContactManagerFacade implements ContactManager, InitializingBean {
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())) {

View File

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

View File

@ -20,7 +20,7 @@ import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException;
import net.sf.acegisecurity.GrantedAuthority;
import net.sf.acegisecurity.context.ContextHolder;
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;
@ -80,8 +80,8 @@ public class SecureIndexController implements Controller, InitializingBean {
Authentication auth = secureContext.getAuthentication();
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;

View File

@ -18,7 +18,7 @@ package sample.contact;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.context.ContextHolder;
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.mvc.SimpleFormController;
@ -61,8 +61,8 @@ public class WebContactAddController extends SimpleFormController {
.getAuthentication();
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,

View File

@ -23,5 +23,25 @@ applications:
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$