From 14c5f3996a46c1281cb133de439f25492c97530a Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Wed, 07 Mar 2007 14:56:34 +0000
Subject: [PATCH] These changes are mostly related to restructuring the regular expression patterns to make them more readable by defining constants. 

---
 opends/src/server/org/opends/server/authorization/dseecompat/AciException.java                     |    4 
 opends/src/server/org/opends/server/authorization/dseecompat/IpCriteria.java                       |   13 
 opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java                        |   12 
 opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilters.java                  |  354 ++++++++
 opends/src/server/org/opends/server/authorization/dseecompat/UserDNTypeURL.java                    |    4 
 opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java               |   11 
 opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java                       |   50 
 opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java                      |    6 
 opends/src/server/org/opends/server/authorization/dseecompat/PermBindRulePair.java                 |    7 
 opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetKeyword.java                |    5 
 opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java                       |  179 +++-
 opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java                           |   13 
 opends/src/server/org/opends/server/authorization/dseecompat/EnumBooleanTypes.java                 |    3 
 opends/src/server/org/opends/server/authorization/dseecompat/AciBody.java                          |  168 +++-
 opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java |  145 ++-
 opends/src/server/org/opends/server/authorization/dseecompat/EnumRight.java                        |   27 
 opends/src/server/org/opends/server/authorization/dseecompat/DayOfWeek.java                        |    7 
 opends/src/server/org/opends/server/authorization/dseecompat/Aci.java                              |  187 ++++
 opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java                      |  170 ++++
 opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java                |   60 +
 opends/src/server/org/opends/server/authorization/dseecompat/EnumDayOfWeek.java                    |    3 
 opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetOperator.java               |    3 
 opends/src/server/org/opends/server/authorization/dseecompat/TargetFilter.java                     |   10 
 opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java                     |   37 
 opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleType.java                 |    3 
 opends/src/server/org/opends/server/authorization/dseecompat/EnumAuthMethod.java                   |    5 
 opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java                       |  153 +--
 opends/src/server/org/opends/server/authorization/dseecompat/EnumEvalResult.java                   |    1 
 opends/src/server/org/opends/server/authorization/dseecompat/EnumAccessType.java                   |    4 
 opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilterList.java               |  221 +++++
 opends/src/server/org/opends/server/authorization/dseecompat/EnumUserDNType.java                   |    1 
 opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java            |   14 
 opends/src/server/org/opends/server/authorization/dseecompat/AciList.java                          |    3 
 opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java                         |   69 +
 opends/src/server/org/opends/server/authorization/dseecompat/Permission.java                       |   25 
 opends/src/server/org/opends/server/authorization/dseecompat/Target.java                           |   41 
 opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java        |    5 
 opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java              |    6 
 opends/src/server/org/opends/server/authorization/dseecompat/DNS.java                              |   24 
 opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java                         |  111 +-
 opends/src/server/org/opends/server/authorization/dseecompat/AuthMethod.java                       |    8 
 opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java                          |   28 
 opends/src/server/org/opends/server/authorization/dseecompat/RoleDN.java                           |   31 
 43 files changed, 1,781 insertions(+), 450 deletions(-)

diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java b/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
index e881dd8..e29445b 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
@@ -37,6 +37,7 @@
  * The Aci class represents ACI strings.
  */
 public class Aci  {
+
     /*
      * The body of the ACI is the version, name and permission-bind rule
      * pairs.
@@ -53,6 +54,9 @@
      */
     public static final String supportedVersion="3.0";
 
+    /*
+     * String representation of the ACI used.
+     */
     private String aciString;
 
     /*
@@ -60,13 +64,191 @@
      */
     private DN dn;
 
+    /**
+     * Regular expression matching a word group.
+     */
+    public static final String WORD_GROUP="(\\w+)";
+
+    /**
+     * Regular expression matching a word group at the start of a
+     * pattern.
+     */
+    public static final String WORD_GROUP_START_PATTERN = "^" + WORD_GROUP;
+
+    /**
+     * Regular expression matching a white space.
+     */
+    public static final String ZERO_OR_MORE_WHITESPACE="\\s*";
+
+    /**
+     * Regular expression matching a white space at the start of a pattern.
+     */
+    public static final String ZERO_OR_MORE_WHITESPACE_START_PATTERN =
+                                             "^" + ZERO_OR_MORE_WHITESPACE ;
+
+    /**
+     * Regular expression matching a white space at the end of a pattern.
+     */
+    public static final String ZERO_OR_MORE_WHITESPACE_END_PATTERN =
+                                             ZERO_OR_MORE_WHITESPACE  + "$";
+
+    /**
+     * Regular expression matching a ACL statement separator.
+     */
+    public static final String ACI_STATEMENT_SEPARATOR =
+                ZERO_OR_MORE_WHITESPACE + ";" + ZERO_OR_MORE_WHITESPACE;
+
     /*
      * This regular expression is used to do a quick syntax check
      * when an ACI is being decoded.
      */
     private static final String aciRegex =
-            "^\\s*" + AciTargets.targetsRegex + "\\s*"+
-             AciBody.bodyRegx + "\\s*$";
+           ZERO_OR_MORE_WHITESPACE_START_PATTERN + AciTargets.targetsRegex +
+           ZERO_OR_MORE_WHITESPACE + AciBody.bodyRegx +
+           ZERO_OR_MORE_WHITESPACE_END_PATTERN;
+
+    /**
+     * Regular expression that graciously matches an attribute type name. Must
+     * begin with an ASCII letter or digit, and contain only ASCII letters,
+     * digit characters, hyphens, semi-colons and underscores.
+     * They are case insensitive.
+     */
+    public  static final String ATTR_NAME =
+              "((?i)[a-z\\d]{1}[[a-z]\\d-_.;]*(?-i))";
+
+    /**
+      * Regular expression matching a LDAP URL.
+      */
+     public  static final String LDAP_URL = ZERO_OR_MORE_WHITESPACE  +
+                                                 "(ldap:///[^\\|]+)";
+
+    /**
+     * Regular expression used to match token that joins expressions (||).
+     */
+    public static final String LOGICAL_OR = "\\|\\|";
+
+    /**
+     * Regular expression used to match an open parenthesis.
+     */
+    public static final String OPEN_PAREN = "\\(";
+
+    /**
+     * Regular expression used to match a closed parenthesis.
+     */
+    public static final String CLOSED_PAREN = "\\)";
+
+    /**
+     * Regular expression used to match a single equal sign.
+     */
+    public static final String EQUAL_SIGN = "={1}";
+
+    /**
+     * Regular expression the matches "*".
+     */
+    public static final String ALL_ATTRS_WILD_CARD = ZERO_OR_MORE_WHITESPACE +
+                                           "\\*" + ZERO_OR_MORE_WHITESPACE;
+
+    /**
+     * ACI_ADD is used to set the container rights for a LDAP add operation.
+     */
+    public static final int ACI_ADD = 0x0001;
+
+    /**
+     * ACI_DELETE is used to set the container rights for a LDAP
+     * delete operation.
+     */
+    public static final int ACI_DELETE = 0x0002;
+
+    /**
+     * ACI_READ is used to set the container rights for a LDAP
+     * search operation.
+     */
+    public static final int ACI_READ = 0x0004;
+
+    /**
+     * ACI_WRITE is used to set the container rights for a LDAP
+     * modify operation.
+     */
+    public static final int ACI_WRITE = 0x0008;
+
+    /**
+     * ACI_COMPARE is used to set the container rights for a LDAP
+     * compare operation.
+     */
+    public static final int ACI_COMPARE = 0x0010;
+
+    /**
+     * ACI_SEARCH is used to set the container rights a LDAP search operation.
+     */
+    public static final int ACI_SEARCH = 0x0020;
+
+    /**
+     * ACI_SELF is used for the SELFWRITE right. Currently not implemented.
+     */
+    public static final int ACI_SELF = 0x0040;
+
+    /**
+     * ACI_ALL is used to as a mask for all of the above. These
+     * six below are not masked by the ACI_ALL.
+     */
+    public static final int ACI_ALL = 0x007F;
+
+    /**
+     * ACI_PROXY is used for the PROXY right. Currently not used.
+     */
+    public static final int ACI_PROXY = 0x0080;
+
+    /**
+     * ACI_IMPORT is used to set the container rights for a LDAP
+     * modify dn operation. Currently not used.
+     */
+    public static final int ACI_IMPORT = 0x0100;
+
+    /**
+     * ACI_EXPORT is used to set the container rights for a LDAP
+     * modify dn operation. Currently not used.
+     */
+    public static final int ACI_EXPORT = 0x0200;
+
+    /**
+     * ACI_WRITE_ADD is used by the LDAP modify operation.
+     */
+    public static final int ACI_WRITE_ADD = 0x800;
+
+    /**
+     * ACI_WRITE_DELETE is used by the LDAP modify operation.
+     */
+    public static final int ACI_WRITE_DELETE = 0x400;
+
+    /**
+     * TARGATTRFILTER_ADD is used to specify that a
+     * targattrfilters ADD operation was seen in the ACI. For example,
+     * given an ACI with:
+     *
+     * (targattrfilters="add=mail:(mail=*@example.com)")
+     *
+     * The TARGATTRFILTERS_ADD flag would be set during ACI parsing in the
+     * TargAttrFilters class.
+     */
+    public static final int TARGATTRFILTERS_ADD = 0x1000;
+
+    /**
+     * TARGATTRFILTER_DELETE is used to specify that a
+     * targattrfilters DELETE operation was seen in the ACI. For example,
+     * given an ACI with:
+     *
+     * (targattrfilters="del=mail:(mail=*@example.com)")
+     *
+     * The TARGATTRFILTERS_DELETE flag would be set during ACI parsing in the
+     * TargAttrFilters class.
+     */
+    public static final int TARGATTRFILTERS_DELETE = 0x2000;
+
+    /**
+     * ACI_NULL is used to set the container rights to all zeros. Used
+     * by LDAP modify.
+     */
+    public static final int ACI_NULL = 0x0000;
 
     /**
      * Construct a new Aci from the provided arguments.
@@ -158,6 +340,7 @@
     isApplicable(Aci aci, AciTargetMatchContext matchCtx) {
         return AciTargets.isTargetApplicable(aci, matchCtx) &&
                 AciTargets.isTargetFilterApplicable(aci, matchCtx) &&
+                AciTargets.isTargAttrFiltersApplicable(aci, matchCtx) &&
                 AciTargets.isTargetAttrApplicable(aci, matchCtx);
     }
 
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciBody.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciBody.java
index dd0c1e5..c5119e5 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciBody.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciBody.java
@@ -28,6 +28,7 @@
 package org.opends.server.authorization.dseecompat;
 
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
 import java.util.ArrayList;
 import java.util.List;
@@ -40,57 +41,120 @@
  */
 public class AciBody {
 
+    /*
+     * Regular expression group position for the version string.
+     */
     private static final int VERSION = 1;
+
+    /*
+     * Regular expression group position for the namr string.
+     */
     private static final int NAME = 2;
+
+    /*
+     * Regular expression group position for the permission string.
+     */
     private static final int PERM = 1;
+
+    /*
+     * Regular expression group position for the rights string.
+     */
     private static final int RIGHTS = 2;
+
+    /*
+     * Regular expression group position for the bindrule string.
+     */
     private static final int BINDRULE = 3;
+
+    /*
+     * Index into the ACI string where the ACI body starts.
+     */
     private int startPos=0;
+
     /*
-     * The name of the ACI, currently not used but parsed.
-     */
+    * The name of the ACI, currently not used but parsed.
+    */
     private String name = null;
+
     /*
-     * The version of the ACi, current not used but parsed and checked
-     * for 3.0.
-     */
+    * The version of the ACi, current not used but parsed and checked
+    * for 3.0.
+    */
     private String version = null;
+
     /*
      This structure represents a permission-bind rule pairs. There can be
      several of these.
     */
     private List<PermBindRulePair> permBindRulePairs;
+
     /*
-     * TODO Define constants for these regular expressions to make them more
-     * readable.
-     * The regular expressions would probably be a lot easier
-     * to understand if you defined a number of constants for the
-     * individual components and then concatenated them.  For example,
-     * "\\s*" could be defined in a constant named ZERO_OR_MORE_SPACES.
-     * This would also help make it easier to understand which parentheses
-     * were part of the regex and which were part of the ACI syntax.
+     * Regular expression used to match the access type group (allow, deny) and
+     * the rights group "(read, write, ...)". The last pattern looks for a group
+     * surrounded by parenthesis. The group must contain at least one
+     * non-paren character.
      */
-    private static final String permissionRegex = "(\\w+)\\s*\\(([^()]+)\\)";
-    private static final String bindRuleRegex = "(.+?\"[)]*)\\s*;";
+    private static final
+    String permissionRegex =
+               WORD_GROUP + ZERO_OR_MORE_WHITESPACE + "\\(([^()]+)\\)";
+
+    /*
+     * Regular expression that matches a bind rule group at a coarse level. It
+     * matches any character one or more times, a single quotation and
+     * an optional right parenthesis.
+     */
+    private static final String bindRuleRegex =
+            "(.+?\"[)]*)" + ACI_STATEMENT_SEPARATOR;
+
+    /*
+     * Regular expression used to match the actions of the ACI. The actions
+     * are permissions and matching bind rules.
+     */
     private static final String actionRegex =
-            "\\s*" + permissionRegex + "\\s*" + bindRuleRegex;
+            ZERO_OR_MORE_WHITESPACE + permissionRegex +
+            ZERO_OR_MORE_WHITESPACE + bindRuleRegex;
+
+    /*
+     * Regular expression used to match the version value (digit.digit).
+     */
     private static final String versionRegex = "(\\d\\.\\d)";
-    private static final String versionToken = "(?i)version";
-    private static final String aclToken = "(?i)acl";
+
+    /*
+     * Regular expression used to match the version token. Case insensitive.
+     */
+    private static final String versionToken = "(?i)version(?-i)";
+
+    /*
+     * Regular expression used to match the acl token. Case insensitive.
+     */
+    private static final String aclToken = "(?i)acl(?-i)";
+
     /**
-     * Regular expression used to parse the body of an ACI.
+     * Regular expression used to match the body of an ACI. This pattern is
+     * a general verification check.
      */
     public static final String bodyRegx =
-        "\\(\\s*" + versionToken + "\\s*"
-        + versionRegex + "\\s*;\\s*" + aclToken + "\\s*\"(.*)\"\\s*;\\s*"
-        + actionRegex + "\\s*\\)";
-    /**
-     * Regular expression used to parse the header of the ACI body. The
+        "\\(" + ZERO_OR_MORE_WHITESPACE + versionToken +
+        ZERO_OR_MORE_WHITESPACE + versionRegex +
+        ACI_STATEMENT_SEPARATOR + aclToken + ZERO_OR_MORE_WHITESPACE +
+        "\"(.*)\"" + ACI_STATEMENT_SEPARATOR + actionRegex +
+        ZERO_OR_MORE_WHITESPACE  + "\\)";
+
+        public static final String bodyRegx1 =
+        "\\("+ Aci.ZERO_OR_MORE_WHITESPACE + versionToken +
+        Aci.ZERO_OR_MORE_WHITESPACE + versionRegex +
+        Aci.ACI_STATEMENT_SEPARATOR + aclToken + Aci.ZERO_OR_MORE_WHITESPACE +
+        "\"(.*)\"" + Aci.ACI_STATEMENT_SEPARATOR + actionRegex +
+        Aci.ZERO_OR_MORE_WHITESPACE  + "\\)";
+    /*
+     * Regular expression used to match the header of the ACI body. The
      * header is version and acl name.
      */
-    public static final String header =
-        "\\(\\s*" + versionToken + "\\s*"
-        + versionRegex + "\\s*;\\s*" + aclToken + "\\s*\"(.*?)\"\\s*;";
+    private static final String header =
+       OPEN_PAREN + ZERO_OR_MORE_WHITESPACE + versionToken +
+       ZERO_OR_MORE_WHITESPACE +
+       versionRegex + ACI_STATEMENT_SEPARATOR + aclToken +
+       ZERO_OR_MORE_WHITESPACE +  "\"(.*?)\"" + ACI_STATEMENT_SEPARATOR;
 
     /**
      * Construct an ACI body from the specified version, name and
@@ -128,7 +192,7 @@
         if(bodyMatcher.find()) {
             startPos=bodyMatcher.start();
             version  = bodyMatcher.group(VERSION);
-            if (!version.equalsIgnoreCase(Aci.supportedVersion)) {
+            if (!version.equalsIgnoreCase(supportedVersion)) {
                 int msgID = MSGID_ACI_SYNTAX_INVAILD_VERSION;
                 String message = getMessage(msgID, version);
                 throw new AciException(msgID, message);
@@ -203,9 +267,6 @@
         return startPos;
     }
 
-    //TODO Evaluate adding support for the "absolute" deny access
-    //     type precedence operator.
-
     /**
      * Performs an evaluation of the permission-bind rule pairs
      * using the evaluation context. The method walks down
@@ -226,29 +287,32 @@
         EnumEvalResult res=EnumEvalResult.FALSE;
         List<PermBindRulePair>pairs=getPermBindRulePairs();
         for(PermBindRulePair p : pairs) {
+            if(evalCtx.isDenyEval() &&
+                    (p.hasAccessType(EnumAccessType.ALLOW)))
+                continue;
             if(!p.hasRights(evalCtx.getRights()))
                 continue;
-           res=p.getBindRule().evaluate(evalCtx);
-           // The evaluation result could be FAIL. Stop processing and return
-           //FAIL. Maybe an internal search failed.
-           if((res != EnumEvalResult.TRUE) &&
-              (res != EnumEvalResult.FALSE)) {
-               res=EnumEvalResult.FAIL;
-               break;
-           //If the access type is DENY and the pair evaluated to TRUE,
-           //then stop processing and return TRUE. A deny pair
-           //succeeded.
-           } else if((p.hasAccessType(EnumAccessType.DENY)) &&
-                     (res == EnumEvalResult.TRUE)) {
-               res=EnumEvalResult.TRUE;
-               break;
-           //An allow access type evaluated TRUE, stop processing
-           //and return TRUE.
-           } else if((p.hasAccessType(EnumAccessType.ALLOW) &&
-                     (res == EnumEvalResult.TRUE))) {
-               res=EnumEvalResult.TRUE;
-               break;
-           }
+            res=p.getBindRule().evaluate(evalCtx);
+            // The evaluation result could be FAIL. Stop processing and return
+            //FAIL. Maybe an internal search failed.
+            if((res != EnumEvalResult.TRUE) &&
+                    (res != EnumEvalResult.FALSE)) {
+                res=EnumEvalResult.FAIL;
+                break;
+                //If the access type is DENY and the pair evaluated to TRUE,
+                //then stop processing and return TRUE. A deny pair
+                //succeeded.
+            } else if((p.hasAccessType(EnumAccessType.DENY)) &&
+                    (res == EnumEvalResult.TRUE)) {
+                res=EnumEvalResult.TRUE;
+                break;
+                //An allow access type evaluated TRUE, stop processing
+                //and return TRUE.
+            } else if((p.hasAccessType(EnumAccessType.ALLOW) &&
+                    (res == EnumEvalResult.TRUE))) {
+                res=EnumEvalResult.TRUE;
+                break;
+            }
         }
         return res;
     }
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
index 0a32315..498f52a 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -104,6 +104,11 @@
      */
     private Operation operation;
 
+    /*
+     * True if a targattrfilters match was found.
+     */
+    private boolean targAttrFiltersMatch=false;
+
     /**
      * This constructor is used by all currently supported LDAP operations.
      *
@@ -305,6 +310,7 @@
     public void setRights(int rights) {
          this.rights=rights;
     }
+
     /**
      * Gets the hostname of the remote client.
      * @return  Cannonical hostname of remote client.
@@ -322,7 +328,7 @@
     }
 
     /**
-     * Return true if this is an add operation.
+     * Return true if the current operation is a LDAP add operation.
      * @return True if this is an add operation.
      */
     public boolean isAddOperation() {
@@ -330,13 +336,32 @@
     }
 
     /**
-     * Tries to determine the authentication information from the connection
-     * class. The checks are for simple and SASL, anything else is not a
-     * match. If the bind rule needs the SSL client flag then that needs
-     * to be set. This code is used by the authmethod bind rule keyword.
+     * Set to true  if the ACI had a targattrfilter rule that matched.
+     * @param v  The value to use.
+     */
+    public void setTargAttrFiltersMatch(boolean v) {
+        this.targAttrFiltersMatch=v;
+    }
+
+    /**
+     * Return the value of the targAttrFiltersMatch variable. This is set to
+     * true if the ACI had a targattrfilter rule that matched.
+     * @return  True if the ACI had a targattrfilter rule that matched.
+     */
+    public boolean getTargAttrFiltersMatch() {
+        return targAttrFiltersMatch;
+    }
+
+    /**
+     * Try to determine the authentication information from the current
+     * client connection. The checks are for simple and SASL, anything else
+     * is not a match. If the bind rule requires any SSL client authentication
+     * information then the "wantSSL" flag should be set. This code is used by
+     * the authmethod bind rule keyword.
+     *
      * @param wantSSL True if the bind rule needs the ssl client auth check.
      * @return  Return an enumeration containing the authentication method
-     * for this connection.
+     * type for this client connection.
      */
     public EnumAuthMethod getAuthenticationMethod(boolean wantSSL) {
         EnumAuthMethod method=EnumAuthMethod.AUTHMETHOD_NOMATCH;
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciException.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciException.java
index 49e4e5e..924a960 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciException.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciException.java
@@ -45,7 +45,9 @@
    */
   private static final long serialVersionUID = -2763328522960628853L;
 
-    // The unique message ID for the associated message.
+    /*
+     * The unique message ID for the associated message.
+     */
     private int messageID;
 
     /**
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
index 2ccd972..6341904 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -29,20 +29,11 @@
 
 import org.opends.server.api.AccessControlHandler;
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import org.opends.server.core.*;
 import static org.opends.server.loggers.Error.logError;
 import static org.opends.server.messages.MessageHandler.getMessage;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ErrorLogCategory;
-import org.opends.server.types.ErrorLogSeverity;
-import org.opends.server.types.Modification;
-import org.opends.server.types.Privilege;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchResultReference;
+import org.opends.server.types.*;
 import static org.opends.server.util.StaticUtils.toLowerCase;
 import java.util.LinkedList;
 import java.util.List;
@@ -54,87 +45,6 @@
  */
 public class AciHandler extends AccessControlHandler
 {
-
-
-    /**
-     * ACI_ADD is used to set the container rights for a LDAP add operation.
-     */
-    public static final int ACI_ADD = 0x0001;
-
-    /**
-     * ACI_DELETE is used to set the container rights for a LDAP
-     * delete operation.
-     */
-    public static final int ACI_DELETE = 0x0002;
-
-    /**
-     * ACI_READ is used to set the container rights for a LDAP
-     * search operation.
-     */
-    public static final int ACI_READ = 0x0004;
-
-    /**
-     * ACI_WRITE is used to set the container rights for a LDAP
-     * modify operation.
-     */
-    public static final int ACI_WRITE = 0x0008;
-
-    /**
-     * ACI_COMPARE is used to set the container rights for a LDAP
-     * compare operation.
-     */
-    public static final int ACI_COMPARE = 0x0010;
-
-    /**
-     * ACI_SEARCH is used to set the container rights a LDAP search operation.
-     */
-    public static final int ACI_SEARCH = 0x0020;
-
-    /**
-     * ACI_SELF is used for the SELFWRITE right. Currently not implemented.
-     */
-    public static final int ACI_SELF = 0x0040;
-
-    /**
-     * ACI_ALL is used to as a mask for all of the above. These
-     * six below are not masked by the ACI_ALL.
-     */
-    public static final int ACI_ALL = 0x007F;
-
-    /**
-     * ACI_PROXY is used for the PROXY right. Currently not implemented.
-     */
-    public static final int ACI_PROXY = 0x0080;
-
-    /**
-     * ACI_IMPORT is used to set the container rights for a LDAP
-     * modify dn operation. Currently not implemented.
-     */
-    public static final int ACI_IMPORT = 0x0100;
-
-    /**
-     * ACI_EXPORT is used to set the container rights for a LDAP
-     * modify dn operation. Currently not implemented.
-     */
-    public static final int ACI_EXPORT = 0x0200;
-
-    /**
-     * ACI_WRITE_ADD and ACI_WRITE_DELETE are used by the LDAP modify
-     * operation. They currently don't have much value; but will be needed
-     * once the targetattrfilters target and modify dn are implemented.
-     */
-    public static final int ACI_WRITE_ADD = 0x800;
-    /**
-     * See above.
-     */
-    public static final int ACI_WRITE_DELETE = 0x400;
-
-    /**
-     * ACI_NULL is used to set the container rights to all zeros. Used
-     * by LDAP modify.
-     */
-    public static final int ACI_NULL = 0x0000;
-
     /*
      * The list that holds that ACIs keyed by the DN of the entry
       * holding the ACI.
@@ -511,6 +421,39 @@
     }
 
     /**
+     * Test the attribute types of the search filter for access. This method
+     * supports the search right.
+     *
+     * @param container  The container used in the access evaluation.
+     * @param filter The filter to check access on.
+     * @return  True if all attribute types in the filter have access.
+     */
+    private boolean
+    testFilter(AciLDAPOperationContainer container, SearchFilter filter) {
+        boolean ret=true;
+        switch (filter.getFilterType()) {
+            case AND:
+            case OR: {
+                for (SearchFilter f : filter.getFilterComponents())
+                    if(!testFilter(container, f))
+                        return false ;
+                break;
+            }
+            case NOT:  {
+                SearchFilter f = filter.getNotComponent();
+                ret=!testFilter(container, f);
+                break;
+            }
+            default: {
+                AttributeType attrType=filter.getAttributeType();
+                container.setCurrentAttributeType(attrType);
+                ret=accessAllowed(container);
+            }
+        }
+        return ret;
+    }
+
+    /**
      * Evaluate an entry to be added to see if it has any "aci"
      * attribute type. If it does, examines each "aci" attribute type
      * value for syntax errors. All of the "aci" attribute type values
@@ -657,19 +600,6 @@
                           skipAccessCheck(operation));
   }
 
-
-  /*
-   * TODO Add access testing of the filter against the entry. This was
-   * brought up in the first code review.
-   *
-   *  The static block that creates the arrays of EnumRight objects needs to
-   *  be documented to explain what they are.  Also, I still disagree with
-   *  the  interpretation that the READ right is all that is necessary to
-   *  perform either search or compare operations.  That definitely goes
-   *  against the documentation, which states that READ applies only to
-   *  the search operation, and that users must have both SEARCH and READ
-   *  in order to access the results.
-   */
   /**
    * Checks access on a search operation.
    * @param operation The search operation class containing information to
@@ -681,9 +611,16 @@
   maySend(SearchOperation operation, SearchResultEntry entry) {
       AciLDAPOperationContainer operationContainer =
               new AciLDAPOperationContainer(operation,
-                                           (ACI_READ | ACI_SEARCH), entry);
-      return skipAccessCheck(operation) ||
-              accessAllowedEntry(operationContainer);
+                      (ACI_SEARCH), entry);
+      boolean ret;
+      if(!(ret=skipAccessCheck(operation))) {
+          ret=testFilter(operationContainer, operation.getFilter());
+          if (ret) {
+              operationContainer.setRights(ACI_READ);
+              ret=accessAllowedEntry(operationContainer);
+          }
+      }
+      return ret;
   }
 
   /*
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
index 126eeb0..30b9560 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
@@ -44,16 +44,17 @@
  */
 public class AciLDAPOperationContainer extends AciContainer  {
 
-    /**
+    /*
      * The entry to be returned if this is a LDAP search.
      */
     private SearchResultEntry searchEntry;
 
-    /**
+    /*
      * The list of modifications if this operation is a LDAP
      * modify.
      */
     private List<Modification>  modifications;
+
     /**
      * Constructor interface for the compare operation.
      * @param operation The compare operation to evaluate.
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
index de2c477..90cfdfe 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
@@ -49,7 +49,8 @@
  * using the entry DN as the key.
  */
 public class AciList {
-  /**
+
+  /*
    * A map containing all the ACIs.
    * We use the copy-on-write technique to avoid locking when reading.
    */
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
index f8f1eb5..3690dee 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
@@ -54,13 +54,17 @@
 public class AciListenerManager
         implements ChangeNotificationListener, BackendInitializationListener {
 
-
+    /*
+     * The AciList caches the ACIs.
+     */
     private AciList aciList;
-       /*
+
+    /*
      * Search filter used in context search for "aci" attribute types.
      */
     private static SearchFilter aciFilter;
-    /**
+
+    /*
      * The aci attribute type is operational so we need to specify it to be
      * returned.
      */
@@ -77,6 +81,7 @@
         }
         attrs.add("aci");
     }
+
     /**
      * Save the list created by the AciHandler routine.
      * @param aciList The list object created and loaded by the handler.
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java
index db9aa81..d75ac45 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java
@@ -364,10 +364,10 @@
     /**
      * The message ID for the message that will be used if an "aci" attribute
      * type value failed parsing because of an invalid target keyword operator.
-     * This takes one argument, which is the target keyword operator string
-     * parsed from the "aci" attribute type value string.
+     * This takes two arguments, which  are the target keyword operator string
+     * parsed from the "aci" attribute type value string and the keyword string.
      */
-    public static final int MSGID_ACI_SYNTAX_INVALID_TARGET_OPERATOR =
+    public static final int MSGID_ACI_SYNTAX_INVALID_TARGET_NOT_OPERATOR =
         CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 35;
 
     /**
@@ -392,11 +392,11 @@
 
     /**
      * The message ID for the message that will be used if an "aci" attribute
-     * type value failed parsing because of an invalid targetscope keyword
-     * operator. This takes one argument, which is the targetscope keyword
+     * type value failed parsing because of an invalid target keyword
+     * operator. This takes one argument, which is the target keyword
      * operator string parsed from the "aci" attribute type value string.
      */
-    public static final int MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_OPERATOR =
+    public static final int MSGID_ACI_SYNTAX_INVALID_TARGETS_OPERATOR =
         CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 38;
 
     /**
@@ -528,6 +528,88 @@
     public static
     final int MSGID_ACI_SYNTAX_INVALID_USERATTR_ROLEDN_INHERITANCE_PATTERN =
         CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 51;
+
+   /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a targattrfilters keyword expression
+     * did not parse because the operation was invalid.  This takes two
+     * arguments, which are the targattrfilters expression parsed from the ACI
+     * and a message further clarifying the error.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_OPERATION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 52;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a targattrfiltesr keyword expression
+     * did not parse.  This takes one argument, which is the targattrfilters
+     * expression parsed from the ACI.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_EXPRESSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 53;
+
+      /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because the operation tokens targattrfilters
+     * in the expresssion are the same.  This takes one argument, which is
+     * the targattrfilters expression parsed from the ACI.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_OPS_MATCH =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 54;
+
+    /**
+    * The message ID for the message that will be used if an "aci" attribute
+    * type value parse failed because the there are two many targattrfilters
+    * filter list statements in the ACI.  This takes one argument, which is
+    * the targattrfilters expression parsed from the ACI.
+    */
+   public static
+   final int MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_MAX_FILTER_LISTS =
+       CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 55;
+
+  /**
+    * The message ID for the message that will be used if an "aci" attribute
+    * type value parse failed because the targattrfilters expression statement
+    * is in the wrong format.  This takes one argument, which is
+    * the targattrfilters expression parsed from the ACI.
+    */
+   public static
+   final int MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LIST_FORMAT =
+       CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 56;
+
+    /**
+      * The message ID for the message that will be used if an "aci" attribute
+      * type value parse failed because one or more targattrfilters filter
+      * statements are invalid.  This takes two arguments, which are
+      * the targattrfilters expression parsed from the ACI and an error
+      * message from the createFilterFromString method.
+      */
+     public static
+     final int MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LISTS_FILTER =
+         CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 57;
+
+     /**
+      * The message ID for the message that will be used if an "aci" attribute
+      * type value parse failed because one or more targattrfilters filter
+      * statements contain invalid attribute type names.  This takes one
+      * argument, which is the targattrfilters expression parsed from the ACI.
+      */
+     public static final
+        int MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LISTS_ATTR_FILTER =
+         CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 58;
+
+     /**
+      * The message ID for the message that will be used if an "aci" attribute
+      * type name is invalid.  This takes one
+      * argument, which is the attribute type name parsed from the ACI.
+      */
+     public static final
+        int MSGID_ACI_SYNTAX_INVALID_ATTRIBUTE_TYPE_NAME =
+         CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 59;
+
     /**
      * Associates a set of generic messages with the message IDs defined in
      * this class.
@@ -559,7 +641,7 @@
                 "The provided Access Control Instruction (ACI) rights " +
                 "keyword values \"%s\" are invalid. The valid rights " +
                 "keyword values are one or more of the following: read, " +
-                "write, add, delete, search, compare or the single value" +
+                "write, add, delete, search, compare or the single value " +
                 "all.");
 
         registerMessage(MSGID_ACI_SYNTAX_BIND_RULE_MISSING_CLOSE_PAREN,
@@ -733,7 +815,7 @@
                 " value is one of the following: target, targetscope, " +
                 "targetfilter, targetattr or targetattrfilters.");
 
-        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGET_OPERATOR,
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGETS_OPERATOR,
                 "The provided Access Control Instruction (ACI) target " +
                 "keyword operator value  \"%s\" is invalid. A valid target" +
                 "keyword operator value is either '=' or \"!=\".");
@@ -747,10 +829,10 @@
                 "target keyword value \"%s\" was seen multiple times in" +
                 " the ACI \"%s\".");
 
-        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_OPERATOR,
-                "The provided Access Control Instruction (ACI) targetscope" +
-                " keyword operator value \"%s\" is invalid. The only valid" +
-                "targetscope operator value is '='.");
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGET_NOT_OPERATOR,
+                "The provided Access Control Instruction (ACI) target" +
+                " operator value \"%s\" is invalid. The only valid" +
+                "target operator value for the \"%s\" keyword is '='.");
 
         registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_EXPRESSION,
                 "The provided Access Control Instruction (ACI) targetscope" +
@@ -775,7 +857,7 @@
                 "The provided Access Control Instruction (ACI) " +
                 "targetattr expression value \"%s\" is invalid. A valid " +
                 "targetattr keyword expression value requires one or more " +
-                "attribute type values in the following format: " +
+                "valid attribute type names in the following format: " +
                 "attribute1 [|| attribute1] ... [|| attributen].");
 
         registerMessage(
@@ -823,5 +905,67 @@
                 "userattr expression inheritance pattern value " +
                 "\"%s\" is invalid for the roledn keyword because it starts " +
                         "with the string \"parent[\".");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_OPERATION,
+                "The provided Access Control Instruction (ACI) " +
+                "targattrfilter expression value " +
+                "%s is invalid because %s.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_EXPRESSION,
+                "The provided Access Control Instruction (ACI) " +
+                "targattrfilter expression value " +
+                "%s is invalid because it is not in the correct format." +
+                "A valid targattrsfilters expression value must be in " +
+                "the following format: "+
+               "\"add=attr1: F1 && attr2: F2 ... && attrn: Fn" +
+                ",del= attr1: F1 && attr2: F2 ... && attrn: Fn\"");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_OPS_MATCH,
+                "The provided Access Control Instruction (ACI) " +
+                   "targattrfilter expression value " +
+                   "%s is invalid because the both operation tokens " +
+                   "match in the two filter lists.");
+
+        registerMessage(
+                MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_MAX_FILTER_LISTS,
+                "The provided Access Control Instruction (ACI) " +
+                     "targattrfilters expression value " +
+                     "%s is invalid because there are more than two" +
+                      "filter list statements.");
+
+        registerMessage(
+                MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LIST_FORMAT,
+                "The provided Access Control Instruction (ACI) " +
+                "targattrfilters expression value " +
+                "%s is invalid because the provided filter list string " +
+                "is in the wrong format. A valid targattrfilters filter " +
+                "list must be in the following format: " +
+                "add=attr1: F1 && attr2: F2 ... && attrn: Fn .");
+
+        registerMessage(
+             MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LISTS_FILTER,
+             "The provided Access Control Instruction (ACI) " +
+             "targattrfilters expression value " +
+             "%s is invalid because the one or more of the specified" +
+             "filters are invalid for the following reason: " +
+             "%s.");
+
+        registerMessage(
+             MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LISTS_ATTR_FILTER,
+             "The provided Access Control Instruction (ACI) " +
+             "targattrfilters expression value " +
+             "%s is invalid because the one or more of the specified" +
+             "filters are invalid because of non-matching attribute" +
+             "type names in the filter.");
+
+        registerMessage(
+             MSGID_ACI_SYNTAX_INVALID_ATTRIBUTE_TYPE_NAME,
+             "The provided Access Control Instruction (ACI) " +
+             "attribute name value " +
+             "%s is invalid. A valid attribute type name must begin " +
+             "with an ASCII letter and must contain only ASCII letters," +
+              "digits or the \"-\" character.");
+
+
     }
 }
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java
index 105f224..be0478b 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java
@@ -38,11 +38,13 @@
  */
 public class AciProvider  implements AccessControlProvider  {
 
-
+    /*
+     * The AciHandler does all the work in this package.
+     */
     private static AciHandler instance = null;
 
     /**
-     * Create an aci provider. This doesn't do much.
+     * Create an aci provider.
      */
     public AciProvider() {
         super();
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
index 833309d..7fdb608 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
@@ -41,6 +41,7 @@
  * checked on.
  */
 public interface AciTargetMatchContext {
+
     /**
      * Set the deny ACI list.
      * @param denyList The deny ACI list.
@@ -129,6 +130,19 @@
      * @param rights The rights to set the container's rights to.
      */
     public void setRights(int rights);
+
+    /**
+     * Set to true  if the ACI had a targattrfilter rule that matched.
+     * @param v  The value to use.
+     */
+    public void setTargAttrFiltersMatch(boolean v);
+
+    /**
+     * Return the value of the targAttrFiltersMatch variable. This is set to
+     * true if the ACI had a targattrfilter rule that matched.
+     * @return  True if the ACI had a targattrfilter rule that matched.
+     */
+    public boolean getTargAttrFiltersMatch();
 }
 
 
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
index f21ac6e..8c90b10 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
@@ -28,6 +28,7 @@
 package org.opends.server.authorization.dseecompat;
 
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.DN;
@@ -40,47 +41,75 @@
  * of an ACI before the ACI body and specifies the entry, attributes, or set
  * of entries and attributes which the ACI controls access.
  *
- * The four supported  ACI target keywords currently
- * supported are: target, targetattr, targetscope and targetfilter.
- * Missing is support for targetattrfilters.
+ * The five supported  ACI target keywords are: target, targetattr,
+ * targetscope, targetfilter and targattrfilters.
  */
 public class AciTargets {
+
     /*
      * ACI syntax has a target keyword.
      */
     private Target target = null ;
+
     /*
      * ACI syntax has a targetscope keyword.
      */
     private SearchScope targetScope = SearchScope.WHOLE_SUBTREE;
+
     /*
      * ACI syntax has a targetattr keyword.
      */
     private TargetAttr targetAttr = null ;
+
     /*
      * ACI syntax has a targetfilter keyword.
      */
     private TargetFilter targetFilter=null;
 
-    private TargAttrFilters targAttrFilters=null;
     /*
-     * These are used in the regular expression parsing.
+     * ACI syntax has a targattrtfilters keyword.
+     */
+    private TargAttrFilters targAttrFilters=null;
+
+    /*
+     * The number of regular expression group positions in a valid ACI target
+     * expression.
      */
     private static final int targetElementCount = 3;
-    private static final int targetKeywordPos       = 1;
-    private static final int targetOperatorPos      = 2;
-    private static final int targetExpressionPos    = 3;
+
     /*
-     * TODO Make the regular expression strings below easier to
-     * understand.
-     *
-     * The same note earlier about making regex values easier to
-     * understand applies to this class as well.
+     *  Regular expression group position of a target keyword.
+     */
+    private static final int targetKeywordPos       = 1;
+
+    /*
+     *  Regular expression group position of a target operator enumeration.
+     */
+    private static final int targetOperatorPos      = 2;
+
+    /*
+     *  Regular expression group position of a target expression statement.
+     */
+    private static final int targetExpressionPos    = 3;
+
+    /*
+     * Regular expression used to match a single target rule.
      */
     private static final String targetRegex =
-            "\\(\\s*(\\w+)\\s*(!?=)\\s*\"([^\"]+)\"\\s*\\)\\s*";
+           OPEN_PAREN +  ZERO_OR_MORE_WHITESPACE  +  WORD_GROUP +
+           ZERO_OR_MORE_WHITESPACE + "(!?=)" + ZERO_OR_MORE_WHITESPACE +
+           "\"([^\"]+)\"" + ZERO_OR_MORE_WHITESPACE + CLOSED_PAREN +
+           ZERO_OR_MORE_WHITESPACE;
+
+    private static final String targetRegex1 =
+           "\\(" +  Aci.ZERO_OR_MORE_WHITESPACE  +  Aci.WORD_GROUP +
+           Aci.ZERO_OR_MORE_WHITESPACE + "(!?=)" + Aci.ZERO_OR_MORE_WHITESPACE +
+           "\"([^\"]+)\"" + Aci.ZERO_OR_MORE_WHITESPACE + "\\)" +
+           Aci.ZERO_OR_MORE_WHITESPACE;
+
     /**
-    * Regular expression used in target matching.
+    * Regular expression used to match one or more target rules. The patern is
+    * part of a general ACI verification.
     */
     public static final String targetsRegex = "(" + targetRegex + ")*";
 
@@ -106,8 +135,7 @@
      *  for this ACI.
      */
 
-    private static final int skipRights =
-            (AciHandler.ACI_ADD | AciHandler.ACI_DELETE | AciHandler.ACI_PROXY);
+    private static final int skipRights = (ACI_ADD | ACI_DELETE | ACI_PROXY);
 
     /**
      * Creates an ACI target from the specified arguments. All of these
@@ -116,14 +144,17 @@
      * @param targetAttr The ACI targetattr keyword if any.
      * @param targetFilter The ACI targetfilter keyword if any.
      * @param targetScope The ACI targetscope keyword if any.
+     * @param targAttrFilters The ACI targAttrFilters keyword if any.
      */
     private AciTargets(Target targetEntry, TargetAttr targetAttr,
                        TargetFilter targetFilter,
-                       SearchScope targetScope) {
+                       SearchScope targetScope,
+                       TargAttrFilters targAttrFilters) {
        this.target=targetEntry;
        this.targetAttr=targetAttr;
        this.targetScope=targetScope;
        this.targetFilter=targetFilter;
+       this.targAttrFilters=targAttrFilters;
     }
 
     /**
@@ -162,6 +193,14 @@
     }
 
     /**
+     * Return the class representing the ACI targattrfilters keyword. May be
+     * null.
+     * @return The targattrfilters information.
+     */
+    public TargAttrFilters getTargAttrFilters() {
+        return targAttrFilters;
+    }
+    /**
      * Decode an ACI's target part of the syntax from the string provided.
      * @param input String representing an ACI target part of syntax.
      * @param dn The DN of the entry containing the ACI.
@@ -197,7 +236,7 @@
             EnumTargetOperator targetOperator =
                 EnumTargetOperator.createOperator(operator);
             if (targetOperator == null) {
-                int msgID = MSGID_ACI_SYNTAX_INVALID_TARGET_OPERATOR;
+                int msgID = MSGID_ACI_SYNTAX_INVALID_TARGETS_OPERATOR;
                 String message = getMessage(msgID, operator);
                 throw new AciException(msgID, message);
             }
@@ -238,7 +277,7 @@
             {
                 // Check the operator for the targetscope is EQUALITY
                 if (targetOperator == EnumTargetOperator.NOT_EQUALITY) {
-                    int msgID = MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_OPERATOR;
+                    int msgID = MSGID_ACI_SYNTAX_INVALID_TARGET_NOT_OPERATOR;
                     String message = getMessage(msgID, operator);
                     throw new AciException(msgID, message);
                 }
@@ -253,31 +292,39 @@
                 }
                 else {
                     int msgID =
-                        MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS;
+                            MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS;
                     String message =
-                        getMessage(msgID, "targetfilter", input);
+                            getMessage(msgID, "targetfilter", input);
                     throw new AciException(msgID, message);
                 }
                 break;
             }
-                case KEYWORD_TARGATTRFILTERS:
-                {
-                    if (targAttrFilters == null){
-                        targAttrFilters = TargAttrFilters.decode(targetOperator,
-                                expression);
-                    }
-                    else {
+            case KEYWORD_TARGATTRFILTERS:
+            {
+                if (targAttrFilters == null){
+                    // Check the operator for the targattrfilters is EQUALITY
+                    if (targetOperator == EnumTargetOperator.NOT_EQUALITY) {
                         int msgID =
-                             MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS;
-                        String message =
-                                getMessage(msgID, "targattrfilters", input);
+                                MSGID_ACI_SYNTAX_INVALID_TARGET_NOT_OPERATOR;
+                        String message = getMessage(msgID, operator);
                         throw new AciException(msgID, message);
                     }
-                    break;
+                    targAttrFilters = TargAttrFilters.decode(targetOperator,
+                            expression);
                 }
+                else {
+                    int msgID =
+                            MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS;
+                    String message =
+                            getMessage(msgID, "targattrfilters", input);
+                    throw new AciException(msgID, message);
+                }
+                break;
+            }
             }
         }
-        return new AciTargets(target, targetAttr, targetFilter, targetScope);
+        return new AciTargets(target, targetAttr, targetFilter,
+                              targetScope, targAttrFilters);
     }
 
     /*
@@ -308,7 +355,7 @@
     }
 
     /**
-     * Checks an ACI's targetfilter information against an target match
+     * Checks an ACI's targetfilter information against a target match
      * context.
      * @param aci The ACI to try an match the targetfilter of.
      * @param matchCtx The target match context containing information needed
@@ -324,6 +371,32 @@
         return ret;
     }
 
+    /**
+     * Check an ACI's targattrfilters against a target match context.
+     * @param aci The ACI to match the targattrfilters against.
+     * @param matchCtx  The target match context containing the information
+     * needed to perform the target match.
+     * @return True if the targattrfilters matched the target context.
+     */
+    public static boolean isTargAttrFiltersApplicable(Aci aci,
+                                               AciTargetMatchContext matchCtx) {
+        boolean ret=true;
+        TargAttrFilters targAttrFilters=aci.getTargets().getTargAttrFilters();
+        if(targAttrFilters != null) {
+            if((matchCtx.hasRights(ACI_ADD) &&
+                targAttrFilters.hasMask(TARGATTRFILTERS_ADD)) ||
+              (matchCtx.hasRights(ACI_DELETE) &&
+               targAttrFilters.hasMask(TARGATTRFILTERS_DELETE)))
+                ret=targAttrFilters.isApplicableAddDel(matchCtx);
+            else if((matchCtx.hasRights(ACI_WRITE_ADD) &&
+                     targAttrFilters.hasMask(TARGATTRFILTERS_ADD)) ||
+                    (matchCtx.hasRights(ACI_WRITE_DELETE) &&
+                    targAttrFilters.hasMask(TARGATTRFILTERS_DELETE)))
+                ret=targAttrFilters.isApplicableMod(matchCtx);
+        }
+        return ret;
+    }
+
     /*
      * TODO Evaluate making this method more efficient.
      * The isTargetAttrApplicable method looks a lot less efficient than it
@@ -338,26 +411,28 @@
      * @return True if the targetattr matched the target context.
      */
     public static boolean isTargetAttrApplicable(Aci aci,
-                                AciTargetMatchContext targetMatchCtx) {
+                                         AciTargetMatchContext targetMatchCtx) {
         boolean ret=true;
-        AciTargets targets=aci.getTargets();
-        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((aci.hasRights(skipRights)) && (skipRightsHasRights(rights))) {
-                ret=true;
-            } else if ((targets.getTargetAttr() != null) &&
-                    (a == null) && (aci.hasRights(AciHandler.ACI_WRITE))) {
-                ret = true;
-            } else {
-                ret = false;
+        if(!targetMatchCtx.getTargAttrFiltersMatch()) {
+            AciTargets targets=aci.getTargets();
+            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((aci.hasRights(skipRights)) &&
+                                                (skipRightsHasRights(rights)))
+                    ret=true;
+                else if ((targets.getTargetAttr() != null) &&
+                        (a == null) && (aci.hasRights(ACI_WRITE)))
+                    ret = true;
+                else
+                    ret = false;
             }
+            if((isFirstAttr) && (aci.getTargets().getTargetAttr() == null))
+                targetMatchCtx.setEntryTestRule(true);
         }
-        if((isFirstAttr) && (aci.getTargets().getTargetAttr() == null))
-            targetMatchCtx.setEntryTestRule(true);
         return ret;
     }
 
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AuthMethod.java b/opends/src/server/org/opends/server/authorization/dseecompat/AuthMethod.java
index 9c58c50..5adc0ec 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AuthMethod.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AuthMethod.java
@@ -34,7 +34,15 @@
  * The AuthMethod class represents an authmethod bind rule keyword expression.
  */
 public class AuthMethod implements KeywordBindRule {
+
+    /*
+     * Enumeration representing the authentication method.
+     */
     private EnumAuthMethod authMethod=null;
+
+    /*
+     * Enumeration representing the bind rule operation type.
+     */
     private EnumBindRuleType type=null;
 
     /**
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java b/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java
index 5d6a79e..011e3e1 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java
@@ -28,6 +28,7 @@
 package org.opends.server.authorization.dseecompat;
 
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
@@ -38,38 +39,84 @@
  * pair.
  */
 public class BindRule {
+
     /*
      * This hash table holds the keyword bind rule mapping.
      */
     private HashMap<String, KeywordBindRule> keywordRuleMap =
                                     new HashMap<String, KeywordBindRule>();
 
-    //True is a boolean "not" was seen.
+    /*
+     * True is a boolean "not" was seen.
+     */
     private boolean negate=false;
 
-    //Complex bind rules have left and right values.
+    /*
+     * Complex bind rules have left and right values.
+     */
     private BindRule left = null;
     private BindRule right = null;
 
-    //Enumeration of the boolean type of the complex bind rule ("and" or "or").
+    /*
+     * Enumeration of the boolean type of the complex bind rule ("and" or "or").
+     */
     private EnumBooleanTypes booleanType = null;
 
-    //The keyword of a simple bind rule.
+    /*
+     * The keyword of a simple bind rule.
+     */
     private EnumBindRuleKeyword keyword = null;
 
-    //Regular expression stuff that needs to be made clearer.
+    /*
+     * Regular expression group position of a bind rule keyword.
+     */
     private static final int keywordPos = 1;
+
+    /*
+     * Regular expression group position of a bind rule operation.
+     */
     private static final int opPos = 2;
+
+    /*
+     * Regular expression group position of a bind rule expression.
+     */
     private static final int expressionPos = 3;
-    private static final String keywordRegex = "^(\\w+)";
-    private static final String opRegex = "([!=<>]+)";
-    private static final String expressionRegex = "\"([^\"]+)\"\\s*";
-    private static final String bindruleRegex =
-        keywordRegex + "\\s*" + opRegex + "\\s*" + expressionRegex;
+
+    /*
+     * Regular expression group position of the remainder part of an operand.
+     */
     private static final int remainingOperandPos = 1;
+
+    /*
+     * Regular expression group position of the remainder of the bind rule.
+     */
     private static final int remainingBindrulePos = 2;
+
+    /*
+     * Regular expression for valid bind rule operator group.
+     */
+    private static final String opRegGroup = "([!=<>]+)";
+
+    /*
+     * Regular expression for the expression part of a partially parsed
+     * bind rule.
+     */
+    private static final String expressionRegex =
+                                  "\"([^\"]+)\"" + ZERO_OR_MORE_WHITESPACE;
+
+    /*
+     * Regular expression for a single bind rule.
+     */
+    private static final String bindruleRegex =
+        WORD_GROUP_START_PATTERN + ZERO_OR_MORE_WHITESPACE +
+        opRegGroup + ZERO_OR_MORE_WHITESPACE + expressionRegex;
+
+    /*
+     * Regular expression of the remainder part of a partially parsed bind rule.
+     */
     private static final String remainingBindruleRegex =
-        "^\\s*(\\w+)\\s*(.*)$";
+        ZERO_OR_MORE_WHITESPACE_START_PATTERN + WORD_GROUP +
+        ZERO_OR_MORE_WHITESPACE + "(.*)$";
 
     /**
      * Constructor that takes an keyword enumeration and corresponding
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/DNS.java b/opends/src/server/org/opends/server/authorization/dseecompat/DNS.java
index ba97b91..9bb3171 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/DNS.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/DNS.java
@@ -28,6 +28,7 @@
 package org.opends.server.authorization.dseecompat;
 
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
 import java.util.LinkedList;
 import java.util.regex.Matcher;
@@ -38,9 +39,28 @@
  */
 public class DNS implements KeywordBindRule {
 
+    /*
+     * List of patterns to match against.
+     */
     LinkedList<String> patterns=null;
+
+    /*
+     * The enumeration representing the bind rule type of the DNS rule.
+     */
     private EnumBindRuleType type=null;
 
+    /*
+     *  Regular expression group used to match a dns rule.
+     */
+    private static final String valueRegex = "([a-zA-Z0-9\\.\\-\\*]+)";
+
+    /*
+     * Regular expression group used to match one or more DNS values.
+     */
+    private static final String valuesRegExGroup =
+            valueRegex + ZERO_OR_MORE_WHITESPACE +
+            "(," +  ZERO_OR_MORE_WHITESPACE  +  valueRegex  +  ")*";
+
     /**
      * Create a class representing a dns bind rule keyword.
      * @param patterns List of dns patterns to match against.
@@ -62,9 +82,7 @@
     public static DNS decode(String expr,  EnumBindRuleType type)
     throws AciException
     {
-        String valueRegex = "([a-zA-Z0-9\\.\\-\\*]+)";
-        String valuesRegex = valueRegex + "\\s*(,\\s*" + valueRegex + ")*";
-        if (!Pattern.matches(valuesRegex, expr)) {
+        if (!Pattern.matches(valuesRegExGroup, expr)) {
             int msgID = MSGID_ACI_SYNTAX_INVALID_DNS_EXPRESSION;
             String message = getMessage(msgID, expr);
             throw new AciException(msgID, message);
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/DayOfWeek.java b/opends/src/server/org/opends/server/authorization/dseecompat/DayOfWeek.java
index f2af1ee..1e5cdf6 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/DayOfWeek.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/DayOfWeek.java
@@ -38,7 +38,14 @@
  */
 public class DayOfWeek  implements KeywordBindRule {
 
+    /*
+     * List containing the enumeration of the day of the week.
+     */
     LinkedList<EnumDayOfWeek> days=null;
+
+    /*
+     * Enumeration representing the bind rule operation type.
+     */
     private EnumBindRuleType type=null;
 
     /**
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/EnumAccessType.java b/opends/src/server/org/opends/server/authorization/dseecompat/EnumAccessType.java
index 3a20a35..fcccc44 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/EnumAccessType.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/EnumAccessType.java
@@ -32,6 +32,7 @@
  * types (allow, deny).
  */
 public enum EnumAccessType {
+
     /**
      * Allow access type.
      */
@@ -41,6 +42,9 @@
      */
     DENY    ("deny");
 
+    /*
+     * The access type string.
+     */
     private final String accessType;
 
     /**
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/EnumAuthMethod.java b/opends/src/server/org/opends/server/authorization/dseecompat/EnumAuthMethod.java
index 1f12a12..7f3fe72 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/EnumAuthMethod.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/EnumAuthMethod.java
@@ -41,6 +41,7 @@
  * This class provides an enumeration of the allowed authmethod types.
  */
 public enum EnumAuthMethod {
+
     /**
      * The enumeration type when the bind rule has specified authentication of
      * none.
@@ -76,10 +77,10 @@
      */
     AUTHMETHOD_NOMATCH       ("nomatch");
 
-    /**
+    /*
      * The name of the authmethod.
      */
-    public String authmethod = null;
+    private String authmethod = null;
 
     /**
      * Creates a new enumeration type for this authmethod.
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java b/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java
index cfea957..d0ce121 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java
@@ -32,6 +32,7 @@
  * keyword types.
  */
 public enum EnumBindRuleKeyword {
+
     /**
      * The enumeration type when the bind rule has specified keyword of
      * userdn.
@@ -77,10 +78,11 @@
      * authmethod.
      */
     AUTHMETHOD ("authmethod");
-    /**
+
+    /*
      * The keyword name.
      */
-    public final String keyword;
+    private final String keyword;
 
     /**
      * Creates a new enumeration type for the specified keyword.
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleType.java b/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleType.java
index 3e0a91d..f780ff3 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleType.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleType.java
@@ -31,6 +31,7 @@
  * This class provides an enumeration of the allowed bind rule types.
  */
 public enum EnumBindRuleType {
+
     /**
      * The enumeration type when the bind rule has specified type of
      * "=".
@@ -62,7 +63,7 @@
      */
     GREATER_OR_EQUAL_BINDRULE_TYPE  (">=");
 
-    /**
+    /*
      * The bind rule type name.
      */
     private final String type;
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/EnumBooleanTypes.java b/opends/src/server/org/opends/server/authorization/dseecompat/EnumBooleanTypes.java
index cd81820..3c8b370 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/EnumBooleanTypes.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/EnumBooleanTypes.java
@@ -31,6 +31,7 @@
  * This class provides an enumeration of the allowed bind rule booelan types.
  */
 public enum EnumBooleanTypes {
+
     /**
      * The enumeration type when the bind rule has specified boolean type of
      * "AND".
@@ -47,7 +48,7 @@
      */
     NOT_BOOLEAN_TYPE                ("not");
 
-    /**
+    /*
     * The bind rule boolean type name.
      */
     private final String booleanType;
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/EnumDayOfWeek.java b/opends/src/server/org/opends/server/authorization/dseecompat/EnumDayOfWeek.java
index bd00a8d..6112488 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/EnumDayOfWeek.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/EnumDayOfWeek.java
@@ -33,6 +33,7 @@
  * This class provides an enumeration of the allowed dayofweek types.
  */
 public enum EnumDayOfWeek {
+
     /**
      * The enumeration type when the bind rule has specified dayofweek type of
      * "mon".
@@ -69,7 +70,7 @@
      */
     DAY_SUNDAY      ("sun");
 
-    /**
+    /*
     * The bind rule dayofweek type name.
      */
     private String day = null;
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/EnumEvalResult.java b/opends/src/server/org/opends/server/authorization/dseecompat/EnumEvalResult.java
index b63581e..bc372a3 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/EnumEvalResult.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/EnumEvalResult.java
@@ -32,6 +32,7 @@
  * the bind rule evaluation methods.
  */
 public enum EnumEvalResult {
+
     /**
      * This enumeration is returned when the result of the evaluation is TRUE.
      */
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/EnumRight.java b/opends/src/server/org/opends/server/authorization/dseecompat/EnumRight.java
index 11a4e4a..b93fecf 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/EnumRight.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/EnumRight.java
@@ -26,6 +26,7 @@
  */
 
 package org.opends.server.authorization.dseecompat;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 
 /**
  * This class provides an enumeration of the allowed rights.
@@ -88,7 +89,7 @@
      */
     ADDWRITE    ("addwrite");
 
-    /**
+    /*
      * The name of the right.
      */
     private final String right;
@@ -132,40 +133,40 @@
      * @return The bit mask associated with the right.
      */
     public static int getMask(EnumRight right) {
-        int mask=AciHandler.ACI_NULL;
+        int mask=ACI_NULL;
         switch(right) {
             case READ:
-                mask=AciHandler.ACI_READ;
+                mask=ACI_READ;
                 break;
             case WRITE:
-                mask=AciHandler.ACI_WRITE;
+                mask=ACI_WRITE;
                 break;
             case ADD:
-                mask=AciHandler.ACI_ADD;
+                mask=ACI_ADD;
                 break;
             case DELETE:
-                mask=AciHandler.ACI_DELETE;
+                mask=ACI_DELETE;
                 break;
             case SEARCH:
-                mask=AciHandler.ACI_SEARCH;
+                mask=ACI_SEARCH;
                 break;
             case COMPARE:
-                mask=AciHandler.ACI_COMPARE;
+                mask=ACI_COMPARE;
                 break;
             case ALL:
-                mask=AciHandler.ACI_ALL;
+                mask=ACI_ALL;
                 break;
             case  EXPORT:
-                mask=AciHandler.ACI_EXPORT;
+                mask=ACI_EXPORT;
                 break;
             case IMPORT:
-                mask=AciHandler.ACI_IMPORT;
+                mask=ACI_IMPORT;
                 break;
             case PROXY:
-                mask=AciHandler.ACI_PROXY;
+                mask=ACI_PROXY;
                 break;
             case SELFWRITE:
-                mask=AciHandler.ACI_SELF;
+                mask=ACI_SELF;
                 break;
         }
         return mask;
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetKeyword.java b/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetKeyword.java
index 9ef3b00..e58fe0b 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetKeyword.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetKeyword.java
@@ -31,6 +31,7 @@
  *  This class provides an enumeration of the valid ACI target keywords.
  */
 public enum EnumTargetKeyword {
+
     /**
      * This enumeration is returned when the target keyword is
      * "target".
@@ -56,10 +57,8 @@
      * "targattrfilters".
      */
     KEYWORD_TARGATTRFILTERS ("targattrfilters");
+
     /*
-     * TODO Add support for the targattrfilters keyword.
-     */
-    /**
      * The target keyword name.
      */
     private final String keyword;
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetOperator.java b/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetOperator.java
index 72f22e7..204a885 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetOperator.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetOperator.java
@@ -31,6 +31,7 @@
  *  This class provides an enumeration of the valid ACI target operators.
  */
 public enum EnumTargetOperator {
+
     /**
     * This enumeration is returned when the target operator is  "=".
      */
@@ -40,7 +41,7 @@
      */
     NOT_EQUALITY    ("!=");
 
-    /**
+    /*
      * The target operator name.
      */
     private final String operator;
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/EnumUserDNType.java b/opends/src/server/org/opends/server/authorization/dseecompat/EnumUserDNType.java
index 9e943c3..868541b 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/EnumUserDNType.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/EnumUserDNType.java
@@ -40,6 +40,7 @@
  * SELF and ANYONE.
  */
 public enum EnumUserDNType {
+
         /**
          * The enumeration type when the "userdn" URL contains only a DN (no
          * filter or scope) and that DN has no pattern.
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java b/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java
index 78aac73..b188b17 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java
@@ -28,6 +28,7 @@
 package org.opends.server.authorization.dseecompat;
 
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
 import org.opends.server.types.*;
 import org.opends.server.api.Group;
@@ -46,10 +47,28 @@
  */
 public class GroupDN implements KeywordBindRule {
 
+    /*
+     * List of group DNs.
+     */
     LinkedList<DN> groupDNs=null;
+
+    /*
+     * Enumeration representing the groupdn operator type.
+     */
     private EnumBindRuleType type=null;
+
+    /*
+     * Group manager needed for group API.
+     */
     private static GroupManager groupManager =
-            DirectoryServer.getGroupManager();
+                                            DirectoryServer.getGroupManager();
+    /**
+     * Regular expression matching one or more LDAP URLs separated by
+     * "||".
+     */
+    public static final String LDAP_URLS = LDAP_URL +
+            ZERO_OR_MORE_WHITESPACE + "(" + LOGICAL_OR +
+            ZERO_OR_MORE_WHITESPACE + LDAP_URL + ")*";
 
     /**
      * Create a class representing a groupdn bind rule keyword.
@@ -71,17 +90,14 @@
      */
     public static KeywordBindRule decode(String expr, EnumBindRuleType type)
     throws AciException  {
-        String ldapURLRegex = "\\s*(ldap:///[^\\|]+)";
-        String ldapURLSRegex =
-            ldapURLRegex + "\\s*(\\|\\|\\s*" + ldapURLRegex + ")*";
-        if (!Pattern.matches(ldapURLSRegex, expr)) {
+        if (!Pattern.matches(LDAP_URLS, expr)) {
             int msgID = MSGID_ACI_SYNTAX_INVALID_GROUPDN_EXPRESSION;
             String message = getMessage(msgID, expr);
             throw new AciException(msgID, message);
         }
         LinkedList<DN>groupDNs=new LinkedList<DN>();
         int ldapURLPos = 1;
-        Pattern ldapURLPattern = Pattern.compile(ldapURLRegex);
+        Pattern ldapURLPattern = Pattern.compile(LDAP_URL);
         Matcher ldapURLMatcher = ldapURLPattern.matcher(expr);
         while (ldapURLMatcher.find()) {
             try {
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/IpCriteria.java b/opends/src/server/org/opends/server/authorization/dseecompat/IpCriteria.java
index a81048b..19199b0 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/IpCriteria.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/IpCriteria.java
@@ -28,6 +28,7 @@
 package org.opends.server.authorization.dseecompat;
 
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -39,8 +40,7 @@
 /**
  * This class represents a ip bind rule keyword.
  */
-public class IpCriteria implements KeywordBindRule
-{
+public class IpCriteria implements KeywordBindRule {
     private EnumBindRuleType type=null;
 
     // private token to express that any address is accepted
@@ -50,6 +50,13 @@
     private IpBitsNetworkCriteria[] ipBitsCriteria = null;
     private IpMaskNetworkCriteria[] ipMaskCriteria = null;
 
+    private static final String valueRegex =
+                                   "([^," + ZERO_OR_MORE_WHITESPACE + "]+)";
+
+    private static final String valuesRegex =
+            valueRegex + ZERO_OR_MORE_WHITESPACE + "(," +
+            ZERO_OR_MORE_WHITESPACE + valueRegex + ")*";
+
     /*
      * TODO Verifiy IpCriteria constructor adheres to DS 5.2 ip keyword
      * syntax.
@@ -245,8 +252,6 @@
      */
     public static KeywordBindRule decode(String expr, EnumBindRuleType type)
     throws AciException  {
-        String valueRegex = "([^,\\s]+)";
-        String valuesRegex = valueRegex + "\\s*(,\\s*" + valueRegex + ")*";
         if (!Pattern.matches(valuesRegex, expr)) {
             int msgID = MSGID_ACI_SYNTAX_INVALID_IP_EXPRESSION;
             String message = getMessage(msgID, expr);
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java b/opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java
index 17e341d..eb151ea 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java
@@ -28,8 +28,12 @@
 package org.opends.server.authorization.dseecompat;
 
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
 import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.types.AttributeType;
 
@@ -38,14 +42,31 @@
  * to determine what parent inheritance checks to make.
  */
 public class ParentInheritance {
+
     /*
      * The maximum number of parent inheritance levels supported.
-     *
      */
     private static final int MAX_LEVELS=10;
+
+    /*
+     * Pattern to match for parent inheritance.
+     */
     private String parentPat="parent[";
+
+    /*
+     * Array used to hold the level information. Each slot corresponds to a
+     * level parsed from the rule.
+     */
     private int[] levels=new int[MAX_LEVELS];
+
+    /*
+     * The number of levels parsed.
+     */
     private int numLevels;
+
+    /*
+     * The attribute type parsed from the rule.
+     */
     private AttributeType attributeType;
 
 
@@ -66,21 +87,29 @@
             //The "parent[" pattern is invalid for ROLEDN user attr keyword.
             if(pattern.startsWith(parentPat)) {
                 int msgID =
-                  MSGID_ACI_SYNTAX_INVALID_USERATTR_ROLEDN_INHERITANCE_PATTERN;
+                   MSGID_ACI_SYNTAX_INVALID_USERATTR_ROLEDN_INHERITANCE_PATTERN;
                 String message = getMessage(msgID, pattern);
                 throw new AciException(msgID, message);
             }  else {
                 pattern=pattern.trim();
-                if((this.attributeType =
-                        DirectoryServer.getAttributeType(pattern)) == null)
-                    this.attributeType =
-                            DirectoryServer.getDefaultAttributeType(pattern);
-                numLevels=1;
-                levels[0]=0;
+                Pattern pattern1=Pattern.compile(ATTR_NAME);
+                Matcher matcher=pattern1.matcher(pattern);
+               //Check if valid attribute type name.
+               if(!matcher.find() || matcher.groupCount() != 1) {
+                int msgID =
+                        MSGID_ACI_SYNTAX_INVALID_ATTRIBUTE_TYPE_NAME;
+                String message = getMessage(msgID, pattern);
+                throw new AciException(msgID, message);
+               }
+               if((this.attributeType =
+                    DirectoryServer.getAttributeType(pattern)) == null)
+                this.attributeType =
+                        DirectoryServer.getDefaultAttributeType(pattern);
+               numLevels=1;
+              levels[0]=0;
             }
-        } else
-            parse(pattern);
-    }
+    } else parse(pattern);
+}
 
     /**
      * Performs all parsing of the specified pattern string.
@@ -108,6 +137,15 @@
                 String message = getMessage(msgID, pattern);
                 throw new AciException(msgID, message);
             }
+            Pattern pattern1=Pattern.compile(ATTR_NAME);
+            Matcher matcher=pattern1.matcher(toks[1]);
+            //Check if valid attribute type name.
+            if(!matcher.find() || matcher.groupCount() != 1) {
+                int msgID =
+                    MSGID_ACI_SYNTAX_INVALID_ATTRIBUTE_TYPE_NAME;
+                String message = getMessage(msgID, toks[1]);
+                throw new AciException(msgID, message);
+            }
             if((this.attributeType =
                 DirectoryServer.getAttributeType(toks[1])) == null)
                 this.attributeType =
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/PermBindRulePair.java b/opends/src/server/org/opends/server/authorization/dseecompat/PermBindRulePair.java
index c64976f..11a9362 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/PermBindRulePair.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/PermBindRulePair.java
@@ -33,7 +33,14 @@
  */
 public class PermBindRulePair {
 
+    /*
+     * The Bind Rule part.
+     */
     private BindRule bindRule;
+
+    /*
+     * The permission part.
+     */
     private Permission perm=null;
 
     /**
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/Permission.java b/opends/src/server/org/opends/server/authorization/dseecompat/Permission.java
index 2e013c7..f258fca 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/Permission.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/Permission.java
@@ -29,6 +29,7 @@
 
 import static org.opends.server.messages.MessageHandler.getMessage;
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import java.util.regex.Pattern;
 
 /**
@@ -36,12 +37,30 @@
  * of an ACI look like deny(search, write).
  */
 public class Permission {
-    //the access type (allow,deny)
+
+    /*
+     *  The access type (allow,deny) corresponding to the ACI permission value.
+     */
     private EnumAccessType accessType = null;
+
+    /*
+     * The rights (search, add, delete, ...) corresponding to the ACI rights
+     * value.
+     */
     private int rights;
+
+    /*
+     * Regular expression token representing the separator.
+     */
     private static final String separatorToken = ",";
-    private static final String rightsRegex =
-        "\\s*(\\w+)\\s*(,\\s*(\\w+)\\s*)*";
+
+    /*
+     * Regular expression used to match the ACI rights string.
+     */
+    private static final String rightsRegex = ZERO_OR_MORE_WHITESPACE +
+            WORD_GROUP + ZERO_OR_MORE_WHITESPACE +
+            "(," + ZERO_OR_MORE_WHITESPACE + WORD_GROUP +
+            ZERO_OR_MORE_WHITESPACE +  ")*";
 
     /**
      * Constructor creating a class representing a permission part of an bind
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/RoleDN.java b/opends/src/server/org/opends/server/authorization/dseecompat/RoleDN.java
index a3ec83e..26a53f9 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/RoleDN.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/RoleDN.java
@@ -28,6 +28,7 @@
 package org.opends.server.authorization.dseecompat;
 
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
 import org.opends.server.types.*;
 import org.opends.server.api.Group;
@@ -47,10 +48,21 @@
  */
 public class RoleDN  implements KeywordBindRule {
 
+    /*
+     * List of DNs parsed from the ACI bind rule.
+     */
     LinkedList<DN> roleDNs=null;
+
+    /*
+     * The bind rule type of the RoleDN statement.
+     */
     private EnumBindRuleType type=null;
+
+    /*
+     * Group manager needed by the class.
+     */
     private static GroupManager groupManager =
-            DirectoryServer.getGroupManager();
+                           DirectoryServer.getGroupManager();
 
     /**
      * Constructor creating a class representing a roledn keyword of a bind
@@ -72,31 +84,26 @@
      * @throws AciException If the expression is invalid.
      */
     public static KeywordBindRule decode(String expr, EnumBindRuleType type)
-    throws AciException {
-        String ldapURLRegex = "\\s*(ldap:///[^\\|]+)";
-        String ldapURLSRegex =
-            ldapURLRegex + "\\s*(\\|\\|\\s*" + ldapURLRegex + ")*";
-        if (!Pattern.matches(ldapURLSRegex, expr)) {
+            throws AciException {
+        if (!Pattern.matches(GroupDN.LDAP_URLS, expr)) {
             int msgID = MSGID_ACI_SYNTAX_INVALID_ROLEDN_EXPRESSION;
             String message = getMessage(msgID, expr);
             throw new AciException(msgID, message);
         }
         LinkedList<DN>roleDNs=new LinkedList<DN>();
         int ldapURLPos = 1;
-        Pattern ldapURLPattern = Pattern.compile(ldapURLRegex);
+        Pattern ldapURLPattern = Pattern.compile(LDAP_URL);
         Matcher ldapURLMatcher = ldapURLPattern.matcher(expr);
         while (ldapURLMatcher.find()) {
-            String val = ldapURLMatcher.group(ldapURLPos);
-            val = val.trim();
-            DN dn;
+            String value = ldapURLMatcher.group(ldapURLPos).trim();
             try {
-                dn=DN.decode(val);
+                DN dn=LDAPURL.decode(value, true).getBaseDN();
+                roleDNs.add(dn);
             } catch (DirectoryException ex) {
                 int msgID = MSGID_ACI_SYNTAX_INVALID_ROLEDN_URL;
                 String message = getMessage(msgID, ex.getErrorMessage());
                 throw new AciException(msgID, message);
             }
-            roleDNs.add(dn);
         }
         return new RoleDN(type, roleDNs);
     }
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilterList.java b/opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilterList.java
new file mode 100644
index 0000000..80bacba
--- /dev/null
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilterList.java
@@ -0,0 +1,221 @@
+/*
+ * 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.types.AttributeType;
+import org.opends.server.types.SearchFilter;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.core.DirectoryServer;
+import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.LinkedHashMap;
+
+/**
+ * The TargAttrFilterList class represents an targattrfilters list. A
+ * targattrfilters list looks like:
+ *
+ *   "Op=attr1:F1 [(&& attr2:F2)*]
+ */
+public class TargAttrFilterList {
+
+    /*
+     * The mask coresponding to the operation of this list (add or del).
+     */
+    private int mask=0;
+
+    /*
+     * ListHashMap keyed by the attribute type and mapping to the corresponding
+     * search filter. LinkedHashMap is used so everything is in order.
+     */
+    private LinkedHashMap<AttributeType, SearchFilter> attrFilterList;
+
+    /*
+     * Regular expression group count.
+     */
+    private static int expectedGroupCount=2;
+
+    /*
+     * Regular expression attribute group position.
+     */
+    private static int attributePos=1;
+
+    /*
+     * Regular expression filter group position.
+     */
+    private static int filterPos=2;
+
+    /*
+     * Regular expression used to match a filter list including the strange
+     * "and" token used to join the multiple attribute type filter pairs.
+     */
+    private static final String filterListSeperator =
+              ZERO_OR_MORE_WHITESPACE  + "&&" + ZERO_OR_MORE_WHITESPACE;
+
+    /*
+     * Regular expression used to match an attribute filter pair.
+     */
+    private static final String attributeFilter=
+            ATTR_NAME + ZERO_OR_MORE_WHITESPACE + ":{1}" +
+            ZERO_OR_MORE_WHITESPACE + "(\\({1}.*\\){1})";
+
+    /**
+     * Construct a class representing an targattrfilters filter list.
+     * @param mask The mask representing the operation.
+     * @param attrFilterList The list map containing the attribute type
+     * filter mappings.
+     */
+    public TargAttrFilterList(int mask,
+                    LinkedHashMap<AttributeType, SearchFilter> attrFilterList) {
+        this.mask=mask;
+        this.attrFilterList=attrFilterList;
+    }
+
+    /**
+     * Decode an TargAttrFilterList from the specified expression string.
+     * @param mask  The mask representing the operation.
+     * @param expression The expression string to decode.
+     * @return A TargAttrFilterList class representing the targattrfilters
+     * filter list.
+     * @throws AciException If the expression string contains errors.
+     */
+    public static TargAttrFilterList decode(int mask, String expression)
+            throws AciException {
+        LinkedHashMap<AttributeType, SearchFilter> attrFilterList =
+                new LinkedHashMap<AttributeType, SearchFilter>();
+        String[] subExpressions=expression.split(filterListSeperator, -1);
+        //Iterate over each sub-expression, parse and add them to the list
+        //if there are no errors.
+        for(String subs : subExpressions) {
+            Pattern pattern=Pattern.compile(attributeFilter);
+            Matcher matcher=pattern.matcher(subs);
+            //Match the attribute:filter pair part of the expression
+            if(!matcher.find() || matcher.groupCount() != expectedGroupCount) {
+                int msgID =
+                    MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LIST_FORMAT;
+                String message = getMessage(msgID, expression);
+                throw new AciException(msgID, message);
+            }
+            String attributeName=matcher.group(attributePos).toLowerCase();
+            //Strip off any options, so it will match the filter option
+            //handling.
+            int semicolon = attributeName.indexOf(';');
+            if (semicolon != -1)
+                attributeName=attributeName.substring(0, semicolon);
+            String filterString=matcher.group(filterPos);
+            AttributeType attributeType;
+            if((attributeType =
+                    DirectoryServer.getAttributeType(attributeName)) == null)
+                attributeType =
+                        DirectoryServer.getDefaultAttributeType(attributeName);
+            SearchFilter filter;
+            //Check if it is a valid filter and add it to the list map if ok.
+            try {
+               filter = SearchFilter.createFilterFromString(filterString);
+               attrFilterList.put(attributeType, filter);
+            } catch (DirectoryException ex) {
+                String er=ex.getErrorMessage();
+                int msgID =
+                   MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LISTS_FILTER;
+                String message = getMessage(msgID, filterString, er);
+                throw new AciException(msgID, message);
+            }
+            //Verify the filter components. This check assures that each
+            //attribute type in the filter matches the provided attribute
+            //type.
+            verifyFilterComponents(filter, attributeType);
+        }
+        return new TargAttrFilterList(mask, attrFilterList);
+    }
+
+    /**
+     * Verify the filter component attribute types by assuring that each
+     * attribute type in the filter matches the specified attribute type.
+     * @param filter  The filter to verify.
+     * @param type The attribute type to use in the verification.
+     * @throws AciException  If the filter contains an attribute type not
+     * specified.
+     */
+    private static void  verifyFilterComponents(SearchFilter filter,
+                                                AttributeType type)
+            throws AciException {
+        switch (filter.getFilterType()) {
+            case AND:
+            case OR: {
+                for (SearchFilter f : filter.getFilterComponents()) {
+                    verifyFilterComponents(f, type);
+                }
+                break;
+            }
+            case NOT:  {
+                SearchFilter f = filter.getNotComponent();
+                verifyFilterComponents(f, type);
+                break;
+            }
+            default: {
+                AttributeType attrType=filter.getAttributeType();
+                if(!attrType.equals(type)) {
+                    int msgID =
+              MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_FILTER_LISTS_ATTR_FILTER;
+                    String message = getMessage(msgID, filter.toString());
+                    throw new AciException(msgID, message);
+                }
+            }
+        }
+    }
+
+    /**
+     * Return the mask of this TargAttrFilterList.
+     * @return  The mask value.
+     */
+    public int getMask() {
+        return this.mask;
+    }
+
+    /**
+     * Check if the mask value of this TargAttrFilterList class contains the
+     * specified mask value.
+     * @param mask The mask to check for.
+     * @return  True if the mask matches the specified value.
+     */
+    public boolean hasMask(int mask) {
+        return (this.mask & mask) != 0;
+    }
+
+    /**
+     * Return the list map holding the attribute type to filter mappings.
+     * @return  The list map.
+     */
+    public
+    LinkedHashMap<AttributeType, SearchFilter> getAttributeTypeFilterList() {
+        return  attrFilterList;
+    }
+}
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilters.java b/opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilters.java
index cba42bc..6265e65 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilters.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilters.java
@@ -27,29 +27,355 @@
 
 package org.opends.server.authorization.dseecompat;
 
+import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import org.opends.server.types.*;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.*;
+
 /**
- * Placeholder. This class is partially complete. The TargAttrFilters class
- * will represent an targAttrFitlers rule.
+ * The TargAttrFilters class represents a targattrfilters rule of an ACI.
  */
 public class TargAttrFilters {
 
-    /**
-     * Represents an targAttrFilters rule.
+    /*
+     * A valid targattrfilters rule may have two TargFilterlist parts -- the
+     * first one is required.
      */
-    public TargAttrFilters() {
+    TargAttrFilterList firstFilterList=null;
+    TargAttrFilterList secondFilterList=null;
 
+    /*
+     * Regular expression group position for the first operation value.
+     */
+    private static final int firstOpPos = 1;
+
+    /*
+     * Regular expression group position for the rest of an partially parsed
+     * rule.
+     */
+    private static final int restOfExpressionPos=2;
+
+    /*
+     * Regular expression used to match the operation group (either add or del).
+     */
+    private static final String ADD_OR_DEL_KEYWORD_GROUP = "(add|del)";
+
+    /**
+     * Regular expression used to match the second operation of the filter list.
+     * If the first was "add" this must be "del", if the first was "del" this
+     * must be "add".
+     */
+    public static final String secondOp =
+            "[,]{1}" + ZERO_OR_MORE_WHITESPACE + "del|add" +
+            ZERO_OR_MORE_WHITESPACE + EQUAL_SIGN + ZERO_OR_MORE_WHITESPACE;
+
+    /*
+     * Regular expression used to match the first targFilterList, it must exist
+     * or an exception is thrown.
+     */
+    private static final String firstOp = "^" + ADD_OR_DEL_KEYWORD_GROUP +
+            ZERO_OR_MORE_WHITESPACE + EQUAL_SIGN + ZERO_OR_MORE_WHITESPACE;
+
+    /*
+     * Regular expression used to group the remainder of a partially parsed
+     * rule.  Any character one or more times.
+     */
+    private static String restOfExpression = "(.+)";
+
+    /*
+     * Regular expression used to match the first operation keyword and the
+     * rest of the expression.
+     */
+    private static String keywordFullPattern = firstOp + restOfExpression;
+
+    /*
+     * The enumeration representing the operation.
+     */
+    EnumTargetOperator op;
+
+    /*
+     * A mask used to denote if the rule has add, del or both operations in the
+     * composite TargFilterList parts.
+     */
+    private int operationMask;
+
+    /**
+     * Represents an targatterfilters keyword rule.
+     * @param op The enumeration representing the operation type.
+     *
+     * @param firstFilterList  The first filter list class parsed from the rule.
+     * This one is required.
+     *
+     * @param secondFilterList The second filter list class parsed from the
+     * rule. This one is optional.
+     */
+    public TargAttrFilters(EnumTargetOperator op,
+                           TargAttrFilterList firstFilterList,
+                           TargAttrFilterList secondFilterList ) {
+        this.op=op;
+        this.firstFilterList=firstFilterList;
+        operationMask=firstFilterList.getMask();
+        if(secondFilterList != null) {
+            //Add the second filter list mask to the mask.
+            operationMask |= secondFilterList.getMask();
+            this.secondFilterList=secondFilterList;
+        }
     }
 
     /**
-     * Decode an string representing a targattrfilters keyword.
-     * @param operator The operator of the rule.
-     * @param expression The string parsed from the ACI representing the
-     * targattrfilters rule.
-     * @return  An object representing an targattrfilters rule.
-     * @throws  AciException if the expression string cannot be parsed.
+     * Decode an targattrfilter rule.
+     * @param type The enumeration representing the type of this rule. Defaults
+     * to equality for this target.
+     *
+     * @param expression The string expression to be decoded.
+     * @return  A TargAttrFilters class representing the decode expression.
+     * @throws AciException If the expression string contains errors and
+     * cannot be decoded.
      */
-    public static TargAttrFilters decode(EnumTargetOperator operator,
-                                  String expression) throws AciException {
-        return new TargAttrFilters();
+    public static TargAttrFilters decode(EnumTargetOperator type,
+                                        String expression) throws AciException {
+        Pattern fullPattern=Pattern.compile(keywordFullPattern);
+        Matcher matcher = fullPattern.matcher(expression);
+        //First match for overall correctness and to get the first operation.
+        if(!matcher.find()) {
+            int msgID = MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_EXPRESSION;
+            String message = getMessage(msgID, expression);
+            throw new AciException(msgID, message);
+        }
+        String firstOp=matcher.group(firstOpPos);
+        String subExpression=matcher.group(restOfExpressionPos);
+        //This pattern is built dynamically and is used to see if the operations
+        //in the two filter list parts (if the second exists) are equal. See
+        //comment below.
+        String opPattern=
+                "[,]{1}" + ZERO_OR_MORE_WHITESPACE  +
+                firstOp + ZERO_OR_MORE_WHITESPACE + EQUAL_SIGN +
+                ZERO_OR_MORE_WHITESPACE;
+        String[] temp=subExpression.split(opPattern);
+        /**
+         * Check that the initial list operation is not equal to the second.
+         * For example:  Matcher find
+         *
+         *  "add:cn:(cn=foo), add:cn:(cn=bar)"
+         *
+         * This is invalid.
+         */
+        if(temp.length > 1) {
+            int msgID =
+                    MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_OPS_MATCH;
+            String message = getMessage(msgID, expression);
+            throw new AciException(msgID, message);
+        }
+        /**
+         * Check that there are not too many filter lists. There can only
+         * be either one or two.
+         */
+        String[] filterLists=
+                subExpression.split(secondOp, -1);
+        if(filterLists.length > 2) {
+            int msgID =
+                    MSGID_ACI_SYNTAX_INVALID_TARGATTRFILTERS_MAX_FILTER_LISTS;
+            String message = getMessage(msgID, expression);
+            throw new AciException(msgID, message);
+        }
+        TargAttrFilterList firstFilterList =
+                TargAttrFilterList.decode(getMask(firstOp), filterLists[0]);
+        TargAttrFilterList secondFilterList=null;
+        //Handle the second filter list if there is one.
+        if(filterLists.length == 2) {
+            String temp2= filterLists[1].substring(1,filterLists[1].length());
+            //Assume the first op is an "add" so this has to be a "del".
+            String secondOp="del";
+            //If the first op is a "del", the second has to be an "add".
+            if(getMask(firstOp) == TARGATTRFILTERS_DELETE)
+                secondOp="add";
+            secondFilterList =
+                    TargAttrFilterList.decode(getMask(secondOp), temp2);
+        }
+        return new TargAttrFilters(type, firstFilterList, secondFilterList);
     }
+
+    /**
+     * Return the mask corrsponding to the specified string.
+     * @param op The op string.
+     * @return   The mask corresponding to the operation string.
+     */
+    private static  int getMask(String op) {
+        if(op.equals("add"))
+            return TARGATTRFILTERS_ADD;
+        else
+            return TARGATTRFILTERS_DELETE;
+    }
+
+    /**
+     * Gets the TargFilterList  corresponding to the mask value.
+     * @param matchCtx The target match context containing the rights to
+     * match against.
+     * @return  A TargAttrFilterList matching both the rights of the target
+     * match context and the mask of the TargFilterAttrList. May return null.
+     */
+    public TargAttrFilterList
+    getTargAttrFilterList(AciTargetMatchContext matchCtx) {
+        TargAttrFilterList filterList=null;
+        int mask=ACI_NULL;
+        //Set up the wanted mask by evaluating both the target match
+        //context's rights and the mask.
+        if(matchCtx.hasRights(ACI_ADD) &&
+                hasMask(TARGATTRFILTERS_ADD))
+            mask=TARGATTRFILTERS_ADD;
+        else if(matchCtx.hasRights(ACI_DELETE) &&
+                hasMask(TARGATTRFILTERS_DELETE))
+            mask=TARGATTRFILTERS_DELETE;
+        //Check the first list first, it always has to be there. If it doesn't
+        //match then check the second if it exists.
+        if(firstFilterList.hasMask(mask))
+            filterList=firstFilterList;
+        else if((secondFilterList != null) &&
+                secondFilterList.hasMask(mask))
+            filterList=secondFilterList;
+        return filterList;
+    }
+
+    /**
+     * Check if this TargAttrFilters object is applicable to the target
+     * specified match context. This check is only used for the LDAP modify
+     * operation.
+     * @param matchCtx The target match context containing the information
+     * needed to match.
+     * @return True if this TargAttrFitlers object is applicable to this
+     * target match context.
+     */
+    public boolean isApplicableMod(AciTargetMatchContext matchCtx) {
+        //Get the targFitlerList corresponding to this context's rights.
+        TargAttrFilterList attrFilterList=getTargAttrFilterList(matchCtx);
+        //If the list is empty return true and go on to the targattr check
+        //in AciTargets.isApplicable().
+        if(attrFilterList == null)
+            return true;
+        LinkedHashMap<AttributeType, SearchFilter> filterList  =
+                attrFilterList.getAttributeTypeFilterList();
+        boolean attrMatched=true;
+        AttributeType attrType=matchCtx.getCurrentAttributeType();
+        //If the filter list contains the current attribute type; check
+        //the attribute types value(s) against the corresponding filter.
+        // If the filter list does not contain the attribute type skip the
+        // attribute type.
+        if((attrType != null) && (filterList.containsKey(attrType))) {
+            AttributeValue value=matchCtx.getCurrentAttributeValue();
+            SearchFilter filter = filterList.get(attrType);
+            attrMatched=matchFilterAttributeValue(attrType, value, filter);
+            //This flag causes any targattr checks to be bypassed in AciTargets.
+            if(attrMatched)
+                matchCtx.setTargAttrFiltersMatch(true);
+            if(op.equals(EnumTargetOperator.NOT_EQUALITY))
+                attrMatched = !attrMatched;
+        }
+        return attrMatched;
+    }
+
+    /**
+     * Check if this TargAttrFilters object is applicable to the specified
+     * target match context. This check is only used for either LDAP add or
+     * delete operations.
+     * @param matchCtx The target match context containing the information
+     * needed to match.
+     * @return True if this TargAttrFilters object is applicable to this
+     * target match context.
+     */
+    public boolean isApplicableAddDel(AciTargetMatchContext matchCtx) {
+        TargAttrFilterList attrFilterList=getTargAttrFilterList(matchCtx);
+        //List didn't match current operation return true.
+        if(attrFilterList == null)
+            return true;
+        LinkedHashMap<AttributeType, SearchFilter> filterList  =
+                attrFilterList.getAttributeTypeFilterList();
+        Iterator<AttributeType> iterator=filterList.keySet().iterator();
+        boolean attrMatched=true;
+        //Get the resource entry.
+        Entry resEntry=matchCtx.getResourceEntry();
+        //Iterate through each attribute type in the filter list checking
+        //the resource entry to see if it has that attribute type. If not
+        //go to the next attribute type. If it is found, then check the entries
+        //attribute type values against the filter.
+        for(;iterator.hasNext() && attrMatched;) {
+            AttributeType attrType=iterator.next();
+            SearchFilter f=filterList.get(attrType);
+            //Found a match in the entry, iterate over each attribute
+            //type in the entry and check its values agaist the filter.
+            if(resEntry.hasAttribute(attrType)) {
+                ListIterator<Attribute> attrIterator=
+                        resEntry.getAttribute(attrType).listIterator();
+                for(;attrIterator.hasNext() && attrMatched;) {
+                    Attribute a=attrIterator.next();
+                    attrMatched=matchFilterAttributeValues(a, attrType, f);
+                }
+            }
+        }
+        if(op.equals(EnumTargetOperator.NOT_EQUALITY))
+            attrMatched = !attrMatched;
+        return attrMatched;
+    }
+
+    /**
+     * Iterate over each attribute type attribute and compare the values
+     * against the provided filter.
+     * @param a The attribute from the resource entry.
+     * @param attrType The attribute type currently working on.
+     * @param filter  The filter to evaluate the values against.
+     * @return  True if all of the values matched the filter.
+     */
+    private boolean matchFilterAttributeValues(Attribute a,
+                                               AttributeType attrType,
+                                               SearchFilter filter) {
+        boolean filterMatch=true;
+        Iterator<AttributeValue> valIterator = a.getValues().iterator();
+        //Iterate through each value and apply the filter against it.
+        for(; valIterator.hasNext() && filterMatch;) {
+            AttributeValue value=valIterator.next();
+            filterMatch=matchFilterAttributeValue(attrType, value, filter);
+        }
+        return filterMatch;
+    }
+
+    /**
+     * Matches an specified attribute value against a specified filter. A dummy
+     * entry is created with only a single attribute containing the value  The
+     * filter is applied against that entry.
+     *
+     * @param attrType The attribute type currently being evaluated.
+     * @param value  The value to match the filter against.
+     * @param filter  The filter to match.
+     * @return  True if the value matches the filter.
+     */
+    private boolean matchFilterAttributeValue(AttributeType attrType,
+                                              AttributeValue value,
+                                              SearchFilter filter) {
+        boolean filterMatch;
+        LinkedHashSet<AttributeValue> values =
+                new LinkedHashSet<AttributeValue>();
+        values.add(new AttributeValue(attrType, value.getValue()));
+        Attribute attr =
+                new Attribute(attrType, attrType.toString(), values);
+        Entry e = new Entry(DN.nullDN(), null, null, null);
+        e.addAttribute(attr, new ArrayList<AttributeValue>());
+        try {
+            filterMatch=filter.matchesEntry(e);
+        } catch(DirectoryException ex) {
+            filterMatch=false;
+        }
+        return filterMatch;
+    }
+
+    /**
+     * Return true if the TargAttrFilters mask contains the specified mask.
+     * @param mask  The mask to check for.
+     * @return  True if the mask matches.
+     */
+    public boolean hasMask(int mask) {
+        return (this.operationMask & mask) != 0;
+    }
+
 }
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/Target.java b/opends/src/server/org/opends/server/authorization/dseecompat/Target.java
index fa02d7b..a7f0300 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/Target.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/Target.java
@@ -28,6 +28,7 @@
 package org.opends.server.authorization.dseecompat;
 
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
 import java.util.ArrayList;
 import java.util.LinkedHashSet;
@@ -47,13 +48,37 @@
  */
 public class Target
 {
+    /*
+     * Enumeration representing the target operator.
+     */
     private EnumTargetOperator operator = EnumTargetOperator.EQUALITY;
-    private LDAPURL targetURL = null;
-    private DN urlDN=null;
-    private boolean isPattern=false;
-    private SearchFilter filter=null;
-    private AttributeType targetType;
 
+    /*
+     * The target URL.
+     */
+    private LDAPURL targetURL = null;
+
+    /*
+     * The DN of the above URL.
+     */
+    private DN urlDN=null;
+
+    /*
+     * True of a wild-card pattern was seen.
+     */
+    private boolean isPattern=false;
+
+    /*
+     * Filter used to apply to an dummy entry when a wild-card pattern is
+     * used.
+     */
+    private SearchFilter filter=null;
+
+    /*
+     * Attribute type that is used to create the pattern attribute.
+     *  See matchesPattern method.
+     */
+    private AttributeType targetType;
 
       /*
      * TODO Save aciDN parameter and use it in matchesPattern re-write.
@@ -89,8 +114,7 @@
             throws AciException {
         this.operator = operator;
         try {
-          String ldapURLRegex = "\\s*(ldap:///[^\\|]+)";
-          if (!Pattern.matches(ldapURLRegex, target)) {
+          if (!Pattern.matches(LDAP_URL, target)) {
               int msgID = MSGID_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION;
               String message = getMessage(msgID, target);
               throw new AciException(msgID, message);
@@ -163,7 +187,8 @@
     }
 
     /*
-     * TODO Evaluate re-writing this method.
+     * TODO Evaluate re-writing this method. Evaluate if we want to dis-allow
+     * wild-card matching in the suffix part of the dn.
      *
      * The matchesPattern() method really needs to be rewritten.  It's using a
      * very inefficient and very error-prone method to make the determination.
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java b/opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java
index e4f23dc..bd17665 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java
@@ -28,6 +28,7 @@
 package org.opends.server.authorization.dseecompat;
 
 import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.authorization.dseecompat.Aci.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
 import java.util.HashSet;
 import java.util.regex.Pattern;
@@ -38,18 +39,29 @@
  * A class representing an ACI's targetattr keyword.
  */
 public class TargetAttr {
+    /*
+     * Enumeration representing the targetattr operator.
+     */
     private EnumTargetOperator operator = EnumTargetOperator.EQUALITY;
+
+    /*
+     * Flags that is set if all attributes pattern seen "*".
+     */
     private boolean allAttributes = false ;
+
     /*
      * HashSet of the attribute types parsed by the constructor.
      */
     private HashSet<AttributeType> attributes = new HashSet<AttributeType>();
-    //private String[] attributes = new String[0];
-    private static final String allAttrsRegex  = "\\s*\\*\\s*";
-    private static final String noAttrsRegex   = "\\s*";
-    private static final String separatorToken = "\\|\\|";
-    private static final String attrListRegex  =
-        "\\s*(\\w+)\\s*(" + separatorToken + "\\s*(\\w+)\\s*)*";
+
+    /*
+     * Regular expression that matches one or more ATTR_NAME's separated by
+     * the "||" token.
+     */
+    private static final String attrListRegex  =  ZERO_OR_MORE_WHITESPACE +
+           ATTR_NAME + ZERO_OR_MORE_WHITESPACE + "(" +
+            LOGICAL_OR + ZERO_OR_MORE_WHITESPACE + ATTR_NAME +
+            ZERO_OR_MORE_WHITESPACE + ")*";
 
     /**
      * Constructor creating a class representing a targetattr keyword of an ACI.
@@ -63,18 +75,19 @@
     throws AciException {
         this.operator = operator;
         if (attrString != null) {
-            if (Pattern.matches(allAttrsRegex, attrString) ){
+            if (Pattern.matches(ALL_ATTRS_WILD_CARD, attrString) ){
                 allAttributes = true ;
             } else {
-                if (Pattern.matches(noAttrsRegex, attrString)){
+                if (Pattern.matches(ZERO_OR_MORE_WHITESPACE, attrString)){
                     allAttributes = false;
                 } else {
                     if (Pattern.matches(attrListRegex, attrString)) {
                         // Remove the spaces in the attr string and
                         // split the list.
                         Pattern separatorPattern =
-                            Pattern.compile(separatorToken);
-                        attrString=attrString.replaceAll("\\s", "");
+                            Pattern.compile(LOGICAL_OR);
+                        attrString=
+                         attrString.replaceAll(ZERO_OR_MORE_WHITESPACE, "");
                         String[] attributeArray=
                              separatorPattern.split(attrString);
                         //Add each element of array to attributes HashSet
@@ -83,7 +96,7 @@
                     } else {
                       int msgID =
                          MSGID_ACI_SYNTAX_INVALID_TARGETATTRKEYWORD_EXPRESSION;
-                      String message = getMessage(msgID, operator);
+                      String message = getMessage(msgID, attrString);
                       throw new AciException(msgID, message);
                     }
                 }
@@ -101,12 +114,13 @@
             String attribute=attributeArray[i].toLowerCase();
             AttributeType attributeType;
             if((attributeType =
-                DirectoryServer.getAttributeType(attribute)) == null)
+                    DirectoryServer.getAttributeType(attribute)) == null)
                 attributeType =
-                    DirectoryServer.getDefaultAttributeType(attribute);
+                        DirectoryServer.getDefaultAttributeType(attribute);
             attributes.add(attributeType);
         }
     }
+
     /**
      * Returns the operator enumeration of the targetattr expression.
      * @return The operator enumeration.
@@ -172,8 +186,14 @@
                           TargetAttr targetAttr) {
       boolean ret;
       if(targetAttr.isAllAttributes()) {
-          ret =
-             !targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY);
+          //If it is an operational attribute, then access is denied for all
+          //attributes wild-card. Operational attributes must be
+          // explicitly defined.
+          if(a.isOperational()) {
+              ret=false;
+          } else
+              ret =
+              !targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY);
       }  else {
           ret=false;
           HashSet<AttributeType> attributes=targetAttr.getAttributes();
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/TargetFilter.java b/opends/src/server/org/opends/server/authorization/dseecompat/TargetFilter.java
index 743d85c..80734df 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/TargetFilter.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/TargetFilter.java
@@ -38,10 +38,18 @@
  *
  */
 public class TargetFilter {
+
+    /*
+     * Enumeration representing the targetfilter operation.
+     */
     private EnumTargetOperator op = EnumTargetOperator.EQUALITY;
+
+    /*
+     * Filter parsed from the ACI used to match the resource entry.
+     */
     private SearchFilter filter;
 
-    /**
+    /*
      * Class representing a targetfilter keyword.
      * @param op The operation of the targetfilter expression (=, !=)
      * @param filter The filter itself.
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java b/opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java
index c42c193..7863fc9 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java
@@ -36,8 +36,20 @@
  * This class represents the timeofday keyword in a bind rule.
  */
 public class TimeOfDay implements KeywordBindRule {
+
+    /*
+     * Regular expression matching a valid timeofday rule value (0-2359).
+     */
     private static final String timeofdayRegex = "[0-2]\\d[0-5]\\d";
+
+    /*
+     *  Enumeration representing the bind rule operation type.
+     */
     private EnumBindRuleType type=null;
+
+    /*
+     * Holds the time value parsed from the ACI.
+     */
     private int timeRef;
 
     /**
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java b/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
index 2f65e25..f1462cf 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
@@ -48,20 +48,58 @@
  * This class implements the  userattr bind rule keyword.
  */
 public class UserAttr implements KeywordBindRule {
+
     /**
      * This enumeration is the various types the userattr can have after
      * the "#" token.
      */
-    enum UserAttrType {
+    private enum UserAttrType {
         USERDN, GROUPDN, ROLEDN, URL, VALUE
     }
-    private  static String f="objectclass=*";
+
+    /*
+     * Filter used in  internal search.
+     */
+    private static SearchFilter filter;
+
+    /*
+     * Used to create an attribute type that can compare the value below in
+     * an entry returned from an internal search.
+     */
     private  String attrStr=null;
+
+    /*
+     * Used to compare a attribute value returned from a search against this
+     * value which might have been defined in the ACI userattr rule.
+     */
     private  String attrVal=null;
+
+    /*
+     * Contains the type of the userattr, one of the above enumerations.
+     */
     private UserAttrType userAttrType=null;
+
+    /*
+     * An enumeration representing the bind rule type.
+     */
     private EnumBindRuleType type=null;
+
+    /*
+     * The class used to hold the parent inheritance information.
+     */
     private ParentInheritance parentInheritance=null;
 
+    static {
+        /*
+         * Set up the filter used to search private and public contexts.
+         */
+        try {
+            filter=SearchFilter.createFilterFromString("(objectclass=*)");
+        } catch (DirectoryException ex) {
+            //TODO should never happen, error message?
+        }
+    }
+
     /**
      * Create an non-USERDN/GROUPDN instance of the userattr keyword class.
      * @param attrStr The attribute name in string form. Kept in string form
@@ -174,27 +212,22 @@
         AttributeType attrType;
         if((attrType = DirectoryServer.getAttributeType(attrStr)) == null)
             attrType = DirectoryServer.getDefaultAttributeType(attrStr);
-        try {
-            InternalClientConnection conn =
+        InternalClientConnection conn =
                 InternalClientConnection.getRootConnection();
-            InternalSearchOperation op =
-                    conn.processSearch(evalCtx.getClientDN(),
-                    SearchScope.BASE_OBJECT,
-                    DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
-                    SearchFilter.createFilterFromString(f), null);
-            LinkedList<SearchResultEntry> result = op.getSearchEntries();
-            if (!result.isEmpty()) {
-                AttributeValue val=new AttributeValue(attrType, attrVal);
-                SearchResultEntry resultEntry = result.getFirst();
-                if(resultEntry.hasValue(attrType, null, val)) {
-                    Entry e=evalCtx.getResourceEntry();
-                    if(e.hasValue(attrType, null, val))
-                        matched=EnumEvalResult.TRUE;
-                }
+        InternalSearchOperation op =
+                conn.processSearch(evalCtx.getClientDN(),
+                        SearchScope.BASE_OBJECT,
+                        DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
+                        filter, null);
+        LinkedList<SearchResultEntry> result = op.getSearchEntries();
+        if (!result.isEmpty()) {
+            AttributeValue val=new AttributeValue(attrType, attrVal);
+            SearchResultEntry resultEntry = result.getFirst();
+            if(resultEntry.hasValue(attrType, null, val)) {
+                Entry e=evalCtx.getResourceEntry();
+                if(e.hasValue(attrType, null, val))
+                    matched=EnumEvalResult.TRUE;
             }
-        } catch (DirectoryException ex) {
-            undefined = true;
-            matched = EnumEvalResult.ERR;
         }
         return matched.getRet(type, undefined);
     }
@@ -305,31 +338,25 @@
                         stop=true;
                 }
             } else {
-                try {
-                    DN pDN=
+                DN pDN=
                         getDNParentLevel(levels[i], evalCtx.getResourceDN());
-                    if(pDN == null)
-                        continue;
-                    InternalClientConnection conn =
+                if(pDN == null)
+                    continue;
+                InternalClientConnection conn =
                         InternalClientConnection.getRootConnection();
-                    InternalSearchOperation op = conn.processSearch(pDN,
-                            SearchScope.BASE_OBJECT,
-                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
-                            SearchFilter.createFilterFromString(f), null);
-                    LinkedList<SearchResultEntry> result =
+                InternalSearchOperation op = conn.processSearch(pDN,
+                        SearchScope.BASE_OBJECT,
+                        DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
+                        filter, null);
+                LinkedList<SearchResultEntry> result =
                         op.getSearchEntries();
-                    if (!result.isEmpty()) {
-                        Entry e = result.getFirst();
-                        if (e.hasAttribute(attrType)) {
-                            matched = evalEntryAttr(e, evalCtx, attrType);
-                           if(matched.equals(EnumEvalResult.TRUE))
-                                stop=true;
-                        }
+                if (!result.isEmpty()) {
+                    Entry e = result.getFirst();
+                    if (e.hasAttribute(attrType)) {
+                        matched = evalEntryAttr(e, evalCtx, attrType);
+                        if(matched.equals(EnumEvalResult.TRUE))
+                            stop=true;
                     }
-                } catch (DirectoryException ex) {
-                    undefined=true;
-                    stop=true;
-                    matched=EnumEvalResult.ERR;
                 }
             }
         }
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java b/opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java
index 2154c3c..4ec5643 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java
@@ -43,13 +43,22 @@
      */
     private static String urlStr="ldap:///";
 
-    /**
+    /*
      * This list holds a list of objects representing a EnumUserDNType
      * URL mapping.
      */
-    List<UserDNTypeURL> urlList=null;
+    private List<UserDNTypeURL> urlList=null;
+
+    /*
+     * Enumeration of the userdn operation type.
+     */
     private EnumBindRuleType type=null;
+
+    /*
+     * Used to evaluate a userdn that has a pattern  (wild-card).
+     */
     private AttributeType userDNAttrType;
+
     /**
      * Constructor that creates the userdn class. It also sets up an attribute
      * type ("userdn") needed  for wild-card matching.
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/UserDNTypeURL.java b/opends/src/server/org/opends/server/authorization/dseecompat/UserDNTypeURL.java
index 9cedaab..849da6e 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/UserDNTypeURL.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/UserDNTypeURL.java
@@ -33,10 +33,12 @@
  * of a "userdn" URL decoded by the UserDN.decode() method.
  */
 public class UserDNTypeURL {
-    /**
+
+    /*
      * The DN type of the URL.
      */
     private EnumUserDNType dnType;
+
     /*
      * The URL value. Maybe a dummy value for types such as ANYONE or SELF.
      */
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
index e8d6958..5418bf1 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
@@ -227,8 +227,24 @@
   private static final String BIND_RULE_GROUPDN_1 = "groupdn=\"ldap:///cn=SomeGroup,dc=example,dc=com\"";
   private static final String BIND_RULE_GROUPDN_2 = "groupdn=\"ldap:///cn=SomeGroup,dc=example,dc=com || ldap:///cn=SomeOtherGroup,dc=example,dc=com\"";
   private static final String BIND_RULE_GROUPDN_3 = "groupdn=\"ldap:///cn=SomeGroup,dc=example,dc=com || ldap:///cn=SomeOtherGroup,dc=example,dc=com || ldap:///cn=SomeThirdGroup,dc=example,dc=com\"";
+  private static final String BIND_RULE_ROLEDN_1 = "roledn=\"ldap:///cn=SomeGroup,dc=example,dc=com\"";
+  private static final String BIND_RULE_ROLEDN_2 =  "roledn=\"ldap:///cn=SomeGroup,dc=example,dc=com || ldap:///cn=SomeOtherGroup,dc=example,dc=com\"";
+  private static final String BIND_RULE_ROLEDN_3 =  "roledn=\"ldap:///cn=SomeGroup,dc=example,dc=com || ldap:///cn=SomeOtherGroup,dc=example,dc=com || ldap:///cn=SomeThirdGroup,dc=example,dc=com\"";
+
   private static final String BIND_RULE_USERDN_FILTER = "userdn=\"ldap:///dc=example,dc=com??one?(|(ou=eng)(ou=acct))\"";
 
+  //bind rule user attr ACIs
+  private static final String BIND_RULE_USERATTR_USERDN = "userattr=\"manager#USERDN\"";
+  private static final String BIND_RULE_USERATTR_USERDN_1 = "userattr=\"ldap:///dc=example,dc=com?owner#USERDN\"";
+  private static final String BIND_RULE_USERATTR_URL = "userattr=\"cn#LDAPURL\"";
+  private static final String BIND_RULE_USERATTR_GROUPDN = "userattr=\"manager#GROUPDN\"";
+  private static final String BIND_RULE_USERATTR_GROUPDN_1 = "userattr=\"ldap:///dc=example,dc=com?owner#GROUPDN\"";
+  private static final String BIND_RULE_USERATTR_ROLEDN = "userattr=\"manager#ROLEDN\"";
+  private static final String BIND_RULE_USERATTR_ROLEDN_1 = "userattr=\"ldap:///dc=example,dc=com?owner#ROLEDN\"";
+  private static final String BIND_RULE_USERATTR_USERDN_INHERITANCE = "userattr=\"parent[0,1,2].cn#USERDN\"";
+  private static final String BIND_RULE_USERATTR_GROUPDN_INHERITANCE = "userattr=\"parent[0,1,2].cn#GROUPDN\"";
+  private static final String BIND_RULE_USERATTR_VALUE = "userattr=\"manager#a manager\"";
+
   private static final String BIND_RULE_INVALID_DAY = "dayofweek=\"sumday\"";
 
   private static final String BIND_RULE_ONLY_AT_NOON = "timeofday=\"1200\"";
@@ -237,6 +253,21 @@
   private static final String BIND_RULE_NOON_AND_AFTER = "timeofday>=\"1200\"";
   private static final String BIND_RULE_BEFORE_NOON = "timeofday<\"1200\"";
   private static final String BIND_RULE_NOON_AND_BEFORE = "timeofday<=\"1200\"";
+  //targattrfilters
+  private static final String TARG_ATTR_FILTERS =  "add=cn:(!(cn=superAdmin))";
+  private static final String TARG_ATTR_FILTERS_1 =  "add=cn:(!(cn=superAdmin)) && telephoneNumber:(telephoneNumber=123*)";
+  private static final String TARG_ATTR_FILTERS_2 =  "add=cn:(!(cn=superAdmin)), del=sn:(!(sn=nonSuperAdmin))";
+  private static final String TARG_ATTR_FILTERS_4 =  "del=cn:(&(cn=foo)(cn=f*)) && sn:(sn=joe*)";
+  private static final String TARG_ATTR_FILTERS_5 = TARG_ATTR_FILTERS_1 + "," + TARG_ATTR_FILTERS_4 ;
+  //targattrfilters invalids
+  private static final String TARG_ATTR_FILTERS_INVALID_FILTER =  "del=cn:(&(cnfoo)(cn=f*)) && sn:(snjoe*)";
+  private static final String TARG_ATTR_FILTERS_BAD_OP =  "delete=cn:(&(cn=foo)(cn=f*)) && sn:(sn=joe*)";
+  private static final String TARG_ATTR_FILTERS_BAD_OP_MATCH = TARG_ATTR_FILTERS_1 + "," + TARG_ATTR_FILTERS_1 ;
+  private static final String TARG_ATTR_FILTERS_BAD_FILTER_ATTR =  "del=cn:(&(cn=foo)(cn=f*)) && sn:(cn=joe*)";
+  private static final String TARG_ATTR_FILTERS_BAD_FORMAT =  "delete=cn;(&(cn=foo)(cn=f*)) && sn:(sn=joe*)";
+  private static final String TARG_ATTR_FILTERS_TOO_MANY_LISTS = TARG_ATTR_FILTERS_1 + "," + TARG_ATTR_FILTERS_4 + "," + TARG_ATTR_FILTERS_1;
+  private static final String TARG_ATTR_FILTERS_BAD_TOK =  "delete=cn:(&(cn=foo)(cn=f*)) && sn:(sn=joe*) || pager:(pager=123-*)";
+  private static final String TARG_ATTR_FILTERS_ATTR_TYPE_NAME =  "del=cn:(&(cn=foo)(cn=f*)) && 1sn_;:(1sn_;=joe*)";
 
   private static final String SELF_MODIFY_ACI = "aci: (targetattr=\"*\")(version 3.0; acl \"self modify\";allow(all) userdn=\"userdn=\"ldap:///self\";)";
 
@@ -250,7 +281,7 @@
           buildAciValue("name", "allow all to anyone", "targetattr", "*", "allow(all)", BIND_RULE_USERDN_ANYONE);
 
   private static final String ALLOW_SEARCH_TO_ADMIN =
-          buildAciValue("name", "allow search to admin", "targetattr", "*", "allow(search)", BIND_RULE_USERDN_ADMIN);
+          buildAciValue("name", "allow search to admin", "targetattr", "*", "allow(search, read)", BIND_RULE_USERDN_ADMIN);
 
   private static final String DENY_ALL_TO_ALL =
           buildAciValue("name", "deny all", "targetattr", "*", "deny(all)", BIND_RULE_USERDN_ALL);
@@ -262,7 +293,7 @@
           buildAciValue("name", "deny search", "targetattr", "*", "deny(search)", BIND_RULE_USERDN_ALL);
 
   private static final String ALLOW_SEARCH_TO_ALL =
-          buildAciValue("name", "allow search", "targetattr", "*", "allow(search)", BIND_RULE_USERDN_ALL);
+          buildAciValue("name", "allow search", "targetattr", "*", "allow(search, read)", BIND_RULE_USERDN_ALL);
 
   private static final String ALLOW_READ_TO_ALL =
           buildAciValue("name", "allow read", "targetattr", "*", "allow(read)", BIND_RULE_USERDN_ALL);
@@ -289,7 +320,7 @@
           buildAciValue("name", "allow all to non ou person", "targetattr", "*", "targetfilter!=", "(|(objectclass=organizationalunit)(objectclass=person))", "allow(all)", BIND_RULE_USERDN_ALL);
 
   private static final String ALLOW_WRITE_DELETE_SEARCH_TO_ALL =
-          buildAciValue("name", "allow write, delete, and search,", "targetattr", "*", "allow(write, delete, search)", BIND_RULE_USERDN_ALL);
+          buildAciValue("name", "allow write, delete, and search,", "targetattr", "*", "allow(write, delete, search, read)", BIND_RULE_USERDN_ALL);
 
   private static final String DENY_WRITE_DELETE_READ_TO_ALL =
           buildAciValue("name", "deny write delete read to all", "targetattr", "*", "deny(write, delete, read)", BIND_RULE_USERDN_ALL);
@@ -307,7 +338,7 @@
           buildAciValue("name", "deny read to users with 'admin' in their cn", "targetattr", "*", "deny(read)", BIND_RULE_USERDN_ALL_CN_ADMINS);
 
   private static final String ALLOW_SEARCH_TO_CN_ADMINS =
-          buildAciValue("name", "allow search to users with 'admin' in their cn", "targetattr", "*", "allow(search)", BIND_RULE_USERDN_ALL_CN_ADMINS);
+          buildAciValue("name", "allow search to users with 'admin' in their cn", "targetattr", "*", "allow(search, read)", BIND_RULE_USERDN_ALL_CN_ADMINS);
 
   private static final String DENY_READ_TO_TOP_LEVEL_CN_ADMINS =
           buildAciValue("name", "deny read to users with 'admin' in their cn", "targetattr", "*", "deny(read)", BIND_RULE_USERDN_TOP_LEVEL_CN_ADMINS);
@@ -386,19 +417,19 @@
           buildAciValue("name", "allow not admin", "targetattr", "*", "allow(all)", BIND_RULE_USERDN_NOT_ADMIN);
 
   private static final String ALLOW_SEARCH_TO_LOCALHOST =
-          buildAciValue("name", "allow search to localhost", "targetattr", "*", "allow(search)", BIND_RULE_IP_LOCALHOST);
+          buildAciValue("name", "allow search to localhost", "targetattr", "*", "allow(search, read)", BIND_RULE_IP_LOCALHOST);
 
   private static final String ALLOW_SEARCH_REALATTRS_TO_LOCALHOST =
-          buildAciValue("name", "allow search to localhost", "targetattr!=", "bogusAttr", "allow(search)", BIND_RULE_IP_LOCALHOST);
+          buildAciValue("name", "allow search to localhost", "targetattr!=", "bogusAttr", "allow(search, read)", BIND_RULE_IP_LOCALHOST);
 
   private static final String ALLOW_SEARCH_OUR_ATTRS_TO_ADMIN =
-          buildAciValue("name", "allow search to our attributes to admin", "targetattr", "objectclass||ou||cn||sn||givenname", "target", LDAP_URL_OU_INNER, "allow(search)", BIND_RULE_USERDN_ADMIN);
+          buildAciValue("name", "allow search to our attributes to admin", "targetattr", "objectclass||ou||cn||sn||givenname", "target", LDAP_URL_OU_INNER, "allow(search, read)", BIND_RULE_USERDN_ADMIN);
 
   private static final String ALLOW_SEARCH_TARGET_INNER_TO_LOCALHOST =
-          buildAciValue("name", "allow search inner to localhost", "targetattr", "*", "target", LDAP_URL_OU_INNER, "allow(search)", BIND_RULE_IP_LOCALHOST);
+          buildAciValue("name", "allow search inner to localhost", "targetattr", "*", "target", LDAP_URL_OU_INNER, "allow(search, read)", BIND_RULE_IP_LOCALHOST);
 
   private static final String ALLOW_SEARCH_OU_AND_PERSON_TO_SIMPLE =
-          buildAciValue("name", "allow search ou and person to localhost", "targetattr", "*", "targetfilter", "(|(objectclass=organizationalunit)(objectclass=person))", "allow(search)", BIND_RULE_AUTHMETHOD_SIMPLE);
+          buildAciValue("name", "allow search ou and person to localhost", "targetattr", "*", "targetfilter", "(|(objectclass=organizationalunit)(objectclass=person))", "allow(search, read)", BIND_RULE_AUTHMETHOD_SIMPLE);
 
 
 // -----------------------------------------------------------------------------
@@ -461,6 +492,13 @@
     buildAciValue("name", "w/ 1 targetattr", "targetattr", "cn", "allow (write)", BIND_RULE_USERDN_SELF),
     buildAciValue("name", "w/ 2 targetattr", "targetattr", "cn || sn", "allow (write)", BIND_RULE_USERDN_SELF),
     buildAciValue("name", "w/ 3 targetattr", "targetattr", "cn || sn || uid", "allow (write)", BIND_RULE_USERDN_SELF),
+    //These are four are OpenDS specific attr names
+    buildAciValue("name", "opends targetattr", "targetattr", "1-digitinfirst", "allow (write)", BIND_RULE_USERDN_SELF),
+    buildAciValue("name", "opendstargetattr", "targetattr", "this_has_underscores", "allow (write)", BIND_RULE_USERDN_SELF),
+    buildAciValue("name", "locality targetattr", "targetattr", "locality;lang-fr-ca", "allow (write)", BIND_RULE_USERDN_SELF),
+    buildAciValue("name", "oid targetattr", "targetattr", " 2.16.840.1.113730.3.3.2.18.1.4", "allow (write)", BIND_RULE_USERDN_SELF),
+    buildAciValue("name", "complicated targetattr", "targetattr", "1ocal_ity;lang-fr-ca", "allow (write)", BIND_RULE_USERDN_SELF),
+
     buildAciValue("name", "w/ * targetattr", "targetattr", "*", "allow (write)", BIND_RULE_USERDN_SELF),
     buildAciValue("name", "w/ non-existing attr", "targetattr", "notanattr", "allow (write)", BIND_RULE_USERDN_SELF),       // DS 5.2p4 accepts this so we should too.
     buildAciValue("name", "w/ non-existing attr", "targetattr", "cn || notanattr", "allow (write)", BIND_RULE_USERDN_SELF), // DS 5.2p4 accepts this so we should too.
@@ -481,20 +519,16 @@
     buildAciValue("name", "w/ 1 !targetattr", "targetattr!=", "cn", "allow (write)", BIND_RULE_USERDN_SELF),
     buildAciValue("name", "w/ 2 !targetattr", "targetattr!=", "cn || sn", "allow (write)", BIND_RULE_USERDN_SELF),
     buildAciValue("name", "w/ targetfilter", "targetfilter!=", "(sn=admin)", "allow (write)", BIND_RULE_USERDN_SELF),
-// </PASSES>
-
-// <FAILS>
-//  These aren't supported yet.  We should open an issue.
-//    buildAciValue("name", "w/ targetattrfilters", "targetattrfilters", "add=cn:(!(cn=superAdmin))", "allow (write)", BIND_RULE_USERDN_SELF),
-//    buildAciValue("name", "w/ targetattrfilters", "targetattrfilters", "add=cn:(!(cn=superAdmin)) && telephoneNumber:(telephoneNumber=123*)", "allow (write)", BIND_RULE_USERDN_SELF),
-// </FAILS>
-
-// <PASSES>
+    buildAciValue("name", "w/ targattrfilters", "targattrfilters=",  TARG_ATTR_FILTERS, "allow (write)", BIND_RULE_USERDN_SELF),
+    buildAciValue("name", "w/ targattrfilters", "targattrfilters=",  TARG_ATTR_FILTERS_1 , "allow (write)", BIND_RULE_USERDN_SELF),
+    buildAciValue("name", "w/ targattrfilters", "targattrfilters=",  TARG_ATTR_FILTERS_2 , "allow (write)", BIND_RULE_USERDN_SELF),
+    buildAciValue("name", "w/ targattrfilters", "targattrfilters=",  TARG_ATTR_FILTERS_5 , "allow (write)", BIND_RULE_USERDN_SELF),
+    buildAciValue("name", "bad_ATTR_TYPE_NAME", "targattrfilters",TARG_ATTR_FILTERS_ATTR_TYPE_NAME, "allow (write)", BIND_RULE_USERDN_SELF),
     buildAciValue("name", "read", "targetattr", "*", "allow (read)", BIND_RULE_USERDN_SELF),
     buildAciValue("name", "write", "targetattr", "*", "allow (write)", BIND_RULE_USERDN_SELF),
     buildAciValue("name", "add", "targetattr", "*", "allow (add)", BIND_RULE_USERDN_SELF),
     buildAciValue("name", "delete", "targetattr", "*", "allow (delete)", BIND_RULE_USERDN_SELF),
-    buildAciValue("name", "search", "targetattr", "*", "allow (search)", BIND_RULE_USERDN_SELF),
+    buildAciValue("name", "search", "targetattr", "*", "allow (search, read)", BIND_RULE_USERDN_SELF),
     buildAciValue("name", "compare", "targetattr", "*", "allow (compare)", BIND_RULE_USERDN_SELF),
     buildAciValue("name", "selfwrite", "targetattr", "*", "allow (selfwrite)", BIND_RULE_USERDN_SELF),
     buildAciValue("name", "all", "targetattr", "*", "allow (all)", BIND_RULE_USERDN_SELF),
@@ -518,16 +552,22 @@
     buildAciValue("name", "read anyone", "targetattr", "*", "allow (read)", BIND_RULE_USERDN_ANYONE),
     buildAciValue("name", "read filter", "targetattr", "*", "allow (read)", BIND_RULE_USERDN_FILTER),
     buildAciValue("name", "read parent", "targetattr", "*", "allow (read)", BIND_RULE_USERDN_PARENT),
-// <FAIL>
-//  These aren't supported yet.  We should open an issue.
-//    buildAciValue("name", "read group dn 1", "targetattr", "*", "allow (read)", BIND_RULE_GROUPDN_1),
-//    buildAciValue("name", "read group dn 2", "targetattr", "*", "allow (read)", BIND_RULE_GROUPDN_2),
-//    buildAciValue("name", "read group dn 3", "targetattr", "*", "allow (read)", BIND_RULE_GROUPDN_3),
-// </FAIL>
-    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", "userattr=\"manager#USERDN\""),
-    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", "userattr=\"ldap:///dc=example,dc=com?owner#USERDN\""),
-    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", "userattr=\"cn#LDAPURL\""),
-
+    buildAciValue("name", "read group dn 1", "targetattr", "*", "allow (read)", BIND_RULE_GROUPDN_1),
+    buildAciValue("name", "read group dn 2", "targetattr", "*", "allow (read)", BIND_RULE_GROUPDN_2),
+    buildAciValue("name", "read group dn 3", "targetattr", "*", "allow (read)", BIND_RULE_GROUPDN_3),
+    buildAciValue("name", "read group dn 1", "targetattr", "*", "allow (read)", BIND_RULE_ROLEDN_1),
+    buildAciValue("name", "read group dn 2", "targetattr", "*", "allow (read)", BIND_RULE_ROLEDN_2),
+    buildAciValue("name", "read group dn 3", "targetattr", "*", "allow (read)", BIND_RULE_ROLEDN_3),
+    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", BIND_RULE_USERATTR_USERDN),
+    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", BIND_RULE_USERATTR_USERDN_1),
+    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", BIND_RULE_USERATTR_URL),
+    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", BIND_RULE_USERATTR_GROUPDN),
+    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", BIND_RULE_USERATTR_GROUPDN_1),
+    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", BIND_RULE_USERATTR_ROLEDN),
+    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", BIND_RULE_USERATTR_ROLEDN_1),
+    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", BIND_RULE_USERATTR_USERDN_INHERITANCE),
+    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", BIND_RULE_USERATTR_GROUPDN_INHERITANCE),
+    buildAciValue("name", "userattr", "targetattr", "*", "allow (read)", BIND_RULE_USERATTR_VALUE),
     // BUG!  These work with DS 5.2p4, but not with OpenDS.
 // <FAIL>
 //    DENY_ALL_TO_LOCALHOST_SUBNET,
@@ -559,12 +599,6 @@
      DENY_ALL_TO_ADMIN_AND_LOCALHOST_OR_SSL,
      ALLOW_ALL_NOT_ADMIN
 
-
-// <FAIL>
-//  These aren't supported yet.  We should open an issue.
-//    buildAciValue("name", "userattr 1", "targetattr", "*", "allow (read)", "userattr=\"owner#GROUPDN\""),
-//    buildAciValue("name", "userattr 1", "targetattr", "*", "allow (read)", "userattr=\"ldap:///dc=example,dc=com?owner#GROUPDN\""),
-// </FAIL>
 // </PASSES>
     // TODO: bind rules for 'ip', 'dns', 'dayofweek', 'timeofday', 'authmethod'
     // TODO: combinations of these things, including multiple bind rules.
@@ -575,20 +609,29 @@
     // Test each feature in isolation.
 // <PASSES>
     "aci: ",
-    buildAciValue("allow (write)", BIND_RULE_USERDN_SELF),  // No name
-    buildAciValue("name", "invalid", "target", "ldap:///", "allow (write)", BIND_RULE_USERDN_SELF),
-    buildAciValue("name", "invalid", "target", "ldap:///not a DN", "allow (write)", BIND_RULE_USERDN_SELF),
-    buildAciValue("name", "invalid", "target", "ldap:///cn=", "allow (write)", BIND_RULE_USERDN_SELF),
-    buildAciValue("name", "invalid", "targetattr", "", "allow (write)", BIND_RULE_USERDN_SELF),
-    buildAciValue("name", "invalid", "targetattr", "not an attr", "allow (write)", BIND_RULE_USERDN_SELF),
-    buildAciValue("name", "invalid", "targetattr", "cn ||", "allow (write)", BIND_RULE_USERDN_SELF),
-    buildAciValue("name", "invalid", "targetattr", "not/an/attr", "allow (write)", BIND_RULE_USERDN_SELF),
-    buildAciValue("name", "invalid", "targetattr", "cn", "allow (write)", BIND_RULE_INVALID_DAY),
+          buildAciValue("allow (write)", BIND_RULE_USERDN_SELF),  // No name
+          buildAciValue("name", "invalid", "target", "ldap:///", "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "invalid", "target", "ldap:///not a DN", "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "invalid", "target", "ldap:///cn=", "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "invalid", "targetattr", "", "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "invalid", "targetattr", "not an attr", "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "invalid", "targetattr", "cn ||", "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "invalid", "targetattr", "not/an/attr", "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "invalid", "targetattr", "cn", "allow (write)", BIND_RULE_INVALID_DAY),
+          buildAciValue("name", "bad_filters", "targetattrfilters",TARG_ATTR_FILTERS_INVALID_FILTER, "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "bad_op", "targetattrfilters",TARG_ATTR_FILTERS_BAD_OP, "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "bad_op_match", "targetattrfilters",TARG_ATTR_FILTERS_BAD_OP_MATCH, "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "bad_filter_attr", "targetattrfilters",TARG_ATTR_FILTERS_BAD_FILTER_ATTR, "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "bad_format", "targetattrfilters",TARG_ATTR_FILTERS_BAD_FORMAT, "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "too_many_lists", "targetattrfilters",TARG_ATTR_FILTERS_TOO_MANY_LISTS, "allow (write)", BIND_RULE_USERDN_SELF),
+          buildAciValue("name", "bad_tok", "targetattrfilters",TARG_ATTR_FILTERS_BAD_TOK, "allow (write)", BIND_RULE_USERDN_SELF),
 
-// <FAIL>
-// Attributes can't have '_' right?, but DS 5.2p4 accepts this, so should we?
-//    buildAciValue("name", "invalid", "targetattr", "not_an_attr", "allow (write)", BIND_RULE_USERDN_SELF),
-// </FAIL>
+
+         buildAciValue("name", "bad targetScope", "targetScope", "sub_tree", "allow (write)", BIND_RULE_USERDN_SELF),
+         buildAciValue("name", "bad right", "targetattr", "*", "allow (read, write, add, delete, search, compare, selfwrite, all, foo)", BIND_RULE_USERDN_SELF),
+         buildAciValue("name", "bad access type", "targetattr", "*", "allows (read, write, add, delete, search, compare, selfwrite, all)", BIND_RULE_USERDN_SELF),
+         //no name
+         buildAciValue("targetattr", "*", "allows (read, write, add, delete, search, compare, selfwrite, all)", BIND_RULE_USERDN_SELF),
 
 // </PASSES>
   };
@@ -1392,7 +1435,7 @@
       // Ignoring whitespace the diff should be empty.
       Assert.assertTrue(diffFromExpected.replaceAll("\\s", "").length() == 0);
     } catch (Throwable e) {
-      System.err.println(
+        System.err.println(
               "Started with dit:\n" +
               params._initialDitLdif +
               ((params._aciLdif.length() == 0) ?
@@ -1429,7 +1472,7 @@
       String aciField = aciFields[i];
       String aciValue = aciFields[i+1];
 
-      if (aciField.startsWith("target")) {
+      if (aciField.startsWith("targ")) {
         if (!aciField.endsWith("=")) {  // We allow = or more importantly != to be included with the target
           aciField += "=";
         }
@@ -1456,7 +1499,7 @@
       String permission = aciFields[i];
       String bindRule = aciFields[i+1];
 
-      if (!permission.startsWith("target") && !permission.equals("name")) {
+      if (!permission.startsWith("targ") && !permission.equals("name")) {
         aci.append(EOL + " " + permission + " " + bindRule + ";");
       }
     }

--
Gitblit v1.10.0