mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
18.43.2011 c9da9e4bd4a115a646dfb846972126ca8eef1158
opends/src/server/org/opends/server/core/PasswordPolicy.java
@@ -23,43 +23,20 @@
 *
 *
 *      Copyright 2006-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS.
 */
package org.opends.server.core;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import org.opends.messages.Message;
import org.opends.server.admin.std.meta.PasswordPolicyCfgDefn;
import org.opends.server.admin.std.server.PasswordPolicyCfg;
import org.opends.server.admin.std.server.PasswordValidatorCfg;
import org.opends.server.api.AccountStatusNotificationHandler;
import org.opends.server.api.PasswordGenerator;
import org.opends.server.api.PasswordStorageScheme;
import org.opends.server.api.PasswordValidator;
import org.opends.server.config.ConfigException;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.schema.GeneralizedTimeSyntax;
import org.opends.server.types.*;
import static org.opends.messages.CoreMessages.*;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.schema.SchemaConstants.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import org.opends.server.admin.std.meta.PasswordPolicyCfgDefn.*;
import org.opends.server.api.*;
import org.opends.server.types.AttributeType;
@@ -67,661 +44,15 @@
 * This class defines a data structure that holds information about a Directory
 * Server password policy.
 */
public class PasswordPolicy
public abstract class PasswordPolicy extends AuthenticationPolicy
{
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = getTracer();
  // The DN of the entry containing the configuration for this password
  // policy.
  private final DN configEntryDN;
  // The attribute type that will hold user passwords for this password policy.
  private final AttributeType passwordAttribute;
  // Indicates whether the attribute type uses the authPassword syntax.
  private final boolean authPasswordSyntax;
  // Indicates whether a user with an expired password will still be allowed to
  // change it via the password modify extended operation.
  private boolean allowExpiredPasswordChanges =
       DEFAULT_PWPOLICY_ALLOW_EXPIRED_CHANGES;
  // Indicates whether the password attribute will be allowed to have multiple
  // distinct values.
  private boolean allowMultiplePasswordValues =
       DEFAULT_PWPOLICY_ALLOW_MULTIPLE_PW_VALUES;
  // Indicates whether to allow pre-encoded passwords.
  private boolean allowPreEncodedPasswords =
       DEFAULT_PWPOLICY_ALLOW_PRE_ENCODED_PASSWORDS;
  // Indicates whether users will be allowed to change their passwords.
  private boolean allowUserPasswordChanges =
       DEFAULT_PWPOLICY_ALLOW_USER_CHANGE;
  // Indicates whether to allow a password to expire without ever providing the
  // user with a notification.
  private boolean expirePasswordsWithoutWarning =
       DEFAULT_PWPOLICY_EXPIRE_WITHOUT_WARNING;
  // Indicates whether users must change their passwords the first time they
  // authenticate after their account is created.
  private boolean forceChangeOnAdd =
       DEFAULT_PWPOLICY_FORCE_CHANGE_ON_ADD;
  // Indicates whether a user must change their password after it has been reset
  // by an administrator.
  private boolean forceChangeOnReset =
       DEFAULT_PWPOLICY_FORCE_CHANGE_ON_RESET;
  // Indicates whether a user must provide their current password in order to
  // use a new password.
  private boolean requireCurrentPassword =
       DEFAULT_PWPOLICY_REQUIRE_CURRENT_PASSWORD;
  // Indicates whether users will be required to authenticate using a secure
  // mechanism.
  private boolean requireSecureAuthentication =
       DEFAULT_PWPOLICY_REQUIRE_SECURE_AUTHENTICATION;
  // Indicates whether users will be required to change their passwords using a
  // secure mechanism.
  private boolean requireSecurePasswordChanges =
       DEFAULT_PWPOLICY_REQUIRE_SECURE_PASSWORD_CHANGES;
  // Indicates whether password validation should be performed for
  // administrative password changes.
  private boolean skipValidationForAdministrators =
       DEFAULT_PWPOLICY_SKIP_ADMIN_VALIDATION;
  // The set of account status notification handlers for this password policy.
  private ConcurrentHashMap<DN, AccountStatusNotificationHandler<?>>
    notificationHandlers;
  // The set of password validators that will be used with this
  // password policy.
  private ConcurrentHashMap<DN, PasswordValidator<?>> passwordValidators;
  // The set of default password storage schemes for this password
  // policy.
  private CopyOnWriteArrayList<PasswordStorageScheme<?>> defaultStorageSchemes =
    new CopyOnWriteArrayList<PasswordStorageScheme<?>>();
  {
    PasswordStorageScheme<?> defaultScheme =
      DirectoryServer.getPasswordStorageScheme(DEFAULT_PASSWORD_STORAGE_SCHEME);
    if (defaultScheme != null) defaultStorageSchemes.add(defaultScheme);
  }
  // DNs of password storage schemes for this password policy.
  private SortedSet<DN> storageSchemeDNs = new TreeSet<DN>();
  // The names of the deprecated password storage schemes for this password
  // policy.
  private CopyOnWriteArraySet<String> deprecatedStorageSchemes =
       new CopyOnWriteArraySet<String>();
  // DNs of deprecated password storage schemes for this password policy.
  private SortedSet<DN> deprecatedStorageSchemeDNs = new TreeSet<DN>();
  // The DN of the password validator for this password policy.
  private DN passwordGeneratorDN = null;
  // The password generator for use with this password policy.
  private PasswordGenerator<?> passwordGenerator = null;
  // The number of grace logins that a user may have.
  private int graceLoginCount = DEFAULT_PWPOLICY_GRACE_LOGIN_COUNT;
  // The number of passwords to keep in the history.
  private int historyCount = DEFAULT_PWPOLICY_HISTORY_COUNT;
  // The maximum length of time in seconds to keep passwords in the history.
  private int historyDuration = DEFAULT_PWPOLICY_HISTORY_DURATION;
  // The maximum length of time in seconds that an account may remain idle
  // before it is locked out.
  private int idleLockoutInterval = DEFAULT_PWPOLICY_IDLE_LOCKOUT_INTERVAL;
  // The length of time a user should stay locked out, in seconds.
  private int lockoutDuration = DEFAULT_PWPOLICY_LOCKOUT_DURATION;
  // The number of authentication failures before an account is locked out.
  private int lockoutFailureCount = DEFAULT_PWPOLICY_LOCKOUT_FAILURE_COUNT;
  // The length of time that authentication failures should be counted against
  // a user.
  private int lockoutFailureExpirationInterval =
       DEFAULT_PWPOLICY_LOCKOUT_FAILURE_EXPIRATION_INTERVAL;
  // The maximum password age (i.e., expiration interval), in seconds.
  private int maximumPasswordAge = DEFAULT_PWPOLICY_MAXIMUM_PASSWORD_AGE;
  // The maximum password age for administratively reset passwords, in seconds.
  private int maximumPasswordResetAge =
       DEFAULT_PWPOLICY_MAXIMUM_PASSWORD_RESET_AGE;
  // The minimum password age, in seconds.
  private int minimumPasswordAge = DEFAULT_PWPOLICY_MINIMUM_PASSWORD_AGE;
  // The password expiration warning interval, in seconds.
  private int warningInterval = DEFAULT_PWPOLICY_WARNING_INTERVAL;
  // The the time by which all users will be required to change their passwords.
  private long requireChangeByTime = -1L;
  // The attribute type that will hold the last login time.
  private AttributeType lastLoginTimeAttribute = null;
  // The format string to use when generating the last login time.
  private String lastLoginTimeFormat = null;
  // The set of previous last login time format strings.
  private CopyOnWriteArrayList<String> previousLastLoginTimeFormats =
       new CopyOnWriteArrayList<String>();
  // The state update failure policy.
  private PasswordPolicyCfgDefn.StateUpdateFailurePolicy
       stateUpdateFailurePolicy =
            PasswordPolicyCfgDefn.StateUpdateFailurePolicy.REACTIVE;
  /**
   * Creates a new password policy based on the configuration contained in the
   * provided configuration entry.  Any parameters not included in the provided
   * configuration entry will be assigned server-wide default values.
   *
   * @param  configuration  The configuration with the information to use to
   *                      initialize this password policy.
   *
   * @throws  ConfigException  If the provided entry does not contain a valid
   *                           password policy configuration.
   *
   * @throws  InitializationException  If an error occurs while initializing the
   *                                   password policy that is not related to
   *                                   the server configuration.
   * Creates a new password policy.
   */
  public PasswordPolicy(PasswordPolicyCfg configuration)
         throws ConfigException, InitializationException
  protected PasswordPolicy()
  {
    // Create a list of units and values that we can use to represent time
    // periods.
    LinkedHashMap<String,Double> timeUnits = new LinkedHashMap<String,Double>();
    timeUnits.put(TIME_UNIT_SECONDS_ABBR, 1D);
    timeUnits.put(TIME_UNIT_SECONDS_FULL, 1D);
    timeUnits.put(TIME_UNIT_MINUTES_ABBR, 60D);
    timeUnits.put(TIME_UNIT_MINUTES_FULL, 60D);
    timeUnits.put(TIME_UNIT_HOURS_ABBR, (double) (60 * 60));
    timeUnits.put(TIME_UNIT_HOURS_FULL, (double) (60 * 60));
    timeUnits.put(TIME_UNIT_DAYS_ABBR, (double) (60 * 60 * 24));
    timeUnits.put(TIME_UNIT_DAYS_FULL, (double) (60 * 60 * 24));
    timeUnits.put(TIME_UNIT_WEEKS_ABBR, (double) (60 * 60 * 24 * 7));
    timeUnits.put(TIME_UNIT_WEEKS_FULL, (double) (60 * 60 * 24 * 7));
    this.configEntryDN = configuration.dn();
    // Get the password attribute.  If specified, it must have either the
    // user password or auth password syntax.
    passwordAttribute = configuration.getPasswordAttribute();
    String syntaxOID = passwordAttribute.getSyntaxOID();
    if (syntaxOID.equals(SYNTAX_AUTH_PASSWORD_OID))
    {
      authPasswordSyntax = true;
    }
    else if (syntaxOID.equals(SYNTAX_USER_PASSWORD_OID))
    {
      authPasswordSyntax = false;
    }
    else
    {
      String syntax = passwordAttribute.getSyntax().getSyntaxName();
      if ((syntax == null) || (syntax.length() == 0))
      {
        syntax = syntaxOID;
      }
      Message message = ERR_PWPOLICY_INVALID_PASSWORD_ATTRIBUTE_SYNTAX.
          get(String.valueOf(configEntryDN), passwordAttribute.getNameOrOID(),
              String.valueOf(syntax));
      throw new ConfigException(message);
    }
    // Get the default storage schemes.  They must all reference valid storage
    // schemes that support the syntax for the specified password attribute.
    storageSchemeDNs =
      configuration.getDefaultPasswordStorageSchemeDNs();
    try
    {
      LinkedList<PasswordStorageScheme<?>> schemes =
        new LinkedList<PasswordStorageScheme<?>>();
      for (DN configEntryDN : storageSchemeDNs)
      {
        PasswordStorageScheme<?> scheme =
          DirectoryServer.getPasswordStorageScheme(configEntryDN);
        if (this.authPasswordSyntax &&
            (! scheme.supportsAuthPasswordSyntax()))
        {
          Message message = ERR_PWPOLICY_SCHEME_DOESNT_SUPPORT_AUTH.get(
              String.valueOf(configEntryDN),
              this.passwordAttribute.getNameOrOID());
          throw new ConfigException(message);
        }
        schemes.add(scheme);
      }
      this.defaultStorageSchemes =
        new CopyOnWriteArrayList<PasswordStorageScheme<?>>(schemes);
    }
    catch (ConfigException ce)
    {
      throw ce;
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_PWPOLICY_CANNOT_DETERMINE_DEFAULT_STORAGE_SCHEMES.
          get(String.valueOf(configEntryDN), getExceptionMessage(e));
      throw new InitializationException(message, e);
    }
    // Get the names of the deprecated storage schemes.
    deprecatedStorageSchemeDNs =
      configuration.getDeprecatedPasswordStorageSchemeDNs();
    try
    {
      LinkedHashSet<String> newDeprecatedStorageSchemes =
        new LinkedHashSet<String>();
      for (DN schemeDN : deprecatedStorageSchemeDNs)
      {
        PasswordStorageScheme<?> scheme =
          DirectoryServer.getPasswordStorageScheme(schemeDN);
        if (this.authPasswordSyntax)
        {
          if (scheme.supportsAuthPasswordSyntax())
          {
            newDeprecatedStorageSchemes.add(
                scheme.getAuthPasswordSchemeName());
          }
          else
          {
            Message message = ERR_PWPOLICY_DEPRECATED_SCHEME_NOT_AUTH.get(
                String.valueOf(configEntryDN),
                String.valueOf(schemeDN));
            throw new ConfigException(message);
          }
        }
        else
        {
          newDeprecatedStorageSchemes.add(
              toLowerCase(scheme.getStorageSchemeName()));
        }
      }
      this.deprecatedStorageSchemes =
        new CopyOnWriteArraySet<String>(newDeprecatedStorageSchemes);
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message =
          ERR_PWPOLICY_CANNOT_DETERMINE_DEPRECATED_STORAGE_SCHEMES.
            get(String.valueOf(configEntryDN), getExceptionMessage(e));
      throw new InitializationException(message, e);
    }
    // Get the password validators.
    SortedSet<DN> passwordValidators = configuration.getPasswordValidatorDNs();
    ConcurrentHashMap<DN, PasswordValidator<?>> validators =
      new ConcurrentHashMap<DN, PasswordValidator<?>>();
    for (DN validatorDN : passwordValidators)
    {
      validators.put(validatorDN,
          DirectoryServer.getPasswordValidator(validatorDN));
    }
    this.passwordValidators = validators;
    // Get the status notification handlers.
    SortedSet<DN> statusNotificationHandlers =
      configuration.getAccountStatusNotificationHandlerDNs();
    ConcurrentHashMap<DN,AccountStatusNotificationHandler<?>> handlers =
      new ConcurrentHashMap<DN,AccountStatusNotificationHandler<?>>();
    for (DN handlerDN : statusNotificationHandlers)
    {
      AccountStatusNotificationHandler<?> handler =
        DirectoryServer.getAccountStatusNotificationHandler(handlerDN);
      handlers.put(handlerDN, handler);
    }
    this.notificationHandlers = handlers;
    // Determine whether to allow user password changes.
    this.allowUserPasswordChanges = configuration.isAllowUserPasswordChanges();
    // Determine whether to require the current password for user changes.
    this.requireCurrentPassword =
      configuration.isPasswordChangeRequiresCurrentPassword();
    // Determine whether to force password changes on add.
    this.forceChangeOnAdd = configuration.isForceChangeOnAdd();
    // Determine whether to force password changes on reset.
    this.forceChangeOnReset = configuration.isForceChangeOnReset();
    // Determine whether to validate reset passwords.
    this.skipValidationForAdministrators =
      configuration.isSkipValidationForAdministrators();
    // Get the password generator.
    DN passGenDN = configuration.getPasswordGeneratorDN() ;
    if (passGenDN != null)
    {
      this.passwordGeneratorDN = passGenDN;
      this.passwordGenerator = DirectoryServer.getPasswordGenerator(passGenDN);
    }
    // Determine whether to require secure authentication.
    this.requireSecureAuthentication =
      configuration.isRequireSecureAuthentication();
    // Determine whether to require secure password changes.
    this.requireSecurePasswordChanges =
      configuration.isRequireSecurePasswordChanges() ;
    // Determine whether to allow multiple password values.
    this.allowMultiplePasswordValues =
      configuration.isAllowMultiplePasswordValues();
    // Determine whether to allow pre-encoded passwords.
    this.allowPreEncodedPasswords = configuration.isAllowPreEncodedPasswords();
    // Get the minimum password age.
    this.minimumPasswordAge = (int) configuration.getMinPasswordAge();
    // Get the maximum password age.
    this.maximumPasswordAge = (int) configuration.getMaxPasswordAge();
    // Get the maximum password reset age.
    this.maximumPasswordResetAge = (int) configuration
        .getMaxPasswordResetAge();
    // Get the warning interval.
    this.warningInterval = (int) configuration
        .getPasswordExpirationWarningInterval();
    // Determine whether to expire passwords without warning.
    this.expirePasswordsWithoutWarning = configuration
        .isExpirePasswordsWithoutWarning();
    // If the expire without warning option is disabled, then there must be a
    // warning interval.
    if ((! this.expirePasswordsWithoutWarning()) &&
        (this.getWarningInterval() <= 0))
    {
      Message message =
        ERR_PWPOLICY_MUST_HAVE_WARNING_IF_NOT_EXPIRE_WITHOUT_WARNING.
            get(String.valueOf(configEntryDN));
      throw new ConfigException(message);
    }
    // Determine whether to allow user changes for expired passwords.
    this.allowExpiredPasswordChanges = configuration
        .isAllowExpiredPasswordChanges();
    // Get the grace login count.
    this.graceLoginCount = configuration.getGraceLoginCount();
    // Get the lockout failure count.
    this.lockoutFailureCount = configuration.getLockoutFailureCount();
    // Get the lockout duration.
    this.lockoutDuration = (int) configuration.getLockoutDuration();
    // Get the lockout failure expiration interval.
    this.lockoutFailureExpirationInterval = (int) configuration
        .getLockoutFailureExpirationInterval();
    // Get the required change time.
    String requireChangeBy = configuration.getRequireChangeByTime();
    try
    {
      if (requireChangeBy != null)
      {
        ByteString valueString = ByteString.valueOf(requireChangeBy);
        GeneralizedTimeSyntax syntax =
             (GeneralizedTimeSyntax)
             DirectoryServer.getAttributeSyntax(SYNTAX_GENERALIZED_TIME_OID,
                                                false);
        if (syntax == null)
        {
          this.requireChangeByTime =
               GeneralizedTimeSyntax.decodeGeneralizedTimeValue(valueString);
        }
        else
        {
          valueString =
               syntax.getEqualityMatchingRule().normalizeValue(valueString);
          this.requireChangeByTime =
               GeneralizedTimeSyntax.decodeGeneralizedTimeValue(valueString);
        }
      }
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_PWPOLICY_CANNOT_DETERMINE_REQUIRE_CHANGE_BY_TIME.
          get(String.valueOf(configEntryDN), getExceptionMessage(e));
      throw new InitializationException(message, e);
    }
    // Get the last login time attribute.  If specified, it must be defined in
    // the server schema.  It does not need to have a generalized time syntax
    // because the value that it will store will not necessarily conform to this
    // format.
    lastLoginTimeAttribute = configuration.getLastLoginTimeAttribute();
    // Get the last login time format.  If specified, it must be a valid format
    // string.
    String formatString = configuration.getLastLoginTimeFormat();
    try
    {
      if (formatString != null)
      {
        try
        {
          new SimpleDateFormat(formatString);
        }
        catch (Exception e)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
          Message message = ERR_PWPOLICY_INVALID_LAST_LOGIN_TIME_FORMAT.get(
              String.valueOf(configEntryDN), String.valueOf(formatString));
          throw new ConfigException(message);
        }
        this.lastLoginTimeFormat = formatString;
      }
    }
    catch (ConfigException ce)
    {
      throw ce;
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_PWPOLICY_CANNOT_DETERMINE_LAST_LOGIN_TIME_FORMAT.
          get(String.valueOf(configEntryDN), getExceptionMessage(e));
      throw new InitializationException(message, e);
    }
    // Get the previous last login time formats.  If specified, they must all
    // be valid format strings.
    SortedSet<String> formatStrings =
      configuration.getPreviousLastLoginTimeFormat() ;
    try
    {
      if (formatStrings != null)
      {
        for (String s : formatStrings)
        {
          try
          {
            new SimpleDateFormat(s);
          }
          catch (Exception e)
          {
            if (debugEnabled())
            {
              TRACER.debugCaught(DebugLogLevel.ERROR, e);
            }
            Message message =
              ERR_PWPOLICY_INVALID_PREVIOUS_LAST_LOGIN_TIME_FORMAT.
                  get(String.valueOf(configEntryDN), String.valueOf(s));
            throw new ConfigException(message);
          }
        }
        this.previousLastLoginTimeFormats =
             new CopyOnWriteArrayList<String>(formatStrings);
      }
    }
    catch (ConfigException ce)
    {
      throw ce;
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message =
          ERR_PWPOLICY_CANNOT_DETERMINE_PREVIOUS_LAST_LOGIN_TIME_FORMAT.
            get(String.valueOf(configEntryDN), getExceptionMessage(e));
      throw new InitializationException(message, e);
    }
    // Get the idle lockout duration.
    this.idleLockoutInterval = (int) configuration.getIdleLockoutInterval();
    // Get the state update failure policy.
    this.stateUpdateFailurePolicy = configuration.getStateUpdateFailurePolicy();
    // Get the password history count and duration.
    this.historyCount    = configuration.getPasswordHistoryCount();
    this.historyDuration = (int) configuration.getPasswordHistoryDuration();
    /*
     *  Holistic validation.
     */
    // Ensure that the password attribute was included in the configuration
    // entry, since it is required.
    if (passwordAttribute == null)
    {
      Message message =
          ERR_PWPOLICY_NO_PASSWORD_ATTRIBUTE.get(String.valueOf(configEntryDN));
      throw new ConfigException(message);
    }
    // Ensure that at least one default password storage scheme was included in
    // the configuration entry, since it is required.
    if (defaultStorageSchemes.isEmpty())
    {
      Message message = ERR_PWPOLICY_NO_DEFAULT_STORAGE_SCHEMES.get(
          String.valueOf(configEntryDN));
      throw new ConfigException(message);
    }
    // If both a maximum password age and a warning interval are provided, then
    // ensure that the warning interval is less than the maximum age.  Further,
    // if a minimum age is specified, then the sum of the minimum age and the
    // warning interval should be less than the maximum age.
    if (maximumPasswordAge > 0)
    {
      int warnInterval = Math.max(0, warningInterval);
      if (minimumPasswordAge > 0)
      {
        if ((warnInterval + minimumPasswordAge) >= maximumPasswordAge)
        {
          Message message =
              ERR_PWPOLICY_MIN_AGE_PLUS_WARNING_GREATER_THAN_MAX_AGE.
                get(String.valueOf(configEntryDN));
          throw new ConfigException(message);
        }
      }
      else if (warnInterval >= maximumPasswordAge)
      {
        Message message = ERR_PWPOLICY_WARNING_INTERVAL_LARGER_THAN_MAX_AGE.get(
            String.valueOf(configEntryDN));
        throw new ConfigException(message);
      }
    }
  }
  /**
   * Retrieves the DN of the configuration entry to which this password policy
   * corresponds.
   *
   * @return  The DN of the configuration entry.
   */
  public DN getConfigEntryDN()
  {
    return configEntryDN;
  }
  /**
   * Retrieves the attribute type used to store the password.
   *
   * @return  The attribute type used to store the password.
   */
  public AttributeType getPasswordAttribute()
  {
    return passwordAttribute;
    // Nothing to do.
  }
@@ -730,44 +61,41 @@
   * Indicates whether the associated password attribute uses the auth password
   * syntax.
   *
   * @return  <CODE>true</CODE> if the associated password attribute uses the
   *          auth password syntax, or <CODE>false</CODE> if not.
   * @return <CODE>true</CODE> if the associated password attribute uses the
   *         auth password syntax, or <CODE>false</CODE> if not.
   */
  public boolean usesAuthPasswordSyntax()
  {
    return authPasswordSyntax;
  }
  public abstract boolean isAuthPasswordSyntax();
  /**
   * Retrieves the default set of password storage schemes that will be used for
   * this password policy.  The returned set should not be modified by the
   * this password policy. The returned set should not be modified by the
   * caller.
   *
   * @return  The default set of password storage schemes that will be used for
   *          this password policy.
   * @return The default set of password storage schemes that will be used for
   *         this password policy.
   */
  public CopyOnWriteArrayList<PasswordStorageScheme<?>>
  getDefaultStorageSchemes()
  {
    return defaultStorageSchemes;
  }
  public abstract List<PasswordStorageScheme<?>>
    getDefaultPasswordStorageSchemes();
  /**
   * Retrieves the default set of password storage scheme DNs that will
   * be used for this password policy.  The returned set should not be
   * modified by the caller.
   * Gets the "deprecated-password-storage-scheme" property.
   * <p>
   * Specifies the names of the password storage schemes that are considered
   * deprecated for this password policy.
   * <p>
   * If a user with this password policy authenticates to the server and
   * his/her password is encoded with a deprecated scheme, those values are
   * removed and replaced with values encoded using the default password
   * storage scheme(s).
   *
   * @return  The default set of password storage scheme DNs that will
   *          be used for this password policy.
   * @return Returns an unmodifiable set containing the values of the
   *         "deprecated-password-storage-scheme" property.
   */
  public SortedSet<DN> getDefaultStorageSchemeDNs()
  {
    return storageSchemeDNs;
  }
  public abstract Set<String> getDeprecatedPasswordStorageSchemes();
@@ -775,226 +103,49 @@
   * Indicates whether the specified storage scheme is a default scheme for this
   * password policy.
   *
   * @param  name  The name of the password storage scheme for which to make the
   *               determination.
   *
   * @return  <CODE>true</CODE> if the storage scheme is a default scheme for
   *          this password policy, or <CODE>false</CODE> if not.
   * @param name
   *          The name of the password storage scheme for which to make the
   *          determination.
   * @return <CODE>true</CODE> if the storage scheme is a default scheme for
   *         this password policy, or <CODE>false</CODE> if not.
   */
  public boolean isDefaultStorageScheme(String name)
  {
    CopyOnWriteArrayList<PasswordStorageScheme<?>> defaultSchemes =
         getDefaultStorageSchemes();
    if (defaultSchemes == null)
    {
      return false;
    }
    for (PasswordStorageScheme<?> s : defaultSchemes)
    {
      if (authPasswordSyntax)
      {
        if (s.getAuthPasswordSchemeName().equalsIgnoreCase(name))
        {
          return true;
        }
      }
      else
      {
        if (s.getStorageSchemeName().equalsIgnoreCase(name))
        {
          return true;
        }
      }
    }
    return false;
  }
  /**
   * Retrieves the names of the password storage schemes that have been
   * deprecated.  If an authenticating user has one or more of these deprecated
   * storage schemes in use in their entry, then they will be removed and
   * replaced with the passwords encoded in the default storage scheme(s).  The
   * returned list should not be altered by the caller.
   *
   * @return  The names of the password storage schemes that have been
   *          deprecated.
   */
  public CopyOnWriteArraySet<String> getDeprecatedStorageSchemes()
  {
    return deprecatedStorageSchemes;
  }
  /**
   * Retrieves DNs of the password storage schemes that have been
   * deprecated.  If an authenticating user has one or more of
   * these deprecated storage schemes in use in their entry, then
   * they will be removed and replaced with the passwords encoded
   * in the default storage scheme(s).  The returned set should
   * not be altered by the caller.
   *
   * @return  DNs of the password storage schemes that have been
   *          deprecated.
   */
  public SortedSet<DN> getDeprecatedStorageSchemeDNs()
  {
    return deprecatedStorageSchemeDNs;
  }
  public abstract boolean isDefaultPasswordStorageScheme(String name);
  /**
   * Indicates whether the specified storage scheme is deprecated.
   *
   * @param  name  The name of the password storage scheme for which to make the
   *               determination.
   *
   * @return  <CODE>true</CODE> if the storage scheme is deprecated, or
   *          <CODE>false</CODE> if not.
   * @param name
   *          The name of the password storage scheme for which to make the
   *          determination.
   * @return <CODE>true</CODE> if the storage scheme is deprecated, or
   *         <CODE>false</CODE> if not.
   */
  public boolean isDeprecatedStorageScheme(String name)
  {
    CopyOnWriteArraySet<String> deprecatedSchemes =
         getDeprecatedStorageSchemes();
    if (deprecatedSchemes == null)
    {
      return false;
    }
    for (String s : deprecatedSchemes)
    {
      if (s.equalsIgnoreCase(name))
      {
        return true;
      }
    }
    return false;
  }
  public abstract boolean isDeprecatedPasswordStorageScheme(String name);
  /**
   * Retrieves the set of password validators for this password policy.  The
   * Retrieves the set of password validators for this password policy. The
   * returned list should not be altered by the caller.
   *
   * @return  The set of password validators for this password policy.
   * @return The set of password validators for this password policy.
   */
  public ConcurrentHashMap<DN,
              PasswordValidator<? extends PasswordValidatorCfg>>
              getPasswordValidators()
  {
    return passwordValidators;
  }
  public abstract Collection<PasswordValidator<?>> getPasswordValidators();
  /**
   * Retrieves the set of account status notification handlers that should be
   * used with this password policy.  The returned list should not be altered by
   * used with this password policy. The returned list should not be altered by
   * the caller.
   *
   * @return  The set of account status notification handlers that should be
   *          used with this password policy.
   * @return The set of account status notification handlers that should be used
   *         with this password policy.
   */
  public ConcurrentHashMap<DN,AccountStatusNotificationHandler<?>>
              getAccountStatusNotificationHandlers()
  {
    return notificationHandlers;
  }
  /**
   * Indicates whether end users will be allowed to change their own passwords
   * (subject to access control restrictions).
   *
   * @return  <CODE>true</CODE> if users will be allowed to change their own
   *          passwords, or <CODE>false</CODE> if not.
   */
  public boolean allowUserPasswordChanges()
  {
    return allowUserPasswordChanges;
  }
  /**
   * Indicates whether the end user must provide their current password (via the
   * password modify extended operation) in order to set a new password.
   *
   * @return  <CODE>true</CODE> if the end user must provide their current
   *          password in order to set a new password, or <CODE>false</CODE> if
   *          they will not.
   */
  public boolean requireCurrentPassword()
  {
    return requireCurrentPassword;
  }
  /**
   * Indicates whether users will be required to change their passwords as soon
   * as they authenticate after their accounts have been created.
   *
   * @return  <CODE>true</CODE> if users will be required to change their
   *          passwords at the initial authentication, or <CODE>false</CODE> if
   *          not.
   */
  public boolean forceChangeOnAdd()
  {
    return forceChangeOnAdd;
  }
  /**
   * Indicates whether a user will be required to change their password after it
   * has been reset by an administrator.
   *
   * @return  <CODE>true</CODE> if a user will be required to change their
   *          password after it has been reset by an administrator, or
   *          <CODE>false</CODE> if they can continue using that password.
   */
  public boolean forceChangeOnReset()
  {
    return forceChangeOnReset;
  }
  /**
   * Indicates whether operations by administrators that specify a new password
   * for a user (e.g., add, modify, or password modify) will be allowed to
   * bypass the password validation process that will be required for user
   * password changes.
   *
   * @return  <CODE>true</CODE> if administrators will be allowed to bypass the
   *          validation checks, or <CODE>false</CODE> if not.
   */
  public boolean skipValidationForAdministrators()
  {
    return skipValidationForAdministrators;
  }
  /**
   * Retrieves the DN of the password validator configuration entry.
   *
   * @return  The DN of the password validator configuration entry.
   */
  public DN getPasswordGeneratorDN()
  {
    return passwordGeneratorDN;
  }
  public abstract Collection<AccountStatusNotificationHandler<?>>
    getAccountStatusNotificationHandlers();
@@ -1002,301 +153,10 @@
   * Retrieves the password generator that will be used with this password
   * policy.
   *
   * @return  The password generator that will be used with this password
   *          policy, or <CODE>null</CODE> if there is none.
   * @return The password generator that will be used with this password policy,
   *         or <CODE>null</CODE> if there is none.
   */
  public PasswordGenerator<?> getPasswordGenerator()
  {
    return passwordGenerator;
  }
  /**
   * Retrieves the maximum number of previous passwords to maintain in the
   * password history.
   *
   * @return  The maximum number of previous passwords to maintain in the
   *          password history.
   */
  public int getPasswordHistoryCount()
  {
    return historyCount;
  }
  /**
   * Retrieves the maximum length of time in seconds that previous passwords
   * should remain in the password history.
   *
   * @return  The maximum length of time in seconds that previous passwords
   *          should remain in the password history.
   */
  public int getPasswordHistoryDuration()
  {
    return historyDuration;
  }
  /**
   * Indicates whether users with this password policy will be required to
   * authenticate in a secure manner that does not expose their password.
   *
   *  @return  <CODE>true</CODE> if users with this password policy will be
   *           required to authenticate in a secure manner that does not expose
   *           their password, or <CODE>false</CODE> if they may authenticate in
   *           an insecure manner.
   */
  public boolean requireSecureAuthentication()
  {
    return requireSecureAuthentication;
  }
  /**
   * Indicates whether users with this password policy will be required to
   * change their passwords in a secure manner that does not expose the new
   * password.
   *
   * @return  <CODE>true</CODE> if users with this password policy will be
   *          required to change their passwords in a secure manner that does
   *          not expose the new password, or <CODE>false</CODE> if they may
   *          change their password in an insecure manner.
   */
  public boolean requireSecurePasswordChanges()
  {
    return requireSecurePasswordChanges;
  }
  /**
   * Indicates whether user entries will be allowed to have multiple distinct
   * values in the password attribute.
   *
   * @return  <CODE>true</CODE> if clients will be allowed to have multiple
   *          distinct password values, or <CODE>false</CODE> if not.
   */
  public boolean allowMultiplePasswordValues()
  {
    return allowMultiplePasswordValues;
  }
  /**
   * Indicates whether clients will be allowed to set pre-encoded passwords that
   * are already hashed and therefore cannot be validated for correctness.
   *
   * @return  <CODE>true</CODE> if clients will be allowed to set pre-encoded
   *          passwords that cannot be validated, or <CODE>false</CODE> if not.
   */
  public boolean allowPreEncodedPasswords()
  {
    return allowPreEncodedPasswords;
  }
  /**
   * Retrieves the minimum password age, which is the minimum length of time in
   * seconds that must elapse between user password changes.
   *
   * @return  The minimum password age, which is the minimum length of time in
   *          seconds that must elapse between user password changes, or zero if
   *          there is no minimum age.
   */
  public int getMinimumPasswordAge()
  {
    if (minimumPasswordAge <= 0)
    {
      return 0;
    }
    return minimumPasswordAge;
  }
  /**
   * Retrieves the maximum length of time in seconds that will be allowed to
   * pass between password changes before the password is expired.
   *
   * @return  The maximum length of time in seconds that will be allowed to pass
   *          between password changes before the password is expired, or zero
   *          if password expiration should not be used.
   */
  public int getMaximumPasswordAge()
  {
    if (maximumPasswordAge < 0)
    {
      return 0;
    }
    return maximumPasswordAge;
  }
  /**
   * Retrieves the maximum length of time in seconds that will be allowed to
   * pass after an administrative password reset before that password is
   * expired.
   *
   * @return  The maximum length of time in seconds that will be allowed to pass
   *          after an administrative password reset before that password is
   *          expired, or zero if there is no limit.
   */
  public int getMaximumPasswordResetAge()
  {
    if (maximumPasswordResetAge < 0)
    {
      return 0;
    }
    return maximumPasswordResetAge;
  }
  /**
   * Retrieves the maximum length of time in seconds before the password will
   * expire that the user should start receiving warning notifications.
   *
   * @return  The maximum length of time in seconds before the password will
   *          expire that the user should start receiving warning notifications,
   *          or zero if no warning should be given.
   */
  public int getWarningInterval()
  {
    if (warningInterval < 0)
    {
      return 0;
    }
    return warningInterval;
  }
  /**
   * Indicates whether user passwords will be allowed to expire without the
   * user receiving at least one notification during the warning period.
   *
   * @return  <CODE>true</CODE> if user passwords will be allowed to expire
   *          without the user receiving at least one notification during the
   *          warning period, or <CODE>false</CODE> if the user will always see
   *          at least one warning before the password expires.
   */
  public boolean expirePasswordsWithoutWarning()
  {
    return expirePasswordsWithoutWarning;
  }
  /**
   * Indicates whether a user will be allowed to change their password after it
   * expires and they have no remaining grace logins (and will not be allowed to
   * perform any other operation until the password is changed).
   *
   * @return  <CODE>true</CODE> if a user will be allowed to change their
   *          password after it expires and they have no remaining grace longs,
   *          or <CODE>false</CODE> if the account will be completely locked and
   *          the password must be reset by an administrator.
   */
  public boolean allowExpiredPasswordChanges()
  {
    return allowExpiredPasswordChanges;
  }
  /**
   * Retrieves the maximum number of grace logins that a user will be allowed
   * after their password has expired before they are completely locked out.
   *
   * @return  The maximum number of grace logins that a user will be allowed
   *          after their password has expired before they are completely
   *          locked out, or zero if no grace logins will be allowed or the
   *          grace login duration will be in effect instead of a fixed number
   *          of logins.
   */
  public int getGraceLoginCount()
  {
    if (graceLoginCount < 0)
    {
      return 0;
    }
    return graceLoginCount;
  }
  /**
   * Retrieves the maximum number of authentication failures that will be
   * allowed before an account is locked out.
   *
   * @return  The maximum number of authentication failures that will be allowed
   *          before an account is locked out, or zero if no account lockout
   *          will be in effect.
   */
  public int getLockoutFailureCount()
  {
    if (lockoutFailureCount < 0)
    {
      return 0;
    }
    return lockoutFailureCount;
  }
  /**
   * Retrieves the maximum length of time in seconds that an account will be
   * locked out due to too many failed authentication attempts.
   *
   * @return  The maximum length of time in seconds that an account will be
   *          locked out due to too many failed authentication attempts, or
   *          zero if the account will remain locked until explicitly unlocked
   *          by an administrator.
   */
  public int getLockoutDuration()
  {
    if (lockoutDuration < 0)
    {
      return 0;
    }
    return lockoutDuration;
  }
  /**
   * Retrieves the maximum length of time in seconds that an authentication
   * failure will be held against a user before it is removed from the failed
   * login count.
   *
   * @return  The maximum length of time in seconds that an authentication
   *          failure will be held against a user before it is removed from the
   *          failed login count, or zero if authentication failures will never
   *          expire.
   */
  public int getLockoutFailureExpirationInterval()
  {
    if (lockoutFailureExpirationInterval < 0)
    {
      return 0;
    }
    return lockoutFailureExpirationInterval;
  }
  public abstract PasswordGenerator<?> getPasswordGenerator();
@@ -1304,375 +164,447 @@
   * Retrieves the time by which all users will be required to change their
   * passwords, expressed in the number of milliseconds since midnight of
   * January 1, 1970 (i.e., the zero time for
   * <CODE>System.currentTimeMillis()</CODE>).  Any passwords not changed before
   * <CODE>System.currentTimeMillis()</CODE>). Any passwords not changed before
   * this time will automatically enter a state in which they must be changed
   * before any other operation will be allowed.
   *
   * @return  The time by which all users will be required to change their
   *          passwords, or zero if no such constraint is in effect.
   * @return The time by which all users will be required to change their
   *         passwords, or zero if no such constraint is in effect.
   */
  public long getRequireChangeByTime()
  {
    if (requireChangeByTime < 0)
    {
      return 0;
    }
    return requireChangeByTime;
  }
  public abstract long getRequireChangeByTime();
  /**
   * Retrieves the attribute type used to store the last login time.
   * Gets the "allow-expired-password-changes" property.
   * <p>
   * Indicates whether a user whose password is expired is still allowed to
   * change that password using the password modify extended operation.
   *
   * @return  The attribute type used to store the last login time, or
   *          <CODE>null</CODE> if the last login time is not to be maintained.
   * @return Returns the value of the "allow-expired-password-changes" property.
   */
  public AttributeType getLastLoginTimeAttribute()
  {
    return lastLoginTimeAttribute;
  }
  public abstract boolean isAllowExpiredPasswordChanges();
  /**
   * Retrieves the format string that should be used for the last login time.
   * Gets the "allow-multiple-password-values" property.
   * <p>
   * Indicates whether user entries can have multiple distinct values for the
   * password attribute.
   * <p>
   * This is potentially dangerous because many mechanisms used to change the
   * password do not work well with such a configuration. If multiple password
   * values are allowed, then any of them can be used to authenticate, and they
   * are all subject to the same policy constraints.
   *
   * @return  The format string that should be used to for the last login time,
   *          or <CODE>null</CODE> if the last login time is not to be
   *          maintained.
   * @return Returns the value of the "allow-multiple-password-values" property.
   */
  public String getLastLoginTimeFormat()
  {
    return lastLoginTimeFormat;
  }
  public abstract boolean isAllowMultiplePasswordValues();
  /**
   * Retrieves the list of previous last login time formats that might have been
   * used for users associated with this password policy.
   * Gets the "allow-pre-encoded-passwords" property.
   * <p>
   * Indicates whether users can change their passwords by providing a
   * pre-encoded value.
   * <p>
   * This can cause a security risk because the clear-text version of the
   * password is not known and therefore validation checks cannot be applied to
   * it.
   *
   * @return  The list of previous last login time formats that might have been
   *          used for users associated with this password policy.
   * @return Returns the value of the "allow-pre-encoded-passwords" property.
   */
  public CopyOnWriteArrayList<String> getPreviousLastLoginTimeFormats()
  {
    return previousLastLoginTimeFormats;
  }
  public abstract boolean isAllowPreEncodedPasswords();
  /**
   * Retrieves the maximum length of time in seconds that an account will be
   * allowed to remain idle (no authentications performed as the user) before it
   * will be locked out.
   * Gets the "allow-user-password-changes" property.
   * <p>
   * Indicates whether users can change their own passwords.
   * <p>
   * This check is made in addition to access control evaluation. Both must
   * allow the password change for it to occur.
   *
   * @return  The maximum length of time in seconds that an account will be
   *          allowed to remain idle before it will be locked out.
   * @return Returns the value of the "allow-user-password-changes" property.
   */
  public int getIdleLockoutInterval()
  {
    if (idleLockoutInterval < 0)
    {
      return 0;
    }
    return idleLockoutInterval;
  }
  public abstract boolean isAllowUserPasswordChanges();
  /**
   * Retrieves the state update failure policy for this password policy.
   * Gets the "expire-passwords-without-warning" property.
   * <p>
   * Indicates whether the directory server allows a user's password to expire
   * even if that user has never seen an expiration warning notification.
   * <p>
   * If this property is true, accounts always expire when the expiration time
   * arrives. If this property is false or disabled, the user always receives at
   * least one warning notification, and the password expiration is set to the
   * warning time plus the warning interval.
   *
   * @return  The state update failure policy for this password policy.
   * @return Returns the value of the "expire-passwords-without-warning"
   *         property.
   */
  public PasswordPolicyCfgDefn.StateUpdateFailurePolicy
              getStateUpdateFailurePolicy()
  {
    return stateUpdateFailurePolicy;
  }
  public abstract boolean isExpirePasswordsWithoutWarning();
  /**
   * Retrieves a string representation of this password policy.
   * Gets the "force-change-on-add" property.
   * <p>
   * Indicates whether users are forced to change their passwords upon first
   * authenticating to the directory server after their account has been
   * created.
   *
   * @return  A string representation of this password policy.
   * @return Returns the value of the "force-change-on-add" property.
   */
  public String toString()
  {
    StringBuilder buffer = new StringBuilder();
    toString(buffer);
    return buffer.toString();
  }
  public abstract boolean isForceChangeOnAdd();
  /**
   * Appends a string representation of this password policy to the provided
   * buffer.
   * Gets the "force-change-on-reset" property.
   * <p>
   * Indicates whether users are forced to change their passwords if they are
   * reset by an administrator.
   * <p>
   * For this purpose, anyone with permission to change a given user's password
   * other than that user is considered an administrator.
   *
   * @param  buffer  The buffer to which the information should be appended.
   * @return Returns the value of the "force-change-on-reset" property.
   */
  public void toString(StringBuilder buffer)
  {
    buffer.append("Password Attribute:                    ");
    buffer.append(passwordAttribute.getNameOrOID());
    buffer.append(EOL);
  public abstract boolean isForceChangeOnReset();
    buffer.append("Default Password Storage Schemes:      ");
    if ((defaultStorageSchemes == null) || defaultStorageSchemes.isEmpty())
    {
      buffer.append("{none specified}");
      buffer.append(EOL);
    }
    else
    {
      Iterator<PasswordStorageScheme<?>> iterator =
           defaultStorageSchemes.iterator();
      buffer.append(iterator.next().getStorageSchemeName());
      buffer.append(EOL);
      while (iterator.hasNext())
      {
        buffer.append("                                       ");
        buffer.append(iterator.next().getStorageSchemeName());
        buffer.append(EOL);
      }
    }
    buffer.append("Deprecated Password Storage Schemes:   ");
    if ((deprecatedStorageSchemes == null) ||
        deprecatedStorageSchemes.isEmpty())
    {
      buffer.append("{none specified}");
      buffer.append(EOL);
    }
    else
    {
      Iterator<String> iterator = deprecatedStorageSchemes.iterator();
      buffer.append(iterator.next());
      buffer.append(EOL);
  /**
   * Gets the "grace-login-count" property.
   * <p>
   * Specifies the number of grace logins that a user is allowed after the
   * account has expired to allow that user to choose a new password.
   * <p>
   * A value of 0 indicates that no grace logins are allowed.
   *
   * @return Returns the value of the "grace-login-count" property.
   */
  public abstract int getGraceLoginCount();
      while (iterator.hasNext())
      {
        buffer.append("                                       ");
        buffer.append(iterator.next());
        buffer.append(EOL);
      }
    }
    buffer.append("Allow Multiple Password Values:        ");
    buffer.append(allowMultiplePasswordValues);
    buffer.append(EOL);
    buffer.append("Allow Pre-Encoded Passwords:           ");
    buffer.append(allowPreEncodedPasswords);
    buffer.append(EOL);
  /**
   * Gets the "idle-lockout-interval" property.
   * <p>
   * Specifies the maximum length of time that an account may remain idle (that
   * is, the associated user does not authenticate to the server) before that
   * user is locked out.
   * <p>
   * The value of this attribute is an integer followed by a unit of seconds,
   * minutes, hours, days, or weeks. A value of 0 seconds indicates that idle
   * accounts are not automatically locked out. This feature is available only
   * if the last login time is maintained.
   *
   * @return Returns the value of the "idle-lockout-interval" property.
   */
  public abstract long getIdleLockoutInterval();
    buffer.append("Allow User Password Changes:           ");
    buffer.append(allowUserPasswordChanges);
    buffer.append(EOL);
    buffer.append("Force Password Change on Add:          ");
    buffer.append(forceChangeOnAdd);
    buffer.append(EOL);
    buffer.append("Force Password Change on Admin Reset:  ");
    buffer.append(forceChangeOnReset);
    buffer.append(EOL);
  /**
   * Gets the "last-login-time-attribute" property.
   * <p>
   * Specifies the name or OID of the attribute type that is used to hold the
   * last login time for users with the associated password policy.
   * <p>
   * This attribute type must be defined in the directory server schema and must
   * either be defined as an operational attribute or must be allowed by the set
   * of objectClasses for all users with the associated password policy.
   *
   * @return Returns the value of the "last-login-time-attribute" property.
   */
  public abstract AttributeType getLastLoginTimeAttribute();
    buffer.append("Require Current Password:              ");
    buffer.append(requireCurrentPassword);
    buffer.append(EOL);
    buffer.append("Require Secure Authentication:         ");
    buffer.append(requireSecureAuthentication);
    buffer.append(EOL);
    buffer.append("Require Secure Password Changes:       ");
    buffer.append(requireSecurePasswordChanges);
    buffer.append(EOL);
  /**
   * Gets the "last-login-time-format" property.
   * <p>
   * Specifies the format string that is used to generate the last login time
   * value for users with the associated password policy.
   * <p>
   * This format string conforms to the syntax described in the API
   * documentation for the java.text.SimpleDateFormat class.
   *
   * @return Returns the value of the "last-login-time-format" property.
   */
  public abstract String getLastLoginTimeFormat();
    buffer.append("Lockout Failure Expiration Interval:   ");
    buffer.append(lockoutFailureExpirationInterval);
    buffer.append(" seconds");
    buffer.append(EOL);
    buffer.append("Password Validators:                   ");
    if ((passwordValidators == null) || passwordValidators.isEmpty())
    {
      buffer.append("{none specified}");
      buffer.append(EOL);
    }
    else
    {
      Iterator<DN> iterator = passwordValidators.keySet().iterator();
      iterator.next().toString(buffer);
      buffer.append(EOL);
      while (iterator.hasNext())
      {
        buffer.append("                                       ");
        iterator.next().toString(buffer);
        buffer.append(EOL);
      }
    }
  /**
   * Gets the "lockout-duration" property.
   * <p>
   * Specifies the length of time that an account is locked after too many
   * authentication failures.
   * <p>
   * The value of this attribute is an integer followed by a unit of seconds,
   * minutes, hours, days, or weeks. A value of 0 seconds indicates that the
   * account must remain locked until an administrator resets the password.
   *
   * @return Returns the value of the "lockout-duration" property.
   */
  public abstract long getLockoutDuration();
    buffer.append("Skip Validation for Administrators:    ");
    buffer.append(skipValidationForAdministrators);
    buffer.append(EOL);
    buffer.append("Password Generator:                    ");
    if (passwordGenerator == null)
    {
      buffer.append("{none specified}");
    }
    else
    {
      passwordGeneratorDN.toString(buffer);
    }
    buffer.append(EOL);
    buffer.append("Account Status Notification Handlers:  ");
    if ((notificationHandlers == null) || notificationHandlers.isEmpty())
    {
      buffer.append("{none specified}");
      buffer.append(EOL);
    }
    else
    {
      Iterator<DN> iterator = notificationHandlers.keySet().iterator();
      iterator.next().toString(buffer);
      buffer.append(EOL);
  /**
   * Gets the "lockout-failure-count" property.
   * <p>
   * Specifies the maximum number of authentication failures that a user is
   * allowed before the account is locked out.
   * <p>
   * A value of 0 indicates that accounts are never locked out due to failed
   * attempts.
   *
   * @return Returns the value of the "lockout-failure-count" property.
   */
  public abstract int getLockoutFailureCount();
      while (iterator.hasNext())
      {
        buffer.append("                                       ");
        iterator.next().toString(buffer);
        buffer.append(EOL);
      }
    }
    buffer.append("Minimum Password Age:                  ");
    buffer.append(minimumPasswordAge);
    buffer.append(" seconds");
    buffer.append(EOL);
    buffer.append("Maximum Password Age:                  ");
    buffer.append(maximumPasswordAge);
    buffer.append(" seconds");
    buffer.append(EOL);
  /**
   * Gets the "lockout-failure-expiration-interval" property.
   * <p>
   * Specifies the length of time before an authentication failure is no longer
   * counted against a user for the purposes of account lockout.
   * <p>
   * The value of this attribute is an integer followed by a unit of seconds,
   * minutes, hours, days, or weeks. A value of 0 seconds indicates that the
   * authentication failures must never expire. The failure count is always
   * cleared upon a successful authentication.
   *
   * @return Returns the value of the "lockout-failure-expiration-interval"
   *         property.
   */
  public abstract long getLockoutFailureExpirationInterval();
    buffer.append("Maximum Password Reset Age:            ");
    buffer.append(maximumPasswordResetAge);
    buffer.append(" seconds");
    buffer.append(EOL);
    buffer.append("Expiration Warning Interval:           ");
    buffer.append(warningInterval);
    buffer.append(" seconds");
    buffer.append(EOL);
    buffer.append("Expire Passwords Without Warning:      ");
    buffer.append(expirePasswordsWithoutWarning);
    buffer.append(EOL);
  /**
   * Gets the "max-password-age" property.
   * <p>
   * Specifies the maximum length of time that a user can continue using the
   * same password before it must be changed (that is, the password expiration
   * interval).
   * <p>
   * The value of this attribute is an integer followed by a unit of seconds,
   * minutes, hours, days, or weeks. A value of 0 seconds disables password
   * expiration.
   *
   * @return Returns the value of the "max-password-age" property.
   */
  public abstract long getMaxPasswordAge();
    buffer.append("Allow Expired Password Changes:        ");
    buffer.append(allowExpiredPasswordChanges);
    buffer.append(EOL);
    buffer.append("Grace Login Count:                     ");
    buffer.append(graceLoginCount);
    buffer.append(EOL);
    buffer.append("Lockout Failure Count:                 ");
    buffer.append(lockoutFailureCount);
    buffer.append(EOL);
  /**
   * Gets the "max-password-reset-age" property.
   * <p>
   * Specifies the maximum length of time that users have to change passwords
   * after they have been reset by an administrator before they become locked.
   * <p>
   * The value of this attribute is an integer followed by a unit of seconds,
   * minutes, hours, days, or weeks. A value of 0 seconds disables this feature.
   *
   * @return Returns the value of the "max-password-reset-age" property.
   */
  public abstract long getMaxPasswordResetAge();
    buffer.append("Lockout Duration:                      ");
    buffer.append(lockoutDuration);
    buffer.append(" seconds");
    buffer.append(EOL);
    buffer.append("Lockout Count Expiration Interval:     ");
    buffer.append(lockoutFailureExpirationInterval);
    buffer.append(" seconds");
    buffer.append(EOL);
    buffer.append("Required Password Change By Time:      ");
    if (requireChangeByTime <= 0)
    {
      buffer.append("{none specified}");
    }
    else
    {
      SimpleDateFormat dateFormat =
           new SimpleDateFormat(DATE_FORMAT_GENERALIZED_TIME);
      dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
      buffer.append(dateFormat.format(new Date(requireChangeByTime)));
    }
    buffer.append(EOL);
  /**
   * Gets the "min-password-age" property.
   * <p>
   * Specifies the minimum length of time after a password change before the
   * user is allowed to change the password again.
   * <p>
   * The value of this attribute is an integer followed by a unit of seconds,
   * minutes, hours, days, or weeks. This setting can be used to prevent users
   * from changing their passwords repeatedly over a short period of time to
   * flush an old password from the history so that it can be re-used.
   *
   * @return Returns the value of the "min-password-age" property.
   */
  public abstract long getMinPasswordAge();
    buffer.append("Last Login Time Attribute:             ");
    if (lastLoginTimeAttribute == null)
    {
      buffer.append("{none specified}");
    }
    else
    {
      buffer.append(lastLoginTimeAttribute.getNameOrOID());
    }
    buffer.append(EOL);
    buffer.append("Last Login Time Format:                ");
    if (lastLoginTimeFormat == null)
    {
      buffer.append("{none specified}");
    }
    else
    {
      buffer.append(lastLoginTimeFormat);
    }
    buffer.append(EOL);
    buffer.append("Previous Last Login Time Formats:      ");
    if ((previousLastLoginTimeFormats == null) ||
        previousLastLoginTimeFormats.isEmpty())
    {
      buffer.append("{none specified}");
      buffer.append(EOL);
    }
    else
    {
      Iterator<String> iterator = previousLastLoginTimeFormats.iterator();
  /**
   * Gets the "password-attribute" property.
   * <p>
   * Specifies the attribute type used to hold user passwords.
   * <p>
   * This attribute type must be defined in the server schema, and it must have
   * either the user password or auth password syntax.
   *
   * @return Returns the value of the "password-attribute" property.
   */
  public abstract AttributeType getPasswordAttribute();
      buffer.append(iterator.next());
      buffer.append(EOL);
      while (iterator.hasNext())
      {
        buffer.append("                                       ");
        buffer.append(iterator.next());
        buffer.append(EOL);
      }
    }
    buffer.append("Idle Lockout Interval:                 ");
    buffer.append(idleLockoutInterval);
    buffer.append(" seconds");
    buffer.append(EOL);
  /**
   * Gets the "password-change-requires-current-password" property.
   * <p>
   * Indicates whether user password changes must use the password modify
   * extended operation and must include the user's current password before the
   * change is allowed.
   *
   * @return Returns the value of the
   *         "password-change-requires-current-password" property.
   */
  public abstract boolean isPasswordChangeRequiresCurrentPassword();
    buffer.append("History Count:                         ");
    buffer.append(historyCount);
    buffer.append(EOL);
    buffer.append("Update Failure Policy:                 ");
    buffer.append(stateUpdateFailurePolicy.toString());
    buffer.append(EOL);
  }
  /**
   * Gets the "password-expiration-warning-interval" property.
   * <p>
   * Specifies the maximum length of time before a user's password actually
   * expires that the server begins to include warning notifications in bind
   * responses for that user.
   * <p>
   * The value of this attribute is an integer followed by a unit of seconds,
   * minutes, hours, days, or weeks. A value of 0 seconds disables the warning
   * interval.
   *
   * @return Returns the value of the "password-expiration-warning-interval"
   *         property.
   */
  public abstract long getPasswordExpirationWarningInterval();
  /**
   * Gets the "password-history-count" property.
   * <p>
   * Specifies the maximum number of former passwords to maintain in the
   * password history.
   * <p>
   * When choosing a new password, the proposed password is checked to ensure
   * that it does not match the current password, nor any other password in the
   * history list. A value of zero indicates that either no password history is
   * to be maintained (if the password history duration has a value of zero
   * seconds), or that there is no maximum number of passwords to maintain in
   * the history (if the password history duration has a value greater than zero
   * seconds).
   *
   * @return Returns the value of the "password-history-count" property.
   */
  public abstract int getPasswordHistoryCount();
  /**
   * Gets the "password-history-duration" property.
   * <p>
   * Specifies the maximum length of time that passwords remain in the password
   * history.
   * <p>
   * When choosing a new password, the proposed password is checked to ensure
   * that it does not match the current password, nor any other password in the
   * history list. A value of zero seconds indicates that either no password
   * history is to be maintained (if the password history count has a value of
   * zero), or that there is no maximum duration for passwords in the history
   * (if the password history count has a value greater than zero).
   *
   * @return Returns the value of the "password-history-duration" property.
   */
  public abstract long getPasswordHistoryDuration();
  /**
   * Gets the "previous-last-login-time-format" property.
   * <p>
   * Specifies the format string(s) that might have been used with the last
   * login time at any point in the past for users associated with the password
   * policy.
   * <p>
   * These values are used to make it possible to parse previous values, but are
   * not used to set new values. The format strings conform to the syntax
   * described in the API documentation for the java.text.SimpleDateFormat
   * class.
   *
   * @return Returns an unmodifiable set containing the values of the
   *         "previous-last-login-time-format" property.
   */
  public abstract SortedSet<String> getPreviousLastLoginTimeFormats();
  /**
   * Gets the "require-secure-authentication" property.
   * <p>
   * Indicates whether users with the associated password policy are required to
   * authenticate in a secure manner.
   * <p>
   * This might mean either using a secure communication channel between the
   * client and the server, or using a SASL mechanism that does not expose the
   * credentials.
   *
   * @return Returns the value of the "require-secure-authentication" property.
   */
  public abstract boolean isRequireSecureAuthentication();
  /**
   * Gets the "require-secure-password-changes" property.
   * <p>
   * Indicates whether users with the associated password policy are required to
   * change their password in a secure manner that does not expose the
   * credentials.
   *
   * @return Returns the value of the "require-secure-password-changes"
   *         property.
   */
  public abstract boolean isRequireSecurePasswordChanges();
  /**
   * Gets the "skip-validation-for-administrators" property.
   * <p>
   * Indicates whether passwords set by administrators are allowed to bypass the
   * password validation process that is required for user password changes.
   *
   * @return Returns the value of the "skip-validation-for-administrators"
   *         property.
   */
  public abstract boolean isSkipValidationForAdministrators();
  /**
   * Gets the "state-update-failure-policy" property.
   * <p>
   * Specifies how the server deals with the inability to update password policy
   * state information during an authentication attempt.
   * <p>
   * In particular, this property can be used to control whether an otherwise
   * successful bind operation fails if a failure occurs while attempting to
   * update password policy state information (for example, to clear a record of
   * previous authentication failures or to update the last login time). It can
   * also be used to control whether to reject a bind request if it is known
   * ahead of time that it will not be possible to update the authentication
   * failure times in the event of an unsuccessful bind attempt (for example, if
   * the backend writability mode is disabled).
   *
   * @return Returns the value of the "state-update-failure-policy" property.
   */
  public abstract StateUpdateFailurePolicy getStateUpdateFailurePolicy();
}