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

Jean-Noel Rouvignac
24.45.2014 4a5675bc1787a8401819fdefba9f438f8b28270e
Code cleanup.

Code review: Ludovic Poitou

JmxClientConnection.java:
Removed all process*() method but processSearch() - totally unused or only used by tests.

JmxPrivilegeTestCase.java
Removed tests that are testing ded code (never used in production).
2 files modified
952 ■■■■■ changed files
opendj3-server-dev/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java 426 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java 526 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
@@ -38,7 +38,6 @@
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConnectionHandler;
@@ -53,7 +52,6 @@
/**
 * This class defines the set of methods and structures that must be implemented
 * by a Directory Server client connection.
 *
 */
public class JmxClientConnection
       extends ClientConnection implements NotificationListener
@@ -61,32 +59,19 @@
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** The message ID counter to use for jmx connections. */
  private AtomicInteger nextMessageID;
  private final AtomicInteger nextMessageID;
  /** The operation ID counter to use for operations on this connection. */
  private AtomicLong nextOperationID;
  private final AtomicLong nextOperationID;
  /** The empty operation list for this connection. */
  private LinkedList<Operation> operationList;
  private final LinkedList<Operation> operationList;
  /** The connection ID for this client connection. */
  private long connectionID;
  /**
   * The JMX connection ID for this client connection.
   */
  protected String jmxConnectionID = null;
  /**
   * The reference to the connection handler that accepted this connection.
   */
  private JmxConnectionHandler jmxConnectionHandler;
  /**
   * Indicate that the disconnect process is started.
   */
  private boolean disconnectStarted = false;
  private final long connectionID;
  /** The JMX connection ID for this client connection. */
  protected String jmxConnectionID;
  /** The reference to the connection handler that accepted this connection. */
  private final JmxConnectionHandler jmxConnectionHandler;
  /** Indicate that the disconnect process is started. */
  private boolean disconnectStarted;
  /**
   * Creates a new Jmx client connection that will be authenticated as
@@ -102,7 +87,7 @@
  {
    super();
    this.setNetworkGroup(NetworkGroup.getAdminNetworkGroup());
    setNetworkGroup(NetworkGroup.getAdminNetworkGroup());
    nextMessageID    = new AtomicInteger(1);
    nextOperationID  = new AtomicLong(0);
@@ -120,40 +105,32 @@
    }
    operationList = new LinkedList<Operation>();
    //
    // Register the Jmx Notification listener (this)
    jmxConnectionHandler.getRMIConnector().jmxRmiConnectorNoClientCertificate
        .addNotificationListener(this, null, null);
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public void handleNotification(Notification notif, Object handback)
  {
    JMXConnectionNotification jcn ;
    // We don't have the expected notification
    if ( ! (notif instanceof JMXConnectionNotification))
    {
      return ;
    }
    else
    {
      jcn = (JMXConnectionNotification) notif ;
    }
    JMXConnectionNotification jcn = (JMXConnectionNotification) notif;
    // The only handled notifications are CLOSED and FAILED
    if ((!jcn.getType().equals(JMXConnectionNotification.CLOSED))
        && (!jcn.getType().equals(JMXConnectionNotification.FAILED)))
    if (!JMXConnectionNotification.CLOSED.equals(jcn.getType())
        && !JMXConnectionNotification.FAILED.equals(jcn.getType()))
    {
      return;
    }
    // Check if the closed connection corresponds to the current connection
    if (!(jcn.getConnectionId().equals(jmxConnectionID)))
    if (!jcn.getConnectionId().equals(jmxConnectionID))
    {
      return;
    }
@@ -404,362 +381,6 @@
  }
  /**
   * Processes an Jmx add operation with the provided information.
   *
   * @param  rawEntryDN     The DN to use for the entry to add.
   * @param  rawAttributes  The set of attributes to include in the entry to
   *                        add.
   *
   * @return  A reference to the add operation that was processed and contains
   *          information about the result of the processing.
   */
  public AddOperation processAdd(ByteString rawEntryDN,
                                 ArrayList<RawAttribute> rawAttributes)
  {
    AddOperationBasis addOperation =
         new AddOperationBasis(this, nextOperationID(), nextMessageID(),
                          new ArrayList<Control>(0), rawEntryDN, rawAttributes);
    // Check if we have enough privilege
    if (! hasPrivilege(Privilege.JMX_WRITE, null))
    {
      LocalizableMessage message = ERR_JMX_ADD_INSUFFICIENT_PRIVILEGES.get();
      addOperation.setErrorMessage(new LocalizableMessageBuilder(message));
      addOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
    }
    else
    {
      addOperation.run();
    }
    return addOperation;
  }
  /**
   * Processes an internal add operation with the provided
   * information.
   *
   * @param  entryDN                The entry DN for the add
   *                                operation.
   * @param  objectClasses          The set of objectclasses for the
   *                                add operation.
   * @param  userAttributes         The set of user attributes for the
   *                                add operation.
   * @param  operationalAttributes  The set of operational attributes
   *                                for the add operation.
   *
   * @return  A reference to the add operation that was processed and
   *          contains information about the result of the processing.
   */
  public AddOperation processAdd(DN entryDN,
                           Map<ObjectClass,String> objectClasses,
                           Map<AttributeType,List<Attribute>>
                                userAttributes,
                           Map<AttributeType,List<Attribute>>
                                operationalAttributes)
  {
    AddOperationBasis addOperation =
         new AddOperationBasis(this, nextOperationID(),
                          nextMessageID(),
                          new ArrayList<Control>(0), entryDN,
                          objectClasses, userAttributes,
                          operationalAttributes);
    // Check if we have enough privilege
    if (! hasPrivilege(Privilege.JMX_WRITE, null))
    {
      LocalizableMessage message = ERR_JMX_ADD_INSUFFICIENT_PRIVILEGES.get();
      addOperation.setErrorMessage(new LocalizableMessageBuilder(message));
      addOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
    }
    else
    {
      addOperation.run();
    }
    return addOperation;
  }
  /**
   * Processes an internal delete operation with the provided
   * information.
   *
   * @param  entryDN  The entry DN for the delete operation.
   *
   * @return  A reference to the delete operation that was processed
   *          and contains information about the result of the
   *          processing.
   */
  public DeleteOperation processDelete(DN entryDN)
  {
    DeleteOperationBasis deleteOperation =
         new DeleteOperationBasis(this, nextOperationID(),
                             nextMessageID(),
                             new ArrayList<Control>(0), entryDN);
    // Check if we have enough privilege
    if (! hasPrivilege(Privilege.JMX_WRITE, null))
    {
      LocalizableMessage message = ERR_JMX_DELETE_INSUFFICIENT_PRIVILEGES.get();
      deleteOperation.setErrorMessage(new LocalizableMessageBuilder(message));
      deleteOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
    }
    else
    {
      deleteOperation.run();
    }
    return deleteOperation;
  }
  /**
   * Processes an Jmx compare operation with the provided information.
   *
   * @param  rawEntryDN      The entry DN for the compare operation.
   * @param  attributeType   The attribute type for the compare operation.
   * @param  assertionValue  The assertion value for the compare operation.
   *
   * @return  A reference to the compare operation that was processed and
   *          contains information about the result of the processing.
   */
  public CompareOperation processCompare(ByteString rawEntryDN,
                                         String attributeType,
                                         ByteString assertionValue)
  {
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(this, nextOperationID(), nextMessageID(),
                              new ArrayList<Control>(0), rawEntryDN,
                              attributeType, assertionValue);
    // Check if we have enough privilege
    if (! hasPrivilege(Privilege.JMX_READ, null))
    {
      LocalizableMessage message = ERR_JMX_SEARCH_INSUFFICIENT_PRIVILEGES.get();
      compareOperation.setErrorMessage(new LocalizableMessageBuilder(message));
      compareOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
    }
    else
    {
      compareOperation.run();
    }
    return compareOperation;
  }
  /**
   * Processes an Jmx delete operation with the provided information.
   *
   * @param  rawEntryDN  The entry DN for the delete operation.
   *
   * @return  A reference to the delete operation that was processed and
   *          contains information about the result of the processing.
   */
  public DeleteOperation processDelete(ByteString rawEntryDN)
  {
    DeleteOperationBasis deleteOperation =
         new DeleteOperationBasis(this, nextOperationID(), nextMessageID(),
                             new ArrayList<Control>(0), rawEntryDN);
    // Check if we have enough privilege
    if (! hasPrivilege(Privilege.JMX_WRITE, null))
    {
      LocalizableMessage message = ERR_JMX_DELETE_INSUFFICIENT_PRIVILEGES.get();
      deleteOperation.setErrorMessage(new LocalizableMessageBuilder(message));
      deleteOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
    }
    else
    {
      deleteOperation.run();
    }
    return deleteOperation;
  }
  /**
   * Processes an Jmx extended operation with the provided information.
   *
   * @param  requestOID    The OID for the extended request.
   * @param  requestValue  The encoded +value for the extended operation, or
   *                       <CODE>null</CODE> if there is no value.
   *
   * @return  A reference to the extended operation that was processed and
   *          contains information about the result of the processing.
   */
  public ExtendedOperation processExtendedOperation(String requestOID,
                                ByteString requestValue)
  {
    ExtendedOperationBasis extendedOperation =
         new ExtendedOperationBasis(this, nextOperationID(), nextMessageID(),
                               new ArrayList<Control>(0), requestOID,
                               requestValue);
    extendedOperation.run();
    return extendedOperation;
  }
  /**
   * Processes an Jmx modify operation with the provided information.
   *
   * @param  rawEntryDN        The raw entry DN for this modify operation.
   * @param  rawModifications  The set of modifications for this modify
   *                           operation.
   *
   * @return  A reference to the modify operation that was processed and
   *          contains information about the result of the processing
   */
  public ModifyOperation processModify(ByteString rawEntryDN,
                              ArrayList<RawModification> rawModifications)
  {
    ModifyOperationBasis modifyOperation =
         new ModifyOperationBasis(this, nextOperationID(), nextMessageID(),
                             new ArrayList<Control>(0), rawEntryDN,
                             rawModifications);
    if (! hasPrivilege(Privilege.JMX_WRITE, null))
    {
      LocalizableMessage message = ERR_JMX_MODIFY_INSUFFICIENT_PRIVILEGES.get();
      modifyOperation.setErrorMessage(new LocalizableMessageBuilder(message));
      modifyOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
    }
    else
    {
      modifyOperation.run();
    }
    return modifyOperation;
  }
  /**
   * Processes an internal modify operation with the provided
   * information.
   *
   * @param  entryDN        The entry DN for this modify operation.
   * @param  modifications  The set of modifications for this modify
   *                        operation.
   *
   * @return  A reference to the modify operation that was processed
   *          and contains information about the result of the
   *          processing.
   */
  public ModifyOperation processModify(DN entryDN,
                              List<Modification> modifications)
  {
    ModifyOperationBasis modifyOperation =
         new ModifyOperationBasis(this, nextOperationID(),
                             nextMessageID(),
                             new ArrayList<Control>(0), entryDN,
                             modifications);
    if (! hasPrivilege(Privilege.JMX_WRITE, null))
    {
      LocalizableMessage message = ERR_JMX_MODIFY_INSUFFICIENT_PRIVILEGES.get();
      modifyOperation.setErrorMessage(new LocalizableMessageBuilder(message));
      modifyOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
    }
    else
    {
      modifyOperation.run();
    }
    return modifyOperation;
  }
  /**
   * Processes an Jmx modify DN operation with the provided information.
   *
   * @param  rawEntryDN    The current DN of the entry to rename.
   * @param  rawNewRDN     The new RDN to use for the entry.
   * @param  deleteOldRDN  The flag indicating whether the old RDN value is to
   *                       be removed from the entry.
   *
   * @return  A reference to the modify DN operation that was processed and
   *          contains information about the result of the processing.
   */
  public ModifyDNOperation processModifyDN(ByteString rawEntryDN,
                                           ByteString rawNewRDN,
                                           boolean deleteOldRDN)
  {
    return processModifyDN(rawEntryDN, rawNewRDN, deleteOldRDN, null);
  }
  /**
   * Processes an Jmx modify DN operation with the provided information.
   *
   * @param  rawEntryDN      The current DN of the entry to rename.
   * @param  rawNewRDN       The new RDN to use for the entry.
   * @param  deleteOldRDN    The flag indicating whether the old RDN value is to
   *                         be removed from the entry.
   * @param  rawNewSuperior  The new superior for the modify DN operation, or
   *                         <CODE>null</CODE> if the entry will remain below
   *                         the same parent.
   *
   * @return  A reference to the modify DN operation that was processed and
   *          contains information about the result of the processing.
   */
  public ModifyDNOperation processModifyDN(ByteString rawEntryDN,
                                           ByteString rawNewRDN,
                                           boolean deleteOldRDN,
                                           ByteString rawNewSuperior)
  {
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(this, nextOperationID(), nextMessageID(),
                               new ArrayList<Control>(0), rawEntryDN, rawNewRDN,
                               deleteOldRDN, rawNewSuperior);
    if (! hasPrivilege(Privilege.JMX_WRITE, null))
    {
      LocalizableMessage message = ERR_JMX_MODDN_INSUFFICIENT_PRIVILEGES.get();
      modifyDNOperation.setErrorMessage(new LocalizableMessageBuilder(message));
      modifyDNOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
    }
    else
    {
      modifyDNOperation.run();
    }
    return modifyDNOperation;
  }
  /**
   * Processes an internal modify DN operation with the provided
   * information.
   *
   * @param  entryDN       The current DN of the entry to rename.
   * @param  newRDN        The new RDN to use for the entry.
   * @param  deleteOldRDN  The flag indicating whether the old RDN
   *                       value is to be removed from the entry.
   * @param  newSuperior   The new superior for the modify DN
   *                       operation, or <CODE>null</CODE> if the
   *                       entry will remain below the same parent.
   *
   * @return  A reference to the modify DN operation that was
   *          processed and contains information about the result of
   *          the processing.
   */
  public ModifyDNOperation processModifyDN(DN entryDN, RDN newRDN,
                                           boolean deleteOldRDN,
                                           DN newSuperior)
  {
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(this, nextOperationID(),
                               nextMessageID(),
                               new ArrayList<Control>(0), entryDN,
                               newRDN, deleteOldRDN, newSuperior);
    if (! hasPrivilege(Privilege.JMX_WRITE, null))
    {
      LocalizableMessage message = ERR_JMX_MODDN_INSUFFICIENT_PRIVILEGES.get();
      modifyDNOperation.setErrorMessage(new LocalizableMessageBuilder(message));
      modifyDNOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
    }
    else
    {
      modifyDNOperation.run();
    }
    return modifyDNOperation;
  }
  /**
   * Processes an Jmx search operation with the provided information.
   *
@@ -889,10 +510,7 @@
    try
    {
      UnbindOperationBasis unbindOp = new UnbindOperationBasis(
          this,
          this.nextOperationID(),
          this.nextMessageID(), null);
          this, nextOperationID(), nextMessageID(), null);
      unbindOp.run();
    }
   catch (Exception e)
@@ -1023,11 +641,7 @@
    // cancelled.
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public String getMonitorSummary()
  {
@@ -1090,9 +704,7 @@
    return 0;
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public int getSSF() {
      return 0;
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
@@ -31,7 +31,6 @@
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.ldap.ByteString;
@@ -44,14 +43,11 @@
import org.opends.server.backends.task.TaskState;
import org.opends.server.controls.ProxiedAuthV1Control;
import org.opends.server.controls.ProxiedAuthV2Control;
import org.opends.server.core.AddOperation;
import org.opends.server.core.AddOperationBasis;
import org.opends.server.core.CompareOperation;
import org.opends.server.core.CompareOperationBasis;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyOperationBasis;
@@ -493,240 +489,6 @@
  }
  /**
   * Tests to ensure that compare operations in the server configuration
   * properly respect the JMX_READ privilege.
   *
   * @param  conn          The client connection to use to perform the compare
   *                       operation.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the JMX_READ privilege and therefore the
   *                       compare should succeed.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testConfigReadCompare(JmxClientConnection conn,
                                    boolean hasPrivilege)
         throws Exception
  {
    assertEquals(conn.hasPrivilege(Privilege.JMX_READ, null), hasPrivilege);
    ByteString asn1 = ByteString.valueOf("cn=config");
    ByteString value = ByteString.valueOf("config");
    CompareOperation compareOperation =
         conn.processCompare(asn1,
                             "cn",
                             value);
    if (hasPrivilege)
    {
      assertEquals(compareOperation.getResultCode(), ResultCode.COMPARE_TRUE);
    }
    else
    {
      assertEquals(compareOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    }
  }
  /**
   * Tests to ensure that add and delete operations in the server configuration
   * properly respect the CONFIG_WRITE privilege.
   *
   * @param  conn          The client connection to use to perform the
   *                       operations.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the CONFIG_WRITE privilege and therefore the
   *                       operations should succeed.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testConfigWriteAddAndDelete(JmxClientConnection conn,
                                          boolean hasPrivilege)
         throws Exception
  {
    assertEquals(conn.hasPrivilege(Privilege.JMX_WRITE, null), hasPrivilege);
    Entry entry = TestCaseUtils.makeEntry(
      "dn: cn=Test Root,cn=Root DNs,cn=config",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "objectClass: ds-cfg-root-dn-user",
      "cn: Test Root",
      "givenName: Test",
      "sn: Root",
      "userPassword: password");
    AddOperation addOperation =
         conn.processAdd(entry.getName(), entry.getObjectClasses(),
                         entry.getUserAttributes(),
                         entry.getOperationalAttributes());
    if (hasPrivilege)
    {
      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
      DeleteOperation deleteOperation = conn.processDelete(entry.getName());
      assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
    }
    else
    {
      assertEquals(addOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
      DeleteOperation deleteOperation =
           conn.processDelete(
                DN.valueOf("cn=Telex Number,cn=Syntaxes,cn=config"));
      assertEquals(deleteOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    }
  }
  /**
   * Tests to ensure that modify operations in the server configuration
   * properly respect the CONFIG_WRITE privilege.
   *
   * @param  conn          The client connection to use to perform the modify
   *                       operation.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the CONFIG_WRITE privilege and therefore the
   *                       modify should succeed.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testConfigWriteModify(JmxClientConnection conn,
                                    boolean hasPrivilege)
         throws Exception
  {
    assertEquals(conn.hasPrivilege(Privilege.JMX_WRITE, null), hasPrivilege);
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.REPLACE,
        Attributes.create("ds-cfg-size-limit", "2000")));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf("cn=config"), mods);
    if (hasPrivilege)
    {
      assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
      mods.clear();
      mods.add(new Modification(ModificationType.REPLACE,
          Attributes.create("ds-cfg-size-limit", "1000")));
      modifyOperation = conn.processModify(DN.valueOf("cn=config"), mods);
      assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    }
    else
    {
      assertEquals(modifyOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    }
  }
  /**
   * Tests to ensure that modify DN operations in the server configuration
   * properly respect the CONFIG_WRITE privilege.
   *
   * @param  conn          The client connection to use to perform the modify DN
   *                       operation.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the CONFIG_WRITE privilege and therefore the
   *                       modify DN should succeed (or at least get past the
   *                       privilege check, only to fail because we don't
   *                       support modify DN in the server configuration).
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testConfigWriteModifyDN(JmxClientConnection conn,
                                      boolean hasPrivilege)
         throws Exception
  {
    assertEquals(conn.hasPrivilege(Privilege.JMX_WRITE, null), hasPrivilege);
    ModifyDNOperation modifyDNOperation =
         conn.processModifyDN(DN.valueOf("cn=Work Queue,cn=config"),
                              RDN.decode("cn=New RDN for Work Queue"), true,
                              null);
    if (hasPrivilege)
    {
      // We don't support modify DN operations in the server configuration, but
      // at least we need to make sure we're getting past the privilege check.
      assertEquals(modifyDNOperation.getResultCode(),
                   ResultCode.UNWILLING_TO_PERFORM);
    }
    else
    {
      assertEquals(modifyDNOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    }
  }
  /**
   * Tests to ensure that attempts to update the schema with a modify operation
   * will properly respect the UPDATE_SCHEMA privilege.
   *
   * @param  conn          The client connection to use to perform the schema
   *                       update.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the UPDATE_SCHEMA privilege and therefore
   *                       the schema update should succeed.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testUpdateSchemaModify(JmxClientConnection conn,
                               boolean hasPrivilege)
         throws Exception
  {
    assertEquals(conn.hasPrivilege(Privilege.JMX_WRITE, null),
                 hasPrivilege);
    String attrDefinition =
         "( testupdateschemaat-oid NAME 'testUpdateSchemaAT' " +
         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
         "X-ORIGIN 'PrivilegeTestCase' )";
    ArrayList<Modification> mods = new ArrayList<Modification>();
    mods.add(new Modification(ModificationType.ADD,
        Attributes.create("attributetypes", attrDefinition)));
    ModifyOperation modifyOperation =
         conn.processModify(DN.valueOf("cn=schema"), mods);
    if (hasPrivilege)
    {
      assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
      mods.clear();
      mods.add(new Modification(ModificationType.DELETE,
          Attributes.create("attributetypes", attrDefinition)));
      modifyOperation = conn.processModify(DN.valueOf("cn=schema"), mods);
      assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    }
    else
    {
      assertEquals(modifyOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    }
  }
  /**
   * Tests to ensure that attempts to update the schema with an add schema file
   * task will properly respect the UPDATE_SCHEMA privilege.
@@ -783,295 +545,7 @@
    }
    writer.close();
    Entry taskEntry = TestCaseUtils.makeEntry(
      "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
      "objectClass: top",
      "objectClass: ds-task",
      "objectClass: ds-task-add-schema-file",
      "ds-task-class-name: org.opends.server.tasks.AddSchemaFileTask",
      "ds-task-schema-file-name: 05-" + identifier + ".ldif");
    AddOperation addOperation =
         conn.processAdd(taskEntry.getName(), taskEntry.getObjectClasses(),
                         taskEntry.getUserAttributes(),
                         taskEntry.getOperationalAttributes());
    if (hasPrivilege)
    {
      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
      Task task = getCompletedTask(taskEntry.getName());
      assertNotNull(task);
      assertTrue(TaskState.isSuccessful(task.getTaskState()));
    }
    else
    {
      assertEquals(addOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    }
  }
  /**
   * Tests to ensure that attempts to backup the Directory Server backends
   * will properly respect the BACKEND_BACKUP privilege.
   *
   * @param  conn          The client connection to use to perform the backup.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the BACKEND_BACKUP privilege and therefore
   *                       the backup should succeed.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata", groups = { "slow" })
  public void testBackupBackend(JmxClientConnection conn,
                                boolean hasPrivilege)
         throws Exception
  {
    // We have to sleep here because the backup ID that gets generated will be
    // based on a timestamp and we don't want two in the same second.
    Thread.sleep(1100);
    assertEquals(conn.hasPrivilege(Privilege.JMX_READ, null),
                 hasPrivilege);
    Entry taskEntry = TestCaseUtils.makeEntry(
      "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
      "objectclass: top",
      "objectclass: ds-task",
      "objectclass: ds-task-backup",
      "ds-task-class-name: org.opends.server.tasks.BackupTask",
      "ds-backup-directory-path: bak",
      "ds-task-backup-all: TRUE");
    AddOperation addOperation =
         conn.processAdd(taskEntry.getName(), taskEntry.getObjectClasses(),
                         taskEntry.getUserAttributes(),
                         taskEntry.getOperationalAttributes());
    if (hasPrivilege)
    {
      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
      Task task = getCompletedTask(taskEntry.getName());
      assertNotNull(task);
      assertTrue(TaskState.isSuccessful(task.getTaskState()));
    }
    else
    {
      assertEquals(addOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    }
  }
  /**
   * Tests to ensure that attempts to restore the Directory Server backends
   * will properly respect the BACKEND_RESTORE privilege.
   *
   * @param  conn          The client connection to use to perform the restore.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the BACKEND_RESTORE privilege and therefore
   *                       the restore should succeed.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(enabled = false, dataProvider = "testdata", groups = { "slow" },
        dependsOnMethods = { "testBackupBackend" })
  public void testRestoreBackend(JmxClientConnection conn,
                                 boolean hasPrivilege)
         throws Exception
  {
    assertEquals(conn.hasPrivilege(Privilege.JMX_WRITE, null),
                 hasPrivilege);
    Entry taskEntry = TestCaseUtils.makeEntry(
      "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
      "objectclass: top",
      "objectclass: ds-task",
      "objectclass: ds-task-restore",
      "ds-task-class-name: org.opends.server.tasks.RestoreTask",
      "ds-backup-directory-path: bak" + File.separator + "userRoot");
    AddOperation addOperation =
         conn.processAdd(taskEntry.getName(), taskEntry.getObjectClasses(),
                         taskEntry.getUserAttributes(),
                         taskEntry.getOperationalAttributes());
    if (hasPrivilege)
    {
      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
      Task task = getCompletedTask(taskEntry.getName());
      assertNotNull(task);
      assertTrue(TaskState.isSuccessful(task.getTaskState()));
    }
    else
    {
      assertEquals(addOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    }
  }
  /**
   * Tests to ensure that attempts to export the contents of a Directory Server
   * backend will properly respect the LDIF_EXPORT privilege.
   *
   * @param  conn          The client connection to use to perform the export.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the LDIF_EXPORT privilege and therefore
   *                       the export should succeed.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata", groups = { "slow" })
  public void testLDIFExport(JmxClientConnection conn,
                             boolean hasPrivilege)
         throws Exception
  {
    assertEquals(conn.hasPrivilege(Privilege.JMX_READ, null), hasPrivilege);
    File   tempFile     = File.createTempFile("export-", ".ldif");
    String tempFilePath = tempFile.getAbsolutePath();
    tempFile.delete();
    Entry taskEntry = TestCaseUtils.makeEntry(
      "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
      "objectclass: top",
      "objectclass: ds-task",
      "objectclass: ds-task-export",
      "ds-task-class-name: org.opends.server.tasks.ExportTask",
      "ds-task-export-backend-id: userRoot",
      "ds-task-export-ldif-file: " + tempFilePath);
    AddOperation addOperation =
         conn.processAdd(taskEntry.getName(), taskEntry.getObjectClasses(),
                         taskEntry.getUserAttributes(),
                         taskEntry.getOperationalAttributes());
    if (hasPrivilege)
    {
      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
      Task task = getCompletedTask(taskEntry.getName());
      assertNotNull(task);
      assertTrue(TaskState.isSuccessful(task.getTaskState()));
      tempFile.delete();
    }
    else
    {
      assertEquals(addOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    }
  }
  /**
   * Tests to ensure that attempts to import into a Directory Server backend
   * will properly respect the LDIF_IMPORT privilege.
   *
   * @param  conn          The client connection to use to perform the import.
   * @param  hasPrivilege  Indicates whether the authenticated user is expected
   *                       to have the LDIF_IMPORT privilege and therefore
   *                       the import should succeed.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata", groups = { "slow" })
  public void testLDIFImport(JmxClientConnection conn,
                             boolean hasPrivilege)
         throws Exception
  {
    assertEquals(conn.hasPrivilege(Privilege.JMX_WRITE, null), hasPrivilege);
    String path = TestCaseUtils.createTempFile(
      "dn: dc=example,dc=com",
      "objectClass: top",
      "objectClass: domain",
      "dc: example");
    Entry taskEntry = TestCaseUtils.makeEntry(
      "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
      "objectclass: top",
      "objectclass: ds-task",
      "objectclass: ds-task-import",
      "ds-task-class-name: org.opends.server.tasks.ImportTask",
      "ds-task-import-backend-id: userRoot",
      "ds-task-import-ldif-file: " + path);
    AddOperation addOperation =
         conn.processAdd(taskEntry.getName(), taskEntry.getObjectClasses(),
                         taskEntry.getUserAttributes(),
                         taskEntry.getOperationalAttributes());
    if (hasPrivilege)
    {
      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
      Task task = getCompletedTask(taskEntry.getName());
      assertNotNull(task);
      assertTrue(TaskState.isSuccessful(task.getTaskState()));
    }
    else
    {
      assertEquals(addOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    }
  }
  /**
   * Test to ensure that attempts to rebuild indexes will property respect
   * the LDIF_IMPORT privilege.
   *
   * @param conn The client connection to use to perform the rebuild.
   * @param hasPrivilege Indicates weather the authenticated user is
   *                     expected to have the INDEX_REBUILD privilege
   *                     and therefore the rebuild should succeed.
   * @throws Exception if an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata", groups = { "slow" })
  public void testRebuildIndex(JmxClientConnection conn,
                               boolean hasPrivilege)
      throws Exception
  {
    assertEquals(conn.hasPrivilege(Privilege.JMX_WRITE, null), hasPrivilege);
    Entry taskEntry = TestCaseUtils.makeEntry(
      "dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
      "objectclass: top",
      "objectclass: ds-task",
      "objectclass: ds-task-rebuild",
      "ds-task-class-name: org.opends.server.tasks.RebuildTask",
      "ds-task-rebuild-base-dn: dc=example,dc=com",
      "ds-task-rebuild-index: cn");
    AddOperation addOperation =
         conn.processAdd(taskEntry.getName(), taskEntry.getObjectClasses(),
                         taskEntry.getUserAttributes(),
                         taskEntry.getOperationalAttributes());
    if (hasPrivilege)
    {
      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
      Task task = getCompletedTask(taskEntry.getName());
      assertNotNull(task);
      assertTrue(TaskState.isSuccessful(task.getTaskState()));
    }
    else
    {
      assertEquals(addOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    }
  }
  /**
   * Tests to ensure that the use of the Directory Server will properly respect