From b4201ac0dae295d63110d97f5f3c411d450e142d Mon Sep 17 00:00:00 2001
From: boli <boli@localhost>
Date: Wed, 02 May 2007 00:34:04 +0000
Subject: [PATCH] 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.

---
 opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java                     |   32 +++----
 opendj-sdk/opends/src/server/org/opends/server/messages/JebMessages.java                            |   11 ++
 opendj-sdk/opends/resource/config/config.ldif                                                       |    1 
 opendj-sdk/opends/src/server/org/opends/server/types/Privilege.java                                 |   13 +++
 opendj-sdk/opends/tests/unit-tests-testng/resource/config-changes.ldif                              |   40 ++++++++++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java           |    2 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java |  112 ++++++++++++++++++++++++++++
 7 files changed, 191 insertions(+), 20 deletions(-)

diff --git a/opendj-sdk/opends/resource/config/config.ldif b/opendj-sdk/opends/resource/config/config.ldif
index 9f4ec56..6fa3c52 100644
--- a/opendj-sdk/opends/resource/config/config.ldif
+++ b/opendj-sdk/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
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
index 18eb18b..64bd468 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
+++ b/opendj-sdk/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
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/JebMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/JebMessages.java
index 4c68e21..037ddaa 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/JebMessages.java
+++ b/opendj-sdk/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");
   }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/Privilege.java b/opendj-sdk/opends/src/server/org/opends/server/types/Privilege.java
index 4b9dc7d..06cbb2a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/Privilege.java
+++ b/opendj-sdk/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);
   }
 
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/resource/config-changes.ldif b/opendj-sdk/opends/tests/unit-tests-testng/resource/config-changes.ldif
index dbd4763..df6788f 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/resource/config-changes.ldif
+++ b/opendj-sdk/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
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
index eecfbf9..6c13eb8 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
+++ b/opendj-sdk/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)
     {
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
index 9e1b04b..1f6f3f5 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
+++ b/opendj-sdk/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);
+    }
+  }
+
 
 
   /**

--
Gitblit v1.10.0