package com.mzl.flower.config.security.provider;
|
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSourceAware;
|
import org.springframework.context.support.MessageSourceAccessor;
|
import org.springframework.security.authentication.*;
|
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.SpringSecurityMessageSource;
|
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
import org.springframework.security.core.userdetails.UserCache;
|
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetailsChecker;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.cache.NullUserCache;
|
import org.springframework.util.Assert;
|
|
@Slf4j
|
public abstract class SelfAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
|
|
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
private UserCache userCache = new NullUserCache();
|
private boolean forcePrincipalAsString = false;
|
protected boolean hideUserNotFoundExceptions = true;
|
private UserDetailsChecker preAuthenticationChecks = new DefaultPreAuthenticationChecks();
|
private UserDetailsChecker postAuthenticationChecks = new DefaultPostAuthenticationChecks();
|
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
|
|
|
protected abstract void additionalAuthenticationChecks(UserDetails userDetails,
|
Authentication authentication)
|
throws AuthenticationException;
|
|
@Override
|
public void afterPropertiesSet() throws Exception {
|
Assert.notNull(this.userCache, "A user cache must be set");
|
Assert.notNull(this.messages, "A message source must be set");
|
doAfterPropertiesSet();
|
}
|
|
@Override
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();
|
|
boolean cacheWasUsed = true;
|
UserDetails user = this.userCache.getUserFromCache(username);
|
|
if (user == null) {
|
cacheWasUsed = false;
|
|
try {
|
user = retrieveUser(username, authentication);
|
}
|
catch (UsernameNotFoundException notFound) {
|
log.debug("User '" + username + "' not found");
|
|
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");
|
}
|
|
try {
|
preAuthenticationChecks.check(user);
|
additionalAuthenticationChecks(user, authentication);
|
}
|
catch (AuthenticationException exception) {
|
if (cacheWasUsed) {
|
cacheWasUsed = false;
|
user = retrieveUser(username, authentication);
|
preAuthenticationChecks.check(user);
|
additionalAuthenticationChecks(user, authentication);
|
}
|
else {
|
throw exception;
|
}
|
}
|
|
postAuthenticationChecks.check(user);
|
|
if (!cacheWasUsed) {
|
this.userCache.putUserInCache(user);
|
}
|
|
Object principalToReturn = user;
|
|
if (forcePrincipalAsString) {
|
principalToReturn = user.getUsername();
|
}
|
|
return createSuccessAuthentication(principalToReturn, authentication, user);
|
}
|
|
protected abstract Authentication createSuccessAuthentication(Object principal,
|
Authentication authentication, UserDetails user);
|
|
protected void doAfterPropertiesSet() throws Exception {
|
}
|
|
public UserCache getUserCache() {
|
return userCache;
|
}
|
|
public boolean isForcePrincipalAsString() {
|
return forcePrincipalAsString;
|
}
|
|
public boolean isHideUserNotFoundExceptions() {
|
return hideUserNotFoundExceptions;
|
}
|
|
protected abstract UserDetails retrieveUser(String username, Authentication authentication) throws AuthenticationException;
|
|
public void setForcePrincipalAsString(boolean forcePrincipalAsString) {
|
this.forcePrincipalAsString = forcePrincipalAsString;
|
}
|
|
public void setHideUserNotFoundExceptions(boolean hideUserNotFoundExceptions) {
|
this.hideUserNotFoundExceptions = hideUserNotFoundExceptions;
|
}
|
|
public void setMessageSource(MessageSource messageSource) {
|
this.messages = new MessageSourceAccessor(messageSource);
|
}
|
|
public void setUserCache(UserCache userCache) {
|
this.userCache = userCache;
|
}
|
|
protected UserDetailsChecker getPreAuthenticationChecks() {
|
return preAuthenticationChecks;
|
}
|
|
public void setPreAuthenticationChecks(UserDetailsChecker preAuthenticationChecks) {
|
this.preAuthenticationChecks = preAuthenticationChecks;
|
}
|
|
protected UserDetailsChecker getPostAuthenticationChecks() {
|
return postAuthenticationChecks;
|
}
|
|
public void setPostAuthenticationChecks(UserDetailsChecker postAuthenticationChecks) {
|
this.postAuthenticationChecks = postAuthenticationChecks;
|
}
|
|
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
this.authoritiesMapper = authoritiesMapper;
|
}
|
|
private class DefaultPreAuthenticationChecks implements UserDetailsChecker {
|
public void check(UserDetails user) {
|
if (!user.isAccountNonLocked()) {
|
log.debug("User account is locked");
|
|
throw new LockedException(messages.getMessage(
|
"AbstractUserDetailsAuthenticationProvider.locked",
|
"User account is locked"));
|
}
|
|
if (!user.isEnabled()) {
|
log.debug("User account is disabled");
|
|
throw new DisabledException(messages.getMessage(
|
"AbstractUserDetailsAuthenticationProvider.disabled",
|
"User is disabled"));
|
}
|
|
if (!user.isAccountNonExpired()) {
|
log.debug("User account is expired");
|
|
throw new AccountExpiredException(messages.getMessage(
|
"AbstractUserDetailsAuthenticationProvider.expired",
|
"User account has expired"));
|
}
|
}
|
}
|
|
private class DefaultPostAuthenticationChecks implements UserDetailsChecker {
|
public void check(UserDetails user) {
|
if (!user.isCredentialsNonExpired()) {
|
log.debug("User account credentials have expired");
|
|
throw new CredentialsExpiredException(messages.getMessage(
|
"AbstractUserDetailsAuthenticationProvider.credentialsExpired",
|
"User credentials have expired"));
|
}
|
}
|
}
|
}
|