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

boli
02.34.2007 35b7b655f3a80e54a734bc3df6e2c71cade42ecb
Added privileges support for unindexed searches. Fixed issue where id2subtree and id2children indexes were not used when they should be. 
Added test cases for the unindexed search privilege.

Fix for issue 480.
7 files modified
211 ■■■■■ changed files
opends/resource/config/config.ldif 1 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/jeb/EntryContainer.java 32 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/messages/JebMessages.java 11 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/Privilege.java 13 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/resource/config-changes.ldif 40 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java 2 ●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java 112 ●●●●● patch | view | raw | blame | history
opends/resource/config/config.ldif
@@ -1235,6 +1235,7 @@
ds-cfg-default-root-privilege-name: update-schema
ds-cfg-default-root-privilege-name: privilege-change
ds-cfg-default-root-privilege-name: index-rebuild
ds-cfg-default-root-privilege-name: unindexed-search
dn: cn=Directory Manager,cn=Root DNs,cn=config
objectClass: top
opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -31,6 +31,7 @@
import org.opends.server.api.AttributeSyntax;
import org.opends.server.api.Backend;
import org.opends.server.api.EntryCache;
import org.opends.server.api.ClientConnection;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
@@ -43,22 +44,7 @@
import org.opends.server.controls.ServerSideSortRequestControl;
import org.opends.server.controls.ServerSideSortResponseControl;
import org.opends.server.controls.VLVRequestControl;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.CancelledOperationException;
import org.opends.server.types.Control;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.LDAPException;
import org.opends.server.types.LockType;
import org.opends.server.types.Modification;
import org.opends.server.types.Operation;
import org.opends.server.types.RDN;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchScope;
import org.opends.server.types.*;
import org.opends.server.util.StaticUtils;
import org.opends.server.util.ServerConstants;
@@ -720,8 +706,7 @@
    // Evaluate the search scope against the id2children and id2subtree indexes.
    boolean candidatesAreInScope = false;
    if (entryIDList.isDefined() &&
            entryIDList.size() > IndexFilter.FILTER_CANDIDATE_THRESHOLD)
    if (entryIDList.size() > IndexFilter.FILTER_CANDIDATE_THRESHOLD)
    {
      // Read the ID from dn2id.
      EntryID baseID = dn2id.get(null, baseDN);
@@ -820,6 +805,17 @@
    }
    else
    {
      ClientConnection clientConnection =
          searchOperation.getClientConnection();
      if(! clientConnection.hasPrivilege(Privilege.UNINDEXED_SEARCH,
                                         searchOperation))
      {
        int msgID = MSGID_JEB_SEARCH_UNINDEXED_INSUFFICIENT_PRIVILEGES;
        String message = getMessage(msgID);
        throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
                                     message, msgID);
      }
      if (sortRequest != null)
      {
        // FIXME -- Add support for sorting unindexed searches using indexes
opends/src/server/org/opends/server/messages/JebMessages.java
@@ -1143,6 +1143,14 @@
       CATEGORY_MASK_JEB | SEVERITY_MASK_MILD_ERROR | 144;
  /**
   * The message ID of an error indicating that unindexed searches are not
   * allowed without the unindexed search prilvilege. This does not take
   * any arguments.
   */
  public static final int MSGID_JEB_SEARCH_UNINDEXED_INSUFFICIENT_PRIVILEGES =
      CATEGORY_MASK_JEB | SEVERITY_MASK_MILD_ERROR | 145;
  /**
   * Associates a set of generic messages with the message IDs defined in this
   * class.
   */
@@ -1467,5 +1475,8 @@
                    "Unable to prcess the virtual list view request because " +
                    "no entry was found in the result set with a sort value " +
                    "greater than or equal to the provided assertion value");
    registerMessage(MSGID_JEB_SEARCH_UNINDEXED_INSUFFICIENT_PRIVILEGES,
                    "You do not have sufficient privileges to perform an " +
                    "unindexed search");
  }
}
opends/src/server/org/opends/server/types/Privilege.java
@@ -214,7 +214,15 @@
   * The privilege that provides the ability to rebuild one or more
   * indexes in a backend that supports indexing.
   */
  INDEX_REBUILD("index-rebuild");
  INDEX_REBUILD("index-rebuild"),
  /**
   * The privilege that provides the ability to perform an unindexed
   * search in the JE backend.
   */
  UNINDEXED_SEARCH("unindexed-search");
@@ -274,6 +282,7 @@
    PRIV_MAP.put("update-schema", UPDATE_SCHEMA);
    PRIV_MAP.put("privilege-change", PRIVILEGE_CHANGE);
    PRIV_MAP.put("index-rebuild", INDEX_REBUILD);
    PRIV_MAP.put("unindexed-search", UNINDEXED_SEARCH);
    PRIV_NAMES.add("bypass-acl");
    PRIV_NAMES.add("modify-acl");
@@ -297,6 +306,7 @@
    PRIV_NAMES.add("update-schema");
    PRIV_NAMES.add("privilege-change");
    PRIV_NAMES.add("index-rebuild");
    PRIV_NAMES.add("unindexed-search");
    DEFAULT_ROOT_PRIV_SET.add(BYPASS_ACL);
    DEFAULT_ROOT_PRIV_SET.add(MODIFY_ACL);
@@ -315,6 +325,7 @@
    DEFAULT_ROOT_PRIV_SET.add(UPDATE_SCHEMA);
    DEFAULT_ROOT_PRIV_SET.add(PRIVILEGE_CHANGE);
    DEFAULT_ROOT_PRIV_SET.add(INDEX_REBUILD);
    DEFAULT_ROOT_PRIV_SET.add(UNINDEXED_SEARCH);
  }
opends/tests/unit-tests-testng/resource/config-changes.ldif
@@ -338,6 +338,46 @@
replace: ds-cfg-override-severity
ds-cfg-override-severity: EXCEPTION=INFO
dn: ds-cfg-backend-id=unindexedRoot,cn=Backends,cn=config
changetype: add
objectClass: top
objectClass: ds-cfg-backend
objectClass: ds-cfg-je-backend
ds-cfg-backend-enabled: true
ds-cfg-backend-class: org.opends.server.backends.jeb.BackendImpl
ds-cfg-backend-id: unindexedRoot
ds-cfg-backend-writability-mode: enabled
ds-cfg-backend-base-dn: dc=unindexed,dc=jeb
ds-cfg-backend-directory: db_unindexed
ds-cfg-backend-mode: 700
ds-cfg-backend-index-entry-limit: 1
ds-cfg-backend-subtree-delete-size-limit: 100000
ds-cfg-backend-preload-time-limit: 0 seconds
ds-cfg-backend-import-temp-directory: importTmp
ds-cfg-backend-import-buffer-size: 256 megabytes
ds-cfg-backend-import-queue-size: 100
ds-cfg-backend-import-pass-size: 0
ds-cfg-backend-import-thread-count: 8
ds-cfg-backend-entries-compressed: false
ds-cfg-backend-deadlock-retry-limit: 10
dn: cn=Index,ds-cfg-backend-id=unindexedRoot,cn=Backends,cn=config
changetype: add
objectClass: top
objectClass: ds-cfg-branch
cn: Index
dn: ds-cfg-index-attribute=mail,cn=Index,ds-cfg-backend-id=unindexedRoot,cn=Backends,cn=config
changetype: add
objectClass: top
objectClass: ds-cfg-je-index
ds-cfg-index-attribute: mail
ds-cfg-index-type: presence
ds-cfg-index-type: equality
ds-cfg-index-type: substring
ds-cfg-index-type: ordering
ds-cfg-index-type: approximate
dn: ds-cfg-backend-id=rebuildRoot,cn=Backends,cn=config
changetype: add
objectClass: top
opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
@@ -190,7 +190,7 @@
    //db_rebuild is the third jeb backend used by the jeb rebuild test cases
    String[] subDirectories = { "bak", "bin", "changelogDb", "classes",
                                "config", "db", "db_verify", "ldif", "lib",
                                "locks", "logs", "db_rebuild",
                                "locks", "logs", "db_rebuild", "db_unindexed",
                                "db_index_test" };
    for (String s : subDirectories)
    {
opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
@@ -40,6 +40,7 @@
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
import static org.opends.server.util.StaticUtils.createEntry;
import org.opends.server.backends.task.Task;
import org.opends.server.backends.task.TaskBackend;
import org.opends.server.backends.task.TaskState;
@@ -134,6 +135,8 @@
      "ds-privilege-name: -ldif-export",
      "ds-privilege-name: -backend-backup",
      "ds-privilege-name: -backend-restore",
      "ds-privilege-name: -index-rebuild",
      "ds-privilege-name: -unindexed-search",
      "",
      "dn: cn=Proxy Root,cn=Root DNs,cn=config",
      "objectClass: top",
@@ -168,6 +171,8 @@
      "ds-privilege-name: backend-restore",
      "ds-privilege-name: proxied-auth",
      "ds-privilege-name: bypass-acl",
      "ds-privilege-name: index-rebuild",
      "ds-privilege-name: unindexed-search",
      "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," +
           "cn=Password Policies,cn=config",
      "",
@@ -250,6 +255,30 @@
      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"
    );
  }
@@ -333,6 +362,43 @@
    }
  }
  /**
   * Tests to ensure that unindexed search operations properly respect the
   * UNINDEXED_SEARCH 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 UNINDEXED_SEARCH privilege and therefore
   *                     the search should succeed.
   * @throws Exception If an unexpected problem occurs.
   */
  @Test(dataProvider = "testdata")
  public void testUnindexedSearch(InternalClientConnection conn,
                                  boolean hasPrivilege)
         throws Exception
  {
    assertEquals(conn.hasPrivilege(Privilege.UNINDEXED_SEARCH, null), hasPrivilege);
    for(DN dn : DirectoryServer.getBaseDNs().keySet())
    {
      System.out.println(dn.toString());
    }
    InternalSearchOperation searchOperation =
        conn.processSearch(DN.decode("dc=unindexed,dc=jeb"), SearchScope.WHOLE_SUBTREE,
             SearchFilter.createFilterFromString("(sn=test*)"));
    if (hasPrivilege)
    {
      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
    }
    else
    {
      assertEquals(searchOperation.getResultCode(),
                   ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
    }
  }
  /**
@@ -1016,6 +1082,52 @@
    }
  }
  /**
   * Test to ensure that attempts to rebuild indexes will property respect
   * the INDEX_REBUILD 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(InternalClientConnection conn,
                               boolean hasPrivilege)
      throws Exception
  {
    assertEquals(conn.hasPrivilege(Privilege.INDEX_REBUILD, 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);
    }
  }
  /**