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")); } } } }