Pull functionality for hiding UsernameNotFoundException's up into AbstractUserDetailsAuthenticationProvider.

This commit is contained in:
Luke Taylor 2005-12-19 17:23:34 +00:00
parent 929b08c085
commit 9554dc50bc
2 changed files with 80 additions and 70 deletions

View File

@ -22,11 +22,13 @@ import org.acegisecurity.AuthenticationException;
import org.acegisecurity.CredentialsExpiredException;
import org.acegisecurity.DisabledException;
import org.acegisecurity.LockedException;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.providers.AuthenticationProvider;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.dao.cache.NullUserCache;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
@ -73,6 +75,7 @@ public abstract class AbstractUserDetailsAuthenticationProvider
protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
private UserCache userCache = new NullUserCache();
private boolean forcePrincipalAsString = false;
protected boolean hideUserNotFoundExceptions = true;
//~ Methods ================================================================
@ -123,8 +126,21 @@ public abstract class AbstractUserDetailsAuthenticationProvider
if (user == null) {
cacheWasUsed = false;
user = retrieveUser(username,
try {
user = retrieveUser(username,
(UsernamePasswordAuthenticationToken) authentication);
} catch (UsernameNotFoundException notFound) {
if (hideUserNotFoundExceptions) {
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
} else {
throw notFound;
}
}
Assert.notNull(user,
"retrieveUser returned null - a violation of the interface contract");
}
@ -292,4 +308,28 @@ public abstract class AbstractUserDetailsAuthenticationProvider
public boolean supports(Class authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
public boolean isHideUserNotFoundExceptions() {
return hideUserNotFoundExceptions;
}
/**
* By default the <code>AbstractUserDetailsAuthenticationProvider</code>
* throws a <code>BadCredentialsException</code> if a username is
* not found or the password is incorrect. Setting this property to
* <code>false</code> will cause
* <code>UsernameNotFoundException</code>s to be thrown instead for
* the former. Note this is considered less secure than throwing
* <code>BadCredentialsException</code> for both exceptions.
*
* @param hideUserNotFoundExceptions set to <code>false</code> if you
* wish <code>UsernameNotFoundException</code>s to be thrown
* instead of the non-specific
* <code>BadCredentialsException</code> (defaults to
* <code>true</code>)
*/
public void setHideUserNotFoundExceptions(
boolean hideUserNotFoundExceptions) {
this.hideUserNotFoundExceptions = hideUserNotFoundExceptions;
}
}

View File

@ -35,6 +35,9 @@ import org.springframework.util.Assert;
/**
* An {@link AuthenticationProvider} implementation that retrieves user details
* from an {@link UserDetailsService}.
*
* @author Ben Alex
* @version $Id$
*/
public class DaoAuthenticationProvider
extends AbstractUserDetailsAuthenticationProvider {
@ -43,7 +46,6 @@ public class DaoAuthenticationProvider
private UserDetailsService userDetailsService;
private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
private SaltSource saltSource;
private boolean hideUserNotFoundExceptions = true;
//~ Methods ================================================================
@ -81,83 +83,51 @@ public class DaoAuthenticationProvider
return saltSource;
}
public boolean isHideUserNotFoundExceptions() {
return hideUserNotFoundExceptions;
}
protected final UserDetails retrieveUser(String username,
UsernamePasswordAuthenticationToken authentication)
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
UserDetails loadedUser;
try {
loadedUser = this.userDetailsService.loadUserByUsername(username);
} catch (UsernameNotFoundException notFound) {
if (hideUserNotFoundExceptions) {
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
} else {
throw notFound;
}
} catch (DataAccessException repositoryProblem) {
throw new AuthenticationServiceException(repositoryProblem
.getMessage(), repositoryProblem);
}
throw new AuthenticationServiceException(
repositoryProblem.getMessage(), repositoryProblem );
}
if (loadedUser == null) {
throw new AuthenticationServiceException(
if (loadedUser == null) {
throw new AuthenticationServiceException(
"AuthenticationDao returned null, which is an interface contract violation");
}
return loadedUser;
}
public void setUserDetailsService(UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
}
/**
* By default the <code>DaoAuthenticationProvider</code> throws a
* <code>BadCredentialsException</code> if a username is not found or
* the password is incorrect. Setting this property to
* <code>false</code> will cause
* <code>UsernameNotFoundException</code>s to be thrown instead for
* the former. Note this is considered less secure than throwing
* <code>BadCredentialsException</code> for both exceptions.
*
* @param hideUserNotFoundExceptions set to <code>false</code> if you
* wish <code>UsernameNotFoundException</code>s to be thrown
* instead of the non-specific
* <code>BadCredentialsException</code> (defaults to
* <code>true</code>)
*/
public void setHideUserNotFoundExceptions(
boolean hideUserNotFoundExceptions) {
this.hideUserNotFoundExceptions = hideUserNotFoundExceptions;
}
/**
* Sets the PasswordEncoder instance to be used to encode and validate
* passwords. If not set, {@link PlaintextPasswordEncoder} will be
* used by default.
*
* @param passwordEncoder The passwordEncoder to use
*/
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
/**
* The source of salts to use when decoding passwords.
* <code>null</code> is a valid value, meaning the
* <code>DaoAuthenticationProvider</code> will present
* <code>null</code> to the relevant <code>PasswordEncoder</code>.
*
* @param saltSource to use when attempting to decode passwords via the
* <code>PasswordEncoder</code>
*/
public void setSaltSource(SaltSource saltSource) {
this.saltSource = saltSource;
}
return loadedUser;
}
public void setUserDetailsService(UserDetailsService authenticationDao) {
this.userDetailsService = authenticationDao;
}
/**
* Sets the PasswordEncoder instance to be used to encode and validate
* passwords. If not set, {@link PlaintextPasswordEncoder} will be
* used by default.
*
* @param passwordEncoder The passwordEncoder to use
*/
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
/**
* The source of salts to use when decoding passwords.
* <code>null</code> is a valid value, meaning the
* <code>DaoAuthenticationProvider</code> will present
* <code>null</code> to the relevant <code>PasswordEncoder</code>.
*
* @param saltSource to use when attempting to decode passwords via the
* <code>PasswordEncoder</code>
*/
public void setSaltSource(SaltSource saltSource) {
this.saltSource = saltSource;
}
}