SEC-9 and SEC-55: Refactor DaoAuthenticationProvider and deprecate PasswordDaoAuthenticationProvider.
This commit is contained in:
parent
f50cbd31ba
commit
e9b1d9452f
|
@ -0,0 +1,280 @@
|
||||||
|
/* Copyright 2004, 2005 Acegi Technology Pty Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.sf.acegisecurity.providers.dao;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.AccountExpiredException;
|
||||||
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
import net.sf.acegisecurity.AuthenticationException;
|
||||||
|
import net.sf.acegisecurity.CredentialsExpiredException;
|
||||||
|
import net.sf.acegisecurity.DisabledException;
|
||||||
|
import net.sf.acegisecurity.LockedException;
|
||||||
|
import net.sf.acegisecurity.UserDetails;
|
||||||
|
import net.sf.acegisecurity.providers.AuthenticationProvider;
|
||||||
|
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base {@link AuthenticationProvider} that allows subclasses to override and
|
||||||
|
* work with {@link net.sf.acegisecurity.UserDetails} objects. The class is
|
||||||
|
* designed to respond to {@link UsernamePasswordAuthenticationToken}
|
||||||
|
* authentication requests.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Upon successful validation, a
|
||||||
|
* <code>UsernamePasswordAuthenticationToken</code> will be created and
|
||||||
|
* returned to the caller. The token will include as its principal either a
|
||||||
|
* <code>String</code> representation of the username, or the {@link
|
||||||
|
* UserDetails} that was returned from the authentication repository. Using
|
||||||
|
* <code>String</code> is appropriate if a container adapter is being used, as
|
||||||
|
* it expects <code>String</code> representations of the username. Using
|
||||||
|
* <code>UserDetails</code> is appropriate if you require access to additional
|
||||||
|
* properties of the authenticated user, such as email addresses,
|
||||||
|
* human-friendly names etc. As container adapters are not recommended to be
|
||||||
|
* used, and <code>UserDetails</code> implementations provide additional
|
||||||
|
* flexibility, by default a <code>UserDetails</code> is returned. To override
|
||||||
|
* this default, set the {@link #setForcePrincipalAsString} to
|
||||||
|
* <code>true</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Caching is handled via the <code>UserDetails</code> object being placed in
|
||||||
|
* the {@link UserCache}. This ensures that subsequent requests with the same
|
||||||
|
* username can be validated without needing to query the {@link
|
||||||
|
* AuthenticationDao}. It should be noted that if a user appears to present an
|
||||||
|
* incorrect password, the {@link AuthenticationDao} will be queried to
|
||||||
|
* confirm the most up-to-date password was used for comparison.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public abstract class AbstractUserDetailsAuthenticationProvider
|
||||||
|
implements AuthenticationProvider, InitializingBean {
|
||||||
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
|
private UserCache userCache = new NullUserCache();
|
||||||
|
private boolean forcePrincipalAsString = false;
|
||||||
|
|
||||||
|
//~ Methods ================================================================
|
||||||
|
|
||||||
|
public void setForcePrincipalAsString(boolean forcePrincipalAsString) {
|
||||||
|
this.forcePrincipalAsString = forcePrincipalAsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isForcePrincipalAsString() {
|
||||||
|
return forcePrincipalAsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserCache(UserCache userCache) {
|
||||||
|
this.userCache = userCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserCache getUserCache() {
|
||||||
|
return userCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void afterPropertiesSet() throws Exception {
|
||||||
|
Assert.notNull(this.userCache, "A user cache must be set");
|
||||||
|
doAfterPropertiesSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Authentication authenticate(Authentication authentication)
|
||||||
|
throws AuthenticationException {
|
||||||
|
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class,
|
||||||
|
authentication,
|
||||||
|
"Only UsernamePasswordAuthenticationToken is supported");
|
||||||
|
|
||||||
|
// Determine username
|
||||||
|
String username = (authentication.getPrincipal() == null)
|
||||||
|
? "NONE_PROVIDED" : authentication.getName();
|
||||||
|
|
||||||
|
boolean cacheWasUsed = true;
|
||||||
|
UserDetails user = this.userCache.getUserFromCache(username);
|
||||||
|
|
||||||
|
if (user == null) {
|
||||||
|
cacheWasUsed = false;
|
||||||
|
user = retrieveUser(username,
|
||||||
|
(UsernamePasswordAuthenticationToken) authentication);
|
||||||
|
Assert.notNull(user,
|
||||||
|
"retrieveUser returned null - a violation of the interface contract");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.isAccountNonLocked()) {
|
||||||
|
throw new LockedException("User account is locked");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.isEnabled()) {
|
||||||
|
throw new DisabledException("User is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.isAccountNonExpired()) {
|
||||||
|
throw new AccountExpiredException("User account has expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
// This check must come here, as we don't want to tell users
|
||||||
|
// about account status unless they presented the correct credentials
|
||||||
|
try {
|
||||||
|
additionalAuthenticationChecks(user,
|
||||||
|
(UsernamePasswordAuthenticationToken) authentication);
|
||||||
|
} catch (AuthenticationException exception) {
|
||||||
|
// There was a problem, so try again after checking we're using latest data
|
||||||
|
cacheWasUsed = false;
|
||||||
|
user = retrieveUser(username,
|
||||||
|
(UsernamePasswordAuthenticationToken) authentication);
|
||||||
|
additionalAuthenticationChecks(user,
|
||||||
|
(UsernamePasswordAuthenticationToken) authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.isCredentialsNonExpired()) {
|
||||||
|
throw new CredentialsExpiredException(
|
||||||
|
"User credentials have expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cacheWasUsed) {
|
||||||
|
this.userCache.putUserInCache(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object principalToReturn = user;
|
||||||
|
|
||||||
|
if (forcePrincipalAsString) {
|
||||||
|
principalToReturn = user.getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
return createSuccessAuthentication(principalToReturn, authentication,
|
||||||
|
user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supports(Class authentication) {
|
||||||
|
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows subclasses to perform any additional checks of a returned (or
|
||||||
|
* cached) <code>UserDetails</code> for a given authentication request.
|
||||||
|
* Generally a subclass will at least compare the {@link
|
||||||
|
* Authentication#getCredentials()} with a {@link
|
||||||
|
* UserDetails#getPassword()}. If custom logic is needed to compare
|
||||||
|
* additional properties of <code>UserDetails</code> and/or
|
||||||
|
* <code>UsernamePasswordAuthenticationToken</code>, these should also
|
||||||
|
* appear in this method.
|
||||||
|
*
|
||||||
|
* @param userDetails as retrieved from the {@link #retrieveUser(String,
|
||||||
|
* UsernamePasswordAuthenticationToken)} or <code>UserCache</code>
|
||||||
|
* @param authentication the current request that needs to be authenticated
|
||||||
|
*
|
||||||
|
* @throws AuthenticationException AuthenticationException if the
|
||||||
|
* credentials could not be validated (generally a
|
||||||
|
* <code>BadCredentialsException</code>, an
|
||||||
|
* <code>AuthenticationServiceException</code>)
|
||||||
|
*/
|
||||||
|
protected abstract void additionalAuthenticationChecks(
|
||||||
|
UserDetails userDetails,
|
||||||
|
UsernamePasswordAuthenticationToken authentication)
|
||||||
|
throws AuthenticationException;
|
||||||
|
|
||||||
|
protected void doAfterPropertiesSet() throws Exception {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows subclasses to actually retrieve the <code>UserDetails</code> from
|
||||||
|
* an implementation-specific location, with the option of throwing an
|
||||||
|
* <code>AuthenticationException</code> immediately if the presented
|
||||||
|
* credentials are incorrect (this is especially useful if it is necessary
|
||||||
|
* to bind to a resource as the user in order to obtain or generate a
|
||||||
|
* <code>UserDetails</code>).
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Subclasses are not required to perform any caching, as the
|
||||||
|
* <code>AbstractUserDetailsAuthenticationProvider</code> will by default
|
||||||
|
* cache the <code>UserDetails</code>. The caching of
|
||||||
|
* <code>UserDetails</code> does present additional complexity as this
|
||||||
|
* means subsequent requests that rely on the cache will need to still
|
||||||
|
* have their credentials validated, even if the correctness of
|
||||||
|
* credentials was assured by subclasses adopting a binding-based strategy
|
||||||
|
* in this method. Accordingly it is important that subclasses either
|
||||||
|
* disable caching (if they want to ensure that this method is the only
|
||||||
|
* method that is capable of authenticating a request, as no
|
||||||
|
* <code>UserDetails</code> will ever be cached) or ensure subclasses
|
||||||
|
* implement {@link #additionalAuthenticationChecks(UserDetails,
|
||||||
|
* UsernamePasswordAuthenticationToken)} to compare the credentials of a
|
||||||
|
* cached <code>UserDetails</code> with subsequent authentication
|
||||||
|
* requests.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Most of the time subclasses will not perform credentials inspection in
|
||||||
|
* this method, instead performing it in {@link
|
||||||
|
* #additionalAuthenticationChecks(UserDetails,
|
||||||
|
* UsernamePasswordAuthenticationToken)} so that code related to
|
||||||
|
* credentials validation need not be duplicated across two methods.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param username The username to retrieve
|
||||||
|
* @param authentication The authentication request, which subclasses
|
||||||
|
* <em>may</em> need to perform a binding-based retrieval of the
|
||||||
|
* <code>UserDetails</code>
|
||||||
|
*
|
||||||
|
* @return the user information (never <code>null</code> - instead an
|
||||||
|
* exception should the thrown)
|
||||||
|
*
|
||||||
|
* @throws AuthenticationException if the credentials could not be
|
||||||
|
* validated (generally a <code>BadCredentialsException</code>, an
|
||||||
|
* <code>AuthenticationServiceException</code> or
|
||||||
|
* <code>UserNotFoundException</code>)
|
||||||
|
*/
|
||||||
|
protected abstract UserDetails retrieveUser(String username,
|
||||||
|
UsernamePasswordAuthenticationToken authentication)
|
||||||
|
throws AuthenticationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a successful {@link Authentication} object.
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Protected so subclasses can override.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* Subclasses will usually store the original credentials the user supplied
|
||||||
|
* (not salted or encoded passwords) in the returned
|
||||||
|
* <code>Authentication</code> object.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param principal that should be the principal in the returned object
|
||||||
|
* (defined by the {@link #isForcePrincipalAsString()} method)
|
||||||
|
* @param authentication that was presented to the
|
||||||
|
* <code>DaoAuthenticationProvider</code> for validation
|
||||||
|
* @param user that was loaded by the <code>AuthenticationDao</code>
|
||||||
|
*
|
||||||
|
* @return the successful authentication token
|
||||||
|
*/
|
||||||
|
protected Authentication createSuccessAuthentication(Object principal,
|
||||||
|
Authentication authentication, UserDetails user) {
|
||||||
|
// Ensure we return the original credentials the user supplied,
|
||||||
|
// so subsequent attempts are successful even with encoded passwords.
|
||||||
|
// Also ensure we return the original getDetails(), so that future
|
||||||
|
// authentication events after cache expiry contain the details
|
||||||
|
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal,
|
||||||
|
authentication.getCredentials(), user.getAuthorities());
|
||||||
|
result.setDetails((authentication.getDetails() != null)
|
||||||
|
? authentication.getDetails() : null);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,23 +15,15 @@
|
||||||
|
|
||||||
package net.sf.acegisecurity.providers.dao;
|
package net.sf.acegisecurity.providers.dao;
|
||||||
|
|
||||||
import net.sf.acegisecurity.AccountExpiredException;
|
|
||||||
import net.sf.acegisecurity.Authentication;
|
|
||||||
import net.sf.acegisecurity.AuthenticationException;
|
import net.sf.acegisecurity.AuthenticationException;
|
||||||
import net.sf.acegisecurity.AuthenticationServiceException;
|
import net.sf.acegisecurity.AuthenticationServiceException;
|
||||||
import net.sf.acegisecurity.BadCredentialsException;
|
import net.sf.acegisecurity.BadCredentialsException;
|
||||||
import net.sf.acegisecurity.CredentialsExpiredException;
|
|
||||||
import net.sf.acegisecurity.DisabledException;
|
|
||||||
import net.sf.acegisecurity.LockedException;
|
|
||||||
import net.sf.acegisecurity.UserDetails;
|
import net.sf.acegisecurity.UserDetails;
|
||||||
import net.sf.acegisecurity.providers.AuthenticationProvider;
|
import net.sf.acegisecurity.providers.AuthenticationProvider;
|
||||||
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
|
|
||||||
import net.sf.acegisecurity.providers.encoding.PasswordEncoder;
|
import net.sf.acegisecurity.providers.encoding.PasswordEncoder;
|
||||||
import net.sf.acegisecurity.providers.encoding.PlaintextPasswordEncoder;
|
import net.sf.acegisecurity.providers.encoding.PlaintextPasswordEncoder;
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
@ -40,51 +32,17 @@ import org.springframework.util.Assert;
|
||||||
/**
|
/**
|
||||||
* An {@link AuthenticationProvider} implementation that retrieves user details
|
* An {@link AuthenticationProvider} implementation that retrieves user details
|
||||||
* from an {@link AuthenticationDao}.
|
* from an {@link AuthenticationDao}.
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This <code>AuthenticationProvider</code> is capable of validating {@link
|
|
||||||
* UsernamePasswordAuthenticationToken} requests contain the correct username,
|
|
||||||
* password and the user is not disabled.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Upon successful validation, a
|
|
||||||
* <code>UsernamePasswordAuthenticationToken</code> will be created and
|
|
||||||
* returned to the caller. The token will include as its principal either a
|
|
||||||
* <code>String</code> representation of the username, or the {@link
|
|
||||||
* UserDetails} that was returned from the authentication repository. Using
|
|
||||||
* <code>String</code> is appropriate if a container adapter is being used, as
|
|
||||||
* it expects <code>String</code> representations of the username. Using
|
|
||||||
* <code>UserDetails</code> is appropriate if you require access to additional
|
|
||||||
* properties of the authenticated user, such as email addresses,
|
|
||||||
* human-friendly names etc. As container adapters are not recommended to be
|
|
||||||
* used, and <code>UserDetails</code> implementations provide additional
|
|
||||||
* flexibility, by default a <code>UserDetails</code> is returned. To override
|
|
||||||
* this default, set the {@link #setForcePrincipalAsString} to
|
|
||||||
* <code>true</code>.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <P>
|
|
||||||
* Caching is handled via the <code>UserDetails</code> object being placed in
|
|
||||||
* the {@link UserCache}. This ensures that subsequent requests with the same
|
|
||||||
* username can be validated without needing to query the {@link
|
|
||||||
* AuthenticationDao}. It should be noted that if a user appears to present an
|
|
||||||
* incorrect password, the {@link AuthenticationDao} will be queried to
|
|
||||||
* confirm the most up-to-date password was used for comparison.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
public class DaoAuthenticationProvider implements AuthenticationProvider,
|
public class DaoAuthenticationProvider
|
||||||
InitializingBean {
|
extends AbstractUserDetailsAuthenticationProvider {
|
||||||
//~ Instance fields ========================================================
|
//~ Instance fields ========================================================
|
||||||
|
|
||||||
private AuthenticationDao authenticationDao;
|
private AuthenticationDao authenticationDao;
|
||||||
private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
|
private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
|
||||||
private SaltSource saltSource;
|
private SaltSource saltSource;
|
||||||
private UserCache userCache = new NullUserCache();
|
|
||||||
private boolean forcePrincipalAsString = false;
|
|
||||||
private boolean hideUserNotFoundExceptions = true;
|
private boolean hideUserNotFoundExceptions = true;
|
||||||
|
|
||||||
//~ Methods ================================================================
|
//~ Methods ================================================================
|
||||||
|
@ -97,14 +55,6 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
|
||||||
return authenticationDao;
|
return authenticationDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setForcePrincipalAsString(boolean forcePrincipalAsString) {
|
|
||||||
this.forcePrincipalAsString = forcePrincipalAsString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isForcePrincipalAsString() {
|
|
||||||
return forcePrincipalAsString;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* By default the <code>DaoAuthenticationProvider</code> throws a
|
* By default the <code>DaoAuthenticationProvider</code> throws a
|
||||||
* <code>BadCredentialsException</code> if a username is not found or the
|
* <code>BadCredentialsException</code> if a username is not found or the
|
||||||
|
@ -159,158 +109,29 @@ public class DaoAuthenticationProvider implements AuthenticationProvider,
|
||||||
return saltSource;
|
return saltSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUserCache(UserCache userCache) {
|
protected void additionalAuthenticationChecks(UserDetails userDetails,
|
||||||
this.userCache = userCache;
|
UsernamePasswordAuthenticationToken authentication)
|
||||||
}
|
|
||||||
|
|
||||||
public UserCache getUserCache() {
|
|
||||||
return userCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
|
||||||
Assert.notNull(this.authenticationDao,
|
|
||||||
"An Authentication DAO must be set");
|
|
||||||
Assert.notNull(this.userCache, "A user cache must be set");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Authentication authenticate(Authentication authentication)
|
|
||||||
throws AuthenticationException {
|
throws AuthenticationException {
|
||||||
// Determine username
|
|
||||||
String username = "NONE_PROVIDED";
|
|
||||||
|
|
||||||
if (authentication.getPrincipal() != null) {
|
|
||||||
username = authentication.getPrincipal().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (authentication.getPrincipal() instanceof UserDetails) {
|
|
||||||
username = ((UserDetails) authentication.getPrincipal())
|
|
||||||
.getUsername();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean cacheWasUsed = true;
|
|
||||||
UserDetails user = this.userCache.getUserFromCache(username);
|
|
||||||
|
|
||||||
if (user == null) {
|
|
||||||
cacheWasUsed = false;
|
|
||||||
user = getUserFromBackend(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user.isAccountNonLocked()) {
|
|
||||||
throw new LockedException("User account is locked");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isPasswordCorrect(authentication, user)) {
|
|
||||||
// Password incorrect, so ensure we're using most current password
|
|
||||||
if (cacheWasUsed) {
|
|
||||||
cacheWasUsed = false;
|
|
||||||
user = getUserFromBackend(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isPasswordCorrect(authentication, user)) {
|
|
||||||
throw new BadCredentialsException("Bad credentials presented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user.isEnabled()) {
|
|
||||||
throw new DisabledException("User is disabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user.isAccountNonExpired()) {
|
|
||||||
throw new AccountExpiredException("User account has expired");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user.isCredentialsNonExpired()) {
|
|
||||||
throw new CredentialsExpiredException(
|
|
||||||
"User credentials have expired");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cacheWasUsed) {
|
|
||||||
// Put into cache
|
|
||||||
this.userCache.putUserInCache(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object principalToReturn = user;
|
|
||||||
|
|
||||||
if (forcePrincipalAsString) {
|
|
||||||
principalToReturn = user.getUsername();
|
|
||||||
}
|
|
||||||
|
|
||||||
return createSuccessAuthentication(principalToReturn, authentication,
|
|
||||||
user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supports(Class authentication) {
|
|
||||||
if (UsernamePasswordAuthenticationToken.class.isAssignableFrom(
|
|
||||||
authentication)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates whether the supplied <code>Authentication</code> object
|
|
||||||
* provided appropriate credentials. This method can be called several
|
|
||||||
* times throughout a single authentication request.
|
|
||||||
*
|
|
||||||
* <P>
|
|
||||||
* Protected so subclasses can override.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param authentication that was presented to the
|
|
||||||
* <code>DaoAuthenticationProvider</code> for validation
|
|
||||||
* @param user that was loaded by the <code>AuthenticationDao</code>
|
|
||||||
*
|
|
||||||
* @return a boolean indicating whether the credentials were correct
|
|
||||||
*/
|
|
||||||
protected boolean isPasswordCorrect(Authentication authentication,
|
|
||||||
UserDetails user) {
|
|
||||||
Object salt = null;
|
Object salt = null;
|
||||||
|
|
||||||
if (this.saltSource != null) {
|
if (this.saltSource != null) {
|
||||||
salt = this.saltSource.getSalt(user);
|
salt = this.saltSource.getSalt(userDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
return passwordEncoder.isPasswordValid(user.getPassword(),
|
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(),
|
||||||
authentication.getCredentials().toString(), salt);
|
authentication.getCredentials().toString(), salt)) {
|
||||||
|
throw new BadCredentialsException("Bad credentials");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected void doAfterPropertiesSet() throws Exception {
|
||||||
* Creates a successful {@link Authentication} object.
|
Assert.notNull(this.authenticationDao,
|
||||||
*
|
"An Authentication DAO must be set");
|
||||||
* <P>
|
|
||||||
* Protected so subclasses can override.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <P>
|
|
||||||
* Subclasses will usually store the original credentials the user supplied
|
|
||||||
* (not salted or encoded passwords) in the returned
|
|
||||||
* <code>Authentication</code> object.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param principal that should be the principal in the returned object
|
|
||||||
* (defined by the {@link #isForcePrincipalAsString()} method)
|
|
||||||
* @param authentication that was presented to the
|
|
||||||
* <code>DaoAuthenticationProvider</code> for validation
|
|
||||||
* @param user that was loaded by the <code>AuthenticationDao</code>
|
|
||||||
*
|
|
||||||
* @return the successful authentication token
|
|
||||||
*/
|
|
||||||
protected Authentication createSuccessAuthentication(Object principal,
|
|
||||||
Authentication authentication, UserDetails user) {
|
|
||||||
// Ensure we return the original credentials the user supplied,
|
|
||||||
// so subsequent attempts are successful even with encoded passwords.
|
|
||||||
// Also ensure we return the original getDetails(), so that future
|
|
||||||
// authentication events after cache expiry contain the details
|
|
||||||
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal,
|
|
||||||
authentication.getCredentials(), user.getAuthorities());
|
|
||||||
result.setDetails((authentication.getDetails() != null)
|
|
||||||
? authentication.getDetails() : null);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserDetails getUserFromBackend(String username) {
|
protected final UserDetails retrieveUser(String username,
|
||||||
|
UsernamePasswordAuthenticationToken authentication)
|
||||||
|
throws AuthenticationException {
|
||||||
UserDetails loadedUser;
|
UserDetails loadedUser;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -24,7 +24,6 @@ import net.sf.acegisecurity.BadCredentialsException;
|
||||||
import net.sf.acegisecurity.GrantedAuthority;
|
import net.sf.acegisecurity.GrantedAuthority;
|
||||||
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||||
import net.sf.acegisecurity.UserDetails;
|
import net.sf.acegisecurity.UserDetails;
|
||||||
import net.sf.acegisecurity.providers.dao.PasswordAuthenticationDao;
|
|
||||||
import net.sf.acegisecurity.providers.dao.User;
|
import net.sf.acegisecurity.providers.dao.User;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.sf.acegisecurity.providers.dao;
|
package net.sf.acegisecurity.providers.dao.ldap;
|
||||||
|
|
||||||
import net.sf.acegisecurity.BadCredentialsException;
|
import net.sf.acegisecurity.BadCredentialsException;
|
||||||
import net.sf.acegisecurity.UserDetails;
|
import net.sf.acegisecurity.UserDetails;
|
||||||
|
@ -33,7 +33,8 @@ import org.springframework.dao.DataAccessException;
|
||||||
* The interface requires only one read-only method, which simplifies support
|
* The interface requires only one read-only method, which simplifies support
|
||||||
* of new data access strategies.
|
* of new data access strategies.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
|
* @deprecated instead subclass {@link net.sf.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider}
|
||||||
* @author Karel Miarka
|
* @author Karel Miarka
|
||||||
*/
|
*/
|
||||||
public interface PasswordAuthenticationDao {
|
public interface PasswordAuthenticationDao {
|
|
@ -13,7 +13,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.sf.acegisecurity.providers.dao;
|
package net.sf.acegisecurity.providers.dao.ldap;
|
||||||
|
|
||||||
import net.sf.acegisecurity.AccountExpiredException;
|
import net.sf.acegisecurity.AccountExpiredException;
|
||||||
import net.sf.acegisecurity.Authentication;
|
import net.sf.acegisecurity.Authentication;
|
||||||
|
@ -25,6 +25,8 @@ import net.sf.acegisecurity.LockedException;
|
||||||
import net.sf.acegisecurity.UserDetails;
|
import net.sf.acegisecurity.UserDetails;
|
||||||
import net.sf.acegisecurity.providers.AuthenticationProvider;
|
import net.sf.acegisecurity.providers.AuthenticationProvider;
|
||||||
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
import net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider;
|
||||||
|
import net.sf.acegisecurity.providers.dao.UserCache;
|
||||||
import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
|
import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
@ -83,6 +85,7 @@ import org.springframework.util.Assert;
|
||||||
* further information.
|
* further information.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
|
* @deprecated instead subclass {@link net.sf.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider}
|
||||||
* @author Karel Miarka
|
* @author Karel Miarka
|
||||||
*/
|
*/
|
||||||
public class PasswordDaoAuthenticationProvider implements AuthenticationProvider,
|
public class PasswordDaoAuthenticationProvider implements AuthenticationProvider,
|
|
@ -24,7 +24,7 @@ import net.sf.acegisecurity.BadCredentialsException;
|
||||||
import net.sf.acegisecurity.GrantedAuthority;
|
import net.sf.acegisecurity.GrantedAuthority;
|
||||||
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
import net.sf.acegisecurity.GrantedAuthorityImpl;
|
||||||
import net.sf.acegisecurity.UserDetails;
|
import net.sf.acegisecurity.UserDetails;
|
||||||
import net.sf.acegisecurity.providers.dao.PasswordAuthenticationDao;
|
import net.sf.acegisecurity.providers.dao.ldap.PasswordAuthenticationDao;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-written version of the ACEGI LDAP code,
|
* Re-written version of the ACEGI LDAP code,
|
||||||
|
|
|
@ -13,10 +13,12 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.sf.acegisecurity.providers.dao;
|
package net.sf.acegisecurity.providers.dao.ldap;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import net.sf.acegisecurity.AccountExpiredException;
|
import net.sf.acegisecurity.AccountExpiredException;
|
||||||
import net.sf.acegisecurity.Authentication;
|
import net.sf.acegisecurity.Authentication;
|
||||||
import net.sf.acegisecurity.AuthenticationServiceException;
|
import net.sf.acegisecurity.AuthenticationServiceException;
|
||||||
|
@ -29,15 +31,15 @@ import net.sf.acegisecurity.LockedException;
|
||||||
import net.sf.acegisecurity.UserDetails;
|
import net.sf.acegisecurity.UserDetails;
|
||||||
import net.sf.acegisecurity.providers.TestingAuthenticationToken;
|
import net.sf.acegisecurity.providers.TestingAuthenticationToken;
|
||||||
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
import net.sf.acegisecurity.providers.dao.User;
|
||||||
|
import net.sf.acegisecurity.providers.dao.UserCache;
|
||||||
|
import net.sf.acegisecurity.providers.dao.UsernameNotFoundException;
|
||||||
import net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache;
|
import net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache;
|
||||||
import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
|
import net.sf.acegisecurity.providers.dao.cache.NullUserCache;
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.dao.DataRetrievalFailureException;
|
import org.springframework.dao.DataRetrievalFailureException;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link PasswordDaoAuthenticationProvider}.
|
* Tests {@link PasswordDaoAuthenticationProvider}.
|
Loading…
Reference in New Issue