/*******************************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ******************************************************************************/
package gov.va.med.esr.ui.common.action;

// Java classes
import gov.va.med.esr.service.impl.AccountAlreadyLockedException;
import gov.va.med.fw.security.AccountDisabledException;
import gov.va.med.fw.security.AccountLockedException;
import gov.va.med.fw.security.InsufficientPrivilegesException;
import gov.va.med.fw.security.InvalidPasswordException;
import gov.va.med.fw.security.PasswordChangeNotAllowedException;
import gov.va.med.fw.security.PasswordSuspendedException;
import gov.va.med.fw.security.LoginManager;
import gov.va.med.fw.security.SecurityContext;
import gov.va.med.fw.security.SecurityContextHelper;
import gov.va.med.fw.security.UserCredentials;

import java.util.Properties;

import javax.security.auth.login.AccountExpiredException;
import javax.security.auth.login.CredentialExpiredException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import weblogic.servlet.security.ServletAuthentication;

/**
 * The base class for User Admin actions.
 *
 * @author Muddaiah Ranga
 * @version: 3.0
 */
public class AbstractLogonAction extends AbstractAction
{
	protected static final String LOGON = "logon";
	protected static final String FORWARD_FAILURE = "unauthorized";
	protected static final String CHANGE_PASSWORD = "changePassword";
	protected static final String CHANGE_PASSWORD_DISPLAY = "changePasswordDisplay";
	protected static final String HOME_PAGE = "ESRHome";
	protected static final String PASSWORD_CHANGED_KEY = "passwordChangedKey";

    public static final String MESSAGE_LOGON_NOT_ATTEMPTED = "message.loginNotAttempted";
    public static final String MESSAGE_LOGON_UNAUTHORIZED = "message.logon.unauthorized";
    public static final String MESSAGE_LOGON_BAD_CREDENDIALS = "message.logon.badCredentials";
    public static final String MESSAGE_LOGON_ACCOUNT_LOCKED = "message.logon.accountLocked";
    public static final String MESSAGE_LOGON_ACCOUNT_LOCKED_WAIT = "message.logon.accountLocked.wait";
    public static final String MESSAGE_LOGON_ACCOUNT_DISABLED = "message.logon.accountDisabled";
    public static final String MESSAGE_LOGON_ACCOUNT_EXPIRED = "message.logon.accountExpire";
    public static final String MESSAGE_LOGON_PASSWORD_EXPIRED = "message.logon.passwordExpire";
    public static final String MESSAGE_LOGON_ERROR= "message.logon.loginerror";
    public static final String MESSAGE_PASSWORD_EXPIRATION_WARNING = "message.passwordExpirationWarning";
    public static final String MESSAGE_CANNOT_CHANGE_PASSWORD_PASSWORD_EXPIRED = "message.changePassword.passwordExpired";
    public static final String MESSAGE_CANNOT_CHANGE_PASSWORD_ACCOUNT_EXPIRED = "message.changePassword.accountExpired";
    public static final String MESSAGE_PASSWORD_CHANGED = "message.changePassword.passwordChanged";
    public static final String MSG_SECURITY_CODE_REQUIRED = "message.logon.agreementSignatureCodeRequired";
    public static final String MSG_SECURITY_CODE_INVALID = "message.logon.invalidLoginSecurityCode";
    public static final String MESSAGE_LOGON_PASSWORD_SUSPENDED = "message.logon.passwordSuspended";
    public static final String FLD_SECURITY_CODE = "agreementSignatureCode";
    public static final String MESSAGE_INSUFFICIENT_PRIVILEGES = "message.insufficientPrivileges";
    public static final String MESSAGE_PASSWORD_REUSE = "message.passwordReuseNotAllowed";
    public static final String MESSAGE_PASSWORD_CHANGE_NOTALLOWED = "message.passwordChangein3daysNotallowed";

	// LoginManager to perform authentication.
	protected LoginManager loginManager;

	// AuthenticationException to message key mapping.
	protected static Properties exceptionMessageProps;

	/**
	 * A default constructor
	 */
	public AbstractLogonAction()
	{
		super();
	}

	/**
	 * Return the LoginManager
	 */
	public LoginManager getLoginManager()
	{
		return loginManager;
	}

	/**
	 * Set the LoginManager
	 *
	 * @param loginManager
	 */
	public void setLoginManager(LoginManager loginManager)
	{
		this.loginManager = loginManager;
	}

	/**
	 * Return the Properties Object containing Exception to Message key mapping.
	 */
	public Properties getExceptionMessageProps()
	{
		return exceptionMessageProps;
	}

	/**
	 * Perform afterPropertiesSet operations, such as check for Null
	 * authentication manager.
	 *
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	public void afterPropertiesSet() throws Exception
	{
		if (loginManager == null)
		{
			throw new IllegalArgumentException(
					"Missing required property - LoginManager: Must be specified.");
		}
		if (getUserAdminService() == null)
		{
			throw new IllegalArgumentException(
					"Missing required property - UserAdminService: Must be specified.");
		}
		if(exceptionMessageProps == null)
		{
		    exceptionMessageProps = getExceptionMessageProperty();
		}
	}

	/**
	 * Perform authentication by delegating authentication request to the defined
	 * AuthenticationManager and sets the SecurityContext in the session.
	 *
	 * @param mapping
	 *           Struts action mapping for this action
	 * @param request
	 *           The Http Request
	 * @param userCredentials
	 *           user information
	 */
	protected void establishSecurityContext(ActionMapping mapping,
			HttpServletRequest request, UserCredentials userCredentials)
			throws LoginException
    {
		// login using login manager.
		loginManager.login(request, userCredentials);

		SecurityContext securityContext = SecurityContextHelper
				.getSecurityContext();
		// Sets a security context in a session
		setSecurityContext(request, securityContext);

	   	/*if (!isPermissionGranted(Capability.LOGIN_INTO_SYSTEM.getName())) {
    		//User doesn't have login permission
    		loginManager.logout();
    		throw new InsufficientPrivilegesException();
    	}*/
	}

    /**
     * Perform all necessary signout processing.
     * @param request The HttpServletRequest
     * @throws Exception if any problems were encountered
     */
    public void processSignout(HttpServletRequest request) throws Exception{
        processSignout(request,null);
    }
    public void processSignout(HttpServletRequest request, String logicalId) throws Exception
    {
        // Clean application data in a session and invalidate it
        cleanSandbox(request);

        // Logout using login manager.
        if (logicalId != null)
            loginManager.loginAnonymous(logicalId);
        //CCR13343 SSOi integration
        /*else {
            //loginManager.loginAnonymous();
        }*/

		HttpSession session = request.getSession(false);
		if (session != null) {
		    session.invalidate();
		}

        // Log a user out
        ServletAuthentication.logout(request);
    }

	/**
	 * Get the action message mapped to the AuthenticationException.
	 *
	 * @param ae
	 * @return ActionMessage
	 */
	protected ActionMessage getActionMessage(LoginException ae)
	{
		String exceptionName = ae.getClass().getName();
		Properties props = getExceptionMessageProps();
		return new ActionMessage(props.getProperty(exceptionName,MESSAGE_LOGON_ERROR));
	}

	/**
	 * Return a default mapping for AuthenticationException to Struts Resource
	 * Message key.
	 */
	protected Properties getExceptionMessageProperty()
	{
		Properties props = new Properties();
		props.setProperty(FailedLoginException.class.getName(),MESSAGE_LOGON_BAD_CREDENDIALS);
		props.setProperty(CredentialExpiredException.class.getName(),MESSAGE_LOGON_PASSWORD_EXPIRED);
		props.setProperty(AccountLockedException.class.getName(),MESSAGE_LOGON_ACCOUNT_LOCKED);
		props.setProperty(AccountAlreadyLockedException.class.getName(),MESSAGE_LOGON_ACCOUNT_LOCKED_WAIT);
		props.setProperty(AccountExpiredException.class.getName(),MESSAGE_LOGON_ACCOUNT_EXPIRED);
		props.setProperty(AccountDisabledException.class.getName(),MESSAGE_LOGON_ACCOUNT_DISABLED);
        props.setProperty(PasswordSuspendedException.class.getName(),MESSAGE_LOGON_PASSWORD_SUSPENDED);
        props.setProperty(InsufficientPrivilegesException.class.getName(),MESSAGE_INSUFFICIENT_PRIVILEGES);
        props.setProperty(InvalidPasswordException.class.getName(),MESSAGE_PASSWORD_REUSE);
        props.setProperty(PasswordChangeNotAllowedException.class.getName(),MESSAGE_PASSWORD_CHANGE_NOTALLOWED);
		return props;
	}
}