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

Ludovic Poitou
17.41.2015 3be59b3c0b3a13204a84aad9e391ec7914eea206
opendj-server-legacy/src/main/java/org/opends/server/extensions/PasswordModifyExtendedOperation.java
@@ -70,37 +70,23 @@
 * as for generating a new password if none was provided.
 */
public class PasswordModifyExtendedOperation
       extends ExtendedOperationHandler<
                    PasswordModifyExtendedOperationHandlerCfg>
       implements ConfigurationChangeListener<
                    PasswordModifyExtendedOperationHandlerCfg>
       extends ExtendedOperationHandler<PasswordModifyExtendedOperationHandlerCfg>
       implements ConfigurationChangeListener<PasswordModifyExtendedOperationHandlerCfg>
{
  // The following attachments may be used by post-op plugins (e.g. Samba) in
  // order to avoid re-decoding the request parameters and also to enforce
  // atomicity.
  /**
   * The name of the attachment which will be used to store the fully resolved
   * target entry.
   */
  /** The name of the attachment which will be used to store the fully resolved target entry. */
  public static final String AUTHZ_DN_ATTACHMENT;
  /**
   * The name of the attachment which will be used to store the password
   * attribute.
   */
  /** The name of the attachment which will be used to store the password attribute. */
  public static final String PWD_ATTRIBUTE_ATTACHMENT;
  /**
   * The clear text password, which may not be present if the provided password
   * was pre-encoded.
   */
  /** The clear text password, which may not be present if the provided password was pre-encoded. */
  public static final String CLEAR_PWD_ATTACHMENT;
  /**
   * A list containing the encoded passwords: plugins can perform changes
   * atomically via CAS.
   */
  /** A list containing the encoded passwords: plugins can perform changes atomically via CAS. */
  public static final String ENCODED_PWD_ATTACHMENT;
  static
@@ -122,22 +108,21 @@
  /** The reference to the identity mapper. */
  private IdentityMapper<?> identityMapper;
  /**
   * Create an instance of this password modify extended operation.  All
   * initialization should be performed in the
   * Create an instance of this password modify extended operation.  All initialization should be performed in the
   * <CODE>initializeExtendedOperationHandler</CODE> method.
   */
  public PasswordModifyExtendedOperation()
  {
    super(new HashSet<String>(Arrays.asList(
        OID_LDAP_NOOP_OPENLDAP_ASSIGNED, OID_PASSWORD_POLICY_CONTROL)));
    super(new HashSet<String>(Arrays.asList(OID_LDAP_NOOP_OPENLDAP_ASSIGNED, OID_PASSWORD_POLICY_CONTROL)));
  }
  /**
   * Initializes this extended operation handler based on the information in the
   * provided configuration.  It should also register itself with the
   * Directory Server for the particular kinds of extended operations that it
   * will process.
   * Initializes this extended operation handler based on the information in the provided configuration.
   * It should also register itself with the Directory Server for the particular kinds of extended operations
   * that it will process.
   *
   * @param   config      The configuration that contains the information
   *                      to use to initialize this extended operation handler.
@@ -146,12 +131,10 @@
   *                           process of performing the initialization.
   *
   * @throws  InitializationException  If a problem occurs during initialization
   *                                   that is not related to the server
   *                                   configuration.
   *                                   that is not related to the server configuration.
   */
  @Override
  public void initializeExtendedOperationHandler(
       PasswordModifyExtendedOperationHandlerCfg config)
  public void initializeExtendedOperationHandler(PasswordModifyExtendedOperationHandlerCfg config)
         throws ConfigException, InitializationException
  {
    try
@@ -167,8 +150,8 @@
    catch (Exception e)
    {
      logger.traceException(e);
      LocalizableMessage message = ERR_EXTOP_PASSMOD_CANNOT_DETERMINE_ID_MAPPER.get(
          config.dn(), getExceptionMessage(e));
      LocalizableMessage message = ERR_EXTOP_PASSMOD_CANNOT_DETERMINE_ID_MAPPER
          .get(config.dn(), getExceptionMessage(e));
      throw new InitializationException(message, e);
    }
@@ -182,10 +165,9 @@
  }
  /**
   * Performs any finalization that may be necessary for this extended
   * operation handler.  By default, no finalization is performed.
   * Performs any finalization that may be necessary for this extended operation handler.
   * By default, no finalization is performed.
   */
  @Override
  public void finalizeExtendedOperationHandler()
@@ -195,6 +177,7 @@
    super.finalizeExtendedOperationHandler();
  }
  /**
   * Processes the provided extended operation.
   *
@@ -203,13 +186,11 @@
  @Override
  public void processExtendedOperation(ExtendedOperation operation)
  {
    // Initialize the variables associated with components that may be included
    // in the request.
    // Initialize the variables associated with components that may be included in the request.
    ByteString userIdentity = null;
    ByteString oldPassword  = null;
    ByteString newPassword  = null;
    // Look at the set of controls included in the request, if there are any.
    boolean                   noOpRequested        = false;
    boolean                   pwPolicyRequested    = false;
@@ -233,7 +214,6 @@
      }
    }
    // Parse the encoded request, if there is one.
    ByteString requestValue = operation.getRequestValue();
    if (requestValue != null)
@@ -242,18 +222,15 @@
      {
        ASN1Reader reader = ASN1.getReader(requestValue);
        reader.readStartSequence();
        if(reader.hasNextElement() &&
            reader.peekType() == TYPE_PASSWORD_MODIFY_USER_ID)
        if(reader.hasNextElement() && reader.peekType() == TYPE_PASSWORD_MODIFY_USER_ID)
        {
          userIdentity = reader.readOctetString();
        }
        if(reader.hasNextElement() &&
            reader.peekType() == TYPE_PASSWORD_MODIFY_OLD_PASSWORD)
        if(reader.hasNextElement() && reader.peekType() == TYPE_PASSWORD_MODIFY_OLD_PASSWORD)
        {
          oldPassword = reader.readOctetString();
        }
        if(reader.hasNextElement() &&
            reader.peekType() == TYPE_PASSWORD_MODIFY_NEW_PASSWORD)
        if(reader.hasNextElement() && reader.peekType() == TYPE_PASSWORD_MODIFY_NEW_PASSWORD)
        {
          newPassword = reader.readOctetString();
        }
@@ -264,17 +241,14 @@
        logger.traceException(ae);
        operation.setResultCode(ResultCode.PROTOCOL_ERROR);
        operation.appendErrorMessage(ERR_EXTOP_PASSMOD_CANNOT_DECODE_REQUEST
            .get(getExceptionMessage(ae)));
        operation.appendErrorMessage(ERR_EXTOP_PASSMOD_CANNOT_DECODE_REQUEST.get(getExceptionMessage(ae)));
        return;
      }
    }
    // Get the entry for the user that issued the request.
    Entry requestorEntry = operation.getAuthorizationEntry();
    // See if a user identity was provided.  If so, then try to resolve it to
    // an actual user.
    DN    userDN    = null;
@@ -285,23 +259,19 @@
    {
      if (userIdentity == null)
      {
        // This request must be targeted at changing the password for the
        // currently-authenticated user.  Make sure that the user actually is
        // authenticated.
        // This request must be targeted at changing the password for the currently-authenticated user.
        // Make sure that the user actually is authenticated.
        ClientConnection   clientConnection = operation.getClientConnection();
        AuthenticationInfo authInfo = clientConnection.getAuthenticationInfo();
        if ((! authInfo.isAuthenticated()) || (requestorEntry == null))
        {
          operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
          operation.appendErrorMessage(
                  ERR_EXTOP_PASSMOD_NO_AUTH_OR_USERID.get());
          operation.appendErrorMessage(ERR_EXTOP_PASSMOD_NO_AUTH_OR_USERID.get());
          return;
        }
        // Retrieve a write lock on that user's entry.
        userDN = requestorEntry.getName();
        userLock = LockManager.lockWrite(userDN);
        if (userLock == null)
        {
@@ -328,13 +298,11 @@
            logger.traceException(de);
            operation.setResultCode(ResultCode.INVALID_DN_SYNTAX);
            operation.appendErrorMessage(
                    ERR_EXTOP_PASSMOD_CANNOT_DECODE_AUTHZ_DN.get(authzIDStr));
            operation.appendErrorMessage(ERR_EXTOP_PASSMOD_CANNOT_DECODE_AUTHZ_DN.get(authzIDStr));
            return;
          }
          // If the provided DN is an alternate DN for a root user, then replace
          // it with the actual root DN.
          // If the provided DN is an alternate DN for a root user, then replace it with the actual root DN.
          DN actualRootDN = DirectoryServer.getActualRootBindDN(userDN);
          if (actualRootDN != null)
          {
@@ -355,8 +323,7 @@
            if (userEntry == null)
            {
              operation.setResultCode(ResultCode.NO_SUCH_OBJECT);
              operation.appendErrorMessage(
                      ERR_EXTOP_PASSMOD_CANNOT_MAP_USER.get(authzIDStr));
              operation.appendErrorMessage(ERR_EXTOP_PASSMOD_CANNOT_MAP_USER.get(authzIDStr));
              return;
            }
@@ -368,15 +335,13 @@
            //Encountered an exception while resolving identity.
            operation.setResultCode(de.getResultCode());
            operation.appendErrorMessage(ERR_EXTOP_PASSMOD_ERROR_MAPPING_USER
                    .get(authzIDStr,de.getMessageObject()));
            operation.appendErrorMessage(ERR_EXTOP_PASSMOD_ERROR_MAPPING_USER.get(authzIDStr, de.getMessageObject()));
            return;
          }
        }
        // the userIdentity provided does not follow Authorization Identity
        // form. RFC3062 declaration "may or may not be an LDAPDN" allows
        // for pretty much anything in that field. we gonna try to parse it
        // as DN first then if that fails as user ID.
        // the userIdentity provided does not follow Authorization Identity form. RFC3062 declaration "may or may
        // not be an LDAPDN" allows for pretty much anything in that field. we gonna try to parse it as DN first
        // then if that fails as user ID.
        else
        {
          try
@@ -389,8 +354,7 @@
          }
          if (userDN != null && !userDN.isRootDN()) {
            // If the provided DN is an alternate DN for a root user,
            // then replace it with the actual root DN.
            // If the provided DN is an alternate DN for a root user, then replace it with the actual root DN.
            DN actualRootDN = DirectoryServer.getActualRootBindDN(userDN);
            if (actualRootDN != null) {
              userDN = actualRootDN;
@@ -410,8 +374,7 @@
          if (userEntry == null) {
            // The userIdentity was invalid.
            operation.setResultCode(ResultCode.PROTOCOL_ERROR);
            operation.appendErrorMessage(
              ERR_EXTOP_PASSMOD_INVALID_AUTHZID_STRING.get(authzIDStr));
            operation.appendErrorMessage(ERR_EXTOP_PASSMOD_INVALID_AUTHZID_STRING.get(authzIDStr));
            return;
          }
@@ -419,38 +382,30 @@
        }
      }
      // At this point, we should have the user entry.  Get the associated
      // password policy.
      // At this point, we should have the user entry.  Get the associated password policy.
      PasswordPolicyState pwPolicyState;
      try
      {
        AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry,
            false);
        AuthenticationPolicy policy = AuthenticationPolicy.forUser(userEntry, false);
        if (!policy.isPasswordPolicy())
        {
          operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
          operation.appendErrorMessage(ERR_EXTOP_PASSMOD_ACCOUNT_NOT_LOCAL.get(userDN));
          return;
        }
        pwPolicyState = (PasswordPolicyState) policy
          .createAuthenticationPolicyState(userEntry);
        pwPolicyState = (PasswordPolicyState) policy.createAuthenticationPolicyState(userEntry);
      }
      catch (DirectoryException de)
      {
        logger.traceException(de);
        operation.setResultCode(DirectoryServer.getServerErrorResultCode());
        operation.appendErrorMessage(
                ERR_EXTOP_PASSMOD_CANNOT_GET_PW_POLICY.get(userDN, de.getMessageObject()));
        operation.appendErrorMessage(ERR_EXTOP_PASSMOD_CANNOT_GET_PW_POLICY.get(userDN, de.getMessageObject()));
        return;
      }
      // Determine whether the user is changing his own password or if it's an
      // administrative reset.  If it's an administrative reset, then the
      // requester must have the PASSWORD_RESET privilege.
      // Determine whether the user is changing his own password or if it's an administrative reset.
      // If it's an administrative reset, then the requester must have the PASSWORD_RESET privilege.
      boolean selfChange;
      if (userIdentity == null)
      {
@@ -468,17 +423,14 @@
      if (! selfChange)
      {
        ClientConnection clientConnection = operation.getClientConnection();
        if (! clientConnection.hasPrivilege(Privilege.PASSWORD_RESET,
                                            operation))
        if (! clientConnection.hasPrivilege(Privilege.PASSWORD_RESET, operation))
        {
          operation.appendErrorMessage(
                  ERR_EXTOP_PASSMOD_INSUFFICIENT_PRIVILEGES.get());
          operation.appendErrorMessage(ERR_EXTOP_PASSMOD_INSUFFICIENT_PRIVILEGES.get());
          operation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
          return;
        }
      }
      // See if the account is locked.  If so, then reject the request.
      if (pwPolicyState.isDisabled())
      {
@@ -486,27 +438,23 @@
        {
          pwPolicyErrorType = PasswordPolicyErrorType.ACCOUNT_LOCKED;
          operation.addResponseControl(
               new PasswordPolicyResponseControl(pwPolicyWarningType,
                                                 pwPolicyWarningValue,
                                                 pwPolicyErrorType));
               new PasswordPolicyResponseControl(pwPolicyWarningType, pwPolicyWarningValue, pwPolicyErrorType));
        }
        operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
        operation.appendErrorMessage(ERR_EXTOP_PASSMOD_ACCOUNT_DISABLED.get());
        return;
      }
      else if (selfChange &&
               (pwPolicyState.lockedDueToFailures() ||
                pwPolicyState.lockedDueToIdleInterval() ||
                pwPolicyState.lockedDueToMaximumResetAge()))
      else if (selfChange
          && (pwPolicyState.lockedDueToFailures()
              || pwPolicyState.lockedDueToIdleInterval()
              || pwPolicyState.lockedDueToMaximumResetAge()))
      {
        if (pwPolicyRequested)
        {
          pwPolicyErrorType = PasswordPolicyErrorType.ACCOUNT_LOCKED;
          operation.addResponseControl(
               new PasswordPolicyResponseControl(pwPolicyWarningType,
                                                 pwPolicyWarningValue,
                                                 pwPolicyErrorType));
               new PasswordPolicyResponseControl(pwPolicyWarningType, pwPolicyWarningValue, pwPolicyErrorType));
        }
        operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
@@ -514,28 +462,21 @@
        return;
      }
      // If the current password was provided, then we'll need to verify whether
      // it was correct.  If it wasn't provided but this is a self change, then
      // make sure that's OK.
      // If the current password was provided, then we'll need to verify whether it was correct.
      // If it wasn't provided but this is a self change, then make sure that's OK.
      if (oldPassword == null)
      {
        if (selfChange
            && pwPolicyState.getAuthenticationPolicy()
                .isPasswordChangeRequiresCurrentPassword())
            && pwPolicyState.getAuthenticationPolicy().isPasswordChangeRequiresCurrentPassword())
        {
          operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
          operation.appendErrorMessage(
                  ERR_EXTOP_PASSMOD_REQUIRE_CURRENT_PW.get());
          operation.appendErrorMessage(ERR_EXTOP_PASSMOD_REQUIRE_CURRENT_PW.get());
          if (pwPolicyRequested)
          {
            pwPolicyErrorType =
                 PasswordPolicyErrorType.MUST_SUPPLY_OLD_PASSWORD;
            pwPolicyErrorType = PasswordPolicyErrorType.MUST_SUPPLY_OLD_PASSWORD;
            operation.addResponseControl(
                 new PasswordPolicyResponseControl(pwPolicyWarningType,
                                                   pwPolicyWarningValue,
                                                   pwPolicyErrorType));
                 new PasswordPolicyResponseControl(pwPolicyWarningType, pwPolicyWarningValue, pwPolicyErrorType));
          }
          return;
@@ -543,13 +484,11 @@
      }
      else
      {
        if (pwPolicyState.getAuthenticationPolicy()
            .isRequireSecureAuthentication()
        if (pwPolicyState.getAuthenticationPolicy().isRequireSecureAuthentication()
            && !operation.getClientConnection().isSecure())
        {
          operation.setResultCode(ResultCode.CONFIDENTIALITY_REQUIRED);
          operation.addAdditionalLogItem(AdditionalLogItem.quotedKeyValue(
              getClass(), "additionalInfo",
          operation.addAdditionalLogItem(AdditionalLogItem.quotedKeyValue(getClass(), "additionalInfo",
              ERR_EXTOP_PASSMOD_SECURE_AUTH_REQUIRED.get()));
          return;
        }
@@ -561,16 +500,14 @@
        else
        {
          operation.setResultCode(ResultCode.INVALID_CREDENTIALS);
          operation.addAdditionalLogItem(AdditionalLogItem.quotedKeyValue(
              getClass(), "additionalInfo",
          operation.addAdditionalLogItem(AdditionalLogItem.quotedKeyValue(getClass(), "additionalInfo",
              ERR_EXTOP_PASSMOD_INVALID_OLD_PASSWORD.get()));
          pwPolicyState.updateAuthFailureTimes();
          List<Modification> mods = pwPolicyState.getModifications();
          if (! mods.isEmpty())
          {
            InternalClientConnection conn =
                 InternalClientConnection.getRootConnection();
            InternalClientConnection conn = InternalClientConnection.getRootConnection();
            conn.processModify(userDN, mods);
          }
@@ -578,53 +515,39 @@
        }
      }
      // If it is a self password change and we don't allow that, then reject
      // the request.
      // If it is a self password change and we don't allow that, then reject the request.
      if (selfChange
          && !pwPolicyState.getAuthenticationPolicy()
              .isAllowUserPasswordChanges())
          && !pwPolicyState.getAuthenticationPolicy().isAllowUserPasswordChanges())
      {
        if (pwPolicyRequested)
        {
          pwPolicyErrorType = PasswordPolicyErrorType.PASSWORD_MOD_NOT_ALLOWED;
          operation.addResponseControl(
               new PasswordPolicyResponseControl(pwPolicyWarningType,
                                                 pwPolicyWarningValue,
                                                 pwPolicyErrorType));
               new PasswordPolicyResponseControl(pwPolicyWarningType, pwPolicyWarningValue, pwPolicyErrorType));
        }
        operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
        operation.appendErrorMessage(
                ERR_EXTOP_PASSMOD_USER_PW_CHANGES_NOT_ALLOWED.get());
        operation.appendErrorMessage(ERR_EXTOP_PASSMOD_USER_PW_CHANGES_NOT_ALLOWED.get());
        return;
      }
      // If we require secure password changes and the connection isn't secure,
      // then reject the request.
      if (pwPolicyState.getAuthenticationPolicy()
          .isRequireSecurePasswordChanges()
      // If we require secure password changes and the connection isn't secure, then reject the request.
      if (pwPolicyState.getAuthenticationPolicy().isRequireSecurePasswordChanges()
          && !operation.getClientConnection().isSecure())
      {
        operation.setResultCode(ResultCode.CONFIDENTIALITY_REQUIRED);
        operation.appendErrorMessage(
                ERR_EXTOP_PASSMOD_SECURE_CHANGES_REQUIRED.get());
        operation.appendErrorMessage(ERR_EXTOP_PASSMOD_SECURE_CHANGES_REQUIRED.get());
        return;
      }
      // If it's a self-change request and the user is within the minimum age,
      // then reject it.
      // If it's a self-change request and the user is within the minimum age, then reject it.
      if (selfChange && pwPolicyState.isWithinMinimumAge())
      {
        if (pwPolicyRequested)
        {
          pwPolicyErrorType = PasswordPolicyErrorType.PASSWORD_TOO_YOUNG;
          operation.addResponseControl(
               new PasswordPolicyResponseControl(pwPolicyWarningType,
                                                 pwPolicyWarningValue,
                                                 pwPolicyErrorType));
               new PasswordPolicyResponseControl(pwPolicyWarningType, pwPolicyWarningValue, pwPolicyErrorType));
        }
        operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
@@ -632,33 +555,25 @@
        return;
      }
      // If the user's password is expired and it's a self-change request, then
      // see if that's OK.
      // If the user's password is expired and it's a self-change request, then see if that's OK.
      if (selfChange
          && pwPolicyState.isPasswordExpired()
          && !pwPolicyState.getAuthenticationPolicy()
              .isAllowExpiredPasswordChanges())
          && !pwPolicyState.getAuthenticationPolicy().isAllowExpiredPasswordChanges())
      {
        if (pwPolicyRequested)
        {
          pwPolicyErrorType = PasswordPolicyErrorType.PASSWORD_EXPIRED;
          operation.addResponseControl(
               new PasswordPolicyResponseControl(pwPolicyWarningType,
                                                 pwPolicyWarningValue,
                                                 pwPolicyErrorType));
               new PasswordPolicyResponseControl(pwPolicyWarningType, pwPolicyWarningValue, pwPolicyErrorType));
        }
        operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
        operation.appendErrorMessage(
                ERR_EXTOP_PASSMOD_PASSWORD_IS_EXPIRED.get());
        operation.appendErrorMessage(ERR_EXTOP_PASSMOD_PASSWORD_IS_EXPIRED.get());
        return;
      }
      // If the a new password was provided, then perform any appropriate
      // validation on it.  If not, then see if we can generate one.
      // If the a new password was provided, then perform any appropriate validation on it.
      // If not, then see if we can generate one.
      boolean generatedPassword = false;
      boolean isPreEncoded      = false;
      if (newPassword == null)
@@ -669,8 +584,7 @@
          if (newPassword == null)
          {
            operation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
            operation.appendErrorMessage(
                    ERR_EXTOP_PASSMOD_NO_PW_GENERATOR.get());
            operation.appendErrorMessage(ERR_EXTOP_PASSMOD_NO_PW_GENERATOR.get());
            return;
          }
@@ -679,13 +593,24 @@
        catch (DirectoryException de)
        {
          logger.traceException(de);
          operation.setResultCode(de.getResultCode());
          operation.appendErrorMessage(
                  ERR_EXTOP_PASSMOD_CANNOT_GENERATE_PW.get(
                          de.getMessageObject()));
          operation.appendErrorMessage(ERR_EXTOP_PASSMOD_CANNOT_GENERATE_PW.get(de.getMessageObject()));
          return;
        }
        // Prepare to update the password history, if necessary.
        if (pwPolicyState.maintainHistory())
        {
          if (pwPolicyState.isPasswordInHistory(newPassword))
          {
            operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
            operation.appendErrorMessage(ERR_EXTOP_PASSMOD_PW_IN_HISTORY.get());
            return;
          }
          else
          {
            pwPolicyState.updatePasswordHistory();
          }
        }
      }
      else
      {
@@ -695,27 +620,22 @@
          // by an internal operation or during synchronization, so we don't
          // need to check for those cases.
          isPreEncoded = true;
          if (!pwPolicyState.getAuthenticationPolicy()
              .isAllowPreEncodedPasswords())
          if (!pwPolicyState.getAuthenticationPolicy().isAllowPreEncodedPasswords())
          {
            operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
            operation.appendErrorMessage(
                    ERR_EXTOP_PASSMOD_PRE_ENCODED_NOT_ALLOWED.get());
            operation.appendErrorMessage(ERR_EXTOP_PASSMOD_PRE_ENCODED_NOT_ALLOWED.get());
            return;
          }
        }
        else
        {
          // Run the new password through the set of password validators.
          if (selfChange
              || !pwPolicyState.getAuthenticationPolicy()
                  .isSkipValidationForAdministrators())
          if (selfChange || !pwPolicyState.getAuthenticationPolicy().isSkipValidationForAdministrators())
          {
            Set<ByteString> clearPasswords;
            if (oldPassword == null)
            {
              clearPasswords =
                   new HashSet<ByteString>(pwPolicyState.getClearPasswords());
              clearPasswords = new HashSet<ByteString>(pwPolicyState.getClearPasswords());
            }
            else
            {
@@ -731,19 +651,13 @@
            }
            LocalizableMessageBuilder invalidReason = new LocalizableMessageBuilder();
            if (! pwPolicyState.passwordIsAcceptable(operation, userEntry,
                                                     newPassword,
                                                     clearPasswords,
                                                     invalidReason))
            if (! pwPolicyState.passwordIsAcceptable(operation, userEntry, newPassword, clearPasswords, invalidReason))
            {
              if (pwPolicyRequested)
              {
                pwPolicyErrorType =
                     PasswordPolicyErrorType.INSUFFICIENT_PASSWORD_QUALITY;
                pwPolicyErrorType = PasswordPolicyErrorType.INSUFFICIENT_PASSWORD_QUALITY;
                operation.addResponseControl(
                     new PasswordPolicyResponseControl(pwPolicyWarningType,
                                                       pwPolicyWarningValue,
                                                       pwPolicyErrorType));
                     new PasswordPolicyResponseControl(pwPolicyWarningType,  pwPolicyWarningValue, pwPolicyErrorType));
              }
              operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
@@ -753,19 +667,15 @@
            }
          }
          // Prepare to update the password history, if necessary.
          if (pwPolicyState.maintainHistory())
          {
            if (pwPolicyState.isPasswordInHistory(newPassword))
            {
              if (selfChange
                  || !pwPolicyState.getAuthenticationPolicy()
                      .isSkipValidationForAdministrators())
              if (selfChange || !pwPolicyState.getAuthenticationPolicy().isSkipValidationForAdministrators())
              {
                operation.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                operation.appendErrorMessage(
                        ERR_EXTOP_PASSMOD_PW_IN_HISTORY.get());
                operation.appendErrorMessage(ERR_EXTOP_PASSMOD_PW_IN_HISTORY.get());
                return;
              }
            }
@@ -777,7 +687,6 @@
        }
      }
      // Get the encoded forms of the new password.
      List<ByteString> encodedPasswords;
      if (isPreEncoded)
@@ -796,48 +705,37 @@
          logger.traceException(de);
          operation.setResultCode(de.getResultCode());
          operation.appendErrorMessage(
                  ERR_EXTOP_PASSMOD_CANNOT_ENCODE_PASSWORD.get(
                          de.getMessageObject()));
          operation.appendErrorMessage(ERR_EXTOP_PASSMOD_CANNOT_ENCODE_PASSWORD.get(de.getMessageObject()));
          return;
        }
      }
      // If the current password was provided, then remove all matching values
      // from the user's entry and replace them with the new password.
      // Otherwise replace all password values.
      AttributeType attrType = pwPolicyState.getAuthenticationPolicy()
          .getPasswordAttribute();
      // If the current password was provided, then remove all matching values from the user's entry
      // and replace them with the new password.  Otherwise replace all password values.
      AttributeType attrType = pwPolicyState.getAuthenticationPolicy().getPasswordAttribute();
      List<Modification> modList = new ArrayList<Modification>();
      if (oldPassword != null)
      {
        // Remove all existing encoded values that match the old password.
        Set<ByteString> existingValues = pwPolicyState.getPasswordValues();
        Set<ByteString> deleteValues =
             new LinkedHashSet<ByteString>(existingValues.size());
        Set<ByteString> deleteValues = new LinkedHashSet<ByteString>(existingValues.size());
        if (pwPolicyState.getAuthenticationPolicy().isAuthPasswordSyntax())
        {
          for (ByteString v : existingValues)
          {
            try
            {
              StringBuilder[] components =
                 AuthPasswordSyntax.decodeAuthPassword(v.toString());
              StringBuilder[] components = AuthPasswordSyntax.decodeAuthPassword(v.toString());
              PasswordStorageScheme<?> scheme =
                   DirectoryServer.getAuthPasswordStorageScheme(
                        components[0].toString());
                   DirectoryServer.getAuthPasswordStorageScheme(components[0].toString());
              if (scheme == null)
              {
                // The password is encoded using an unknown scheme.  Remove it
                // from the user's entry.
                // The password is encoded using an unknown scheme.  Remove it from the user's entry.
                deleteValues.add(v);
              }
              else
              {
                if (scheme.authPasswordMatches(oldPassword,
                                               components[1].toString(),
                                               components[2].toString()))
                if (scheme.authPasswordMatches(oldPassword, components[1].toString(), components[2].toString()))
                {
                  deleteValues.add(v);
                }
@@ -847,8 +745,7 @@
            {
              logger.traceException(de);
              // We couldn't decode the provided password value, so remove it
              // from the user's entry.
              // We couldn't decode the provided password value, so remove it from the user's entry.
              deleteValues.add(v);
            }
          }
@@ -859,21 +756,17 @@
          {
            try
            {
              String[] components =
                 UserPasswordSyntax.decodeUserPassword(v.toString());
              String[] components = UserPasswordSyntax.decodeUserPassword(v.toString());
              PasswordStorageScheme<?> scheme =
                   DirectoryServer.getPasswordStorageScheme(
                        toLowerCase(components[0]));
                   DirectoryServer.getPasswordStorageScheme(toLowerCase(components[0]));
              if (scheme == null)
              {
                // The password is encoded using an unknown scheme.  Remove it
                // from the user's entry.
                // The password is encoded using an unknown scheme.  Remove it from the user's entry.
                deleteValues.add(v);
              }
              else
              {
                if (scheme.passwordMatches(oldPassword,
                    ByteString.valueOf(components[1])))
                if (scheme.passwordMatches(oldPassword, ByteString.valueOf(components[1])))
                {
                  deleteValues.add(v);
                }
@@ -883,8 +776,7 @@
            {
              logger.traceException(de);
              // We couldn't decode the provided password value, so remove it
              // from the user's entry.
              // We couldn't decode the provided password value, so remove it from the user's entry.
              deleteValues.add(v);
            }
          }
@@ -895,7 +787,6 @@
        Attribute deleteAttr = builder.toAttribute();
        modList.add(new Modification(ModificationType.DELETE, deleteAttr));
        builder = new AttributeBuilder(attrType);
        builder.addAll(toAttributeValues(encodedPasswords));
        Attribute addAttr = builder.toAttribute();
@@ -909,32 +800,25 @@
        modList.add(new Modification(ModificationType.REPLACE, addAttr));
      }
      // Update the password changed time for the user entry.
      pwPolicyState.setPasswordChangedTime();
      // If the password was changed by an end user, then clear any reset flag
      // that might exist.  If the password was changed by an administrator,
      // then see if we need to set the reset flag.
      // If the password was changed by an end user, then clear any reset flag that might exist.
      // If the password was changed by an administrator, then see if we need to set the reset flag.
      if (selfChange)
      {
        pwPolicyState.setMustChangePassword(false);
      }
      else
      {
        pwPolicyState.setMustChangePassword(
             pwPolicyState.getAuthenticationPolicy().isForceChangeOnReset());
        pwPolicyState.setMustChangePassword(pwPolicyState.getAuthenticationPolicy().isForceChangeOnReset());
      }
      // Clear any record of grace logins, auth failures, and expiration
      // warnings.
      // Clear any record of grace logins, auth failures, and expiration warnings.
      pwPolicyState.clearFailureLockout();
      pwPolicyState.clearGraceLoginTimes();
      pwPolicyState.clearWarnedTime();
      // If the LDAP no-op control was included in the request, then set the
      // appropriate response.  Otherwise, process the operation.
      if (noOpRequested)
@@ -951,13 +835,10 @@
      // Get an internal connection and use it to perform the modification.
      boolean isRoot = DirectoryServer.isRootDN(requestorEntry.getName());
      AuthenticationInfo authInfo = new AuthenticationInfo(requestorEntry,
                                                           isRoot);
      InternalClientConnection internalConnection = new
           InternalClientConnection(authInfo);
      AuthenticationInfo authInfo = new AuthenticationInfo(requestorEntry, isRoot);
      InternalClientConnection internalConnection = new InternalClientConnection(authInfo);
      ModifyOperation modifyOperation =
           internalConnection.processModify(userDN, modList);
      ModifyOperation modifyOperation = internalConnection.processModify(userDN, modList);
      ResultCode resultCode = modifyOperation.getResultCode();
      if (resultCode != ResultCode.SUCCESS)
      {
@@ -967,7 +848,6 @@
        return;
      }
      // If there were any password policy state changes, we need to apply
      // them using a root connection because the end user may not have
      // sufficient access to apply them.  This is less efficient than
@@ -975,30 +855,24 @@
      List<Modification> pwPolicyMods = pwPolicyState.getModifications();
      if (! pwPolicyMods.isEmpty())
      {
        InternalClientConnection rootConnection =
             InternalClientConnection.getRootConnection();
        ModifyOperation modOp =
             rootConnection.processModify(userDN, pwPolicyMods);
        InternalClientConnection rootConnection = InternalClientConnection.getRootConnection();
        ModifyOperation modOp = rootConnection.processModify(userDN, pwPolicyMods);
        if (modOp.getResultCode() != ResultCode.SUCCESS)
        {
          // At this point, the user's password is already changed so there's
          // not much point in returning a non-success result.  However, we
          // should at least log that something went wrong.
          logger.warn(WARN_EXTOP_PASSMOD_CANNOT_UPDATE_PWP_STATE, userDN,
                  modOp.getResultCode(),
                  modOp.getErrorMessage());
          logger.warn(WARN_EXTOP_PASSMOD_CANNOT_UPDATE_PWP_STATE, userDN, modOp.getResultCode(),
              modOp.getErrorMessage());
        }
      }
      // If we've gotten here, then everything is OK, so indicate that the
      // operation was successful.
      // If we've gotten here, then everything is OK, so indicate that the operation was successful.
      operation.setResultCode(ResultCode.SUCCESS);
      // Save attachments for post-op plugins (e.g. Samba password plugin).
      operation.setAttachment(AUTHZ_DN_ATTACHMENT, userDN);
      operation.setAttachment(PWD_ATTRIBUTE_ATTACHMENT, pwPolicyState
          .getAuthenticationPolicy().getPasswordAttribute());
      operation.setAttachment(PWD_ATTRIBUTE_ATTACHMENT, pwPolicyState.getAuthenticationPolicy().getPasswordAttribute());
      if (!isPreEncoded)
      {
        operation.setAttachment(CLEAR_PWD_ATTACHMENT, newPassword);
@@ -1014,8 +888,7 @@
        try
        {
          writer.writeStartSequence();
          writer.writeOctetString(TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD,
              newPassword);
          writer.writeOctetString(TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD, newPassword);
          writer.writeEndSequence();
        }
        catch (IOException e)
@@ -1027,26 +900,20 @@
      }
      // If this was a self password change, and the client is authenticated
      // as the user whose password was changed, then clear the "must change
      // password" flag in the client connection.  Note that we're using the
      // authentication DN rather than the authorization DN in this case to
      // avoid mistakenly clearing the flag for the wrong user.
      if (selfChange && (authInfo.getAuthenticationDN() != null) &&
          (authInfo.getAuthenticationDN().equals(userDN)))
      // If this was a self password change, and the client is authenticated as the user whose password was changed,
      // then clear the "must change password" flag in the client connection.  Note that we're using the
      // authentication DN rather than the authorization DN in this case to avoid mistakenly clearing the flag
      // for the wrong user.
      if (selfChange && (authInfo.getAuthenticationDN() != null) && (authInfo.getAuthenticationDN().equals(userDN)))
      {
        operation.getClientConnection().setMustChangePassword(false);
      }
      // If the password policy control was requested, then add the
      // appropriate response control.
      // If the password policy control was requested, then add the appropriate response control.
      if (pwPolicyRequested)
      {
        operation.addResponseControl(
             new PasswordPolicyResponseControl(pwPolicyWarningType,
                                               pwPolicyWarningValue,
                                               pwPolicyErrorType));
             new PasswordPolicyResponseControl(pwPolicyWarningType, pwPolicyWarningValue, pwPolicyErrorType));
      }
      // Handle Account Status Notifications that may be needed.
@@ -1067,19 +934,15 @@
      {
        LocalizableMessage message = INFO_MODIFY_PASSWORD_CHANGED.get();
        pwPolicyState.generateAccountStatusNotification(
          AccountStatusNotificationType.PASSWORD_CHANGED,
          userEntry, message,
          AccountStatusNotification.createProperties(pwPolicyState, false,
                -1, currentPasswords, newPasswords));
            AccountStatusNotificationType.PASSWORD_CHANGED, userEntry, message,
            AccountStatusNotification.createProperties(pwPolicyState, false, -1, currentPasswords, newPasswords));
      }
      else
      {
        LocalizableMessage message = INFO_MODIFY_PASSWORD_RESET.get();
        pwPolicyState.generateAccountStatusNotification(
          AccountStatusNotificationType.PASSWORD_RESET,
          userEntry, message,
          AccountStatusNotification.createProperties(pwPolicyState, false,
                -1, currentPasswords, newPasswords));
            AccountStatusNotificationType.PASSWORD_RESET, userEntry, message,
            AccountStatusNotification.createProperties(pwPolicyState, false, -1, currentPasswords, newPasswords));
      }
    }
    finally
@@ -1097,22 +960,19 @@
  }
  /**
   * Retrieves the entry for the specified user based on the provided DN.  If
   * any problem is encountered or the requested entry does not exist, then the
   * provided operation will be updated with appropriate result information and
   * this method will return <CODE>null</CODE>.  The caller must hold a write
   * lock on the specified entry.
   * Retrieves the entry for the specified user based on the provided DN.  If any problem is encountered or
   * the requested entry does not exist, then the provided operation will be updated with appropriate result
   * information and this method will return <CODE>null</CODE>.
   * The caller must hold a write lock on the specified entry.
   *
   * @param  operation  The extended operation being processed.
   * @param  entryDN    The DN of the user entry to retrieve.
   *
   * @return  The requested entry, or <CODE>null</CODE> if there was no such
   *          entry or it could not be retrieved.
   * @return  The requested entry, or <CODE>null</CODE> if there was no such entry or it could not be retrieved.
   */
  private Entry getEntryByDN(ExtendedOperation operation, DN entryDN)
  {
    // Retrieve the user's entry from the directory.  If it does not exist, then
    // fail.
    // Retrieve the user's entry from the directory.  If it does not exist, then fail.
    try
    {
      Entry userEntry = DirectoryServer.getEntry(entryDN);
@@ -1120,8 +980,7 @@
      if (userEntry == null)
      {
        operation.setResultCode(ResultCode.NO_SUCH_OBJECT);
        operation.appendErrorMessage(
                ERR_EXTOP_PASSMOD_NO_USER_ENTRY_BY_AUTHZID.get(entryDN));
        operation.appendErrorMessage(ERR_EXTOP_PASSMOD_NO_USER_ENTRY_BY_AUTHZID.get(entryDN));
        // See if one of the entry's ancestors exists.
        operation.setMatchedDN(findMatchedDN(entryDN));
@@ -1168,35 +1027,29 @@
   * {@inheritDoc}
   */
  @Override
  public boolean isConfigurationAcceptable(ExtendedOperationHandlerCfg
                                                configuration,
  public boolean isConfigurationAcceptable(ExtendedOperationHandlerCfg configuration,
                                           List<LocalizableMessage> unacceptableReasons)
  {
    PasswordModifyExtendedOperationHandlerCfg config =
         (PasswordModifyExtendedOperationHandlerCfg) configuration;
    PasswordModifyExtendedOperationHandlerCfg config = (PasswordModifyExtendedOperationHandlerCfg) configuration;
    return isConfigurationChangeAcceptable(config, unacceptableReasons);
  }
  /**
   * Indicates whether the provided configuration entry has an acceptable
   * configuration for this component.  If it does not, then detailed
   * information about the problem(s) should be added to the provided list.
   * Indicates whether the provided configuration entry has an acceptable configuration for this component.
   * If it does not, then detailed information about the problem(s) should be added to the provided list.
   *
   * @param  config          The configuration entry for which to make the
   *                              determination.
   * @param  unacceptableReasons  A list that can be used to hold messages about
   *                              why the provided entry does not have an
   *                              acceptable configuration.
   * @param  config          The configuration entry for which to make the determination.
   * @param  unacceptableReasons  A list that can be used to hold messages about why the provided entry does not
   *                              have an acceptable configuration.
   *
   * @return  <CODE>true</CODE> if the provided entry has an acceptable
   *          configuration for this component, or <CODE>false</CODE> if not.
   * @return  <CODE>true</CODE> if the provided entry has an acceptable configuration for this component,
   *          or <CODE>false</CODE> if not.
   */
  @Override
  public boolean isConfigurationChangeAcceptable(
       PasswordModifyExtendedOperationHandlerCfg config,
       List<LocalizableMessage> unacceptableReasons)
  public boolean isConfigurationChangeAcceptable(PasswordModifyExtendedOperationHandlerCfg config,
                                                 List<LocalizableMessage> unacceptableReasons)
  {
    // Make sure that the specified identity mapper is OK.
    try
@@ -1217,7 +1070,6 @@
      return false;
    }
    // If we've gotten here, then everything is OK.
    return true;
  }
@@ -1225,26 +1077,21 @@
  /**
   * Makes a best-effort attempt to apply the configuration contained in the
   * provided entry.  Information about the result of this processing should be
   * added to the provided message list.  Information should always be added to
   * this list if a configuration change could not be applied.  If detailed
   * results are requested, then information about the changes applied
   * successfully (and optionally about parameters that were not changed) should
   * also be included.
   * Makes a best-effort attempt to apply the configuration contained in the provided entry.
   * Information about the result of this processing should be added to the provided message list.
   * Information should always be added to this list if a configuration change could not be applied.
   * If detailed results are requested, then information about the changes applied successfully (and optionally
   * about parameters that were not changed) should also be included.
   *
   * @param  config      The entry containing the new configuration to
   *                          apply for this component.
   * @param  config      The entry containing the new configuration to apply for this component.
   *
   * @return  Information about the result of the configuration update.
   */
  @Override
  public ConfigChangeResult applyConfigurationChange(
       PasswordModifyExtendedOperationHandlerCfg config)
  public ConfigChangeResult applyConfigurationChange(PasswordModifyExtendedOperationHandlerCfg config)
  {
    final ConfigChangeResult ccr = new ConfigChangeResult();
    // Make sure that the specified identity mapper is OK.
    DN             mapperDN = null;
    IdentityMapper<?> mapper   = null;
@@ -1266,7 +1113,6 @@
      ccr.addMessage(ERR_EXTOP_PASSMOD_CANNOT_DETERMINE_ID_MAPPER.get(config.dn(), getExceptionMessage(e)));
    }
    // If all of the changes were acceptable, then apply them.
    if (ccr.getResultCode() == ResultCode.SUCCESS
        && ! identityMapperDN.equals(mapperDN))
@@ -1275,7 +1121,6 @@
      identityMapperDN = mapperDN;
    }
    // Save this configuration for future reference.
    currentConfig = config;
opendj-server-legacy/src/test/java/org/opends/server/extensions/PasswordModifyExtendedOperationTestCase.java
@@ -89,8 +89,7 @@
         "objectClass: ds-cfg-extended-operation-handler",
         "objectClass: ds-cfg-password-modify-extended-operation-handler",
         "cn: Password Modify",
         "ds-cfg-java-class: org.opends.server." +
              "extensions.PasswordModifyExtendedOperation",
         "ds-cfg-java-class: org.opends.server.extensions.PasswordModifyExtendedOperation",
         "ds-cfg-enabled: true",
         "",
         "dn: cn=Password Modify,cn=Extended Operations,cn=config",
@@ -98,8 +97,7 @@
         "objectClass: ds-cfg-extended-operation-handler",
         "objectClass: ds-cfg-password-modify-extended-operation-handler",
         "cn: Password Modify",
         "ds-cfg-java-class: org.opends.server." +
              "extensions.PasswordModifyExtendedOperation",
         "ds-cfg-java-class: org.opends.server.extensions.PasswordModifyExtendedOperation",
         "ds-cfg-enabled: true",
         "ds-cfg-identity-mapper: invaliddn",
         "",
@@ -108,8 +106,7 @@
         "objectClass: ds-cfg-extended-operation-handler",
         "objectClass: ds-cfg-password-modify-extended-operation-handler",
         "cn: Password Modify",
         "ds-cfg-java-class: org.opends.server." +
              "extensions.PasswordModifyExtendedOperation",
         "ds-cfg-java-class: org.opends.server.extensions.PasswordModifyExtendedOperation",
         "ds-cfg-enabled: true",
         "ds-cfg-identity-mapper: cn=nonexistent,cn=config");
@@ -131,27 +128,21 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "invalidConfigs",
        expectedExceptions = { ConfigException.class,
                               InitializationException.class })
  @Test(dataProvider = "invalidConfigs", expectedExceptions = { ConfigException.class, InitializationException.class})
  public void testInitializeWithInvalidConfigs(Entry e)
         throws Exception
  {
    PasswordModifyExtendedOperationHandlerCfg configuration =
         AdminTestCaseUtils.getConfiguration(
              PasswordModifyExtendedOperationHandlerCfgDefn.getInstance(),
              e);
         AdminTestCaseUtils.getConfiguration(PasswordModifyExtendedOperationHandlerCfgDefn.getInstance(), e);
    PasswordModifyExtendedOperation handler =
         new PasswordModifyExtendedOperation();
    PasswordModifyExtendedOperation handler = new PasswordModifyExtendedOperation();
    handler.initializeExtendedOperationHandler(configuration);
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Authenticated as a root user</LI>
@@ -176,17 +167,9 @@
      "-c", "password",
      "-n", "newPassword"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn =
         new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
         conn.processSimpleBind(DN.valueOf("cn=Directory Manager"),
                                ByteString.valueOf("newPassword"));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
    verifyPasswordPerformingInternalBind(DN.valueOf("cn=Directory Manager"), "newPassword");
    // Now change the password back to what it was.
    args = new String[]
@@ -199,15 +182,12 @@
      "-c", "newPassword",
      "-n", "password"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Authenticated as a root user</LI>
@@ -233,17 +213,9 @@
      "-n", "newPassword",
      "-A"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn =
         new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
         conn.processSimpleBind(DN.valueOf("cn=Directory Manager"),
                                ByteString.valueOf("newPassword"));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
    verifyPasswordPerformingInternalBind(DN.valueOf("cn=Directory Manager"), "newPassword");
    // Now change the password back to what it was.
    args = new String[]
@@ -257,18 +229,15 @@
      "-n", "password",
      "-A"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Unauthenticated client conection</LI>
   *   <LI>Unauthenticated client connection</LI>
   *   <LI>Authorization ID provided</LI>
   *   <LI>Current password provided</LI>
   *   <LI>New password provided</LI>
@@ -289,17 +258,9 @@
      "-c", "password",
      "-n", "newPassword"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn =
         new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
         conn.processSimpleBind(DN.valueOf("cn=Directory Manager"),
                                ByteString.valueOf("newPassword"));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
    verifyPasswordPerformingInternalBind(DN.valueOf("cn=Directory Manager"), "newPassword");
    // Now change the password back to what it was.
    args = new String[]
@@ -311,15 +272,12 @@
      "-c", "newPassword",
      "-n", "password"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Authenticated as a normal user</LI>
@@ -335,18 +293,7 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "ds-privilege-name: bypass-acl",
         "userPassword: password");
    Entry userEntry = addDefaultTestEntry();
    String[] args =
@@ -359,22 +306,14 @@
      "-c", "password",
      "-n", "newPassword"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn = new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
         conn.processSimpleBind(userEntry.getName(),
                                ByteString.valueOf("newPassword"));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
    verifyPasswordPerformingInternalBind(userEntry.getName(), "newPassword");
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Authenticated as a normal user</LI>
@@ -390,18 +329,7 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "ds-privilege-name: bypass-acl",
         "userPassword: password");
    Entry userEntry = addDefaultTestEntry();
    String[] args =
@@ -413,22 +341,15 @@
      "-w", "password",
      "-n", "newPassword"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn = new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
         conn.processSimpleBind(userEntry.getName(),
                                ByteString.valueOf("newPassword"));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
    verifyPasswordPerformingInternalBind(userEntry.getName(), "newPassword");
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Authenticated as a normal user</LI>
@@ -466,15 +387,12 @@
      "-D", "uid=test.user,o=test",
      "-w", "password"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Authenticated as a normal user</LI>
@@ -490,18 +408,7 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "ds-privilege-name: bypass-acl",
         "userPassword: password");
    Entry userEntry = addDefaultTestEntry();
    String[] args =
@@ -514,22 +421,15 @@
      "-a", "dn:uid=test.user,o=test",
      "-n", "newPassword"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn = new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
         conn.processSimpleBind(userEntry.getName(),
                                ByteString.valueOf("newPassword"));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
    verifyPasswordPerformingInternalBind(userEntry.getName(), "newPassword");
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Authenticated as a normal user</LI>
@@ -545,18 +445,7 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "ds-privilege-name: bypass-acl",
         "userPassword: password");
    Entry userEntry = addDefaultTestEntry();
    String[] args =
@@ -569,22 +458,15 @@
      "-a", "u:test.user",
      "-n", "newPassword"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn = new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
         conn.processSimpleBind(userEntry.getName(),
                                ByteString.valueOf("newPassword"));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
    verifyPasswordPerformingInternalBind(userEntry.getName(), "newPassword");
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Authenticated as a normal user</LI>
@@ -600,18 +482,7 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "ds-privilege-name: bypass-acl",
         "userPassword: password");
    Entry userEntry = addDefaultTestEntry();
    String[] args =
@@ -624,22 +495,15 @@
      "-a", "uid=test.user,o=test",
      "-n", "newPassword"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn = new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
         conn.processSimpleBind(userEntry.getName(),
                                ByteString.valueOf("newPassword"));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
    verifyPasswordPerformingInternalBind(userEntry.getName(), "newPassword");
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Authenticated as a normal user</LI>
@@ -655,18 +519,7 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "ds-privilege-name: bypass-acl",
         "userPassword: password");
    Entry userEntry = addDefaultTestEntry();
    String[] args =
@@ -679,22 +532,15 @@
      "-a", "test.user",
      "-n", "newPassword"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn = new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
         conn.processSimpleBind(userEntry.getName(),
                                ByteString.valueOf("newPassword"));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
    verifyPasswordPerformingInternalBind(userEntry.getName(), "newPassword");
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Unauthenticated client connection</LI>
@@ -710,18 +556,7 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "ds-privilege-name: bypass-acl",
         "userPassword: password");
    Entry userEntry = addDefaultTestEntry();
    String[] args =
    {
@@ -732,22 +567,15 @@
      "-c", "password",
      "-n", "newPassword"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn = new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
         conn.processSimpleBind(userEntry.getName(),
                                ByteString.valueOf("newPassword"));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
    verifyPasswordPerformingInternalBind(userEntry.getName(), "newPassword");
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Unauthenticated client connection</LI>
@@ -763,18 +591,7 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "ds-privilege-name: bypass-acl",
         "userPassword: password");
    Entry userEntry = addDefaultTestEntry();
    String[] args =
    {
@@ -785,22 +602,15 @@
      "-c", "password",
      "-n", "newPassword"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn = new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
         conn.processSimpleBind(userEntry.getName(),
                                ByteString.valueOf("newPassword"));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
    verifyPasswordPerformingInternalBind(userEntry.getName(), "newPassword");
  }
  /**
   * Tests the password modify extended operation over LDAP.  It will use the
   * following configuration:
   * Tests the password modify extended operation over LDAP.  It will use the following configuration:
   * <BR>
   * <UL>
   *   <LI>Authenticated as a root user</LI>
@@ -816,18 +626,7 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "ds-privilege-name: bypass-acl",
         "userPassword: password");
    Entry userEntry = addDefaultTestEntry();
    String[] args =
    {
@@ -839,22 +638,16 @@
      "-a", "dn:uid=test.user,o=test",
      "-n", "newPassword"
    };
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null),
                 0);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn = new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
         conn.processSimpleBind(userEntry.getName(),
                                ByteString.valueOf("newPassword"));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
    verifyPasswordPerformingInternalBind(userEntry.getName(), "newPassword");
  }
  /**
   * Tests the password modify extended operation over LDAP using an
   * authorization ID with the DN of a user that doesn't exist.
   * Tests the password modify extended operation over LDAP using an authorization ID
   * with the DN of a user that doesn't exist.
   *
   *
   * @throws  Exception  If an unexpected error occurs.
@@ -876,16 +669,13 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
  }
  /**
   * Tests the password modify extended operation over LDAP using an
   * authorization ID with a malformed DN.
   * Tests the password modify extended operation over LDAP using an authorization ID with a malformed DN.
   *
   *
   * @throws  Exception  If an unexpected error occurs.
@@ -907,17 +697,14 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
  }
  /**
   * Tests the password modify extended operation over LDAP using an
   * authorization ID with the DN of a user where no part of the hierarchy
   * exists.
   * Tests the password modify extended operation over LDAP using an authorization ID with the DN
   * of a user where no part of the hierarchy exists.
   *
   *
   * @throws  Exception  If an unexpected error occurs.
@@ -939,16 +726,14 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
  }
  /**
   * Tests the password modify extended operation over LDAP using an
   * authorization ID with the uid of a user that doesn't exist.
   * Tests the password modify extended operation over LDAP using an authorization ID with the uid
   * of a user that doesn't exist.
   *
   *
   * @throws  Exception  If an unexpected error occurs.
@@ -970,17 +755,14 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
  }
  /**
   * Tests the password modify extended operation over LDAP using an
   * authorization ID with the uid of a user that doesn't exist and providing
   * the current password..
   * Tests the password modify extended operation over LDAP using an authorization ID with the uid
   * of a user that doesn't exist and providing the current password.
   *
   *
   * @throws  Exception  If an unexpected error occurs.
@@ -1003,16 +785,13 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertEquals(exitCode, 32);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 32);
  }
  /**
   * Tests the password modify extended operation over LDAP using a malformed
   * authorization ID.
   * Tests the password modify extended operation over LDAP using a malformed authorization ID.
   *
   *
   * @throws  Exception  If an unexpected error occurs.
@@ -1034,16 +813,13 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
  }
  /**
   * Tests the password modify extended operation over LDAP using a bad
   * current password.
   * Tests the password modify extended operation over LDAP using a bad current password.
   *
   *
   * @throws  Exception  If an unexpected error occurs.
@@ -1053,17 +829,7 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    String[] args =
    {
@@ -1077,17 +843,13 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertEquals(exitCode, 49);
    assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 49);
  }
  /**
   * Tests the password modify extended operation over LDAP using a pre-encoded
   * new password.
   *
   * Tests the password modify extended operation over LDAP using a pre-encoded new password.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -1096,27 +858,12 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-allow-pre-encoded-passwords";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "true")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    String[] args =
@@ -1130,23 +877,17 @@
      "-n", "{SSHA}Fv4b7f4AnRMUiGqBi9QA1xJrTtRTqS3WpRi81g=="
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertEquals(exitCode, 0);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "false")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "false");
    }
  }
  /**
   * Tests the password modify extended operation over LDAP using a pre-encoded
   * new password.
   * Tests the password modify extended operation over LDAP using a pre-encoded new password.
   *
   *
   * @throws  Exception  If an unexpected error occurs.
@@ -1156,26 +897,13 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    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";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
        Attributes.create(attr, "false")));
    ModifyOperation modifyOperation = getRootConnection().processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "false");
    String[] args =
    {
@@ -1188,17 +916,14 @@
      "-n", "{SSHA}Fv4b7f4AnRMUiGqBi9QA1xJrTtRTqS3WpRi81g=="
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    // don't restore password policy as this is already the default.
  }
  /**
   * Tests the password modify extended operation over LDAP using a pre-encoded
   * new password.
   *
   * Tests the password modify extended operation over LDAP using a pre-encoded new password.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -1207,26 +932,13 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    /* Make sure preEncoded passwords are rejected */
    /* 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";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
        Attributes.create(attr, "false")));
    ModifyOperation modifyOperation = getRootConnection().processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "false");
    String[] args =
    {
@@ -1238,35 +950,30 @@
      "-n", "{SSHA}Fv4b7f4AnRMUiGqBi9QA1xJrTtRTqS3WpRi81g=="
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
  }
  /**
   * Tests the password modify extended operation over an internal connection
   * with a request whose value isn't a valid encoded sequence.
   * Tests the password modify extended operation over an internal connection with a request whose value
   * isn't a valid encoded sequence.
   */
  @Test
  public void testFailureInvalidRequestValueFormat()
  {
    ByteString requestValue = ByteString.valueOf("malformed");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ExtendedOperation extOp =
         conn.processExtendedOperation(OID_PASSWORD_MODIFY_REQUEST,
                                       requestValue);
    InternalClientConnection conn = getRootConnection();
    ExtendedOperation extOp = conn.processExtendedOperation(OID_PASSWORD_MODIFY_REQUEST, requestValue);
    assertFalse(extOp.getResultCode() == ResultCode.SUCCESS);
  }
  /**
   * Tests the password modify extended operation over an internal connection
   * with a request that contain an invalid sequence element type.
   * Tests the password modify extended operation over an internal connection with a request that contain
   * an invalid sequence element type.
   */
  @Test
  public void testFailureInvalidSequenceElementType() throws Exception
@@ -1278,19 +985,16 @@
    writer.writeEndSequence();
    ByteString requestValue = builder.toByteString();
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ExtendedOperation extOp =
         conn.processExtendedOperation(OID_PASSWORD_MODIFY_REQUEST,
                                       requestValue);
    InternalClientConnection conn = getRootConnection();
    ExtendedOperation extOp = conn.processExtendedOperation(OID_PASSWORD_MODIFY_REQUEST, requestValue);
    assertFalse(extOp.getResultCode() == ResultCode.SUCCESS);
  }
  /**
   * Tests the password modify extended operation over an unauthenticated
   * internal connection and without providing an authorization ID.
   * Tests the password modify extended operation over an unauthenticated internal connection
   * and without providing an authorization ID.
   */
  @Test
  public void testFailureCompletelyAnonymous() throws Exception
@@ -1298,24 +1002,20 @@
    ByteStringBuilder builder = new ByteStringBuilder();
    ASN1Writer writer = ASN1.getWriter(builder);
    writer.writeStartSequence();
    writer.writeOctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD,
                                     "newPassword");
    writer.writeOctetString(TYPE_PASSWORD_MODIFY_NEW_PASSWORD, "newPassword");
    writer.writeEndSequence();
    ByteString requestValue = builder.toByteString();
    InternalClientConnection conn =
         new InternalClientConnection(new AuthenticationInfo());
    ExtendedOperation extOp =
         conn.processExtendedOperation(OID_PASSWORD_MODIFY_REQUEST,
                                       requestValue);
    InternalClientConnection conn = new InternalClientConnection(new AuthenticationInfo());
    ExtendedOperation extOp = conn.processExtendedOperation(OID_PASSWORD_MODIFY_REQUEST, requestValue);
    assertFalse(extOp.getResultCode() == ResultCode.SUCCESS);
  }
  /**
   * Tests the password modify extended operation with a password policy that
   * doesn't allow users to change their own passwords.
   * Tests the password modify extended operation with a password policy that doesn't allow users
   * to change their own passwords. The current password is not provided in the extended operation.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -1324,29 +1024,13 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-allow-user-password-changes";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "false")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "false");
    String[] args =
    {
@@ -1358,23 +1042,18 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "true")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "true");
    }
  }
  /**
   * Tests the password modify extended operation with a password policy that
   * doesn't allow users to change their own passwords.
   * Tests the password modify extended operation with a password policy that doesn't allow users to change
   * their own passwords. The current password is provided.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -1383,29 +1062,13 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-allow-user-password-changes";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "false")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "false");
    String[] args =
    {
@@ -1418,23 +1081,18 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertEquals(exitCode, 53);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "true")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 53);
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "true");
    }
  }
  /**
   * Tests the password modify extended operation without providing the current
   * password but with a password policy that requires it.
   * Tests the password modify extended operation without providing the current password
   * but with a password policy that requires it.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -1443,27 +1101,12 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-password-change-requires-current-password";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "true")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    String[] args =
@@ -1477,23 +1120,19 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "false")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    } finally {
      // Reset to default configuration
      applyPwdPolicyMods(conn, dnStr, attr, "false");
    }
  }
  /**
   * Tests the password modify extended operation that requires secure
   * authentication but a connection that doesn't provide it.
   * Tests the password modify extended operation that requires secure authentication
   * but a connection that doesn't provide it.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -1502,28 +1141,13 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-require-secure-authentication";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "true")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    String[] args =
@@ -1536,23 +1160,19 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertEquals(exitCode, 13);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "false")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 13);
    } finally {
      // Reset to default configuration
      applyPwdPolicyMods(conn, dnStr, attr, "false");
    }
  }
  /**
   * Tests the password modify extended operation that requires secure
   * password changes but a connection that doesn't provide it.
   * Tests the password modify extended operation that requires secure password changes
   * but a connection that doesn't provide it, using self-authentication.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -1561,28 +1181,13 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-require-secure-password-changes";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "true")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    String[] args =
@@ -1595,23 +1200,18 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "false")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 13);
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "false");
    }
  }
  /**
   * Tests the password modify extended operation that requires secure
   * password changes but a connection that doesn't provide it.
   * Tests the password modify extended operation that requires secure password changes
   * but a connection that doesn't provide it. Authenticating as Directory Manager.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -1620,28 +1220,13 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-require-secure-password-changes";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "true")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    String[] args =
@@ -1649,29 +1234,25 @@
      "--noPropertiesFile",
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "uid=test.user,o=test",
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-a", "uid=test.user,o=test",
      "-c", "password",
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertEquals(exitCode, 13);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "false")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 13);
    } finally {
      // Reset to default configuration
      applyPwdPolicyMods(conn, dnStr, attr, "false");
    }
  }
  /**
   * Tests the password modify extended operation with a password change that is
   * within the minimum password age.
   * Tests the password modify extended operation with a password change that is within the minimum password age.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -1680,29 +1261,13 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-min-password-age";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "24 hours")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "24 hours");
    String[] args =
    {
@@ -1713,23 +1278,18 @@
      "-w", "password",
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "0 seconds")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "0 seconds");
    }
  }
  /**
   * Tests the password modify extended operation with a password change that is
   * within the minimum password age.
   * Tests the password modify extended operation with a password change that is within the minimum password age.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -1738,29 +1298,13 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-min-password-age";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "24 hours")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "24 hours");
    String[] args =
    {
@@ -1772,24 +1316,19 @@
      "-c", "password",
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertEquals(exitCode, 53);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "0 seconds")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 53);
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "0 seconds");
    }
  }
  /**
   * Tests the password modify extended operation with a password change for a
   * user whose password is expired but expired password changes are not
   * allowed.
   * Tests the password modify extended operation with a password change for a user whose password is expired
   * but expired password changes are not allowed.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -1798,68 +1337,40 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    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");
    String attr2 = "ds-cfg-expire-passwords-without-warning";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr1, "90 days")));
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr2, "true")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr2, "true");
    try {
      setPasswordChangedTime(conn, userEntry);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create("pwdchangedtime",
                                            "20050101000000.000Z")));
    modifyOperation = conn.processModify(userEntry.getName(), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
      String[] args =
      {
        "--noPropertiesFile",
        "-h", "127.0.0.1",
        "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
        "-a", "dn:uid=test.user,o=test",
        "-c", "password",
        "-n", "newPassword"
      };
    String[] args =
    {
      "--noPropertiesFile",
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-a", "dn:uid=test.user,o=test",
      "-c", "password",
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr1, "0 seconds")));
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr2, "false")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr1, "0 seconds");
      applyPwdPolicyMods(conn, dnStr, attr2, "false");
    }
  }
  /**
   * Tests the password modify extended operation with a password change for a
   * user whose password is expired but expired password changes are allowed.
   * Tests the password modify extended operation with a password change for a user whose password is expired
   * but expired password changes are allowed.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -1868,136 +1379,81 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    Entry userEntry = TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "ds-privilege-name: bypass-acl",
         "userPassword: password");
    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");
    String attr2 = "ds-cfg-expire-passwords-without-warning";
    applyPwdPolicyMods(conn, dnStr, attr2, "true");
    String attr3 = "ds-cfg-allow-expired-password-changes";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr1, "90 days")));
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr2, "true")));
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr3, "true")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr3, "true");
    try {
      setPasswordChangedTime(conn, userEntry);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create("pwdchangedtime",
                                            "20050101000000.000Z")));
    modifyOperation = conn.processModify(userEntry.getName(), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
      String[] args =
      {
        "--noPropertiesFile",
        "-h", "127.0.0.1",
        "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
        "-a", "dn:uid=test.user,o=test",
        "-c", "password",
        "-n", "newPassword"
      };
    String[] args =
    {
      "--noPropertiesFile",
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-a", "dn:uid=test.user,o=test",
      "-c", "password",
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertEquals(exitCode, 0);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr1, "0 seconds")));
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr2, "false")));
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr3, "false")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
      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");
    }
  }
  /**
   * Tests the password modify extended operation with a password change for a
   * user where there is no new password provided and there is no password
   * generator.
   * Tests the password modify extended operation with a password change for a user
   * where there is no new password provided and there is no password generator.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
  @Test
  public void testFailureNoPasswordNoGenerator()
         throws Exception
  {
         throws Exception {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr = "ds-cfg-password-generator";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                      Attributes.empty(DirectoryServer.getAttributeType(attr))));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, null);
    String[] args =
    {
      "--noPropertiesFile",
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "uid=test.user,o=test",
      "-w", "password"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    mods.clear();
    String genDN =
         "cn=Random Password Generator,cn=Password Generators,cn=config";
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, genDN)));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
        {
            "--noPropertiesFile",
            "-h", "127.0.0.1",
            "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
            "-D", "uid=test.user,o=test",
            "-w", "password"
        };
    try {
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "cn=Random Password Generator,cn=Password Generators,cn=config");
    }
  }
  /**
   * Tests the password modify extended operation with a password change for a
   * user where there is no new password provided and there is no password
   * generator.
   * Tests the password modify extended operation with a password change for a user where there is no new password
   * provided and there is no password generator.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -2006,29 +1462,13 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr = "ds-cfg-password-generator";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                      Attributes.empty(DirectoryServer.getAttributeType(attr))));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, null);
    String[] args =
    {
@@ -2038,25 +1478,19 @@
      "-a", "dn:uid=test.user,o=test",
      "-c", "password"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    mods.clear();
    String genDN =
         "cn=Random Password Generator,cn=Password Generators,cn=config";
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, genDN)));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    }
    finally {
      applyPwdPolicyMods(conn, dnStr, attr, "cn=Random Password Generator,cn=Password Generators,cn=config");
    }
  }
  /**
   * Tests the password modify extended operation with a password change for a
   * user where a password validator rejects the change.
   * Tests the password modify extended operation with a password change for a user where a password validator
   * rejects the change.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -2065,30 +1499,13 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr = "ds-cfg-password-validator";
    String valDN =
         "cn=Length-Based Password Validator,cn=Password Validators,cn=config";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, valDN)));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "cn=Length-Based Password Validator,cn=Password Validators,cn=config");
    String[] args =
@@ -2100,23 +1517,19 @@
      "-w", "password",
      "-n", "short"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                      Attributes.empty(DirectoryServer.getAttributeType(attr))));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    }
    finally {
      applyPwdPolicyMods(conn, dnStr, attr, null);
    }
  }
  /**
   * Tests the password modify extended operation with a password change for a
   * user where a password validator rejects the change.
   * Tests the password modify extended operation with a password change for a user where a password validator
   * rejects the change.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -2125,31 +1538,13 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User",
         "userPassword: password");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr = "ds-cfg-password-validator";
    String valDN =
         "cn=Length-Based Password Validator,cn=Password Validators,cn=config";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, valDN)));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "cn=Length-Based Password Validator,cn=Password Validators,cn=config");
    String[] args =
    {
@@ -2160,20 +1555,15 @@
      "-c", "password",
      "-n", "short"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertFalse(exitCode == 0);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                      Attributes.empty(DirectoryServer.getAttributeType(attr))));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, null));
    }
    finally {
      applyPwdPolicyMods(conn, dnStr, attr, null);
    }
  }
  /**
   * Tests the password modify extended operation over LDAP when the existing
   * account has multiple passwords.
@@ -2188,16 +1578,10 @@
    TestCaseUtils.initializeTestBackend(true);
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-allow-multiple-password-values";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "true")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    InternalClientConnection conn = getRootConnection();
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    TestCaseUtils.addEntry(
        "dn: uid=test.user,o=test",
@@ -2225,24 +1609,17 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertEquals(exitCode, 0);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "false")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, null), 0);
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "false");
    }
  }
  /**
   * Tests the password modify extended operation over LDAP when the existing
   * account has multiple passwords.
   *
   * Tests the password modify extended operation over LDAP when the existing account has multiple passwords.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -2252,16 +1629,10 @@
  {
    TestCaseUtils.initializeTestBackend(true);
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=SHA1 AuthPassword Policy,cn=Password Policies,cn=config";
    String attr  = "ds-cfg-allow-multiple-password-values";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "true")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    applyPwdPolicyMods(conn, dnStr, attr, "true");
    TestCaseUtils.addEntry(
        "dn: uid=test.user,o=test",
@@ -2276,8 +1647,7 @@
        "cn: Test User",
        "authPassword: password",
        "authPassword: password2",
        "ds-pwp-password-policy-dn: cn=SHA1 AuthPassword Policy," +
        "cn=Password Policies,cn=config");
        "ds-pwp-password-policy-dn: cn=SHA1 AuthPassword Policy,cn=Password Policies,cn=config");
    String[] args =
@@ -2292,23 +1662,18 @@
      "-n", "newPassword"
    };
    int exitCode =
         LDAPPasswordModify.mainPasswordModify(args, false, null, null);
    assertEquals(exitCode, 0);
    mods.clear();
    mods.add(new Modification(ModificationType.REPLACE,
                              Attributes.create(attr, "false")));
    modifyOperation = conn.processModify(DN.valueOf(dnStr), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    try {
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, System.err), 0);
    } finally {
      applyPwdPolicyMods(conn, dnStr, attr, "false");
    }
  }
  /**
   * Tests to ensure that if the user provides the correct old password, then
   * the last login time will be updated if that feature is enabled.
   * Tests to ensure that if the user provides the correct old password, then the last login time will be
   * updated if that feature is enabled.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
@@ -2317,27 +1682,8 @@
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    addDefaultTestEntry();
    TestCaseUtils.applyModifications(false,
      "dn: uid=test.user,o=test",
      "changetype: add",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "uid: test.user",
      "givenName: Test",
      "sn: User",
      "cn: Test User",
      "userPassword: oldpassword",
      // FIXME -- I shouldn't have to add this ACI explicitly, but for some
      //          reason the global ACIs are getting removed and never put back,
      //          and without this ACI the user won't have permission to change
      //          its own password.  If we ever change the access control syntax
      //          then this will likely need to be updated, but I don't want to
      //          have to give the user the bypass-acl privilege.
      "aci: (targetattr=\"*\")(version 3.0; acl \"Self Modify Rights\"; " +
           "allow (read,search,compare,write) userdn=\"ldap:///self\";)");
    TestCaseUtils.applyModifications(true,
      "dn: cn=Default Password Policy,cn=Password Policies,cn=config",
      "changetype: modify",
@@ -2364,13 +1710,11 @@
        "-h", "127.0.0.1",
        "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
        "-a", "dn:uid=test.user,o=test",
        "-c", "oldpassword",
        "-c", "password",
        "-n", "newpassword"
      };
      int exitCode = LDAPPasswordModify.mainPasswordModify(args, false, null,
                                                           System.err);
      assertEquals(exitCode, 0);
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, System.err), 0);
      userEntry = DirectoryServer.getEntry(userDN);
      assertNotNull(userEntry);
@@ -2388,7 +1732,6 @@
  }
  /**
   * Tests to ensure that if the user provides an incorrect old password, then
   * the auth failure times will be updated if that feature is enabled.
@@ -2401,23 +1744,12 @@
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.applyModifications(false,
      "dn: uid=test.user,o=test",
      "changetype: add",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "uid: test.user",
      "givenName: Test",
      "sn: User",
      "cn: Test User",
      "userPassword: oldpassword");
    TestCaseUtils.applyModifications(true,
      "dn: cn=Default Password Policy,cn=Password Policies,cn=config",
      "changetype: modify",
      "replace: ds-cfg-lockout-failure-count",
      "ds-cfg-lockout-failure-count: 3");
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    applyPwdPolicyMods(conn, dnStr,
        "ds-cfg-lockout-failure-count", "3");
    try
    {
@@ -2440,22 +1772,110 @@
        "-n", "newpassword"
      };
      int exitCode = LDAPPasswordModify.mainPasswordModify(args, false, null,
                                                           System.err);
      assertFalse(exitCode == 0);
      assertFalse(0 == LDAPPasswordModify.mainPasswordModify(args, false, null, System.err));
      userEntry = DirectoryServer.getEntry(userDN);
      assertNotNull(userEntry);
      assertTrue(userEntry.hasAttribute(authFailureTimesAttr));
    } finally {
      applyPwdPolicyMods(conn, dnStr,
          "ds-cfg-lockout-failure-count", "0");
    }
  }
  /**
   * Tests to ensure that if the password is changed with a generated password, the pwdHistory is getting
   * updated properly.
   *
   * @throws  Exception  If an unexpected error occurs.
   */
  @Test()
  public void testUpdatePasswordHistory()
      throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    addDefaultTestEntry();
    InternalClientConnection conn = getRootConnection();
    String dnStr = "cn=Default Password Policy,cn=Password Policies,cn=config";
    applyPwdPolicyMods(conn, dnStr ,
        "ds-cfg-password-history-count", "5");
    try
    {
      AttributeType pwdHistoryAttr = DirectoryServer.getAttributeType("pwdhistory", false);
      assertNotNull(pwdHistoryAttr);
      DN userDN = DN.valueOf("uid=test.user,o=test");
      Entry userEntry = DirectoryServer.getEntry(userDN);
      assertNotNull(userEntry);
      assertFalse(userEntry.hasAttribute(pwdHistoryAttr));
      String[] args =
      {
        "--noPropertiesFile",
        "-h", "127.0.0.1",
        "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
        "-a", "dn:uid=test.user,o=test",
        "-c", "password"
      };
      assertEquals(LDAPPasswordModify.mainPasswordModify(args, false, null, System.err), 0);
      userEntry = DirectoryServer.getEntry(userDN);
      assertNotNull(userEntry);
      assertTrue(userEntry.hasAttribute(pwdHistoryAttr));
    }
    finally
    {
      TestCaseUtils.applyModifications(true,
        "dn: cn=Default Password Policy,cn=Password Policies,cn=config",
        "changetype: modify",
        "replace: ds-cfg-lockout-failure-count",
        "ds-cfg-lockout-failure-count: 0");
      applyPwdPolicyMods(conn, dnStr,
          "ds-cfg-password-history-count", "0");
    }
  }
  private Entry addDefaultTestEntry() throws Exception {
    return TestCaseUtils.addEntry(
        "dn: uid=test.user,o=test",
        "objectClass: top",
        "objectClass: person",
        "objectClass: organizationalPerson",
        "objectClass: inetOrgPerson",
        "uid: test.user",
        "givenName: Test",
        "sn: User",
        "cn: Test User",
        "ds-privilege-name: bypass-acl",
        "userPassword: password");
  }
  private void verifyPasswordPerformingInternalBind(DN name, String newPwd) throws DirectoryException {
    // Perform an internal bind to verify the password was actually changed.
    InternalClientConnection conn = new InternalClientConnection(new AuthenticationInfo());
    BindOperation bindOperation =
        conn.processSimpleBind(name, ByteString.valueOf(newPwd));
    assertEquals(bindOperation.getResultCode(), ResultCode.SUCCESS);
  }
  private void applyPwdPolicyMods(InternalClientConnection conn, String pwPolDN, String attr, String value)
      throws DirectoryException
  {
    ArrayList<Modification> mods = new ArrayList<Modification>();
    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);
  }
  private void setPasswordChangedTime(InternalClientConnection conn, Entry userEntry) {
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
        Attributes.create("pwdchangedtime",
            "20050101000000.000Z")));
    ModifyOperation modifyOperation = conn.processModify(userEntry.getName(), mods);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
  }
}