From 5c703f3851c86aacbcbcfd5cb216d84da4a204c3 Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Thu, 17 May 2007 11:33:06 +0000
Subject: [PATCH] ACI fixes and unit tests for issues related to targetattr keyword and returning operational attributes.

---
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java         |  166 ++++++++++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java                                         |   20 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java                              |   33 ++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java |  269 ----------------
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java                                           |    5 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java                                                |   21 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java                                       |   43 ++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java                                         |   50 ++-
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java                |  300 ++++++++++++++++++
 9 files changed, 614 insertions(+), 293 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
index b56d87b..bb665b4 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
@@ -250,6 +250,27 @@
     public static final int TARGATTRFILTERS_DELETE = 0x2000;
 
     /**
+     * ACI_ATTR_STAR_MATCHED is the flag set when the evaluation reason of a
+     * AciHandler.maysend ACI_READ access evaluation was the result of an
+     * ACI targetattr all attributes expression (targetattr="*") target match.
+     * For this flag to be set, there must be only one ACI matching.
+     *
+     * This flag and ACI_FOUND_ATTR_RULE are used in the
+     * AciHandler.filterEntry.accessAllowedAttrs method to skip access
+     * evaluation if the flag is ACI_ATTR_STAR_MATCHED (all attributes match)
+     * and the attribute type is not operational.
+     */
+    public static final int ACI_ATTR_STAR_MATCHED = 0x0008;
+
+    /**
+     * ACI_FOUND_ATTR_RULE is the flag set when the evaluation reason of a
+     * AciHandler.maysend ACI_READ access evaluation was the result of an
+     * ACI targetattr specific attribute expression
+     * (targetattr="some attribute type") target match.
+     */
+    public static final int ACI_FOUND_ATTR_RULE = 0x0010;
+
+    /**
      * ACI_NULL is used to set the container rights to all zeros. Used
      * by LDAP modify.
      */
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
index 495212b..71e208a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -101,6 +101,12 @@
      * The entry being evaluated (resource entry).
      */
     private Entry resourceEntry;
+
+    /*
+     * Saves the resource entry. Used in geteffectiverights evaluation to
+     * restore the current resource entry state after a read right was
+     * evaluated.
+     */
     private Entry saveResourceEntry;
 
     /*
@@ -225,6 +231,11 @@
      */
     private String summaryString=null;
 
+   /*
+    * Flag used to determine if ACI all attributes target matched.
+    */
+    private int evalAllAttributes=0;
+
   /**
      * This constructor is used by all currently supported LDAP operations.
      *
@@ -265,6 +276,9 @@
           this.specificAttrs=getEffectiveRightsControl.getAttributes();
           fullEntry=(Entry)operation.getAttachment(ALL_ATTRS_RESOURCE_ENTRY);
         }
+        String allAttrs=(String)operation.getAttachment(ALL_ATTRS_MATCHED);
+        if(allAttrs != null)
+          evalAllAttributes = ACI_ATTR_STAR_MATCHED;
       }
       //Reference the current authorization entry, so it can be put back
       //if an access proxy check was performed.
@@ -791,4 +805,33 @@
         return "selfwrite";
       return null;
   }
+
+  /**
+   * {@inheritDoc}
+   */
+  public  void setACIEvalAttributesRule(int v) {
+    if(operation instanceof SearchOperation && (rights == ACI_READ)) {
+      if(v == ACI_FOUND_ATTR_RULE) {
+        evalAllAttributes |= ACI_FOUND_ATTR_RULE;
+        evalAllAttributes &= ~ACI_ATTR_STAR_MATCHED;
+      } else
+        evalAllAttributes |= Aci.ACI_ATTR_STAR_MATCHED;
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean hasACIEvalAttributes() {
+    return (evalAllAttributes == 0) ||
+           (evalAllAttributes & ACI_FOUND_ATTR_RULE) == ACI_FOUND_ATTR_RULE;
+  }
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void clearACIEvalAttributesRule(int v) {
+    evalAllAttributes &= ~v;
+  }
 }
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 fc4d426..7521308 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
@@ -85,6 +85,13 @@
     public static String ALL_ATTRS_RESOURCE_ENTRY = "allAttrsResourceEntry";
 
     /**
+     * String used to indicate that the evaluating ACI had a all attributes
+     * targetattr match (targetattr="*").
+     */
+     public static String ALL_ATTRS_MATCHED = "allAttrsMatched";
+
+
+    /**
      * This constructor instantiates the ACI handler class that performs the
      * main processing for the dseecompat ACI package. It does the following
      * initializations:
@@ -556,16 +563,16 @@
         return ret;
     }
 
-  /**
-   * Check if the specified attribute type is a DN by checking if its syntax
-   * OID is equal to the DN syntax OID.
-   * @param attribute The attribute type to check.
-   * @return True if the attribute type syntax OID is equal to a DN syntax OID.
-   */
-  private boolean isAttributeDN(AttributeType attribute) {
-    return (attribute.getSyntaxOID().equals(SYNTAX_DN_OID));
-  }
-
+    /**
+     * Check if the specified attribute type is a DN by checking if its syntax
+     * OID is equal to the DN syntax OID.
+     * @param attribute The attribute type to check.
+     * @return True if the attribute type syntax OID is equal to a DN syntax
+     *         OID.
+     */
+    private boolean isAttributeDN(AttributeType attribute) {
+      return (attribute.getSyntaxOID().equals(SYNTAX_DN_OID));
+    }
 
     /**
      * Performs an access check against all of the attributes of an entry.
@@ -579,15 +586,17 @@
      */
     private SearchResultEntry
     accessAllowedAttrs(AciLDAPOperationContainer container) {
-        Entry e=container.getResourceEntry();
-        List<AttributeType> typeList=getAllAttrs(e);
-        for(AttributeType attrType : typeList) {
-            container.setCurrentAttributeType(attrType);
-            if(!accessAllowed(container)) {
-                e.removeAttribute(attrType);
-            }
+      Entry e=container.getResourceEntry();
+      List<AttributeType> typeList=getAllAttrs(e);
+      for(AttributeType attrType : typeList) {
+        if(!container.hasACIEvalAttributes() && !attrType.isOperational())
+          continue;
+        container.setCurrentAttributeType(attrType);
+        if(!accessAllowed(container)) {
+          e.removeAttribute(attrType);
         }
-        return container.getSearchResultEntry();
+      }
+      return container.getSearchResultEntry();
     }
 
     /**
@@ -600,6 +609,8 @@
      */
     private List<AttributeType> getAllAttrs(Entry e) {
         Map<AttributeType,List<Attribute>> attrMap = e.getUserAttributes();
+        Map<AttributeType,List<Attribute>> opAttrMap =
+                                                   e.getOperationalAttributes();
         List<AttributeType> typeList=new LinkedList<AttributeType>();
         Attribute attr=e.getObjectClassAttribute();
         /*
@@ -611,6 +622,7 @@
            typeList.add(ocType);
         }
         typeList.addAll(attrMap.keySet());
+        typeList.addAll(opAttrMap.keySet());
         return typeList;
     }
 
@@ -877,6 +889,8 @@
           if (ret) {
               operationContainer.setRights(ACI_READ);
               ret=accessAllowedEntry(operationContainer);
+              if(ret && !operationContainer.hasACIEvalAttributes())
+                operation.setAttachment(ALL_ATTRS_MATCHED, ALL_ATTRS_MATCHED);
           }
       }
       if(ret && operation.getAttachment(OID_GET_EFFECTIVE_RIGHTS) != null)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
index 3ccb74b..f70e3bb 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
@@ -165,6 +165,39 @@
      * @return  True if a match context is evaluating geteffectiverights.
      */
     boolean isGetEffectiveRightsEval();
+
+  /**
+   * This method toggles a mask that indicates that access checking of
+   * individual non-operational attributes may or may not be skipped depending
+   * on if there is a single ACI containing a targetattr all attributes  rule
+   * (targetattr="*").
+   *
+   * The only case where individual non-operational attribute access checking
+   * can be skipped, is when a single ACI matched using a targetattr
+   * all attributes rule.
+   *
+   * @param v  The flag to set the mask to.
+   */
+  void setACIEvalAttributesRule(int v);
+
+  /**
+   * Return true if the evaluating ACI either contained an explicitly defined
+   * attribute type in a targeattr target rule or both a targetattr all
+   * attributes rule matched and a explictly defined targetattr target rule
+   * matched.
+   *
+   * @return  True if the above condition was seen.
+   */
+    boolean hasACIEvalAttributes();
+
+
+  /**
+   * Used to clear the mask used to detect if access checking needs to be
+   * performed on individual non-operational attributes types.
+   *
+   * @param v  The flag to clear (always ACI_ATTR_STAR_MATCHED)
+   */
+    public void clearACIEvalAttributesRule(int v);
 }
 
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
index 8fd9d7b..d7d212d 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
@@ -411,9 +411,23 @@
             AttributeType a=targetMatchCtx.getCurrentAttributeType();
             int rights=targetMatchCtx.getRights();
             boolean isFirstAttr=targetMatchCtx.isFirstAttribute();
-            if((a != null) && (targets.getTargetAttr() != null))
-                ret=TargetAttr.isApplicable(a, targets.getTargetAttr());
-            else if((a != null) || (targets.getTargetAttr() != null)) {
+            if((a != null) && (targets.getTargetAttr() != null))  {
+             ret=TargetAttr.isApplicable(a,targets.getTargetAttr());
+             targetMatchCtx.clearACIEvalAttributesRule(ACI_ATTR_STAR_MATCHED);
+             /*
+               If a explicitly defined targetattr's match rule has not
+               been seen (~ACI_FOUND_ATTR_RULE) and the current attribute type
+               is applicable because of a targetattr all attributes rule match,
+               set a flag to indicate this situation (ACI_ATTR_STAR_MATCHED).
+               Else the attributes is applicable because it is operational or
+               not a targetattr's all attribute match.
+              */
+             if(ret && targets.getTargetAttr().isAllAttributes() &&
+                !targetMatchCtx.hasACIEvalAttributes())
+               targetMatchCtx.setACIEvalAttributesRule(ACI_ATTR_STAR_MATCHED);
+              else
+                targetMatchCtx.setACIEvalAttributesRule(ACI_FOUND_ATTR_RULE);
+            } else if((a != null) || (targets.getTargetAttr() != null)) {
                 if((aci.hasRights(skipRights)) &&
                                                 (skipRightsHasRights(rights)))
                     ret=true;
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
index ea6b303..632f9c9 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
@@ -178,7 +178,6 @@
      */
     public EnumEvalResult evaluate(AciEvalContext evalCtx) {
         EnumEvalResult matched;
-        boolean undefined=false;
 
         switch(userAttrType) {
         case ROLEDN:
@@ -194,9 +193,7 @@
         default:
             matched=evalVAL(evalCtx);
         }
-        if(matched == EnumEvalResult.ERR)
-            undefined=true;
-        return matched.getRet(type, undefined);
+        return matched;
     }
 
     /** Evaluate a VALUE userattr type. Look in client entry for an
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
new file mode 100644
index 0000000..5d6d9c7
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
@@ -0,0 +1,300 @@
+/*
+ * 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.opends.server.DirectoryServerTestCase;
+import org.opends.server.TestCaseUtils;
+import org.opends.server.tools.LDAPModify;
+import org.opends.server.tools.LDAPSearch;
+import static org.opends.server.util.ServerConstants.EOL;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.io.*;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.ArrayList;
+
+@Test(groups = { "precommit", "dseecompat" })
+public abstract class  AciTestCase extends DirectoryServerTestCase {
+  public static final String DIR_MGR_DN = "cn=Directory Manager";
+  public static final String PWD = "password";
+  public  static final String filter = "(objectclass=*)";
+  public static final String ACCESS_HANDLER_DN =
+                                       "cn=Access Control Handler,cn=config";
+
+  private static ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+  private  static ThreadLocal<Map<String,File>> tempLdifFile =
+           new ThreadLocal<Map<String,File>>();
+
+  protected String LDAPSearchCtrl(String bindDn, String bindPassword,
+                            String proxyDN, String controlStr,
+                            String base, String filter, String attr)
+          throws Exception {
+    ArrayList<String> argList=new ArrayList<String>(20);
+    argList.add("-h");
+    argList.add("127.0.0.1");
+    argList.add("-p");
+    argList.add(String.valueOf(TestCaseUtils.getServerLdapPort()));
+    argList.add("-D");
+    argList.add(bindDn);
+    argList.add("-w");
+    argList.add(bindPassword);
+    argList.add("-T");
+    if(proxyDN != null) {
+      argList.add("-Y");
+      argList.add("dn:" + proxyDN);
+    }
+    if(controlStr != null) {
+      argList.add("-J");
+      argList.add(controlStr);
+    }
+    argList.add("-b");
+    argList.add(base);
+    argList.add("-s");
+    argList.add("sub");
+    argList.add(filter);
+    String[] attrs=attr.split("\\s+");
+    for(String a : attrs)
+     argList.add(a);
+    String[] args = new String[argList.size()];
+    oStream.reset();
+    int retVal =
+            LDAPSearch.mainSearch(argList.toArray(args), false, oStream, oStream);
+    Assert.assertEquals(0, retVal,  "Returned error: " + oStream.toString());
+    return oStream.toString();
+  }
+
+  protected String LDAPSearchParams(String bindDn, String bindPassword,
+                            String proxyDN, String authzid, String[] attrList,
+                            String base, String filter ,String attr)
+          throws Exception {
+    ArrayList<String> argList=new ArrayList<String>(20);
+    argList.add("-h");
+    argList.add("127.0.0.1");
+    argList.add("-p");
+    argList.add(String.valueOf(TestCaseUtils.getServerLdapPort()));
+    argList.add("-D");
+    argList.add(bindDn);
+    argList.add("-w");
+    argList.add(bindPassword);
+    argList.add("-T");
+    if(proxyDN != null) {
+      argList.add("-Y");
+      argList.add("dn:" + proxyDN);
+    }
+    if(authzid != null) {
+      argList.add("-g");
+      argList.add(authzid);
+    }
+    if(attrList != null) {
+      for(String a : attrList) {
+        argList.add("-e");
+        argList.add(a);
+      }
+    }
+    argList.add("-b");
+    argList.add(base);
+    argList.add("-s");
+    argList.add("sub");
+    argList.add(filter);
+    String[] attrs=attr.split("\\s+");
+    for(String a : attrs)
+     argList.add(a);
+    String[] args = new String[argList.size()];
+    oStream.reset();
+    int retVal =
+         LDAPSearch.mainSearch(argList.toArray(args), false, oStream, oStream);
+    Assert.assertEquals(0, retVal, "Returned error: " + oStream.toString());
+    return oStream.toString();
+  }
+
+  protected void modEntries(String ldif, String bindDn, String bindPassword)
+          throws Exception {
+    File tempFile = getTemporaryLdifFile();
+    TestCaseUtils.writeFile(tempFile, ldif);
+    ArrayList<String> argList=new ArrayList<String>(20);
+    argList.add("-h");
+    argList.add("127.0.0.1");
+    argList.add("-p");
+    argList.add(String.valueOf(TestCaseUtils.getServerLdapPort()));
+    argList.add("-D");
+    argList.add(bindDn);
+    argList.add("-w");
+    argList.add(bindPassword);
+    argList.add("-f");
+    argList.add(tempFile.getAbsolutePath());
+    String[] args = new String[argList.size()];
+    ldapModify(argList.toArray(args));
+  }
+
+  protected void ldapModify(String[] args) {
+    oStream.reset();
+    LDAPModify.mainModify(args, false, oStream, oStream);
+  }
+
+  protected void deleteAttrFromEntry(String dn, String attr)
+  throws Exception {
+    StringBuilder ldif = new StringBuilder();
+    ldif.append(TestCaseUtils.makeLdif(
+            "dn: "  + dn,
+            "changetype: modify",
+            "delete: " + attr));
+    modEntries(ldif.toString(), DIR_MGR_DN, PWD);
+  }
+
+  protected static String makeAddAciLdif(String attr, String dn, String... acis) {
+    StringBuilder ldif = new StringBuilder();
+    ldif.append("dn: ").append(dn).append(EOL);
+    ldif.append("changetype: modify").append(EOL);
+    ldif.append("add: ").append(attr).append(EOL);
+    for(String aci : acis)
+      ldif.append(attr).append(":").append(aci).append(EOL);
+    ldif.append(EOL);
+    return ldif.toString();
+  }
+
+  protected File getTemporaryLdifFile() throws IOException {
+    Map<String,File> tempFilesForThisThread = tempLdifFile.get();
+    if (tempFilesForThisThread == null) {
+      tempFilesForThisThread = new HashMap<String,File>();
+      tempLdifFile.set(tempFilesForThisThread);
+    }
+    File tempFile = tempFilesForThisThread.get("effectiverights-tests");
+    if (tempFile == null) {
+      tempFile = File.createTempFile("effectiverights-tests", ".ldif");
+      tempFile.deleteOnExit();
+      tempFilesForThisThread.put("effectiverights-tests", tempFile);
+    }
+    return tempFile;
+  }
+
+  protected void addEntries() throws Exception {
+    TestCaseUtils.initializeTestBackend(true);
+    TestCaseUtils.addEntries(
+            "dn: ou=People,o=test",
+            "objectClass: top",
+            "objectClass: organizationalUnit",
+            "ou: People",
+            "",
+            "dn: ou=admins,o=test",
+            "objectClass: top",
+            "objectClass: organizationalUnit",
+            "ou: admins",
+            "",
+            "dn: cn=group,ou=People,o=test",
+            "objectclass: top",
+            "objectclass: groupOfNames",
+            "cn: group",
+            "member: uid=user.1,ou=People,o=test",
+            "",
+            "dn: uid=superuser,ou=admins,o=test",
+            "objectClass: top",
+            "objectClass: person",
+            "objectClass: organizationalPerson",
+            "objectClass: inetOrgPerson",
+            "uid: superuser",
+            "givenName: superuser",
+            "sn: 1",
+            "cn: User 1",
+            "userPassword: password",
+            "ds-privilege-name: proxied-auth",
+            "",
+            "dn: uid=proxyuser,ou=admins,o=test",
+            "objectClass: top",
+            "objectClass: person",
+            "objectClass: organizationalPerson",
+            "objectClass: inetOrgPerson",
+            "uid: proxyuser",
+            "givenName: proxyuser",
+            "sn: 1",
+            "cn: User 1",
+            "userPassword: password",
+            "",
+            "dn: uid=user.1,ou=People,o=test",
+            "objectClass: top",
+            "objectClass: person",
+            "objectClass: organizationalPerson",
+            "objectClass: inetOrgPerson",
+            "uid: user.1",
+            "givenName: User 1",
+            "sn: 1",
+            "cn: User1",
+            "l: Austin",
+            "userPassword: password",
+            "",
+            "dn: uid=user.2,ou=People,o=test",
+            "objectClass: top",
+            "objectClass: person",
+            "objectClass: organizationalPerson",
+            "objectClass: inetOrgPerson",
+            "uid: user.2",
+            "givenName: User 2",
+            "sn: 2",
+            "cn: User 2",
+             "l: dallas",
+            "userPassword: password",
+            "",
+            "dn: uid=user.3,ou=People,o=test",
+            "objectClass: top",
+            "objectClass: person",
+            "objectClass: organizationalPerson",
+            "objectClass: inetOrgPerson",
+            "uid: user.3",
+            "givenName: User 3",
+            "sn: 3",
+            "mail: user.3@test",
+            "description: user.3 description",
+            "cn: User 3",
+            "l: Austin",
+            "userPassword: password");
+  }
+
+  protected HashMap<String, String>
+  getAttrMap(String resultString) throws Exception {
+    StringReader r=new StringReader(resultString);
+    BufferedReader br=new BufferedReader(r);
+    HashMap<String, String> attrMap = new HashMap<String,String>();
+    try {
+      while(true) {
+        String s = br.readLine();
+        if(s == null)
+          break;
+        if(s.startsWith("dn:"))
+          continue;
+        String[] a=s.split(": ");
+        if(a.length != 2)
+          break;
+        attrMap.put(a[0],a[1]);
+      }
+    } catch (IOException e) {
+      Assert.assertEquals(0, 1,  e.getMessage());
+    }
+    return attrMap;
+  }
+}
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 4ae744c..80f36c2 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
@@ -32,26 +32,11 @@
 import org.testng.annotations.BeforeMethod;
 import static org.opends.server.config.ConfigConstants.*;
 import org.testng.Assert;
-import static org.testng.Assert.assertEquals;
 import org.opends.server.TestCaseUtils;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.Attribute;
-import org.opends.server.tools.LDAPSearch;
-import org.opends.server.tools.LDAPModify;
 import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
-import static org.opends.server.util.ServerConstants.EOL;
-
-import java.io.*;
-import java.util.ArrayList;
-import java.util.Map;
 import java.util.HashMap;
-import java.util.List;
 
-public class GetEffectiveRightsTestCase {
-  private static ByteArrayOutputStream oStream = new ByteArrayOutputStream();
-  private static final String DIR_MGR_DN = "cn=Directory Manager";
-  private static final String PWD = "password";
-  private static final String filter = "(objectclass=*)";
+public class GetEffectiveRightsTestCase extends AciTestCase {
   private static final String base="uid=user.3,ou=People,o=test";
   private static final String user1="uid=user.1,ou=People,o=test";
   private static final String superUser="uid=superuser,ou=admins,o=test";
@@ -79,9 +64,6 @@
   private static final
   String allRights = "add:1,delete:1,read:1,write:1,proxy:1";
 
-  private static final
-  String ACCESS_HANDLER_DN = "cn=Access Control Handler,cn=config";
-
   //Results for attributeLevel searches
   private static final String srwMailAttrRights =
           "search:1,read:1,compare:0,write:1," +
@@ -415,253 +397,4 @@
     String retRightsStr=attrMap.get(entryLevel);
     Assert.assertTrue(retRightsStr.equals(reqRightsStr));
  }
-
- private HashMap<String, String>
- getAttrMap(String resultString) throws Exception {
-       StringReader r=new StringReader(resultString);
-    BufferedReader br=new BufferedReader(r);
-    HashMap<String, String> attrMap = new HashMap<String,String>();
-    try {
-      while(true) {
-        String s = br.readLine();
-        if(s == null)
-          break;
-        if(s.startsWith("dn:"))
-          continue;
-        String[] a=s.split(": ");
-        if(a.length != 2)
-          break;
-        attrMap.put(a[0],a[1]);
-      }
-    } catch (IOException e) {
-      Assert.assertEquals(0, 1,  e.getMessage());
-    }
-   return attrMap;
- }
-
-
-  private void addEntries() throws Exception {
-    TestCaseUtils.initializeTestBackend(true);
-    TestCaseUtils.addEntries(
-            "dn: ou=People,o=test",
-            "objectClass: top",
-            "objectClass: organizationalUnit",
-            "ou: People",
-            "",
-            "dn: ou=admins,o=test",
-            "objectClass: top",
-            "objectClass: organizationalUnit",
-            "ou: admins",
-            "",
-            "dn: cn=group,ou=People,o=test",
-            "objectclass: top",
-            "objectclass: groupOfNames",
-            "cn: group",
-            "member: uid=user.1,ou=People,o=test",
-            "",
-            "dn: uid=superuser,ou=admins,o=test",
-            "objectClass: top",
-            "objectClass: person",
-            "objectClass: organizationalPerson",
-            "objectClass: inetOrgPerson",
-            "uid: superuser",
-            "givenName: superuser",
-            "sn: 1",
-            "cn: User 1",
-            "userPassword: password",
-            "ds-privilege-name: proxied-auth",
-            "",
-            "dn: uid=proxyuser,ou=admins,o=test",
-            "objectClass: top",
-            "objectClass: person",
-            "objectClass: organizationalPerson",
-            "objectClass: inetOrgPerson",
-            "uid: proxyuser",
-            "givenName: proxyuser",
-            "sn: 1",
-            "cn: User 1",
-            "userPassword: password",
-            "",
-            "dn: uid=user.1,ou=People,o=test",
-            "objectClass: top",
-            "objectClass: person",
-            "objectClass: organizationalPerson",
-            "objectClass: inetOrgPerson",
-            "uid: user.1",
-            "givenName: User",
-            "sn: 1",
-            "cn: User 1",
-            "userPassword: password",
-            "",
-            "dn: uid=user.2,ou=People,o=test",
-            "objectClass: top",
-            "objectClass: person",
-            "objectClass: organizationalPerson",
-            "objectClass: inetOrgPerson",
-            "uid: user.2",
-            "givenName: User",
-            "sn: 2",
-            "cn: User 2",
-            "userPassword: password",
-            "",
-            "dn: uid=user.3,ou=People,o=test",
-            "objectClass: top",
-            "objectClass: person",
-            "objectClass: organizationalPerson",
-            "objectClass: inetOrgPerson",
-            "uid: user.3",
-            "givenName: User",
-            "sn: 3",
-            "mail: user.3@test",
-            "description: user.3 description",
-            "cn: User 3",
-            "userPassword: password");
-  }
-
-  private String LDAPSearchCtrl(String bindDn, String bindPassword,
-                            String proxyDN, String controlStr,
-                            String base, String filter, String attr)
-          throws Exception {
-    ArrayList<String> argList=new ArrayList<String>(20);
-    argList.add("-h");
-    argList.add("127.0.0.1");
-    argList.add("-p");
-    argList.add(String.valueOf(TestCaseUtils.getServerLdapPort()));
-    argList.add("-D");
-    argList.add(bindDn);
-    argList.add("-w");
-    argList.add(bindPassword);
-    argList.add("-T");
-    if(proxyDN != null) {
-      argList.add("-Y");
-      argList.add("dn:" + proxyDN);
-    }
-    if(controlStr != null) {
-      argList.add("-J");
-      argList.add(controlStr);
-    }
-    argList.add("-b");
-    argList.add(base);
-    argList.add("-s");
-    argList.add("sub");
-    argList.add(filter);
-    String[] attrs=attr.split("\\s+");
-    for(String a : attrs)
-     argList.add(a);
-    String[] args = new String[argList.size()];
-    oStream.reset();
-    int retVal =
-            LDAPSearch.mainSearch(argList.toArray(args), false, oStream, oStream);
-    Assert.assertEquals(0, retVal,  "Returned error: " + oStream.toString());
-    return oStream.toString();
-  }
-
-  private String LDAPSearchParams(String bindDn, String bindPassword,
-                            String proxyDN, String authzid, String[] attrList,
-                            String base, String filter ,String attr)
-          throws Exception {
-    ArrayList<String> argList=new ArrayList<String>(20);
-    argList.add("-h");
-    argList.add("127.0.0.1");
-    argList.add("-p");
-    argList.add(String.valueOf(TestCaseUtils.getServerLdapPort()));
-    argList.add("-D");
-    argList.add(bindDn);
-    argList.add("-w");
-    argList.add(bindPassword);
-    argList.add("-T");
-    if(proxyDN != null) {
-      argList.add("-Y");
-      argList.add("dn:" + proxyDN);
-    }
-    if(authzid != null) {
-      argList.add("-g");
-      argList.add(authzid);
-    }
-    if(attrList != null) {
-      for(String a : attrList) {
-        argList.add("-e");
-        argList.add(a);
-      }
-    }
-    argList.add("-b");
-    argList.add(base);
-    argList.add("-s");
-    argList.add("sub");
-    argList.add(filter);
-    String[] attrs=attr.split("\\s+");
-    for(String a : attrs)
-     argList.add(a);
-    String[] args = new String[argList.size()];
-    oStream.reset();
-    int retVal =
-         LDAPSearch.mainSearch(argList.toArray(args), false, oStream, oStream);
-    Assert.assertEquals(0, retVal, "Returned error: " + oStream.toString());
-    return oStream.toString();
-  }
-
-
-  private void modEntries(String ldif, String bindDn, String bindPassword)
-          throws Exception {
-    File tempFile = getTemporaryLdifFile();
-    TestCaseUtils.writeFile(tempFile, ldif);
-    ArrayList<String> argList=new ArrayList<String>(20);
-    argList.add("-h");
-    argList.add("127.0.0.1");
-    argList.add("-p");
-    argList.add(String.valueOf(TestCaseUtils.getServerLdapPort()));
-    argList.add("-D");
-    argList.add(bindDn);
-    argList.add("-w");
-    argList.add(bindPassword);
-    argList.add("-f");
-    argList.add(tempFile.getAbsolutePath());
-    String[] args = new String[argList.size()];
-    ldapModify(argList.toArray(args));
-  }
-
-
-  private void ldapModify(String[] args) {
-    oStream.reset();
-    LDAPModify.mainModify(args, false, oStream, oStream);
-  }
-
-  private void deleteAttrFromEntry(String dn, String attr)
-  throws Exception {
-    StringBuilder ldif = new StringBuilder();
-    ldif.append(TestCaseUtils.makeLdif(
-            "dn: "  + dn,
-            "changetype: modify",
-            "delete: " + attr));
-    modEntries(ldif.toString(), DIR_MGR_DN, PWD);
-  }
-
-  private static ThreadLocal<Map<String,File>> tempLdifFile =
-          new ThreadLocal<Map<String,File>>();
-
-  private File getTemporaryLdifFile() throws IOException {
-    Map<String,File> tempFilesForThisThread = tempLdifFile.get();
-    if (tempFilesForThisThread == null) {
-      tempFilesForThisThread = new HashMap<String,File>();
-      tempLdifFile.set(tempFilesForThisThread);
-    }
-    File tempFile = tempFilesForThisThread.get("effectiverights-tests");
-    if (tempFile == null) {
-      tempFile = File.createTempFile("effectiverights-tests", ".ldif");
-      tempFile.deleteOnExit();
-      tempFilesForThisThread.put("effectiverights-tests", tempFile);
-    }
-    return tempFile;
-  }
-
-  private static String makeAddAciLdif(String attr, String dn, String... acis) {
-    StringBuilder ldif = new StringBuilder();
-    ldif.append("dn: ").append(dn).append(EOL);
-    ldif.append("changetype: modify").append(EOL);
-    ldif.append("add: ").append(attr).append(EOL);
-    for(String aci : acis)
-      ldif.append(attr).append(":").append(aci).append(EOL);
-    ldif.append(EOL);
-    return ldif.toString();
-  }
 }
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
new file mode 100644
index 0000000..da90cbd
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
@@ -0,0 +1,166 @@
+/*
+ * 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.Test;
+import org.testng.Assert;
+import org.opends.server.TestCaseUtils;
+import static org.opends.server.config.ConfigConstants.*;
+
+import java.util.HashMap;
+
+public class TargetAttrTestCase extends AciTestCase {
+
+  private static String attrList="sn uid l";
+  private static String opAttrList="sn uid aci";
+  private static final String user1="uid=user.1,ou=People,o=test";
+  private static final String user3="uid=user.3,ou=People,o=test";
+  public  static final String aciFilter = "(aci=*)";
+
+  private static final
+  String userAttrAci = "(targetattr=\"*\")" +
+          "(version 3.0;acl \"read/search userattr\";" +
+          "allow (search, read) " +
+          "userattr=\"l#Austin\";)";
+
+  private static final
+  String userAttrAci1 = "(targetattr=\"*\")" +
+          "(version 3.0;acl \"read/search userattr\";" +
+          "allow (search, read) " +
+          "userattr!=\"l#New York\";)";
+
+  private static final
+  String nonOpAttrAci = "(targetattr=\"*\")" +
+          "(version 3.0;acl \"read/search non-operational attr\";" +
+          "allow (search, read) " +
+          "userdn=\"ldap:///uid=user.3,ou=People,o=test\";)";
+
+  private static final
+  String opAttrAci = "(targetattr=\"aci\")" +
+          "(version 3.0;acl \"read/search operational attr\";" +
+          "allow (search, read) " +
+          "userdn=\"ldap:///uid=user.3,ou=People,o=test\";)";
+
+  @BeforeClass
+  public void setupClass() throws Exception {
+    TestCaseUtils.startServer();
+    deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
+    addEntries();
+  }
+
+  /**
+   * Test targetattr behavior using userattr bind rule.
+   *
+   * @throws Exception  If a test result is unexpected.
+   */
+  @Test()
+  public void testTargetAttrUserAttr() throws Exception {
+    String aciLdif=makeAddAciLdif("aci", user1, userAttrAci);
+    modEntries(aciLdif, DIR_MGR_DN, PWD);
+    String userResults =
+            LDAPSearchParams(user3, PWD, null, null, null,
+                    user1, filter, attrList);
+    Assert.assertFalse(userResults.equals(""));
+    HashMap<String, String> attrMap=getAttrMap(userResults);
+    checkAttributeVal(attrMap, "l", "Austin");
+    checkAttributeVal(attrMap, "sn", "1");
+    checkAttributeVal(attrMap, "uid", "user.1");
+    deleteAttrFromEntry(user1, "aci");
+    String aciLdif1=makeAddAciLdif("aci", user1, userAttrAci1);
+    modEntries(aciLdif1, DIR_MGR_DN, PWD);
+    String userResults1 =
+            LDAPSearchParams(user3, PWD, null, null, null,
+                    user1, filter, attrList);
+    Assert.assertFalse(userResults1.equals(""));
+    HashMap<String, String> attrMap1=getAttrMap(userResults1);
+    checkAttributeVal(attrMap1, "l", "Austin");
+    checkAttributeVal(attrMap1, "sn", "1");
+    checkAttributeVal(attrMap1, "uid", "user.1");
+    deleteAttrFromEntry(user1, "aci");
+  }
+
+  /**
+   * Test targetattr and operational attribute behavior. See comments.
+   *
+   * @throws Exception If a test result is unexpected.
+   */
+  @Test()
+  public void testTargetAttrOpAttr() throws Exception {
+    //Add aci that only allows non-operational attributes search/read.
+    String aciLdif=makeAddAciLdif("aci", user1, nonOpAttrAci);
+    modEntries(aciLdif, DIR_MGR_DN, PWD);
+    String userResults =
+            LDAPSearchParams(user3, PWD, null, null, null,
+                    user1, filter, opAttrList);
+    Assert.assertFalse(userResults.equals(""));
+    HashMap<String, String> attrMap=getAttrMap(userResults);
+    //The aci attribute type is operational, it should not be there.
+    //The other two should be there.
+    Assert.assertFalse(attrMap.containsKey("aci"));
+    Assert.assertTrue(attrMap.containsKey("sn"));
+    Assert.assertTrue(attrMap.containsKey("uid"));
+    deleteAttrFromEntry(user1, "aci");
+    //Add aci that allows both non-operational attributes and the operational
+    //attribute "aci" search/read.
+    String aciLdif1=makeAddAciLdif("aci", user1, nonOpAttrAci, opAttrAci);
+    modEntries(aciLdif1, DIR_MGR_DN, PWD);
+    String userResults1 =
+            LDAPSearchParams(user3, PWD, null, null, null,
+                    user1, filter, opAttrList);
+    Assert.assertFalse(userResults1.equals(""));
+    HashMap<String, String> attrMap1=getAttrMap(userResults1);
+    //All three attributes should be there.
+    Assert.assertTrue(attrMap1.containsKey("aci"));
+    Assert.assertTrue(attrMap1.containsKey("sn"));
+    Assert.assertTrue(attrMap1.containsKey("uid"));
+    deleteAttrFromEntry(user1, "aci");
+    //Add ACI that only allows only aci operational attribute search/read.
+    String aciLdif2=makeAddAciLdif("aci", user1, opAttrAci);
+    modEntries(aciLdif2, DIR_MGR_DN, PWD);
+    String userResults2 =
+            LDAPSearchParams(user3, PWD, null, null, null,
+                    user1, aciFilter, opAttrList);
+    Assert.assertFalse(userResults2.equals(""));
+    HashMap<String, String> attrMap2=getAttrMap(userResults2);
+    //Only operational attribute aci should be there, the other two should
+    //not.
+    Assert.assertTrue(attrMap2.containsKey("aci"));
+    Assert.assertFalse(attrMap2.containsKey("sn"));
+    Assert.assertFalse(attrMap2.containsKey("uid"));
+    deleteAttrFromEntry(user1, "aci");
+  }
+
+  private void
+  checkAttributeVal(HashMap<String, String> attrMap, String attr,
+                      String val) throws Exception {
+    String mapVal=attrMap.get(attr);
+    Assert.assertTrue(mapVal.equals(val));
+  }
+
+}

--
Gitblit v1.10.0