Refactor DaoAuthenticationProvider cache model.
This commit is contained in:
parent
d9f77a7ed1
commit
1b24ff5ea8
|
@ -33,7 +33,6 @@
|
|||
|
||||
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
|
||||
<property name="key"><value>my_password</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
|
||||
<property name="key"><value>my_password</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
|
||||
|
|
|
@ -22,6 +22,7 @@ import net.sf.acegisecurity.BadCredentialsException;
|
|||
import net.sf.acegisecurity.DisabledException;
|
||||
import net.sf.acegisecurity.providers.AuthenticationProvider;
|
||||
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||
import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
|
||||
import net.sf.acegisecurity.providers.dao.event.AuthenticationFailureDisabledEvent;
|
||||
import net.sf.acegisecurity.providers.dao.event.AuthenticationFailurePasswordEvent;
|
||||
import net.sf.acegisecurity.providers.dao.event.AuthenticationSuccessEvent;
|
||||
|
@ -36,32 +37,26 @@ import org.springframework.context.ApplicationContextAware;
|
|||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* An {@link AuthenticationProvider} implementation that retrieves user details
|
||||
* from an {@link AuthenticationDao}.
|
||||
*
|
||||
* <p>
|
||||
* This <code>AuthenticationProvider</code> is capable of validating {@link
|
||||
* This <code>AuthenticationProvider</code> is capable of validating {@link
|
||||
* UsernamePasswordAuthenticationToken} requests contain the correct username,
|
||||
* password and the user is not disabled.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Upon successful validation, a <code>DaoAuthenticationToken</code> will be
|
||||
* created and returned to the caller. This token will be signed with the key
|
||||
* configured by {@link #getKey()} and expire {@link
|
||||
* #getRefreshTokenInterval()} milliseconds into the future. The token will be
|
||||
* assumed to remain valid whilstever it has not expired, and no requests of
|
||||
* the <code>AuthenticationProvider</code> will need to be made. Once the
|
||||
* token has expired, the relevant <code>AuthenticationProvider</code> will be
|
||||
* called again to provide an updated enabled/disabled status, and list of
|
||||
* granted authorities. It should be noted the credentials will not be
|
||||
* revalidated, as the user presented correct credentials in the originial
|
||||
* <code>UsernamePasswordAuthenticationToken</code>. This avoids complications
|
||||
* if the user changes their password during the session.
|
||||
* Upon successful validation, a
|
||||
* <code>UsernamePasswordAuthenticationToken</code> will be created and
|
||||
* returned to the caller. In addition, the {@link User} will be placed in the
|
||||
* {@link UserCache} so that subsequent requests with the same username can be
|
||||
* validated without needing to query the {@link AuthenticationDao}. It should
|
||||
* be noted that if a user appears to present an incorrect password, the
|
||||
* {@link AuthenticationDao} will be queried to confirm the most up-to-date
|
||||
* password was used for comparison.
|
||||
* </p>
|
||||
*
|
||||
* <P>
|
||||
|
@ -83,8 +78,7 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
|
|||
private AuthenticationDao authenticationDao;
|
||||
private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
|
||||
private SaltSource saltSource;
|
||||
private String key;
|
||||
private long refreshTokenInterval = 60000; // 60 seconds
|
||||
private UserCache userCache = new NullUserCache();
|
||||
|
||||
//~ Methods ================================================================
|
||||
|
||||
|
@ -101,14 +95,6 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
|
|||
return authenticationDao;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the PasswordEncoder instance to be used to encode and validate
|
||||
* passwords. If not set, {@link PlaintextPasswordEncoder} will be used by
|
||||
|
@ -124,22 +110,6 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
|
|||
return passwordEncoder;
|
||||
}
|
||||
|
||||
public void setRefreshTokenInterval(long refreshTokenInterval) {
|
||||
this.refreshTokenInterval = refreshTokenInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates the number of seconds a created
|
||||
* <code>DaoAuthenticationToken</code> will remain valid for. Whilstever
|
||||
* the token is valid, the <code>DaoAuthenticationProvider</code> will
|
||||
* only check it presents the expected key hash code.
|
||||
*
|
||||
* @return Returns the refreshTokenInterval.
|
||||
*/
|
||||
public long getRefreshTokenInterval() {
|
||||
return refreshTokenInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* The source of salts to use when decoding passwords. <code>null</code>
|
||||
* is a valid value, meaning the <code>DaoAuthenticationProvider</code>
|
||||
|
@ -157,46 +127,36 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
|
|||
return saltSource;
|
||||
}
|
||||
|
||||
public void setUserCache(UserCache userCache) {
|
||||
this.userCache = userCache;
|
||||
}
|
||||
|
||||
public UserCache getUserCache() {
|
||||
return userCache;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.authenticationDao == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"An Authentication DAO must be set");
|
||||
}
|
||||
|
||||
if ((this.key == null) || "".equals(key)) {
|
||||
throw new IllegalArgumentException("A key must be set");
|
||||
if (this.userCache == null) {
|
||||
throw new IllegalArgumentException("A user cache must be set");
|
||||
}
|
||||
}
|
||||
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
// If an existing DaoAuthenticationToken, check we created it and it hasn't expired
|
||||
if (authentication instanceof DaoAuthenticationToken) {
|
||||
if (this.key.hashCode() == ((DaoAuthenticationToken) authentication)
|
||||
.getKeyHash()) {
|
||||
if (((DaoAuthenticationToken) authentication).getExpires()
|
||||
.after(new Date())) {
|
||||
return authentication;
|
||||
}
|
||||
} else {
|
||||
throw new BadCredentialsException(
|
||||
"The presented DaoAuthenticationToken does not contain the expected key");
|
||||
}
|
||||
boolean cacheWasUsed = true;
|
||||
User user = this.userCache.getUserFromCache(authentication.getPrincipal()
|
||||
.toString());
|
||||
|
||||
if (user == null) {
|
||||
cacheWasUsed = false;
|
||||
user = getUserFromBackend(authentication);
|
||||
}
|
||||
|
||||
// We need to authenticate or refresh the token
|
||||
User user = null;
|
||||
|
||||
try {
|
||||
user = this.authenticationDao.loadUserByUsername(authentication.getPrincipal()
|
||||
.toString());
|
||||
} catch (UsernameNotFoundException notFound) {
|
||||
throw new BadCredentialsException("Bad credentials presented");
|
||||
} catch (DataAccessException repositoryProblem) {
|
||||
throw new AuthenticationServiceException(repositoryProblem
|
||||
.getMessage(), repositoryProblem);
|
||||
}
|
||||
|
||||
if (!user.isEnabled()) {
|
||||
if (this.ctx != null) {
|
||||
ctx.publishEvent(new AuthenticationFailureDisabledEvent(
|
||||
|
@ -206,16 +166,14 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
|
|||
throw new DisabledException("User is disabled");
|
||||
}
|
||||
|
||||
if (!(authentication instanceof DaoAuthenticationToken)) {
|
||||
// Must validate credentials, as this is not simply a token refresh
|
||||
Object salt = null;
|
||||
|
||||
if (this.saltSource != null) {
|
||||
salt = this.saltSource.getSalt(user);
|
||||
if (!isPasswordCorrect(authentication, user)) {
|
||||
// Password incorrect, so ensure we're using most current password
|
||||
if (cacheWasUsed) {
|
||||
cacheWasUsed = false;
|
||||
user = getUserFromBackend(authentication);
|
||||
}
|
||||
|
||||
if (!passwordEncoder.isPasswordValid(user.getPassword(),
|
||||
authentication.getCredentials().toString(), salt)) {
|
||||
if (!isPasswordCorrect(authentication, user)) {
|
||||
if (this.ctx != null) {
|
||||
ctx.publishEvent(new AuthenticationFailurePasswordEvent(
|
||||
authentication, user));
|
||||
|
@ -225,24 +183,50 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
|
|||
}
|
||||
}
|
||||
|
||||
Date expiry = new Date(new Date().getTime()
|
||||
+ this.getRefreshTokenInterval());
|
||||
if (!cacheWasUsed) {
|
||||
// Put into cache
|
||||
this.userCache.putUserInCache(user);
|
||||
|
||||
if (this.ctx != null) {
|
||||
ctx.publishEvent(new AuthenticationSuccessEvent(authentication, user));
|
||||
// As this appears to be an initial login, publish the event
|
||||
if (this.ctx != null) {
|
||||
ctx.publishEvent(new AuthenticationSuccessEvent(
|
||||
authentication, user));
|
||||
}
|
||||
}
|
||||
|
||||
return new DaoAuthenticationToken(this.getKey(), expiry,
|
||||
user.getUsername(), user.getPassword(), user.getAuthorities());
|
||||
return new UsernamePasswordAuthenticationToken(user.getUsername(),
|
||||
user.getPassword(), user.getAuthorities());
|
||||
}
|
||||
|
||||
public boolean supports(Class authentication) {
|
||||
if (UsernamePasswordAuthenticationToken.class.isAssignableFrom(
|
||||
authentication)
|
||||
|| (DaoAuthenticationToken.class.isAssignableFrom(authentication))) {
|
||||
authentication)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPasswordCorrect(Authentication authentication, User user) {
|
||||
Object salt = null;
|
||||
|
||||
if (this.saltSource != null) {
|
||||
salt = this.saltSource.getSalt(user);
|
||||
}
|
||||
|
||||
return passwordEncoder.isPasswordValid(user.getPassword(),
|
||||
authentication.getCredentials().toString(), salt);
|
||||
}
|
||||
|
||||
private User getUserFromBackend(Authentication authentication) {
|
||||
try {
|
||||
return this.authenticationDao.loadUserByUsername(authentication.getPrincipal()
|
||||
.toString());
|
||||
} catch (UsernameNotFoundException notFound) {
|
||||
throw new BadCredentialsException("Bad credentials presented");
|
||||
} catch (DataAccessException repositoryProblem) {
|
||||
throw new AuthenticationServiceException(repositoryProblem
|
||||
.getMessage(), repositoryProblem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
/* 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 net.sf.acegisecurity.providers.AbstractAuthenticationToken;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a successful DAO-based <code>Authentication</code>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class DaoAuthenticationToken extends AbstractAuthenticationToken
|
||||
implements Serializable {
|
||||
//~ Instance fields ========================================================
|
||||
|
||||
private Date expires;
|
||||
private Object credentials;
|
||||
private Object principal;
|
||||
private GrantedAuthority[] authorities;
|
||||
private int keyHash;
|
||||
|
||||
//~ Constructors ===========================================================
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param key to identify if this object made by a given {@link
|
||||
* DaoAuthenticationProvider}
|
||||
* @param expires when the token is due to expire
|
||||
* @param principal the username from the {@link User} object
|
||||
* @param credentials the password from the {@link User} object
|
||||
* @param authorities the authorities granted to the user, from the {@link
|
||||
* User} object
|
||||
*
|
||||
* @throws IllegalArgumentException if a <code>null</code> was passed
|
||||
*/
|
||||
public DaoAuthenticationToken(String key, Date expires, Object principal,
|
||||
Object credentials, GrantedAuthority[] authorities) {
|
||||
if ((key == null) || ("".equals(key)) || (expires == null)
|
||||
|| (principal == null) || "".equals(principal)
|
||||
|| (credentials == null) || "".equals(credentials)
|
||||
|| (authorities == null)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot pass null or empty values to constructor");
|
||||
}
|
||||
|
||||
for (int i = 0; i < authorities.length; i++) {
|
||||
if (authorities[i] == null) {
|
||||
throw new IllegalArgumentException("Granted authority element "
|
||||
+ i
|
||||
+ " is null - GrantedAuthority[] cannot contain any null elements");
|
||||
}
|
||||
}
|
||||
|
||||
this.keyHash = key.hashCode();
|
||||
this.expires = expires;
|
||||
this.principal = principal;
|
||||
this.credentials = credentials;
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
protected DaoAuthenticationToken() {
|
||||
throw new IllegalArgumentException("Cannot use default constructor");
|
||||
}
|
||||
|
||||
//~ Methods ================================================================
|
||||
|
||||
/**
|
||||
* Ignored (always <code>true</code>).
|
||||
*
|
||||
* @param isAuthenticated ignored
|
||||
*/
|
||||
public void setAuthenticated(boolean isAuthenticated) {
|
||||
// ignored
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns <code>true</code>.
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public boolean isAuthenticated() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public GrantedAuthority[] getAuthorities() {
|
||||
return this.authorities;
|
||||
}
|
||||
|
||||
public Object getCredentials() {
|
||||
return this.credentials;
|
||||
}
|
||||
|
||||
public Date getExpires() {
|
||||
return this.expires;
|
||||
}
|
||||
|
||||
public int getKeyHash() {
|
||||
return this.keyHash;
|
||||
}
|
||||
|
||||
public Object getPrincipal() {
|
||||
return this.principal;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj instanceof DaoAuthenticationToken) {
|
||||
DaoAuthenticationToken test = (DaoAuthenticationToken) obj;
|
||||
|
||||
if (this.getKeyHash() != test.getKeyHash()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// expires never null due to constructor
|
||||
if (this.getExpires() != test.getExpires()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(super.toString());
|
||||
sb.append("; Expires: " + this.expires.toString());
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/* 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;
|
||||
|
||||
/**
|
||||
* Provides a cache of {@link User} objects.
|
||||
*
|
||||
* <P>
|
||||
* Implementations should provide appropriate methods to set their cache
|
||||
* parameters (eg time-to-live) and/or force removal of entities before their
|
||||
* normal expiration. These are not part of the <code>UserCache</code>
|
||||
* interface contract because they vary depending on the type of caching
|
||||
* system used (eg in-memory vs disk vs cluster vs hybrid).
|
||||
* </p>
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface UserCache {
|
||||
//~ Methods ================================================================
|
||||
|
||||
/**
|
||||
* Obtains a {@link User} 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
|
||||
*/
|
||||
public User 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>.
|
||||
*
|
||||
* @param user the fully populated <code>User</code> to place in the cache
|
||||
*/
|
||||
public void putUserInCache(User user);
|
||||
}
|
135
core/src/main/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCache.java
vendored
Normal file
135
core/src/main/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCache.java
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
/* 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.cache;
|
||||
|
||||
import net.sf.acegisecurity.providers.dao.User;
|
||||
import net.sf.acegisecurity.providers.dao.UserCache;
|
||||
|
||||
import net.sf.ehcache.Cache;
|
||||
import net.sf.ehcache.CacheException;
|
||||
import net.sf.ehcache.CacheManager;
|
||||
import net.sf.ehcache.Element;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
|
||||
|
||||
/**
|
||||
* Caches <code>User</code> objects using <A
|
||||
* HREF="http://ehcache.sourceforge.net">EHCACHE</a>.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class EhCacheBasedUserCache implements UserCache, InitializingBean,
|
||||
DisposableBean {
|
||||
//~ Static fields/initializers =============================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(EhCacheBasedUserCache.class);
|
||||
private static final String CACHE_NAME = "ehCacheBasedUserCache";
|
||||
|
||||
//~ Instance fields ========================================================
|
||||
|
||||
private Cache cache;
|
||||
private CacheManager manager;
|
||||
private int minutesToIdle = 5;
|
||||
|
||||
//~ Methods ================================================================
|
||||
|
||||
public void setMinutesToIdle(int minutesToIdle) {
|
||||
this.minutesToIdle = minutesToIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies how many minutes an entry will remain in the cache from when
|
||||
* it was last accessed. This is effectively the session duration.
|
||||
*
|
||||
* <P>
|
||||
* Defaults to 5 minutes.
|
||||
* </p>
|
||||
*
|
||||
* @return Returns the minutes an element remains in the cache
|
||||
*/
|
||||
public int getMinutesToIdle() {
|
||||
return minutesToIdle;
|
||||
}
|
||||
|
||||
public User getUserFromCache(String username) {
|
||||
Element element = null;
|
||||
|
||||
try {
|
||||
element = cache.get(username);
|
||||
} catch (CacheException cacheException) {
|
||||
throw new DataRetrievalFailureException("Cache failure: "
|
||||
+ cacheException.getMessage());
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cache hit: " + (element != null) + "; username: "
|
||||
+ username);
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
return null;
|
||||
} else {
|
||||
return (User) element.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (CacheManager.getInstance().cacheExists(CACHE_NAME)) {
|
||||
CacheManager.getInstance().removeCache(CACHE_NAME);
|
||||
}
|
||||
|
||||
manager = CacheManager.create();
|
||||
|
||||
// Cache name, max memory, overflowToDisk, eternal, timeToLive, timeToIdle
|
||||
cache = new Cache(CACHE_NAME, Integer.MAX_VALUE, false, false,
|
||||
minutesToIdle * 60, minutesToIdle * 60);
|
||||
manager.addCache(cache);
|
||||
}
|
||||
|
||||
public void destroy() throws Exception {
|
||||
manager.removeCache(CACHE_NAME);
|
||||
}
|
||||
|
||||
public void putUserInCache(User user) {
|
||||
Element element = new Element(user.getUsername(), user);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cache put: " + element.getKey());
|
||||
}
|
||||
|
||||
cache.put(element);
|
||||
}
|
||||
|
||||
public void removeUserFromCache(User user) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cache remove: " + user.getUsername());
|
||||
}
|
||||
|
||||
this.removeUserFromCache(user.getUsername());
|
||||
}
|
||||
|
||||
public void removeUserFromCache(String username) {
|
||||
cache.remove(username);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/* 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.cache;
|
||||
|
||||
import net.sf.acegisecurity.providers.dao.User;
|
||||
import net.sf.acegisecurity.providers.dao.UserCache;
|
||||
|
||||
|
||||
/**
|
||||
* Does not perform any caching.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class NullUserCache implements UserCache {
|
||||
//~ Methods ================================================================
|
||||
|
||||
public User getUserFromCache(String username) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void putUserInCache(User user) {}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<html>
|
||||
<body>
|
||||
Caches <code>User</code> objects for the <code>DaoAuthenticationProvider</code>.
|
||||
</body>
|
||||
</html>
|
|
@ -36,7 +36,6 @@
|
|||
<!-- Authentication provider that queries our data access object -->
|
||||
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
|
||||
<property name="key"><value>my_password</value></property>
|
||||
</bean>
|
||||
|
||||
<!-- The authentication manager that iterates through our only authentication provider -->
|
||||
|
|
|
@ -25,13 +25,16 @@ import net.sf.acegisecurity.GrantedAuthority;
|
|||
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||
import net.sf.acegisecurity.providers.TestingAuthenticationToken;
|
||||
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||
import net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache;
|
||||
import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
|
||||
import net.sf.acegisecurity.providers.dao.salt.SystemWideSaltSource;
|
||||
import net.sf.acegisecurity.providers.encoding.ShaPasswordEncoder;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataRetrievalFailureException;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -56,8 +59,8 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
"KOala");
|
||||
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setKey("x");
|
||||
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
|
||||
provider.setUserCache(new MockUserCache());
|
||||
|
||||
try {
|
||||
provider.authenticate(token);
|
||||
|
@ -72,8 +75,8 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
"opal");
|
||||
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setKey("x");
|
||||
provider.setAuthenticationDao(new MockAuthenticationDaoUserPeter());
|
||||
provider.setUserCache(new MockUserCache());
|
||||
|
||||
try {
|
||||
provider.authenticate(token);
|
||||
|
@ -88,8 +91,8 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
"koala");
|
||||
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setKey("x");
|
||||
provider.setAuthenticationDao(new MockAuthenticationDaoSimulateBackendError());
|
||||
provider.setUserCache(new MockUserCache());
|
||||
|
||||
try {
|
||||
provider.authenticate(token);
|
||||
|
@ -104,8 +107,8 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
"INVALID_PASSWORD");
|
||||
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setKey("x");
|
||||
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
|
||||
provider.setUserCache(new MockUserCache());
|
||||
|
||||
try {
|
||||
provider.authenticate(token);
|
||||
|
@ -120,8 +123,8 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
"koala");
|
||||
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setKey("x");
|
||||
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
|
||||
provider.setUserCache(new MockUserCache());
|
||||
|
||||
try {
|
||||
provider.authenticate(token);
|
||||
|
@ -136,8 +139,8 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
"koala");
|
||||
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setKey("x");
|
||||
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
|
||||
provider.setUserCache(new MockUserCache());
|
||||
|
||||
try {
|
||||
provider.authenticate(token);
|
||||
|
@ -152,55 +155,21 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
"koala");
|
||||
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setKey("x");
|
||||
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
|
||||
provider.setUserCache(new MockUserCache());
|
||||
|
||||
Authentication result = provider.authenticate(token);
|
||||
|
||||
if (!(result instanceof DaoAuthenticationToken)) {
|
||||
fail("Should have returned instance of DaoAuthenticationToken");
|
||||
if (!(result instanceof UsernamePasswordAuthenticationToken)) {
|
||||
fail(
|
||||
"Should have returned instance of UsernamePasswordAuthenticationToken");
|
||||
}
|
||||
|
||||
DaoAuthenticationToken castResult = (DaoAuthenticationToken) result;
|
||||
UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
|
||||
assertEquals("marissa", castResult.getPrincipal());
|
||||
assertEquals("koala", castResult.getCredentials());
|
||||
assertEquals("ROLE_ONE", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals(provider.getKey().hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
public void testAuthenticatesThenAcceptsCreatedTokenAutomatically() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa",
|
||||
"koala");
|
||||
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setKey("x");
|
||||
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
|
||||
|
||||
Authentication result = provider.authenticate(token);
|
||||
|
||||
if (!(result instanceof DaoAuthenticationToken)) {
|
||||
fail("Should have returned instance of DaoAuthenticationToken");
|
||||
}
|
||||
|
||||
DaoAuthenticationToken castResult = (DaoAuthenticationToken) result;
|
||||
assertEquals("marissa", castResult.getPrincipal());
|
||||
assertEquals(provider.getKey().hashCode(), castResult.getKeyHash());
|
||||
assertTrue(castResult.getExpires().after(new Date()));
|
||||
|
||||
// Now try to re-authenticate
|
||||
// Set provider to null, so we get a NullPointerException if it tries to re-authenticate
|
||||
provider.setAuthenticationDao(null);
|
||||
|
||||
Authentication secondResult = provider.authenticate(result);
|
||||
|
||||
if (!(secondResult instanceof DaoAuthenticationToken)) {
|
||||
fail("Should have returned instance of DaoAuthenticationToken");
|
||||
}
|
||||
|
||||
// Should still have the same expiry time as original
|
||||
assertEquals(castResult.getExpires(),
|
||||
((DaoAuthenticationToken) secondResult).getExpires());
|
||||
}
|
||||
|
||||
public void testAuthenticatesWhenASaltIsUsed() {
|
||||
|
@ -211,77 +180,22 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
salt.setSystemWideSalt("SYSTEM_SALT_VALUE");
|
||||
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setKey("x");
|
||||
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissaWithSalt());
|
||||
provider.setSaltSource(salt);
|
||||
provider.setUserCache(new MockUserCache());
|
||||
|
||||
Authentication result = provider.authenticate(token);
|
||||
|
||||
if (!(result instanceof DaoAuthenticationToken)) {
|
||||
if (!(result instanceof UsernamePasswordAuthenticationToken)) {
|
||||
fail(
|
||||
"Should have returned instance of DaoPasswordAuthenticationToken");
|
||||
"Should have returned instance of UsernamePasswordAuthenticationToken");
|
||||
}
|
||||
|
||||
DaoAuthenticationToken castResult = (DaoAuthenticationToken) result;
|
||||
UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
|
||||
assertEquals("marissa", castResult.getPrincipal());
|
||||
assertEquals("koala{SYSTEM_SALT_VALUE}", castResult.getCredentials());
|
||||
assertEquals("ROLE_ONE", castResult.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
|
||||
assertEquals(provider.getKey().hashCode(), castResult.getKeyHash());
|
||||
}
|
||||
|
||||
public void testDaoAuthenticationTokensThatHaveExpiredAreRefreshed()
|
||||
throws Exception {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa",
|
||||
"koala");
|
||||
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setKey("x");
|
||||
provider.setRefreshTokenInterval(0); // never cache
|
||||
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
|
||||
|
||||
Authentication result = provider.authenticate(token);
|
||||
|
||||
if (!(result instanceof DaoAuthenticationToken)) {
|
||||
fail("Should have returned instance of DaoAuthenticationToken");
|
||||
}
|
||||
|
||||
DaoAuthenticationToken castResult = (DaoAuthenticationToken) result;
|
||||
assertEquals("marissa", castResult.getPrincipal());
|
||||
assertEquals(provider.getKey().hashCode(), castResult.getKeyHash());
|
||||
Thread.sleep(1000);
|
||||
assertTrue(castResult.getExpires().before(new Date())); // already expired
|
||||
|
||||
// Now try to re-authenticate
|
||||
Authentication secondResult = provider.authenticate(result);
|
||||
|
||||
if (!(secondResult instanceof DaoAuthenticationToken)) {
|
||||
fail("Should have returned instance of DaoAuthenticationToken");
|
||||
}
|
||||
|
||||
// Should still have a later expiry time than original
|
||||
assertTrue(castResult.getExpires().before(((DaoAuthenticationToken) secondResult)
|
||||
.getExpires()));
|
||||
}
|
||||
|
||||
public void testDaoAuthenticationTokensWithWrongKeyAreRejected()
|
||||
throws Exception {
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setKey("x");
|
||||
provider.setRefreshTokenInterval(0); // never cache
|
||||
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
|
||||
|
||||
DaoAuthenticationToken token = new DaoAuthenticationToken("key",
|
||||
new Date(), "Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
|
||||
try {
|
||||
provider.authenticate(token);
|
||||
fail("Should have thrown BadCredentialsException");
|
||||
} catch (BadCredentialsException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testGettersSetters() {
|
||||
|
@ -293,12 +207,15 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
provider.setSaltSource(new SystemWideSaltSource());
|
||||
assertEquals(SystemWideSaltSource.class,
|
||||
provider.getSaltSource().getClass());
|
||||
|
||||
provider.setUserCache(new EhCacheBasedUserCache());
|
||||
assertEquals(EhCacheBasedUserCache.class,
|
||||
provider.getUserCache().getClass());
|
||||
}
|
||||
|
||||
public void testStartupFailsIfNoAuthenticationDao()
|
||||
throws Exception {
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setKey("xxx");
|
||||
|
||||
try {
|
||||
provider.afterPropertiesSet();
|
||||
|
@ -308,9 +225,11 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public void testStartupFailsIfNoKeySet() throws Exception {
|
||||
public void testStartupFailsIfNoUserCacheSet() throws Exception {
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
provider.setAuthenticationDao(new MockAuthenticationDaoUserMarissa());
|
||||
assertEquals(NullUserCache.class, provider.getUserCache().getClass());
|
||||
provider.setUserCache(null);
|
||||
|
||||
try {
|
||||
provider.afterPropertiesSet();
|
||||
|
@ -323,8 +242,8 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
public void testStartupSuccess() throws Exception {
|
||||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
AuthenticationDao dao = new MockAuthenticationDaoUserMarissa();
|
||||
provider.setKey("x");
|
||||
provider.setAuthenticationDao(dao);
|
||||
provider.setUserCache(new MockUserCache());
|
||||
assertEquals(dao, provider.getAuthenticationDao());
|
||||
provider.afterPropertiesSet();
|
||||
assertTrue(true);
|
||||
|
@ -334,7 +253,6 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
|
||||
assertTrue(provider.supports(UsernamePasswordAuthenticationToken.class));
|
||||
assertTrue(!provider.supports(TestingAuthenticationToken.class));
|
||||
assertTrue(provider.supports(DaoAuthenticationToken.class));
|
||||
}
|
||||
|
||||
//~ Inner Classes ==========================================================
|
||||
|
@ -390,4 +308,16 @@ public class DaoAuthenticationProviderTests extends TestCase {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MockUserCache implements UserCache {
|
||||
private Map cache = new HashMap();
|
||||
|
||||
public User getUserFromCache(String username) {
|
||||
return (User) cache.get(username);
|
||||
}
|
||||
|
||||
public void putUserInCache(User user) {
|
||||
cache.put(user.getUsername(), user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,226 +0,0 @@
|
|||
/* 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 junit.framework.TestCase;
|
||||
|
||||
import net.sf.acegisecurity.GrantedAuthority;
|
||||
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link DaoAuthenticationToken}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class DaoAuthenticationTokenTests extends TestCase {
|
||||
//~ Constructors ===========================================================
|
||||
|
||||
public DaoAuthenticationTokenTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public DaoAuthenticationTokenTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ================================================================
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(DaoAuthenticationTokenTests.class);
|
||||
}
|
||||
|
||||
public void testConstructorRejectsNulls() {
|
||||
try {
|
||||
new DaoAuthenticationToken(null, new Date(), "Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
new DaoAuthenticationToken("key", null, "Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
new DaoAuthenticationToken("key", new Date(), null, "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
new DaoAuthenticationToken("key", new Date(), "Test", null,
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
new DaoAuthenticationToken("key", new Date(), "Test", "Password",
|
||||
null);
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
try {
|
||||
new DaoAuthenticationToken("key", new Date(), "Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), null});
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testEqualsWhenEqual() {
|
||||
Date date = new Date();
|
||||
|
||||
DaoAuthenticationToken token1 = new DaoAuthenticationToken("key", date,
|
||||
"Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
|
||||
DaoAuthenticationToken token2 = new DaoAuthenticationToken("key", date,
|
||||
"Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
|
||||
assertEquals(token1, token2);
|
||||
}
|
||||
|
||||
public void testGetters() {
|
||||
Date date = new Date();
|
||||
DaoAuthenticationToken token = new DaoAuthenticationToken("key", date,
|
||||
"Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
assertEquals("key".hashCode(), token.getKeyHash());
|
||||
assertEquals("Test", token.getPrincipal());
|
||||
assertEquals("Password", token.getCredentials());
|
||||
assertEquals("ROLE_ONE", token.getAuthorities()[0].getAuthority());
|
||||
assertEquals("ROLE_TWO", token.getAuthorities()[1].getAuthority());
|
||||
assertEquals(date, token.getExpires());
|
||||
}
|
||||
|
||||
public void testNoArgConstructor() {
|
||||
try {
|
||||
new DaoAuthenticationToken();
|
||||
fail("Should have thrown IllegalArgumentException");
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testNotEqualsDueToAbstractParentEqualsCheck() {
|
||||
Date date = new Date();
|
||||
|
||||
DaoAuthenticationToken token1 = new DaoAuthenticationToken("key", date,
|
||||
"Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
|
||||
DaoAuthenticationToken token2 = new DaoAuthenticationToken("key", date,
|
||||
"DIFFERENT_PRINCIPAL", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
|
||||
assertTrue(!token1.equals(token2));
|
||||
}
|
||||
|
||||
public void testNotEqualsDueToDifferentAuthenticationClass() {
|
||||
DaoAuthenticationToken token1 = new DaoAuthenticationToken("key",
|
||||
new Date(), "Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
|
||||
UsernamePasswordAuthenticationToken token2 = new UsernamePasswordAuthenticationToken("Test",
|
||||
"Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
token2.setAuthenticated(true);
|
||||
|
||||
assertTrue(!token1.equals(token2));
|
||||
}
|
||||
|
||||
public void testNotEqualsDueToDifferentExpiresDate() {
|
||||
DaoAuthenticationToken token1 = new DaoAuthenticationToken("key",
|
||||
new Date(50000), "Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
|
||||
DaoAuthenticationToken token2 = new DaoAuthenticationToken("key",
|
||||
new Date(60000), "Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
|
||||
assertTrue(!token1.equals(token2));
|
||||
}
|
||||
|
||||
public void testNotEqualsDueToKey() {
|
||||
Date date = new Date();
|
||||
|
||||
DaoAuthenticationToken token1 = new DaoAuthenticationToken("key", date,
|
||||
"Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
|
||||
DaoAuthenticationToken token2 = new DaoAuthenticationToken("DIFFERENT_KEY",
|
||||
date, "Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
|
||||
assertTrue(!token1.equals(token2));
|
||||
}
|
||||
|
||||
public void testSetAuthenticatedIgnored() {
|
||||
DaoAuthenticationToken token = new DaoAuthenticationToken("key",
|
||||
new Date(), "Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
assertTrue(token.isAuthenticated());
|
||||
token.setAuthenticated(false); // ignored
|
||||
assertTrue(token.isAuthenticated());
|
||||
}
|
||||
|
||||
public void testToString() {
|
||||
DaoAuthenticationToken token = new DaoAuthenticationToken("key",
|
||||
new Date(), "Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
String result = token.toString();
|
||||
assertTrue(result.lastIndexOf("Expires:") != -1);
|
||||
}
|
||||
}
|
83
core/src/test/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCacheTests.java
vendored
Normal file
83
core/src/test/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCacheTests.java
vendored
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* 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.cache;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import net.sf.acegisecurity.GrantedAuthority;
|
||||
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||
import net.sf.acegisecurity.providers.dao.User;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link EhCacheBasedUserCache}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class EhCacheBasedUserCacheTests extends TestCase {
|
||||
//~ Constructors ===========================================================
|
||||
|
||||
public EhCacheBasedUserCacheTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public EhCacheBasedUserCacheTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ================================================================
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(EhCacheBasedUserCacheTests.class);
|
||||
}
|
||||
|
||||
public void testCacheOperation() throws Exception {
|
||||
EhCacheBasedUserCache cache = new EhCacheBasedUserCache();
|
||||
cache.afterPropertiesSet();
|
||||
|
||||
// Check it gets stored in the cache
|
||||
cache.putUserInCache(getUser());
|
||||
assertEquals(getUser().getPassword(),
|
||||
cache.getUserFromCache(getUser().getUsername()).getPassword());
|
||||
|
||||
// Check it gets removed from the cache
|
||||
cache.removeUserFromCache(getUser());
|
||||
assertNull(cache.getUserFromCache(getUser().getUsername()));
|
||||
|
||||
// Check it doesn't return values for null or unknown users
|
||||
assertNull(cache.getUserFromCache(null));
|
||||
assertNull(cache.getUserFromCache("UNKNOWN_USER"));
|
||||
|
||||
cache.destroy();
|
||||
}
|
||||
|
||||
public void testGettersSetters() {
|
||||
EhCacheBasedUserCache cache = new EhCacheBasedUserCache();
|
||||
cache.setMinutesToIdle(15);
|
||||
assertEquals(15, cache.getMinutesToIdle());
|
||||
}
|
||||
|
||||
private User getUser() {
|
||||
return new User("john", "password", true,
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
}
|
||||
}
|
63
core/src/test/java/org/acegisecurity/providers/dao/cache/NullUserCacheTests.java
vendored
Normal file
63
core/src/test/java/org/acegisecurity/providers/dao/cache/NullUserCacheTests.java
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* 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.cache;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import net.sf.acegisecurity.GrantedAuthority;
|
||||
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||
import net.sf.acegisecurity.providers.dao.User;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link NullUserCache}.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class NullUserCacheTests extends TestCase {
|
||||
//~ Constructors ===========================================================
|
||||
|
||||
public NullUserCacheTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NullUserCacheTests(String arg0) {
|
||||
super(arg0);
|
||||
}
|
||||
|
||||
//~ Methods ================================================================
|
||||
|
||||
public final void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(NullUserCacheTests.class);
|
||||
}
|
||||
|
||||
public void testCacheOperation() throws Exception {
|
||||
NullUserCache cache = new NullUserCache();
|
||||
cache.putUserInCache(getUser());
|
||||
assertNull(cache.getUserFromCache(null));
|
||||
}
|
||||
|
||||
private User getUser() {
|
||||
return new User("john", "password", true,
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
|
||||
"ROLE_TWO")});
|
||||
}
|
||||
}
|
|
@ -36,7 +36,6 @@
|
|||
<!-- Authentication provider that queries our data access object -->
|
||||
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
|
||||
<property name="key"><value>my_password</value></property>
|
||||
</bean>
|
||||
|
||||
<!-- The authentication manager that iterates through our only authentication provider -->
|
||||
|
|
|
@ -892,7 +892,6 @@
|
|||
|
||||
<para><programlisting><bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
|
||||
<property name="key"><value>my_password</value></property>
|
||||
<property name="refreshTokenInterval"><value>60000</value></property>
|
||||
<property name="saltSource"><ref bean="saltSource"/></property>
|
||||
<property name="passwordEncoder"><ref bean="passwordEncoder"/></property>
|
||||
|
@ -910,23 +909,30 @@
|
|||
<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 User 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>User</literal>
|
||||
object to obtain the salt. Please refer to the JavaDocs for further
|
||||
details on these optional features.</para>
|
||||
|
||||
<para>The <literal>key</literal> property permits the
|
||||
<literal>DaoAuthenticationProvider</literal> to build a
|
||||
<literal>DaoAuthenticationToken</literal> that represents the
|
||||
successful authentication request. This allows the
|
||||
<literal>DaoAuthenticationProvider</literal> to avoid repeated lookups
|
||||
of the backend authentication repository. For a presented
|
||||
<literal>DaoAuthenticationToken</literal> to be accepted as valid, it
|
||||
needs to both present the expected key (to prove it was created by the
|
||||
<literal>DaoAuthenticationProvider</literal>) and that is has not
|
||||
expired. <literal>DaoAuthenticationToken</literal>s by default expire
|
||||
60 seconds after they have been created, although this can be set to
|
||||
any other millisecond value via the
|
||||
<literal>refreshTokenInterval</literal> property.</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
|
||||
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.
|
||||
A usable caching implementation is also provided,
|
||||
<literal>EhCacheBasedUserCache</literal>, which is configured as
|
||||
follows:</para>
|
||||
|
||||
<para><programlisting><bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="authenticationDao"><ref bean="authenticationDao"/></property>
|
||||
<property name="userCache"><ref bean="userCache"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
|
||||
<property name="minutesToIdle"><value>5</value></property>
|
||||
</bean></programlisting></para>
|
||||
|
||||
<para>For a class to be able to provide the
|
||||
<literal>DaoAuthenticationProvider</literal> with access to an
|
||||
|
|
|
@ -152,6 +152,8 @@
|
|||
<lib dir="${lib.dir}/j2ee" includes="jstl.jar"/>
|
||||
<lib dir="${lib.dir}/caucho" includes="*.jar"/>
|
||||
<lib dir="${lib.dir}/jakarta-commons" includes="commons-codec.jar"/>
|
||||
<lib dir="${lib.dir}/jakarta-commons" includes="commons-collections.jar"/>
|
||||
<lib dir="${lib.dir}/ehcache" includes="*.jar"/>
|
||||
<lib dir="${dist.lib.dir}" includes="acegi-security-taglib.jar"/>
|
||||
<lib dir="${dist.lib.dir}" includes="acegi-security.jar"/>
|
||||
</war>
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
|
||||
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
|
||||
<property name="key"><value>my_password</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="basicProcessingFilter" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter">
|
||||
|
|
|
@ -43,7 +43,11 @@
|
|||
|
||||
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="authenticationDao"><ref bean="inMemoryDaoImpl"/></property>
|
||||
<property name="key"><value>my_password</value></property>
|
||||
<property name="userCache"><ref bean="userCache"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
|
||||
<property name="minutesToIdle"><value>5</value></property>
|
||||
</bean>
|
||||
|
||||
<!-- Automatically receives AuthenticationEvent messages from DaoAuthenticationProvider -->
|
||||
|
|
|
@ -42,11 +42,14 @@
|
|||
</bean>
|
||||
|
||||
<!-- =================== SECURITY BEANS YOU WILL RARELY (IF EVER) CHANGE ================== -->
|
||||
<!-- However, it is a good idea to change each <property name="key">'s to a new random value -->
|
||||
|
||||
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
|
||||
<property name="authenticationDao"><ref bean="authenticationDao"/></property>
|
||||
<property name="key"><value>my_password</value></property>
|
||||
<property name="userCache"><ref bean="userCache"/></property>
|
||||
</bean>
|
||||
|
||||
<bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
|
||||
<property name="minutesToIdle"><value>5</value></property>
|
||||
</bean>
|
||||
|
||||
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
|
||||
|
|
Loading…
Reference in New Issue