directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From elecha...@apache.org
Subject svn commit: r1485190 [2/2] - in /directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/authz: AutzIntegUtils.java SearchAuthorizationIT.java
Date Wed, 22 May 2013 12:36:06 GMT
Modified: directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/authz/SearchAuthorizationIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/authz/SearchAuthorizationIT.java?rev=1485190&r1=1485189&r2=1485190&view=diff
==============================================================================
--- directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/authz/SearchAuthorizationIT.java (original)
+++ directory/apacheds/trunk/core-integ/src/test/java/org/apache/directory/server/core/authz/SearchAuthorizationIT.java Wed May 22 12:36:06 2013
@@ -29,6 +29,7 @@ import static org.apache.directory.serve
 import static org.apache.directory.server.core.authz.AutzIntegUtils.deleteAccessControlSubentry;
 import static org.apache.directory.server.core.authz.AutzIntegUtils.getAdminConnection;
 import static org.apache.directory.server.core.authz.AutzIntegUtils.getConnectionAs;
+import static org.apache.directory.server.core.authz.AutzIntegUtils.removeEntryACI;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -51,6 +52,7 @@ import org.apache.directory.api.ldap.mod
 import org.apache.directory.api.ldap.model.message.SearchScope;
 import org.apache.directory.api.ldap.model.name.Dn;
 import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.server.core.annotations.ApplyLdifs;
 import org.apache.directory.server.core.annotations.CreateDS;
 import org.apache.directory.server.core.annotations.LoadSchema;
 import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
@@ -76,953 +78,848 @@ import org.junit.runner.RunWith;
     name = "SearchAuthorizationIT",
     loadedSchemas =
         { @LoadSchema(name = "nis", enabled = true) })
+@ApplyLdifs(
+    {
+        "dn: ou=tests,ou=system",
+        "objectclass: top",
+        "objectclass: organizationalUnit",
+        "ou: testEntry",
+        "ou: 0",
+        "ou: tests",
+        "telephonenumber: 1",
+        "",
+        "dn: ou=0,ou=tests,ou=system",
+        "objectclass: top",
+        "objectclass: organizationalUnit",
+        "ou: testEntry",
+        "ou: 0",
+        "telephonenumber: 3",
+        "",
+        "dn: ou=1,ou=tests,ou=system",
+        "objectclass: top",
+        "objectclass: organizationalUnit",
+        "ou: testEntry",
+        "ou: 1",
+        "telephonenumber: 3",
+        "",
+        "dn: ou=2,ou=tests,ou=system",
+        "objectclass: top",
+        "objectclass: organizationalUnit",
+        "ou: testEntry",
+        "ou: 2",
+        "telephonenumber: 3",
+        "",
+        "dn: ou=0,ou=0,ou=tests,ou=system",
+        "objectclass: top",
+        "objectclass: organizationalUnit",
+        "ou: testEntry",
+        "ou: 0",
+        "telephonenumber: 3",
+        "",
+        "dn: ou=1,ou=0,ou=tests,ou=system",
+        "objectclass: top",
+        "objectclass: organizationalUnit",
+        "ou: testEntry",
+        "ou: 1",
+        "telephonenumber: 3",
+        "",
+        "dn: ou=2,ou=0,ou=tests,ou=system",
+        "objectclass: top",
+        "objectclass: organizationalUnit",
+        "ou: testEntry",
+        "ou: 2",
+        "telephonenumber: 3",
+        "",
+        "dn: ou=0,ou=0,ou=0,ou=tests,ou=system",
+        "objectclass: top",
+        "objectclass: organizationalUnit",
+        "ou: testEntry",
+        "ou: 0",
+        "telephonenumber: 3",
+        "",
+        "dn: ou=1,ou=0,ou=0,ou=tests,ou=system",
+        "objectclass: top",
+        "objectclass: organizationalUnit",
+        "ou: testEntry",
+        "ou: 1",
+        "telephonenumber: 3",
+        "",
+        "dn: ou=2,ou=0,ou=0,ou=tests,ou=system",
+        "objectclass: top",
+        "objectclass: organizationalUnit",
+        "ou: testEntry",
+        "ou: 2",
+        "telephonenumber: 3"
+})
 public class SearchAuthorizationIT extends AbstractLdapTestUnit
 {
-    // to avoid creating too many connections during recursive operations
-    private LdapConnection reusableAdminCon;
+// to avoid creating too many connections during recursive operations
+private LdapConnection reusableAdminCon;
+
+
+@Before
+public void setService() throws Exception
+{
+    AutzIntegUtils.service = getService();
+    reusableAdminCon = getAdminConnection();
+}
+
+
+@After
+public void closeConnections()
+{
+    IntegrationUtils.closeConnections();
+}
+
+/**
+ * The search results of tests are added to this map via put (<String, Entry>)
+ * the map is also cleared before each search test.  This allows further inspections
+ * of the results for more specific test cases.
+ */
+private Map<String, Entry> results = new HashMap<String, Entry>();
 
 
-    @Before
-    public void setService() throws Exception
+/**
+ * Generates a set of simple organizationalUnit entries where the
+ * ou of the entry returned is the index of the entry in the array.
+ *
+ * @param count the number of entries to produce
+ * @return an array of entries with length = count
+ */
+private Entry[] getTestNodes( Dn base, final int count ) throws LdapException
+{
+    Entry[] entries = new DefaultEntry[count];
+
+    for ( int i = 0; i < count; i++ )
     {
-        AutzIntegUtils.service = getService();
-        reusableAdminCon = getAdminConnection();
+        Entry entry = new DefaultEntry(
+            base.toString(),
+            "ObjectClass: top",
+            "ObjectClass: organizationalUnit",
+            "ou: testEntry",
+            "ou", String.valueOf( i ),
+            "telephoneNumber", String.valueOf( count ) );
+
+        entries[i] = entry;
     }
 
+    return entries;
+}
+
 
-    @After
-    public void closeConnections()
+private void recursivelyAddSearchData( Dn parent, Entry[] children, final long sizeLimit, long[] count )
+    throws Exception
+{
+    Dn[] childRdns = new Dn[children.length];
+
+    for ( int i = 0; ( i < children.length ) && ( count[0] < sizeLimit ); i++ )
     {
-        IntegrationUtils.closeConnections();
+        Dn childRdn = new Dn();
+        childRdn = childRdn.add( parent );
+        childRdn = childRdn.add( "ou=" + i );
+        childRdns[i] = childRdn;
+        children[i].setDn( childRdn );
+        System.out.println( children[i] );
+        reusableAdminCon.add( children[i] );
+        count[0]++;
     }
 
-    /**
-     * The search results of tests are added to this map via put (<String, Entry>)
-     * the map is also cleared before each search test.  This allows further inspections
-     * of the results for more specific test cases.
-     */
-    private Map<String, Entry> results = new HashMap<String, Entry>();
-
-
-    /**
-     * Generates a set of simple organizationalUnit entries where the
-     * ou of the entry returned is the index of the entry in the array.
-     *
-     * @param count the number of entries to produce
-     * @return an array of entries with length = count
-     */
-    private Entry[] getTestNodes( Dn base, final int count ) throws LdapException
+    if ( count[0] >= sizeLimit )
     {
-        Entry[] entries = new DefaultEntry[count];
+        return;
+    }
 
-        for ( int i = 0; i < count; i++ )
-        {
-            Entry entry = new DefaultEntry(
-                base.toString(),
-                "ObjectClass: top",
-                "ObjectClass: organizationalUnit",
-                "ou: testEntry",
-                "ou", String.valueOf( i ),
-                "telephoneNumber", String.valueOf( count ) );
+    for ( int i = 0; ( i < children.length ) && ( count[0] < sizeLimit ); i++ )
+    {
+        recursivelyAddSearchData( childRdns[i], children, sizeLimit, count );
+    }
+}
 
-            entries[i] = entry;
-        }
 
-        return entries;
-    }
+/**
+ * Starts creating nodes under a parent with a set number of children.  First
+ * a single node is created under the parent.  Thereafter a number of children
+ * determined by the branchingFactor is added.  Until a sizeLimit is reached
+ * descendants are created this way in a breath first recursive descent.
+ *
+ * @param parent the parent under which the first node is created
+ * @param branchingFactor how to brach the data
+ * @param sizelimit the amount of entries 
+ * @return the immediate child node created under parent which contains the subtree
+ * @throws Exception on error
+ *
+private Dn addSearchData( Dn parent, int branchingFactor, long sizelimit ) throws Exception
+{
+    Dn base = new Dn( "ou=tests," + parent.getName() );
+    Entry entry = getTestNodes( base, 1 )[0];
+    entry.add( "ou", "tests" );
+
+    reusableAdminCon.add( entry );
+
+    recursivelyAddSearchData( base, getTestNodes( base, branchingFactor ), sizelimit, new long[]
+        { 1 } );
+    return base;
+}
 
 
-    private void recursivelyAddSearchData( Dn parent, Entry[] children, final long sizeLimit, long[] count )
-        throws Exception
+/**
+ * Recursively deletes all entries including the base specified.
+ *
+ * @param rdn the relative dn from ou=system of the entry to delete recursively
+ * @throws Exception if there are problems deleting entries
+ */
+private void recursivelyDelete( Dn rdn ) throws Exception
+{
+    EntryCursor entries = reusableAdminCon.search( rdn.getName(), "(objectClass=*)",
+        SearchScope.ONELEVEL, "*" );
+
+    while ( entries.next() )
     {
-        Dn[] childRdns = new Dn[children.length];
+        Entry entry = entries.get();
+        Dn childRdn = entry.getDn();
 
-        for ( int i = 0; ( i < children.length ) && ( count[0] < sizeLimit ); i++ )
-        {
-            Dn childRdn = new Dn();
-            childRdn = childRdn.add( parent );
-            childRdn = childRdn.add( "ou=" + i );
-            childRdns[i] = childRdn;
-            children[i].setDn( childRdn );
-            reusableAdminCon.add( children[i] );
-            count[0]++;
-        }
-
-        if ( count[0] >= sizeLimit )
-        {
-            return;
-        }
-
-        for ( int i = 0; ( i < children.length ) && ( count[0] < sizeLimit ); i++ )
-        {
-            recursivelyAddSearchData( childRdns[i], children, sizeLimit, count );
-        }
+        recursivelyDelete( childRdn );
     }
 
+    entries.close();
 
-    /**
-     * Starts creating nodes under a parent with a set number of children.  First
-     * a single node is created under the parent.  Thereafter a number of children
-     * determined by the branchingFactor is added.  Until a sizeLimit is reached
-     * descendants are created this way in a breath first recursive descent.
-     *
-     * @param parent the parent under which the first node is created
-     * @param branchingFactor how to brach the data
-     * @param sizelimit the amount of entries 
-     * @return the immediate child node created under parent which contains the subtree
-     * @throws Exception on error
-     */
-    private Dn addSearchData( Dn parent, int branchingFactor, long sizelimit ) throws Exception
-    {
-        Dn base = new Dn( "ou=tests," + parent.getName() );
-        Entry entry = getTestNodes( base, 1 )[0];
-        entry.add( "ou", "tests" );
-
-        reusableAdminCon.add( entry );
-
-        recursivelyAddSearchData( base, getTestNodes( base, branchingFactor ), sizelimit, new long[]
-            { 1 } );
-        return base;
-    }
+    reusableAdminCon.delete( rdn );
+}
 
 
-    /**
-     * Recursively deletes all entries including the base specified.
-     *
-     * @param rdn the relative dn from ou=system of the entry to delete recursively
-     * @throws Exception if there are problems deleting entries
-     */
-    private void recursivelyDelete( Dn rdn ) throws Exception
-    {
-        EntryCursor entries = reusableAdminCon.search( rdn.getName(), "(objectClass=*)",
-            SearchScope.ONELEVEL, "*" );
+/**
+ * Performs a single level search as a specific user on newly created data and checks
+ * that result set count is 3.  The basic (objectClass=*) filter is used.
+ *
+ * @param uid the uid Rdn attribute value for the user under ou=users,ou=system
+ * @param password the password of the user
+ * @return true if the search succeeds as expected, false otherwise
+ * @throws Exception if there are problems conducting the search
+ */
+private boolean checkCanSearchAs( String uid, String password ) throws Exception
+{
+    return checkCanSearchAs( uid, password, "(objectClass=*)", SearchScope.ONELEVEL, 3 );
+}
 
-        while ( entries.next() )
-        {
-            Entry entry = entries.get();
-            Dn childRdn = entry.getDn();
 
-            recursivelyDelete( childRdn );
-        }
+/**
+ * Performs a single level search as a specific user on newly created data and checks
+ * that result set count is equal to a user specified amount.  The basic
+ * (objectClass=*) filter is used.
+ *
+ * @param uid the uid Rdn attribute value for the user under ou=users,ou=system
+ * @param password the password of the user
+ * @param resultSetSz the expected size of the results
+ * @return true if the search succeeds as expected, false otherwise
+ * @throws Exception if there are problems conducting the search
+ */
+private boolean checkCanSearchAs( String uid, String password, int resultSetSz ) throws Exception
+{
+    return checkCanSearchAs( uid, password, "(objectClass=*)", SearchScope.ONELEVEL, resultSetSz );
+}
 
-        entries.close();
 
-        reusableAdminCon.delete( rdn );
-    }
+/**
+ * Performs a search as a specific user on newly created data and checks
+ * that result set count is equal to a user specified amount.  The basic
+ * (objectClass=*) filter is used.
+ *
+ * @param uid the uid Rdn attribute value for the user under ou=users,ou=system
+ * @param password the password of the user
+ * @param scope search controls
+ * @param resultSetSz the expected size of the results
+ * @return true if the search succeeds as expected, false otherwise
+ * @throws Exception if there are problems conducting the search
+ */
+private boolean checkCanSearchAs( String uid, String password, SearchScope scope, int resultSetSz )
+    throws Exception
+{
+    return checkCanSearchAs( uid, password, "(objectClass=*)", scope, resultSetSz );
+}
 
 
-    /**
-     * Performs a single level search as a specific user on newly created data and checks
-     * that result set count is 3.  The basic (objectClass=*) filter is used.
-     *
-     * @param uid the uid Rdn attribute value for the user under ou=users,ou=system
-     * @param password the password of the user
-     * @return true if the search succeeds as expected, false otherwise
-     * @throws Exception if there are problems conducting the search
-     */
-    private boolean checkCanSearchAs( String uid, String password ) throws Exception
-    {
-        return checkCanSearchAs( uid, password, "(objectClass=*)", SearchScope.ONELEVEL, 3 );
-    }
+/**
+ * Performs a search as a specific user on newly created data and checks
+ * that result set count is equal to a user specified amount.
+ *
+ * @param uid the uid Rdn attribute value for the user under ou=users,ou=system
+ * @param password the password of the user
+ * @param filter the search filter to use
+ * @param scope search scope
+ * @param resultSetSz the expected size of the results
+ * @return true if the search succeeds as expected, false otherwise
+ * @throws Exception if there are problems conducting the search
+ */
+private boolean checkCanSearchAs( String uid, String password, String filter, SearchScope scope, int resultSetSz )
+    throws Exception
+{
 
+    Dn base = new Dn( "ou=tests,ou=system" );
+    Dn userDn = new Dn( "uid=" + uid + ",ou=users,ou=system" );
+    results.clear();
+    LdapConnection userCtx = getConnectionAs( userDn, password );
+    EntryCursor cursor = userCtx.search( base.getName(), filter, scope, "*" );
+    int counter = 0;
 
-    /**
-     * Performs a single level search as a specific user on newly created data and checks
-     * that result set count is equal to a user specified amount.  The basic
-     * (objectClass=*) filter is used.
-     *
-     * @param uid the uid Rdn attribute value for the user under ou=users,ou=system
-     * @param password the password of the user
-     * @param resultSetSz the expected size of the results
-     * @return true if the search succeeds as expected, false otherwise
-     * @throws Exception if there are problems conducting the search
-     */
-    private boolean checkCanSearchAs( String uid, String password, int resultSetSz ) throws Exception
+    while ( cursor.next() )
     {
-        return checkCanSearchAs( uid, password, "(objectClass=*)", SearchScope.ONELEVEL, resultSetSz );
+        Entry result = cursor.get();
+        results.put( result.getDn().getName(), result );
+        counter++;
     }
 
+    cursor.close();
+
+    //recursivelyDelete( base );
 
-    /**
-     * Performs a search as a specific user on newly created data and checks
-     * that result set count is equal to a user specified amount.  The basic
-     * (objectClass=*) filter is used.
-     *
-     * @param uid the uid Rdn attribute value for the user under ou=users,ou=system
-     * @param password the password of the user
-     * @param scope search controls
-     * @param resultSetSz the expected size of the results
-     * @return true if the search succeeds as expected, false otherwise
-     * @throws Exception if there are problems conducting the search
-     */
-    private boolean checkCanSearchAs( String uid, String password, SearchScope scope, int resultSetSz )
-        throws Exception
+    return counter == resultSetSz;
+}
+
+
+/**
+ * Adds an entryACI to specified entry below ou=system and runs a search.  Then it
+ * checks to see the result size is correct.
+ *
+ * @param uid the uid Rdn attribute value for the user under ou=users,ou=system
+ * @param password the password of the user
+ * @param scope the search controls
+ * @param dn the rdn
+ * @param aci the aci
+ * @param resultSetSz the result sz
+ * @return true if the search succeeds as expected, false otherwise
+ * @throws Exception if there are problems conducting the search
+ */
+private boolean checkSearchAsWithEntryACI( String uid, String password, SearchScope scope, Dn dn, String aci,
+    int resultSetSz ) throws Exception
+{
+    Dn base = new Dn( "ou=tests,ou=system" );
+    addEntryACI( base, aci );
+    Dn userDn = new Dn( "uid=" + uid + ",ou=users,ou=system" );
+
+    results.clear();
+    LdapConnection userCtx = getConnectionAs( userDn, password );
+    EntryCursor cursor = userCtx.search( base.getName(), "(objectClass=*)", scope, "*" );
+    int counter = 0;
+
+    while ( cursor.next() )
     {
-        return checkCanSearchAs( uid, password, "(objectClass=*)", scope, resultSetSz );
+        Entry result = cursor.get();
+        results.put( result.getDn().getName(), result );
+        counter++;
     }
 
+    cursor.close();
 
-    /**
-     * Performs a search as a specific user on newly created data and checks
-     * that result set count is equal to a user specified amount.
-     *
-     * @param uid the uid Rdn attribute value for the user under ou=users,ou=system
-     * @param password the password of the user
-     * @param filter the search filter to use
-     * @param scope search scope
-     * @param resultSetSz the expected size of the results
-     * @return true if the search succeeds as expected, false otherwise
-     * @throws Exception if there are problems conducting the search
-     */
-    private boolean checkCanSearchAs( String uid, String password, String filter, SearchScope scope, int resultSetSz )
-        throws Exception
-    {
+    removeEntryACI( base );
 
-        Dn base = addSearchData( new Dn( "ou=system" ), 3, 10 );
-        Dn userDn = new Dn( "uid=" + uid + ",ou=users,ou=system" );
-        results.clear();
-        LdapConnection userCtx = getConnectionAs( userDn, password );
-        EntryCursor cursor = userCtx.search( base.getName(), filter, scope, "*" );
-        int counter = 0;
-
-        while ( cursor.next() )
-        {
-            Entry result = cursor.get();
-            results.put( result.getDn().getName(), result );
-            counter++;
-        }
+    //recursivelyDelete( base );
 
-        cursor.close();
+    return counter == resultSetSz;
+}
 
-        recursivelyDelete( base );
 
-        return counter == resultSetSz;
-    }
+/**
+ * Checks to see that the addSearchData() and the recursiveDelete()
+ * functions in this test work properly.
+ *
+ * @throws Exception if there is a problem with the implementation of
+ * these utility functions
+ */
+@Test
+public void testAddSearchData() throws Exception
+{
+    LdapConnection connection = getAdminConnection();
+    Dn base = new Dn( "ou=tests,ou=system" );
 
+    EntryCursor entries = connection.search( base.getName(), "(objectClass=*)", SearchScope.SUBTREE,
+        "+" );
+    int counter = 0;
 
-    /**
-     * Adds an entryACI to specified entry below ou=system and runs a search.  Then it
-     * checks to see the result size is correct.
-     *
-     * @param uid the uid Rdn attribute value for the user under ou=users,ou=system
-     * @param password the password of the user
-     * @param scope the search controls
-     * @param dn the rdn
-     * @param aci the aci
-     * @param resultSetSz the result sz
-     * @return true if the search succeeds as expected, false otherwise
-     * @throws Exception if there are problems conducting the search
-     */
-    private boolean checkSearchAsWithEntryACI( String uid, String password, SearchScope scope, Dn dn, String aci,
-        int resultSetSz ) throws Exception
+    while ( entries.next() )
     {
-        Dn base = addSearchData( dn, 3, 10 );
-        addEntryACI( base, aci );
-        Dn userDn = new Dn( "uid=" + uid + ",ou=users,ou=system" );
-
-        results.clear();
-        LdapConnection userCtx = getConnectionAs( userDn, password );
-        EntryCursor cursor = userCtx.search( base.getName(), "(objectClass=*)", scope, "*" );
-        int counter = 0;
-
-        while ( cursor.next() )
-        {
-            Entry result = cursor.get();
-            results.put( result.getDn().getName(), result );
-            counter++;
-        }
-
-        cursor.close();
+        entries.get();
+        counter++;
+    }
 
-        recursivelyDelete( base );
+    entries.close();
 
-        return counter == resultSetSz;
-    }
+    assertEquals( 10, counter );
+    recursivelyDelete( base );
 
+    Entry entry = connection.lookup( base.getName() );
+    assertNull( entry );
+}
 
-    /**
-     * Checks to see that the addSearchData() and the recursiveDelete()
-     * functions in this test work properly.
-     *
-     * @throws Exception if there is a problem with the implementation of
-     * these utility functions
-     */
-    @Test
-    public void testAddSearchData() throws Exception
-    {
-        LdapConnection connection = getAdminConnection();
-        Dn base = addSearchData( new Dn( "ou=system" ), 3, 10 );
 
-        EntryCursor entries = connection.search( base.getName(), "(objectClass=*)", SearchScope.SUBTREE,
-            "+" );
-        int counter = 0;
-
-        while ( entries.next() )
-        {
-            entries.get();
-            counter++;
-        }
+// -----------------------------------------------------------------------
+// All or nothing search ACI rule tests
+// -----------------------------------------------------------------------
 
-        entries.close();
+/**
+ * Checks to make sure group membership based userClass works for add operations.
+ *
+ * @throws Exception if the test encounters an error
+ */
+@Test
+public void testGrantAdministrators() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
 
-        assertEquals( 10, counter );
-        recursivelyDelete( base );
+    // try a search operation which should fail without any ACI
+    assertFalse( checkCanSearchAs( "billyd", "billyd" ) );
 
-        Entry entry = connection.lookup( base.getName() );
-        assertNull( entry );
-    }
+    // Gives search perms to all users in the Administrators group for
+    // entries and all attribute types and values
+    createAccessControlSubentry( "searchAdmin",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses " +
+            "    { " +
+            "      userGroup { \"cn=Administrators,ou=groups,ou=system\" } " +
+            "    }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
 
+    // see if we can now search that test entry which we could not before
+    // add or should still fail since billd is not in the admin group
+    assertFalse( checkCanSearchAs( "billyd", "billyd" ) );
 
-    // -----------------------------------------------------------------------
-    // All or nothing search ACI rule tests
-    // -----------------------------------------------------------------------
-
-    /**
-     * Checks to make sure group membership based userClass works for add operations.
-     *
-     * @throws Exception if the test encounters an error
-     */
-    @Test
-    public void testGrantAdministrators() throws Exception
-    {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
+    // now add billyd to the Administrator group and try again
+    addUserToGroup( "billyd", "Administrators" );
 
-        // try a search operation which should fail without any ACI
-        assertFalse( checkCanSearchAs( "billyd", "billyd" ) );
+    // try a search operation which should succeed with ACI and group membership change
+    assertTrue( checkCanSearchAs( "billyd", "billyd" ) );
+}
 
-        // Gives search perms to all users in the Administrators group for
-        // entries and all attribute types and values
-        createAccessControlSubentry( "searchAdmin",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses " +
-                "    { " +
-                "      userGroup { \"cn=Administrators,ou=groups,ou=system\" } " +
-                "    }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
-
-        // see if we can now search that test entry which we could not before
-        // add or should still fail since billd is not in the admin group
-        assertFalse( checkCanSearchAs( "billyd", "billyd" ) );
 
-        // now add billyd to the Administrator group and try again
-        addUserToGroup( "billyd", "Administrators" );
+/**
+ * Checks to make sure name based userClass works for search operations.
+ *
+ * @throws Exception if the test encounters an error
+ */
+@Test
+public void testGrantSearchByName() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
 
-        // try a search operation which should succeed with ACI and group membership change
-        assertTrue( checkCanSearchAs( "billyd", "billyd" ) );
-    }
+    // try a search operation which should fail without any ACI
+    assertFalse( checkCanSearchAs( "billyd", "billyd" ) );
 
+    // now add a subentry that enables user billyd to search an entry below ou=system
+    createAccessControlSubentry( "billydSearch",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses " +
+            "    { " +
+            "      name { \"uid=billyd,ou=users,ou=system\" } " +
+            "    }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    }" +
+            "  } " +
+            "}" );
 
-    /**
-     * Checks to make sure name based userClass works for search operations.
-     *
-     * @throws Exception if the test encounters an error
-     */
-    @Test
-    public void testGrantSearchByName() throws Exception
-    {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
+    // should work now that billyd is authorized by name
+    assertTrue( checkCanSearchAs( "billyd", "billyd" ) );
+}
 
-        // try a search operation which should fail without any ACI
-        assertFalse( checkCanSearchAs( "billyd", "billyd" ) );
 
-        // now add a subentry that enables user billyd to search an entry below ou=system
-        createAccessControlSubentry( "billydSearch",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses " +
-                "    { " +
-                "      name { \"uid=billyd,ou=users,ou=system\" } " +
-                "    }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    }" +
-                "  } " +
-                "}" );
+/**
+ * Checks to make sure name based userClass works for search operations
+ * when we vary the case of the Dn.
+ *
+ * @throws Exception if the test encounters an error
+ */
+@Test
+public void testGrantSearchByNameUserDnCase() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
 
-        // should work now that billyd is authorized by name
-        assertTrue( checkCanSearchAs( "billyd", "billyd" ) );
-    }
+    // try a search operation which should fail without any ACI
+    assertFalse( checkCanSearchAs( "BillyD", "billyd" ) );
 
+    // now add a subentry that enables user billyd to search an entry below ou=system
+    createAccessControlSubentry( "billydSearch",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses " +
+            "    { " +
+            "      name { \"uid=billyd,ou=users,ou=system\" } " +
+            "    }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
 
-    /**
-     * Checks to make sure name based userClass works for search operations
-     * when we vary the case of the Dn.
-     *
-     * @throws Exception if the test encounters an error
-     */
-    @Test
-    public void testGrantSearchByNameUserDnCase() throws Exception
-    {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
+    // should work now that billyd is authorized by name
+    assertTrue( checkCanSearchAs( "BillyD", "billyd" ) );
+}
 
-        // try a search operation which should fail without any ACI
-        assertFalse( checkCanSearchAs( "BillyD", "billyd" ) );
 
-        // now add a subentry that enables user billyd to search an entry below ou=system
-        createAccessControlSubentry( "billydSearch",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses " +
-                "    { " +
-                "      name { \"uid=billyd,ou=users,ou=system\" } " +
-                "    }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
+/**
+ * Checks to make sure subtree based userClass works for search operations.
+ *
+ * @throws Exception if the test encounters an error
+ */
+@Test
+public void testGrantSearchBySubtree() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
 
-        // should work now that billyd is authorized by name
-        assertTrue( checkCanSearchAs( "BillyD", "billyd" ) );
-    }
+    // try a search operation which should fail without any ACI
+    assertFalse( checkCanSearchAs( "billyd", "billyd" ) );
 
+    // now add a subentry that enables user billyd to search an entry below ou=system
+    createAccessControlSubentry( "billySearchBySubtree",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses " +
+            "    { " +
+            "      subtree " +
+            "      { " +
+            "        { base \"ou=users,ou=system\" } " +
+            "      } " +
+            "    }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials {  grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
 
-    /**
-     * Checks to make sure subtree based userClass works for search operations.
-     *
-     * @throws Exception if the test encounters an error
-     */
-    @Test
-    public void testGrantSearchBySubtree() throws Exception
-    {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
+    // should work now that billyd is authorized by the subtree userClass
+    assertTrue( checkCanSearchAs( "billyd", "billyd" ) );
+}
 
-        // try a search operation which should fail without any ACI
-        assertFalse( checkCanSearchAs( "billyd", "billyd" ) );
 
-        // now add a subentry that enables user billyd to search an entry below ou=system
-        createAccessControlSubentry( "billySearchBySubtree",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses " +
-                "    { " +
-                "      subtree " +
-                "      { " +
-                "        { base \"ou=users,ou=system\" } " +
-                "      } " +
-                "    }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials {  grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
+/**
+ * Checks to make sure <b>allUsers</b> userClass works for search operations.
+ *
+ * @throws Exception if the test encounters an error
+ */
+@Test
+public void testGrantSearchAllUsers() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
 
-        // should work now that billyd is authorized by the subtree userClass
-        assertTrue( checkCanSearchAs( "billyd", "billyd" ) );
-    }
+    // try a search operation which should fail without any ACI
+    assertFalse( checkCanSearchAs( "billyd", "billyd" ) );
 
+    // now add a subentry that enables anyone to search an entry below ou=system
+    createAccessControlSubentry( "anybodySearch",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
 
-    /**
-     * Checks to make sure <b>allUsers</b> userClass works for search operations.
-     *
-     * @throws Exception if the test encounters an error
-     */
-    @Test
-    public void testGrantSearchAllUsers() throws Exception
-    {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
+    // see if we can now search that tree which we could not before
+    // should work now with billyd now that all users are authorized
+    assertTrue( checkCanSearchAs( "billyd", "billyd" ) );
+}
 
-        // try a search operation which should fail without any ACI
-        assertFalse( checkCanSearchAs( "billyd", "billyd" ) );
 
-        // now add a subentry that enables anyone to search an entry below ou=system
-        createAccessControlSubentry( "anybodySearch",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
-
-        // see if we can now search that tree which we could not before
-        // should work now with billyd now that all users are authorized
-        assertTrue( checkCanSearchAs( "billyd", "billyd" ) );
-    }
+// -----------------------------------------------------------------------
+//
+// -----------------------------------------------------------------------
 
+/**
+ * Checks to make sure search does not return entries not assigned the
+ * perscriptiveACI and that it does not fail with an exception.
+ *
+ * @throws Exception if the test encounters an error
+ */
+@Test
+public void testSelectiveGrantsAllUsers() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
 
-    // -----------------------------------------------------------------------
-    //
-    // -----------------------------------------------------------------------
-
-    /**
-     * Checks to make sure search does not return entries not assigned the
-     * perscriptiveACI and that it does not fail with an exception.
-     *
-     * @throws Exception if the test encounters an error
-     */
-    @Test
-    public void testSelectiveGrantsAllUsers() throws Exception
-    {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
+    // try a search operation which should fail without any ACI
+    assertFalse( checkCanSearchAs( "billyd", "billyd", SearchScope.SUBTREE, 4 ) );
 
-        // try a search operation which should fail without any ACI
-        assertFalse( checkCanSearchAs( "billyd", "billyd", SearchScope.SUBTREE, 4 ) );
+    // now add a subentry that enables anyone to search an entry below ou=system
+    // down two more rdns for DNs of a max size of 3
+    createAccessControlSubentry( "anybodySearch", "{ maximum 2 }",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
 
-        // now add a subentry that enables anyone to search an entry below ou=system
-        // down two more rdns for DNs of a max size of 3
-        createAccessControlSubentry( "anybodySearch", "{ maximum 2 }",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
-
-        // see if we can now search that test entry which we could not before
-        // should work now with billyd now that all users are authorized
-        assertTrue( checkCanSearchAs( "billyd", "billyd", SearchScope.SUBTREE, 4 ) );
-    }
+    // see if we can now search that test entry which we could not before
+    // should work now with billyd now that all users are authorized
+    assertTrue( checkCanSearchAs( "billyd", "billyd", SearchScope.SUBTREE, 4 ) );
+}
 
 
-    /**
-     * Checks to make sure attributeTypes are not present when permissions are
-     * not given for reading them and their values.
-     *
-     * @throws Exception if the test encounters an error
-     */
-    @Test
-    public void testHidingAttributes() throws Exception
-    {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
+/**
+ * Checks to make sure attributeTypes are not present when permissions are
+ * not given for reading them and their values.
+ *
+ * @throws Exception if the test encounters an error
+ */
+@Test
+public void testHidingAttributes() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
 
-        // try a search operation which should fail without any ACI
-        assertFalse( checkCanSearchAs( "billyd", "billyd", SearchScope.SUBTREE, 4 ) );
+    // try a search operation which should fail without any ACI
+    assertFalse( checkCanSearchAs( "billyd", "billyd", SearchScope.SUBTREE, 4 ) );
 
-        // now add a subentry that enables anyone to search an entry below ou=system
-        // down two more rdns for DNs of a max size of 3.  It only grants access to
-        // the ou and objectClass attributes however.
-        createAccessControlSubentry( "excludeTelephoneNumber", "{ maximum 2 }",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allAttributeValues { ou, objectClass } }, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
-
-        // see if we can now search and find 4 entries
-        assertTrue( checkCanSearchAs( "billyd", "billyd", SearchScope.SUBTREE, 4 ) );
-
-        // check to make sure the telephoneNumber attribute is not present in results
-        for ( Entry result : results.values() )
-        {
-            assertNull( result.get( "telephoneNumber" ) );
-        }
-
-        // delete the subentry to test more general rule's inclusion of telephoneNumber
-        deleteAccessControlSubentry( "excludeTelephoneNumber" );
-
-        // now add a subentry that enables anyone to search an entry below ou=system
-        // down two more rdns for DNs of a max size of 3.  This time we should be able
-        // to see the telephoneNumber attribute
-        createAccessControlSubentry( "includeAllAttributeTypesAndValues", "{ maximum 2 }",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues }, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    }" +
-                "  } " +
-                "}" );
-
-        // again we should find four entries
-        assertTrue( checkCanSearchAs( "billyd", "billyd", SearchScope.SUBTREE, 4 ) );
-
-        // check now to make sure the telephoneNumber attribute is present in results
-        for ( Entry result : results.values() )
-        {
-            assertNotNull( result.get( "telephoneNumber" ) );
-        }
-    }
+    // now add a subentry that enables anyone to search an entry below ou=system
+    // down two more rdns for DNs of a max size of 3.  It only grants access to
+    // the ou and objectClass attributes however.
+    createAccessControlSubentry( "excludeTelephoneNumber", "{ maximum 2 }",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allAttributeValues { ou, objectClass } }, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
 
+    // see if we can now search and find 4 entries
+    assertTrue( checkCanSearchAs( "billyd", "billyd", SearchScope.SUBTREE, 4 ) );
 
-    /**
-     * Checks to make sure specific attribute values are not present when
-     * read permission is denied.
-     *
-     * @throws Exception if the test encounters an error
-     */
-    @Test
-    public void testHidingAttributeValues() throws Exception
+    // check to make sure the telephoneNumber attribute is not present in results
+    for ( Entry result : results.values() )
     {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
+        assertNull( result.get( "telephoneNumber" ) );
+    }
 
-        // try a search operation which should fail without any ACI
-        assertFalse( checkCanSearchAs( "billyd", "billyd", 3 ) );
+    // delete the subentry to test more general rule's inclusion of telephoneNumber
+    deleteAccessControlSubentry( "excludeTelephoneNumber" );
 
-        // now add a subentry that enables anyone to search an entry below ou=system
-        // down two more rdns for DNs of a max size of 3.  It only grants access to
-        // the ou and objectClass attributes however.
-        createAccessControlSubentry( "excludeOUValue", "{ maximum 2 }",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems " +
-                "        {" +
-                "          entry, " +
-                "          attributeType { ou }, " +
-                "          allAttributeValues { objectClass }, " +
-                "          attributeValue { ou=0, ou=1, ou=2 } " +
-                "        }, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
-
-        // see if we can now search and find 4 entries
-        assertTrue( checkCanSearchAs( "billyd", "billyd", 3 ) );
-
-        // check to make sure the ou attribute value "testEntry" is not present in results
-        for ( Entry result : results.values() )
-        {
-            assertFalse( result.get( "ou" ).contains( "testEntry" ) );
-        }
-
-        // delete the subentry to test more general rule's inclusion of all values
-        deleteAccessControlSubentry( "excludeOUValue" );
-
-        // now add a subentry that enables anyone to search an entry below ou=system
-        // down two more rdns for DNs of a max size of 3.  This time we should be able
-        // to see the telephoneNumber attribute
-        createAccessControlSubentry( "includeAllAttributeTypesAndValues", "{ maximum 2 }",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues }, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  }" +
-                "}" );
-
-        // again we should find four entries
-        assertTrue( checkCanSearchAs( "billyd", "billyd", 3 ) );
-
-        // check now to make sure the telephoneNumber attribute is present in results
-        for ( Entry result : results.values() )
-        {
-            assertTrue( result.get( "ou" ).contains( "testEntry" ) );
-        }
-    }
+    // now add a subentry that enables anyone to search an entry below ou=system
+    // down two more rdns for DNs of a max size of 3.  This time we should be able
+    // to see the telephoneNumber attribute
+    createAccessControlSubentry( "includeAllAttributeTypesAndValues", "{ maximum 2 }",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues }, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    }" +
+            "  } " +
+            "}" );
 
+    // again we should find four entries
+    assertTrue( checkCanSearchAs( "billyd", "billyd", SearchScope.SUBTREE, 4 ) );
 
-    /**
-     * Adds a perscriptiveACI to allow search, tests for success, then adds entryACI
-     * to deny read, browse and returnDN to a specific entry and checks to make sure
-     * that entry cannot be accessed via search as a specific user.
-     *
-     * @throws Exception if the test is broken
-     */
-    @Test
-    public void testPerscriptiveGrantWithEntryDenial() throws Exception
+    // check now to make sure the telephoneNumber attribute is present in results
+    for ( Entry result : results.values() )
     {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
-
-        // now add an entryACI denies browse, read and returnDN to a specific entry
-        String aci =
-            "{ " +
-                "  identificationTag \"denyAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { denyRead, denyReturnDN, denyBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}";
-
-        // try a search operation which should fail without any prescriptive ACI
-        Dn testsDn = new Dn( "ou=system" );
-
-        assertFalse( checkSearchAsWithEntryACI( "billyd", "billyd", SearchScope.SUBTREE, testsDn, aci, 9 ) );
-
-        // now add a subentry that enables anyone to search below ou=system
-        createAccessControlSubentry( "anybodySearch",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
-
-        // see if we can now search the tree which we could not before
-        // should work with billyd now that all users are authorized
-        // we should NOT see the entry we are about to deny access to
-        assertTrue( checkSearchAsWithEntryACI( "billyd", "billyd", SearchScope.SUBTREE, testsDn, aci, 9 ) );
-        assertNull( results.get( "ou=tests,ou=system" ) );
-
-        // try without the entry ACI, just perscriptive and see ou=tests,ou=system
-        assertTrue( checkCanSearchAs( "billyd", "billyd", SearchScope.SUBTREE, 10 ) );
-        assertNotNull( results.get( "ou=tests,ou=system" ) );
+        assertNotNull( result.get( "telephoneNumber" ) );
     }
+}
 
 
-    /**
-     * Adds a perscriptiveACI to allow search, tests for success, then adds entryACI
-     * to deny read, browse and returnDN to a specific entry and checks to make sure
-     * that entry cannot be accessed via search as a specific user.  Here the
-     * precidence of the ACI is put to the test.
-     *
-     * @throws Exception if the test is broken
-     */
-    @Test
-    public void testPerscriptiveGrantWithEntryDenialWithPrecidence() throws Exception
-    {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
+/**
+ * Checks to make sure specific attribute values are not present when
+ * read permission is denied.
+ *
+ * @throws Exception if the test encounters an error
+ */
+@Test
+public void testHidingAttributeValues() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
 
-        // now add an entryACI denying browse, read and returnDN to a specific entry
-        String aci =
-            "{ " +
-                "  identificationTag \"denyAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { denyRead, denyReturnDN, denyBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}";
-
-        // try a search operation which should fail without any prescriptive ACI
-        Dn testsDn = new Dn( "ou=system" );
-
-        assertFalse( checkSearchAsWithEntryACI( "billyd", "billyd", SearchScope.SUBTREE, testsDn, aci, 9 ) );
-
-        // now add a subentry that enables anyone to search below ou=system
-        createAccessControlSubentry( "anybodySearch",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 15, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
-
-        // see if we can now search the tree which we could not before
-        // should work with billyd now that all users are authorized
-        // we should also see the entry we are about to deny access to
-        // we see it because the precidence of the grant is greater
-        // than the precedence of the denial
-        assertTrue( checkSearchAsWithEntryACI( "billyd", "billyd", SearchScope.SUBTREE, testsDn, aci, 10 ) );
-        assertNotNull( results.get( "ou=tests,ou=system" ) );
-
-        // now add an entryACI denies browse, read and returnDN to a specific entry
-        // but this time the precedence will be higher than that of the grant
-        aci =
-            "{ " +
-                "  identificationTag \"denyAci\", " +
-                "  precedence 16, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " + "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { denyRead, denyReturnDN, denyBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}";
-
-        // see if we can now search the tree which we could not before
-        // should work with billyd now that all users are authorized
-        // we should NOT see the entry we are about to deny access to
-        // we do NOT see it because the precidence of the grant is less
-        // than the precedence of the denial - so the denial wins
-        assertTrue( checkSearchAsWithEntryACI( "billyd", "billyd", SearchScope.SUBTREE, testsDn, aci, 9 ) );
-        assertNull( results.get( "ou=tests,ou=system" ) );
-    }
+    // try a search operation which should fail without any ACI
+    assertFalse( checkCanSearchAs( "billyd", "billyd", 3 ) );
+
+    // now add a subentry that enables anyone to search an entry below ou=system
+    // down two more rdns for DNs of a max size of 3.  It only grants access to
+    // the ou and objectClass attributes however.
+    createAccessControlSubentry( "excludeOUValue", "{ maximum 2 }",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems " +
+            "        {" +
+            "          entry, " +
+            "          attributeType { ou }, " +
+            "          allAttributeValues { objectClass }, " +
+            "          attributeValue { ou=0, ou=1, ou=2 } " +
+            "        }, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
 
+    // see if we can now search and find 4 entries
+    assertTrue( checkCanSearchAs( "billyd", "billyd", 3 ) );
 
-    /**
-     * Performs an object level search on the specified subentry relative to ou=system as a specific user.
-     *
-     * @param uid the uid Rdn attribute value of the user to perform the search as
-     * @param password the password of the user
-     * @param dn the relative name to the subentry under the ou=system AP
-     * @return the single search result if access is allowed or null
-     * @throws Exception if the search fails w/ exception other than no permission
-     */
-    private Entry checkCanSearchSubentryAs( String uid, String password, Dn dn ) throws Exception
+    // check to make sure the ou attribute value "testEntry" is not present in results
+    for ( Entry result : results.values() )
     {
-        LdapConnection userCtx = getConnectionAs( new Dn( "uid=" + uid + ",ou=users,ou=system" ), password );
-        Entry result = null;
-        EntryCursor list = null;
+        assertFalse( result.get( "ou" ).contains( "testEntry" ) );
+    }
 
-        list = userCtx.search( dn.getName(), "(objectClass=*)", SearchScope.OBJECT, "*" );
+    // delete the subentry to test more general rule's inclusion of all values
+    deleteAccessControlSubentry( "excludeOUValue" );
 
-        if ( list.next() )
-        {
-            result = list.get();
-        }
+    // now add a subentry that enables anyone to search an entry below ou=system
+    // down two more rdns for DNs of a max size of 3.  This time we should be able
+    // to see the telephoneNumber attribute
+    createAccessControlSubentry( "includeAllAttributeTypesAndValues", "{ maximum 2 }",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues }, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    } " +
+            "  }" +
+            "}" );
 
-        list.close();
+    // again we should find four entries
+    assertTrue( checkCanSearchAs( "billyd", "billyd", 3 ) );
 
-        return result;
+    // check now to make sure the telephoneNumber attribute is present in results
+    for ( Entry result : results.values() )
+    {
+        assertTrue( result.get( "ou" ).contains( "testEntry" ) );
     }
+}
 
 
-    @Test
-    public void testSubentryAccess() throws Exception
-    {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
+/**
+ * Adds a perscriptiveACI to allow search, tests for success, then adds entryACI
+ * to deny read, browse and returnDN to a specific entry and checks to make sure
+ * that entry cannot be accessed via search as a specific user.
+ *
+ * @throws Exception if the test is broken
+ */
+@Test
+public void testPerscriptiveGrantWithEntryDenial() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
+
+    // now add an entryACI denies browse, read and returnDN to a specific entry
+    String aci =
+        "{ " +
+            "  identificationTag \"denyAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials { denyRead, denyReturnDN, denyBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}";
 
-        // now add a subentry that enables anyone to search below ou=system
-        createAccessControlSubentry( "anybodySearch",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
+    // try a search operation which should fail without any prescriptive ACI
+    Dn testsDn = new Dn( "ou=system" );
 
-        // check and see if we can access the subentry now
-        assertNotNull( checkCanSearchSubentryAs( "billyd", "billyd", new Dn( "cn=anybodySearch,ou=system" ) ) );
+    assertFalse( checkSearchAsWithEntryACI( "billyd", "billyd", SearchScope.SUBTREE, testsDn, aci, 9 ) );
 
-        // now add a denial to prevent all users except the admin from accessing the subentry
-        addSubentryACI(
+    // now add a subentry that enables anyone to search below ou=system
+    createAccessControlSubentry( "anybodySearch",
         "{ " +
             "  identificationTag \"searchAci\", " +
             "  precedence 14, " +
@@ -1034,315 +931,496 @@ public class SearchAuthorizationIT exten
             "    { " +
             "      { " +
             "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
+
+    // see if we can now search the tree which we could not before
+    // should work with billyd now that all users are authorized
+    // we should NOT see the entry we are about to deny access to
+    assertTrue( checkSearchAsWithEntryACI( "billyd", "billyd", SearchScope.SUBTREE, testsDn, aci, 9 ) );
+    assertNull( results.get( "ou=tests,ou=system" ) );
+
+    // try without the entry ACI, just perscriptive and see ou=tests,ou=system
+    assertTrue( checkCanSearchAs( "billyd", "billyd", SearchScope.SUBTREE, 10 ) );
+    assertNotNull( results.get( "ou=tests,ou=system" ) );
+}
+
+
+/**
+ * Adds a perscriptiveACI to allow search, tests for success, then adds entryACI
+ * to deny read, browse and returnDN to a specific entry and checks to make sure
+ * that entry cannot be accessed via search as a specific user.  Here the
+ * precidence of the ACI is put to the test.
+ *
+ * @throws Exception if the test is broken
+ */
+@Test
+public void testPerscriptiveGrantWithEntryDenialWithPrecidence() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
+
+    // now add an entryACI denying browse, read and returnDN to a specific entry
+    String aci =
+        "{ " +
+            "  identificationTag \"denyAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
             "        grantsAndDenials { denyRead, denyReturnDN, denyBrowse } " +
             "      } " +
             "    } " +
             "  } " +
+            "}";
+
+    // try a search operation which should fail without any prescriptive ACI
+    Dn testsDn = new Dn( "ou=system" );
+
+    assertFalse( checkSearchAsWithEntryACI( "billyd", "billyd", SearchScope.SUBTREE, testsDn, aci, 9 ) );
+
+    // now add a subentry that enables anyone to search below ou=system
+    createAccessControlSubentry( "anybodySearch",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 15, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
             "}" );
 
-        // now we should not be able to access the subentry with a search
-        assertNull( checkCanSearchSubentryAs( "billyd", "billyd", new Dn( "cn=anybodySearch,ou=system" ) ) );
-    }
+    // see if we can now search the tree which we could not before
+    // should work with billyd now that all users are authorized
+    // we should also see the entry we are about to deny access to
+    // we see it because the precidence of the grant is greater
+    // than the precedence of the denial
+    assertTrue( checkSearchAsWithEntryACI( "billyd", "billyd", SearchScope.SUBTREE, testsDn, aci, 10 ) );
+    assertNotNull( results.get( "ou=tests,ou=system" ) );
+
+    // now add an entryACI denies browse, read and returnDN to a specific entry
+    // but this time the precedence will be higher than that of the grant
+    aci =
+        "{ " +
+            "  identificationTag \"denyAci\", " +
+            "  precedence 16, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " + "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials { denyRead, denyReturnDN, denyBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}";
 
+    // see if we can now search the tree which we could not before
+    // should work with billyd now that all users are authorized
+    // we should NOT see the entry we are about to deny access to
+    // we do NOT see it because the precidence of the grant is less
+    // than the precedence of the denial - so the denial wins
+    assertTrue( checkSearchAsWithEntryACI( "billyd", "billyd", SearchScope.SUBTREE, testsDn, aci, 9 ) );
+    assertNull( results.get( "ou=tests,ou=system" ) );
+}
 
-    @Test
-    public void testGetMatchedName() throws Exception
-    {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
 
-        // now add a subentry that enables anyone to search/lookup and disclose on error
-        // below ou=system, with the exclusion of ou=groups and everything below it
-        createAccessControlSubentry( "selectiveDiscloseOnError",
-            "{ specificExclusions " +
-                "  { chopBefore:\"ou=groups\" } " +
-                "}",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst:" +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials " +
-                "        { " +
-                "          grantRead, " +
-                "          grantReturnDN, " +
-                "          grantBrowse, " +
-                "          grantDiscloseOnError " +
-                "        } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
-
-        // get a context as the user and try a lookup of a non-existant entry under ou=groups,ou=system
-        LdapConnection userCtx = getConnectionAs( "uid=billyd,ou=users,ou=system", "billyd" );
-
-        // we should not see ou=groups,ou=system for the remaining name
-        Entry entry = userCtx.lookup( "cn=blah,ou=groups" );
-        assertNull( entry );
-
-        // now delete and replace subentry with one that does not excluse ou=groups,ou=system
-        deleteAccessControlSubentry( "selectiveDiscloseOnError" );
-        createAccessControlSubentry( "selectiveDiscloseOnError",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials " +
-                "        { " +
-                "          grantRead, " +
-                "          grantReturnDN, " +
-                "          grantBrowse, " +
-                "          grantDiscloseOnError " +
-                "        } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
-
-        // now try a lookup of a non-existant entry under ou=groups,ou=system again
-        entry = userCtx.lookup( "cn=blah,ou=groups" );
-        assertNull( entry );
-    }
+/**
+ * Performs an object level search on the specified subentry relative to ou=system as a specific user.
+ *
+ * @param uid the uid Rdn attribute value of the user to perform the search as
+ * @param password the password of the user
+ * @param dn the relative name to the subentry under the ou=system AP
+ * @return the single search result if access is allowed or null
+ * @throws Exception if the search fails w/ exception other than no permission
+ */
+private Entry checkCanSearchSubentryAs( String uid, String password, Dn dn ) throws Exception
+{
+    LdapConnection userCtx = getConnectionAs( new Dn( "uid=" + uid + ",ou=users,ou=system" ), password );
+    Entry result = null;
+    EntryCursor list = null;
 
+    list = userCtx.search( dn.getName(), "(objectClass=*)", SearchScope.OBJECT, "*" );
 
-    @Test
-    public void testUserClassParentOfEntry() throws Exception
+    if ( list.next() )
     {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
+        result = list.get();
+    }
 
-        // create an entry subordinate to the user
-        Entry phoneBook = new DefaultEntry( "ou=phoneBook,uid=billyd,ou=users,ou=system" );
-        phoneBook.add( SchemaConstants.OU_AT, "phoneBook" );
-        phoneBook.add( SchemaConstants.OBJECT_CLASS_AT, "organizationalUnit" );
-
-        getAdminConnection().add( phoneBook );
-
-        // now add a subentry that enables anyone to search below their own entries
-        createAccessControlSubentry( "anybodySearchTheirSubordinates",
-            "{ " +
-                "  identificationTag \"searchAci\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
-
-        // check and see if we can access the subentry now
-        assertNotNull( checkCanSearchSubentryAs( "billyd", "billyd", new Dn(
-            "ou=phoneBook,uid=billyd,ou=users,ou=system" ) ) );
-
-        // now add a denial to prevent all users except the admin from accessing the subentry
-        addPrescriptiveACI( "anybodySearchTheirSubordinates",
-            "{ " +
-                "  identificationTag \"anybodyDontSearchTheirSubordinates\", " +
-                "  precedence 14, " +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { parentOfEntry }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
-                "        grantsAndDenials { denyRead, denyReturnDN, denyBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
+    list.close();
 
-        // now we should not be able to access the subentry with a search
-        assertNull( checkCanSearchSubentryAs( "billyd", "billyd", new Dn( "ou=phoneBook,uid=billyd,ou=users,ou=system" ) ) );
-    }
+    return result;
+}
 
 
-    /**
-     * Checks that we can protect a RangeOfValues item
-     *
-     * @throws Exception if the test encounters an error
-     */
-    @Test
-    @Ignore("The test is currently failing")
-    public void testRangeOfValues() throws Exception
-    {
-        // create the non-admin user
-        createUser( "billyd", "billyd" );
+@Test
+public void testSubentryAccess() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
 
-        // try a search operation which should fail without any ACI
-        assertFalse( checkCanSearchAs( "billyd", "billyd" ) );
+    // now add a subentry that enables anyone to search below ou=system
+    createAccessControlSubentry( "anybodySearch",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
 
-        // now add a subentry that allows a user to read the CN only
-        createAccessControlSubentry( "rangeOfValues",
-            "{ " +
-                "  identificationTag \"rangeOfValuesAci\", " +
-                "  precedence 14," +
-                "  authenticationLevel none, " +
-                "  itemOrUserFirst userFirst: " +
-                "  { " +
-                "    userClasses { allUsers }, " +
-                "    userPermissions " +
-                "    { " +
-                "      { " +
-                "        protectedItems { entry }, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      }, " +
-                "      { " +
-                "        protectedItems { rangeOfValues (cn=billyd) }, " +
-                "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
-                "      } " +
-                "    } " +
-                "  } " +
-                "}" );
-
-        // see if we can now search and find 4 entries
-        assertTrue( checkCanSearchAs( "billyd", "billyd" ) );
-
-        // check to make sure the telephoneNumber attribute is not present in results
-        for ( Entry result : results.values() )
-        {
-            assertNotNull( result.get( "cn" ) );
-        }
-    }
+    // check and see if we can access the subentry now
+    assertNotNull( checkCanSearchSubentryAs( "billyd", "billyd", new Dn( "cn=anybodySearch,ou=system" ) ) );
 
+    // now add a denial to prevent all users except the admin from accessing the subentry
+    addSubentryACI(
+    "{ " +
+        "  identificationTag \"searchAci\", " +
+        "  precedence 14, " +
+        "  authenticationLevel none, " +
+        "  itemOrUserFirst userFirst: " +
+        "  { " +
+        "    userClasses { allUsers }, " +
+        "    userPermissions " +
+        "    { " +
+        "      { " +
+        "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+        "        grantsAndDenials { denyRead, denyReturnDN, denyBrowse } " +
+        "      } " +
+        "    } " +
+        "  } " +
+        "}" );
 
-    @Test
-    public void testLdifFileLoader() throws Exception
-    {
-        URL url = getClass().getResource( "LdifFileLoader.ldif" );
-        URL url2 = getClass().getResource( "LdifFileLoader2.ldif" );
+    // now we should not be able to access the subentry with a search
+    assertNull( checkCanSearchSubentryAs( "billyd", "billyd", new Dn( "cn=anybodySearch,ou=system" ) ) );
+}
+
+
+@Test
+public void testGetMatchedName() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
+
+    // now add a subentry that enables anyone to search/lookup and disclose on error
+    // below ou=system, with the exclusion of ou=groups and everything below it
+    createAccessControlSubentry( "selectiveDiscloseOnError",
+        "{ specificExclusions " +
+            "  { chopBefore:\"ou=groups\" } " +
+            "}",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst:" +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials " +
+            "        { " +
+            "          grantRead, " +
+            "          grantReturnDN, " +
+            "          grantBrowse, " +
+            "          grantDiscloseOnError " +
+            "        } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
 
-        String file = url.getFile();
-        String file2 = url2.getFile();
+    // get a context as the user and try a lookup of a non-existant entry under ou=groups,ou=system
+    LdapConnection userCtx = getConnectionAs( "uid=billyd,ou=users,ou=system", "billyd" );
 
-        LdifFileLoader loader = new LdifFileLoader( service.getAdminSession(), file );
-        int count = loader.execute();
+    // we should not see ou=groups,ou=system for the remaining name
+    Entry entry = userCtx.lookup( "cn=blah,ou=groups" );
+    assertNull( entry );
+
+    // now delete and replace subentry with one that does not excluse ou=groups,ou=system
+    deleteAccessControlSubentry( "selectiveDiscloseOnError" );
+    createAccessControlSubentry( "selectiveDiscloseOnError",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials " +
+            "        { " +
+            "          grantRead, " +
+            "          grantReturnDN, " +
+            "          grantBrowse, " +
+            "          grantDiscloseOnError " +
+            "        } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
 
-        loader = new LdifFileLoader( service.getAdminSession(), file2 );
-        count = loader.execute();
+    // now try a lookup of a non-existant entry under ou=groups,ou=system again
+    entry = userCtx.lookup( "cn=blah,ou=groups" );
+    assertNull( entry );
+}
 
-        // Try to modify the entry with the created user
-        LdapConnection cnx = getConnectionAs( "uid=READER ,ou=users,ou=system", "secret" );
 
-        Entry res = cnx.lookup( "uid=READER ,ou=users,ou=system" );
+@Test
+public void testUserClassParentOfEntry() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
 
-        assertNotNull( res );
+    // create an entry subordinate to the user
+    Entry phoneBook = new DefaultEntry( "ou=phoneBook,uid=billyd,ou=users,ou=system" );
+    phoneBook.add( SchemaConstants.OU_AT, "phoneBook" );
+    phoneBook.add( SchemaConstants.OBJECT_CLASS_AT, "organizationalUnit" );
 
-        try
-        {
-            cnx.modify( "uid=READER ,ou=users,ou=system",
-                new DefaultModification( ModificationOperation.ADD_ATTRIBUTE, "description", "test" ) );
-            fail(); // expected
-        }
-        catch ( LdapNoPermissionException lnpe )
-        {
-            assertTrue( true );
-        }
+    getAdminConnection().add( phoneBook );
 
-        res = cnx.lookup( "uid=READER ,ou=users,ou=system" );
+    // now add a subentry that enables anyone to search below their own entries
+    createAccessControlSubentry( "anybodySearchTheirSubordinates",
+        "{ " +
+            "  identificationTag \"searchAci\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { allUsers }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials { grantRead, grantReturnDN, grantBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
 
-        assertNotNull( res );
+    // check and see if we can access the subentry now
+    assertNotNull( checkCanSearchSubentryAs( "billyd", "billyd", new Dn(
+        "ou=phoneBook,uid=billyd,ou=users,ou=system" ) ) );
 
-        cnx.unBind();
+    // now add a denial to prevent all users except the admin from accessing the subentry
+    addPrescriptiveACI( "anybodySearchTheirSubordinates",
+        "{ " +
+            "  identificationTag \"anybodyDontSearchTheirSubordinates\", " +
+            "  precedence 14, " +
+            "  authenticationLevel none, " +
+            "  itemOrUserFirst userFirst: " +
+            "  { " +
+            "    userClasses { parentOfEntry }, " +
+            "    userPermissions " +
+            "    { " +
+            "      { " +
+            "        protectedItems {entry, allUserAttributeTypesAndValues}, " +
+            "        grantsAndDenials { denyRead, denyReturnDN, denyBrowse } " +
+            "      } " +
+            "    } " +
+            "  } " +
+            "}" );
+
+    // now we should not be able to access the subentry with a search
+    assertNull( checkCanSearchSubentryAs( "billyd", "billyd", new Dn( "ou=phoneBook,uid=billyd,ou=users,ou=system" ) ) );
+}
+
+
+/**
+ * Checks that we can protect a RangeOfValues item
+ *
+ * @throws Exception if the test encounters an error
+ */
+@Test
+@Ignore("The test is currently failing")
+public void testRangeOfValues() throws Exception
+{
+    // create the non-admin user
+    createUser( "billyd", "billyd" );
+
+    // try a search operation which should fail without any ACI

[... 227 lines stripped ...]


Mime
View raw message