package gov.va.med.authentication.kernel.sspi.authentication.manageable;

import java.util.HashMap;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
import weblogic.management.security.ProviderMBean;
import weblogic.security.provider.PrincipalValidatorImpl;
import weblogic.security.spi.AuthenticationProviderV2;
import weblogic.security.spi.IdentityAsserterV2;
import weblogic.security.spi.PrincipalValidator;
import weblogic.security.spi.SecurityServices;

import weblogic.security.principal.WLSGroupImpl;
import weblogic.security.principal.WLSUserImpl;
import weblogic.logging.NonCatalogLogger;

/**
 * The manageable authenticator's runtime implementation.
 *
 * It also provides its own login module implementation
 * (ManageableLoginModuleImpl).
 *
 * The manageable  authenticator is used in one of two modes:
 *
 * In authentation mode, it configures its login module
 * to validVate that the user's password is correct
 * and that the user exists.
 *
 * In identity assertion mode, it configures its login
 * module to just validate that the user exists.
 *
 * In either mode, it has the login module put
 * principals for the user and the user's groups into
 * the subject.
 *
 * Rather than write its own principal and principal validator
 * implementations, it uses the standard weblogic ones:
 * - weblogic.security.principal.WLSGroupImpl
 * - weblogic.security.principal.WLSUserImpl
 * - weblogic.security.provider.PrincipalValidatorImpl
 *
 * It stores the user and group definitions in a properties
 * file.  The ManageableAuthenticatorDatabase class handles
 * the properties file.  This class just delegates
 * to the database class.

 * Note: The manageable authenticator's mbean's ProviderClassName
 * attribute must be set the the name of this class.
 *
 * 
 * @author VHIT Security and Other Common Services (S&OCS)
 * @version 1.1.0.002
 */
public final class KaajeeManageableAuthenticationProviderImpl implements AuthenticationProviderV2
{
  private String                 description; // a description of this provider
  private KaajeeUserGroupDatabase      database;    // manages user and group definitions for this provider
  private LoginModuleControlFlag controlFlag; // how this provider's login module should be used during the JAAS login
  private static NonCatalogLogger sLogger = new NonCatalogLogger( "SSPI_Authentication_Providers_logs" );

  /**
   * Initialize the manageable  authenticator.
   *
   * It either creates or re-opens the file containing the
   * manageable  authenticator's user and group definitions.
   *
   * @param mbean A ProviderMBean that holds the manageable 
   * authenticator's configuration data.  This mbean must be an
   * instance of the manageable  authenticator's mbean.
   *
   * @param services The SecurityServices gives access to the auditor
   * so that the provider can to post audit events.
   *
   * @see SecurityProvider
   */
  public void initialize(ProviderMBean mbean, SecurityServices services)
  {
   // System.out.println("KaajeeManageableAuthenticationProviderImpl.initialize");
    sLogger.debug( "KaajeeManageableAuthenticationProviderImpl.initialize" );
    // Cast the mbean from a generic ProviderMBean to a ManageableAuthenticatorMBean.
	KaajeeManageableAuthenticatorMBean myMBean = (KaajeeManageableAuthenticatorMBean)mbean;

    // Set the description to the manageable  authenticator's mbean's description and version 
    description = myMBean.getDescription() + "\n" + myMBean.getVersion();

    // Get the database that manages this provider's user and group definitions.
    // Note that instead of instantiating the database, we delegate to the database
    // class.  This allows this run-time impl and the mbean impl (used for management
    // to share the same database object).
   //ESwara
	database = KaajeeUserGroupDatabase.getDatabase(myMBean);

    // Give the SecurityServices to the database.  Later on, the mbean impl will
    // get the SecurityServices from the database.  This allows the
    // mbean impl to get access to the auditor so it can post audit events.
    database.setSecurityServices(services);

    // Extract the JAAS control flag from the manageable  authenticator's mbean.
    // This flag controls how the manageable  authenticator's login module is used
    // by the JAAS login, both for authentication and for identity assertion.
    String flag = myMBean.getControlFlag();
    if (flag.equalsIgnoreCase("REQUIRED")) {
      controlFlag = LoginModuleControlFlag.REQUIRED;
    } else if (flag.equalsIgnoreCase("OPTIONAL")) {
      controlFlag = LoginModuleControlFlag.OPTIONAL;
    } else if (flag.equalsIgnoreCase("REQUISITE")) {
      controlFlag = LoginModuleControlFlag.REQUISITE;
    } else if (flag.equalsIgnoreCase("SUFFICIENT")) {
      controlFlag = LoginModuleControlFlag.SUFFICIENT;
    } else {
      throw new IllegalArgumentException("invalid flag value" + flag);
    }
  }

  /**
   * Get the manageable  authenticator's description.
   *
   * @return A String containing a brief description of the manageable  authenticator.
   *
   * @see SecurityProvider
   */
  public String getDescription()
  {
    return description;
  }

  /**
   * Shutdown the manageable  authenticator.
   *
   * A no-op.
   *
   * @see SecurityProvider
   */
  public void shutdown()
  {
    sLogger.debug( "KaajeeManageableAuthenticationProviderImpl.shutdown" );
	//System.out.println("KaajeeManageableAuthenticationProviderImpl.shutdown");
  }

  /**
   * Create a JAAS AppConfigurationEntry (which tells JAAS
   * how to create the login module and how to use it).
   * This helper method is used both for authentication mode
   * and identity assertion mode.
   *
   * @param options A HashMap containing the options to pass to the
   * manageable  authenticator's login module.  This method adds the
   * "database" object to the options.  This allows the
   * login module to access the users and groups.
   *
   * @return An AppConfigurationEntry that tells JAAS how to use the
   * manageable  authenticator's login module.
   */
  private AppConfigurationEntry getConfiguration(HashMap options)
  {
    // add the "database" object to the options so that the
    // login module can access the user and group definitions
    options.put("database", database);

    // make sure to specify the manageable  authenticator's login module
    // and to use the control flag from the manageable  authenticator's mbean.
    return new
      AppConfigurationEntry(
        "gov.va.med.authentication.kernel.sspi.authentication.manageable.KaajeeManageableLoginModuleImpl",
        controlFlag,
        options
      );
  }

  /**
   * Create a JAAS AppConfigurationEntry (which tells JAAS
   * how to create the login module and how to use it) when
   * the manageable  authenticator is used to authenticate
   * (vs. to complete identity assertion).
   *
   * @return An AppConfigurationEntry that tells JAAS how to use the
   * manageable  authenticator's login module for authentication.
   */
  public AppConfigurationEntry getLoginModuleConfiguration()
  {
    // Don't pass in any special options.
    // By default, the manageable  authenticator's login module
    // will authenticate (by checking that the passwords match).
    HashMap options = new HashMap();
    return getConfiguration(options);
  }

  /**
   * Create a JAAS AppConfigurationEntry (which tells JAAS
   * how to create the login module and how to use it) when
   * the manageable  authenticator is used to complete identity
   * assertion (vs. to authenticate).
   *
   * @return An AppConfigurationEntry that tells JAAS how to use the
   * manageable  authenticator's login module for identity assertion.
   */
  public AppConfigurationEntry getAssertionModuleConfiguration()
  {
    // Pass an option indicating that we're doing identity
    // assertion (vs. authentication) therefore the login module
    // should only check that the user exists (instead of checking
    // the password)
    HashMap options = new HashMap();
    options.put("IdentityAssertion","true");
    return getConfiguration(options);
  }

  /**
   * Return the principal validator that can validate the
   * principals that the authenticator's login module
   * puts into the subject.
   *
   * Since the manageable  authenticator uses the built in
   * WLSUserImpl and WLSGroupImpl principal classes, just
   * returns the built in PrincipalValidatorImpl that knows
   * how to handle these kinds of principals.
   *
   * @return A PrincipalValidator that can validate the
   * principals that the manageable authenticator's
   * login module puts in the subject.
   */
  public PrincipalValidator getPrincipalValidator() 
  {
    return new PrincipalValidatorImpl();
  }

  /**
   * Returns this providers identity asserter object.
   *
   * @return null since the manageable authenticator
   * doesn't support identity assertion (that is, mapping a
   * token to a user name).  Do not confuse this with using a
   * login module in identity assertion mode where the
   * login module shouldn't try to validate the user.
   */
  public IdentityAsserterV2 getIdentityAsserter()
  {
    return null;
  }
}
