package gov.va.med.edp.springframework.security.providers.vistalink; import gov.va.med.edp.springframework.security.userdetails.VistaUserDetails; import gov.va.med.edp.springframework.security.userdetails.VistaUserDetailsService; import org.springframework.security.*; import org.springframework.security.providers.AuthenticationProvider; import org.springframework.security.providers.dao.UserCache; import org.springframework.security.providers.dao.cache.NullUserCache; 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.dao.DataAccessException; import org.springframework.util.Assert; public class VistaAuthenticationProvider implements AuthenticationProvider, MessageSourceAware, InitializingBean { protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); private UserCache userCache = new NullUserCache(); private VistaUserDetailsService userDetailsService; 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"); Assert.notNull(this.userDetailsService, "A VistaUserDetailsService must be set"); } public Authentication authenticate(Authentication authentication) throws AuthenticationException { Assert.isInstanceOf(VistaAuthenticationToken.class, authentication, messages.getMessage("VistaAuthenticationProvider.onlySupports", "Only VistaAuthenticationToken is supported")); VistaAuthenticationToken auth = (VistaAuthenticationToken) authentication; String username = auth.getName(); boolean cacheWasUsed = true; VistaUserDetails user = (VistaUserDetails) this.userCache.getUserFromCache(username); if (user == null) { cacheWasUsed = false; user = retrieveUser(auth); Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract"); } if (!user.isAccountNonLocked()) { throw new LockedException(messages.getMessage("VistaAuthenticationProvider.locked", "User account is locked")); } if (!user.isEnabled()) { throw new DisabledException(messages.getMessage("VistaAuthenticationProvider.disabled", "User is disabled")); } if (!user.isAccountNonExpired()) { throw new AccountExpiredException(messages.getMessage("VistaAuthenticationProvider.expired", "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, auth); } catch (AuthenticationException exception) { if (cacheWasUsed) { // There was a problem, so try again after checking // we're using latest data (ie not from the cache) cacheWasUsed = false; user = retrieveUser(auth); additionalAuthenticationChecks(user, auth); } else { throw exception; } } if (!user.isCredentialsNonExpired()) { throw new CredentialsExpiredException(messages.getMessage( "VistaAuthenticationProvider.credentialsExpired", "User credentials have expired")); } if (!cacheWasUsed) { this.userCache.putUserInCache(user); } return createSuccessAuthentication(user, auth); } protected void additionalAuthenticationChecks(VistaUserDetails userDetails, VistaAuthenticationToken authentication) throws AuthenticationException { // Object salt = null; // // if (this.saltSource != null) { // salt = this.saltSource.getSalt(userDetails); // } // if (authentication.getCredentials() == null) { throw new BadCredentialsException(messages.getMessage( "VistaAuthenticationProvider.badCredentials", "Bad credentials"), userDetails); } // // String presentedPassword = authentication.getCredentials() == null ? "" : authentication.getCredentials() // .toString(); // // if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) { // throw new BadCredentialsException(messages.getMessage( // "VistaAuthenticationProvider.badCredentials", "Bad credentials"), // includeDetailsObject ? userDetails : null); // } } protected Authentication createSuccessAuthentication(VistaUserDetails user, VistaAuthenticationToken authentication) { return new VistaAuthenticationToken(user, authentication.getAccessCode(), authentication.getVerifyCode(), authentication.getRemoteAddress(), user.getAuthorities()); } public void setMessageSource(MessageSource messageSource) { this.messages = new MessageSourceAccessor(messageSource); } public void setUserCache(UserCache userCache) { this.userCache = userCache; } public boolean supports(Class authentication) { return VistaAuthenticationToken.class.isAssignableFrom(authentication); } public VistaUserDetailsService getUserDetailsService() { return userDetailsService; } protected final VistaUserDetails retrieveUser(VistaAuthenticationToken authentication) throws AuthenticationException { VistaUserDetails loadedUser; try { loadedUser = this.getUserDetailsService().login(authentication.getStationNumber(), authentication.getAccessCode(), authentication.getVerifyCode(), authentication.getRemoteAddress()); } catch (DataAccessException repositoryProblem) { throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem); } if (loadedUser == null) { throw new AuthenticationServiceException( "VistaUserDetailsService returned null, which is an interface contract violation"); } return loadedUser; } public void setUserDetailsService(VistaUserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } public UserCache getUserCache() { return userCache; } }