From c1405673acad68e2233b152fec84409b0af36994 Mon Sep 17 00:00:00 2001
From: lutoff <lutoff@localhost>
Date: Thu, 12 Jul 2007 08:18:55 +0000
Subject: [PATCH] fix for issue #1217 Privilege checks are done in the JmxClientConnection code. Due to JMX design choice (See chapter 13.4.3,page 210 of the JMX Specification, version 1.4 Final Release - http://jcp.org/en/jsr/detail?id=160) JMX_NOTIFY privilege cannot be checked when a remote client adds a Listener. For this reason, we have chosen to allow JMX connection only if the user has the JMX_READ privilege (at least). The JMX_READ privilege is now also check during connection establishment.

---
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxConnectTest.java              |  127 ++
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java        | 1692 ++++++++++++++++++++++++++++++++++++++++++++
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java                   |   32 
 opends/src/server/org/opends/server/messages/ProtocolMessages.java                                         |   69 +
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/postConnectedDisconnectTest.java |   66 +
 opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java                                 |  228 +++++
 opends/src/server/org/opends/server/protocols/jmx/RmiAuthenticator.java                                    |   20 
 7 files changed, 2,207 insertions(+), 27 deletions(-)

diff --git a/opends/src/server/org/opends/server/messages/ProtocolMessages.java b/opends/src/server/org/opends/server/messages/ProtocolMessages.java
index 3d93db9..632fdc2 100644
--- a/opends/src/server/org/opends/server/messages/ProtocolMessages.java
+++ b/opends/src/server/org/opends/server/messages/ProtocolMessages.java
@@ -4678,6 +4678,56 @@
   public static final int MSGID_JMX_CONNHANDLER_CANNOT_BIND =
        CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_SEVERE_ERROR | 433;
 
+  /**
+   * The message ID for the message that will be used if an attempt is made to
+   * perform an add operation through JMX but the user doesn't
+   * have the necessary privileges to do so.  This does not take any arguments.
+   */
+  public static final int MSGID_JMX_ADD_INSUFFICIENT_PRIVILEGES =
+    CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_MILD_ERROR | 434;
+
+  /**
+   * The message ID for the message that will be used if an attempt is made to
+   * perform a delete operation through JMX but the user doesn't
+   * have the necessary privileges to do so.  This does not take any arguments.
+   */
+  public static final int MSGID_JMX_DELETE_INSUFFICIENT_PRIVILEGES =
+    CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_MILD_ERROR | 435;
+
+  /**
+   * The message ID for the message that will be used if an attempt is made to
+   * perform a modify operation through JMX but the user doesn't
+   * have the necessary privileges to do so.  This does not take any arguments.
+   */
+  public static final int MSGID_JMX_MODIFY_INSUFFICIENT_PRIVILEGES =
+    CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_MILD_ERROR | 436;
+
+
+  /**
+   * The message ID for the message that will be used if an attempt is made to
+   * perform a modify DN operation through JMX but the user
+   * doesn't have the necessary privileges to do so.  This does not take any
+   * arguments.
+   */
+  public static final int MSGID_JMX_MODDN_INSUFFICIENT_PRIVILEGES =
+    CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_MILD_ERROR | 437;
+
+
+  /**
+   * The message ID for the message that will be used if an attempt is made to
+   * perform a search operation in the server configuration but the user doesn't
+   * have the necessary privileges to do so.  This does not take any arguments.
+   */
+  public static final int MSGID_JMX_SEARCH_INSUFFICIENT_PRIVILEGES =
+    CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_MILD_ERROR | 438;
+
+  /**
+   * The message ID for the message that will be used if an attempt is made to
+   * perform a search operation in the server configuration but the user doesn't
+   * have the necessary privileges to do so.  This does not take any arguments.
+   */
+  public static final int MSGID_JMX_INSUFFICIENT_PRIVILEGES =
+    CATEGORY_MASK_PROTOCOL | SEVERITY_MASK_MILD_ERROR | 439;
 
 
   /**
@@ -6505,7 +6555,24 @@
             ATTR_KEYMANAGER_DN + " attribute in configuration " +
             "entry %s, which is used to specify the DN of the key manager " +
             "provider to use for accepting SSL/TSL connections:  %s");
-
+    registerMessage(MSGID_JMX_ADD_INSUFFICIENT_PRIVILEGES,
+            "You do not have sufficient privileges to perform add " +
+            "operations through JMX");
+    registerMessage(MSGID_JMX_DELETE_INSUFFICIENT_PRIVILEGES,
+            "You do not have sufficient privileges to perform delete " +
+            "operations through JMX");
+    registerMessage(MSGID_JMX_MODIFY_INSUFFICIENT_PRIVILEGES,
+            "You do not have sufficient privileges to perform modify " +
+             "operations through JMX");
+    registerMessage(MSGID_JMX_MODDN_INSUFFICIENT_PRIVILEGES,
+            "You do not have sufficient privileges to perform modify " +
+            "DN operations through JMX");
+    registerMessage(MSGID_JMX_SEARCH_INSUFFICIENT_PRIVILEGES,
+            "You do not have sufficient privileges to perform search " +
+            "operations through JMX");
+    registerMessage(MSGID_JMX_INSUFFICIENT_PRIVILEGES,
+            "You do not have sufficient privileges to establish the " +
+            "connection through JMX. At least JMX_READ privilege is required");
 
     registerMessage(MSGID_PWPOLICYREQ_CONTROL_HAS_VALUE,
                     "Cannot decode the provided control as a password policy " +
diff --git a/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java b/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
index 67c2fd6..d872b3b 100644
--- a/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
+++ b/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
@@ -44,6 +44,8 @@
 import org.opends.server.protocols.internal.InternalSearchListener;
 
 import org.opends.server.types.AbstractOperation;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
 import org.opends.server.types.DebugLogLevel;
 import org.opends.server.types.AuthenticationInfo;
 import org.opends.server.types.CancelRequest;
@@ -54,9 +56,14 @@
 import org.opends.server.types.DirectoryException;
 import org.opends.server.types.DisconnectReason;
 import org.opends.server.types.IntermediateResponse;
+import org.opends.server.types.Modification;
+import org.opends.server.types.ObjectClass;
 import org.opends.server.types.Operation;
+import org.opends.server.types.Privilege;
+import org.opends.server.types.RDN;
 import org.opends.server.types.RawAttribute;
 import org.opends.server.types.RawModification;
+import org.opends.server.types.ResultCode;
 import org.opends.server.types.SearchResultEntry;
 import org.opends.server.types.SearchResultReference;
 import org.opends.server.types.SearchScope;
@@ -64,6 +71,7 @@
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
 import static org.opends.server.messages.ProtocolMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
 
 
 /**
@@ -476,10 +484,95 @@
          new AddOperationBasis(this, nextOperationID(), nextMessageID(),
                           new ArrayList<Control>(0), rawEntryDN, rawAttributes);
 
-    addOperation.run();
+    // Check if we have enough privilege
+    if (! hasPrivilege(Privilege.JMX_WRITE, null))
+    {
+      int msgID = MSGID_JMX_ADD_INSUFFICIENT_PRIVILEGES;
+      String message = getMessage(msgID);
+      addOperation.setErrorMessage(new StringBuilder(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))
+    {
+      int msgID = MSGID_JMX_ADD_INSUFFICIENT_PRIVILEGES;
+      String message = getMessage(msgID);
+      addOperation.setErrorMessage(new StringBuilder(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))
+    {
+      int msgID = MSGID_JMX_DELETE_INSUFFICIENT_PRIVILEGES;
+      String message = getMessage(msgID);
+      deleteOperation.setErrorMessage(new StringBuilder(message));
+      deleteOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
+    }
+    else
+    {
+      deleteOperation.run();
+    }
+    return deleteOperation;
+  }
 
 
   /**
@@ -501,7 +594,18 @@
                               new ArrayList<Control>(0), rawEntryDN,
                               attributeType, assertionValue);
 
-    compareOperation.run();
+    // Check if we have enough privilege
+    if (! hasPrivilege(Privilege.JMX_READ, null))
+    {
+      int msgID = MSGID_JMX_SEARCH_INSUFFICIENT_PRIVILEGES;
+      String message = getMessage(msgID);
+      compareOperation.setErrorMessage(new StringBuilder(message));
+      compareOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
+    }
+    else
+    {
+      compareOperation.run();
+    }
     return compareOperation;
   }
 
@@ -521,7 +625,18 @@
          new DeleteOperationBasis(this, nextOperationID(), nextMessageID(),
                              new ArrayList<Control>(0), rawEntryDN);
 
-    deleteOperation.run();
+    // Check if we have enough privilege
+    if (! hasPrivilege(Privilege.JMX_WRITE, null))
+    {
+      int msgID = MSGID_JMX_DELETE_INSUFFICIENT_PRIVILEGES;
+      String message = getMessage(msgID);
+      deleteOperation.setErrorMessage(new StringBuilder(message));
+      deleteOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
+    }
+    else
+    {
+      deleteOperation.run();
+    }
     return deleteOperation;
   }
 
@@ -569,11 +684,54 @@
                              new ArrayList<Control>(0), rawEntryDN,
                              rawModifications);
 
-    modifyOperation.run();
+    if (! hasPrivilege(Privilege.JMX_WRITE, null))
+    {
+      int msgID = MSGID_JMX_MODIFY_INSUFFICIENT_PRIVILEGES;
+      String message = getMessage(msgID);
+      modifyOperation.setErrorMessage(new StringBuilder(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))
+    {
+      int msgID = MSGID_JMX_MODIFY_INSUFFICIENT_PRIVILEGES;
+      String message = getMessage(msgID);
+      modifyOperation.setErrorMessage(new StringBuilder(message));
+      modifyOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
+    }
+    else
+    {
+      modifyOperation.run();
+    }
+    return modifyOperation;
+  }
 
   /**
    * Processes an Jmx modify DN operation with the provided information.
@@ -619,11 +777,59 @@
                                new ArrayList<Control>(0), rawEntryDN, rawNewRDN,
                                deleteOldRDN, rawNewSuperior);
 
-    modifyDNOperation.run();
+    if (! hasPrivilege(Privilege.JMX_WRITE, null))
+    {
+      int msgID = MSGID_JMX_MODDN_INSUFFICIENT_PRIVILEGES;
+      String message = getMessage(msgID);
+      modifyDNOperation.setErrorMessage(new StringBuilder(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)
+  {
+    ModifyDNOperation modifyDNOperation =
+         new ModifyDNOperation(this, nextOperationID(),
+                               nextMessageID(),
+                               new ArrayList<Control>(0), entryDN,
+                               newRDN, deleteOldRDN, newSuperior);
 
+    if (! hasPrivilege(Privilege.JMX_WRITE, null))
+    {
+      int msgID = MSGID_JMX_MODDN_INSUFFICIENT_PRIVILEGES;
+      String message = getMessage(msgID);
+      modifyDNOperation.setErrorMessage(new StringBuilder(message));
+      modifyDNOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
+    }
+    else
+    {
+      modifyDNOperation.run();
+    }
+    return modifyDNOperation;
+  }
 
   /**
    * Processes an Jmx search operation with the provided information.
@@ -677,7 +883,17 @@
                                      scope, derefPolicy, sizeLimit, timeLimit,
                                      typesOnly, filter, attributes, null);
 
-    searchOperation.run();
+    if (! hasPrivilege(Privilege.JMX_READ, null))
+    {
+      int msgID = MSGID_JMX_SEARCH_INSUFFICIENT_PRIVILEGES;
+      String message = getMessage(msgID);
+      searchOperation.setErrorMessage(new StringBuilder(message));
+      searchOperation.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS) ;
+    }
+    else
+    {
+      searchOperation.run();
+    }
     return searchOperation;
   }
 
diff --git a/opends/src/server/org/opends/server/protocols/jmx/RmiAuthenticator.java b/opends/src/server/org/opends/server/protocols/jmx/RmiAuthenticator.java
index 47bb286..1fcd21f 100644
--- a/opends/src/server/org/opends/server/protocols/jmx/RmiAuthenticator.java
+++ b/opends/src/server/org/opends/server/protocols/jmx/RmiAuthenticator.java
@@ -39,12 +39,17 @@
 import org.opends.server.protocols.asn1.ASN1OctetString;
 import org.opends.server.protocols.ldap.LDAPResultCode;
 import org.opends.server.types.Control;
+import org.opends.server.types.DisconnectReason;
+import org.opends.server.types.Privilege;
 import org.opends.server.types.ResultCode;
 import org.opends.server.types.DN;
 import org.opends.server.types.AuthenticationInfo;
 import org.opends.server.types.LDAPException;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.messages.ProtocolMessages.*;
+
 import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.types.DebugLogLevel;
 
@@ -183,7 +188,7 @@
       {
         TRACER.debugCaught(DebugLogLevel.ERROR, e);
       }
-      SecurityException se = new SecurityException();
+      SecurityException se = new SecurityException(e.getMessage());
       se.initCause(e);
       throw se;
     }
@@ -277,6 +282,19 @@
 
       authInfo = bindOp.getAuthenticationInfo();
       jmxClientConnection.setAuthenticationInfo(authInfo);
+
+      // Check JMX_READ privilege.
+      if (! jmxClientConnection.hasPrivilege(Privilege.JMX_READ, null))
+      {
+        int msgID = MSGID_JMX_INSUFFICIENT_PRIVILEGES;
+        String message = getMessage(msgID);
+
+        jmxClientConnection.disconnect(DisconnectReason.CONNECTION_REJECTED,
+            false, msgID);
+
+        SecurityException se = new SecurityException(message);
+        throw se;
+      }
       return jmxClientConnection;
     }
     else
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxConnectTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxConnectTest.java
index a2c57a4..a9f5229 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxConnectTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxConnectTest.java
@@ -52,6 +52,7 @@
 import org.opends.server.admin.std.server.JMXConnectionHandlerCfg;
 import org.opends.server.config.JMXMBean;
 import org.opends.server.core.AddOperationBasis;
+import org.opends.server.core.DeleteOperation;
 import org.opends.server.core.DeleteOperationBasis;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.protocols.internal.InternalClientConnection;
@@ -59,6 +60,8 @@
 import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
 import org.opends.server.types.ResultCode;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -71,6 +74,94 @@
  * JMX get and set - configuration change
  */
 public class JmxConnectTest extends JmxTestCase {
+  
+  /**
+   * Set up the environment for performing the tests in this suite.
+   * 
+   * @throws Exception
+   *           If the environment could not be set up.
+   */
+  @BeforeClass
+  public void setUp() throws Exception
+  {
+    super.setUp();
+    
+    TestCaseUtils.addEntries(
+        "dn: cn=Privileged User,o=test",
+        "objectClass: top",
+        "objectClass: person",
+        "objectClass: organizationalPerson",
+        "objectClass: inetOrgPerson",
+        "cn: Privileged User",
+        "givenName: Privileged",
+        "sn: User",
+        "uid: privileged.user",
+        "userPassword: password",
+        "ds-privilege-name: config-read",
+        "ds-privilege-name: config-write",
+        "ds-privilege-name: password-reset",
+        "ds-privilege-name: update-schema",
+        "ds-privilege-name: ldif-import",
+        "ds-privilege-name: ldif-export",
+        "ds-privilege-name: backend-backup",
+        "ds-privilege-name: backend-restore",
+        "ds-privilege-name: proxied-auth",
+        "ds-privilege-name: bypass-acl",
+        "ds-privilege-name: unindexed-search",
+        "ds-privilege-name: jmx-read",
+        "ds-privilege-name: jmx-write",
+        "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
+             "cn=Password Policies,cn=config",
+        "",
+        "dn: cn=Unprivileged JMX User,o=test",
+        "objectClass: top",
+        "objectClass: person",
+        "objectClass: organizationalPerson",
+        "objectClass: inetOrgPerson",
+        "cn: Privileged User",
+        "givenName: Privileged",
+        "sn: User",
+        "uid: privileged.user",
+        "userPassword: password",
+        "ds-privilege-name: config-read",
+        "ds-privilege-name: config-write",
+        "ds-privilege-name: password-reset",
+        "ds-privilege-name: update-schema",
+        "ds-privilege-name: ldif-import",
+        "ds-privilege-name: ldif-export",
+        "ds-privilege-name: backend-backup",
+        "ds-privilege-name: backend-restore",
+        "ds-privilege-name: proxied-auth",
+        "ds-privilege-name: bypass-acl",
+        "ds-privilege-name: unindexed-search",
+        "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
+             "cn=Password Policies,cn=config");
+  }
+  
+  
+  /**
+   * Clean up the environment after performing the tests in this suite.
+   * 
+   * @throws Exception
+   *           If the environment could not be set up.
+   */
+  @AfterClass
+  public void afterClass() throws Exception
+  {
+    InternalClientConnection conn = InternalClientConnection
+        .getRootConnection();
+
+    DeleteOperation deleteOperation = conn.processDelete(DN
+        .decode("cn=Privileged User,o=test"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+    
+    deleteOperation = conn.processDelete(DN
+        .decode("cn=Unprivileged JMX User,o=test"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+    
+  }
+  
+  
 
   /**
    * Build data for the simpleConnect test.
@@ -80,11 +171,12 @@
   @DataProvider(name = "simpleConnect")
   Object[][] createCredentials() {
     return new Object[][] {
-        { "cn=directory manager", "password", true },
-        { "cn=directory manager", "wrongPassword", false },
+        { "cn=directory manager", "password", false }, // no JMX_READ privilege
+        { "cn=Privileged User,o=test", "password", true },
+        { "cn=Privileged User,o=test", "wrongPassword", false },
         { "cn=wrong user", "password", false },
         { "invalid DN", "password", false },
-        { "cn=directory manager", null, false },
+        { "cn=Privileged User,o=test", null, false },
         { null, "password", false }, { null, null, false }, };
   }
 
@@ -105,9 +197,7 @@
       connector.close();
     }
   }
-
-
-
+  
   /**
    * Build some data for the simpleGet test.
    */
@@ -139,7 +229,7 @@
   public void simpleGet(String dn, String attributeName, Object value)
       throws Exception {
 
-    OpendsJmxConnector connector = connect("cn=directory manager",
+    OpendsJmxConnector connector = connect("cn=Privileged User,o=test",
         "password", TestCaseUtils.getServerJmxPort());
     MBeanServerConnection jmxc = connector.getMBeanServerConnection();
     assertNotNull(jmxc);
@@ -163,7 +253,7 @@
   //        the admin framework, and the cn=config entry is now governed by it.
   @Test(enabled = false)
   public void simpleSet() throws Exception {
-    OpendsJmxConnector connector = connect("cn=directory manager",
+    OpendsJmxConnector connector = connect("cn=Privileged User,o=test",
         "password", TestCaseUtils.getServerJmxPort());
     MBeanServerConnection jmxc = connector.getMBeanServerConnection();
     assertNotNull(jmxc);
@@ -231,12 +321,12 @@
     addOp.run();
     Thread.sleep(200);
     OpendsJmxConnector newJmxConnector = connect(
-        "cn=directory manager", "password", serverJmxPort);
+        "cn=Privileged User,o=test", "password", serverJmxPort);
     assertNotNull(newJmxConnector);
     newJmxConnector.close();
 
     // Get the "old" connector
-    OpendsJmxConnector connector = connect("cn=directory manager",
+    OpendsJmxConnector connector = connect("cn=Privileged User,o=test",
         "password", TestCaseUtils.getServerJmxPort());
     MBeanServerConnection jmxc = connector.getMBeanServerConnection();
     assertNotNull(jmxc);
@@ -245,14 +335,14 @@
     toggleEnableJmxConnector(connector, newJmxConnectionJmx.getDN(),
         false);
     Thread.sleep(100);
-    OpendsJmxConnector jmxcDisabled = connect("cn=directory manager",
+    OpendsJmxConnector jmxcDisabled = connect("cn=Privileged User,o=test",
         "password", serverJmxPort);
     assertNull(jmxcDisabled);
 
     toggleEnableJmxConnector(connector, newJmxConnectionJmx.getDN(),
         true);
     Thread.sleep(100);
-    jmxcDisabled = connect("cn=directory manager", "password",
+    jmxcDisabled = connect("cn=Privileged User,o=test", "password",
         serverJmxPort);
     assertNotNull(jmxcDisabled);
 
@@ -279,7 +369,7 @@
     final String dn = "cn=JMX Connection Handler,cn=Connection Handlers,cn=config";
     final String attribute = "ds-cfg-listen-port";
 
-    OpendsJmxConnector connector = connect("cn=directory manager",
+    OpendsJmxConnector connector = connect("cn=Privileged User,o=test",
         "password", TestCaseUtils.getServerJmxPort());
     MBeanServerConnection jmxc = connector.getMBeanServerConnection();
     assertNotNull(jmxc);
@@ -309,7 +399,7 @@
     configureJmx(entry);
 
     // connect the the JMX service using the new port
-    connector = connect("cn=directory manager", "password",
+    connector = connect("cn=Privileged User,o=test", "password",
         serverJmxPort);
     jmxc = connector.getMBeanServerConnection();
     assertNotNull(jmxc);
@@ -333,7 +423,7 @@
     configureJmx(entry);
 
     // Check that the old port is ok
-    connector = connect("cn=directory manager", "password",
+    connector = connect("cn=Privileged User,o=test", "password",
         TestCaseUtils.getServerJmxPort());
     jmxc = connector.getMBeanServerConnection();
     assertNotNull(jmxc);
@@ -368,8 +458,9 @@
 
     configureJmx(entry);
 
-    OpendsJmxConnector jmxc = sslConnect("cn=directory manager",
+    OpendsJmxConnector jmxc = sslConnect("cn=Privileged User,o=test",
         "password", initJmxPort);
+    assertNotNull(jmxc,"OpendsJmxConnector shouldn't be null");
     MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
     jmxc.close();
 
@@ -393,7 +484,7 @@
       e.printStackTrace();
     }
 
-    jmxc = connect("cn=directory manager", "password", initJmxPort);
+    jmxc = connect("cn=Privileged User,o=test", "password", initJmxPort);
     jmxc.close();
     assertNotNull(jmxc);
   }
@@ -430,7 +521,7 @@
    * Connect to the JMX service.
    */
   private OpendsJmxConnector connect(String user, String password,
-      long jmxPort) throws MalformedURLException, IOException {
+      long jmxPort) throws MalformedURLException, IOException{
     HashMap<String, Object> env = new HashMap<String, Object>();
 
     // Provide the credentials required by the server to successfully
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
new file mode 100644
index 0000000..fd0d383
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
@@ -0,0 +1,1692 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.protocols.jmx;
+
+
+
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.messages.ProtocolMessages.MSGID_JMX_INSUFFICIENT_PRIVILEGES;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.UUID;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.admin.ClassLoaderProvider;
+import org.opends.server.backends.task.Task;
+import org.opends.server.backends.task.TaskBackend;
+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.DeleteOperation;
+import org.opends.server.core.DeleteOperationBasis;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ModifyDNOperation;
+import org.opends.server.core.ModifyOperation;
+import org.opends.server.core.ModifyOperationBasis;
+import org.opends.server.core.SchemaConfigManager;
+import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.protocols.ldap.LDAPFilter;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AuthenticationInfo;
+import org.opends.server.types.ByteStringFactory;
+import org.opends.server.types.Control;
+import org.opends.server.types.DN;
+import org.opends.server.types.DereferencePolicy;
+import org.opends.server.types.Entry;
+import org.opends.server.types.Modification;
+import org.opends.server.types.ModificationType;
+import org.opends.server.types.Privilege;
+import org.opends.server.types.RDN;
+import org.opends.server.types.ResultCode;
+import org.opends.server.types.SearchFilter;
+import org.opends.server.types.SearchScope;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+
+/**
+ * This class provides a set of test cases for the Directory Server JMX 
+ * privilege subsystem.
+ */
+public class JmxPrivilegeTestCase
+       extends JmxTestCase
+{
+  // An array of boolean values that indicates whether config read operations
+  // should be successful for users in the corresponding slots of the
+  // connections array.
+  private boolean[] successful;
+
+  // The set of client connections that should be used when performing
+  // operations.
+  private JmxClientConnection[] connections;
+
+
+
+  /**
+   * Make sure that the server is running and that an appropriate set of
+   * structures are in place.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @BeforeClass()
+  public void setUp()
+         throws Exception
+  {
+    super.setUp();
+
+
+    TestCaseUtils.initializeTestBackend(true);
+    TestCaseUtils.addEntries(
+      "dn: cn=Unprivileged Root,cn=Root DNs,cn=config",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "objectClass: ds-cfg-root-dn",
+      "cn: Unprivileged Root",
+      "givenName: Unprivileged",
+      "sn: Root",
+      "uid: unprivileged.root",
+      "userPassword: password",
+      "ds-privilege-name: config-read",
+      "ds-privilege-name: config-write",
+      "ds-privilege-name: password-reset",
+      "ds-privilege-name: update-schema",
+      "ds-privilege-name: ldif-import",
+      "ds-privilege-name: ldif-export",
+      "ds-privilege-name: backend-backup",
+      "ds-privilege-name: backend-restore",
+      "ds-privilege-name: unindexed-search",
+      "ds-privilege-name: -jmx-read",
+      "ds-privilege-name: -jmx-write",
+      "",
+      "dn: cn=Unprivileged JMX Root,cn=Root DNs,cn=config",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "objectClass: ds-cfg-root-dn",
+      "cn: Unprivileged Root",
+      "givenName: Unprivileged",
+      "sn: Root",
+      "uid: unprivileged.root",
+      "userPassword: password",
+      "",
+      "dn: cn=Proxy Root,cn=Root DNs,cn=config",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "objectClass: ds-cfg-root-dn",
+      "cn: Proxy Root",
+      "givenName: Proxy",
+      "sn: Root",
+      "uid: proxy.root",
+      "userPassword: password",
+      "ds-privilege-name: proxied-auth",
+      "ds-privilege-name: jmx-read",
+      "ds-privilege-name: jmx-write",
+      "",
+      "",
+      "dn: cn=Privileged User,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "cn: Privileged User",
+      "givenName: Privileged",
+      "sn: User",
+      "uid: privileged.user",
+      "userPassword: password",
+      "ds-privilege-name: config-read",
+      "ds-privilege-name: config-write",
+      "ds-privilege-name: password-reset",
+      "ds-privilege-name: update-schema",
+      "ds-privilege-name: ldif-import",
+      "ds-privilege-name: ldif-export",
+      "ds-privilege-name: backend-backup",
+      "ds-privilege-name: backend-restore",
+      "ds-privilege-name: proxied-auth",
+      "ds-privilege-name: bypass-acl",
+      "ds-privilege-name: unindexed-search",
+      "ds-privilege-name: jmx-read",
+      "ds-privilege-name: jmx-write",
+      "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
+           "cn=Password Policies,cn=config",
+      "",
+      "dn: cn=Unprivileged User,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "cn: Unprivileged User",
+      "givenName: Unprivileged",
+      "sn: User",
+      "uid: unprivileged.user",
+      "ds-privilege-name: bypass-acl",
+      "userPassword: password",
+      "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
+           "cn=Password Policies,cn=config",
+      "",
+      "dn: cn=PWReset Target,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "cn: PWReset Target",
+      "givenName: PWReset",
+      "sn: Target",
+      "uid: pwreset.target",
+      "userPassword: password");
+
+    TestCaseUtils.applyModifications(
+      "dn: o=test",
+      "changetype: modify",
+      "add: aci",
+      "aci: (version 3.0; acl \"Proxy Root\"; allow (proxy) " +
+           "userdn=\"ldap:///cn=Proxy Root,cn=Root DNs,cn=config\";)",
+      "aci: (version 3.0; acl \"Unprivileged Root\"; allow (proxy) " +
+           "userdn=\"ldap:///cn=Unprivileged Root,cn=Root DNs,cn=config\";)",
+      "aci: (version 3.0; acl \"Privileged User\"; allow (proxy) " +
+           "userdn=\"ldap:///cn=Privileged User,o=test\";)",
+      "aci: (targetattr=\"*\")(version 3.0; acl \"PWReset Target\"; " +
+           "allow (all) userdn=\"ldap:///cn=PWReset Target,o=test\";)");
+
+
+    // Build the array of connections we will use to perform the tests.
+    JmxConnectionHandler jmxCtx = getJmxConnectionHandler();
+    ArrayList<JmxClientConnection> connList =
+         new ArrayList<JmxClientConnection>();
+    ArrayList<Boolean> successList = new ArrayList<Boolean>();
+    String userDN ;
+    Entry userEntry ;
+    AuthenticationInfo authInfo;
+
+    connList.add(new JmxClientConnection(jmxCtx,new AuthenticationInfo()));
+    successList.add(false);
+
+    userDN    = "cn=Unprivileged Root,cn=Root DNs,cn=config";
+    userEntry = DirectoryServer.getEntry(DN.decode(userDN));
+    authInfo  = new AuthenticationInfo(userEntry, true);
+    connList.add(new JmxClientConnection(jmxCtx,authInfo));
+    successList.add(false);
+
+    userDN    = "cn=Proxy Root,cn=Root DNs,cn=config";
+    userEntry = DirectoryServer.getEntry(DN.decode(userDN));
+    authInfo  = new AuthenticationInfo(userEntry, true);
+    connList.add(new JmxClientConnection(jmxCtx,authInfo));
+    successList.add(true);
+
+    userDN    = "cn=Unprivileged User,o=test";
+    userEntry = DirectoryServer.getEntry(DN.decode(userDN));
+    authInfo  = new AuthenticationInfo(userEntry, false);
+    connList.add(new JmxClientConnection(jmxCtx,authInfo));
+    successList.add(false);
+
+    userDN    = "cn=Privileged User,o=test";
+    userEntry = DirectoryServer.getEntry(DN.decode(userDN));
+    authInfo  = new AuthenticationInfo(userEntry, false);
+    connList.add(new JmxClientConnection(jmxCtx,authInfo));
+    successList.add(true);
+
+
+    connections = new JmxClientConnection[connList.size()];
+    successful  = new boolean[connections.length];
+    for (int i=0; i < connections.length; i++)
+    {
+      connections[i] = connList.get(i);
+      successful[i]  = successList.get(i);
+    }
+
+    TestCaseUtils.addEntries(
+        "dn: dc=unindexed,dc=jeb",
+        "objectClass: top",
+        "objectClass: domain",
+        "",
+        "dn: cn=test1 user,dc=unindexed,dc=jeb",
+        "objectClass: top",
+        "objectClass: person",
+        "objectClass: organizationalPerson",
+        "objectClass: inetOrgPerson",
+        "cn: test1 user",
+        "givenName: user",
+        "sn: test1",
+        "",
+        "dn: cn=test2 user,dc=unindexed,dc=jeb",
+        "objectClass: top",
+        "objectClass: person",
+        "objectClass: organizationalPerson",
+        "objectClass: inetOrgPerson",
+        "cn: test2 user",
+        "givenName: user",
+        "sn: test2"
+    );
+  }
+
+
+
+  /**
+   * Cleans up anything that might be left around after running the tests in
+   * this class.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @AfterClass()
+  public void cleanUp()
+         throws Exception
+  {
+    InternalClientConnection conn = InternalClientConnection
+        .getRootConnection();
+
+    DeleteOperation deleteOperation = conn.processDelete(DN
+        .decode("cn=Unprivileged Root,cn=Root DNs,cn=config"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+    
+    deleteOperation = conn.processDelete(DN
+        .decode("cn=Unprivileged JMX Root,cn=Root DNs,cn=config"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation = conn.processDelete(DN
+        .decode("cn=Proxy Root,cn=Root DNs,cn=config"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation = conn.processDelete(DN
+        .decode("cn=Privileged User,o=test"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation = conn.processDelete(DN
+        .decode("cn=UnPrivileged User,o=test"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation = conn.processDelete(DN
+        .decode("cn=PWReset Target,o=test"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation = conn.processDelete(DN
+        .decode("cn=test1 user,dc=unindexed,dc=jeb"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation = conn.processDelete(DN
+        .decode("cn=test2 user,dc=unindexed,dc=jeb"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation = conn.processDelete(DN
+        .decode("dc=unindexed,dc=jeb"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Retrieves a set of data that can be used for performing the tests.  The
+   * arguments generated for each method will be:
+   * <OL>
+   *   <LI>A client connection to use to perform the operation</LI>
+   *   <LI>A flag indicating whether or not the operation should succeed</LI>
+   * </OL>
+   *
+   * @return  A set of data that can be used for performing the tests.
+   */
+  @DataProvider(name = "testdata")
+  public Object[][] getTestData()
+  {
+    Object[][] returnArray = new Object[connections.length][2];
+    for (int i=0; i < connections.length; i++)
+    {
+      returnArray[i][0] = connections[i];
+      returnArray[i][1] = successful[i];
+    }
+
+    return returnArray;
+  }
+
+
+  /**
+   * Check that simple connection to the JMX service are
+   * accepted only if JMX_READ privilege is set.
+   */
+  @Test(enabled = true)
+  public void simpleConnectJmxPrivilege() throws Exception
+  {
+    OpendsJmxConnector opendsConnector;
+    int jmxPort = TestCaseUtils.getServerJmxPort() ;
+    HashMap<String, Object> env = new HashMap<String, Object>();
+    String user = "cn=Unprivileged JMX Root,cn=Root DNs,cn=config";
+    String password  = "password";
+    String[] credentials = new String[] { user, password };
+    env.put("jmx.remote.credentials", credentials);
+    env.put("jmx.remote.x.client.connection.check.period", 0);
+
+    // Try connection withoutJMX_READ privilege
+    // Expected result: failed
+    try
+    {
+      opendsConnector = new OpendsJmxConnector("localhost", jmxPort, env);
+      opendsConnector.connect();
+      opendsConnector.close() ;
+      assertTrue(false, "User \"cn=Unprivileged JMX Root,cn=Root "+
+          "DNs,cn=config\" doesn't have JMX_READ privilege but he's able " +
+          "to connect, which is not the correct behavior");
+    }
+    catch (SecurityException e)
+    {
+      int msgID = MSGID_JMX_INSUFFICIENT_PRIVILEGES;
+      String message = getMessage(msgID);
+      assertEquals(message, e.getMessage());
+    }
+    catch (IOException e)
+    {
+      assertTrue(false, "Unexpected exception - error message: "
+          + e.getMessage());
+    }
+    
+    // Add JMX_READ privilege
+    InternalClientConnection rootConnection =
+      InternalClientConnection.getRootConnection();
+    ArrayList<Modification> mods = new ArrayList<Modification>();
+    mods.add(new Modification(ModificationType.ADD,
+                      new Attribute("ds-privilege-name", "jmx-read")));
+    ModifyOperation modifyOperation =
+         rootConnection.processModify(DN.decode(user), mods);
+    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+    
+    //  Try connection withoutJMX_READ privilege
+    // Expected result: success
+    try
+    {
+      opendsConnector = new OpendsJmxConnector("localhost", jmxPort, env);
+      opendsConnector.connect();
+      opendsConnector.close() ;
+      assertTrue(true, "User \"cn=Unprivileged JMX Root,cn=Root "+
+          "DNs,cn=config\" has JMX_READ privilege and he's able " +
+          "to connect, which is the correct behavior.");
+    }
+    catch (SecurityException e)
+    {
+      assertTrue(true, "User \"cn=Unprivileged JMX Root,cn=Root " +
+          "DNs,cn=config\" has JMX_READ privilege and he's NOT able " +
+          "to connect, which is NOT the correct behavior.");
+    }
+    catch (IOException e)
+    {
+      assertTrue(false, "Unexpected exception - error message: "
+          + e.getMessage());
+    }
+    
+    // remove JMX_READ privilege
+    mods = new ArrayList<Modification>();
+    mods.add(new Modification(ModificationType.DELETE,
+                      new Attribute("ds-privilege-name", "jmx-read")));
+    modifyOperation =
+         rootConnection.processModify(DN.decode(user), mods);
+    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+    
+    // Try connection withoutJMX_READ privilege
+    // Expected result: failed
+    try
+    {
+      opendsConnector = new OpendsJmxConnector("localhost", jmxPort, env);
+      opendsConnector.connect();
+      opendsConnector.close() ;
+      assertTrue(false, "User \"cn=Unprivileged JMX Root,cn=Root "+
+          "DNs,cn=config\" doesn't have JMX_READ privilege but he's able " +
+          "to connect, which is not the correct behavior");
+    }
+    catch (SecurityException e)
+    {
+      int msgID = MSGID_JMX_INSUFFICIENT_PRIVILEGES;
+      String message = getMessage(msgID);
+      assertEquals(message, e.getMessage());
+    }
+    catch (IOException e)
+    {
+      assertTrue(false, "Unexpected exception - error message: "
+          + e.getMessage());
+    }
+  }
+  
+
+  /**
+   * Tests to ensure that search operations in the server configuration properly
+   * respect the JMX_READ privilege.
+   *
+   * @param  conn          The client connection to use to perform the search
+   *                       operation.
+   * @param  hasPrivilege  Indicates whether the authenticated user is expected
+   *                       to have the JMX_READ privilege and therefore the
+   *                       search should succeed.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "testdata")
+  public void testConfigReadSearch(JmxClientConnection conn,
+                                   boolean hasPrivilege)
+         throws Exception
+  {
+    assertEquals(conn.hasPrivilege(Privilege.JMX_READ, null), hasPrivilege);
+
+    ASN1OctetString dn = new ASN1OctetString(DN.decode("cn=config").toString());
+    LDAPFilter filter = new LDAPFilter(SearchFilter
+        .createFilterFromString("(objectClass=*)"));
+    InternalSearchOperation searchOperation = conn.processSearch(dn,
+        SearchScope.BASE_OBJECT, filter);
+    if (hasPrivilege)
+    {
+      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
+    }
+    else
+    {
+      assertEquals(searchOperation.getResultCode(),
+                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+    }
+  }
+
+
+
+  /**
+   * 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);
+
+    ASN1OctetString asn1 = new ASN1OctetString(DN.decode("cn=config")
+        .toString());
+    ASN1OctetString value = new ASN1OctetString("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",
+      "cn: Test Root",
+      "givenName: Test",
+      "sn: Root",
+      "userPassword: password");
+
+    AddOperation addOperation =
+         conn.processAdd(entry.getDN(), entry.getObjectClasses(),
+                         entry.getUserAttributes(),
+                         entry.getOperationalAttributes());
+    if (hasPrivilege)
+    {
+      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+      DeleteOperation deleteOperation = conn.processDelete(entry.getDN());
+      assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+    }
+    else
+    {
+      assertEquals(addOperation.getResultCode(),
+                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+
+      DeleteOperation deleteOperation =
+           conn.processDelete(
+                DN.decode("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,
+                              new Attribute("ds-cfg-size-limit", "2000")));
+
+    ModifyOperation modifyOperation =
+         conn.processModify(DN.decode("cn=config"), mods);
+    if (hasPrivilege)
+    {
+      assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+      mods.clear();
+      mods.add(new Modification(ModificationType.REPLACE,
+                              new Attribute("ds-cfg-size-limit", "1000")));
+
+      modifyOperation = conn.processModify(DN.decode("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.decode("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,
+                              new Attribute("attributetypes", attrDefinition)));
+
+    ModifyOperation modifyOperation =
+         conn.processModify(DN.decode("cn=schema"), mods);
+    if (hasPrivilege)
+    {
+      assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+      mods.clear();
+      mods.add(new Modification(ModificationType.DELETE,
+                        new Attribute("attributetypes", attrDefinition)));
+
+      modifyOperation = conn.processModify(DN.decode("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.
+   *
+   * @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 testUpdateSchemaAddSchemaFile(JmxClientConnection conn,
+                                            boolean hasPrivilege)
+         throws Exception
+  {
+    assertEquals(conn.hasPrivilege(Privilege.JMX_WRITE, null),
+                 hasPrivilege);
+
+
+    String schemaDirectory = SchemaConfigManager.getSchemaDirectoryPath();
+
+    String identifier;
+    Entry authNEntry = conn.getAuthenticationInfo().getAuthenticationEntry();
+    if (authNEntry == null)
+    {
+      identifier = "null";
+    }
+    else
+    {
+      identifier = authNEntry.getDN().toString();
+      identifier = identifier.replace(',', '-');
+      identifier = identifier.replace(' ', '-');
+      identifier = identifier.replace('=', '-');
+    }
+
+    String[] fileLines =
+    {
+      "dn: cn=schema",
+      "objectClass: top",
+      "objectClass: ldapSubentry",
+      "objectClass: subschema",
+      "attributeTypes: ( " + identifier.toLowerCase() + "-oid " +
+           "NAME '" + identifier + "' )"
+    };
+
+    File validFile = new File(schemaDirectory, "05-" + identifier + ".ldif");
+    BufferedWriter writer = new BufferedWriter(new FileWriter(validFile));
+    for (String line : fileLines)
+    {
+      writer.write(line);
+      writer.newLine();
+    }
+    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.getDN(), taskEntry.getObjectClasses(),
+                         taskEntry.getUserAttributes(),
+                         taskEntry.getOperationalAttributes());
+
+    if (hasPrivilege)
+    {
+      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+      Task task = getCompletedTask(taskEntry.getDN());
+      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.getDN(), taskEntry.getObjectClasses(),
+                         taskEntry.getUserAttributes(),
+                         taskEntry.getOperationalAttributes());
+
+    if (hasPrivilege)
+    {
+      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+      Task task = getCompletedTask(taskEntry.getDN());
+      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.getDN(), taskEntry.getObjectClasses(),
+                         taskEntry.getUserAttributes(),
+                         taskEntry.getOperationalAttributes());
+
+    if (hasPrivilege)
+    {
+      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+      Task task = getCompletedTask(taskEntry.getDN());
+      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.getDN(), taskEntry.getObjectClasses(),
+                         taskEntry.getUserAttributes(),
+                         taskEntry.getOperationalAttributes());
+
+    if (hasPrivilege)
+    {
+      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+      Task task = getCompletedTask(taskEntry.getDN());
+      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.getDN(), taskEntry.getObjectClasses(),
+                         taskEntry.getUserAttributes(),
+                         taskEntry.getOperationalAttributes());
+
+    if (hasPrivilege)
+    {
+      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+      Task task = getCompletedTask(taskEntry.getDN());
+      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.getDN(), taskEntry.getObjectClasses(),
+                         taskEntry.getUserAttributes(),
+                         taskEntry.getOperationalAttributes());
+
+    if (hasPrivilege)
+    {
+      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+      Task task = getCompletedTask(taskEntry.getDN());
+      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
+   * the PROXIED_AUTH privilege for add, delete, modify and modify DN requests
+   * that contain the proxied auth v1 control.
+   *
+   * @param  conn          The client connection to use to perform the
+   *                       operation.
+   * @param  hasPrivilege  Indicates whether the authenticated user is expected
+   *                       to have the PROXIED_AUTH privilege and therefore
+   *                       the operation should succeed.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "testdata")
+  public void testProxyAuthV1Write(JmxClientConnection conn,
+                                   boolean hasPrivilege)
+         throws Exception
+  {
+    // We can't trust the value of hasPrivilege because root users don't get
+    // proxy privileges by default.  So make the determination based on the
+    // privileges the user actually has.
+    boolean hasProxyPrivilege = conn.hasPrivilege(Privilege.PROXIED_AUTH, null);
+
+    Entry e = TestCaseUtils.makeEntry(
+      "dn: cn=ProxyV1 Test,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "cn: ProxyV1 Test",
+      "givenName: ProxyV1",
+      "sn: Test");
+
+    ArrayList<Control> controls = new ArrayList<Control>(1);
+    controls.add(new ProxiedAuthV1Control(
+                          DN.decode("cn=PWReset Target,o=test")));
+
+
+    // Try to add the entry.  If this fails with the proxy control, then add it
+    // with a root connection so we can do other things with it.
+    AddOperationBasis addOperation =
+         new AddOperationBasis(conn, conn
+        .nextOperationID(), conn.nextMessageID(), controls, e.getDN(), e
+        .getObjectClasses(), e.getUserAttributes(), e
+        .getOperationalAttributes());
+    addOperation.run();
+
+    if (hasProxyPrivilege)
+    {
+      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+    }
+    else
+    {
+      assertEquals(addOperation.getResultCode(),
+                   ResultCode.AUTHORIZATION_DENIED);
+      TestCaseUtils.addEntry(e);
+    }
+
+
+    // Try to modify the entry to add a description.
+    ArrayList<Modification> mods = new ArrayList<Modification>(1);
+    mods.add(new Modification(ModificationType.REPLACE,
+                              new Attribute("description", "foo")));
+
+    ModifyOperationBasis modifyOperation = new ModifyOperationBasis(conn,
+        conn.nextOperationID(), conn.nextMessageID(), controls, e.getDN(),
+        mods);
+    modifyOperation.run();
+
+    if (hasProxyPrivilege)
+    {
+      assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+    }
+    else
+    {
+      assertEquals(modifyOperation.getResultCode(),
+                   ResultCode.AUTHORIZATION_DENIED);
+    }
+
+
+    // Try to rename the entry.
+    ModifyDNOperation modifyDNOperation =
+         new ModifyDNOperation(conn, conn.nextOperationID(),
+                               conn.nextMessageID(), controls, e.getDN(),
+                               RDN.decode("cn=Proxy V1 Test"), true, null);
+    modifyDNOperation.run();
+
+    DN newEntryDN;
+    if (hasProxyPrivilege)
+    {
+      assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
+      newEntryDN = modifyDNOperation.getUpdatedEntry().getDN();
+    }
+    else
+    {
+      assertEquals(modifyDNOperation.getResultCode(),
+                   ResultCode.AUTHORIZATION_DENIED);
+      newEntryDN = e.getDN();
+    }
+
+
+    // Try to delete the operation.  If this fails, then delete it with a root
+    // connection so it gets cleaned up.
+    DeleteOperationBasis deleteOperation =
+         new DeleteOperationBasis(conn,
+        conn.nextOperationID(), conn.nextMessageID(), controls, newEntryDN);
+    deleteOperation.run();
+
+    if (hasProxyPrivilege)
+    {
+      assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+    }
+    else
+    {
+      assertEquals(deleteOperation.getResultCode(),
+                   ResultCode.AUTHORIZATION_DENIED);
+
+      InternalClientConnection rootConnection =
+           InternalClientConnection.getRootConnection();
+      DeleteOperation delOp = rootConnection.processDelete(newEntryDN);
+      assertEquals(delOp.getResultCode(), ResultCode.SUCCESS);
+    }
+  }
+
+
+
+  /**
+   * Tests to ensure that the use of the Directory Server will properly respect
+   * the PROXIED_AUTH privilege for search and compare requests that contain the
+   * proxied auth v1 control.
+   *
+   * @param  conn          The client connection to use to perform the
+   *                       operation.
+   * @param  hasPrivilege  Indicates whether the authenticated user is expected
+   *                       to have the PROXIED_AUTH privilege and therefore
+   *                       the operation should succeed.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "testdata")
+  public void testProxyAuthV1Read(JmxClientConnection conn,
+                                  boolean hasPrivilege)
+         throws Exception
+  {
+    // We can't trust the value of hasPrivilege because root users don't get
+    // proxy privileges by default.  So make the determination based on the
+    // privileges the user actually has.
+    boolean hasProxyPrivilege = conn.hasPrivilege(Privilege.PROXIED_AUTH, null);
+
+    DN targetDN = DN.decode("cn=PWReset Target,o=test");
+    ArrayList<Control> controls = new ArrayList<Control>(1);
+    controls.add(new ProxiedAuthV1Control(targetDN));
+
+
+    // Test a compare operation against the PWReset Target user.
+    CompareOperation compareOperation =
+         new CompareOperation(conn, conn.nextOperationID(),
+                              conn.nextMessageID(), controls, targetDN,
+                              DirectoryServer.getAttributeType("cn", true),
+                              ByteStringFactory.create("PWReset Target"));
+    compareOperation.run();
+
+    if (hasProxyPrivilege)
+    {
+      assertEquals(compareOperation.getResultCode(), ResultCode.COMPARE_TRUE);
+    }
+    else
+    {
+      assertEquals(compareOperation.getResultCode(),
+                   ResultCode.AUTHORIZATION_DENIED);
+    }
+
+
+    // Test a search operation against the PWReset Target user.
+    InternalSearchOperation searchOperation =
+         new InternalSearchOperation(conn, conn.nextOperationID(),
+                  conn.nextMessageID(), controls, targetDN,
+                  SearchScope.BASE_OBJECT,
+                  DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
+                  SearchFilter.createFilterFromString("(objectClass=*)"), null,
+                  null);
+    searchOperation.run();
+
+    if (hasProxyPrivilege)
+    {
+      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
+    }
+    else
+    {
+      assertEquals(searchOperation.getResultCode(),
+                   ResultCode.AUTHORIZATION_DENIED);
+    }
+  }
+
+
+
+  /**
+   * Tests to ensure that the use of the Directory Server will properly respect
+   * the PROXIED_AUTH privilege for add, delete, modify and modify DN requests
+   * that contain the proxied auth v2 control.
+   *
+   * @param  conn          The client connection to use to perform the
+   *                       operation.
+   * @param  hasPrivilege  Indicates whether the authenticated user is expected
+   *                       to have the PROXIED_AUTH privilege and therefore
+   *                       the operation should succeed.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "testdata")
+  public void testProxyAuthV2Write(JmxClientConnection conn,
+                                   boolean hasPrivilege)
+         throws Exception
+  {
+    // We can't trust the value of hasPrivilege because root users don't get
+    // proxy privileges by default.  So make the determination based on the
+    // privileges the user actually has.
+    boolean hasProxyPrivilege = conn.hasPrivilege(Privilege.PROXIED_AUTH, null);
+
+    Entry e = TestCaseUtils.makeEntry(
+      "dn: cn=ProxyV2 Test,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "cn: ProxyV2 Test",
+      "givenName: ProxyV2",
+      "sn: Test");
+
+    ArrayList<Control> controls = new ArrayList<Control>(1);
+    controls.add(new ProxiedAuthV2Control(
+                          new ASN1OctetString("dn:cn=PWReset Target,o=test")));
+
+
+    // Try to add the entry.  If this fails with the proxy control, then add it
+    // with a root connection so we can do other things with it.
+    DN authDN = conn.getAuthenticationInfo().getAuthenticationDN();
+    AddOperationBasis addOperation =
+         new AddOperationBasis(conn, conn
+        .nextOperationID(), conn.nextMessageID(), controls, e.getDN(), e
+        .getObjectClasses(), e.getUserAttributes(), e
+        .getOperationalAttributes());
+    addOperation.run();
+
+    if (hasProxyPrivilege)
+    {
+      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS,
+                   "Unexpected add failure for user " + authDN);
+    }
+    else
+    {
+      assertEquals(addOperation.getResultCode(),
+                   ResultCode.AUTHORIZATION_DENIED,
+                   "Unexpected add success for user " + authDN);
+      TestCaseUtils.addEntry(e);
+    }
+
+
+    // Try to modify the entry to add a description.
+    ArrayList<Modification> mods = new ArrayList<Modification>(1);
+    mods.add(new Modification(ModificationType.REPLACE,
+                              new Attribute("description", "foo")));
+
+    ModifyOperationBasis modifyOperation =
+         new ModifyOperationBasis(conn,
+        conn.nextOperationID(), conn.nextMessageID(), controls, e.getDN(),
+        mods);
+    modifyOperation.run();
+
+    if (hasProxyPrivilege)
+    {
+      assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS,
+                   "Unexpected mod failure for user " + authDN);
+    }
+    else
+    {
+      assertEquals(modifyOperation.getResultCode(),
+                   ResultCode.AUTHORIZATION_DENIED,
+                   "Unexpected mod success for user " + authDN);
+    }
+
+
+    // Try to rename the entry.
+    ModifyDNOperation modifyDNOperation =
+         new ModifyDNOperation(conn, conn.nextOperationID(),
+                               conn.nextMessageID(), controls, e.getDN(),
+                               RDN.decode("cn=Proxy V2 Test"), true, null);
+    modifyDNOperation.run();
+
+    DN newEntryDN;
+    if (hasProxyPrivilege)
+    {
+      assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS,
+                   "Unexpected moddn failure for user " + authDN);
+      newEntryDN = modifyDNOperation.getUpdatedEntry().getDN();
+    }
+    else
+    {
+      assertEquals(modifyDNOperation.getResultCode(),
+                   ResultCode.AUTHORIZATION_DENIED,
+                   "Unexpected moddn success for user " + authDN);
+      newEntryDN = e.getDN();
+    }
+
+
+    // Try to delete the operation.  If this fails, then delete it with a root
+    // connection so it gets cleaned up.
+    DeleteOperationBasis deleteOperation =
+         new DeleteOperationBasis(conn,
+        conn.nextOperationID(), conn.nextMessageID(), controls, newEntryDN);
+    deleteOperation.run();
+
+    if (hasProxyPrivilege)
+    {
+      assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS,
+                   "Unexpected delete failure for user " + authDN);
+    }
+    else
+    {
+      assertEquals(deleteOperation.getResultCode(),
+                   ResultCode.AUTHORIZATION_DENIED,
+                   "Unexpected delete success for user " + authDN);
+
+      InternalClientConnection rootConnection =
+           InternalClientConnection.getRootConnection();
+      DeleteOperation delOp = rootConnection.processDelete(newEntryDN);
+      assertEquals(delOp.getResultCode(), ResultCode.SUCCESS);
+    }
+  }
+
+
+
+  /**
+   * Tests to ensure that the use of the Directory Server will properly respect
+   * the PROXIED_AUTH privilege for search and compare requests that contain the
+   * proxied auth v2 control.
+   *
+   * @param  conn          The client connection to use to perform the
+   *                       operation.
+   * @param  hasPrivilege  Indicates whether the authenticated user is expected
+   *                       to have the PROXIED_AUTH privilege and therefore
+   *                       the operation should succeed.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test(dataProvider = "testdata")
+  public void testProxyAuthV2Read(JmxClientConnection conn,
+                                  boolean hasPrivilege)
+         throws Exception
+  {
+    // We can't trust the value of hasPrivilege because root users don't get
+    // proxy privileges by default.  So make the determination based on the
+    // privileges the user actually has.
+    boolean hasProxyPrivilege = conn.hasPrivilege(Privilege.PROXIED_AUTH, null);
+
+    DN targetDN = DN.decode("cn=PWReset Target,o=test");
+    ArrayList<Control> controls = new ArrayList<Control>(1);
+    controls.add(new ProxiedAuthV2Control(
+                          new ASN1OctetString("dn:" + targetDN.toString())));
+
+
+    // Test a compare operation against the PWReset Target user.
+    CompareOperation compareOperation =
+         new CompareOperation(conn, conn.nextOperationID(),
+                              conn.nextMessageID(), controls, targetDN,
+                              DirectoryServer.getAttributeType("cn", true),
+                              ByteStringFactory.create("PWReset Target"));
+    compareOperation.run();
+
+    if (hasProxyPrivilege)
+    {
+      assertEquals(compareOperation.getResultCode(), ResultCode.COMPARE_TRUE);
+    }
+    else
+    {
+      assertEquals(compareOperation.getResultCode(),
+                   ResultCode.AUTHORIZATION_DENIED);
+    }
+
+
+    // Test a search operation against the PWReset Target user.
+    InternalSearchOperation searchOperation =
+         new InternalSearchOperation(conn, conn.nextOperationID(),
+                  conn.nextMessageID(), controls, targetDN,
+                  SearchScope.BASE_OBJECT,
+                  DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
+                  SearchFilter.createFilterFromString("(objectClass=*)"), null,
+                  null);
+    searchOperation.run();
+
+    if (hasProxyPrivilege)
+    {
+      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
+    }
+    else
+    {
+      assertEquals(searchOperation.getResultCode(),
+                   ResultCode.AUTHORIZATION_DENIED);
+    }
+  }
+
+
+  /**
+   * Tests the ability to update the set of privileges for a user on the fly
+   * and have them take effect immediately.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testUpdateUserPrivileges()
+         throws Exception
+  {
+    InternalClientConnection rootConnection =
+      InternalClientConnection.getRootConnection();
+
+    TestCaseUtils.addEntry(
+      "dn: cn=Test User,o=test",
+      "objectClass: top",
+      "objectClass: person",
+      "objectClass: organizationalPerson",
+      "objectClass: inetOrgPerson",
+      "cn: Test User",
+      "givenName: Test",
+      "sn: User",
+      "userPassword: password");
+
+
+    Entry testEntry =
+               DirectoryServer.getEntry(DN.decode("cn=Test User,o=test"));
+    AuthenticationInfo authInfo = new AuthenticationInfo(testEntry, false);
+    JmxConnectionHandler jmxCtx = getJmxConnectionHandler();
+    JmxClientConnection testConnection =
+         new JmxClientConnection(jmxCtx,authInfo);
+
+
+    // Make sure the user starts out without any privileges.
+    for (Privilege p : Privilege.values())
+    {
+      assertFalse(testConnection.hasPrivilege(p, null));
+    }
+
+
+    // Modify the user entry to add the JMX_READ privilege and verify that
+    // the client connection reflects that.
+    ArrayList<Modification> mods = new ArrayList<Modification>();
+    mods.add(new Modification(ModificationType.ADD,
+                      new Attribute("ds-privilege-name", "jmx-read")));
+    ModifyOperation modifyOperation =
+         rootConnection.processModify(DN.decode("cn=Test User,o=test"), mods);
+    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+    assertTrue(testConnection.hasPrivilege(Privilege.JMX_READ, null));
+
+
+    // Take the privilege away from the user and verify that it is recognized
+    // immediately.
+    mods.clear();
+    mods.add(new Modification(ModificationType.DELETE,
+                      new Attribute("ds-privilege-name", "jmx-read")));
+    modifyOperation =
+         rootConnection.processModify(DN.decode("cn=Test User,o=test"), mods);
+    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+    assertFalse(testConnection.hasPrivilege(Privilege.JMX_READ, null));
+
+
+    DeleteOperation deleteOperation =
+         rootConnection.processDelete(DN.decode("cn=Test User,o=test"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+
+
+
+  /**
+   * Tests the ability to update the set of root privileges and have them take
+   * effect immediately for new root connections.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  @Test()
+  public void testUpdateRootPrivileges()
+         throws Exception
+  {
+    // Make sure that a root connection doesn't  have the proxied auth
+    // privilege.
+    DN unprivRootDN = DN.decode("cn=Unprivileged Root,cn=Root DNs,cn=config");
+    Entry unprivRootEntry = DirectoryServer.getEntry(unprivRootDN);
+    AuthenticationInfo authInfo = new AuthenticationInfo(unprivRootEntry, true);
+    JmxConnectionHandler jmxCtx = getJmxConnectionHandler();
+    JmxClientConnection unprivRootConn =
+         new JmxClientConnection(jmxCtx,authInfo);
+    assertFalse(unprivRootConn.hasPrivilege(Privilege.PROXIED_AUTH, null));
+
+
+    // Update the set of root privileges to include proxied auth.
+    InternalClientConnection internalRootConn =
+      InternalClientConnection.getRootConnection();
+
+    ArrayList<Modification> mods = new ArrayList<Modification>();
+    mods.add(new Modification(ModificationType.ADD,
+                      new Attribute("ds-cfg-default-root-privilege-name",
+                                    "proxied-auth")));
+    ModifyOperation modifyOperation =
+         internalRootConn.processModify(DN.decode("cn=Root DNs,cn=config"),
+                                        mods);
+    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+    // Get a new root connection and verify that it now has proxied auth.
+    unprivRootEntry = DirectoryServer.getEntry(unprivRootDN);
+    authInfo = new AuthenticationInfo(unprivRootEntry, true);
+    unprivRootConn = new JmxClientConnection(jmxCtx,authInfo);
+    assertTrue(unprivRootConn.hasPrivilege(Privilege.PROXIED_AUTH, null));
+
+
+    // Update the set of root privileges to revoke proxied auth.
+    mods.clear();
+    mods.add(new Modification(ModificationType.DELETE,
+                      new Attribute("ds-cfg-default-root-privilege-name",
+                                    "proxied-auth")));
+    modifyOperation =
+         internalRootConn.processModify(DN.decode("cn=Root DNs,cn=config"),
+                                        mods);
+    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+
+
+    // Get a new root connection and verify that it no longer has proxied auth.
+    unprivRootEntry = DirectoryServer.getEntry(unprivRootDN);
+    authInfo = new AuthenticationInfo(unprivRootEntry, true);
+    unprivRootConn = new JmxClientConnection(jmxCtx,authInfo);
+    assertFalse(unprivRootConn.hasPrivilege(Privilege.PROXIED_AUTH, null));
+  }
+
+
+
+  /**
+   * Retrieves the specified task from the server, waiting for it to finish all
+   * the running its going to do before returning.
+   *
+   * @param  taskEntryDN  The DN of the entry for the task to retrieve.
+   *
+   * @return  The requested task entry.
+   *
+   * @throws  Exception  If an unexpected problem occurs.
+   */
+  private Task getCompletedTask(DN taskEntryDN)
+          throws Exception
+  {
+    TaskBackend taskBackend =
+         (TaskBackend) DirectoryServer.getBackend(DN.decode("cn=tasks"));
+    Task task = taskBackend.getScheduledTask(taskEntryDN);
+    if (task == null)
+    {
+      long stopWaitingTime = System.currentTimeMillis() + 10000L;
+      while ((task == null) && (System.currentTimeMillis() < stopWaitingTime))
+      {
+        Thread.sleep(10);
+        task = taskBackend.getScheduledTask(taskEntryDN);
+      }
+    }
+
+    if (task == null)
+    {
+      throw new AssertionError("There is no such task " +
+                               taskEntryDN.toString());
+    }
+
+    if (! TaskState.isDone(task.getTaskState()))
+    {
+      long stopWaitingTime = System.currentTimeMillis() + 20000L;
+      while ((! TaskState.isDone(task.getTaskState())) &&
+             (System.currentTimeMillis() < stopWaitingTime))
+      {
+        Thread.sleep(10);
+      }
+    }
+
+    if (! TaskState.isDone(task.getTaskState()))
+    {
+      throw new AssertionError("Task " + taskEntryDN.toString() +
+                               " did not complete in a timely manner.");
+    }
+
+    return task;
+  }
+}
+
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/postConnectedDisconnectTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/postConnectedDisconnectTest.java
index 04363eb..d01c65a 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/postConnectedDisconnectTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/postConnectedDisconnectTest.java
@@ -30,7 +30,13 @@
 import java.util.HashMap;
 
 import org.opends.server.TestCaseUtils;
+import org.opends.server.core.DeleteOperation;
 import org.opends.server.plugins.InvocationCounterPlugin;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.types.DN;
+import org.opends.server.types.ResultCode;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 import static org.testng.Assert.*;
 
@@ -40,6 +46,63 @@
  */
 public class postConnectedDisconnectTest extends JmxTestCase
 {
+  
+  /**
+   * Set up the environment for performing the tests in this suite.
+   * 
+   * @throws Exception
+   *           If the environment could not be set up.
+   */
+  @BeforeClass
+  public void setUp() throws Exception
+  {
+    super.setUp();
+    
+    TestCaseUtils.addEntries(
+        "dn: cn=Privileged User,o=test",
+        "objectClass: top",
+        "objectClass: person",
+        "objectClass: organizationalPerson",
+        "objectClass: inetOrgPerson",
+        "cn: Privileged User",
+        "givenName: Privileged",
+        "sn: User",
+        "uid: privileged.user",
+        "userPassword: password",
+        "ds-privilege-name: config-read",
+        "ds-privilege-name: config-write",
+        "ds-privilege-name: password-reset",
+        "ds-privilege-name: update-schema",
+        "ds-privilege-name: ldif-import",
+        "ds-privilege-name: ldif-export",
+        "ds-privilege-name: backend-backup",
+        "ds-privilege-name: backend-restore",
+        "ds-privilege-name: proxied-auth",
+        "ds-privilege-name: bypass-acl",
+        "ds-privilege-name: unindexed-search",
+        "ds-privilege-name: jmx-read",
+        "ds-privilege-name: jmx-write",
+        "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
+             "cn=Password Policies,cn=config");
+  }
+  
+  /**
+   * Clean up the environment after performing the tests in this suite.
+   * 
+   * @throws Exception
+   *           If the environment could not be set up.
+   */
+  @AfterClass
+  public void afterClass() throws Exception
+  {
+    InternalClientConnection conn = InternalClientConnection
+        .getRootConnection();
+
+    DeleteOperation deleteOperation = conn.processDelete(DN
+        .decode("cn=Privileged User,o=test"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+  }
+  
   /**
    * Perform a simple connect.
    * @throws Exception If something wrong occurs.
@@ -54,7 +117,8 @@
 
     // Create a new client connection
     HashMap<String, Object> env = new HashMap<String, Object>();
-    String[] credentials = new String[] { "cn=directory manager" , "password"};
+    String[] credentials = new String[] { "cn=Privileged User,o=test",
+        "password" };
     env.put("jmx.remote.credentials", credentials);
     env.put("jmx.remote.x.client.connection.check.period",0);
     OpendsJmxConnector opendsConnector = new OpendsJmxConnector("localhost",
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
index bdd0828..87e4bf6 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
@@ -303,6 +303,38 @@
          conn.processDelete(
               DN.decode("cn=Unprivileged Root,cn=Root DNs,cn=config"));
     assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation =
+      conn.processDelete(
+           DN.decode("cn=Proxy Root,cn=Root DNs,cn=config"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation =
+      conn.processDelete(
+           DN.decode("cn=Privileged User,o=test"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation =
+      conn.processDelete(
+           DN.decode("cn=UnPrivileged User,o=test"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation =
+      conn.processDelete(
+           DN.decode("cn=PWReset Target,o=test"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation = conn.processDelete(DN
+        .decode("cn=test1 user,dc=unindexed,dc=jeb"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation = conn.processDelete(DN
+        .decode("cn=test2 user,dc=unindexed,dc=jeb"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+
+    deleteOperation = conn.processDelete(DN
+        .decode("dc=unindexed,dc=jeb"));
+    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
 

--
Gitblit v1.10.0