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

Jean-Noël Rouvignac
22.01.2015 4a62ca7cee5dcab3ae2a5283a3d11aabf3137819
PasswordPolicyState.java: code cleanup
Extracted methods replace() and clear().
2 files modified
593 ■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/server/core/PasswordPolicyState.java 425 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/extensions/PasswordModifyExtendedOperationTestCase.java 168 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/PasswordPolicyState.java
@@ -88,7 +88,6 @@
{
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** The string representation of the user's DN. */
  private final String userDNString;
@@ -141,9 +140,7 @@
  private long warnedTime = Long.MIN_VALUE;
  /** The set of modifications that should be applied to the user's entry. */
  private LinkedList<Modification> modifications = new LinkedList<>();
  private final LinkedList<Modification> modifications = new LinkedList<>();
  /**
   * Creates a new password policy state object with the provided information.
@@ -165,8 +162,6 @@
    this.passwordPolicy = policy;
  }
   /**
    * Retrieves the value of the specified attribute as a string.
    *
@@ -178,21 +173,18 @@
  {
    Attribute attr = getFirstAttributeNotEmpty(attributeType);
    String stringValue = attr != null ? attr.iterator().next().toString() : null;
    if (stringValue == null)
    if (logger.isTraceEnabled())
    {
      if (logger.isTraceEnabled())
      if (stringValue != null)
      {
        logger.trace("Returning value %s for user %s", stringValue, userDNString);
      }
      else
      {
        logger.trace("Returning null because attribute %s does not exist in user entry %s",
            attributeType.getNameOrOID(), userDNString);
      }
    }
    else
    {
      if (logger.isTraceEnabled())
      {
        logger.trace("Returning value %s for user %s", stringValue, userDNString);
      }
    }
    return stringValue;
  }
@@ -251,7 +243,6 @@
    return timeValues;
  }
  /**
   * Get the password storage scheme used by a given password value.
   *
@@ -281,8 +272,6 @@
    return passwordPolicy;
  }
  /**
   * Retrieves the time that the password was last changed.
   *
@@ -340,7 +329,6 @@
    return passwordChangedTime;
  }
  private long getGeneralizedTime0(Entry userEntry, String attrName) throws DirectoryException
  {
    return getGeneralizedTime(userEntry, DirectoryServer.getAttributeType(attrName));
@@ -356,8 +344,6 @@
    return currentTime;
  }
  /**
   * Retrieves the unmodifiable set of values for the password attribute from the user entry.
   *
@@ -378,17 +364,12 @@
    return Collections.emptySet();
  }
  /**
   * Sets a new value for the password changed time equal to the current time.
   */
  /** Sets a new value for the password changed time equal to the current time. */
  public void setPasswordChangedTime()
  {
    setPasswordChangedTime(currentTime);
  }
  /**
   * Sets a new value for the password changed time equal to the specified time.
   * This method should generally only be used for testing purposes, since the variant that uses
@@ -407,30 +388,19 @@
    if (getPasswordChangedTime() != passwordChangedTime)
    {
      this.passwordChangedTime = passwordChangedTime;
      String timeValue = GeneralizedTimeSyntax.format(passwordChangedTime);
      Attribute a = Attributes.create(OP_ATTR_PWPOLICY_CHANGED_TIME, timeValue);
      modifications.add(new Modification(ModificationType.REPLACE, a, true));
      replaceAttribute(OP_ATTR_PWPOLICY_CHANGED_TIME, GeneralizedTimeSyntax.format(passwordChangedTime));
    }
  }
  /**
   * Removes the password changed time value from the user's entry.  This should only be used for testing
   * purposes, as it can really mess things up if you don't know what you're doing.
   */
  public void clearPasswordChangedTime()
  {
    if (logger.isTraceEnabled())
    {
      logger.trace("Clearing password changed time for user %s", userDNString);
    }
    logger.trace("Clearing password changed time for user %s", userDNString);
    Attribute a = Attributes.empty(OP_ATTR_PWPOLICY_CHANGED_TIME_LC);
    modifications.add(new Modification(ModificationType.REPLACE, a, true));
    clearAttribute(OP_ATTR_PWPOLICY_CHANGED_TIME_LC);
    // Fall back to using the entry creation time as the password changed time, if it's defined.
    // Otherwise, use a value of zero.
@@ -448,8 +418,6 @@
    }
  }
  /**
   * Updates the user entry to indicate whether user account has been administratively disabled.
   *
@@ -463,27 +431,15 @@
      logger.trace("Updating user %s to set the disabled flag to %b", userDNString, isDisabled);
    }
    if (isDisabled == isDisabled())
    {
      return; // requested state matches current state
    }
    this.isDisabled = ConditionResult.not(this.isDisabled);
    if (isDisabled)
    {
      Attribute a = Attributes.create(OP_ATTR_ACCOUNT_DISABLED, String.valueOf(true));
      modifications.add(new Modification(ModificationType.REPLACE, a, true));
    }
    else
    {
      // erase
      modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(OP_ATTR_ACCOUNT_DISABLED), true));
    }
    replaceAttribute(OP_ATTR_ACCOUNT_DISABLED, isDisabled);
  }
  /**
   * Indicates whether the user's account is currently expired.
   *
@@ -539,8 +495,6 @@
    return isAccountExpired == ConditionResult.TRUE;
  }
  /**
   * Retrieves the time at which the user's account will expire.
   *
@@ -556,8 +510,6 @@
    return accountExpirationTime;
  }
  /**
   * Sets the user's account expiration time to the specified value.
   *
@@ -572,39 +524,22 @@
    else
    {
      String timeStr = GeneralizedTimeSyntax.format(accountExpirationTime);
      if (logger.isTraceEnabled())
      {
        logger.trace("Setting account expiration time for user %s to %s", userDNString, timeStr);
      }
      logger.trace("Setting account expiration time for user %s to %s", userDNString, timeStr);
      this.accountExpirationTime = accountExpirationTime;
      Attribute a = Attributes.create(OP_ATTR_ACCOUNT_EXPIRATION_TIME, timeStr);
      modifications.add(new Modification(ModificationType.REPLACE, a, true));
      replaceAttribute(OP_ATTR_ACCOUNT_EXPIRATION_TIME, timeStr);
    }
  }
  /**
   * Clears the user's account expiration time.
   */
  /** Clears the user's account expiration time. */
  public void clearAccountExpirationTime()
  {
    if (logger.isTraceEnabled())
    {
      logger.trace("Clearing account expiration time for user %s", userDNString);
    }
    logger.trace("Clearing account expiration time for user %s", userDNString);
    accountExpirationTime = -1;
    String attrName = OP_ATTR_ACCOUNT_EXPIRATION_TIME;
    modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(attrName), true));
    clearAttribute(OP_ATTR_ACCOUNT_EXPIRATION_TIME);
  }
  /**
   * Retrieves the set of times of failed authentication attempts for the user. If authentication failure
   * time expiration is enabled, and there are expired times in the entry, these times are removed
@@ -636,7 +571,7 @@
      logger.traceException(e, "Error while processing auth failure times for user %s", userDNString);
      authFailureTimes = new ArrayList<>();
      modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true));
      clearAttribute(type);
      return authFailureTimes;
    }
@@ -695,7 +630,6 @@
    return authFailureTimes;
  }
  /**
   * Updates the set of authentication failure times to include the current time.
   * If the number of failures reaches the policy configuration limit, lock the account.
@@ -712,7 +646,6 @@
      logger.trace("Updating authentication failure times for user %s", userDNString);
    }
    List<Long> failureTimes = getAuthFailureTimes();
    long highestFailureTime = computeHighestTime(failureTimes);
    // Update the current policy state
@@ -735,8 +668,6 @@
    }
  }
  /**
   * Explicitly specifies the auth failure times for the associated user.  This should generally only be used
   * for testing purposes.  Note that it will also set or clear the locked time as appropriate.
@@ -763,9 +694,7 @@
      highestFailureTime = Math.max(l, highestFailureTime);
      builder.add(GeneralizedTimeSyntax.format(l));
    }
    Attribute a = builder.toAttribute();
    modifications.add(new Modification(ModificationType.REPLACE, a, true));
    replaceAttribute(builder.toAttribute());
    // Now check to see if there have been sufficient failures to lock the account.
    int lockoutCount = passwordPolicy.getLockoutFailureCount();
@@ -779,31 +708,19 @@
    }
  }
  /**
   * Updates the user entry to remove any record of previous authentication failure times.
   */
  /** Updates the user entry to remove any record of previous authentication failure times. */
  private void clearAuthFailureTimes()
  {
    if (logger.isTraceEnabled())
    {
      logger.trace("Clearing authentication failure times for user %s", userDNString);
    }
    logger.trace("Clearing authentication failure times for user %s", userDNString);
    List<Long> failureTimes = getAuthFailureTimes();
    if (failureTimes.isEmpty())
    if (!failureTimes.isEmpty())
    {
      return;
      failureTimes.clear(); // Note: failureTimes != this.authFailureTimes
      clearAttribute(OP_ATTR_PWPOLICY_FAILURE_TIME);
    }
    failureTimes.clear(); // Note: failureTimes != this.authFailureTimes
    AttributeType type = DirectoryServer.getAttributeType(OP_ATTR_PWPOLICY_FAILURE_TIME);
    modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true));
  }
  /**
   * Retrieves the time of an authentication failure lockout for the user.
   *
@@ -833,8 +750,6 @@
    return failureLockedTime;
  }
  /**
    Sets the failure lockout attribute in the entry to the requested time.
@@ -842,42 +757,25 @@
   */
  private void setFailureLockedTime(final long time)
  {
    if (time == getFailureLockedTime())
    if (time != getFailureLockedTime())
    {
      return;
      failureLockedTime = time;
      replaceAttribute(OP_ATTR_PWPOLICY_LOCKED_TIME, GeneralizedTimeSyntax.format(failureLockedTime));
    }
    failureLockedTime = time;
    AttributeType type = DirectoryServer.getAttributeType(OP_ATTR_PWPOLICY_LOCKED_TIME);
    Attribute a = Attributes.create(type, GeneralizedTimeSyntax.format(failureLockedTime));
    modifications.add(new Modification(ModificationType.REPLACE, a, true));
  }
  /**
   * Updates the user entry to remove any record of previous authentication failure lockout.
   */
  /** Updates the user entry to remove any record of previous authentication failure lockout. */
  private void clearFailureLockedTime()
  {
    if (logger.isTraceEnabled())
    logger.trace("Clearing failure lockout time for user %s.", userDNString);
    if (-1L != getFailureLockedTime())
    {
      logger.trace("Clearing failure lockout time for user %s.", userDNString);
      failureLockedTime = -1L;
      clearAttribute(OP_ATTR_PWPOLICY_LOCKED_TIME);
    }
    if (-1L == getFailureLockedTime())
    {
      return;
    }
    failureLockedTime = -1L;
    AttributeType type = DirectoryServer.getAttributeType(OP_ATTR_PWPOLICY_LOCKED_TIME);
    modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true));
  }
  /**
   * Indicates whether the associated user should be considered locked out as a result of too many
   * authentication failures. In the case of an expired lock-out, this routine produces the update
@@ -978,8 +876,6 @@
    return true;
  }
  /**
   * Retrieves the length of time in seconds until the user's account is automatically unlocked.
   * This should only be called after calling <CODE>lockedDueToFailures</CODE>.
@@ -996,8 +892,6 @@
    return secondsUntilUnlock < 0 ? -1 : secondsUntilUnlock;
  }
  /**
   * Updates the user account to remove any record of a previous lockout due to failed authentications.
   */
@@ -1007,8 +901,6 @@
    clearFailureLockedTime();
  }
  /**
   * Retrieves the time that the user last authenticated to the Directory Server.
   *
@@ -1119,16 +1011,12 @@
    return dateFormat.parse(time).getTime();
  }
  /**
   * Updates the user entry to set the current time as the last login time.
   */
  /** Updates the user entry to set the current time as the last login time. */
  public void setLastLoginTime()
  {
    setLastLoginTime(currentTime);
  }
  /**
   * Updates the user entry to use the specified last login time.  This should be used primarily for testing purposes,
   * as the variant that uses the current time should be used most of the time.
@@ -1163,7 +1051,6 @@
      return;
    }
    String existingTimestamp = getValue(type);
    if (existingTimestamp != null && timestamp.equals(existingTimestamp))
    {
@@ -1172,31 +1059,22 @@
      return;
    }
    Attribute a = Attributes.create(type, timestamp);
    modifications.add(new Modification(ModificationType.REPLACE, a, true));
    replaceAttribute(Attributes.create(type, timestamp));
    logger.trace("Updated the last login time for user %s to %s", userDNString, timestamp);
  }
  /**
   * Clears the last login time from the user's entry.  This should generally be used only for testing purposes.
   */
  public void clearLastLoginTime()
  {
    if (logger.isTraceEnabled())
    {
      logger.trace("Clearing last login time for user %s", userDNString);
    }
    logger.trace("Clearing last login time for user %s", userDNString);
    lastLoginTime = -1;
    modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(OP_ATTR_LAST_LOGIN_TIME), true));
    clearAttribute(OP_ATTR_LAST_LOGIN_TIME);
  }
  /**
   * Indicates whether the user's account is currently locked because it has been idle for too long.
   *
@@ -1271,8 +1149,6 @@
    return isIdleLocked == ConditionResult.TRUE;
  }
/**
* Indicates whether the user's password must be changed before any other operation can be performed.
*
@@ -1316,9 +1192,7 @@
    catch (Exception e)
    {
      logger.traceException(e, "Returning true for user %s because an error occurred", userDNString);
      mustChangePassword = ConditionResult.TRUE;
      return true;
    }
@@ -1327,7 +1201,6 @@
      mustChangePassword = ConditionResult.FALSE;
      logger.trace("Returning %b for user since the attribute \"%s\" is not present in the entry.",
          false, userDNString, OP_ATTR_PWPOLICY_RESET_REQUIRED);
      return false;
    }
@@ -1336,8 +1209,6 @@
    return result;
  }
/**
* Updates the user entry to indicate whether the user's password must be changed.
*
@@ -1355,19 +1226,41 @@
      return;  // requested state matches current state
    }
    AttributeType type = DirectoryServer.getAttributeType(OP_ATTR_PWPOLICY_RESET_REQUIRED);
    this.mustChangePassword = ConditionResult.not(this.mustChangePassword);
    if (mustChangePassword)
    replaceAttribute(OP_ATTR_PWPOLICY_RESET_REQUIRED, mustChangePassword);
  }
  private void replaceAttribute(String attrName, boolean newValue)
  {
    if (newValue)
    {
      Attribute a = Attributes.create(type, String.valueOf(true));
      modifications.add(new Modification(ModificationType.REPLACE, a, true));
      replaceAttribute(attrName, String.valueOf(true));
    }
    else
    {
      modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true));
      clearAttribute(attrName);
    }
  }
  private void clearAttribute(String attrName)
  {
    clearAttribute(DirectoryServer.getAttributeType(attrName));
  }
  private void clearAttribute(AttributeType type)
  {
    replaceAttribute(Attributes.empty(type));
  }
  private void replaceAttribute(String attrName, String attrValue)
  {
    replaceAttribute(Attributes.create(attrName, attrValue));
  }
  private void replaceAttribute(Attribute a)
  {
    modifications.add(new Modification(ModificationType.REPLACE, a, true));
  }
  /**
   * Indicates whether the user's account is locked because the password has been reset by an administrator
@@ -1565,15 +1458,7 @@
          // There will never be a warning, and the user's password may be expired.
          shouldWarn     = ConditionResult.FALSE;
          isFirstWarning = ConditionResult.FALSE;
          if (currentTime > passwordExpirationTime)
          {
            isPasswordExpired = ConditionResult.TRUE;
          }
          else
          {
            isPasswordExpired = ConditionResult.FALSE;
          }
          isPasswordExpired = ConditionResult.valueOf(currentTime > passwordExpirationTime);
        }
      }
      else
@@ -1581,15 +1466,7 @@
        mayUseGraceLogin = ConditionResult.FALSE;
        shouldWarn       = ConditionResult.FALSE;
        isFirstWarning   = ConditionResult.FALSE;
        if (passwordExpirationTime < currentTime)
        {
          isPasswordExpired = ConditionResult.TRUE;
        }
        else
        {
          isPasswordExpired = ConditionResult.FALSE;
        }
        isPasswordExpired = ConditionResult.valueOf(passwordExpirationTime < currentTime);
      }
    }
@@ -1601,8 +1478,6 @@
    return passwordExpirationTime;
  }
  /**
   * Indicates whether the user's password is currently expired.
   *
@@ -1614,14 +1489,6 @@
    return isPasswordExpired == ConditionResult.TRUE;
  }
  private void refreshIfUndefined(ConditionResult cond)
  {
    if (cond == null || cond == ConditionResult.UNDEFINED)
    {
      getPasswordExpirationTime();
    }
  }
  /**
   * Indicates whether the user's last password change was within the minimum password age.
   *
@@ -1674,8 +1541,6 @@
    }
  }
  /**
   * Indicates whether the user may use a grace login if the password is expired and there is at least one
   * grace login remaining.  Note that this does not check to see if the user's password is expired, does not
@@ -1691,8 +1556,6 @@
    return mayUseGraceLogin == ConditionResult.TRUE;
  }
  /**
   * Indicates whether the user should receive a warning notification that the password is about to expire.
   *
@@ -1705,8 +1568,6 @@
    return shouldWarn == ConditionResult.TRUE;
  }
  /**
   * Indicates whether the warning that the user should receive would be the first warning for the user.
   *
@@ -1719,7 +1580,13 @@
    return isFirstWarning == ConditionResult.TRUE;
  }
  private void refreshIfUndefined(ConditionResult cond)
  {
    if (cond == null || cond == ConditionResult.UNDEFINED)
    {
      getPasswordExpirationTime();
    }
  }
  /**
   * Retrieves the length of time in seconds until the user's password expires.
@@ -1744,8 +1611,6 @@
    }
  }
  /**
   * Retrieves the timestamp for the last required change time that the user complied with.
   *
@@ -1781,8 +1646,6 @@
    return requiredChangeTime;
  }
  /**
   * Updates the user entry with a timestamp indicating that the password has been changed in accordance
   * with the require change time.
@@ -1796,8 +1659,6 @@
    }
  }
  /**
   * Updates the user entry with a timestamp indicating that the password has been changed in accordance
   * with the require change time.
@@ -1814,33 +1675,22 @@
    if (getRequiredChangeTime() != requiredChangeTime)
    {
      this.requiredChangeTime = requiredChangeTime;
      String timeValue = GeneralizedTimeSyntax.format(requiredChangeTime);
      Attribute a = Attributes.create(OP_ATTR_PWPOLICY_CHANGED_BY_REQUIRED_TIME, timeValue);
      modifications.add(new Modification(ModificationType.REPLACE, a, true));
      replaceAttribute(OP_ATTR_PWPOLICY_CHANGED_BY_REQUIRED_TIME, GeneralizedTimeSyntax.format(requiredChangeTime));
    }
  }
  /**
   * Updates the user entry to remove any timestamp indicating that the password has been changed in accordance
   * with the required change time.
   */
  public void clearRequiredChangeTime()
  {
    if (logger.isTraceEnabled())
    {
      logger.trace("Clearing required change time for user %s", userDNString);
    }
    logger.trace("Clearing required change time for user %s", userDNString);
    this.requiredChangeTime = Long.MIN_VALUE;
    String attrName = OP_ATTR_PWPOLICY_CHANGED_BY_REQUIRED_TIME;
    modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(attrName), true));
    clearAttribute(OP_ATTR_PWPOLICY_CHANGED_BY_REQUIRED_TIME);
  }
  /**
   * Retrieves the time that the user was first warned about an upcoming expiration.
   *
@@ -1866,18 +1716,12 @@
    return warnedTime;
  }
  /**
   * Updates the user entry to set the warned time to the current time.
   */
  /** Updates the user entry to set the warned time to the current time. */
  public void setWarnedTime()
  {
    setWarnedTime(currentTime);
  }
  /**
   * Updates the user entry to set the warned time to the specified time.  This method should generally
   * only be used for testing purposes, since the variant that uses the current time is preferred almost
@@ -1900,11 +1744,8 @@
    }
    this.warnedTime = warnedTime;
    AttributeType type = DirectoryServer.getAttributeType(OP_ATTR_PWPOLICY_WARNED_TIME);
    Attribute a = Attributes.create(type, GeneralizedTimeSyntax.createGeneralizedTimeValue(currentTime));
    modifications.add(new Modification(ModificationType.REPLACE, a, true));
    replaceAttribute(Attributes.create(type, GeneralizedTimeSyntax.createGeneralizedTimeValue(currentTime)));
    if (logger.isTraceEnabled())
    {
@@ -1912,35 +1753,20 @@
    }
  }
  /**
   * Updates the user entry to clear the warned time.
   */
  /** Updates the user entry to clear the warned time. */
  public void clearWarnedTime()
  {
    if (logger.isTraceEnabled())
    {
      logger.trace("Clearing warned time for user %s", userDNString);
    }
    logger.trace("Clearing warned time for user %s", userDNString);
    if (getWarnedTime() < 0)
    if (getWarnedTime() >= 0)
    {
      return;
    }
    warnedTime = -1;
      warnedTime = -1;
      clearAttribute(OP_ATTR_PWPOLICY_WARNED_TIME);
    String attrName = OP_ATTR_PWPOLICY_WARNED_TIME;
    modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(attrName), true));
    if (logger.isTraceEnabled())
    {
      logger.trace("Cleared the warned time for user %s", userDNString);
    }
  }
  /**
   * Retrieves the times that the user has authenticated to the server using a grace login.
   *
@@ -1960,8 +1786,7 @@
        logger.traceException(e, "Error while processing grace login times for user %s", userDNString);
        graceLoginTimes = new ArrayList<>();
        modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true));
        clearAttribute(type);
      }
    }
@@ -1969,8 +1794,6 @@
    return graceLoginTimes;
  }
  /**
   * Retrieves the number of grace logins that the user has left.
   *
@@ -1988,11 +1811,7 @@
    return maxGraceLogins - theGraceLoginTimes.size();
  }
  /**
   * Updates the set of grace login times for the user to include the current time.
   */
  /** Updates the set of grace login times for the user to include the current time. */
  public void updateGraceLoginTimes()
  {
    if (logger.isTraceEnabled())
@@ -2028,8 +1847,6 @@
    return highestTime;
  }
  /**
   * Specifies the set of grace login use times for the associated user.  If the provided list is empty
   * or {@code null}, then the set will be cleared.
@@ -2056,35 +1873,22 @@
    {
      builder.add(GeneralizedTimeSyntax.format(l));
    }
    Attribute a = builder.toAttribute();
    modifications.add(new Modification(ModificationType.REPLACE, a, true));
    replaceAttribute(builder.toAttribute());
  }
  /**
   * Updates the user entry to remove any record of previous grace logins.
   */
  /** Updates the user entry to remove any record of previous grace logins. */
  public void clearGraceLoginTimes()
  {
    if (logger.isTraceEnabled())
    {
      logger.trace("Clearing grace login times for user %s", userDNString);
    }
    logger.trace("Clearing grace login times for user %s", userDNString);
    List<Long> graceTimes = getGraceLoginTimes();
    if (graceTimes.isEmpty())
    if (!graceTimes.isEmpty())
    {
      return;
      graceTimes.clear(); // graceTimes == this.graceLoginTimes
      clearAttribute(OP_ATTR_PWPOLICY_GRACE_LOGIN_TIME);
    }
    graceTimes.clear(); // graceTimes == this.graceLoginTimes
    AttributeType type = DirectoryServer.getAttributeType(OP_ATTR_PWPOLICY_GRACE_LOGIN_TIME);
    modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(type), true));
  }
  /**
   * Retrieves a list of the clear-text passwords for the user.  If the user does not have any passwords
   * in the clear, then the list will be empty.
@@ -2210,7 +2014,6 @@
    return false;
  }
  /**
   * Get the broken-down components of the given password value.
   *
@@ -2240,8 +2043,6 @@
        : UserPasswordSyntax.isEncoded(passwordValue);
  }
  /**
   * Encodes the provided password using the default storage schemes (using the appropriate syntax for the
   * password attribute).
@@ -2276,8 +2077,6 @@
    return encodedPasswords;
  }
  /**
   * Indicates whether the provided password appears to be acceptable according to the password validators.
   *
@@ -2308,8 +2107,6 @@
    return true;
  }
  /**
   * Performs any processing that may be necessary to remove deprecated storage schemes from the user's entry
   * that match the provided password and re-encodes them using the default schemes.
@@ -2329,7 +2126,6 @@
      return;
    }
    AttributeType type = passwordPolicy.getPasswordAttribute();
    List<Attribute> attrList = userEntry.getAttribute(type);
    if (attrList.isEmpty())
@@ -2338,7 +2134,6 @@
      return;
    }
    HashSet<String> existingDefaultSchemes = new HashSet<>();
    LinkedHashSet<ByteString> removedValues = new LinkedHashSet<>();
    LinkedHashSet<ByteString> updatedValues = new LinkedHashSet<>();
@@ -2467,8 +2262,6 @@
        || passwordPolicy.getPasswordHistoryDuration() > 0;
  }
  /**
   * Indicates whether the provided password is equal to any of the current passwords,
   * or any of the passwords in the history.
@@ -2554,8 +2347,6 @@
    return false;
  }
  /**
   * Gets a sorted list of the password history values contained in the user's entry.
   * The values will be sorted by timestamp.
@@ -2611,8 +2402,6 @@
    return historyMap;
  }
  /**
   * Indicates whether the provided password matches the given history value.
   *
@@ -2754,8 +2543,6 @@
    }
  }
  /**
   * Adds the provided password to the password history.  If appropriate, one or more old passwords may be
   * evicted from the list if the total size would exceed the configured count, or if passwords are older
@@ -2776,12 +2563,10 @@
      return;
    }
    // Get a sorted list of the existing values to see if there are any that should be removed.
    LinkedList<Attribute> removeAttrs = new LinkedList<>();
    TreeMap<Long, ByteString> historyMap = getSortedHistoryValues(removeAttrs);
    // If there is a maximum number of values to retain and we would be over the limit with the new value,
    // then get rid of enough values (oldest first) to satisfy the count.
    AttributeType historyType = DirectoryServer.getAttributeType(OP_ATTR_PWPOLICY_HISTORY_LC);
@@ -2810,7 +2595,6 @@
      }
    }
    // If there is a maximum duration, then get rid of any values that would be over the duration.
    long historyDuration = passwordPolicy.getPasswordHistoryDuration();
    if (historyDuration > 0L)
@@ -2842,7 +2626,6 @@
      }
    }
    // At this point, we can add the new value.  However, we want to make sure that its timestamp
    // (which is the current time) doesn't conflict with any value already in the list.  If there is a conflict,
    // then simply add one to it until we don't have any more conflicts.
@@ -2860,7 +2643,6 @@
      logger.trace("Going to add history value " + newHistStr);
    }
    // Apply the changes, either by adding modifications or by directly updating the entry.
    for (Attribute a : removeAttrs)
    {
@@ -2896,22 +2678,16 @@
    return historyValues.toArray(new String[historyValues.size()]);
  }
  /**
   * Clears the password history state information for the user.  This is only intended for testing purposes.
   */
  public void clearPasswordHistory()
  {
    if (logger.isTraceEnabled())
    {
      logger.trace("Clearing password history for user %s", userDNString);
    }
    logger.trace("Clearing password history for user %s", userDNString);
    modifications.add(new Modification(ModificationType.REPLACE, Attributes.empty(OP_ATTR_PWPOLICY_HISTORY_LC), true));
    clearAttribute(OP_ATTR_PWPOLICY_HISTORY_LC);
  }
  /**
   * Generates a new password for the user.
   *
@@ -2937,8 +2713,6 @@
    return generator.generatePassword(userEntry);
  }
  /**
   * Generates an account status notification for this user.
   *
@@ -2956,14 +2730,7 @@
        new AccountStatusNotification(notificationType, userEntry, message, notificationProperties));
  }
  /**
   * Generates an account status notification for this user.
   *
   * @param  notification  The account status notification that should be generated.
   */
  public void generateAccountStatusNotification(AccountStatusNotification notification)
  private void generateAccountStatusNotification(AccountStatusNotification notification)
  {
    Collection<AccountStatusNotificationHandler<?>> handlers = passwordPolicy.getAccountStatusNotificationHandlers();
    for (AccountStatusNotificationHandler<?> handler : handlers)
@@ -2972,8 +2739,6 @@
    }
  }
  /**
   * Retrieves the set of modifications that correspond to changes made in password policy processing
   * that may need to be applied to the user entry.
@@ -2986,8 +2751,6 @@
    return modifications;
  }
  @Override
  public void finalizeStateAfterBind()
         throws DirectoryException
opendj-server-legacy/src/test/java/org/opends/server/extensions/PasswordModifyExtendedOperationTestCase.java
@@ -26,7 +26,6 @@
 */
package org.opends.server.extensions;
import java.util.ArrayList;
import java.util.List;
import org.forgerock.opendj.config.server.ConfigException;
@@ -36,21 +35,32 @@
import org.forgerock.opendj.ldap.ByteStringBuilder;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.server.AdminTestCaseUtils;
import org.opends.server.admin.std.meta.PasswordModifyExtendedOperationHandlerCfgDefn;
import org.opends.server.admin.std.server.PasswordModifyExtendedOperationHandlerCfg;
import org.opends.server.core.*;
import org.opends.server.core.BindOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ExtendedOperation;
import org.opends.server.core.ModifyOperation;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.tools.LDAPPasswordModify;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.opends.server.types.*;
import org.opends.server.types.Attributes;
import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import org.opends.server.types.InitializationException;
import org.opends.server.types.Modification;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.forgerock.opendj.ldap.ModificationType.*;
import static org.opends.server.extensions.ExtensionsConstants.*;
import static org.opends.server.protocols.internal.InternalClientConnection.*;
import static org.opends.server.util.CollectionUtils.*;
import static org.opends.server.util.ServerConstants.*;
import static org.testng.Assert.*;
@@ -861,10 +871,9 @@
    TestCaseUtils.initializeTestBackend(true);
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-allow-pre-encoded-passwords";
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    applyPwdPolicyMods(dnStr, attr, "true");
    String[] args =
@@ -881,7 +890,7 @@
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "false");
      applyPwdPolicyMods(dnStr, attr, "false");
    }
  }
@@ -901,10 +910,9 @@
    addDefaultTestEntry();
    /* Make sure preEncoded passwords are rejected */
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-allow-pre-encoded-passwords";
    applyPwdPolicyMods(conn, dnStr, attr, "false");
    applyPwdPolicyMods(dnStr, attr, "false");
    String[] args =
    {
@@ -936,10 +944,9 @@
    addDefaultTestEntry();
    /* Make sure preEncoded passwords are rejected. This should be the default, so we will not restore config after */
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-allow-pre-encoded-passwords";
    applyPwdPolicyMods(conn, dnStr, attr, "false");
    applyPwdPolicyMods(dnStr, attr, "false");
    String[] args =
    {
@@ -1028,10 +1035,9 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-allow-user-password-changes";
    applyPwdPolicyMods(conn, dnStr, attr, "false");
    applyPwdPolicyMods(dnStr, attr, "false");
    String[] args =
    {
@@ -1046,7 +1052,7 @@
    try {
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "true");
      applyPwdPolicyMods(dnStr, attr, "true");
    }
  }
@@ -1066,10 +1072,9 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-allow-user-password-changes";
    applyPwdPolicyMods(conn, dnStr, attr, "false");
    applyPwdPolicyMods(dnStr, attr, "false");
    String[] args =
    {
@@ -1085,7 +1090,7 @@
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 53);
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "true");
      applyPwdPolicyMods(dnStr, attr, "true");
    }
  }
@@ -1104,10 +1109,9 @@
    TestCaseUtils.initializeTestBackend(true);
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-password-change-requires-current-password";
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    applyPwdPolicyMods(dnStr, attr, "true");
    String[] args =
@@ -1125,7 +1129,7 @@
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    } finally {
      // Reset to default configuration
      applyPwdPolicyMods(conn, dnStr, attr, "false");
      applyPwdPolicyMods(dnStr, attr, "false");
    }
  }
@@ -1145,10 +1149,9 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-require-secure-authentication";
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    applyPwdPolicyMods(dnStr, attr, "true");
    String[] args =
@@ -1165,7 +1168,7 @@
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 13);
    } finally {
      // Reset to default configuration
      applyPwdPolicyMods(conn, dnStr, attr, "false");
      applyPwdPolicyMods(dnStr, attr, "false");
    }
  }
@@ -1185,10 +1188,9 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-require-secure-password-changes";
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    applyPwdPolicyMods(dnStr, attr, "true");
    String[] args =
@@ -1204,7 +1206,7 @@
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 13);
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "false");
      applyPwdPolicyMods(dnStr, attr, "false");
    }
  }
@@ -1224,10 +1226,9 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-require-secure-password-changes";
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    applyPwdPolicyMods(dnStr, attr, "true");
    String[] args =
@@ -1246,7 +1247,7 @@
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 13);
    } finally {
      // Reset to default configuration
      applyPwdPolicyMods(conn, dnStr, attr, "false");
      applyPwdPolicyMods(dnStr, attr, "false");
    }
  }
@@ -1265,10 +1266,9 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-min-password-age";
    applyPwdPolicyMods(conn, dnStr, attr, "24 hours");
    applyPwdPolicyMods(dnStr, attr, "24 hours");
    String[] args =
    {
@@ -1283,7 +1283,7 @@
    try {
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "0 seconds");
      applyPwdPolicyMods(dnStr, attr, "0 seconds");
    }
  }
@@ -1302,10 +1302,9 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-min-password-age";
    applyPwdPolicyMods(conn, dnStr, attr, "24 hours");
    applyPwdPolicyMods(dnStr, attr, "24 hours");
    String[] args =
    {
@@ -1321,7 +1320,7 @@
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 53);
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "0 seconds");
      applyPwdPolicyMods(dnStr, attr, "0 seconds");
    }
  }
@@ -1340,16 +1339,15 @@
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr1 = "ds-cfg-max-password-age";
    applyPwdPolicyMods(conn, dnStr, attr1, "90 days");
    applyPwdPolicyMods(dnStr, attr1, "90 days");
    String attr2 = "ds-cfg-expire-passwords-without-warning";
    applyPwdPolicyMods(conn, dnStr, attr2, "true");
    applyPwdPolicyMods(dnStr, attr2, "true");
    try {
      setPasswordChangedTime(conn, userEntry);
      setPasswordChangedTime(userEntry);
      String[] args =
      {
@@ -1363,8 +1361,8 @@
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr1, "0 seconds");
      applyPwdPolicyMods(conn, dnStr, attr2, "false");
      applyPwdPolicyMods(dnStr, attr1, "0 seconds");
      applyPwdPolicyMods(dnStr, attr2, "false");
    }
  }
@@ -1382,19 +1380,18 @@
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr1 = "ds-cfg-max-password-age";
    applyPwdPolicyMods(conn, dnStr, attr1, "90 days");
    applyPwdPolicyMods(dnStr, attr1, "90 days");
    String attr2 = "ds-cfg-expire-passwords-without-warning";
    applyPwdPolicyMods(conn, dnStr, attr2, "true");
    applyPwdPolicyMods(dnStr, attr2, "true");
    String attr3 = "ds-cfg-allow-expired-password-changes";
    applyPwdPolicyMods(conn, dnStr, attr3, "true");
    applyPwdPolicyMods(dnStr, attr3, "true");
    try {
      setPasswordChangedTime(conn, userEntry);
      setPasswordChangedTime(userEntry);
      String[] args =
      {
@@ -1409,9 +1406,9 @@
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    }
    finally {
      applyPwdPolicyMods(conn, dnStr, attr1, "0 seconds");
      applyPwdPolicyMods(conn, dnStr, attr2, "false");
      applyPwdPolicyMods(conn, dnStr, attr3, "false");
      applyPwdPolicyMods(dnStr, attr1, "0 seconds");
      applyPwdPolicyMods(dnStr, attr2, "false");
      applyPwdPolicyMods(dnStr, attr3, "false");
    }
  }
@@ -1430,10 +1427,9 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr = "ds-cfg-password-generator";
    applyPwdPolicyMods(conn, dnStr, attr, null);
    applyPwdPolicyMods(dnStr, attr, null);
    String[] args =
@@ -1447,7 +1443,7 @@
    try {
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "cn=Random Password Generator,cn=Password Generators,cn=config");
      applyPwdPolicyMods(dnStr, attr, "cn=Random Password Generator,cn=Password Generators,cn=config");
    }
  }
@@ -1466,10 +1462,9 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr = "ds-cfg-password-generator";
    applyPwdPolicyMods(conn, dnStr, attr, null);
    applyPwdPolicyMods(dnStr, attr, null);
    String[] args =
    {
@@ -1483,7 +1478,7 @@
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    }
    finally {
      applyPwdPolicyMods(conn, dnStr, attr, "cn=Random Password Generator,cn=Password Generators,cn=config");
      applyPwdPolicyMods(dnStr, attr, "cn=Random Password Generator,cn=Password Generators,cn=config");
    }
  }
@@ -1503,10 +1498,9 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr = "ds-cfg-password-validator";
    applyPwdPolicyMods(conn, dnStr, attr, "cn=Length-Based Password Validator,cn=Password Validators,cn=config");
    applyPwdPolicyMods(dnStr, attr, "cn=Length-Based Password Validator,cn=Password Validators,cn=config");
    String[] args =
@@ -1522,7 +1516,7 @@
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    }
    finally {
      applyPwdPolicyMods(conn, dnStr, attr, null);
      applyPwdPolicyMods(dnStr, attr, null);
    }
  }
@@ -1542,10 +1536,9 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr = "ds-cfg-password-validator";
    applyPwdPolicyMods(conn, dnStr, attr, "cn=Length-Based Password Validator,cn=Password Validators,cn=config");
    applyPwdPolicyMods(dnStr, attr, "cn=Length-Based Password Validator,cn=Password Validators,cn=config");
    String[] args =
    {
@@ -1560,7 +1553,7 @@
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    }
    finally {
      applyPwdPolicyMods(conn, dnStr, attr, null);
      applyPwdPolicyMods(dnStr, attr, null);
    }
  }
@@ -1581,8 +1574,7 @@
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-allow-multiple-password-values";
    InternalClientConnection conn = getRootConnection();
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    applyPwdPolicyMods(dnStr, attr, "true");
    TestCaseUtils.addEntry(
        "dn: uid=test.user,o=test",
@@ -1613,7 +1605,7 @@
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "false");
      applyPwdPolicyMods(dnStr, attr, "false");
    }
  }
@@ -1630,10 +1622,9 @@
  {
    TestCaseUtils.initializeTestBackend(true);
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=SHA1 AuthPassword Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-allow-multiple-password-values";
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    applyPwdPolicyMods(dnStr, attr, "true");
    TestCaseUtils.addEntry(
        "dn: uid=test.user,o=test",
@@ -1666,7 +1657,7 @@
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, System.err), 0);
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "false");
      applyPwdPolicyMods(dnStr, attr, "false");
    }
  }
@@ -1746,10 +1737,9 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    applyPwdPolicyMods(conn, dnStr,
        "ds-cfg-lockout-failure-count", "3");
    applyPwdPolicyMods(dnStr, "ds-cfg-lockout-failure-count",
        "3");
    try
    {
@@ -1777,8 +1767,8 @@
      assertNotNull(userEntry);
      assertTrue(userEntry.hasAttribute(authFailureTimesAttr));
    } finally {
      applyPwdPolicyMods(conn, dnStr,
          "ds-cfg-lockout-failure-count", "0");
      applyPwdPolicyMods(dnStr, "ds-cfg-lockout-failure-count",
          "0");
    }
  }
@@ -1797,10 +1787,8 @@
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    applyPwdPolicyMods(conn, dnStr ,
        "ds-cfg-password-history-count", "5");
    applyPwdPolicyMods(dnStr, "ds-cfg-password-history-count" , "5");
    try
    {
@@ -1829,8 +1817,8 @@
    }
    finally
    {
      applyPwdPolicyMods(conn, dnStr,
          "ds-cfg-password-history-count", "0");
      applyPwdPolicyMods(dnStr, "ds-cfg-password-history-count",
          "0");
    }
  }
@@ -1857,21 +1845,23 @@
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
  }
  private void applyPwdPolicyMods(InternalClientConnection conn, String pwPolDN, String attr, String value)
  private void applyPwdPolicyMods(String pwPolDN, String attr, String value)
      throws DirectoryException
  {
    ArrayList<Modification> mods = new ArrayList<>();
    mods.add(new Modification(ModificationType.REPLACE,
        value == null ? Attributes.empty(attr) : Attributes.create(attr, value)));
    ModifyOperation modifyOperation = conn.processModify(DN.valueOf(pwPolDN), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    List<Modification> mods = newModifications(REPLACE, attr, value);
    ModifyOperation op = getRootConnection().processModify(DN.valueOf(pwPolDN), mods);
    assertEquals(op.getResultCode(), ResultCode.SUCCESS);
  }
  private void setPasswordChangedTime(InternalClientConnection conn, Entry userEntry) {
    ArrayList<Modification> mods = new ArrayList<>();
    mods.add(new Modification(ModificationType.REPLACE,
        Attributes.create("pwdchangedtime", "20050101000000.000Z")));
    ModifyOperation modifyOperation = conn.processModify(userEntry.getName(), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
  private void setPasswordChangedTime(Entry userEntry) {
    List<Modification> mods = newModifications(REPLACE, "pwdchangedtime", "20050101000000.000Z");
    ModifyOperation op = getRootConnection().processModify(userEntry.getName(), mods);
    assertEquals(op.getResultCode(), ResultCode.SUCCESS);
  }
  private List<Modification> newModifications(ModificationType modType, String attrName, String attrValue)
  {
    return newArrayList(new Modification(modType,
        attrValue == null ? Attributes.empty(attrName) : Attributes.create(attrName, attrValue)));
  }
}