From 571884cec31d00f0c1b9de186fb1bbac17d289d5 Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Wed, 01 Aug 2007 01:15:44 +0000
Subject: [PATCH] Add ACI support to control whether a  "smart referral" (named subordinate references -- RFC 3296) may be returned to a client. Smart referral entries contain the referral objectclass and have one or more "ref" attributes containing LDAP URLS. The ref attribute type has usage distributedOperation, so the operational shorthand '+' character can be used to match it:

---
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java         |    2 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java |    2 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java                                 |   12 +
 opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java                                            |    2 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AlternateRootDN.java            |    2 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java                                         |   49 +++++-
 opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationBasis.java                                                   |    4 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/ReferencesTestCase.java         |  214 ++++++++++++++++++++++++++++++
 opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationWrapper.java                                                 |    4 
 opendj-sdk/opends/src/server/org/opends/server/types/operation/PreOperationSearchOperation.java                                 |    5 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/ExtOpTestCase.java              |    2 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java      |    2 
 opendj-sdk/opends/src/server/org/opends/server/types/operation/PreParseSearchOperation.java                                     |   14 -
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java                |   57 +++++--
 opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java                                                    |   10 +
 opendj-sdk/opends/src/server/org/opends/server/backends/jeb/DN2URI.java                                                         |    2 
 opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java                                                        |    4 
 17 files changed, 329 insertions(+), 58 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java b/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
index 12200ab..a15238b 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
@@ -308,7 +308,10 @@
 
   /**
    * Indicates whether the provided search result reference may be
-   * sent to the client.
+   * sent to the client based on the access control configuration.
+   *
+   * @param  dn         A DN that can be used in the access
+   *                    determination.
    *
    * @param  searchOperation  The search operation with which the
    *                          provided reference is associated.
@@ -319,8 +322,9 @@
    *          the reference to be returned to the client, or
    *          {@code false} if not.
    */
-  public abstract boolean maySend(SearchOperation searchOperation,
-                               SearchResultReference searchReference);
+  public abstract boolean maySend(DN dn,
+                             SearchOperation searchOperation,
+                             SearchResultReference searchReference);
 
 }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
index 77c3ba1..fa824cd 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -97,6 +97,12 @@
    */
   static AttributeType debugSearchIndex;
 
+  /**
+   * Attribute type corresponding to the "ref" attribute type. Used in the
+   * search reference access check.
+   */
+  static AttributeType refAttrType;
+
  /*
   * DN corresponding to "debugsearchindex" attribute type.
   */
@@ -149,6 +155,14 @@
        DirectoryServer.
                getDefaultAttributeType(EntryContainer.ATTR_DEBUG_SEARCH_INDEX);
      }
+
+     if((refAttrType =
+             DirectoryServer.
+                     getAttributeType(ATTR_REFERRAL_URL)) == null) {
+       refAttrType =
+               DirectoryServer.
+                       getDefaultAttributeType(ATTR_REFERRAL_URL);
+     }
      try {
        debugSearchIndexDN=DN.decode("cn=debugsearch");
      } catch (DirectoryException ex) {
@@ -1232,26 +1246,39 @@
          new AciLDAPOperationContainer(operation, e, (ACI_READ | ACI_EXT_OP));
       ret=accessAllowed(operationContainer);
     }
-    if(operation.getRequestOID().equals(OID_PROXIED_AUTH_V2) ||
-            operation.getRequestOID().equals(OID_PROXIED_AUTH_V1))
-       operation.
-              setAttachment(ORIG_AUTH_ENTRY, operation.getAuthorizationEntry());
     return ret;
   }
 
 
-  //Not planned to be implemented methods.
-
-   /**
+  /**
    * {@inheritDoc}
    */
   @Override
-  public boolean maySend(SearchOperation operation,
-      SearchResultReference reference) {
-    //TODO: Deferred.
-    return true;
+  public boolean maySend(DN dn, SearchOperation operation,
+                         SearchResultReference reference) {
+    boolean ret;
+    if(!(ret=skipAccessCheck(operation))) {
+      Entry e = new Entry(dn, null, null, null);
+      LinkedHashSet<AttributeValue> vals = new LinkedHashSet<AttributeValue>();
+      List<String> URLStrings=reference.getReferralURLs();
+      //Load the values, a bind rule might want to evaluate them.
+      for(String URLString : URLStrings) {
+        vals.add(new AttributeValue(refAttrType, URLString));
+      }
+      Attribute attr =
+                     new Attribute(refAttrType, ATTR_REFERRAL_URL, vals);
+      e.addAttribute(attr,null);
+      SearchResultEntry se=new  SearchResultEntry(e);
+      AciLDAPOperationContainer operationContainer =
+              new AciLDAPOperationContainer(operation,
+                                           (ACI_READ), se);
+      operationContainer.setCurrentAttributeType(refAttrType);
+      ret=accessAllowed(operationContainer);
+    }
+    return ret;
   }
 
+
   /**
    * {@inheritDoc}
    */
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
index 5cc1340..fc0b121 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
@@ -46,10 +46,8 @@
 import static org.opends.server.messages.MessageHandler.getMessage;
 import org.opends.server.core.DirectoryServer;
 import static org.opends.server.util.ServerConstants.*;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.LinkedList;
-import java.util.LinkedHashMap;
+
+import java.util.*;
 
 /**
  * The AciListenerManager updates an ACI list after each
@@ -216,6 +214,10 @@
       InternalClientConnection conn =
            InternalClientConnection.getRootConnection();
       LinkedList<String>failedACIMsgs=new LinkedList<String>();
+      //Add manageDsaIT control so any ACIs in referral entries will be
+      //picked up.
+      ArrayList<Control> controls = new ArrayList<Control>(1);
+      controls.add(new Control(OID_MANAGE_DSAIT_CONTROL, true));
       for (DN baseDN : backend.getBaseDNs()) {
         try {
           if (! backend.entryExists(baseDN))  {
@@ -233,7 +235,7 @@
                   conn,
                   InternalClientConnection.nextOperationID(),
                   InternalClientConnection.nextMessageID(),
-                  null, baseDN, SearchScope.WHOLE_SUBTREE,
+                  controls, baseDN, SearchScope.WHOLE_SUBTREE,
                   DereferencePolicy.NEVER_DEREF_ALIASES,
                   0, 0, false, aciFilter, attrs, null);
         LocalBackendSearchOperation localInternalSearch =
diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/DN2URI.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/DN2URI.java
index d432af7..cb2a7ca 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/DN2URI.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/DN2URI.java
@@ -667,7 +667,7 @@
           } while (status == OperationStatus.SUCCESS);
 
           SearchResultReference reference = new SearchResultReference(URIList);
-          if (!searchOp.returnReference(reference))
+          if (!searchOp.returnReference(dn, reference))
           {
             return false;
           }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java b/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
index 1980fd6..40eadf2 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
@@ -216,7 +216,7 @@
    * {@inheritDoc}
    */
   @Override
-  public boolean maySend(SearchOperation searchOperation,
+  public boolean maySend(DN dn, SearchOperation searchOperation,
                          SearchResultReference searchReference)
   {
     return true;
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java
index 80fb4fa..6769aa2 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperation.java
@@ -258,13 +258,15 @@
    * should be performed to potentially send it back to the client.
    *
    * @param  reference  The search reference to send to the client.
+   * @param  dn         The DN related to the specified search reference.
    *
    * @return  <CODE>true</CODE> if the caller should continue processing the
    *          search request and sending additional entries and references , or
    *          <CODE>false</CODE> if not for some reason (e.g., the size limit
    *          has been reached or the search has been abandoned).
    */
-  public abstract boolean returnReference(SearchResultReference reference);
+  public abstract boolean returnReference(DN dn,
+                                          SearchResultReference reference);
 
   /**
    * Sends the search result done message to the client.  Note that this method
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationBasis.java b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationBasis.java
index d95e942..69f0534 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationBasis.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationBasis.java
@@ -1040,7 +1040,7 @@
   /**
    * {@inheritDoc}
    */
-  public final boolean returnReference(SearchResultReference reference)
+  public final boolean returnReference(DN dn, SearchResultReference reference)
   {
     // See if the operation has been abandoned.  If so, then don't send the
     // reference and indicate that the search should end.
@@ -1073,7 +1073,7 @@
 
     // See if the client has permission to read this reference.
     if (AccessControlConfigManager.getInstance()
-        .getAccessControlHandler().maySend(this, reference) == false) {
+        .getAccessControlHandler().maySend(dn, this, reference) == false) {
       return true;
     }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationWrapper.java b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationWrapper.java
index 0673335..6246a26 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationWrapper.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationWrapper.java
@@ -76,9 +76,9 @@
   /**
    * {@inheritDoc}
    */
-  public boolean returnReference(SearchResultReference reference)
+  public boolean returnReference(DN dn, SearchResultReference reference)
   {
-    return search.returnReference(reference);
+    return search.returnReference(dn, reference);
   }
 
   /**
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/operation/PreOperationSearchOperation.java b/opendj-sdk/opends/src/server/org/opends/server/types/operation/PreOperationSearchOperation.java
index db145f8..16d1044 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/operation/PreOperationSearchOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/operation/PreOperationSearchOperation.java
@@ -175,6 +175,8 @@
   /**
    * Returns the provided search result reference to the client.
    *
+   * @param   dn        A DN related to the specified search
+   *                    reference.
    * @param  reference  The search reference that should be returned.
    *
    * @return  {@code true} if the caller should continue processing
@@ -183,6 +185,7 @@
    *          (e.g., the size limit has been reached or the search has
    *          been abandoned).
    */
-  public boolean returnReference(SearchResultReference reference);
+  public boolean
+  returnReference(DN dn ,SearchResultReference reference);
 }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/operation/PreParseSearchOperation.java b/opendj-sdk/opends/src/server/org/opends/server/types/operation/PreParseSearchOperation.java
index c25f1a5..5284d17 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/operation/PreParseSearchOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/operation/PreParseSearchOperation.java
@@ -31,14 +31,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 
-import org.opends.server.types.ByteString;
-import org.opends.server.types.Control;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.Entry;
-import org.opends.server.types.RawFilter;
-import org.opends.server.types.SearchResultReference;
-import org.opends.server.types.SearchScope;
-
+import org.opends.server.types.*;
 
 
 /**
@@ -234,6 +227,8 @@
    * Returns the provided search result reference to the client.
    *
    * @param  reference  The search reference that should be returned.
+   * @param  dn         A DN related to the specified search
+   *                    reference.
    *
    * @return  {@code true} if the caller should continue processing
    *          the search request and sending additional entries and
@@ -241,6 +236,7 @@
    *          (e.g., the size limit has been reached or the search has
    *          been abandoned).
    */
-  public boolean returnReference(SearchResultReference reference);
+  public boolean
+  returnReference(DN dn, SearchResultReference reference);
 }
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
index 1244306..3240d8b 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
@@ -49,7 +49,8 @@
   public  static final String filter = "(objectclass=*)";
   public static final String ACCESS_HANDLER_DN =
                                        "cn=Access Control Handler,cn=config";
-
+  public static final String refURL=
+          "ldap://kansashost/OU=People,O=Kansas,C=US";
   //GLOBAL ACIs
 
   protected final static String G_READ_ACI =
@@ -227,9 +228,11 @@
     argList.add("-s");
     argList.add("sub");
     argList.add(filter);
-    String[] attrs=attr.split("\\s+");
-    for(String a : attrs)
-     argList.add(a);
+    if(attr != null) {
+      String[] attrs=attr.split("\\s+");
+      for(String a : attrs)
+        argList.add(a);
+    }
     String[] args = new String[argList.size()];
     oStream.reset();
     int retVal =
@@ -253,6 +256,12 @@
     _LDIFModify(ldif, bindDn, bindPassword, null, false, -1);
   }
 
+  protected void LDIFModify(String ldif, String bindDn, String bindPassword,
+                            String ctrlString)
+  throws Exception {
+    _LDIFModify(ldif, bindDn, bindPassword, ctrlString, false, -1);
+  }
+
   protected void LDIFDelete(String dn, String bindDn, String bindPassword,
                             String controlStr, int rc) {
     _LDIFDelete(dn, bindDn, bindPassword, controlStr, rc);
@@ -413,26 +422,26 @@
   }
 
 
-  protected void addEntries() throws Exception {
+  protected void addEntries(String suffix) throws Exception {
     TestCaseUtils.initializeTestBackend(true);
     TestCaseUtils.addEntries(
-            "dn: ou=People,o=test",
+            "dn: ou=People," + suffix,
             "objectClass: top",
             "objectClass: organizationalUnit",
             "ou: People",
             "",
-            "dn: ou=admins,o=test",
+            "dn: ou=admins," + suffix ,
             "objectClass: top",
             "objectClass: organizationalUnit",
             "ou: admins",
             "",
-            "dn: cn=group,ou=People,o=test",
+            "dn: cn=group,ou=People," + suffix,
             "objectclass: top",
             "objectclass: groupOfNames",
             "cn: group",
-            "member: uid=user.3,ou=People,o=test",
+            "member: uid=user.3,ou=People," + suffix,
             "",
-            "dn: uid=superuser,ou=admins,o=test",
+            "dn: uid=superuser,ou=admins," + suffix,
             "objectClass: top",
             "objectClass: person",
             "objectClass: organizationalPerson",
@@ -444,7 +453,7 @@
             "userPassword: password",
             "ds-privilege-name: proxied-auth",
             "",
-            "dn: uid=proxyuser,ou=admins,o=test",
+            "dn: uid=proxyuser,ou=admins," + suffix,
             "objectClass: top",
             "objectClass: person",
             "objectClass: organizationalPerson",
@@ -455,7 +464,21 @@
             "cn: User 1",
             "userPassword: password",
             "",
-            "dn: uid=user.1,ou=People,o=test",
+            "dn: uid=smart referral admin,uid=proxyuser,ou=admins," + suffix,
+            "objectClass: top",
+            "objectClass: extensibleobject",
+            "objectClass: referral",
+            "ref:" + refURL,
+            "ref: ldap://texashost/OU=People,O=Texas,C=US",
+            "",
+            "dn: uid=smart referral people,ou=people," + suffix,
+            "objectClass: top",
+            "objectClass: extensibleobject",
+            "objectClass: referral",
+            "ref:" + refURL,
+            "ref: ldap://texashost/OU=People,O=Texas,C=US",
+            "",
+            "dn: uid=user.1,ou=People," + suffix,
             "objectClass: top",
             "objectClass: person",
             "objectClass: organizationalPerson",
@@ -465,10 +488,10 @@
             "sn: 1",
             "cn: User1",
             "l: Austin",
-            "manager: cn=group,ou=People,o=test",
+            "manager: cn=group,ou=People," + suffix,
             "userPassword: password",
             "",
-            "dn: uid=user.2,ou=People,o=test",
+            "dn: uid=user.2,ou=People," + suffix,
             "objectClass: top",
             "objectClass: person",
             "objectClass: organizationalPerson",
@@ -480,7 +503,7 @@
              "l: dallas",
             "userPassword: password",
             "",
-            "dn: uid=user.3,ou=People,o=test",
+            "dn: uid=user.3,ou=People," + suffix,
             "objectClass: top",
             "objectClass: person",
             "objectClass: organizationalPerson",
@@ -493,7 +516,7 @@
             "userPassword: password",
             "ds-privilege-name: proxied-auth",
             "",
-            "dn: uid=user.4,ou=People,o=test",
+            "dn: uid=user.4,ou=People," + suffix,
             "objectClass: top",
             "objectClass: person",
             "objectClass: organizationalPerson",
@@ -505,7 +528,7 @@
              "l: ft worth",
             "userPassword: password",
             "",
-            "dn: uid=user.5,ou=People,o=test",
+            "dn: uid=user.5,ou=People," + suffix,
             "objectClass: top",
             "objectClass: person",
             "objectClass: organizationalPerson",
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AlternateRootDN.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AlternateRootDN.java
index dbf633d..1485019 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AlternateRootDN.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AlternateRootDN.java
@@ -72,7 +72,7 @@
   public void setupClass() throws Exception {
     TestCaseUtils.startServer();
     deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
-    addEntries();
+    addEntries("o=test");
     addRootEntry();
   }
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/ExtOpTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/ExtOpTestCase.java
index 3843231..05473db 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/ExtOpTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/ExtOpTestCase.java
@@ -120,7 +120,7 @@
   public void setupClass() throws Exception {
     TestCaseUtils.startServer();
     deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
-    addEntries();
+    addEntries("o=test");
   }
 
    @AfterClass
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java
index c7fa970..101c274 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java
@@ -165,7 +165,7 @@
   public void setupClass() throws Exception {
     TestCaseUtils.startServer();
     deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
-    addEntries();
+    addEntries("o=test");
   }
 
   @AfterClass
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/ReferencesTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/ReferencesTestCase.java
new file mode 100644
index 0000000..1b6975c
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/ReferencesTestCase.java
@@ -0,0 +1,214 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+package org.opends.server.authorization.dseecompat;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+import org.opends.server.TestCaseUtils;
+import static org.opends.server.util.ServerConstants.OID_MANAGE_DSAIT_CONTROL;
+import static org.opends.server.config.ConfigConstants.ATTR_AUTHZ_GLOBAL_ACI;
+
+import java.util.HashMap;
+import java.io.StringReader;
+import java.io.BufferedReader;
+import java.io.IOException;
+
+
+/**
+ * Unit test to test ACI behavior and Named Subordinate References (RFC 3296).
+ * This test needs a jeb backend, the memory backend cannot be used.
+ */
+
+public class ReferencesTestCase extends AciTestCase{
+  private static String suffix="dc=example,dc=com";
+  private static final String level5User="uid=user.5,ou=People," + suffix;
+  private static final String adminBase="ou=Admins," + suffix;
+  private static final String peopleBase="ou=people," + suffix;
+  private static final String smartReferralAdmin=
+          "uid=smart referral admin,uid=proxyuser,ou=admins," + suffix;
+  private static final String ctrlString = OID_MANAGE_DSAIT_CONTROL + ":false";
+
+  //Allow based on plus operator.
+  private static final
+  String ALLOW_OC_PLUS = "(targetattr=\"objectclass || +\")" +
+          "(version 3.0;acl \"plus\";" +
+          "allow (search, read) " +
+          "userdn=\"ldap:///" + level5User + "\";)";
+
+  //Allow based on ref name.
+  private static final
+  String ALLOW_OC = "(targetattr=\"objectclass || ref\")" +
+          "(version 3.0;acl \"ref name\";" +
+          "allow (search, read) " +
+          "userdn=\"ldap:///" + level5User + "\";)";
+
+  //Allow based on target keyword.
+  private static final
+  String ALLOW_PEOPLE =
+          "(target=\"ldap:///" + peopleBase + "\")" +
+                  "(targetattr=\"objectclass || ref\")" +
+                  "(version 3.0;acl \"target\";" +
+                  "allow (search, read) " +
+                  "userdn=\"ldap:///" + level5User + "\";)";
+
+  @BeforeClass
+  public void setupClass() throws Exception {
+    TestCaseUtils.startServer();
+    deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
+    TestCaseUtils.clearJEBackend(true,"userRoot", suffix);
+    addEntries(suffix);
+  }
+
+  @AfterClass
+  public void tearDown() throws Exception {
+    String aciLdif=makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
+            G_READ_ACI, G_SELF_MOD, G_SCHEMA, G_DSE, G_USER_OPS, G_CONTROL,
+            E_EXTEND_OP);
+    LDIFModify(aciLdif, DIR_MGR_DN, PWD);
+    TestCaseUtils.clearJEBackend(false,"userRoot", suffix);
+  }
+
+  @BeforeMethod
+  public void clearBackend() throws Exception {
+    deleteAttrFromEntry(adminBase, "aci");
+    deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
+  }
+
+  /**
+   * Test using ACI added to admin base containing "ref" attribute type name
+   * specified in targetattr keword.
+   *
+   * @throws Exception If results are unexpected.
+   */
+  @Test()
+  public void testRef() throws Exception {
+    String pwdLdifs =
+            makeAddLDIF("aci", adminBase, ALLOW_OC);
+
+    LDIFModify(pwdLdifs, DIR_MGR_DN, PWD);
+    String userResults =
+            LDAPSearchParams(level5User, PWD, null,null, null,
+                    adminBase, filter, null);
+    Assert.assertTrue(isRefMap(userResults));
+  }
+
+  /**
+   * Test using ACI added to actual referral entry (added using ldifmodify
+   * passing manageDsaIT control).
+   *
+   * @throws Exception  If results are unexpected.
+   */
+  @Test()
+  public void testRefAci() throws Exception {
+    String pwdLdifs =
+            makeAddLDIF("aci", smartReferralAdmin, ALLOW_OC);
+    //Add the ACI passing the manageDsaIT control.
+    LDIFModify(pwdLdifs, DIR_MGR_DN, PWD, ctrlString);
+    String userResults =
+            LDAPSearchParams(level5User, PWD, null,null, null,
+                    adminBase, filter, null);
+    Assert.assertTrue(isRefMap(userResults));
+  }
+
+
+
+  /**
+   * Test global ACI allowing the "ref" attribute type to be returned only if
+   * if the search is under the people base. A search under the admin base
+   * should not return a reference.
+   *
+   * @throws Exception If an unexpected result is returned.
+   */
+  @Test()
+  public void testGlobalTargetAci() throws Exception {
+    String pwdLdifs =
+            makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN, ALLOW_PEOPLE);
+    LDIFModify(pwdLdifs, DIR_MGR_DN, PWD);
+    //Fail, ACI only allows people references
+    String userResults =
+            LDAPSearchParams(level5User, PWD, null,null, null,
+                    adminBase, filter, null);
+    Assert.assertFalse(isRefMap(userResults));
+    //Pass, ACI allows people references
+    String userResults1 =
+            LDAPSearchParams(level5User, PWD, null,null, null,
+                    peopleBase, filter, null);
+    Assert.assertTrue(isRefMap(userResults1));
+  }
+
+
+
+  /**
+   * Test global ACI allowing the "ref" attribute type specifed by the
+   * plus operator.
+   *
+   * @throws Exception If an unexpected result us returned.
+   */
+  @Test()
+  public void testGlobalAci() throws Exception {
+    String pwdLdifs =
+           makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN, ALLOW_OC_PLUS);
+    LDIFModify(pwdLdifs, DIR_MGR_DN, PWD);
+    String userResults =
+            LDAPSearchParams(level5User, PWD, null,null, null,
+                    adminBase, filter, null);
+    Assert.assertTrue(isRefMap(userResults));
+  }
+
+
+  /**
+   * Simple function that searches for the "SearchReference" string and returns
+   * true if it is seen.
+   *
+   * @param resultString The string containing the results from the search.
+   * @return True if the "SearchReference" string is seen in the results.
+   */
+  protected boolean
+  isRefMap(String resultString) {
+    boolean ret=false;
+    StringReader r=new StringReader(resultString);
+    BufferedReader br=new BufferedReader(r);
+    try {
+      while(true) {
+        String s = br.readLine();
+        if(s == null)
+          break;
+        if(s.startsWith("SearchReference")) {
+          ret=true;
+          break;
+        }
+      }
+    } catch (IOException e) {
+      Assert.assertEquals(0, 1,  e.getMessage());
+    }
+    return ret;
+  }
+}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
index 73c6a75..aa4a0fa 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
@@ -124,7 +124,7 @@
   public void setupClass() throws Exception {
     TestCaseUtils.startServer();
     deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
-    addEntries();
+    addEntries("o=test");
   }
 
   @AfterClass
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java
index 2ff7888..e2b13a4 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java
@@ -63,7 +63,7 @@
   public void setupClass() throws Exception {
     TestCaseUtils.startServer();
     deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
-    addEntries();
+    addEntries("o=test");
   }
 
   @AfterClass

--
Gitblit v1.10.0