package com.ym.mec.auth.core.provider;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.AccountExpiredException;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
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;

public abstract class AbstractAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {

	protected final Log logger = LogFactory.getLog(this.getClass());
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	private UserCache userCache = new NullUserCache();
	private boolean forcePrincipalAsString = false;
	protected boolean hideUserNotFoundExceptions = true;
	private UserDetailsChecker preAuthenticationChecks = new AbstractAuthenticationProvider.DefaultPreAuthenticationChecks();
	private UserDetailsChecker postAuthenticationChecks = new AbstractAuthenticationProvider.DefaultPostAuthenticationChecks();

	protected abstract void additionalAuthenticationChecks(UserDetails var1, Authentication var2) throws AuthenticationException;

	public final void afterPropertiesSet() throws Exception {
		Assert.notNull(this.userCache, "A user cache must be set");
		Assert.notNull(this.messages, "A message source must be set");
		this.doAfterPropertiesSet();
	}

	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 = this.retrieveUser(username, authentication);
			} catch (UsernameNotFoundException var6) {
				this.logger.debug("User \'" + username + "\' not found");
				if (this.hideUserNotFoundExceptions) {
					throw new BadCredentialsException(this.messages.getMessage("MyAbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
				}

				throw var6;
			}

			Assert.notNull(user, "retrieveUser returned null - a violation of the interface contract");
		}

		try {
			this.preAuthenticationChecks.check(user);
			this.additionalAuthenticationChecks(user, authentication);
		} catch (AuthenticationException var7) {
			if (!cacheWasUsed) {
				throw var7;
			}

			cacheWasUsed = false;
			user = this.retrieveUser(username, authentication);
			this.preAuthenticationChecks.check(user);
			this.additionalAuthenticationChecks(user, authentication);
		}

		this.postAuthenticationChecks.check(user);
		if (!cacheWasUsed) {
			this.userCache.putUserInCache(user);
		}

		Object principalToReturn = user;
		if (this.forcePrincipalAsString) {
			principalToReturn = user.getUsername();
		}

		return this.createSuccessAuthentication(principalToReturn, authentication, user);
	}

	protected abstract Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user);

	protected void doAfterPropertiesSet() throws Exception {
	}

	public UserCache getUserCache() {
		return this.userCache;
	}

	public boolean isForcePrincipalAsString() {
		return this.forcePrincipalAsString;
	}

	public boolean isHideUserNotFoundExceptions() {
		return this.hideUserNotFoundExceptions;
	}

	protected abstract UserDetails retrieveUser(String var1, Authentication var2) 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 this.preAuthenticationChecks;
	}

	public void setPreAuthenticationChecks(UserDetailsChecker preAuthenticationChecks) {
		this.preAuthenticationChecks = preAuthenticationChecks;
	}

	protected UserDetailsChecker getPostAuthenticationChecks() {
		return this.postAuthenticationChecks;
	}

	public void setPostAuthenticationChecks(UserDetailsChecker postAuthenticationChecks) {
		this.postAuthenticationChecks = postAuthenticationChecks;
	}

	private class DefaultPostAuthenticationChecks implements UserDetailsChecker {
		private DefaultPostAuthenticationChecks() {
		}

		public void check(UserDetails user) {
			if (!user.isCredentialsNonExpired()) {
				throw new CredentialsExpiredException("User account credentials have expired");
			}
		}
	}

	private class DefaultPreAuthenticationChecks implements UserDetailsChecker {
		private DefaultPreAuthenticationChecks() {
		}

		public void check(UserDetails user) {
			if (!user.isAccountNonLocked()) {
				throw new LockedException("User account is locked");
			} else if (!user.isEnabled()) {
				throw new DisabledException("User account is disabled");
			} else if (!user.isAccountNonExpired()) {
				throw new AccountExpiredException("User account is expired");
			}
		}
	}
}
