From 550e66541ba792fe0e8c24fac50a480f97c114e3 Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Wed, 21 Feb 2007 16:31:49 +0000
Subject: [PATCH] Initial commit of the dseecompat ACI code

---
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetKeyword.java         |  108 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/DayOfWeek.java                 |   96 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java                |  187 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java               |   85 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpBitsNetworkCriteria.java     |  200 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpMaskNetworkCriteria.java     |  140 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciBody.java                   |  255 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java       |  118 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleType.java          |  104 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java                    |  385 ++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserDNTypeURL.java             |   71 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java |  120 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java                   |  151 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Permission.java                |  117 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java     |  134 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciException.java              |  107 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java         |  172 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/PermBindRulePair.java          |   93 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java                  |  388 ++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetOperator.java        |   81 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java              |  426 ++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumAuthMethod.java            |  116 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumUserDNType.java            |   84 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumBooleanTypes.java          |   90 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java            |  143 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/DNS.java                       |  160 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumRight.java                 |  173 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AuthMethod.java                |  112 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java                   |  251 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java        |  210 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumDayOfWeek.java             |  154 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java                       |  207 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java                 |  121 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java                |  759 +++++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java                  |  538 +++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilters.java           |   55 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java               |  827 +++++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetFilter.java              |  103 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java                |  472 +++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/KeywordBindRule.java           |   44 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Target.java                    |  198 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumEvalResult.java            |  111 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumAccessType.java            |   88 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpCriteria.java                |  291 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/RoleDN.java                    |  157 +
 45 files changed, 9,002 insertions(+), 0 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
new file mode 100644
index 0000000..9edddc5
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
@@ -0,0 +1,207 @@
+/*
+ * 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.ByteString;
+import org.opends.server.types.DN;
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import java.util.regex.Pattern;
+/**
+ * The Aci class represents ACI strings.
+ */
+public class Aci  {
+    /*
+     * The body of the ACI is the version, name and permission-bind rule
+     * pairs.
+     */
+    private AciBody body;
+    /*
+     * The ACI targets.
+     */
+    private AciTargets targets=null;
+    /**
+     * The ACIs are on a linked list hashed by the ACI entry DN.
+     * Next points to the next Aci object in the list.
+     */
+    /*
+     * TODO Remove this linked list an replace with an array
+     * of ACIs.
+     */
+    Aci next = null;
+    /**
+     * Version that we support.
+     */
+    public static final String supportedVersion="3.0";
+    private String aciString;
+    /*
+     * The DN of the entry containing this ACI.
+     */
+    private DN dn;
+    /*
+     * 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*$";
+
+    /**
+     * Construct a new Aci from the provided arguments.
+     * @param input The string representation of the ACI.
+     * @param dn The DN of entry containing the ACI.
+     * @param body The body of the ACI.
+     * @param targets The targets of the ACI.
+     */
+    private  Aci(String input, DN dn, AciBody body, AciTargets targets) {
+        this.aciString  = input;
+        this.dn=dn;
+        this.body=body;
+        this.targets=targets;
+    }
+
+    /**
+     * Decode an ACI byte string.
+     * @param byteString The ByteString containing the ACI string.
+     * @param dn DN of the ACI entry.
+     * @return  Returns a decoded ACI representing the string argument.
+     * @throws AciException If the parsing of the ACI string fails.
+     */
+
+    //MPD remove ConfigException after fixing David's problem
+    public static Aci decode (ByteString byteString, DN dn)
+    throws AciException {
+        String input=byteString.stringValue();
+        //Perform an quick pattern check against the string to catch any
+        //obvious syntax errors.
+        if (!Pattern.matches(aciRegex, input)) {
+            int msgID = MSGID_ACI_SYNTAX_GENERAL_PARSE_FAILED;
+            String message = getMessage(msgID, input);
+            throw new AciException(msgID, message);
+        }
+        //Decode the body first.
+        AciBody body=AciBody.decode(input);
+        //Create a substring from the start of the string to start of
+        //the body. That should be the target.
+        String targetStr = input.substring(0, body.getMatcherStartPos());
+        //Decode that target string using the substring.
+        AciTargets targets=AciTargets.decode(targetStr, dn);
+        return new Aci(input, dn, body, targets);
+    }
+
+    /**
+     * Return the string representation of the ACI. This was the string that
+     * was used to create the Aci class.
+     * @return A string representation of the ACI.
+     */
+    public String toString() {
+        return aciString;
+    }
+
+    /**
+     * Returns the targets of the ACI.
+     * @return Any AciTargets of the ACI. There may be no targets
+     * so this might be null.
+     */
+    public AciTargets getTargets() {
+        return targets;
+    }
+
+    /**
+     * Return the DN of the entry containing the ACI.
+     * @return The DN of the entry containing the ACI.
+     */
+    public DN getDN() {
+        return dn;
+    }
+
+    /**
+     * Test if the given ACI is applicable using the target match information
+     * provided. The ACI target can have four keywords at this time:
+     *
+     *       1. target - checked in isTargetApplicable.
+     *       2. targetscope - checked in isTargetApplicable.
+     *       3. targetfilter - checked in isTargetFilterApplicable.
+     *       4. targetattr - checked in isTargetAttrApplicable.
+     *
+     * One and two are checked for match first. If they return true, then
+     * three is checked. Lastly four is checked.
+     *
+     * @param aci The ACI to test.
+     * @param matchCtx The target matching context containing all the info
+     * needed to match ACI targets.
+     * @return  True if this ACI targets are applicable or match.
+     */
+    public static boolean
+    isApplicable(Aci aci, AciTargetMatchContext matchCtx) {
+        return AciTargets.isTargetApplicable(aci, matchCtx) &&
+                AciTargets.isTargetFilterApplicable(aci, matchCtx) &&
+                AciTargets.isTargetAttrApplicable(aci, matchCtx);
+    }
+
+    /**
+     * Check if the body of the ACI matches the rights specified.
+     * @param rights Bit mask representing the rights to match.
+     * @return True if the body's rights match one of the rights specified.
+     */
+    public boolean hasRights(int rights) {
+        return body.hasRights(rights);
+    }
+
+    /**
+     * Re-direct has access type to the body's hasAccessType method.
+     * @param accessType The access type to match.
+     * @return  True if the body's hasAccessType determines a permission
+     * contains this access type (allow or deny are valid types).
+     */
+    public boolean hasAccessType(EnumAccessType accessType) {
+        return body.hasAccessType(accessType);
+    }
+
+    /**
+     * Evaluate this ACI using the evaluation context provided. Re-direct
+     * that calls the body's evaluate method.
+     * @param evalCtx The evaluation context to evaluate with.
+     * @return EnumEvalResult that contains the evaluation result of this
+     * aci evaluation.
+     */
+    private EnumEvalResult evaluate(AciEvalContext evalCtx) {
+        return body.evaluate(evalCtx);
+    }
+
+    /**
+     * Static class used to evaluate an ACI and evaluation context.
+     * @param evalCtx  The context to evaluate with.
+     * @param aci The ACI to evaluate.
+     * @return EnumEvalResult that contains the evaluation result of the aci
+     * evaluation.
+     */
+    public static EnumEvalResult evaluate(AciEvalContext evalCtx, Aci aci) {
+        return aci.evaluate(evalCtx);
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciBody.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciBody.java
new file mode 100644
index 0000000..80e63cc
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciBody.java
@@ -0,0 +1,255 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class represents the body of an ACI. The body of the ACI is the
+ * version, name, and permission-bind rule pairs.
+ */
+public class AciBody {
+
+    private static final int VERSION = 1;
+    private static final int NAME = 2;
+    private static final int PERM = 1;
+    private static final int RIGHTS = 2;
+    private static final int BINDRULE = 3;
+    private int startPos=0;
+    /*
+     * 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.
+     */
+    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.
+     */
+    private static final String permissionRegex = "(\\w+)\\s*\\(([^()]+)\\)";
+    private static final String bindRuleRegex = "(.+?\"[)]*)\\s*;";
+    private static final String actionRegex =
+            "\\s*" + permissionRegex + "\\s*" + bindRuleRegex;
+    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 parse the body of an ACI.
+     */
+    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
+     * header is version and acl name.
+     */
+    public static final String header =
+        "\\(\\s*" + versionToken + "\\s*"
+        + versionRegex + "\\s*;\\s*" + aclToken + "\\s*\"(.*?)\"\\s*;";
+
+    /**
+     * Construct an ACI body from the specified version, name and
+     * permission-bind rule pairs.
+     *
+     * @param verision The version of the ACI.
+     * @param name The name of the ACI.
+     * @param startPos The start position in the string of the ACI body.
+     * @param permBindRulePairs The set of fully parsed permission-bind rule
+     * pairs pertaining to this ACI.
+     */
+    private AciBody(String verision, String name, int startPos,
+            List<PermBindRulePair> permBindRulePairs) {
+        this.version=verision;
+        this.name=name;
+        this.startPos=startPos;
+        this.permBindRulePairs=permBindRulePairs;
+    }
+
+    /**
+     * Decode an ACI string representing the ACI body.
+     *
+     * @param input String representation of the ACI body.
+     * @return An AciBody class representing the decoded ACI body string.
+     * @throws AciException If the provided string contains errors.
+     */
+    public static AciBody decode(String input)
+    throws AciException {
+        String version=null, name=null;
+        int startPos=0;
+        List<PermBindRulePair> permBindRulePairs=
+                new ArrayList<PermBindRulePair>();
+        Pattern bodyPattern = Pattern.compile(header);
+        Matcher bodyMatcher = bodyPattern.matcher(input);
+        if(bodyMatcher.find()) {
+            startPos=bodyMatcher.start();
+            version  = bodyMatcher.group(VERSION);
+            if (!version.equalsIgnoreCase(Aci.supportedVersion)) {
+                int msgID = MSGID_ACI_SYNTAX_INVAILD_VERSION;
+                String message = getMessage(msgID, version);
+                throw new AciException(msgID, message);
+            }
+            name = bodyMatcher.group(NAME);
+        }
+        Pattern bodyPattern1 = Pattern.compile(actionRegex);
+        Matcher bodyMatcher1 = bodyPattern1.matcher(input);
+        /*
+         * The may be many permission-bind rule pairs.
+         */
+        while(bodyMatcher1.find()) {
+         String perm=bodyMatcher1.group(PERM);
+         String rights=bodyMatcher1.group(RIGHTS);
+         String bRule=bodyMatcher1.group(BINDRULE);
+         PermBindRulePair pair = PermBindRulePair.decode(perm, rights, bRule);
+         permBindRulePairs.add(pair);
+        }
+        return new AciBody(version, name, startPos, permBindRulePairs);
+    }
+
+    /**
+     * Checks all of the permissions in this body for a specific access type.
+     * Need to walk down each permission-bind rule pair and call it's
+     * hasAccessType method.
+     *
+     * @param accessType The access type enumeration to search for.
+     * @return True if the access type is found in a permission of
+     * a permission bind rule pair.
+     */
+    public boolean hasAccessType(EnumAccessType accessType) {
+        List<PermBindRulePair>pairs=getPermBindRulePairs();
+         for(PermBindRulePair p : pairs) {
+             if(p.hasAccessType(accessType))
+                 return true;
+         }
+         return false;
+    }
+
+    /**
+     * Search through each permission bind rule associated with this body and
+     * try and match a single right of the specified rights.
+     *
+     * @param rights The rights that are used in the match.
+     * @return True if a one or more right of the specified rights matches
+     * a body's permission rights.
+     */
+    public boolean hasRights(int rights) {
+        List<PermBindRulePair>pairs=getPermBindRulePairs();
+        for(PermBindRulePair p : pairs) {
+            if(p.hasRights(rights))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Retrieve the permission-bind rule pairs of this ACI body.
+     *
+     * @return The permission-bind rule pairs.
+     */
+    private List<PermBindRulePair> getPermBindRulePairs() {
+        return permBindRulePairs;
+    }
+
+    /**
+     * Get the start position in the ACI string of the ACI body.
+     *
+     * @return Index into the ACI string of the ACI body.
+     */
+    public int getMatcherStartPos() {
+        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
+     * each PermBindRulePair object and:
+     *
+     *  1. Skips a pair if the evaluation context rights don't
+     *     apply to that ACI. For example, an LDAP search would skip
+     *     an ACI pair that allows writes.
+     *
+     *  2. The pair's bind rule is evaluated using the evaluation context.
+     *  3. The result of the evaluation is itself evaluated. See comments
+     *     below in the code.
+     *
+     * @param evalCtx The evaluation context to evaluate against.
+     * @return An enumeration result of the evaluation.
+     */
+    public  EnumEvalResult evaluate(AciEvalContext evalCtx) {
+        EnumEvalResult res=EnumEvalResult.FALSE;
+        List<PermBindRulePair>pairs=getPermBindRulePairs();
+        for(PermBindRulePair p : pairs) {
+            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;
+           }
+        }
+        return res;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
new file mode 100644
index 0000000..e24e9a0
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -0,0 +1,426 @@
+/*
+ * 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.*;
+import org.opends.server.api.ClientConnection;
+import org.opends.server.api.Group;
+import org.opends.server.core.AddOperation;
+import org.opends.server.core.Operation;
+import org.opends.server.extensions.TLSConnectionSecurityProvider;
+import org.opends.server.util.ServerConstants;
+import java.net.InetAddress;
+import java.util.LinkedList;
+
+/**
+ *  The AciContainer class contains all of the needed information to perform
+ *  both target match and evaluate an ACI. Target matching is the process
+ *  of testing if an ACI is applicable to an operation, and evaluation is
+ *  the actual access evaluation of the ACI.
+ */
+public abstract class AciContainer
+implements AciTargetMatchContext, AciEvalContext {
+
+    /*
+     * The allow and deny lists.
+     */
+    private LinkedList<Aci> denyList, allowList;
+
+    /*
+     * The attribute type in the resource entry currently being evaluated.
+     */
+    private AttributeType attributeType;
+
+    /*
+     * The attribute type value in the resource entry currently being
+     * evaluated.
+     */
+    private AttributeValue attributeValue;
+
+    /*
+     * True if this is the first attribute type in the resource entry being
+     * evaluated.
+     */
+    private boolean isFirst = false;
+
+    /*
+     * True if an entry test rule was seen during target matching of an ACI
+     * entry. A entry test rule is an ACI with targetattrs target keyword.
+     */
+    private boolean isEntryTestRule = false;
+
+    /*
+     * True if the evaluation of an ACI is from the deny list.
+     */
+    private boolean isDenyEval;
+
+    /*
+     * True if the evaluation is a result of an LDAP add operation.
+     */
+    private boolean isAddOp=false;
+
+    /*
+     * The rights to use in the evaluation of the LDAP operation.
+     */
+    private int rights;
+
+    /*
+     * The entry being evaluated (resource entry).
+     */
+    private Entry resourceEntry;
+
+    /*
+     * The client connection information.
+     */
+    private ClientConnection clientConnection;
+
+    /*
+     * The operation being evaluated.
+     */
+    private Operation operation;
+
+    /**
+     * This constructor is used by all currently supported LDAP operations.
+     *
+     * @param operation The Operation object being evaluated and target
+     * matching.
+     * @param rights The rights array to use in evaluation and target matching.
+     * @param entry The current entry being evaluated and target matched.
+     */
+    protected AciContainer(Operation operation, int rights, Entry entry) {
+      this.resourceEntry=entry;
+      this.operation=operation;
+      this.clientConnection=operation.getClientConnection();
+      if(operation instanceof AddOperation)
+          this.isAddOp=true;
+      this.rights = rights;
+    }
+
+    /**
+     * The list of deny ACIs. These are all of the applicable
+     * ACIs that have a deny permission. Note that an ACI can
+     * be on both allow and deny list if it has multiple
+     * permission-bind rule pairs.
+     *
+     * @param denys The list of deny ACIs.
+     */
+    public void setDenyList(LinkedList<Aci> denys) {
+        denyList=denys;
+    }
+
+    /**
+     * The list of allow ACIs. These are all of the applicable
+     * ACIs that have an allow permission.
+     *
+     * @param allows  The list of allow ACIs.
+     */
+    public void setAllowList(LinkedList<Aci> allows) {
+        allowList=allows;
+    }
+
+    /**
+     * Return the current attribute type being evaluated.
+     * @return  Attribute type being evaluated.
+     */
+    public AttributeType getCurrentAttributeType() {
+        return attributeType;
+    }
+
+    /**
+     * Return the current attribute type value being evaluated.
+     * @return Attribute type value being evaluated.
+     */
+    public AttributeValue getCurrentAttributeValue() {
+        return attributeValue;
+    }
+
+    /**
+     * Set the attribute type to be evaluated.
+     * @param type The attribute type to evaluate.
+     */
+    public void setCurrentAttributeType(AttributeType type) {
+        attributeType=type;
+    }
+
+    /**
+     * Set the attribute type value to be evaluated.
+     * @param value The attribute type value to evaluate.
+     */
+    public void setCurrentAttributeValue(AttributeValue value) {
+        attributeValue=value;
+    }
+
+    /**
+     * Check is this the first attribute being evaluated in an entry.
+     * @return  True if it is the first attribute.
+     */
+    public boolean isFirstAttribute() {
+        return isFirst;
+    }
+
+    /**
+     * Set if this is the first attribute in the entry.
+     * @param val True if this is the first attribute being evaluated in the
+     * entry.
+     */
+    public void setIsFirstAttribute(boolean val) {
+        isFirst=val;
+    }
+
+    /**
+     * Check if an entry test rule was seen during target evaluation.
+     * @return True if an entry test rule was seen.
+     */
+    public boolean hasEntryTestRule() {
+        return isEntryTestRule;
+    }
+
+    /**
+     * Used to set if an entry test rule was seen during target evaluation.
+     * @param val Set to true if an entry test rule was seen.
+     */
+    public void setEntryTestRule(boolean val) {
+        isEntryTestRule=val;
+    }
+
+    /**
+     * Get the entry being evaluated (known as the resource entry).
+     * @return  The entry being evaluated.
+     */
+    public Entry getResourceEntry() {
+        return resourceEntry;
+    }
+
+    /**
+     * Get the entry that corresponds to the client DN.
+     * @return The client entry.
+     */
+    public Entry getClientEntry() {
+       return clientConnection.getAuthenticationInfo().getAuthorizationEntry();
+    }
+
+    /**
+     * Get the deny list of ACIs.
+     * @return The deny ACI list.
+     */
+    public LinkedList<Aci> getDenyList() {
+        return denyList;
+     }
+
+    /**
+     * Get the allow list of ACIs.
+     * @return The allow ACI list.
+     */
+    public LinkedList<Aci> getAllowList() {
+       return allowList;
+    }
+
+    /**
+     * Check is this is a deny ACI evaluation.
+     * @return  True if the evaluation is using an ACI from
+     * deny list.
+     */
+    public boolean isDenyEval() {
+        return isDenyEval;
+    }
+
+    /**
+     * Check is this operation bound anonymously.
+     * @return  True if the authentication is anonymous.
+     */
+    public boolean isAnonymousUser() {
+        return !clientConnection.getAuthenticationInfo().isAuthenticated();
+    }
+
+    /**
+     * Set the deny evaluation flag.
+     * @param val True if this evaluation is a deny ACI.
+     */
+    public void setDenyEval(boolean val) {
+        isDenyEval = val;
+    }
+
+    /**
+     * Returns the client authorization DN known as the client DN.
+     * @return  The client's authorization DN.
+     */
+    public DN getClientDN() {
+        return clientConnection.getAuthenticationInfo().getAuthorizationDN();
+    }
+
+    /**
+     * Get the DN of the entry being evaluated.
+     * @return The DN of the entry.
+     */
+    public DN getResourceDN() {
+        return resourceEntry.getDN();
+    }
+
+    /**
+     * Checks if the container's rights has the specified rights.
+     * @param  rights The rights to check for.
+     * @return True if the container's rights has the specified rights.
+     */
+    public boolean hasRights(int rights) {
+       return (this.rights & rights) != 0;
+    }
+
+    /**
+     * Return the rights set for this container's LDAP operation.
+     * @return  The rights set for the container's LDAP operation.
+     */
+    public int getRights() {
+        return this.rights;
+    }
+
+    /**
+     * Sets the rights for this container to the specified rights.
+     * @param rights The rights to set the container's rights to.
+     */
+    public void setRights(int rights) {
+         this.rights=rights;
+    }
+    /**
+     * Gets the hostname of the remote client.
+     * @return  Cannonical hostname of remote client.
+     */
+    public String getHostName() {
+        return clientConnection.getRemoteAddress().getCanonicalHostName();
+    }
+
+    /**
+     * Gets the remote client's address information.
+     * @return  Remote client's address.
+     */
+    public InetAddress getRemoteAddress() {
+        return clientConnection.getRemoteAddress();
+    }
+
+    /**
+     * Return true if this is an add operation.
+     * @return True if this is an add operation.
+     */
+    public boolean isAddOperation() {
+        return isAddOp;
+    }
+
+    /**
+     * 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.
+     * @param wantSSL True if the bind rule needs the ssl client auth check.
+     * @return  Return an enumeration containing the authentication method
+     * for this connection.
+     */
+    public EnumAuthMethod getAuthenticationMethod(boolean wantSSL) {
+        EnumAuthMethod method=EnumAuthMethod.AUTHMETHOD_NOMATCH;
+        AuthenticationInfo authInfo=clientConnection.getAuthenticationInfo();
+        if(authInfo.isAuthenticated()) {
+            if(authInfo.hasAuthenticationType(AuthenticationType.SIMPLE))
+                method=EnumAuthMethod.AUTHMETHOD_SIMPLE;
+            else if(authInfo.hasAuthenticationType(AuthenticationType.SASL))
+                method=getSaslAuthenticationMethod(authInfo, wantSSL);
+            else
+                method=EnumAuthMethod.AUTHMETHOD_NOMATCH;
+        }
+        return method;
+    }
+
+    /*
+     * TODO This method needs to be tested.
+     * TODO Investigate multi-factor authentication.
+     *   Second, OpenDS is devised so that it could be possible to use
+     *   multi-factor or step-up authentication, in which the same client
+     *   has provided multiple forms of credentials, but this method
+     *   expects only a single authentication type.
+     */
+    /**
+     * This method attempts to figure out what the SASL method was/is or
+     * what the client auth is.
+     * @param authInfo The authentication information to use.
+     * @param wantSSL The bin drule wants the SSL client auth status.
+     * @return An enumeration containing the SASL bind information.
+     */
+    private EnumAuthMethod
+    getSaslAuthenticationMethod(AuthenticationInfo authInfo, boolean wantSSL) {
+        EnumAuthMethod method=EnumAuthMethod.AUTHMETHOD_NOMATCH;
+        if(authInfo.hasAuthenticationType(AuthenticationType.SASL)) {
+            if(authInfo.hasSASLMechanism(ServerConstants.
+                    SASL_MECHANISM_DIGEST_MD5))
+                method=EnumAuthMethod.AUTHMETHOD_SASL_MD5;
+            else if(authInfo.hasSASLMechanism(ServerConstants.
+                    SASL_MECHANISM_GSSAPI))
+                method=EnumAuthMethod.AUTHMETHOD_SASL_GSSAPI;
+            else if(authInfo.hasSASLMechanism(ServerConstants.
+                    SASL_MECHANISM_EXTERNAL)) {
+                /*
+                 * The bind rule wants ssl client auth information. Need the
+                 * security provider to see if the clientAuthPolicy is
+                 * required. If it is optional, we really can't determine if
+                 * the client auth.
+                */
+                if(wantSSL) {
+                    String mechName=
+                        clientConnection.getConnectionSecurityProvider().
+                                getSecurityMechanismName();
+                    if(mechName.equalsIgnoreCase("TLS")) {
+                        TLSConnectionSecurityProvider tlsProv=
+                            (TLSConnectionSecurityProvider)clientConnection.
+                                           getConnectionSecurityProvider();
+                        SSLClientAuthPolicy clientAuthPolicy=
+                            tlsProv.getSSLClientAuthPolicy();
+                        if(clientAuthPolicy == SSLClientAuthPolicy.REQUIRED)
+                            method=EnumAuthMethod.AUTHMETHOD_SSL;
+                    } else
+                       method=EnumAuthMethod.AUTHMETHOD_NOMATCH;
+                } else {
+                    method=EnumAuthMethod.AUTHMETHOD_SASL_EXTERNAL;
+                }
+            } else
+                method=EnumAuthMethod.AUTHMETHOD_NOMATCH;
+        }
+        return method;
+    }
+
+    /**
+     * Convienance method that checks if the the clientDN is a member of the
+     * specified group.
+     * @param group The group to check membership in.
+     * @return True if the clientDN is a member of the specified group.
+     */
+    public boolean isMemberOf(Group group) {
+        boolean ret;
+        try {
+           ret=clientConnection.isMemberOf(group, operation);
+        } catch (DirectoryException ex) {
+            ret=false;
+        }
+        return  ret;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java
new file mode 100644
index 0000000..0e2bd70
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java
@@ -0,0 +1,143 @@
+/*
+ * 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.DN;
+import org.opends.server.types.Entry;
+import org.opends.server.api.Group;
+
+import java.net.InetAddress;
+import java.util.LinkedList;
+
+/**
+ * Interface that provides a view of the AciContainer that is
+ * used by the ACI evaluation code to evaluate an ACI.
+ */
+public interface AciEvalContext
+{
+    /**
+     * Get client DN. The client DN is the authorization DN.
+     * @return   The client DN.
+     */
+    public DN getClientDN();
+
+    /**
+     * Get the client entry. The client entry is the entry that corresponds
+     * to the client DN.
+     * @return The client entry corresponding to the client DN.
+     */
+    public Entry getClientEntry();
+
+    /**
+     * Get the resource DN. The resource DN is the DN of the entry being
+     * evaluated.
+     * @return   The resource DN.
+     */
+    public DN getResourceDN();
+
+    /**
+     * Get the list of deny ACIs.
+     * @return The deny ACI list.
+     */
+    public LinkedList<Aci> getDenyList();
+
+    /**
+     * Get the list allow ACIs.
+     * @return The allow ACI list.
+     */
+    public LinkedList<Aci> getAllowList();
+
+    /**
+     * Set when the deny list is being evaluated.
+     * @param v True if deny's are being evaluated.
+     */
+    public void setDenyEval(boolean v);
+
+    /**
+     * Returns true if the deny list is being evaluated.
+     * @return True if the deny list is being evaluated.
+     */
+    public boolean isDenyEval();
+
+    /**
+     * Check if the remote client is bound anonymously.
+     * @return True if client is bound anonymously.
+     */
+    public boolean isAnonymousUser();
+
+    /**
+     * Return the rights set for this container's LDAP operation.
+     * @return  The rights set for the container's LDAP operation.
+     */
+    public int getRights();
+
+    /**
+     * Return the entry being evaluated
+     * .
+     * @return The evaluation entry.
+     */
+    public Entry getResourceEntry();
+
+    /**
+     * Get the hostname of the bound connection.
+     * @return The hostname of the connection.
+     */
+    public String getHostName();
+
+    /**
+     * Get the authentication method.
+     * @param wantSSL The authmethod bind rule needs the SSL client auth
+     * status.
+     * @return An Enumeration of the auth method bound as.
+     */
+    public EnumAuthMethod getAuthenticationMethod(boolean wantSSL);
+
+    /**
+     * Get the  address of the bound connection.
+     * @return The  address of the bound connection.
+     */
+    public InetAddress getRemoteAddress();
+
+    /**
+     * Return true if this is an add operation, needed by the userattr
+     * USERDN parent inheritance level 0 processing.
+     * @return True if this is an add operation.
+     */
+    public boolean isAddOperation();
+
+    /**
+     * Return true if the operation associated with this evaluation
+     * context is a member of the specified group. Calls the
+     * ClientConnection.isMemberOf() method, which checks authorization
+     * DN membership in the specified group.
+     * @param group The group to check membership in.
+     * @return True if the authorization DN of the operation is a
+     * member of the specified group.
+     */
+    public boolean isMemberOf(Group group);
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciException.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciException.java
new file mode 100644
index 0000000..4556ca7
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciException.java
@@ -0,0 +1,107 @@
+/*
+ * 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 static org.opends.server.loggers.Debug.debugConstructor;
+import static org.opends.server.loggers.Debug.debugEnter;
+
+/**
+ * The AciException class defines an exception that may be thrown
+ * either during ACI syntax verification of an "aci" attribute type value
+ * or during evaluation of an LDAP operation using a set of applicable
+ * ACIs.
+ */
+public class AciException extends Exception {
+
+    /**
+   * The fully-qualified name of this class for debugging purposes.
+   */
+  private static final String CLASS_NAME =
+       "org.opends.server.authorization.dseecompat.AciException";
+
+  /**
+   * The serial version identifier required to satisfy the compiler because this
+   * class extends <CODE>java.lang.Exception</CODE>, which implements the
+   * <CODE>java.io.Serializable</CODE> interface.  This value was generated
+   * using the <CODE>serialver</CODE> command-line utility included with the
+   * Java SDK.
+   */
+  private static final long serialVersionUID = -2763328522960628853L;
+
+    // The unique message ID for the associated message.
+    private int messageID;
+
+    /**
+     * Constructs a new exception with <code>null</code> as its detail message.
+     * The cause is not initialized. Used to break out of a recursive bind rule
+     * decode and not print duplicate messages.
+     */
+    public AciException() {
+      super();
+    }
+
+    /**
+     * Creates a new ACI exception with the provided message.
+     *
+     * @param  messageID  The unique message ID for the provided message.
+     * @param  message    The message to use for this ACI exception.
+     */
+    public AciException(int messageID, String message) {
+      super(message);
+      assert debugConstructor(CLASS_NAME, String.valueOf(messageID),
+                              String.valueOf(message));
+      this.messageID = messageID;
+    }
+
+    /**
+     * Creates a new ACI exception with the provided message and root
+     * cause.
+     *
+     * @param  messageID  The unique identifier for the associated message.
+     * @param  message    The message that explains the problem that occurred.
+     * @param  cause      The exception that was caught to trigger this
+     *                    exception.
+     */
+    public AciException(int messageID, String message, Throwable cause) {
+      super(message, cause);
+
+      assert debugConstructor(CLASS_NAME, String.valueOf(message),
+                              String.valueOf(cause));
+
+      this.messageID = messageID;
+    }
+
+  /**
+   * Retrieves the message ID for this exception.
+   *
+   * @return  The message ID for this exception.
+   */
+  public int getMessageID() {
+    assert debugEnter(CLASS_NAME, "getMessageID");
+    return messageID;
+  }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
new file mode 100644
index 0000000..b69761b
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -0,0 +1,759 @@
+/*
+ * 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.api.AccessControlHandler;
+import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import org.opends.server.core.*;
+import static org.opends.server.loggers.Debug.debugEnter;
+import static org.opends.server.loggers.Error.logError;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import org.opends.server.types.*;
+import static org.opends.server.util.StaticUtils.toLowerCase;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The AciHandler class performs the main processing for the
+ * dseecompat package.
+ */
+public class AciHandler extends AccessControlHandler
+{
+
+    private static final String CLASS_NAME =
+        "org.opends.server.authorization.dseecompat.AciHandler";
+
+    /**
+     * 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.
+     */
+    private AciList aciList;
+
+    /**
+     * Attribute type corresponding to "aci" attribute.
+     */
+    public static AttributeType aciType;
+
+    /**
+     * Constructor that registers the message catalog, creates the ACI list
+     * class that manages the ACI list. Instantiates and registers the change
+     * notification listener that is used to manage the ACI list on
+     * modifications and the backend initialization listener that is used to
+     * register/de-register aci attribute types in backends when backends
+     * are initialized/finalized.
+    */
+    public AciHandler() {
+        AciMessages.registerMessages();
+        aciList = new AciList();
+        AciListenerManager aciListenerMgr =
+            new AciListenerManager(aciList);
+        DirectoryServer.registerChangeNotificationListener(aciListenerMgr);
+        DirectoryServer.registerBackendInitializationListener(aciListenerMgr);
+        if((aciType = DirectoryServer.getAttributeType("aci")) == null)
+            aciType = DirectoryServer.getDefaultAttributeType("aci");
+    }
+
+    /*
+     * TODO
+     * The internal search performed by the searchAcis method will require
+     * a presence index on the aci attribute for any database of any significant
+     * size.  We should probably consider making this index present by default,
+     * because if they aren't using the DSEE-compatible implementation then
+     * they probably won't have any instances of the aci attribute.
+     */
+    /**
+     * Checks to see if a LDAP modification is allowed access.
+     *
+     * @param container  The structure containing the LDAP modifications
+     * @param operation The operation to check modify privileges on.
+     * operation to check and the evaluation context to apply the check against.
+     * @param skipAccessCheck True if access checking should be skipped.
+     * @return  True if access is allowed.
+     */
+    private boolean aciCheckMods(AciLDAPOperationContainer container,
+                                 Operation operation,
+                                 boolean skipAccessCheck) {
+        Entry resourceEntry=container.getResourceEntry();
+        DN dn=resourceEntry.getDN();
+        List<Modification> modifications=container.getModifications();
+        for(Modification m : modifications) {
+            Attribute modAttr=m.getAttribute();
+            AttributeType modType=modAttr.getAttributeType();
+            switch(m.getModificationType()) {
+            /*
+             * TODO Increment modification type needs to be handled.
+             */
+                case DELETE:
+                case REPLACE:
+                {
+                    /*
+                        Check if we have rights to delete all values of
+                        an attribute type in the resource entry.
+                    */
+                    if(resourceEntry.hasAttribute(modType)) {
+                        container.setCurrentAttributeType(modType);
+                        List<Attribute> attrList =
+                            resourceEntry.getAttribute(modType,null);
+                        for (Attribute a : attrList) {
+                            for (AttributeValue v : a.getValues()) {
+                                container.setCurrentAttributeValue(v);
+                                container.setRights(ACI_WRITE_DELETE);
+                                if(!skipAccessCheck &&
+                                   !accessAllowed(container))
+                                    return false;
+                            }
+                        }
+                    }
+                }
+            }
+            if(modAttr.hasValue()) {
+               boolean checkPrivileges=true;
+               for(AttributeValue v : modAttr.getValues()) {
+                   container.setCurrentAttributeType(modType);
+                   container.setCurrentAttributeValue(v);
+                   if((m.getModificationType() == ModificationType.ADD) ||
+                      (m.getModificationType() == ModificationType.REPLACE)) {
+                       container.setRights(ACI_WRITE_ADD);
+                       if(!skipAccessCheck && !accessAllowed(container))
+                           return false;
+                   } else if(m.getModificationType()
+                           == ModificationType.DELETE) {
+                       container.setRights(ACI_WRITE_DELETE);
+                       if(!skipAccessCheck && !accessAllowed(container))
+                           return false;
+                   } else
+                       return false;
+                   /*
+                    Check if the modification type has an "aci" attribute type.
+                    If so, check the syntax of that attribute value. Fail the
+                    the operation if the syntax check fails.
+                    */
+                   if(modType.equals(aciType)) {
+                       try {
+                           /*
+                            * Check that the operation has modify privileges if
+                            * it contains an "aci" attribute type. Flip the
+                            * boolean to false so this check isn't made again
+                            * if there are several ACI values being added.
+                            */
+                           if(checkPrivileges) {
+                            if (!operation.getClientConnection().
+                               hasPrivilege(Privilege.MODIFY_ACL, operation)) {
+                              int  msgID  =
+                                    MSGID_ACI_MODIFY_FAILED_PRIVILEGE;
+                              String message = getMessage(msgID,
+                                      String.valueOf(container.getResourceDN()),
+                                    String.valueOf(container.getClientDN()));
+                              logError(ErrorLogCategory.ACCESS_CONTROL,
+                                         ErrorLogSeverity.SEVERE_WARNING,
+                                         message, msgID);
+                              return false;
+                            }
+                            checkPrivileges=false;
+                           }
+                           Aci.decode(v.getValue(),dn);
+                       } catch (AciException ex) {
+                           int    msgID  = MSGID_ACI_MODIFY_FAILED_DECODE;
+                           String message = getMessage(msgID,
+                                   String.valueOf(dn),
+                                   ex.getMessage());
+                           logError(ErrorLogCategory.ACCESS_CONTROL,
+                                    ErrorLogSeverity.SEVERE_WARNING,
+                                    message, msgID);
+                           return false;
+                       }
+                   }
+               }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Performs the test of the deny and allow access lists using the
+     * provided evaluation context. The deny list is checked first.
+     *
+     * @param evalCtx  The evaluation context to use.
+     * @return  True if access is allowed.
+     */
+    private boolean testApplicableLists(AciEvalContext evalCtx) {
+        EnumEvalResult res=EnumEvalResult.FALSE;
+        //First check deny lists
+        LinkedList<Aci>denys=evalCtx.getDenyList();
+        evalCtx.setDenyEval(true);
+        for(Aci denyAci : denys) {
+           res=Aci.evaluate(evalCtx, denyAci);
+            //Failure could be returned if a system limit is hit or
+            //search fails
+           if((res.equals(EnumEvalResult.FAIL) ||
+              (res.equals(EnumEvalResult.TRUE)))) {
+               return false;
+           }
+        }
+        //Now check the allows -- flip the deny flag to false first.
+        evalCtx.setDenyEval(false);
+        LinkedList<Aci>allows=evalCtx.getAllowList();
+        for(Aci allowAci : allows) {
+           res=Aci.evaluate(evalCtx, allowAci);
+           if(res.equals(EnumEvalResult.TRUE)) {
+               break;
+           }
+        }
+        return res.getBoolVal();
+    }
+
+    /**
+     * Creates the allow and deny ACI lists based on the provided target
+     * match context. These lists are stored in the evaluation context.
+     * @param candidates  List of all possible ACI candidates.
+     * @param targetMatchCtx Target matching context to use for testing each
+     * ACI.
+     */
+    private void createApplicableList(LinkedList<Aci> candidates,
+                                      AciTargetMatchContext targetMatchCtx)
+    {
+        LinkedList<Aci>denys=new LinkedList<Aci>();
+        LinkedList<Aci>allows=new LinkedList<Aci>();
+        for(Aci aci : candidates) {
+            if(Aci.isApplicable(aci, targetMatchCtx)) {
+                if (aci.hasAccessType(EnumAccessType.DENY)) {
+                    denys.add(aci);
+                }
+                if(aci.hasAccessType(EnumAccessType.ALLOW)) {
+                   allows.add(aci);
+                }
+            }
+        }
+        targetMatchCtx.setAllowList(allows);
+        targetMatchCtx.setDenyList(denys);
+    }
+
+
+    /**
+     * Check to see if the client entry has BYPASS_ACL privileges
+     * for this operation.
+     * @param operation The operation to check privileges on.
+     * @return True if access checking can be skipped because
+     * the operation client connection has BYPASS_ACL privileges.
+     */
+    boolean skipAccessCheck(Operation operation) {
+        return operation.getClientConnection().
+                hasPrivilege(Privilege.BYPASS_ACL, operation);
+    }
+
+    /**
+     * Check access using the specified container. This container will have all
+     * of the information to gather applicable ACIs and perform evaluation on
+     * them.
+     *
+     * @param container An ACI operation container which has all of the
+     * information needed to check access.
+     *
+     * @return True if access is allowed.
+     */
+    private boolean accessAllowed(AciContainer container)
+    {
+        DN dn = container.getResourceEntry().getDN();
+        //For ACI_WRITE_ADD and ACI_WRITE_DELETE set the ACI_WRITE
+        //right.
+        if(container.hasRights(ACI_WRITE_ADD) ||
+           container.hasRights(ACI_WRITE_DELETE))
+                container.setRights(container.getRights() | ACI_WRITE);
+        /*
+         * First get all allowed candidate ACIs.
+         */
+        LinkedList<Aci>candidates = aciList.getCandidateAcis(dn);
+        /*
+         * Create an applicable list of ACIs by target matching each
+         * candidate ACI against the container's target match view.
+         */
+        createApplicableList(candidates,container);
+        /*
+         * Lastly, evaluate the applicable list.
+         */
+        return(testApplicableLists(container));
+    }
+
+    /**
+     * Performs an access check against all of the attributes of an entry.
+     * The attributes that fail access are removed from the entry. This method
+     * performs the processing needed for the filterEntry method processing.
+     *
+     * @param container The search or compare container which has all of the
+     * information needed to filter the attributes for this entry.
+     * @return The  entry to send back to the client, minus any attribute
+     * types that failed access check.
+     */
+    private SearchResultEntry
+    accessAllowedAttrs(AciLDAPOperationContainer container) {
+        Entry e=container.getResourceEntry();
+        List<AttributeType> typeList=getAllAttrs(e);
+        for(AttributeType attrType : typeList) {
+            container.setCurrentAttributeType(attrType);
+            if(!accessAllowed(container)) {
+                e.removeAttribute(attrType);
+            }
+        }
+        return container.getSearchResultEntry();
+    }
+
+    /**
+     * Gathers all of the attribute types in an entry along with the
+     * "objectclass" attribute type in a List. The "objectclass" attribute is
+     * added to the list first so it is evaluated first.
+     *
+     * @param e Entry to gather the attributes for.
+     * @return List containing the attribute types.
+     */
+    private List<AttributeType> getAllAttrs(Entry e) {
+        Map<AttributeType,List<Attribute>> attrMap = e.getUserAttributes();
+        List<AttributeType> typeList=new LinkedList<AttributeType>();
+        Attribute attr=e.getObjectClassAttribute();
+        /*
+         * When a search is not all attributes returned, the "objectclass"
+         * attribute type is missing from the entry.
+         */
+        if(attr != null) {
+           AttributeType ocType=attr.getAttributeType();
+           typeList.add(ocType);
+        }
+        typeList.addAll(attrMap.keySet());
+        return typeList;
+    }
+
+    /*
+     * TODO Evaluate performance of this method.
+     * TODO Evaluate security concerns of this method. Logic from this method
+     * taken almost directly from DS6 implementation.
+     *
+     *  I find the work done in the accessAllowedEntry method, particularly
+     *  with regard to the entry test evaluation, to be very confusing and
+     *  potentially pretty inefficient.  I'm also concerned that the "return
+     *  "true" inside the for loop could potentially allow access when it
+     *  should be denied.
+     */
+    /**
+     * Check if access is allowed on an entry. Access is checked by iterating
+     * through each attribute of an entry, starting with the "objectclass"
+     * attribute type.
+     *
+     * If access is allowed on the entry based on one of it's attribute types,
+     * then a possible second access check is performed. This second check is
+     * only performed if an entry test ACI was found during the earlier
+     * successful access check. An entry test ACI has no "targetattrs" keyword,
+     * so allowing access based on an attribute type only would be incorrect.
+     *
+     * @param container ACI search container containing all of the information
+     * needed to check access.
+     *
+     * @return True if access is allowed.
+     */
+    private boolean accessAllowedEntry(AciLDAPOperationContainer container) {
+        boolean ret=false;
+        //set flag that specifies this is the first attribute evaluated
+        //in the entry
+        container.setIsFirstAttribute(true);
+        List<AttributeType> typeList=getAllAttrs(container.getResourceEntry());
+        for(AttributeType attrType : typeList) {
+            container.setCurrentAttributeType(attrType);
+            /*
+             * Check if access is allowed. If true, then check to see if an
+             * entry test rule was found (no targetattrs) during target match
+             * evaluation. If such a rule was found, set the current attribute
+             * type to "null" and check access again so that rule is applied.
+             */
+            if(accessAllowed(container)) {
+                if(container.hasEntryTestRule()) {
+                    container.setCurrentAttributeType(null);
+                    if(!accessAllowed(container)) {
+                        /*
+                         * If we failed because of a deny permission-bind rule,
+                         * we need to stop and return false.
+                         */
+                        if(container.isDenyEval()) {
+                            return false;
+                        }
+                        /*
+                         * If we failed because there was no explicit
+                         * allow rule, then we grant implicit access to the
+                         * entry.
+                         */
+                    }
+                }
+                return true;
+            }
+        }
+        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
+     * must pass syntax check for the add operation to proceed. Any
+     * entry with an "aci" attribute type must have "modify-acl"
+     * privileges.
+     *
+     * @param entry  The entry to be examined.
+     * @param operation The operation to to check privileges on.
+     * @param clientDN The authorization DN.
+     * @return True if the entry has no ACI attributes or if all of the "aci"
+     * attributes values pass ACI syntax checking.
+     */
+    private boolean
+    verifySyntax(Entry entry, Operation operation, DN clientDN) {
+        if(entry.hasOperationalAttribute(aciType)) {
+            /*
+             * Check that the operation has "modify-acl" privileges since the
+             * entry to be added has an "aci" attribute type.
+             */
+            if (!operation.getClientConnection().
+                    hasPrivilege(Privilege.MODIFY_ACL, operation))  {
+                int    msgID  = MSGID_ACI_ADD_FAILED_PRIVILEGE;
+                String message = getMessage(msgID,
+                        String.valueOf(entry.getDN()),
+                        String.valueOf(clientDN));
+                logError(ErrorLogCategory.ACCESS_CONTROL,
+                         ErrorLogSeverity.SEVERE_WARNING,
+                         message, msgID);
+                return false;
+            }
+            List<Attribute> attributeList =
+                entry.getOperationalAttribute(aciType, null);
+            for (Attribute attribute : attributeList)
+            {
+                for (AttributeValue value : attribute.getValues())
+                {
+                    try {
+                       DN dn=entry.getDN();
+                       Aci.decode(value.getValue(),dn);
+                    } catch (AciException ex) {
+                        int    msgID  = MSGID_ACI_ADD_FAILED_DECODE;
+                        String message = getMessage(msgID,
+                                String.valueOf(entry.getDN()),
+                                ex.getMessage());
+                        logError(ErrorLogCategory.ACCESS_CONTROL,
+                                 ErrorLogSeverity.SEVERE_WARNING,
+                                 message, msgID);
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Check access using the accessAllowed method. The
+     * LDAP add, compare, modify and delete operations use this function.
+     * The other supported LDAP operations have more specialized checks.
+     * @param operationContainer  The container containing the information
+     * needed to evaluate this operation.
+     * @param operation The operation being evaluated.
+     * @return True if this operation is allowed access.
+     */
+    private boolean isAllowed(AciLDAPOperationContainer operationContainer,
+                              Operation operation) {
+        return skipAccessCheck(operation) || accessAllowed(operationContainer);
+    }
+
+    /**
+     * Check access on add operations.
+     *
+     * @param operation The add operation to check access on.
+     * @return  True if access is allowed.
+     */
+    public boolean isAllowed(AddOperation operation) {
+        assert debugEnter(CLASS_NAME, "isAllowed");
+        AciLDAPOperationContainer operationContainer =
+                new AciLDAPOperationContainer(operation, ACI_ADD);
+        boolean ret=isAllowed(operationContainer,operation);
+        //LDAP add needs a verify ACI syntax step in case any
+        //"aci" attribute types are being added.
+        if(ret)
+            ret=verifySyntax(operation.getEntryToAdd(), operation,
+                             operationContainer.getClientDN());
+        return ret;
+    }
+
+   /**
+     * Check access on compare operations. Note that the attribute
+     * type is unavailable at this time, so this method partially
+     * parses the raw attribute string to get the base attribute
+     * type. Options are ignored.
+     *
+     * @param operation The compare operation to check access on.
+     * @return  True if access is allowed.
+     */
+   public boolean isAllowed(CompareOperation operation) {
+       assert debugEnter(CLASS_NAME, "isAllowed");
+
+       AciLDAPOperationContainer operationContainer =
+               new AciLDAPOperationContainer(operation, ACI_COMPARE);
+       String baseName;
+       String rawAttributeType=operation.getRawAttributeType();
+       int  semicolonPosition=rawAttributeType.indexOf(';');
+       if (semicolonPosition > 0)
+         baseName =
+             toLowerCase(rawAttributeType.substring(0, semicolonPosition));
+       else
+         baseName = toLowerCase(rawAttributeType);
+       AttributeType attributeType;
+       if((attributeType =
+           DirectoryServer.getAttributeType(baseName)) == null)
+           attributeType = DirectoryServer.getDefaultAttributeType(baseName);
+       AttributeValue attributeValue =
+           new AttributeValue(attributeType, operation.getAssertionValue());
+       operationContainer.setCurrentAttributeType(attributeType);
+       operationContainer.setCurrentAttributeValue(attributeValue);
+       return isAllowed(operationContainer, operation);
+   }
+
+   /**
+     * Check access on delete operations.
+     *
+     * @param operation The delete operation to check access on.
+     * @return  True if access is allowed.
+     */
+   public boolean isAllowed(DeleteOperation operation) {
+       assert debugEnter(CLASS_NAME, "isAllowed");
+       AciLDAPOperationContainer operationContainer=
+               new AciLDAPOperationContainer(operation, ACI_DELETE);
+       return isAllowed(operationContainer, operation);
+   }
+
+   /**
+    * Check access on modify operations.
+    *
+    * @param operation The modify operation to check access on.
+    * @return  True if access is allowed.
+    */
+
+  public boolean isAllowed(ModifyOperation operation) {
+      assert debugEnter(CLASS_NAME, "isAllowed");
+      AciLDAPOperationContainer operationContainer=
+              new AciLDAPOperationContainer(operation, ACI_NULL);
+      return aciCheckMods(operationContainer, operation,
+                          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
+   * check the access on.
+   * @param entry  The entry to evaluate access.
+   * @return   True if access is allowed.
+   */
+  public boolean
+  maySend(SearchOperation operation, SearchResultEntry entry) {
+      assert debugEnter(CLASS_NAME, "maySend");
+      AciLDAPOperationContainer operationContainer =
+              new AciLDAPOperationContainer(operation,
+                                           (ACI_READ | ACI_SEARCH), entry);
+      return skipAccessCheck(operation) ||
+              accessAllowedEntry(operationContainer);
+  }
+
+  /*
+   * TODO Rename this method. Needs to be changed in SearchOperation.
+   *
+   * I find the name of the filterEntry method to be misleading because
+   * it works on a search operation but has nothing to do with the search
+   * filter.  Something like "removeDisallowedAttributes" would be clearer.
+   */
+  /**
+   * Checks access on each attribute in an entry. It removes those attributes
+   * that fail access check.
+   *
+   * @param operation The search operation class containing information to
+   * check access on.
+   * @param entry   The entry containing the attributes.
+   * @return    The entry to return minus filtered attributes.
+   */
+  public SearchResultEntry filterEntry(SearchOperation operation,
+                                       SearchResultEntry entry) {
+
+      assert debugEnter(CLASS_NAME, "filterEntry");
+      AciLDAPOperationContainer operationContainer =
+              new AciLDAPOperationContainer(operation,
+                                            (ACI_READ | ACI_SEARCH), entry);
+      SearchResultEntry returnEntry;
+      if(!skipAccessCheck(operation)) {
+          returnEntry=accessAllowedAttrs(operationContainer);
+      } else
+          returnEntry=entry;
+      return returnEntry;
+  }
+
+  //Planned to be implemented methods
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean maySend(SearchOperation operation,
+      SearchResultReference reference) {
+    assert debugEnter(CLASS_NAME, "maySend");
+    //TODO: Planned to be implemented.
+    return true;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isAllowed(ModifyDNOperation modifyDNOperation) {
+      assert debugEnter(CLASS_NAME, "isAllowed");
+      // TODO: Planned to be implemented.
+      return true;
+  }
+
+  //Not planned to be implemented methods.
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isAllowed(BindOperation bindOperation) {
+      assert debugEnter(CLASS_NAME, "isAllowed");
+      //Not planned to be implemented.
+      return true;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isAllowed(ExtendedOperation extendedOperation) {
+      assert debugEnter(CLASS_NAME, "isAllowed");
+      //Not planned to be implemented.
+      return true;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean isAllowed(SearchOperation searchOperation) {
+      assert debugEnter(CLASS_NAME, "isAllowed");
+      //Not planned to be implemented.
+      return true;
+  }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
new file mode 100644
index 0000000..58d43f4
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
@@ -0,0 +1,120 @@
+/*
+ * 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 java.util.List;
+
+import org.opends.server.core.AddOperation;
+import org.opends.server.core.CompareOperation;
+import org.opends.server.core.DeleteOperation;
+import org.opends.server.core.ModifyOperation;
+import org.opends.server.core.SearchOperation;
+import org.opends.server.types.Modification;
+import org.opends.server.types.SearchResultEntry;
+
+/**
+ * The AciLDAPOperationContainer is an AciContainer
+ * extended class that wraps each LDAP operation being
+ * evaluated or tested for target matched of an ACI.
+ */
+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.
+     * @param rights  The rights of a compare operation.
+     */
+    public AciLDAPOperationContainer(CompareOperation operation, int rights) {
+        super(operation, rights, operation.getEntryToCompare());
+    }
+
+    /**
+     * Constructor interface for the add operation.
+     * @param operation The add operation to evaluate.
+     * @param rights  The rights of an add operation.
+     */
+    public AciLDAPOperationContainer(AddOperation operation, int rights) {
+        super(operation, rights, operation.getEntryToAdd());
+    }
+
+    /**
+     * Constructor interface for the delete operation.
+     * @param operation The add operation to evaluate.
+     * @param rights  The rights of a delete operation.
+     */
+    public AciLDAPOperationContainer(DeleteOperation operation,  int rights) {
+        super(operation, rights, operation.getEntryToDelete());
+    }
+
+    /**
+     * Constructor interface for the modify operation.
+     * @param rights The rights of modify operation.
+     * @param operation The add operation to evaluate.
+     */
+    public AciLDAPOperationContainer(ModifyOperation operation, int rights) {
+        super(operation, rights, operation.getCurrentEntry());
+        this.modifications=operation.getModifications();
+    }
+
+    /**
+     * Constructor interface for the LDAP search operation.
+     * @param operation The search operation.
+     * @param rights The rights of a search operation.
+     * @param entry The entry to be evaluated for this search.
+     */
+    public AciLDAPOperationContainer(SearchOperation operation,  int rights,
+                                     SearchResultEntry entry) {
+        super(operation, rights,  entry);
+        this.searchEntry = entry;
+    }
+
+    /**
+     * Retrieve the search result entry of the search operation.
+     * @return The search result entry.
+     */
+    public SearchResultEntry getSearchResultEntry() {
+        return this.searchEntry;
+    }
+
+    /** Retrieve the list of modifications if this is a LDAP modify.
+     * @return The list of LDAP modifications to made on the resource entry.
+     */
+    public  List<Modification>  getModifications() {
+        return modifications;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
new file mode 100644
index 0000000..3a85b35
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciList.java
@@ -0,0 +1,251 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.loggers.Error.logError;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.opends.server.types.Attribute;
+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.api.Backend;
+
+/**
+ * The AciList class performs caching of the ACI attribute values
+ * using the entry DN as the key.
+ */
+public class AciList {
+    /*
+     * TODO Change linked list implementation as suggested below.
+     *  I would strongly recommend that you change aciList to be
+     *  LinkedHashMap<DN,List<Aci>> or LinkedHashMap<DN,Aci[]> rather than
+     *  LinkedHashMap<String,Aci>.  It looks like there are some costly
+     *  string->DN and even string->DN->string conversions.  Further, the very
+     *  hackish way that the linked-list is currently maintained is very
+     *  ugly and potentially error-prone.
+     */
+    private LinkedHashMap<DN, Aci> aciList =
+            new LinkedHashMap<DN, Aci>();
+    /*
+     * TODO Evaluate making this class lock-free.
+     *  I would definitely try to make this a lock-free class if at all
+     *  possible. Read locks aren't free to acquire, since they still require
+     *  an exclusive lock at some point.  If possible, you should use a
+     *  copy-on-write structure so that you only incur penalties for changing
+     *  the ACI list (which should be a rare event) and there is no need for
+     *  any kind of locking at all for read operations.
+     */
+    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+    private final Lock aciReadLock  = rwl.readLock();
+    private final Lock aciWriteLock = rwl.writeLock();
+
+    /*
+     * TODO Add support global ACIs in config.ldif.
+     *
+     */
+    /**
+     * Using the base DN, return a list of ACIs that are candidates for
+     * evaluation by walking up from the base DN towards the root of the
+     * DIT gathering ACIs on parents.
+     *
+     * @param baseDN  The DN to check.
+     * @return A list of candidate ACIs that might be applicable.
+     */
+    public LinkedList<Aci> getCandidateAcis(DN baseDN) {
+        LinkedList<Aci> candidates = new LinkedList<Aci>();
+        if(baseDN == null)
+            return candidates;
+        try {
+            aciReadLock.lock();
+            while(baseDN != null) {
+                Aci aci = aciList.get(baseDN);
+                if (aci != null)
+                {
+                    while (aci != null)
+                    {
+                        candidates.add(aci);
+                        aci = aci.next;
+                    }
+                }
+                if(baseDN.isNullDN())
+                    break;
+               DN parentDN=baseDN.getParent();
+               if(parentDN == null)
+                    baseDN=DN.nullDN();
+                else
+                    baseDN=parentDN;
+            }
+        } finally {
+            aciReadLock.unlock();
+        }
+        return candidates;
+    }
+
+
+    /**
+     * Add all of an entries ACI attribute values to the ACI list. This
+     * method locks/unlocks the list.
+     * @param entry The entry containing the "aci" attribute values.\
+     * @return The number of valid ACI attribute values added to the ACI list.
+     */
+    public int addAci(Entry entry) {
+        int validAcis=0;
+        DN dn=entry.getDN();
+        List<Attribute> attributeList =
+                entry.getOperationalAttribute(AciHandler.aciType);
+        try {
+            aciWriteLock.lock();
+            validAcis=addAciAttributeListNoLock(dn, attributeList);
+        } finally {
+            aciWriteLock.unlock();
+        }
+        return validAcis;
+    }
+
+    /**
+     * Add "aci" attribute type values to the ACI list. There is a chance
+     * that an ACI will throw an exception if it has an invalid syntax.
+     * If that happens a message will be logged and the ACI skipped.
+     * @param dn The DN to use a the key in the ACI list.
+     * @param attributeList List of attributes contain the "aci" attribute
+     * values.
+     * @return The number of valid "aci" attribute types added to the ACI list.
+     */
+    private int addAciAttributeListNoLock(DN dn,
+                                    List<Attribute> attributeList) {
+        int validAcis=0;
+        for (Attribute attribute : attributeList) {
+            for (AttributeValue value : attribute.getValues()) {
+                try {
+                    Aci aci= Aci.decode(value.getValue(),dn);
+                    addAci(dn, aci);
+                    validAcis++;
+                } catch (AciException ex) {
+                    /* An illegal ACI might have been loaded
+                     * during import and is failing at ACI handler
+                     * initialization time. Log a message and continue
+                     * processing. ACIs added via LDAP add have their
+                     * syntax checked before adding and should never
+                     * hit this code.
+                     */
+                    int    msgID  = MSGID_ACI_ADD_LIST_FAILED_DECODE;
+                    String message = getMessage(msgID,
+                            ex.getMessage());
+                    logError(ErrorLogCategory.ACCESS_CONTROL,
+                             ErrorLogSeverity.SEVERE_WARNING,
+                             message, msgID);
+                }
+            }
+        }
+        return validAcis;
+    }
+
+    /**
+     * Remove all of the ACIs related to the old entry and then add all of the
+     * ACIs related to the new entry. This method locks/unlocks the list.
+     * @param oldEntry The old entry maybe containing old "aci" attribute
+     * values.
+     * @param newEntry The new entry maybe containing new "aci" attribute
+     * values.
+     */
+    public void modAciOldNewEntry(Entry oldEntry, Entry newEntry) {
+         if((oldEntry.hasOperationalAttribute(AciHandler.aciType)) ||
+                 (newEntry.hasOperationalAttribute(AciHandler.aciType))) {
+             try {
+                 aciWriteLock.lock();
+                 aciList.remove(oldEntry.getDN());
+                 List<Attribute> attributeList =
+                     newEntry.getOperationalAttribute(AciHandler.aciType, null);
+                 addAciAttributeListNoLock(newEntry.getDN(),attributeList);
+             } finally {
+                 aciWriteLock.unlock();
+             }
+         }
+     }
+
+    /**
+     * Add an ACI using the DN as a key. If the DN already
+     * has ACI(s) on the list, then the new ACI is added to the
+     * end of the linked list.
+     * @param dn The DN to use as the key.
+     * @param aci  The ACI to add to the list.
+     */
+    public void addAci(DN dn, Aci aci)  {
+        if(aciList.containsKey(dn)) {
+            Aci tmpAci = aciList.get(dn);
+            while(tmpAci.next != null)
+                tmpAci=tmpAci.next;
+            tmpAci.next=aci;
+        } else
+            aciList.put(dn, aci);
+    }
+
+    /**
+     * Remove ACIs related to an entry.
+     * @param entry The entry to be removed.
+     * @return True if the ACI set was deleted.
+     */
+    public boolean removeAci(Entry entry) {
+        boolean deleted = false;
+        try {
+            aciWriteLock.lock();
+            if (aciList.remove(entry.getDN()) != null)
+                deleted = true;
+        } finally {
+            aciWriteLock.unlock();
+        }
+        return deleted;
+    }
+
+    /**
+     * Remove all ACIs related to a backend.
+     * @param backend  The backend to check if each DN is handled by that
+     * backend.
+     */
+    public void removeAci (Backend backend) {
+        try {
+            aciWriteLock.lock();
+            Set<DN> keys=aciList.keySet();
+            for(DN dn : keys) {
+                if (backend.handlesEntry(dn))
+                    aciList.remove(dn);
+            }
+        } finally {
+            aciWriteLock.unlock();
+        }
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
new file mode 100644
index 0000000..0d82365
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
@@ -0,0 +1,210 @@
+/*
+ * 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.api.ChangeNotificationListener;
+import org.opends.server.api.BackendInitializationListener;
+import org.opends.server.api.Backend;
+import org.opends.server.types.*;
+import org.opends.server.types.operation.PostResponseAddOperation;
+import org.opends.server.types.operation.PostResponseDeleteOperation;
+import org.opends.server.types.operation.PostResponseModifyOperation;
+import org.opends.server.types.operation.PostResponseModifyDNOperation;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.internal.InternalSearchOperation;
+import static org.opends.server.loggers.Debug.debugException;
+import static org.opends.server.loggers.Error.logError;
+import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+
+import java.util.LinkedHashSet;
+
+/**
+ * The AciListenerManager updates an ACI list after each
+ * modification operation. Also, updates ACI list when backends are initialized
+ * and finalized.
+ */
+public class AciListenerManager
+        implements ChangeNotificationListener, BackendInitializationListener {
+
+    /**
+   * The fully-qualified name of this class for debugging purposes.
+   */
+  private static final String CLASS_NAME =
+       "org.opends.server.core.AciListenerManager";
+
+    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.
+     */
+    private static LinkedHashSet<String> attrs = new LinkedHashSet<String>();
+
+    static {
+        /*
+         * Set up the filter used to search private and public contexts.
+         */
+        try {
+            aciFilter=SearchFilter.createFilterFromString("(aci=*)");
+        } catch (DirectoryException ex) {
+            //TODO should never happen, error message?
+        }
+        attrs.add("aci");
+    }
+    /**
+     * Save the list created by the AciHandler routine.
+     * @param aciList The list object created and loaded by the handler.
+     */
+    public AciListenerManager(AciList aciList) {
+        this.aciList=aciList;
+    }
+
+    /**
+     * A delete operation succeeded. Remove any ACIs associated with the
+     * entry deleted.
+     * @param deleteOperation The delete operation.
+     * @param entry The entry being deleted.
+     */
+    public void handleDeleteOperation(PostResponseDeleteOperation
+                                      deleteOperation, Entry entry) {
+       if(entry.hasOperationalAttribute(AciHandler.aciType)) {
+            aciList.removeAci(entry);
+       }
+    }
+
+    /**
+     * An Add operation succeeded. Add any ACIs associated with the
+     * entry being added.
+     * @param addOperation  The add operation.
+     * @param entry   The entry being added.
+     */
+    public void handleAddOperation(PostResponseAddOperation addOperation,
+            Entry entry) {
+        if(entry.hasOperationalAttribute(AciHandler.aciType))
+        {
+            aciList.addAci(entry);
+        }
+    }
+
+    /**
+     * A modify operation succeeded. Adjust the ACIs by removing
+     * ACIs based on the oldEntry and then adding ACIs based on the new
+     * entry.
+     * @param modOperation  the modify operation.
+     * @param oldEntry The old entry to examine.
+     * @param newEntry  The new entry to examine.
+     */
+    public void handleModifyOperation(PostResponseModifyOperation modOperation,
+            Entry oldEntry, Entry newEntry)
+    {
+        aciList.modAciOldNewEntry(oldEntry, newEntry);
+    }
+
+    /**
+     * Not implemented.
+     * @param modifyDNOperation  The LDAP modify DN operation.
+     * @param oldEntry  The old entry.
+     * @param newEntry The new entry.
+     */
+    public void handleModifyDNOperation(
+            PostResponseModifyDNOperation modifyDNOperation,
+            Entry oldEntry, Entry newEntry)
+    {
+        /*
+         * TODO Not yet implemented.
+         */
+    }
+
+    /**
+     * {@inheritDoc}  In this case, the server will search the backend to find
+     * all aci attribute type values that it may contain and add them to the
+     * ACI list.
+     */
+    public void performBackendInitializationProcessing(Backend backend) {
+        InternalClientConnection conn =
+                InternalClientConnection.getRootConnection();
+        for (DN baseDN : backend.getBaseDNs()) {
+            try {
+                if (! backend.entryExists(baseDN))  {
+                    continue;
+                }
+            } catch (Exception e) {
+                assert debugException(CLASS_NAME,
+                        "performBackendInitializationProcessing", e);
+                //TODO log message
+                continue;
+            }
+            InternalSearchOperation internalSearch =
+                    new InternalSearchOperation(conn,
+                            InternalClientConnection.nextOperationID(),
+                            InternalClientConnection.nextMessageID(),
+                            null, baseDN, SearchScope.WHOLE_SUBTREE,
+                            DereferencePolicy.NEVER_DEREF_ALIASES,
+                            0, 0, false, aciFilter, attrs, null);
+            try
+            {
+                backend.search(internalSearch);
+            } catch (Exception e) {
+                assert debugException(CLASS_NAME,
+                        "performBackendInitializationProcessing", e);
+                //TODO log message
+                continue;
+            }
+            if(internalSearch.getSearchEntries().isEmpty()) {
+                int    msgID  = MSGID_ACI_ADD_LIST_NO_ACIS;
+                String message = getMessage(msgID, String.valueOf(baseDN));
+                logError(ErrorLogCategory.ACCESS_CONTROL,
+                        ErrorLogSeverity.NOTICE, message, msgID);
+            } else {
+                int validAcis=0;
+                for (SearchResultEntry entry :
+                        internalSearch.getSearchEntries()) {
+                    validAcis += aciList.addAci(entry);
+                }
+                int    msgID  = MSGID_ACI_ADD_LIST_ACIS;
+                String message = getMessage(msgID, Integer.toString(validAcis),
+                        String.valueOf(baseDN));
+                logError(ErrorLogCategory.ACCESS_CONTROL,
+                        ErrorLogSeverity.NOTICE,
+                        message, msgID);
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}  In this case, the server will remove all aci attribute
+     * type values associated with entries in the provided backend.
+     */
+    public void performBackendFinalizationProcessing(Backend backend) {
+        aciList.removeAci(backend);
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java
new file mode 100644
index 0000000..1dd5539
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciMessages.java
@@ -0,0 +1,827 @@
+/*
+ * 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 static org.opends.server.messages.MessageHandler.*;
+
+/**
+ * The AciMessages class defines the set of message IDs and default format
+ * strings for messages associated with the dseecompat access control
+ * implementation.
+ */
+public class AciMessages {
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value cannot be parsed because it failed the non-specific regular
+     * expression check during the initial ACI decode process. This takes one
+     * argument, which is the string representation of the "aci" attribute
+     * type value.
+     */
+    public static final int MSGID_ACI_SYNTAX_GENERAL_PARSE_FAILED =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 1;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of an invalid version string. This
+     * takes one argument, which is the version string parsed from the
+     * "aci" attribute type value.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVAILD_VERSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 2;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of an invalid access type string. This
+     * takes one argument, which is the access type string parsed from the
+     * "aci" attribute type value.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_ACCESS_TYPE_VERSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 3;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of an invalid rights string. This
+     * takes one argument, which is the rights string parsed from the
+     * "aci" attribute type value.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_RIGHTS_SYNTAX =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 4;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of an invalid rights keyword. This
+     * takes one argument, which is the rights keyword string parsed from the
+     * rights string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_RIGHTS_KEYWORD =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 5;
+
+    /**
+     * The message ID for the message that will be used if an ACI bind rule
+     * value failed parsing because it starts with an open parenthesis,
+     * but does not contain a matching close parenthesis.  This takes one
+     * argument, which is the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_BIND_RULE_MISSING_CLOSE_PAREN =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_MILD_ERROR | 6;
+
+    /**
+     * The message ID for the message that will be used if an ACI bind rule
+     * value failed parsing because it is an invalid bind rule syntax. This
+     * takes one argument, which is the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_BIND_RULE_SYNTAX =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_MILD_ERROR | 7;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of an invalid bind rule keyword. This
+     * takes one argument, which is the bind rule keyword string parsed from
+     * the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 8;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of an invalid bind rule operator. This
+     * takes one argument, which is the bind rule operator string parsed
+     * from the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_BIND_RULE_OPERATOR =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 9;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of a missing bind rule expression
+     * string. This takes one argument, which is the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_MISSING_BIND_RULE_EXPRESSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 10;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of an invalid bind rule boolean
+     * operator. This takes one argument, which is the bind rule boolean
+     * operator string parsed from the bind rule string.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_INVALID_BIND_RULE_BOOLEAN_OPERATOR =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 11;
+
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of an invalid bind rule keyword,
+     * keyword operation combination. This takes two arguments, which are the
+     * bind rule keyword string and the bind rule keyword operator parsed from
+     * the bind rule string.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD_OPERATOR_COMBO =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 12;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule userdn LDAP URL failed
+     * to decode.  This takes one argument the message from the LDAP
+     * URL decode DirectoryException.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_USERDN_URL =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 13;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule roledn expression failed
+     * to parse.  This takes one argument, which is the roledn expression
+     * string parsed from the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_ROLEDN_EXPRESSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 14;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule roledn LDAP URL failed
+     * to decode.  This takes one argument the message from the LDAP
+     * URL decode DirectoryException.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_ROLEDN_URL =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 15;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule groupdn expression failed
+     * to parse.  This takes one argument, which is the groupdn expression
+     * string parsed from the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_GROUPDN_EXPRESSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 16;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule groupdn LDAP URL failed
+     * to decode.  This takes one argument the message from the LDAP
+     * URL decode DirectoryException.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_GROUPDN_URL =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 17;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule ip keyword expression
+     * network mask value did not match the expression network address value.
+     * For example, the ACI has a IPV6 network mask; but the internet
+     * address part is IPV4. This takes two arguments, which are the
+     * bind rule ip netmask string and the bind rule ip inet address
+     * parsed from the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_ADDRESS_FAMILY_MISMATCH =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 18;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule ip keyword expression
+     * failed to parse because the number of bits specified to match the
+     * network was not valid for the inet address specified. This takes
+     * two arguments, which an string specifying the address type
+     * (inet6address, inet4address) and an error message.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_NETWORK_BIT_MATCH =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 19;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule ip expression failed
+     * to decode.  This takes one argument, the message from the
+     * thrown exception.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_IP_CRITERIA_DECODE =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 20;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule ip expression failed
+     * to parse.  This takes one argument, which is the ip expression
+     * string parsed from the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_IP_EXPRESSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 21;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule dns expression failed
+     * to parse.  This takes one argument, which is the dns expression
+     * string parsed from the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_DNS_EXPRESSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 22;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule dns expression failed
+     * to parse because a wild-card was not in the leftmost position.
+     * This takes one argument, which is the dns expression string parsed
+     * from the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_DNS_WILDCARD =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 23;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule dayofweek expression failed
+     * to parse.  This takes one argument, which is the dayofweek expression
+     * string parsed from the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_DAYOFWEEK =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING |24;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule timeofday expression failed
+     * to parse.  This takes one argument, which is the timeofday expression
+     * string parsed from the bind rule string.
+     */
+
+    public static final int MSGID_ACI_SYNTAX_INVALID_TIMEOFDAY =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING |25;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule timeofday expression failed
+     * to parse because the timeofday was not in a valid range.  This takes one
+     * argument, which is the timeofday expression string parsed from the
+     * bind rule string.
+     */
+
+    public static final int MSGID_ACI_SYNTAX_INVALID_TIMEOFDAY_RANGE =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING |26;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule authmethod expression failed
+     * to parse.  This takes one argument, which is the authmethod expression
+     * string parsed from the bind rule string.
+     */
+
+    public static final int MSGID_ACI_SYNTAX_INVALID_AUTHMETHOD_EXPRESSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING |27;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule userattr expression failed
+     * to decode.  This takes one argument, the message from the
+     * thrown exception.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_USERATTR_EXPRESSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 28;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule userattr expression value
+     * is not supported.  This takes one argument, which is the userattr
+     * expression string parsed from the bind rule string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_USERATTR_KEYWORD =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 29;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule userattr expression
+     * inheritance pattern did not parse.  This takes one argument, which
+     * is the userattr expression inheritance pattern string parsed
+     * from the bind rule string.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_INVALID_USERATTR_INHERITANCE_PATTERN =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 30;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule userattr expression
+     * inheritance level exceeded the max value.  This takes two arguments,
+     * which are the userattr expression inheritance pattern string parsed
+     * from the bind rule string and the max leval value.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_MAX_USERATTR_INHERITANCE_LEVEL_EXCEEDED =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 31;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule userattr expression
+     * inheritance level was non-numeric.  This takes one argument,
+     * which is the userattr expression inheritance level pattern string
+     * parsed from the bind rule string.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_INVALID_INHERITANCE_VALUE =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 32;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a target rule had an invalid syntax.
+     * This takes one argument, which is the target rule string
+     * parsed from the "aci" attribute type value string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_TARGET_SYNTAX =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 33;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of an invalid target keyword. This
+     * takes one argument, which is the target keyword string parsed
+     * from the "aci" attribute type value string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_TARGET_KEYWORD =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 34;
+
+    /**
+     * 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.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_TARGET_OPERATOR =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 35;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of a target keyword is not supported
+     * at this time. This takes one argument, which is the unsupported target
+     * keyword string parsed from the "aci" attribute type value string.
+     */
+    public static final int MSGID_ACI_SYNTAX_TARGET_KEYWORD_NOT_SUPPORTED =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 36;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of a target keyword was seen multiple
+     * times in the value. This takes two arguments, which are the target
+     * keyword string parsed from the "aci" attribute type value string and
+     * the "aci" attribute type value string.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 37;
+
+    /**
+     * 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
+     * operator string parsed from the "aci" attribute type value string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_OPERATOR =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 38;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of an invalid targetscope expression.
+     * This takes one argument, which is the targetscope expression
+     * string parsed from the "aci" attribute type value string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_EXPRESSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 39;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of an invalid target keyword
+     * expression.  This takes one argument, which is the target keyword
+     * expression string parsed from the "aci" attribute type value string.
+     */
+    public static final int MSGID_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 40;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of a target keyword DN is not a
+     * descendant of the ACI entry DN. This takes two arguments, which are
+     * the target keyword DN string parsed from the "aci" attribute type value
+     * string and the DN of the "aci" attribute type entry.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_TARGET_DN_NOT_DESCENDENTOF =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 41;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of a targetattr keyword expression
+     * is invalid. This takes one argument, which is the targetattr
+     * keyword expression string parsed from the "aci" attribute type value
+     * string.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_INVALID_TARGETATTRKEYWORD_EXPRESSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 42;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value failed parsing because of a targetfilter keyword expression
+     * string is invalid. This takes one argument, which is the targetfilter
+     * keyword expression string parsed from the "aci" attribute type value
+     * string.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_INVALID_TARGETFILTERKEYWORD_EXPRESSION =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 43;
+
+    /**
+     * The message ID for the ACI message that will be generated when a client
+     * attempts to add an entry with the "aci" attribute type
+     * and they do not have the required "modify-acl"privilege.  This takes two
+     * arguments, which are the string representation of the entry DN of the
+     * entry being added, and the string representation of the
+     * authorization DN.
+     */
+    public static final int MSGID_ACI_ADD_FAILED_PRIVILEGE =
+        CATEGORY_MASK_ACCESS_CONTROL  | 44;
+
+
+    /**
+     * The message ID for the ACI message that will be generated when a client
+     * attempts to perform a modification on an "aci" attribute type
+     * and they do not have the required "modify-acl"privilege.  This takes two
+     * arguments, which are the string representation of the entry DN of the
+     * entry being modified, and the string representation of the
+     * authorization DN.
+     */
+    public static final int MSGID_ACI_MODIFY_FAILED_PRIVILEGE =
+        CATEGORY_MASK_ACCESS_CONTROL  | 45;
+
+    /**
+     * The message ID for the ACI message that will be generated when a client
+     * attempts to add an entry with the "aci" attribute type
+     * and the ACI decode failed because of an syntax error.  This takes one
+     * argument, which is the message string thrown by the AciException.
+     */
+    public static final int MSGID_ACI_ADD_FAILED_DECODE =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 46;
+
+    /**
+     * The message ID for the ACI message that will be generated when a client
+     * attempts to perform a modification on an "aci" attribute type
+     * and the ACI decode failed because of a syntax error.  This takes one
+     * argument, which is the message string thrown by the AciException.
+     */
+    public static final int MSGID_ACI_MODIFY_FAILED_DECODE =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 47;
+
+    /**
+     * The message ID for the ACI message that will be generated when
+     * an ACI decode failed because of an syntax error. This message is usually
+     * generated by an invalid ACI that was added during import which
+     * fails the decode at server startup. This takes one
+     * argument, which is the message string thrown by the AciException.
+     */
+    public static final int MSGID_ACI_ADD_LIST_FAILED_DECODE =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 48;
+
+    /**
+     * The message ID for the ACI message that will be generated the server
+     * searches an directory context for "aci" attribute types and finds none.
+     * This takes one argument, which is the DN of the directory context.
+     */
+    public static final int MSGID_ACI_ADD_LIST_NO_ACIS =
+        CATEGORY_MASK_ACCESS_CONTROL | 49;
+
+    /**
+     * The message ID for the ACI message that will be generated the server
+     * searches an directory context for "aci" attribute types and finds some.
+     * This takes two arguments, which are the DN of the directory context,
+     * the number of valid ACIs decoded.
+     */
+    public static final int MSGID_ACI_ADD_LIST_ACIS =
+        CATEGORY_MASK_ACCESS_CONTROL | 50;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a bind rule userattr roledn expression
+     * inheritance pattern did not parse.  This takes one argument, which
+     * is the userattr expression inheritance pattern string parsed
+     * from the bind rule string.
+     */
+    public static
+    final int MSGID_ACI_SYNTAX_INVALID_USERATTR_ROLEDN_INHERITANCE_PATTERN =
+        CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 51;
+    /**
+     * Associates a set of generic messages with the message IDs defined in
+     * this class.
+     */
+    public static void registerMessages() {
+
+        registerMessage(MSGID_ACI_SYNTAX_GENERAL_PARSE_FAILED,
+                "The provided string  \"%s\" could not be parsed as a valid " +
+                "Access Control Instruction (ACI) because it failed "+
+                "general ACI syntax evaluation.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVAILD_VERSION,
+                "The provided Access Control Instruction (ACI) version " +
+                "value  \"%s\" is invalid, only the version 3.0 is " +
+                "supported.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_ACCESS_TYPE_VERSION,
+                "The provided Access Control Instruction access " +
+                "type value  \"%s\" is invalid. A valid access type " +
+                "value is either allow or deny.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_RIGHTS_SYNTAX,
+                "The provided Access Control Instruction (ACI) rights " +
+                "values \"%s\" are invalid. The rights must be a " +
+                "list of 1 to 6 comma-separated keywords enclosed in " +
+                "parentheses.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_RIGHTS_KEYWORD,
+                "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" +
+                "all.");
+
+        registerMessage(MSGID_ACI_SYNTAX_BIND_RULE_MISSING_CLOSE_PAREN,
+                "The provided Access Control Instruction (ACI) bind " +
+                "rule value \"%s\" is invalid because it is missing a " +
+                "close parenthesis that corresponded to the initial open " +
+                "parenthesis.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_BIND_RULE_SYNTAX,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "value \"%s\" is invalid. A valid bind rule value must " +
+                "be in the following form: " +
+                "keyword operator \"expression\".");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "keyword value \"%s\" is invalid. A valid keyword value is" +
+                " one of the following: userdn, groupdn, roledn, userattr," +
+                "ip, dns, dayofweek, timeofday or authmethod.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_BIND_RULE_OPERATOR ,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "operator value  \"%s\" is invalid. A valid bind rule " +
+                "operator value is either '=' or \"!=\".");
+
+        registerMessage(MSGID_ACI_SYNTAX_MISSING_BIND_RULE_EXPRESSION ,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "expression value corresponding to the keyword value " +
+                "\"%s\" is missing an expression. A valid bind rule value " +
+                "must be in the following form:" +
+                " keyword operator \"expression\".");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_BIND_RULE_BOOLEAN_OPERATOR ,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "boolean operator value \"%s\" is invalid. A valid bind" +
+                "rule boolean operator value is either \"OR\" or \"AND\".");
+
+        registerMessage(
+                MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD_OPERATOR_COMBO,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "keyword string  \"%s\" is invalid for the bind rule " +
+                "operator string \"%s\".");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_USERDN_URL,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "userdn expression failed to URL decode for " +
+                "the following reason: %s");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_ROLEDN_EXPRESSION,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "roledn expression value \"%s\" is invalid. A valid roledn " +
+                "keyword expression value requires one or more LDAP URLs " +
+                "in the following format: " +
+                "ldap:///dn [|| ldap:///dn] ... [|| ldap:///dn].");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_ROLEDN_URL,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "roledn expression failed to URL decode for " +
+                "the following reason: %s");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_GROUPDN_EXPRESSION,
+         "The provided Access Control Instruction (ACI) bind rule " +
+          "groupdn expression value \"%s\" is invalid. A valid groupdn " +
+         "keyword expression  value requires one or more LDAP URLs in the" +
+         " following format: " +
+         "ldap:///groupdn [|| ldap:///groupdn] ... [|| ldap:///groupdn].");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_GROUPDN_URL,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "groupdn expression value failed to URL decode for " +
+                "the following reason: %s");
+
+        registerMessage(MSGID_ACI_SYNTAX_ADDRESS_FAMILY_MISMATCH,
+                "The network mask value \"%s\" is not valid for " +
+                "the ip expression network address \"%s\".");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_NETWORK_BIT_MATCH,
+                "The bit mask for address type value \"%s\" is not valid." +
+                "%s.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_IP_CRITERIA_DECODE,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "ip expression value failed to decode for " +
+                "the following reason: %s");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_IP_EXPRESSION,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "ip expression value \"%s\" is invalid. A valid ip " +
+                "keyword expression value requires one or more" +
+                "comma-separated elements of an IP address list expression.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_DNS_EXPRESSION,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "dns expression value \"%s\" is invalid. A valid dns " +
+                "keyword expression value requires a valid fully qualified"+
+                " DNS domain name.");
+
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_DNS_WILDCARD,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "dns expression value \"%s\" is invalid, because a wild-card" +
+                " pattern was found in the wrong position. A valid dns " +
+                "keyword wild-card expression value requires the '*' " +
+                "character only be in the leftmost position of the " +
+                "domain name.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_DAYOFWEEK,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "dayofweek expression value \"%s\" is invalid, because of " +
+                "an invalid day of week value. A valid dayofweek value " +
+                "is one of the following English three-letter abbreviations" +
+                "for the days of the week: sun, mon, tue, wed, thu, " +
+                "fri, or sat.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TIMEOFDAY,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "timeofday expression value \"%s\" is invalid. A valid " +
+                "timeofday value is expressed as four digits representing " +
+                "hours and minutes in the 24-hour clock (0 to 2359).");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TIMEOFDAY_RANGE,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "timeofday expression value \"%s\" is not in the valid" +
+                 " range. A valid timeofday value is expressed as four" +
+                 " digits representing hours and minutes in the 24-hour" +
+                 " clock (0 to 2359).");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_AUTHMETHOD_EXPRESSION,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "authmethod expression value \"%s\" is invalid. A valid " +
+                "authmethod value is one of the following: none, simple," +
+                "SSL, sasl EXTERNAL, sasl DIGEST-MD5, or sasl GSSAPI.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_USERATTR_EXPRESSION,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "userattr expression value \"%s\" is invalid.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_USERATTR_KEYWORD,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "userattr expression value \"%s\" is not supported.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_USERATTR_INHERITANCE_PATTERN,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "userattr expression inheritance pattern value \"%s\" is " +
+                "invalid. A valid inheritance pattern value must have" +
+                "the following format:" +
+                " parent[inheritance_level].attribute#bindType.");
+
+        registerMessage(
+                MSGID_ACI_SYNTAX_MAX_USERATTR_INHERITANCE_LEVEL_EXCEEDED,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "userattr expression inheritance pattern value \"%s\" is " +
+                "invalid. The inheritance level value cannot exceed the" +
+                "max level limit of %s.");
+
+        registerMessage(
+                MSGID_ACI_SYNTAX_INVALID_INHERITANCE_VALUE,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "userattr expression inheritance pattern value \"%s\" is" +
+                " invalid because it is non-numeric.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGET_SYNTAX,
+                "The provided Access Control Instruction (ACI) target rule" +
+                "value \"%s\" is invalid. A valid target rule value must" +
+                "be in the following form: " +
+                "keyword operator \"expression\".");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGET_KEYWORD,
+                "The provided Access Control Instruction (ACI) target " +
+                "keyword value \"%s\" is invalid. A valid target keyword" +
+                " value is one of the following: target, targetscope, " +
+                "targetfilter, targetattr or targetattrfilters.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGET_OPERATOR,
+                "The provided Access Control Instruction (ACI) target " +
+                "keyword operator value  \"%s\" is invalid. A valid target" +
+                "keyword operator value is either '=' or \"!=\".");
+
+        registerMessage(MSGID_ACI_SYNTAX_TARGET_KEYWORD_NOT_SUPPORTED,
+                "The provided Access Control Instruction (ACI) " +
+                "target keyword value \"%s\" is not supported at this time.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS,
+                "The provided Access Control Instruction (ACI) " +
+                "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_TARGETSCOPE_EXPRESSION,
+                "The provided Access Control Instruction (ACI) targetscope" +
+                " expression operator value  \"%s\" is invalid. A valid" +
+                " targetscope expression value is one of the following: one," +
+                " onelevel or subtree.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION,
+                "The provided Access Control Instruction (ACI)" +
+                " target expression value \"%s\" is invalid. A valid target" +
+                " keyword expression  value requires a LDAP URL in the" +
+                " following format: ldap:///distinguished_name.");
+
+        registerMessage(MSGID_ACI_SYNTAX_TARGET_DN_NOT_DESCENDENTOF,
+                "The provided Access Control Instruction (ACI) " +
+                "target expression DN value \"%s\" is invalid. The target " +
+                "expression DN value must be a descendant of the ACI entry" +
+                " DN \"%s\", if no wild-card is specified in the target" +
+                "expression DN.");
+
+        registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGETATTRKEYWORD_EXPRESSION,
+                "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: " +
+                "attribute1 [|| attribute1] ... [|| attributen].");
+
+        registerMessage(
+                MSGID_ACI_SYNTAX_INVALID_TARGETFILTERKEYWORD_EXPRESSION,
+                "The provided Access Control Instruction (ACI)" +
+                " targetfilter expression value \"%s\" is invalid because it" +
+                " is not a valid LDAP filter.");
+
+        registerMessage(MSGID_ACI_ADD_FAILED_PRIVILEGE,
+                "An attempt to add the entry \"%s\" containing" +
+                " an aci attribute type failed, because the authorization DN" +
+                " \"%s\" lacked modify-acl privileges.");
+
+        registerMessage(MSGID_ACI_MODIFY_FAILED_PRIVILEGE,
+                "An attempt to modify an aci "+
+                "attribute type in the entry \"%s\" failed, because the" +
+                "authorization DN \"%s\" lacked modify-acl privileges.");
+
+        registerMessage(MSGID_ACI_ADD_FAILED_DECODE,
+                "An attempt to add the entry \"%s\" containing" +
+                " an aci attribute type failed because of the following" +
+                " reason: %s");
+
+        registerMessage(MSGID_ACI_MODIFY_FAILED_DECODE,
+                "An attempt to modify an aci "+
+                "attribute type in the entry \"%s\" failed "+
+                "because of the following reason: %s");
+
+        registerMessage(MSGID_ACI_ADD_LIST_FAILED_DECODE,
+                "An attempt to decode an Access Control Instruction (ACI)" +
+                " failed because of the following reason: %s");
+
+        registerMessage(MSGID_ACI_ADD_LIST_NO_ACIS,
+                "No Access Control Instruction (ACI) attribute types were" +
+                " found in context \"%s\".");
+
+        registerMessage(MSGID_ACI_ADD_LIST_ACIS,
+                "Added %s Access Control Instruction (ACI) attribute types" +
+                " found in context \"%s\" to the access" +
+                "control evaluation engine.");
+
+        registerMessage(
+                MSGID_ACI_SYNTAX_INVALID_USERATTR_ROLEDN_INHERITANCE_PATTERN,
+                "The provided Access Control Instruction (ACI) bind rule " +
+                "userattr expression inheritance pattern value " +
+                "\"%s\" is invalid for the roledn keyword because it starts " +
+                        "with the string \"parent[\".");
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java
new file mode 100644
index 0000000..05a71e1
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciProvider.java
@@ -0,0 +1,85 @@
+/*
+ * 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.api.AccessControlHandler;
+import org.opends.server.api.AccessControlProvider;
+import org.opends.server.config.ConfigEntry;
+import org.opends.server.config.ConfigException;
+import org.opends.server.types.InitializationException;
+import static org.opends.server.loggers.Debug.debugConstructor;
+
+/**
+ * This class is the provider class for the dseecompt ACI.
+ */
+public class AciProvider  implements AccessControlProvider  {
+
+    private static final String CLASS_NAME =
+      "org.opends.server.authorization.dseecompat.AciProvider";
+
+    private static AciHandler instance = null;
+
+    /**
+     * Create an aci provider. This doesn't do much.
+     */
+    public AciProvider() {
+        super();
+        assert debugConstructor(CLASS_NAME);
+    }
+
+
+    /**
+     * Creates the AciHandler class and calls its initialization method.
+     * @param configEntry The entry containing the configuration Access Control
+     * entry.
+     * @throws ConfigException If the initialization fails.
+     * @throws InitializationException If the initialization fails.
+     */
+    public void initializeAccessControlHandler(ConfigEntry configEntry)
+    throws ConfigException, InitializationException {
+        getInstance();
+    }
+
+    /**
+     * Returns a new AciHandler instance. There can be only one active.
+     * @return  A new AciHandler instance.
+     */
+    public  AccessControlHandler getInstance() {
+        if (instance == null) {
+            instance = new AciHandler();
+        }
+        return instance;
+    }
+
+    /**
+     * Not used at this time.
+     */
+    public void finalizeAccessControlHandler() {
+
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
new file mode 100644
index 0000000..2276a50
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
@@ -0,0 +1,134 @@
+/*
+ * 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.AttributeValue;
+import org.opends.server.types.Entry;
+import java.util.LinkedList;
+
+/**
+ * The AciTargetMatchContext interface provides a
+ * view of an AciContainer that exposes information to be
+ * used by the Aci.isApplicable() method to determine if
+ * an ACI is applicable (targets matched) to the LDAP operation,
+ * operation rights and entry and attributes having access
+ * checked on.
+ */
+public interface AciTargetMatchContext {
+    /**
+     * Set the deny ACI list.
+     * @param denyList The deny ACI list.
+     */
+    public void setDenyList(LinkedList<Aci> denyList);
+
+    /**
+     * Set the allow ACI list.
+     * @param allowList The list of allow ACIs.
+     */
+    public void setAllowList(LinkedList<Aci> allowList);
+
+    /**
+     * Get the entry being evaluated. This is known as the
+     * resource entry.
+     * @return The entry being evaluated.
+     */
+    public Entry getResourceEntry();
+
+    /**
+     * Get the current attribute type being evaluated.
+     * @return  The attribute type being evaluated.
+     */
+    public AttributeType getCurrentAttributeType();
+
+    /**
+     * The current attribute type value being evaluated.
+     * @return The current attribute type value being evaluated.
+     */
+    public AttributeValue getCurrentAttributeValue();
+
+    /**
+     * True if the first attribute of the resource entry is being evaluated.
+     * @return True if this is the first attribute.
+     */
+    public boolean isFirstAttribute();
+
+    /**
+     * Set to true if the first attribute of the resource entry is
+     * being evaluated.
+     * @param isFirst  True if this is the first attribute of the
+     * resource entry being evaluated.
+     */
+    public void setIsFirstAttribute(boolean isFirst);
+
+    /**
+     * Set the attribute type to be evaluated.
+     * @param type  The attribute type to set to.
+     */
+    public void setCurrentAttributeType(AttributeType type);
+
+    /**
+     * Set the attribute value to be evaluated.
+     * @param v The current attribute value to set to.
+     */
+    public void setCurrentAttributeValue(AttributeValue v);
+
+    /**
+     * True if the target matching code found an entry test rule. An
+     * entry test rule is an ACI without a targetattr target rule.
+     * @param val True if an entry test rule was found.
+     */
+    public void setEntryTestRule(boolean val);
+
+    /**
+     * True if an entry test rule was found.
+     * @return True if an entry test rule was found.
+     */
+    public boolean hasEntryTestRule();
+
+    /**
+     * Return the rights for this container's LDAP operation.
+     * @return  The rights for the container's LDAP operation.
+     */
+    public int getRights();
+
+    /**
+     * Checks if the container's rights has the specified rights.
+     * @param  rights The rights to check for.
+     * @return True if the container's rights has the specified rights.
+     */
+    public boolean hasRights(int rights);
+
+    /**
+     * Set the rights of the container to the specified rights.
+     * @param rights The rights to set the container's rights to.
+     */
+    public void setRights(int rights);
+}
+
+
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
new file mode 100644
index 0000000..8352955
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
@@ -0,0 +1,472 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.DN;
+import org.opends.server.types.SearchScope;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class represents target part of an ACI's syntax. This is the part
+ * 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.
+ */
+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.
+     */
+    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.
+     */
+    private static final String targetRegex =
+            "\\(\\s*(\\w+)\\s*(!?=)\\s*\"([^\"]+)\"\\s*\\)\\s*";
+    /**
+    * Regular expression used in target matching.
+    */
+    public static final String targetsRegex = "(" + targetRegex + ")*";
+
+    /*
+     * Rights that are skipped for certain target evaluations.
+     * The test is use the skipRights array is:
+     *
+     * Either the ACI has a targetattr's rule and the current
+     * attribute type is null or the current attribute type has
+     * a type specified and the targetattr's rule is null.
+     *
+     * The actual check against the skipRights array is:
+     *
+     *  1. Is the ACI's rights in this array? For example,
+     *     allow(all) or deny(add)
+     *
+     *  AND
+     *
+     *  2. Is the rights from the LDAP operation in this array? For
+     *      example, an LDAP add would have rights of add and all.
+     *
+     *  If both are true, than the target match test returns true
+     *  for this ACI.
+     */
+
+    private static final int skipRights =
+            (AciHandler.ACI_ADD | AciHandler.ACI_DELETE | AciHandler.ACI_PROXY);
+
+    /**
+     * Creates an ACI target from the specified arguments. All of these
+     * may be null -- the ACI has no targets an will use defaults.
+     * @param targetEntry The ACI target keyword if any.
+     * @param targetAttr The ACI targetattr keyword if any.
+     * @param targetFilter The ACI targetfilter keyword if any.
+     * @param targetScope The ACI targetscope keyword if any.
+     */
+    private AciTargets(Target targetEntry, TargetAttr targetAttr,
+                       TargetFilter targetFilter,
+                       SearchScope targetScope) {
+       this.target=targetEntry;
+       this.targetAttr=targetAttr;
+       this.targetScope=targetScope;
+       this.targetFilter=targetFilter;
+    }
+
+    /**
+     * Return class representing the ACI target keyword. May be
+     * null. The default is the use the DN of the entry containing
+     * the ACI and check if the resource entry is a descendant of that.
+     * @return The ACI target class.
+     */
+    public Target getTarget() {
+        return target;
+    }
+
+    /**
+     * Return class representing the ACI targetattr keyword. May be null.
+     * The default is to not match any attribute types in an entry.
+     * @return The ACI targetattr class.
+     */
+    public TargetAttr getTargetAttr() {
+        return targetAttr;
+    }
+
+    /**
+     * Return the ACI targetscope keyword. Default is WHOLE_SUBTREE.
+     * @return The ACI targetscope information.
+     */
+    public SearchScope getTargetScope() {
+        return targetScope;
+    }
+
+    /**
+     * Return class representing the  ACI targetfilter keyword. May be null.
+     * @return The targetscope information.
+     */
+    public TargetFilter getTargetFilter() {
+        return targetFilter;
+    }
+
+    /**
+     * 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.
+     * @return An AciTargets class representing the decoded ACI target string.
+     * @throws AciException If the provided string contains errors.
+     */
+    public static AciTargets decode(String input, DN dn)
+    throws AciException {
+        Target target=null;
+        TargetAttr targetAttr=null;
+        TargetFilter targetFilter=null;
+        TargAttrFilters targAttrFilters=null;
+        SearchScope targetScope=SearchScope.WHOLE_SUBTREE;
+        Pattern targetPattern = Pattern.compile(targetRegex);
+        Matcher targetMatcher = targetPattern.matcher(input);
+        while (targetMatcher.find())
+        {
+            if (targetMatcher.groupCount() != targetElementCount) {
+                int msgID = MSGID_ACI_SYNTAX_INVALID_TARGET_SYNTAX;
+                String message = getMessage(msgID, input);
+                throw new AciException(msgID, message);
+            }
+            String keyword = targetMatcher.group(targetKeywordPos);
+            EnumTargetKeyword targetKeyword  =
+                EnumTargetKeyword.createKeyword(keyword);
+            if (targetKeyword == null) {
+                int msgID = MSGID_ACI_SYNTAX_INVALID_TARGET_KEYWORD;
+                String message = getMessage(msgID, keyword  );
+                throw new AciException(msgID, message);
+            }
+            String operator =
+                targetMatcher.group(targetOperatorPos);
+            EnumTargetOperator targetOperator =
+                EnumTargetOperator.createOperator(operator);
+            if (targetOperator == null) {
+                int msgID = MSGID_ACI_SYNTAX_INVALID_TARGET_OPERATOR;
+                String message = getMessage(msgID, operator);
+                throw new AciException(msgID, message);
+            }
+            String expression = targetMatcher.group(targetExpressionPos);
+            switch(targetKeyword)
+            {
+            case KEYWORD_TARGET:
+            {
+                if (target == null){
+                    target =  Target.decode(targetOperator, expression, dn);
+                }
+                else
+                {
+                    int msgID =
+                        MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS;
+                    String message =
+                        getMessage(msgID, "target", input);
+                    throw new AciException(msgID, message);
+                }
+                break;
+            }
+            case KEYWORD_TARGETATTR:
+            {
+                if (targetAttr == null){
+                    targetAttr = TargetAttr.decode(targetOperator,
+                            expression);
+                }
+                else {
+                    int msgID =
+                        MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS;
+                    String message =
+                        getMessage(msgID, "targetattr", input);
+                    throw new AciException(msgID, message);
+                }
+                break;
+            }
+            case KEYWORD_TARGETSCOPE:
+            {
+                // Check the operator for the targetscope is EQUALITY
+                if (targetOperator == EnumTargetOperator.NOT_EQUALITY) {
+                    int msgID = MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_OPERATOR;
+                    String message = getMessage(msgID, operator);
+                    throw new AciException(msgID, message);
+                }
+                targetScope=createScope(expression);
+                break;
+            }
+            case KEYWORD_TARGETFILTER:
+            {
+                if (targetFilter == null){
+                    targetFilter = TargetFilter.decode(targetOperator,
+                            expression);
+                }
+                else {
+                    int msgID =
+                        MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS;
+                    String message =
+                        getMessage(msgID, "targetfilter", input);
+                    throw new AciException(msgID, message);
+                }
+                break;
+            }
+                case KEYWORD_TARGATTRFILTERS:
+                {
+                    if (targAttrFilters == null){
+                        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);
+    }
+
+    /*
+     * TODO Add support for the SearchScope.SUBORDINATE_SUBTREE scope.
+     */
+    /**
+     * Evaluates a provided scope string and returns an appropriate
+     * SearchScope enumeration.
+     * @param expression The expression string.
+     * @return An search scope enumeration matching the string.
+     * @throws AciException If the expression is an invalid targetscope
+     * string.
+     */
+    private static SearchScope createScope(String expression)
+    throws AciException {
+        if(expression.equalsIgnoreCase("base"))
+                return SearchScope.BASE_OBJECT;
+        else if(expression.equalsIgnoreCase("onelevel"))
+            return SearchScope.SINGLE_LEVEL;
+        else if(expression.equalsIgnoreCase("subtree"))
+            return SearchScope.WHOLE_SUBTREE;
+        else {
+            int msgID =
+                MSGID_ACI_SYNTAX_INVALID_TARGETSCOPE_EXPRESSION;
+            String message = getMessage(msgID, expression);
+            throw new AciException(msgID, message);
+        }
+    }
+
+    /**
+     * Checks an ACI's targetfilter information against an target match
+     * context.
+     * @param aci The ACI to try an match the targetfilter of.
+     * @param matchCtx The target match context containing information needed
+     * to perform a target match.
+     * @return True if the targetfilter matched the target context.
+     */
+    public static boolean isTargetFilterApplicable(Aci aci,
+                                              AciTargetMatchContext matchCtx) {
+        boolean ret=true;
+        TargetFilter targetFilter=aci.getTargets().getTargetFilter();
+        if(targetFilter != null)
+             ret=targetFilter.isApplicable(matchCtx);
+        return ret;
+    }
+
+    /*
+     * TODO Evaluate making this method more efficient.
+     * The isTargetAttrApplicable method looks a lot less efficient than it
+     * could be with regard to the logic that it employs and the repeated use
+     * of method calls over local variables.
+     */
+    /**
+     * Checks an provided ACI's targetattr information against a target match
+     * context.
+     * @param aci The ACI to evaluate.
+     * @param targetMatchCtx The target match context to check the ACI against.
+     * @return True if the targetattr matched the target context.
+     */
+    public static boolean isTargetAttrApplicable(Aci aci,
+                                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((isFirstAttr) && (aci.getTargets().getTargetAttr() == null))
+            targetMatchCtx.setEntryTestRule(true);
+        return ret;
+    }
+
+    /**
+     * Try and match a one or more of the specified rights in the skiprights
+     * mask.
+     * @param rights The rights to check for.
+     * @return  True if the one or more of the specified rights are in the
+     * skiprights rights mask.
+     */
+    public static boolean skipRightsHasRights(int rights) {
+         return  ((skipRights & rights) == rights);
+    }
+
+    /*
+     * TODO Track DS 6.1 changes to ONELEVEL scope.
+     *
+     * The isTargetApplicable method appears to handle the ONELEVEL scope
+     * incorrectly.  The standard definition of onelevel only includes
+     * the immediate children of a given entry -- it does not include that
+     * entry itself.  It is a bug for the server to behave in any other way.
+     * Unfortunately, it does appear that the implementation you currently
+     * have matches the implementation in DS6. Nevertheless, I don't think
+     * that it is acceptable use this standard term in a nonstandard way and
+     * therefore we must change it to the standards-compliant interpretation
+     *  which does not include the parent.
+     *
+     * TODO Investigate supporting alternative representations of the scope.
+     *
+     * Should we also consider supporting alternate representations of the
+     * scope values (in particular, allow "one" in addition to "onelevel"
+     * and "sub" in addition to "subtree") to match the very common
+     * abbreviations in widespread use for those terms?
+     */
+    /**
+     * Checks an provided ACI's target information against an target match
+     * context.
+     * @param aci The ACI to match the target against.
+     * @param matchCtx The target match context to check the ACI against.
+     * @return True if the target matched the context.
+     */
+    public static boolean isTargetApplicable(Aci aci,
+            AciTargetMatchContext matchCtx) {
+        boolean ret=true;
+        DN entryDN=matchCtx.getResourceEntry().getDN();
+        DN targetDN=aci.getDN();
+        AciTargets targets=aci.getTargets();
+
+        /*
+         * Scoping of the ACI uses either the DN of the entry
+         * containing the ACI (aci.getDN above), or if the ACI item
+         * contains a simple target DN and a equality operator that
+         * target DN is used.
+         */
+        if((targets.getTarget() != null) &&
+                (!targets.getTarget().isPattern())) {
+            EnumTargetOperator op=targets.getTarget().getOperator();
+            if(op != EnumTargetOperator.NOT_EQUALITY)
+                targetDN=targets.getTarget().getDN();
+        }
+        switch(targets.getTargetScope()) {
+        case BASE_OBJECT:
+            if(!targetDN.equals(entryDN))
+                return false;
+            break;
+        case SINGLE_LEVEL:
+            if((!targetDN.equals(entryDN)) &&
+                    (!entryDN.getParent().equals(targetDN)))
+                return false;
+            break;
+        case WHOLE_SUBTREE:
+            if(!entryDN.isDescendantOf(targetDN))
+                return false;
+            break;
+        /*
+         * TODO Add support for the SearchScope.SUBORDINATE_SUBTREE scope.
+         *
+         * The isTargetApplicable method doesn't account for the subordinate
+         * subtree search scope.
+        */
+        default:
+            return false;
+        }
+        /*
+         * The entry is in scope. For inequality checks, scope was tested
+         * against the entry containing the ACI. If operator is inequality,
+         * check that it doesn't match the target DN.
+         */
+        if((targets.getTarget() != null) &&
+                (!targets.getTarget().isPattern())) {
+            EnumTargetOperator op=targets.getTarget().getOperator();
+            if(op == EnumTargetOperator.NOT_EQUALITY) {
+                DN tmpDN=targets.getTarget().getDN();
+                if(entryDN.isDescendantOf(tmpDN))
+                    return false;
+            }
+        }
+        /*
+         * There is a pattern, need to match the substring filter
+         * created when the ACI was decoded. If inequality flip the
+         * result.
+         */
+        if((targets.getTarget() != null) &&
+                (targets.getTarget().isPattern()))  {
+            ret=targets.getTarget().matchesPattern(entryDN);
+            EnumTargetOperator op=targets.getTarget().getOperator();
+            if(ret && op == EnumTargetOperator.NOT_EQUALITY)
+                ret=!ret;
+        }
+        return ret;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AuthMethod.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AuthMethod.java
new file mode 100644
index 0000000..2027bed
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AuthMethod.java
@@ -0,0 +1,112 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+
+/**
+ * The AuthMethod class represents an authmethod bind rule keyword expression.
+ */
+public class AuthMethod implements KeywordBindRule {
+    private EnumAuthMethod authMethod=null;
+    private EnumBindRuleType type=null;
+
+    /**
+     * Create a class representing an authmethod bind rule keyword from the
+     * provided method and bind rule type.
+     * @param method An enumeration representing the method of the expression.
+     * @param type An enumeration representing the type of the expression.
+     */
+    private AuthMethod(EnumAuthMethod method, EnumBindRuleType type) {
+        this.authMethod=method;
+        this.type=type;
+    }
+
+    /**
+     * Decode a string representing a authmethod bind rule.
+     * @param expr  The string representing the bind rule.
+     * @param type An enumeration representing the bind rule type.
+     * @return  An keyword bind rule class that can be used to evaluate the
+     * bind rule.
+     * @throws AciException If the expression string is invalid.
+     */
+    public static KeywordBindRule decode(String expr, EnumBindRuleType type)
+    throws AciException  {
+        EnumAuthMethod method=EnumAuthMethod.createAuthmethod(expr);
+        if (method == null)
+        {
+            int msgID = MSGID_ACI_SYNTAX_INVALID_AUTHMETHOD_EXPRESSION;
+            String message = getMessage(msgID, expr);
+            throw new AciException(msgID, message);
+        }
+        return new AuthMethod(method, type);
+    }
+
+    /*
+     * TODO Evaluate if AUTHMETHOD_NONE processing is correct. This was fixed
+     * prior to Neil's review. Verify in a unit test.
+     *
+     * I'm not sure that the evaluate() method handles AUTHMETHOD_NONE
+     * correctly. My understanding is that it should only match in cases
+     * in which no authentication has been performed, but you have it
+     * always matching.
+     */
+    /**
+     * Evaluate authmethod bind rule using the provided evaluation context.
+     * @param evalCtx  An evaluation context to use.
+     * @return  An enumeration evaluation result.
+     */
+    public EnumEvalResult evaluate(AciEvalContext evalCtx) {
+        EnumEvalResult matched=EnumEvalResult.FALSE;
+        if(authMethod==EnumAuthMethod.AUTHMETHOD_NONE) {
+            matched=EnumEvalResult.TRUE;
+        } else if(authMethod==EnumAuthMethod.AUTHMETHOD_SIMPLE) {
+            if(evalCtx.getAuthenticationMethod(false)
+                    == EnumAuthMethod.AUTHMETHOD_SIMPLE){
+                matched=EnumEvalResult.TRUE;
+            }
+        } else if(authMethod == EnumAuthMethod.AUTHMETHOD_SSL) {
+            /*
+             * TODO Verfiy that SSL authemethod is correctly handled in a
+             * unit test.
+             * I'm not sure that the evaluate() method correctly handles
+             * SASL EXTERNAL in all cases.  My understanding is that in
+             * DS 5/6, an authmethod of SSL is the same as an authmethod of
+             * SASL EXTERNAL.  If that's true, then you don't properly handle
+             * that condition.
+             */
+            if(authMethod == evalCtx.getAuthenticationMethod(true))
+                    matched=EnumEvalResult.TRUE;
+        } else {
+            if(authMethod ==evalCtx.getAuthenticationMethod(false))
+                matched=EnumEvalResult.TRUE;
+        }
+        return matched.getRet(type, false);
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java
new file mode 100644
index 0000000..d9e7888
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/BindRule.java
@@ -0,0 +1,538 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.HashMap;
+
+/**
+ * This class represents a single bind rule of an ACI permission-bind rule
+ * 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.
+    private boolean negate=false;
+
+    //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").
+    private EnumBooleanTypes booleanType = null;
+
+    //The keyword of a simple bind rule.
+    private EnumBindRuleKeyword keyword = null;
+
+    //Regular expression stuff that needs to be made clearer.
+    private static final int keywordPos = 1;
+    private static final int opPos = 2;
+    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;
+    private static final int remainingOperandPos = 1;
+    private static final int remainingBindrulePos = 2;
+    private static final String remainingBindruleRegex =
+        "^\\s*(\\w+)\\s*(.*)$";
+
+    /**
+     * Constructor that takes an keyword enumeration and corresponding
+     * simple bind rule. The keyword string is the key for the keyword rule in
+     * the keywordRuleMap. This is a simple bind rule representation:
+
+     * keyword  op  rule
+     *
+     * An example of a simple bind rule is:
+     *
+     *  userdn = "ldap:///anyone"
+     *
+     * @param keyword The keyword enumeration.
+     * @param rule The rule corresponding to this keyword.
+     */
+    private BindRule(EnumBindRuleKeyword keyword, KeywordBindRule rule) {
+        this.keyword=keyword;
+        this.keywordRuleMap.put(keyword.toString(), rule);
+    }
+
+
+    /*
+     * TODO Verify that this handles the NOT boolean properly by
+     * creating a unit test.
+     *
+     * I'm a bit confused by the constructor which takes left and right
+     * arguments. Is it always supposed to have exactly two elements?
+     * Is it supposed to keep nesting bind rules in a chain until all of
+     * them have been processed?  The documentation for this method needs
+     * to be a lot clearer.  Also, it doesn't look like it handles the NOT
+     * type properly.
+     */
+    /**
+     * Constructor that represents a complex bind rule. The left and right
+     * bind rules are saved along with the boolean type operator. A complex
+     * bind rule looks like:
+     *
+     *  bindrule   booleantype   bindrule
+     *
+     * Each side of the complex bind rule can be complex bind rule(s)
+     * itself. An example of a complex bind rule would be:
+     *
+     * (dns="*.example.com" and (userdn="ldap:///anyone" or
+     * (userdn="ldap:///cn=foo,dc=example,dc=com and ip=129.34.56.66)))
+     *
+     * This constructor should always have two elements. The processing
+     * of a complex bind rule is dependent on the boolean operator type.
+     * See the evalComplex method for more information.
+     *
+     *
+     * @param left The bind rule left of the boolean.
+     * @param right The right bind rule.
+     * @param booleanType The boolean type enumeration ("and" or "or").
+     */
+    private BindRule(BindRule left, BindRule right,
+            EnumBooleanTypes booleanType) {
+        this.booleanType = booleanType;
+        this.left = left;
+        this.right = right;
+    }
+
+    /*
+     * TODO Verify this method handles escaped parentheses by writing
+     * a unit test.
+     *
+     * It doesn't look like the decode() method handles the possibility of
+     * escaped parentheses in a bind rule.
+     */
+    /**
+     * Decode an ACI bind rule string representation.
+     * @param input The string representation of the bind rule.
+     * @return A BindRule class representing the bind rule.
+     * @throws AciException If the string is an invalid bind rule.
+     */
+    public static BindRule decode (String input)
+    throws AciException {
+        if ((input == null) || (input.length() == 0))
+        {
+          return null;
+        }
+        String bindruleStr = input.trim();
+        char firstChar = bindruleStr.charAt(0);
+        char[] bindruleArray = bindruleStr.toCharArray();
+
+        if (firstChar == '(')
+        {
+          BindRule bindrule_1 = null;
+          int currentPos;
+          int numOpen = 0;
+          int numClose = 0;
+
+          // Find the associated closed parenthesis
+          for (currentPos = 0; currentPos < bindruleArray.length; currentPos++)
+          {
+            if (bindruleArray[currentPos] == '(')
+            {
+              numOpen++;
+            }
+            else if (bindruleArray[currentPos] == ')')
+            {
+              numClose++;
+            }
+            if (numClose == numOpen)
+            {
+              //We found the associated closed parenthesis
+              //the parenthesis are removed
+              String bindruleStr1 = bindruleStr.substring(1, currentPos);
+              bindrule_1 = BindRule.decode(bindruleStr1);
+              break;
+            }
+          }
+          /*
+           * Check that the number of open parenthesis is the same as
+           * the number of closed parenthesis.
+           * Raise an exception otherwise.
+           */
+          if (numOpen > numClose) {
+              int msgID = MSGID_ACI_SYNTAX_BIND_RULE_MISSING_CLOSE_PAREN;
+              String message = getMessage(msgID, input);
+              throw new AciException(msgID, message);
+          }
+          /*
+           * If there are remaining chars => there MUST be an
+           * operand (AND / OR)
+           * otherwise there is a syntax error
+           */
+          if (currentPos < (bindruleArray.length - 1))
+          {
+            String remainingBindruleStr =
+                bindruleStr.substring(currentPos + 1);
+            return createBindRule(bindrule_1, remainingBindruleStr);
+          }
+          else
+          {
+            return bindrule_1;
+          }
+        }
+        else
+        {
+          StringBuilder b=new StringBuilder(bindruleStr);
+          /*
+           * TODO Verify by unit test that this negation
+           * is correct. This code handles a simple bind rule negation such
+           * as:
+           *
+           *  not userdn="ldap:///anyone"
+           */
+          boolean negate=determineNegation(b);
+          bindruleStr=b.toString();
+          Pattern bindrulePattern = Pattern.compile(bindruleRegex);
+          Matcher bindruleMatcher = bindrulePattern.matcher(bindruleStr);
+          int bindruleEndIndex;
+          if (bindruleMatcher.find())
+          {
+            bindruleEndIndex = bindruleMatcher.end();
+            BindRule bindrule_1 = parseAndCreateBindrule(bindruleMatcher);
+            bindrule_1.setNegate(negate);
+            if (bindruleEndIndex < bindruleStr.length())
+            {
+              String remainingBindruleStr =
+                  bindruleStr.substring(bindruleEndIndex);
+              return createBindRule(bindrule_1, remainingBindruleStr);
+            }
+            else {
+              return bindrule_1;
+            }
+          }
+          else {
+              int msgID = MSGID_ACI_SYNTAX_INVALID_BIND_RULE_SYNTAX;
+              String message = getMessage(msgID, input);
+              throw new AciException(msgID, message);
+          }
+        }
+    }
+
+
+    /**
+     * Parses a simple bind rule using the regular expression matcher.
+     * @param bindruleMatcher A regular expression matcher holding
+     * the engine to use in the creation of a simple bind rule.
+     * @return A BindRule determined by the matcher.
+     * @throws AciException If the bind rule matcher found errors.
+     */
+    private static BindRule parseAndCreateBindrule(Matcher bindruleMatcher)
+    throws AciException {
+        String keywordStr = bindruleMatcher.group(keywordPos);
+        String operatorStr = bindruleMatcher.group(opPos);
+        String expression = bindruleMatcher.group(expressionPos);
+        EnumBindRuleKeyword keyword;
+        EnumBindRuleType operator;
+
+        // Get the Keyword
+        keyword = EnumBindRuleKeyword.createBindRuleKeyword(keywordStr);
+        if (keyword == null)
+        {
+            int msgID = MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD;
+            String message = getMessage(msgID, keywordStr);
+            throw new AciException(msgID, message);
+        }
+
+        // Get the operator
+        operator = EnumBindRuleType.createBindruleOperand(operatorStr);
+        if (operator == null) {
+            int msgID = MSGID_ACI_SYNTAX_INVALID_BIND_RULE_OPERATOR;
+            String message = getMessage(msgID, operatorStr);
+            throw new AciException(msgID, message);
+        }
+
+        //expression can't be null
+        if (expression == null) {
+            int msgID = MSGID_ACI_SYNTAX_MISSING_BIND_RULE_EXPRESSION;
+            String message = getMessage(msgID, operatorStr);
+            throw new AciException(msgID, message);
+        }
+        validateOperation(keyword, operator);
+        KeywordBindRule rule = decode(expression, keyword, operator);
+        return new BindRule(keyword, rule);
+    }
+
+    /**
+     * Create a complex bind rule from a substring
+     * parsed from the ACI string.
+     * @param bindrule The left hand part of a complex bind rule
+     * parsed previously.
+     * @param remainingBindruleStr The string used to determine the right
+     * hand part.
+     * @return A BindRule representing a complex bind rule.
+     * @throws AciException If the string contains an invalid
+     * right hand bind rule string.
+     */
+    private static BindRule createBindRule(BindRule bindrule,
+            String remainingBindruleStr) throws AciException {
+        Pattern remainingBindrulePattern =
+            Pattern.compile(remainingBindruleRegex);
+        Matcher remainingBindruleMatcher =
+            remainingBindrulePattern.matcher(remainingBindruleStr);
+        if (remainingBindruleMatcher.find()) {
+            String remainingOperand =
+                remainingBindruleMatcher.group(remainingOperandPos);
+            String remainingBindrule =
+                remainingBindruleMatcher.group(remainingBindrulePos);
+            EnumBooleanTypes operand =
+                EnumBooleanTypes.createBindruleOperand(remainingOperand);
+            if ((operand == null)
+                    || ((operand != EnumBooleanTypes.AND_BOOLEAN_TYPE) &&
+                            (operand != EnumBooleanTypes.OR_BOOLEAN_TYPE))) {
+                int msgID =
+                    MSGID_ACI_SYNTAX_INVALID_BIND_RULE_BOOLEAN_OPERATOR;
+                String message = getMessage(msgID, remainingOperand);
+                throw new AciException(msgID, message);
+            }
+            StringBuilder ruleExpr=new StringBuilder(remainingBindrule);
+            /* TODO write a unit test to verify.
+             * This is a check for something like:
+             * bindrule and not (bindrule)
+             * or something ill-advised like:
+             * and not not not (bindrule).
+             */
+            boolean negate=determineNegation(ruleExpr);
+            remainingBindrule=ruleExpr.toString();
+            BindRule bindrule_2 =
+                BindRule.decode(remainingBindrule);
+            bindrule_2.setNegate(negate);
+            return new BindRule(bindrule, bindrule_2, operand);
+        } else {
+            int msgID = MSGID_ACI_SYNTAX_INVALID_BIND_RULE_SYNTAX;
+            String message = getMessage(msgID, remainingBindruleStr);
+            throw new AciException(msgID, message);
+        }
+    }
+
+    /**
+     * Tries to strip an "not" boolean modifier from the string and
+     * determine at the same time if the value should be flipped.
+     * For example:
+     *
+     * not not not bindrule
+     *
+     * is true.
+     *
+     * @param ruleExpr The bindrule expression to evaluate. This
+     * string will be changed if needed.
+     * @return True if the boolean needs to be negated.
+     */
+    private static boolean determineNegation(StringBuilder ruleExpr)  {
+        boolean negate=false;
+        String ruleStr=ruleExpr.toString();
+        while(ruleStr.regionMatches(true, 0, "not ", 0, 4)) {
+            negate = !negate;
+            ruleStr = ruleStr.substring(4);
+        }
+        ruleExpr.replace(0, ruleExpr.length(), ruleStr);
+        return negate;
+    }
+
+    /**
+     * Set the negation parameter as determined by the function above.
+     * @param v The value to assign negate to.
+     */
+    private void setNegate(boolean v) {
+        negate=v;
+    }
+
+    /*
+     * TODO This method needs to handle the userattr keyword. Also verify
+     * that the rest of the keywords are handled correctly.
+     * TODO Investigate moving this method into EnumBindRuleKeyword class.
+     *
+     * Does validateOperation need a default case?  Why is USERATTR not in this
+     * list? Why is TIMEOFDAY not in this list when DAYOFWEEK is in the list?
+     * Would it be more appropriate to put this logic in the
+     * EnumBindRuleKeyword class so we can be sure it's always handled properly
+     *  for all keywords?
+     */
+    /**
+     * Checks the keyword operator enumeration to make sure it is valid.
+     * This method doesn't handle all cases.
+     * @param keyword The keyword enumeration to evaluate.
+     * @param op The operation enumeration to evaluate.
+     * @throws AciException If the operation is not valid for the keyword.
+     */
+    private static void validateOperation(EnumBindRuleKeyword keyword,
+                                        EnumBindRuleType op)
+    throws AciException {
+        switch (keyword) {
+        case USERDN:
+        case ROLEDN:
+        case GROUPDN:
+        case IP:
+        case DNS:
+        case AUTHMETHOD:
+        case DAYOFWEEK:
+            if ((op != EnumBindRuleType.EQUAL_BINDRULE_TYPE)
+                    && (op != EnumBindRuleType.NOT_EQUAL_BINDRULE_TYPE)) {
+                int msgID =
+                    MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD_OPERATOR_COMBO;
+                String message = getMessage(msgID,
+                                            keyword.toString(),
+                                            op.toString());
+                throw new AciException(msgID, message);
+            }
+        }
+    }
+
+    /*
+     * TODO Investigate moving into the EnumBindRuleKeyword class.
+     *
+     * Should we move the logic in the
+     * decode(String,EnumBindRuleKeyword,EnumBindRuleType) method into the
+     * EnumBindRuleKeyword class so we can be sure that it's always
+     * handled properly for all keywords?
+     */
+    /**
+     * Creates a keyword bind rule suitable for saving in the keyword
+     * rule map table. Each individual keyword class will do further
+     * parsing and validation of the expression string.  This processing
+     * is part of the simple bind rule creation.
+     * @param expr The expression string to further parse.
+     * @param keyword The keyword to create.
+     * @param op The operation part of the bind rule.
+     * @return A keyword bind rule class that can be stored in the
+     * map table.
+     * @throws AciException If the expr string contains a invalid
+     * bind rule.
+     */
+    private static KeywordBindRule decode(String expr,
+                                          EnumBindRuleKeyword keyword,
+                                          EnumBindRuleType op)
+            throws AciException  {
+        KeywordBindRule rule;
+        switch (keyword) {
+            case USERDN:
+            {
+                rule = UserDN.decode(expr, op);
+                break;
+            }
+            case ROLEDN:
+            {
+                rule = RoleDN.decode(expr, op);
+                break;
+            }
+            case GROUPDN:
+            {
+                rule = GroupDN.decode(expr, op);
+                break;
+            }
+            case IP:
+            {
+                rule = IpCriteria.decode(expr, op);
+                break;
+            }
+            case DNS:
+            {
+                rule = DNS.decode(expr, op);
+                break;
+            }
+            case DAYOFWEEK:
+            {
+                rule = DayOfWeek.decode(expr, op);
+                break;
+            }
+            case TIMEOFDAY:
+            {
+                rule=TimeOfDay.decode(expr, op);
+                break;
+            }
+            case AUTHMETHOD:
+            {
+                rule = AuthMethod.decode(expr, op);
+                break;
+            }
+            case USERATTR:
+            {
+                rule = UserAttr.decode(expr, op);
+                break;
+            }
+            default:  {
+                int msgID = MSGID_ACI_SYNTAX_INVALID_BIND_RULE_KEYWORD;
+                String message = getMessage(msgID, keyword.toString());
+                throw new AciException(msgID, message);
+            }
+        }
+        return rule;
+    }
+
+    /**
+     * Evaluate the results of a complex bind rule. If the boolean
+     * is an AND type then left and right must be TRUE, else
+     * it must be an OR result and one of the bind rules must be
+     * TRUE.
+     * @param left The left bind rule result to evaluate.
+     * @param right The right bind result to evaluate.
+     * @return The result of the complex evaluation.
+     */
+    private EnumEvalResult evalComplex(EnumEvalResult left,
+                                       EnumEvalResult right) {
+        EnumEvalResult ret=EnumEvalResult.FALSE;
+        if(booleanType == EnumBooleanTypes.AND_BOOLEAN_TYPE) {
+           if((left == EnumEvalResult.TRUE) && (right == EnumEvalResult.TRUE))
+                ret=EnumEvalResult.TRUE;
+        } else if((left == EnumEvalResult.TRUE) ||
+                  (right == EnumEvalResult.TRUE))
+            ret=EnumEvalResult.TRUE;
+       return ret;
+    }
+
+    /**
+     * Evaluate an bind rule against an evaluation context. If it is a simple
+     * bind rule (no boolean type) then grab the keyword rule from the map
+     * table and call the corresponding evaluate function. If it is a
+     * complex rule call the routine above "evalComplex()".
+     * @param evalCtx The evaluation context to pass to the keyword
+     * evaluation function.
+     * @return An result enumeration containing the result of the evaluation.
+     */
+    public EnumEvalResult evaluate(AciEvalContext evalCtx) {
+        EnumEvalResult ret;
+        //Simple bind rules have a null booleanType enumeration.
+        if(this.booleanType == null) {
+            KeywordBindRule rule=keywordRuleMap.get(keyword.toString());
+            ret = rule.evaluate(evalCtx);
+        }  else
+            ret=evalComplex(left.evaluate(evalCtx),right.evaluate(evalCtx));
+        return EnumEvalResult.negateIfNeeded(ret, negate);
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/DNS.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/DNS.java
new file mode 100644
index 0000000..ea403b4
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/DNS.java
@@ -0,0 +1,160 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.util.LinkedList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class implements the dns bind rule keyword.
+ */
+public class DNS implements KeywordBindRule {
+
+    LinkedList<String> patterns=null;
+    private EnumBindRuleType type=null;
+
+    /**
+     * Create a class representing a dns bind rule keyword.
+     * @param patterns List of dns patterns to match against.
+     * @param type An enumeration representing the bind rule type.
+     */
+    private DNS(LinkedList<String> patterns, EnumBindRuleType type) {
+        this.patterns=patterns;
+        this.type=type;
+    }
+
+    /**
+     * Decode an string representing a dns bind rule.
+     * @param expr A string representation of the bind rule.
+     * @param type  An enumeration representing the bind rule type.
+     * @return  A keyword bind rule class that can be used to evaluate
+     * this bind rule.
+     * @throws AciException  If the expression string is invalid.
+     */
+    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)) {
+            int msgID = MSGID_ACI_SYNTAX_INVALID_DNS_EXPRESSION;
+            String message = getMessage(msgID, expr);
+            throw new AciException(msgID, message);
+        }
+        LinkedList<String>dns=new LinkedList<String>();
+        int valuePos = 1;
+        Pattern valuePattern = Pattern.compile(valueRegex);
+        Matcher valueMatcher = valuePattern.matcher(expr);
+        while (valueMatcher.find()) {
+            String hn=valueMatcher.group(valuePos);
+            String[] hnArray=hn.split("\\.", -1);
+            for(int i=1, n=hnArray.length; i < n; i++) {
+                if(hnArray[i].equals("*")) {
+                    int msgID = MSGID_ACI_SYNTAX_INVALID_DNS_WILDCARD;
+                    String message = getMessage(msgID, expr);
+                    throw new AciException(msgID, message);
+                }
+            }
+            dns.add(hn);
+        }
+        return new DNS(dns, type);
+    }
+
+    /**
+     * Performs evaluation of dns keyword bind rule using the provided
+     * evaluation context.
+     * @param evalCtx  An evaluation context to use in the evaluation.
+     * @return An enumeration evaluation result.
+     */
+    public EnumEvalResult evaluate(AciEvalContext evalCtx) {
+        EnumEvalResult matched=EnumEvalResult.FALSE;
+        String[] remoteHost = evalCtx.getHostName().split("\\.", -1);
+        for(String p : patterns) {
+          String[] pat = p.split("\\.", -1);
+          if(evalHostName(remoteHost, pat)) {
+              matched=EnumEvalResult.TRUE;
+              break;
+          }
+        }
+        return matched.getRet(type, false);
+    }
+
+    /*
+     * TODO Verify that a DNS pattern of "*" is valid by writing a unit
+     * test. Probably isn't.
+     *
+     * TODO Evaluate if extending the wild-card matching to multiple name
+     * components should be supported. Currently wild-cards are only permitted
+     * in the leftmost field and the rest of the domain name components must
+     * match.
+     *
+     * TODO Evaluate extending wild-card matching to non-complete name matching.
+     *
+     * Is it acceptable to have a DNS address of just "*"
+     * (which presumably will match any system)?
+     *
+     * Is it acceptable for a wildcard to match multiple name components?  For
+     * example, is "*.example.com" supposed to be considered a match for
+     * "host.east.example.com"?  Similarly, would a pattern like
+     * "www.*.example.com" match "www.newyork.east.example.com"?  It doesn't
+     * appear that the current implementation matches either of them.
+     *
+     * Is it acceptable for a wildcard to appear as anything other than a
+     * complete name component?  For example, if I have three web servers
+     * "www1.example.com","www2.example.com", and "www3.example.com", then
+     * can I use "www*.example.com"? It doesn't appear that the current
+     * implementation allows that.  Further, would "www*.example.com" match
+     * cases like "www.example.com" or "www1.east.example.com"?
+     */
+    /**
+     * Checks an array containing the remote client's hostname against
+     * patterns specified in the bind rule expression. Wild-cards are
+     * only permitted in the leftmost field and the rest of the domain
+     * name array components must match.
+     * @param remoteHostName  Array containing components of the remote clients
+     * hostname (split on ".").
+     * @param pat  An array containing the pattern specified in
+     * the bind rule expression. The first array slot may be a wild-card "*".
+     * @return  True if the remote hostname matches the pattern.
+     */
+    private boolean evalHostName(String[] remoteHostName, String[] pat) {
+        if(remoteHostName.length != pat.length)
+            return false;
+        for(int i=0;i<remoteHostName.length;i++)
+        {
+            if(!pat[i].equals("*")) {
+                if(!pat[i].equalsIgnoreCase(remoteHostName[i]))
+                    return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/DayOfWeek.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/DayOfWeek.java
new file mode 100644
index 0000000..c5c732c
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/DayOfWeek.java
@@ -0,0 +1,96 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.LinkedList;
+
+/**
+ * This class implements the dayofweek bind rule keyword.
+ */
+public class DayOfWeek  implements KeywordBindRule {
+
+    LinkedList<EnumDayOfWeek> days=null;
+    private EnumBindRuleType type=null;
+
+    /**
+     * Create a class representing a dayofweek bind rule keyword.
+     * @param days  A list of day of the week enumerations.
+     * @param type An enumeration representing the bind rule type.
+     */
+    private DayOfWeek(LinkedList<EnumDayOfWeek> days, EnumBindRuleType type) {
+        this.days=days;
+        this.type=type;
+    }
+
+    /**
+     * Decode an string representing a dayofweek bind rule.
+     * @param expr A string representation of the bind rule.
+     * @param type  An enumeration representing the bind rule type.
+     * @return  A keyword bind rule class that can be used to evaluate
+     * this bind rule.
+     * @throws AciException  If the expression string is invalid.
+     */
+    public static KeywordBindRule decode(String expr, EnumBindRuleType type)
+    throws AciException
+    {
+        LinkedList<EnumDayOfWeek>days=new LinkedList<EnumDayOfWeek>();
+        String[] dayArray=expr.split(",", -1);
+        for(int i=0, m=dayArray.length; i < m; i++)
+        {
+          EnumDayOfWeek day=EnumDayOfWeek.createDayOfWeek(dayArray[i]);
+          if (day == null)
+          {
+              int msgID = MSGID_ACI_SYNTAX_INVALID_DAYOFWEEK;
+              String message = getMessage(msgID, expr);
+              throw new AciException(msgID, message);
+          }
+          days.add(day);
+        }
+        return new DayOfWeek(days, type);
+    }
+
+    /**
+     * Performs evaluation of a dayofweek bind rule using the provided
+     * evaluation context.
+     * @param evalCtx  An evaluation context to use in the evaluation.
+     * @return An enumeration evaluation result.
+     */
+    public EnumEvalResult evaluate(AciEvalContext evalCtx) {
+        EnumEvalResult matched=EnumEvalResult.FALSE;
+        GregorianCalendar calendar = new GregorianCalendar();
+        EnumDayOfWeek dayofweek
+            = EnumDayOfWeek.getDayOfWeek(calendar.get(Calendar.DAY_OF_WEEK));
+        if(days.contains(dayofweek))
+            matched=EnumEvalResult.TRUE;
+        return matched.getRet(type, false);
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumAccessType.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumAccessType.java
new file mode 100644
index 0000000..f486bb1
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumAccessType.java
@@ -0,0 +1,88 @@
+/*
+ * 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;
+
+/**
+ * This class provides an enumeration of the two access
+ * types (allow, deny).
+ */
+public enum EnumAccessType {
+    /**
+     * Allow access type.
+     */
+    ALLOW   ("allow"),
+    /**
+     *  Deny access type.
+     */
+    DENY    ("deny");
+
+    private final String accessType;
+
+    /**
+     * Constructor that sets the accessType string.
+     * @param accessType The access type string to set.
+     */
+    EnumAccessType (String accessType){
+        this.accessType = accessType ;
+    }
+
+    /**
+     * Checks if the access type is equal to the string
+     * representation passed in.
+     * @param type The string representation of the access type.
+     * @return True if the access types are equal.
+     */
+    public boolean isAccessType(String type){
+        return type.equalsIgnoreCase(accessType);
+    }
+
+    /*
+     * TODO Make this method and all other Enum decode methods more efficient.
+     *
+     * Using the Enum.values() method is documented to be potentially slow.
+     * If we ever expect to use the decode() method in a performance-critical
+     * manner, then we should make it more efficient.  The same thing applies
+     * to all of the other enumeration types defined in the package.
+     */
+    /**
+     * Decodes an access type enumeration from a string passed into the method.
+     * @param type The string representation of the access type.
+     * @return   Return an EnumAccessType matching the string representation,
+     * or null if the string is not valid.
+     */
+    public static EnumAccessType decode(String type){
+        if (type != null){
+            for (EnumAccessType t : EnumAccessType.values()) {
+                if (t.isAccessType(type)){
+                    return t;
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumAuthMethod.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumAuthMethod.java
new file mode 100644
index 0000000..740667e
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumAuthMethod.java
@@ -0,0 +1,116 @@
+/*
+ * 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;
+/*
+ * TODO Evaluate moving this to a non-enumeration class that can add
+ * SASL mechanisms dynamically.
+ *
+ *  Given our previous discussion about needing to support any kind of SASL
+ *  mechanism that may be registered with the server, perhaps an enum isn't
+ *  the right way to handle this because we don't know ahead of time what
+ *  auth methods might be available (certainly not at compile time, but
+ *  potentially not even at runtime since I can add support for a new SASL
+ *  mechanism on the fly without restarting the server).
+ */
+/**
+ * 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.
+     */
+    AUTHMETHOD_NONE          ("none"),
+    /**
+      * The enumeration type when the bind rule has specified authentication of
+     *  simple.
+     */
+    AUTHMETHOD_SIMPLE        ("simple"),
+    /**
+      * The enumeration type when the bind rule has specified authentication of
+     *  ssl client auth.
+     */
+    AUTHMETHOD_SSL           ("ssl"),
+    /**
+     * The enumeration type when the bind rule has specified authentication of
+     * sasl DIGEST-MD5.
+     */
+    AUTHMETHOD_SASL_MD5      ("sasl DIGEST-MD5"),
+    /**
+     * The enumeration type when the bind rule has specified authentication of
+     * sasl EXTERNAL.
+     */
+    AUTHMETHOD_SASL_EXTERNAL ("sasl EXTERNAL"),
+    /**
+     * The enumeration type when the bind rule has specified authentication of
+     * sasl GSSAPI.
+     */
+    AUTHMETHOD_SASL_GSSAPI   ("sasl GSSAPI"),
+    /**
+     * Special internal enumeration for when there is no match.
+     */
+    AUTHMETHOD_NOMATCH       ("nomatch");
+
+    /**
+     * The name of the authmethod.
+     */
+    public String authmethod = null;
+
+    /**
+     * Creates a new enumeration type for this authmethod.
+     * @param authmethod The authemethod name.
+     */
+    EnumAuthMethod (String authmethod){
+        this.authmethod = authmethod;
+    }
+
+    /**
+     * Checks if a authmethod name is equal to this enumeration.
+     * @param myauthmethod  The name to test for.
+     * @return  True if the names match.
+     */
+    public boolean isAuthMethod(String myauthmethod){
+        return myauthmethod.equalsIgnoreCase(this.authmethod);
+    }
+
+    /**
+     * Creates an authmethod enumeration from the name passed in.
+     * @param myauthmethod The name to create.
+     * @return An authmethod enumeration if the name was found or null if not.
+     */
+    public static EnumAuthMethod createAuthmethod(String myauthmethod){
+        if (myauthmethod != null){
+            for (EnumAuthMethod t : EnumAuthMethod.values()){
+                if (t.isAuthMethod(myauthmethod)){
+                    return t;
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java
new file mode 100644
index 0000000..84fa1f3
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleKeyword.java
@@ -0,0 +1,118 @@
+/*
+ * 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;
+
+/**
+ * This class provides an enumeration of the allowed bind rule
+ * keyword types.
+ */
+public enum EnumBindRuleKeyword {
+    /**
+     * The enumeration type when the bind rule has specified keyword of
+     * userdn.
+     */
+    USERDN     ("userdn"),
+    /**
+     * The enumeration type when the bind rule has specified keyword of
+     * groupdn.
+     */
+    GROUPDN    ("groupdn"),
+    /**
+     * The enumeration type when the bind rule has specified keyword of
+     * roledn.
+     */
+    ROLEDN     ("roledn"),
+    /**
+     * The enumeration type when the bind rule has specified keyword of
+     * ip.
+     */
+    IP         ("ip"),
+    /**
+     * The enumeration type when the bind rule has specified keyword of
+     * dns.
+     */
+    DNS        ("dns"),
+    /**
+     * The enumeration type when the bind rule has specified keyword of
+     * dayofweek.
+     */
+    DAYOFWEEK  ("dayofweek"),
+    /**
+     * The enumeration type when the bind rule has specified keyword of
+     * timeofday.
+     */
+    TIMEOFDAY  ("timeofday"),
+    /**
+     * The enumeration type when the bind rule has specified keyword of
+     * userattr.
+     */
+    USERATTR ("userattr"),
+    /**
+     * The enumeration type when the bind rule has specified keyword of
+     * authmethod.
+     */
+    AUTHMETHOD ("authmethod");
+    /**
+     * The keyword name.
+     */
+    public final String keyword;
+
+    /**
+     * Creates a new enumeration type for the specified keyword.
+     * @param keyword The keyword name.
+     */
+    EnumBindRuleKeyword(String keyword){
+        this.keyword = keyword;
+    }
+
+    /**
+     * Checks to see if the keyword string is equal to the enumeration.
+     * @param keywordStr   The keyword name to check equality for.
+     * @return  True if the keyword is equal to the specified name.
+     */
+    public boolean isBindRuleKeyword(String keywordStr){
+        return keywordStr.equalsIgnoreCase(this.keyword);
+    }
+
+    /**
+     * Create a new enumeration type for the specified keyword name.
+     * @param keywordStr The name of the enumeration to create.
+     * @return A new enumeration type for the name or null if the name is
+     * not valid.
+     */
+    public static EnumBindRuleKeyword createBindRuleKeyword(String keywordStr){
+        if (keywordStr != null){
+            for (EnumBindRuleKeyword t : EnumBindRuleKeyword.values()){
+                if (t.isBindRuleKeyword(keywordStr)){
+                    return t;
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleType.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleType.java
new file mode 100644
index 0000000..ba2421e
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumBindRuleType.java
@@ -0,0 +1,104 @@
+/*
+ * 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;
+
+/**
+ * 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
+     * "=".
+     */
+    EQUAL_BINDRULE_TYPE             ("="),
+    /**
+     * The enumeration type when the bind rule has specified type of
+     * "!=".
+     */
+    NOT_EQUAL_BINDRULE_TYPE         ("!="),
+    /**
+     * The enumeration type when the bind rule has specified type of
+     * "<".
+     */
+    LESS_BINDRULE_TYPE              ("<"),
+    /**
+     * The enumeration type when the bind rule has specified type of
+     * "<=".
+     */
+    LESS_OR_EQUAL_BINDRULE_TYPE     ("<="),
+    /**
+     * The enumeration type when the bind rule has specified type of
+     * >".
+     */
+    GREATER_BINDRULE_TYPE           (">"),
+    /**
+     * The enumeration type when the bind rule has specified type of
+     * ">=".
+     */
+    GREATER_OR_EQUAL_BINDRULE_TYPE  (">=");
+
+    /**
+     * The bind rule type name.
+     */
+    private final String type;
+
+    /**
+     * Creates a new enumeration type for the specified bind rule type.
+     * @param type The bind rule type name.
+     */
+    EnumBindRuleType(String type){
+        this.type = type;
+    }
+
+    /**
+     * Checks to see if the type string is equal to the enumeration type
+     * name.
+     * @param type  The type name to check equality for.
+     * @return  True if the keyword is equal to the specified name.
+     */
+    public boolean isBindRuleType(String type){
+        return type.equals(this.type);
+    }
+
+    /**
+     * Create a new enumeration type for the specified type name.
+     * @param type  The name of the enumeration to create.
+     * @return A new enumeration type for the name or null if the name is
+     * not valid.
+     */
+    public static EnumBindRuleType createBindruleOperand(String type){
+        if (type != null){
+            for (EnumBindRuleType t : EnumBindRuleType.values()){
+                if (t.isBindRuleType(type)){
+                    return t;
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumBooleanTypes.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumBooleanTypes.java
new file mode 100644
index 0000000..c2fa963
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumBooleanTypes.java
@@ -0,0 +1,90 @@
+/*
+ * 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;
+
+/**
+ * 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".
+     */
+    AND_BOOLEAN_TYPE               ("and"),
+    /**
+     * The enumeration type when the bind rule has specified boolean type of
+     * "OR".
+     */
+    OR_BOOLEAN_TYPE                ("or"),
+    /**
+     * The enumeration type when the bind rule has specified boolean type of
+     * "NOT".
+     */
+    NOT_BOOLEAN_TYPE                ("not");
+
+    /**
+    * The bind rule boolean type name.
+     */
+    private final String booleanType;
+
+    /**
+     * Creates a new enumeration type for the specified bind rule boolean type.
+     * @param booleanType  The boolean type name.
+     */
+    EnumBooleanTypes(String booleanType){
+        this.booleanType = booleanType;
+    }
+
+    /**
+     * Checks to see if the boolean type string is equal to the enumeration type
+     * name.
+     * @param booleanType  The type name to check equality for.
+     * @return  True if the keyword is equal to the specified name.
+     */
+    public boolean isBindRuleBooleanOperand(String booleanType){
+        return booleanType.equalsIgnoreCase(this.booleanType);
+    }
+
+    /**
+     * Create a new enumeration type for the specified boolean type name.
+     * @param booleanType  The name of the enumeration to create.
+     * @return A new enumeration type for the name or null if the name is
+     * not valid.
+     */
+    public static
+    EnumBooleanTypes createBindruleOperand(String booleanType) {
+        if (booleanType != null){
+          for (EnumBooleanTypes t : EnumBooleanTypes.values()) {
+                if (t.isBindRuleBooleanOperand(booleanType)) {
+                    return t;
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumDayOfWeek.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumDayOfWeek.java
new file mode 100644
index 0000000..1d183b0
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumDayOfWeek.java
@@ -0,0 +1,154 @@
+/*
+ * 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 java.util.Calendar;
+
+/**
+ * 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".
+     */
+    DAY_MONDAY      ("mon"),
+    /**
+     * The enumeration type when the bind rule has specified dayofweek type of
+     * "tue" .
+     */
+    DAY_TUESDAY     ("tue"),
+    /**
+     * The enumeration type when the bind rule has specified dayofweek type of
+     * "wed".
+     */
+    DAY_WEDNESDAY   ("wed"),
+    /**
+     * The enumeration type when the bind rule has specified dayofweek type of
+     * "thu".
+     */
+    DAY_THURSDAY    ("thu"),
+    /**
+     * The enumeration type when the bind rule has specified dayofweek type of
+     * "fri".
+     */
+    DAY_FRIDAY      ("fri"),
+    /**
+     * The enumeration type when the bind rule has specified dayofweek type of
+     * "sat".
+     */
+    DAY_SATURDAY    ("sat"),
+    /**
+     * The enumeration type when the bind rule has specified dayofweek type of
+     * "sun".
+     */
+    DAY_SUNDAY      ("sun");
+
+    /**
+    * The bind rule dayofweek type name.
+     */
+    private String day = null;
+
+    /**
+     * Creates a new enumeration type for the specified bind rule dayofweek
+     * type.
+     * @param day  The day name.
+     */
+    EnumDayOfWeek (String day){
+        this.day = day;
+    }
+
+    /**
+     * Creates a new enumeration type for the specified bind rule dayofweek
+     * type.
+     * @param day  The boolean type name.
+     * @return  True if the keyword is equal to the specified name.
+     */
+    public boolean isDayOfWeek(String day){
+        return day.equalsIgnoreCase(this.day);
+    }
+
+    /**
+     * Create a new enumeration type for the specified dayofweek type name.
+     * @param day  The name of the enumeration to create.
+     * @return A new enumeration type for the name or null if the name is
+     * not valid.
+     */
+    public static EnumDayOfWeek createDayOfWeek(String day)
+    {
+        if (day != null){
+            for (EnumDayOfWeek t : EnumDayOfWeek.values()){
+                if (t.isDayOfWeek(day)){
+                    return t;
+                }
+            }
+        }
+        return null;
+    }
+
+    /*
+     * TODO Evaluate supporting alternative forms for days of the week.
+     *
+     *  Should we support alternate forms for the names of the days of the
+     *  week in the isDayOfWeek() or createdayOfWeek() method?  In particular,
+     *  should we handle the case in which the user provided the full name
+     *  (e.g., "monday" instead of "mon")?
+     */
+    /**
+     *  Return a enumeration relating to a Calendar day of week field.
+     * @param day The day of week index to get.
+     * @return  An enumeration corresponding to the wanted day of the week or
+     * null if the day index is invalid.
+     */
+    public static EnumDayOfWeek getDayOfWeek(int day)
+    {
+        switch(day){
+        case Calendar.SUNDAY:
+            return DAY_SUNDAY;
+
+        case Calendar.MONDAY:
+            return DAY_MONDAY;
+
+        case Calendar.TUESDAY:
+            return DAY_TUESDAY;
+
+        case Calendar.WEDNESDAY:
+            return DAY_WEDNESDAY;
+
+        case Calendar.THURSDAY:
+            return DAY_THURSDAY;
+
+        case Calendar.FRIDAY:
+            return DAY_FRIDAY;
+
+        case Calendar.SATURDAY:
+            return DAY_SATURDAY;
+        }
+        return null;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumEvalResult.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumEvalResult.java
new file mode 100644
index 0000000..a3a9d22
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumEvalResult.java
@@ -0,0 +1,111 @@
+/*
+ * 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;
+
+/**
+ * This class provides an enumeration of evaluation results returned by
+ * the bind rule evaluation methods.
+ */
+public enum EnumEvalResult {
+    /**
+     * This enumeration is returned when the result of the evaluation is TRUE.
+     */
+    TRUE(0),
+    /**
+     * This enumeration is returned when the result of the evaluation is FALSE.
+     */
+    FALSE(1),
+    /**
+     * This enumeration is returned when the result of the evaluation is FAIL.
+     * This should only be returned when a system failure occurred.
+     */
+    FAIL(2),
+    /**
+     * This is an internal enumeration used during evaluation of bind rule when
+     * internal processing of the evaluation is undefined. It is never returned
+     * back as a result of the evaluation.
+     */
+    ERR(3);
+
+    /**
+     * Create a new enumeration type for the specified result value.
+     * @param v The value of the result.
+     */
+    EnumEvalResult(int v) {
+    }
+
+    /**
+     * The method tries to determine if the result was undefined, and if so
+     * it returns an FAIL enumeration. If the result was not undefined (the
+     * common case for all of the bind rule evaluations), then the bind rule
+     * type is examined to see if the result needs to be flipped (type equals
+     * NOT_EQUAL_BINDRULE_TYPE).
+     * @param type The bind rule type enumeration of the bind rule.
+     * @param undefined  A flag that signals the the result was undefined.
+     * @return An enumeration containing the correct result after processing
+     * the undefined field and the bind rule type enumeration.
+     */
+    public EnumEvalResult getRet(EnumBindRuleType type, boolean undefined) {
+        EnumEvalResult ret=this;
+        if(this.equals(EnumEvalResult.TRUE) || !undefined) {
+            if(type.equals(EnumBindRuleType.NOT_EQUAL_BINDRULE_TYPE))
+                if(this.equals(EnumEvalResult.TRUE))
+                    ret=EnumEvalResult.FALSE;
+                else
+                    ret=EnumEvalResult.TRUE;
+        } else
+            ret=EnumEvalResult.FAIL;
+        return ret;
+    }
+
+    /**
+     * This method is used to possibly negate the result of a simple bind rule
+     * evaluation. If the boolean is true than the result is negated.
+     * @param v The enumeration result of the simple bind rule evaluation.
+     * @param n If true the result should be negated (TRUE->FALSE, FALSE->TRUE).
+     * @return  A possibly negated enumeration result.
+     */
+    public  static EnumEvalResult negateIfNeeded(EnumEvalResult v, boolean n) {
+        if(n) {
+            if(v.equals(EnumEvalResult.TRUE))
+                v=EnumEvalResult.FALSE;
+            else
+                v=EnumEvalResult.TRUE;
+        }
+        return v;
+    }
+
+    /**
+     * Helper method that converts this enumeration to a boolean. Usually the
+     * FAIL enumeration has been handled before this is called.
+     * @return True if the enumeration is TRUE, else false.
+     */
+    public boolean getBoolVal() {
+        return this == EnumEvalResult.TRUE;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumRight.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumRight.java
new file mode 100644
index 0000000..335124e
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumRight.java
@@ -0,0 +1,173 @@
+/*
+ * 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;
+
+/**
+ * This class provides an enumeration of the allowed rights.
+ */
+public enum EnumRight {
+
+    /**
+     * This enumeration is returned when the result of the right is "read".
+     */
+    READ        ("read"),
+    /**
+     * This enumeration is returned when the result of the right is "write".
+     */
+    WRITE       ("write"),
+    /**
+     * This enumeration is returned when the result of the right is "add".
+     */
+    ADD         ("add"),
+    /**
+     * This enumeration is returned when the result of the right is "delete".
+     */
+    DELETE      ("delete"),
+    /**
+     * This enumeration is returned when the result of the right is "search".
+     */
+    SEARCH      ("search"),
+    /**
+     * This enumeration is returned when the result of the right is "compare".
+     */
+    COMPARE     ("compare"),
+    /**
+     * This enumeration is returned when the result of the right is
+     * "selfwrite".
+     */
+    SELFWRITE   ("selfwrite"),
+    /**
+     * This enumeration is returned when the result of the right is "proxy".
+     */
+    PROXY       ("proxy"),
+    /**
+     * This enumeration is returned when the result of the right is "import".
+     */
+    IMPORT      ("import"),
+    /**
+     * This enumeration is returned when the result of the right is "export".
+     */
+    EXPORT      ("export"),
+    /**
+     * This enumeration is returned when the result of the right is "all".
+     */
+    ALL         ("all"),
+    /**
+     * This enumeration is used internally by the modify operation
+     * processing and is not part of the ACI syntax.
+     */
+    DELWRITE    ("delwrite"),
+    /**
+     * This enumerations is used internally by the modify operation
+     * processing and is not part of the ACI syntax.
+     */
+    ADDWRITE    ("addwrite");
+
+    /**
+     * The name of the right.
+     */
+    private final String right;
+
+    /**
+     * Creates an enumeration of the right name.
+     * @param right The name of the right.
+     */
+    EnumRight (String right) {
+        this.right = right ;
+    }
+
+    /**
+     * Checks if the enumeration is equal to the right name.
+     * @param right The name of the right to check.
+     * @return  True if the right is equal to the enumeration's.
+     */
+    public boolean isRight(String right){
+        return right.equalsIgnoreCase(this.right);
+    }
+
+    /**
+     * Creates an enumeration of the right name.
+     * @param right The name of the right.
+     * @return An enumeration of the right or null if the name is invalid.
+     */
+    public static EnumRight decode(String right){
+        if (right != null){
+            for (EnumRight t : EnumRight.values()){
+                if (t.isRight(right)){
+                    return t;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns bit mask associated with the specified right.
+     * @param right The right enumeration to return the mask for.
+     * @return The bit mask associated with the right.
+     */
+    public static int getMask(EnumRight right) {
+        int mask=AciHandler.ACI_NULL;
+        switch(right) {
+            case READ:
+                mask=AciHandler.ACI_READ;
+                break;
+            case WRITE:
+                mask=AciHandler.ACI_WRITE;
+                break;
+            case ADD:
+                mask=AciHandler.ACI_ADD;
+                break;
+            case DELETE:
+                mask=AciHandler.ACI_DELETE;
+                break;
+            case SEARCH:
+                mask=AciHandler.ACI_SEARCH;
+                break;
+            case COMPARE:
+                mask=AciHandler.ACI_COMPARE;
+                break;
+            case ALL:
+                mask=AciHandler.ACI_ALL;
+                break;
+            case  EXPORT:
+                mask=AciHandler.ACI_EXPORT;
+                break;
+            case IMPORT:
+                mask=AciHandler.ACI_IMPORT;
+                break;
+            case PROXY:
+                mask=AciHandler.ACI_PROXY;
+                break;
+            case SELFWRITE:
+                mask=AciHandler.ACI_SELF;
+                break;
+        }
+        return mask;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetKeyword.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetKeyword.java
new file mode 100644
index 0000000..0368d5d
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetKeyword.java
@@ -0,0 +1,108 @@
+/*
+ * 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;
+
+/**
+ *  This class provides an enumeration of the valid ACI target keywords.
+ */
+public enum EnumTargetKeyword {
+    /**
+     * This enumeration is returned when the target keyword is
+     * "target".
+     */
+    KEYWORD_TARGET      ("target"),
+    /**
+     * This enumeration is returned when the target keyword is
+     * "targetattr".
+     */
+    KEYWORD_TARGETATTR  ("targetattr"),
+    /**
+     * This enumeration is returned when the target keyword  is
+     * "targetscope".
+     */
+    KEYWORD_TARGETSCOPE ("targetscope"),
+    /**
+     * This enumeration is returned when the target keyword is
+     * "targetfilter".
+     */
+    KEYWORD_TARGETFILTER ("targetfilter"),
+    /**
+     * This enumeration is returned when the target keyword is
+     * "targattrfilters".
+     */
+    KEYWORD_TARGATTRFILTERS ("targattrfilters");
+    /*
+     * TODO Add support for the targattrfilters keyword.
+     */
+    /**
+     * The target keyword name.
+     */
+    private final String keyword;
+
+    /**
+     * Create a target keyword enumeration of the specified name.
+     * @param keyword    The keyword name.
+     */
+    EnumTargetKeyword(String keyword){
+        this.keyword = keyword;
+    }
+
+    /**
+     * Checks if the keyword name is equal to the enumeration name.
+     * @param keyword The keyword name to check.
+     * @return  True if the keyword name is equal to the enumeration.
+     */
+    public boolean isKeyword(String keyword){
+        return keyword.equalsIgnoreCase(this.keyword);
+    }
+
+    /**
+     * Create an enumeration of the provided keyword name.
+     * @param keyword The keyword name to create.
+     * @return  An enumeration of the specified keyword name or null
+     * if the keyword name is invalid.
+     */
+    public static EnumTargetKeyword createKeyword(String keyword){
+        if (keyword != null){
+            for (EnumTargetKeyword t : EnumTargetKeyword.values()){
+                if (t.isKeyword(keyword)){
+                    return t;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Return the enumeration keyword name.
+     * @return The keyword name.
+     */
+    public String getKeyword() {
+      return keyword;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetOperator.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetOperator.java
new file mode 100644
index 0000000..195208c
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetOperator.java
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+/**
+ *  This class provides an enumeration of the valid ACI target operators.
+ */
+public enum EnumTargetOperator {
+    /**
+    * This enumeration is returned when the target operator is  "=".
+     */
+    EQUALITY        ("="),
+    /**
+    * This enumeration is returned when the target operator is  "!=".
+     */
+    NOT_EQUALITY    ("!=");
+
+    /**
+     * The target operator name.
+     */
+    private final String operator;
+
+    /**
+     * Create an enumeration of the provided operator name.
+     * @param operator The operator name to create.
+     */
+    EnumTargetOperator(String operator){
+        this.operator = operator;
+    }
+
+    /**
+     * Checks if the provided operator name is equal to the enumeration.
+     * @param op The operator name to check for.
+     * @return  True if the operator name is equal to the enumeration.
+     */
+    public boolean isOperator(String op){
+        return op.equalsIgnoreCase(operator);
+    }
+
+    /**
+     * Creates an enumeration of the specified operator type name.
+     * @param op The operator type name to create.
+     * @return  Return an enumeration of the operator type name or null if the
+     * name is invalid.
+     */
+    public static EnumTargetOperator createOperator(String op){
+        if (op != null){
+            for (EnumTargetOperator t : EnumTargetOperator.values()){
+                if (t.isOperator(op)){
+                    return t;
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumUserDNType.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumUserDNType.java
new file mode 100644
index 0000000..240c969
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumUserDNType.java
@@ -0,0 +1,84 @@
+/*
+ * 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;
+
+
+/**
+ * Enumeration that represents the type an "userdn" keyword DN can have.
+ * The issues is the syntax allows invalid URLs such as "ldap:///anyone"
+ * and "ldap:///self".  The strategy is to use this class to hold
+ * the type and another class UserDNTypeURL to hold both this type and URL.
+ *
+ * If the URL is an invalid URL, then a dummy URL is saved.
+ * For types such as URL, DN and DNPATTERN, the actual URL is saved and can
+ * be retrieved by the UserDN.evaluate() method when needed. The dummy URL is
+ * ignored in the UserDN.evaluate() method for types such as: ALL, PARENT,
+ * 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.
+         */
+        DN(0),
+        /**
+         * The enumeration type when the "userdn" URL contains only a DN (no
+         * filter or scope) and that DN has a substring pattern.
+         */
+        DNPATTERN(1),
+        /**
+         * The enumeration type when the "userdn" URL has the value of:
+         *  "ldap:///all".
+         */
+        ALL(2),
+        /**
+         * The enumeration type when the "userdn" URL has the value of:
+         *  "ldap:///parent".
+         */
+        PARENT(3),
+        /**
+         * The enumeration type when the "userdn" URL has the value of:
+         *  "ldap:///self".
+         */
+        SELF(4),
+        /**
+         * The enumeration type when the "userdn" URL has the value of:
+         *  "ldap:///anyone".
+         */
+        ANYONE(5),
+        /**
+         * The enumeration type when the "userdn" URL is contains a DN (suffix),
+         * a scope and a filter.
+         */
+        URL(6);
+
+        /**
+         * Constructor taking an integer value.
+         * @param v Integer value.
+         */
+        EnumUserDNType(int v) {}
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java
new file mode 100644
index 0000000..2145e77
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/GroupDN.java
@@ -0,0 +1,151 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import org.opends.server.types.*;
+import org.opends.server.api.Group;
+import org.opends.server.core.GroupManager;
+import org.opends.server.core.DirectoryServer;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.LinkedHashSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * This class implements the groupdn bind rule keyword.
+ */
+public class GroupDN implements KeywordBindRule {
+
+    LinkedList<DN> groupDNs=null;
+    private EnumBindRuleType type=null;
+    private static GroupManager groupManager =
+            DirectoryServer.getGroupManager();
+
+    /**
+     * Create a class representing a groupdn bind rule keyword.
+     * @param type An enumeration representing the bind rule type.
+     * @param groupDNs A list of the dns representing groups.
+     */
+    private GroupDN(EnumBindRuleType type, LinkedList<DN> groupDNs ) {
+        this.groupDNs=groupDNs;
+        this.type=type;
+    }
+
+    /**
+     * Decode an string expression representing a groupdn bind rule.
+     * @param expr  A string representation of the bind rule.
+     * @param type An enumeration of the type of the bind rule.
+     * @return  A keyword bind rule class that can be used to evaluate
+     * this bind rule.
+     * @throws AciException   If the expression string 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)) {
+            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);
+        Matcher ldapURLMatcher = ldapURLPattern.matcher(expr);
+        while (ldapURLMatcher.find()) {
+            try {
+               String value = ldapURLMatcher.group(ldapURLPos).trim();
+               DN dn=LDAPURL.decode(value, true).getBaseDN();
+               groupDNs.add(dn);
+            } catch (DirectoryException ex) {
+                int msgID = MSGID_ACI_SYNTAX_INVALID_GROUPDN_URL;
+                String message = getMessage(msgID, ex.getErrorMessage());
+                throw new AciException(msgID, message);
+            }
+        }
+        return new GroupDN(type, groupDNs);
+    }
+
+    /**
+     * Performs the evaluation of a groupdn bind rule based on the
+     * evaluation context passed to it. The evaluation stops when there
+     * are no more group DNs to evaluate, or if a group DN evaluates to true
+     * if it contains the client DN.
+     * @param evalCtx  An evaluation context to use  in the evaluation.
+     * @return  Enumeration evaluation result.
+     */
+    public EnumEvalResult evaluate(AciEvalContext evalCtx) {
+        EnumEvalResult matched = EnumEvalResult.FALSE;
+       Iterator<DN> it=groupDNs.iterator();
+        for(; it.hasNext() && matched != EnumEvalResult.TRUE;) {
+            DN  groupDN=it.next();
+            Group group = groupManager.getGroupInstance(groupDN);
+            if((group != null) && (evalCtx.isMemberOf(group)))
+               matched = EnumEvalResult.TRUE;
+        }
+        return matched.getRet(type, false);
+    }
+
+    /**
+     * Performs an evaluation of a group that was specified in an attribute
+     * type value of the specified entry and attribute type. Each
+     * value of the attribute type is assumed to be a group DN and evaluation
+     * stops when there are no more values or if the group DN evaluates to
+     * true if it contains the client DN.
+     * @param e The entry to use in the evaluation.
+     * @param evalCtx  The evaluation context to use in the evaluation.
+     * @param attributeType The attribute type of the entry to use to get the
+     * values for the groupd DNs.
+     * @return Enumeration evaluation result.
+     */
+    public static EnumEvalResult evaluate (Entry e, AciEvalContext evalCtx,
+                                           AttributeType attributeType) {
+        EnumEvalResult matched= EnumEvalResult.FALSE;
+        List<Attribute> attrs = e.getAttribute(attributeType);
+        LinkedHashSet<AttributeValue> vals = attrs.get(0).getValues();
+        for(AttributeValue v : vals) {
+            try {
+                DN groupDN=DN.decode(v.getStringValue());
+                Group group = groupManager.getGroupInstance(groupDN);
+                if((group != null) && (evalCtx.isMemberOf(group))) {
+                    matched=EnumEvalResult.TRUE;
+                    break;
+                }
+            } catch (DirectoryException ex) {
+                break;
+            }
+        }
+        return matched;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpBitsNetworkCriteria.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpBitsNetworkCriteria.java
new file mode 100644
index 0000000..f1c76e1
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpBitsNetworkCriteria.java
@@ -0,0 +1,200 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * This class builds a network string to an internal representation.
+ */
+public class IpBitsNetworkCriteria {
+
+  byte[] _address;    // address in byte format
+  int _bits;      // number of bits for matching
+  byte[] _bitsArray;    // bits in network order
+  InetAddress _inetAddress;
+
+  /**
+   * Creates a new IpBitsNeworkCriteria instance.
+   *
+   * @param  theInputAddress     IP address associated the rule. For IPV4
+   *                             addresses, the following
+   *                             textual formats are supported
+   *                             a.b.c.d
+   *                             a.b.c
+   *                             a.b
+   *                             a
+   *                             For IPv6 addresses, the following textual
+   *                             format are supported:
+   *                             x:x:x:x:x:x:x:x, where x are the hexadecimal
+   *                             values of the 8
+   *                             16-bits pieces of the address
+   *                             Use of :: to compress the leading
+   *                             and/or trailing zeros e.g.
+   *                             x::x:x:x:x:x:x
+   *
+   * @param  theBits             Number of bits of the network address
+   *                             necessary for matching.
+   *                             Max is 32 for IPv4 addresses and 128
+   *                              for IPv6 addresses \
+   *
+   * @throws UnknownHostException Thrown if the inetaddress cannot be gotten
+   * from the input address string.
+   * @throws AciException Thrown if the bit count is not in the correct
+   * ranges.
+   */
+
+  public IpBitsNetworkCriteria(String theInputAddress, int theBits)
+  throws UnknownHostException, AciException
+  {
+    boolean ipv4 = true;
+    _inetAddress = InetAddress.getByName(theInputAddress);
+
+    if (_inetAddress instanceof Inet6Address)
+    {
+      if (theBits < 0 || theBits > 128) {
+          int msgID = MSGID_ACI_SYNTAX_INVALID_NETWORK_BIT_MATCH;
+          String message = getMessage(msgID, "IPV6",
+                  "Bits must be in [0..128] range.");
+          throw new AciException(msgID, message);
+      }
+      ipv4=false;
+    }
+    else
+    {
+      // Assume IPv4
+      if (theBits < 0 || theBits > 32) {
+          int msgID = MSGID_ACI_SYNTAX_INVALID_NETWORK_BIT_MATCH;
+          String message = getMessage(msgID, "IPV4",
+                  "Bits must be in [0..32] range.");
+          throw new AciException(msgID, message);
+      }
+    }
+
+    _bits = theBits;
+
+    // Convert the bits into a mask in network byte order
+    if (ipv4)
+    {
+      _bitsArray = new byte[4];
+      // in java int is exactly 4 bytes
+      int rawBits;
+      if (theBits==0)
+        rawBits=0;
+      else
+        rawBits=~0;
+      rawBits = rawBits << (32 - theBits);
+      // Use network order for the comparison
+      _bitsArray[0] = (byte) ((rawBits >> 24) & 0xFF );
+      _bitsArray[1] = (byte) ((rawBits >> 16) & 0xFF );
+      _bitsArray[2] = (byte) ((rawBits >> 8) & 0xFF );
+      _bitsArray[3] = (byte) ((rawBits) & 0xFF );
+    }
+    else
+    {
+      _bitsArray = new byte[16];
+      int index=0;
+      if (theBits > 64)
+      {
+        _bitsArray[0] = (byte) 0xFF;
+        _bitsArray[1] = (byte) 0xFF;
+        _bitsArray[2] = (byte) 0xFF;
+        _bitsArray[3] = (byte) 0xFF;
+        _bitsArray[4] = (byte) 0xFF;
+        _bitsArray[5] = (byte) 0xFF;
+        _bitsArray[6] = (byte) 0xFF;
+        _bitsArray[7] = (byte) 0xFF;
+        theBits-=64;
+        index=8;
+      }
+      long rawBits = ~0;
+      rawBits = rawBits << (64 - theBits);
+
+      if (_bits !=0)
+      {
+        _bitsArray[index++] = (byte) ((rawBits >> 56) & 0xFF );
+        _bitsArray[index++] = (byte) ((rawBits >> 48) & 0xFF );
+        _bitsArray[index++] = (byte) ((rawBits >> 40) & 0xFF );
+        _bitsArray[index++] = (byte) ((rawBits >> 32) & 0xFF );
+        _bitsArray[index++] = (byte) ((rawBits >> 24) & 0xFF );
+        _bitsArray[index++] = (byte) ((rawBits >> 16) & 0xFF );
+        _bitsArray[index++] = (byte) ((rawBits >> 8) & 0xFF );
+        _bitsArray[index] = (byte) ((rawBits ) & 0xFF );
+      }
+    }
+
+    _address = _inetAddress.getAddress();
+  }
+
+  /**
+   * Compare an IP address with the network rule.
+   *
+   * @param  theSourceAddress   IP source address of the client contacting
+   *                            the proxy server.
+   * @return  <CODE>true</CODE> if client matches the network rule or
+   *          <CODE>false</CODE> if they may not.
+   */
+
+  public boolean match (InetAddress theSourceAddress)
+  {
+
+    byte[] addr = theSourceAddress.getAddress();
+
+    if ((addr.length * 8) < _bits) {
+      // Client IP  too small. Won't match.
+      return false;
+    }
+
+    for (int i=0; i<addr.length; i++)
+    {
+      if ((addr[i] & _bitsArray[i]) != (_address[i] & _bitsArray[i])) {
+        return false;
+      }
+    }
+
+    return true;
+
+  }
+
+  /**
+   * String representation of this criteria.
+   *
+   * @return  a String representation of the IpMaskNetworkCriteria
+   */
+
+  public String toString()
+  {
+    return "Address:" + _inetAddress.getHostAddress() +
+        "/" + Integer.toString(_bits);
+  }
+
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpCriteria.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpCriteria.java
new file mode 100644
index 0000000..6e05740
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpCriteria.java
@@ -0,0 +1,291 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class represents a ip bind rule keyword.
+ */
+public class IpCriteria implements KeywordBindRule
+{
+    private EnumBindRuleType type=null;
+
+    // private token to express that any address is accepted
+    private final static String ANY_ADDRESSES = "ALL";
+    private boolean matchAnyAddress = false;
+
+    private IpBitsNetworkCriteria[] ipBitsCriteria = null;
+    private IpMaskNetworkCriteria[] ipMaskCriteria = null;
+
+    /*
+     * TODO Verifiy IpCriteria constructor adheres to DS 5.2 ip keyword
+     * syntax.
+     *
+     * Based on the contents of the constructor, it doesn't appear that the
+     * IpCriteria class uses the same set of allowed values as DS 5.2 does
+     * with the "ip" keyword (as documented at
+     * http://docs.sun.com/source/817-7613/aci.html#wp20242).  Was that the
+     * intention?  It looks like it doesn't allow asterisks as wild-ccards or
+     * plus signs to specify netmasks (although it appears that it expects a
+     * slash to be  used if you want a netmask).  While I don't mind allowing
+     * alternate formats (e.g., CIDR-style addresses), we can't drop support
+     * for the existing ones if we're trying to maintain compatibility.
+     */
+    /**
+     * Constructor that creates an IpCriteria from an array of values and
+     * an enumeration bind rule type.
+     * @param values An array of address values.
+     * @param type An enumeration of the bind rule type.
+     * @throws UnknownHostException If the host address cannot be resolved to
+     * a hostname.
+     * @throws AciException  If a part of the address is invalid.
+     * @throws IndexOutOfBoundsException  If an index is incremented past an
+     * array bounds when copying or evaluating an address.
+     */
+    public IpCriteria(String[] values, EnumBindRuleType type)
+    throws UnknownHostException, IndexOutOfBoundsException, AciException {
+        IpBitsNetworkCriteria[] ipBitsCriteria_2 = null;
+        IpMaskNetworkCriteria[] ipMaskCriteria_2 = null;
+        try
+        {
+            for (String value : values)
+            {
+                if (value.equalsIgnoreCase(ANY_ADDRESSES))
+                {
+                    matchAnyAddress = true;
+                    continue;
+                }
+                // determine what format it is to instantiate
+                // the right criteria object
+                int slash = value.indexOf("/");
+                if (slash == -1)
+                {
+                    // simple raw IP address
+                    IpBitsNetworkCriteria newInstance;
+                    if (InetAddress.getByName(value)
+                            instanceof Inet6Address)
+                    {
+                        newInstance = new IpBitsNetworkCriteria(value, 128);
+                    } else
+                    {
+                        newInstance = new IpBitsNetworkCriteria(value, 32);
+                    }
+                    if (ipBitsCriteria_2 == null)
+                    {
+                        ipBitsCriteria_2 = new IpBitsNetworkCriteria[1];
+                    } else
+                    {
+                        IpBitsNetworkCriteria[] newIpBitsCriteria =
+                         new IpBitsNetworkCriteria[ipBitsCriteria_2.length + 1];
+                        System.arraycopy(ipBitsCriteria_2, 0,
+                                newIpBitsCriteria, 0, ipBitsCriteria_2.length);
+                        ipBitsCriteria_2 = newIpBitsCriteria;
+                    }
+                    ipBitsCriteria_2[ipBitsCriteria_2.length - 1] = newInstance;
+                } else
+                {
+                    // Extract data following the / and figure out whether it
+                    // is a bit number or a mask
+                    try
+                    {
+                        int bits =
+                                Integer.parseInt(value.substring(slash + 1));
+                        // Well, no exception, so this is a bit
+                        // Let's instantiate the corresponding criterion
+                        if (ipBitsCriteria_2 == null)
+                        {
+                            ipBitsCriteria_2 = new IpBitsNetworkCriteria[1];
+                        } else
+                        {
+                         IpBitsNetworkCriteria[] newIpBitsCriteria =
+                         new IpBitsNetworkCriteria[ipBitsCriteria_2.length + 1];
+                            System.arraycopy(ipBitsCriteria_2, 0,
+                                 newIpBitsCriteria, 0, ipBitsCriteria_2.length);
+                            ipBitsCriteria_2 = newIpBitsCriteria;
+                        }
+                        ipBitsCriteria_2[ipBitsCriteria_2.length - 1] =
+                                new IpBitsNetworkCriteria(value.
+                                        substring(0, slash), bits);
+                    }
+                    catch (IndexOutOfBoundsException e1)
+                    {
+                        throw e1;
+                    }
+                    catch (Exception e2)
+                    {
+                        // Looks like this is a network mask.
+                        if (ipMaskCriteria_2 == null)
+                        {
+                            ipMaskCriteria_2 = new IpMaskNetworkCriteria[1];
+                        } else
+                        {
+                        IpMaskNetworkCriteria[] newIpMaskCriteria =
+                         new IpMaskNetworkCriteria[ipMaskCriteria_2.length + 1];
+                            System.arraycopy(ipMaskCriteria_2, 0,
+                                 newIpMaskCriteria, 0, ipMaskCriteria_2.length);
+                            ipMaskCriteria_2 = newIpMaskCriteria;
+                        }
+                        try
+                        {
+                            ipMaskCriteria_2[ipMaskCriteria_2.length - 1] =
+                              new IpMaskNetworkCriteria(value.
+                              substring(0, slash), value.substring(slash + 1));
+                        }
+                        catch (IndexOutOfBoundsException e3)
+                        {
+                            throw e3;
+                        }
+                    }
+                }
+            }
+        }
+        catch (UnknownHostException ue)
+        {
+            throw ue;
+        }
+        ipBitsCriteria = ipBitsCriteria_2;
+        ipMaskCriteria = ipMaskCriteria_2;
+        this.type=type;
+    }
+
+    /**
+     * Return the ipBitsNetworkCriteria of this  IpCriteria.
+     * @return Returns the ipBitsNetworkCriteria.
+     */
+    public IpBitsNetworkCriteria[] getIpBitsNetworkCriteria() {
+        return ipBitsCriteria;
+    }
+
+    /**
+     * Return the ipMaskNetworkCriteria of this IpCriteria.
+     * @return Returns the ipMaskNetworkCriteria.
+     */
+    public IpMaskNetworkCriteria[] getIpMaskNetworkCriteria() {
+        return ipMaskCriteria;
+    }
+
+    /**
+     * Compare an IP address with the network rule.
+     *
+     * @param  theSourceAddress   IP source address of the client.
+     * @return  <CODE>true</CODE> if client matches the network rule or
+     *          <CODE>false</CODE> if they may not.
+     */
+    public boolean match (InetAddress theSourceAddress)
+    {
+        if (matchAnyAddress){
+            return true;
+        }
+        if (ipMaskCriteria != null)
+        {
+            for (IpMaskNetworkCriteria anIpMaskCriteria : ipMaskCriteria)
+            {
+                if (anIpMaskCriteria.match(theSourceAddress))
+                {
+                    return true;
+                }
+            }
+        }
+
+        if (ipBitsCriteria != null)
+        {
+            for (IpBitsNetworkCriteria anIpBitsCriteria : ipBitsCriteria)
+            {
+                if (anIpBitsCriteria.match(theSourceAddress))
+                {
+                    return true;
+                }
+            }
+        }
+
+        return (ipBitsCriteria == null) && (ipMaskCriteria == null);
+    }
+
+    /**
+     * Decode an expression string representing a ip keyword bind rule
+     * expression.
+     * @param expr A string representing the expression.
+     * @param type An enumeration representing the bind rule type.
+     * @return  An keyword bind rule that can be used to evaluate the
+     * expression.
+     * @throws AciException  If the expression string is invalid.
+     */
+    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);
+            throw new AciException(msgID, message);
+        }
+
+        int valuePos = 1;
+        Pattern valuePattern = Pattern.compile(valueRegex);
+        Matcher valueMatcher = valuePattern.matcher(expr);
+        HashSet<String> values = new HashSet<String>();
+        while (valueMatcher.find()) {
+            String value = valueMatcher.group(valuePos);
+            values.add(value);
+        }
+        IpCriteria ipCriteria;
+        String[] strValues = null;
+        if (!values.isEmpty()) {
+            strValues = values.toArray(new String[values.size()]);
+        }
+        try {
+            ipCriteria = new IpCriteria(strValues, type);
+        } catch (Exception e) {
+            int msgID = MSGID_ACI_SYNTAX_INVALID_IP_CRITERIA_DECODE;
+            String message = getMessage(msgID, e.getMessage());
+            throw new AciException(msgID, message);
+        }
+        return ipCriteria;
+    }
+
+    /**
+     * Evaluate the evaluation context against this ip criteria.
+     * @param evalCtx An evaluation context to use.
+     * @return An enumeration evaluation result.
+     */
+    public EnumEvalResult evaluate(AciEvalContext evalCtx) {
+        EnumEvalResult matched=EnumEvalResult.FALSE;
+        if(match(evalCtx.getRemoteAddress()))
+              matched=EnumEvalResult.TRUE;
+        return matched.getRet(type, false);
+    }
+}
+
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpMaskNetworkCriteria.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpMaskNetworkCriteria.java
new file mode 100644
index 0000000..38e15a7
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/IpMaskNetworkCriteria.java
@@ -0,0 +1,140 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ *   This class creates a network mask criteria from the address and mask
+ *   string passed to it.
+ */
+class IpMaskNetworkCriteria
+{
+
+  byte[] _address;    // address in byte format
+  byte[] _mask;     // mask in byte format
+  InetAddress _inetAddress;
+  InetAddress _inetMask;
+  boolean _ipv4;      // true if ipv4 address
+
+
+  /**
+   * Creates a new IpMaskNeworkCriteria instance.
+   *
+   * @param  theInputAddress     IP address associated the rule. For IPV4
+   *                             addresses, the following
+   *                             textual formats are supported
+   *                             a.b.c.d
+   *                             a.b.c
+   *                             a.b
+   *                             a
+   *                             For IPv6 addresses, the following textual
+   *                             format are supported:
+   *                             x:x:x:x:x:x:x:x, where x are the hexadecimal
+   *                             values of the 8 16-bits pieces of the address
+   *                             Use of :: to compress the leading  and/or
+   *                             trailing zeros e.g.x::x:x:x:x:x:x
+   *
+   * @param  theInputMask        Bits of the network address necessary
+   *                             for matching.
+   *                             Same format as the IP address above.
+   *
+   * @throws UnknownHostException Thrown if the hostname of the input address
+   * cannot be resolved.
+   * @throws AciException If the address family has a mismatch.
+   */
+
+  public IpMaskNetworkCriteria(String theInputAddress, String theInputMask)
+  throws UnknownHostException, AciException {
+    _inetAddress = InetAddress.getByName(theInputAddress);
+    _inetMask = InetAddress.getByName(theInputMask);
+    _address = _inetAddress.getAddress();
+    _mask = _inetMask.getAddress();
+
+    if (_inetAddress instanceof Inet4Address)
+      _ipv4=true;
+
+    if (_ipv4 && !(_inetMask instanceof Inet4Address) ||
+       (!_ipv4 && !(_inetMask instanceof Inet6Address))) {
+        int msgID = MSGID_ACI_SYNTAX_ADDRESS_FAMILY_MISMATCH;
+        String message = getMessage(msgID, theInputMask, theInputAddress);
+        throw new AciException(msgID, message);
+    }
+  }
+
+  /**
+   * Compare an IP address with the network criteria.
+   *
+   * @param  theSourceAddress   IP source address of the client.
+   * @return  <CODE>true</CODE> if client matches the network rule or
+   *          <CODE>false</CODE> if they may not.
+   */
+
+  public boolean match (InetAddress theSourceAddress)
+  {
+    // First address family must match
+    if (_ipv4)
+    {
+      if (!(theSourceAddress instanceof Inet4Address))
+        return false;
+    }
+    else
+    {
+      if (!(theSourceAddress instanceof Inet6Address))
+        return false;
+    }
+
+    byte[] addr = theSourceAddress.getAddress();
+    for (int i=0; i<addr.length; i++) {
+      if ((addr[i] & _mask[i]) != (_address[i] & _mask[i])) {
+        return false;
+      }
+    }
+    return true;
+
+  }
+
+  /**
+   * String representation of this rule.
+   *
+   * @return  a String representation of the IpMaskNetworkRule.
+   */
+
+  public String toString()
+  {
+    return "Address:" + _inetAddress.getHostAddress() +
+        " Mask:" + _inetMask.getHostAddress();
+  }
+}
+
+
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/KeywordBindRule.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/KeywordBindRule.java
new file mode 100644
index 0000000..c9205f8
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/KeywordBindRule.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+/**
+ * This interface represents a keyword  bind rule class
+ * that can evaluate an evaluation context. It defines a single
+ * function that each of the keyword functions implement (ip, dns,
+ * roledn, groupdn, ...)
+ */
+public interface KeywordBindRule
+{
+    /**
+     * Evaluate a bind rule using the passed in context.
+     * @param evalCtx An evaluation context to use in the evaluation.
+     * @return An enumeration evaluation result.
+     */
+    public EnumEvalResult evaluate(AciEvalContext evalCtx);
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java
new file mode 100644
index 0000000..abb6ed9
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/ParentInheritance.java
@@ -0,0 +1,172 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.util.StringTokenizer;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.AttributeType;
+
+/**
+ * This class is used by USERDN and GROUPDN userattr types
+ * 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;
+    private String parentPat="parent[";
+    private int[] levels=new int[MAX_LEVELS];
+    private int numLevels;
+    private AttributeType attributeType;
+
+
+    /**
+     * Construct a class from the inheritance pattern. The skipParsing boolean
+     * specifies that parent parsing should be skipped and sets up the class:
+     * with numLevels=1, level[0]=0 and an attribute type from the
+     * specified pattern.
+     *
+     * @param pattern The string pattern containing the inheritance
+     * information.
+     * @param skipParse Specify if the parent inheritance parsing should be
+     * skipped or not.
+     * @throws AciException  If the pattern is invalid.
+     */
+    ParentInheritance (String pattern, boolean skipParse)  throws AciException {
+        if (skipParse) {
+            //The "parent[" pattern is invalid for ROLEDN user attr keyword.
+            if(pattern.startsWith(parentPat)) {
+                int msgID =
+                  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;
+            }
+        } else
+            parse(pattern);
+    }
+
+    /**
+     * Performs all parsing of the specified pattern string.
+     * @param pattern The string pattern containing the inheritance
+     * information.
+     * @throws AciException  If the pattern is invalid.
+     */
+    private void parse (String pattern) throws AciException {
+        pattern=pattern.trim();
+        /**
+         * Check if we have a "parent[" string.
+         */
+        if(pattern.startsWith(parentPat)) {
+            numLevels=0;
+            levels[0]=0;
+            String p=pattern.substring(parentPat.length());
+            /**
+             * Format needs to be parent[XX].attribute -- everything after the
+             * '.' is the attribute type.
+             */
+            String[] toks=p.split("\\.");
+            if(toks.length != 2) {
+                int msgID =
+                    MSGID_ACI_SYNTAX_INVALID_USERATTR_INHERITANCE_PATTERN;
+                String message = getMessage(msgID, pattern);
+                throw new AciException(msgID, message);
+            }
+            if((this.attributeType =
+                DirectoryServer.getAttributeType(toks[1])) == null)
+                this.attributeType =
+                    DirectoryServer.getDefaultAttributeType(toks[1]);
+            StringTokenizer tok=new StringTokenizer(toks[0],"],",false);
+            while(tok.hasMoreTokens()) {
+                String v=tok.nextToken();
+                /**
+                 * Everything between the brackets must be an integer or it's
+                 * an error.
+                 */
+                try {
+                    if(numLevels < MAX_LEVELS) {
+                        levels[numLevels++]=Integer.decode(v);
+                    } else {
+                        int msgID =
+                      MSGID_ACI_SYNTAX_MAX_USERATTR_INHERITANCE_LEVEL_EXCEEDED;
+                        String message = getMessage(msgID, pattern,
+                                               Integer.toString(MAX_LEVELS));
+                        throw new AciException(msgID, message);
+                    }
+                } catch (NumberFormatException ex) {
+                    int msgID = MSGID_ACI_SYNTAX_INVALID_INHERITANCE_VALUE;
+                    String message = getMessage(msgID, pattern);
+                    throw new AciException(msgID, message);
+                }
+            }
+        } else {
+            if((this.attributeType =
+                DirectoryServer.getAttributeType(pattern)) == null)
+                this.attributeType =
+                    DirectoryServer.getDefaultAttributeType(pattern);
+            numLevels=1;
+            levels[0]=0;
+        }
+    }
+
+    /**
+     * Returns the number of levels counted.
+     * @return The number of levels.
+     */
+    public int getNumLevels() {
+        return numLevels;
+    }
+
+    /**
+     * Returns an array of levels, where levels are integers.
+     * @return Return an array of levels.
+     */
+    public int[] getLevels() {
+        return levels;
+    }
+
+    /**
+     * Return the attribute type.
+     * @return The attribute type.
+     */
+    public AttributeType getAttributeType() {
+        return attributeType;
+    }
+}
+
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/PermBindRulePair.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/PermBindRulePair.java
new file mode 100644
index 0000000..41474a6
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/PermBindRulePair.java
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+/**
+ * A class representing a permission-bind rule pair. There can be multiple
+ * of these in an ACI.
+ */
+public class PermBindRulePair {
+
+    private BindRule bindRule;
+    private Permission perm=null;
+
+    /**
+     * This constructor calls the permission and bind rule decodes
+     * with the appropriate strings.
+     * @param perm  A string representing the permissions.
+     * @param rights  A string representing the rights.
+     * @param bindRule A string representing the bind rule.
+     * @throws AciException  If any of the strings fail to decode.
+     */
+    private  PermBindRulePair(String perm, String rights, String bindRule)
+    throws AciException {
+     this.perm=Permission.decode(perm, rights);
+     this.bindRule=BindRule.decode(bindRule);
+    }
+
+    /**
+     * Decodes a permission bind rule pair.
+     * @param perm  A string representing the permissions.
+     * @param rights  A string representing the rights.
+     * @param bRule A string representing the bind rule.
+     * @return An permission bind rule pair class representing this pair.
+     * @throws AciException  If any of the strings fail to decode.
+     */
+    public static PermBindRulePair decode(String perm, String rights,
+                                          String bRule) throws AciException {
+       return new PermBindRulePair(perm, rights, bRule);
+    }
+
+    /**
+     * Gets the bind rule part of this pair.
+     * @return  The bind rule part of this pair.
+     */
+    public BindRule getBindRule () {
+        return bindRule;
+    }
+
+    /**
+     * Checks the permission to see if it has this access type.
+     * @param accessType An enumeration of the desired access type.
+     * @return True if the access type equals the permission access type.
+     */
+    public boolean hasAccessType(EnumAccessType accessType) {
+        return perm.hasAccessType(accessType);
+    }
+
+    /**
+     * Try and match one or more of the specified rights against a rights set
+     * of the permission class.
+     * @param right  The rights to match.
+     * @return True if one or more of the specified rights match a right in
+     * the rights set of the permission class.
+     */
+    public boolean hasRights(int right) {
+        return perm.hasRights(right);
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Permission.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Permission.java
new file mode 100644
index 0000000..5f340ba
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Permission.java
@@ -0,0 +1,117 @@
+/*
+ * 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 static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.authorization.dseecompat.AciMessages.*;
+import java.util.regex.Pattern;
+
+/**
+ * A class representing the permissions of an bind rule. The permissions
+ * of an ACI look like deny(search, write).
+ */
+public class Permission {
+    //the access type (allow,deny)
+    private EnumAccessType accessType = null;
+    private int rights;
+    private static final String separatorToken = ",";
+    private static final String rightsRegex =
+        "\\s*(\\w+)\\s*(,\\s*(\\w+)\\s*)*";
+
+    /**
+     * Constructor creating a class representing a permission part of an bind
+     * rule.
+     * @param accessType A string representing access type.
+     * @param rights  A string representing the rights.
+     * @throws AciException If the access type string or rights string
+     * is invalid.
+     */
+    private Permission(String accessType, String rights)
+    throws AciException {
+        if ((this.accessType =
+            EnumAccessType.decode(accessType)) == null){
+            int msgID = MSGID_ACI_SYNTAX_INVALID_ACCESS_TYPE_VERSION;
+            String message = getMessage(msgID, accessType);
+            throw new AciException(msgID, message);
+        }
+        if (!Pattern.matches(rightsRegex, rights)){
+            int msgID = MSGID_ACI_SYNTAX_INVALID_RIGHTS_SYNTAX;
+            String message = getMessage(msgID, rights);
+            throw new AciException(msgID, message);
+        }
+        else {
+            Pattern separatorPattern = Pattern.compile(separatorToken);
+            String[] rightsStr =
+                separatorPattern.split(rights.replaceAll("\\s", ""));
+            for (String r : rightsStr) {
+                EnumRight right = EnumRight.decode(r);
+                if (right != null)
+                    this.rights|= EnumRight.getMask(right);
+                else {
+                    int msgID = MSGID_ACI_SYNTAX_INVALID_RIGHTS_KEYWORD;
+                    String message = getMessage(msgID, rights);
+                    throw new AciException(msgID, message);
+                }
+            }
+        }
+    }
+
+    /**
+     * Decode an string representation of bind rule permission into a Permission
+     * class.
+     * @param accessType  A string representing the access type.
+     * @param rights   A string representing the rights.
+     * @return  A Permission class representing the permissions of the bind
+     * rule.
+     * @throws AciException  If the accesstype or rights strings are invalid.
+     */
+    public static
+    Permission decode (String accessType, String rights)
+    throws AciException {
+        return new Permission(accessType, rights);
+    }
+
+    /**
+     * Checks if a given access type enumeration is equal to this classes
+     * access type.
+     * @param accessType An enumeration representing an access type.
+     * @return True if the access types are equal.
+     */
+    public boolean hasAccessType(EnumAccessType accessType) {
+        return this.accessType == accessType;
+    }
+
+    /**
+     * Checks if the permission's rights has the specified rights.
+     * @param  rights The rights to check for.
+     * @return True if the permission's rights has the specified rights.
+     */
+    public boolean hasRights(int rights) {
+        return (this.rights & rights) != 0;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/RoleDN.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/RoleDN.java
new file mode 100644
index 0000000..a32f27e
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/RoleDN.java
@@ -0,0 +1,157 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import org.opends.server.types.*;
+import org.opends.server.api.Group;
+import org.opends.server.core.GroupManager;
+import org.opends.server.core.DirectoryServer;
+
+import java.util.LinkedList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.LinkedHashSet;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/**
+ * A class representing a roledn bind rule keyword. This class is almost
+ * an exact copy of groupDN, except for variable names and error messages.
+ */
+public class RoleDN  implements KeywordBindRule {
+
+    LinkedList<DN> roleDNs=null;
+    private EnumBindRuleType type=null;
+    private static GroupManager groupManager =
+            DirectoryServer.getGroupManager();
+
+    /**
+     * Constructor creating a class representing a roledn keyword of a bind
+     * rule.
+     * @param type An enumeration of the type of the bind rule.
+     * @param roleDNs A list of the role dns parsed from the expression string.
+     */
+    private RoleDN(EnumBindRuleType type, LinkedList<DN> roleDNs ) {
+        this.roleDNs=roleDNs;
+        this.type=type;
+    }
+
+    /**
+     * Decodes an expression string representing an roledn bind rule.
+     * @param expr A string representation of the bind rule.
+     * @param type An enumeration of the type of the bind rule.
+     * @return A keyword bind rule class that can be used to evaluate
+     * this bind rule.
+     * @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)) {
+            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);
+        Matcher ldapURLMatcher = ldapURLPattern.matcher(expr);
+        while (ldapURLMatcher.find()) {
+            String val = ldapURLMatcher.group(ldapURLPos);
+            val = val.trim();
+            DN dn;
+            try {
+                dn=DN.decode(val);
+            } 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);
+    }
+
+
+    /**
+     * Performs the evaluation of a roledn bind rule based on the
+     * evaluation context passed to it. The method uses an exact copy
+     * evaluation method as the groupDN.evaluate().  The evaluation stops when
+     * there are no more group DNs to evaluate, or if a group DN evaluates to
+     * true if it contains the authorization DN.
+     * @param evalCtx  An evaluation context to use  in the evaluation.
+     * @return  Enumeration evaluation result.
+     */
+    public EnumEvalResult evaluate(AciEvalContext evalCtx) {
+        EnumEvalResult matched = EnumEvalResult.FALSE;
+       Iterator<DN> it=roleDNs.iterator();
+        for(; it.hasNext() && matched != EnumEvalResult.TRUE;) {
+            DN groupDN=it.next();
+            Group group = groupManager.getGroupInstance(groupDN);
+            if(evalCtx.isMemberOf(group))
+               matched = EnumEvalResult.TRUE;
+        }
+        return matched.getRet(type, false);
+    }
+
+       /**
+     * Performs an evaluation of a group that was specified in an attribute
+     * type value of the specified entry and attribute type. Each
+     * value of the attribute type is assumed to be a group DN and evaluation
+     * stops when there are no more values or if the group DN evaluates to
+     * true if it contains the client DN.
+     * @param e The entry to use in the evaluation.
+     * @param evalCtx  The evaluation context to use in the evaluation.
+     * @param attributeType The attribute type of the entry to use to get the
+     * values for the groupd DNs.
+     * @return Enumeration evaluation result.
+     */
+    public static EnumEvalResult evaluate (Entry e, AciEvalContext evalCtx,
+                                           AttributeType attributeType) {
+        EnumEvalResult matched= EnumEvalResult.FALSE;
+        List<Attribute> attrs = e.getAttribute(attributeType);
+        LinkedHashSet<AttributeValue> vals = attrs.get(0).getValues();
+        for(AttributeValue v : vals) {
+            try {
+                DN groupDN=DN.decode(v.getStringValue());
+                Group group = groupManager.getGroupInstance(groupDN);
+                if((group != null) && (evalCtx.isMemberOf(group))) {
+                    matched=EnumEvalResult.TRUE;
+                    break;
+                }
+            } catch (DirectoryException ex) {
+                break;
+            }
+        }
+        return matched;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilters.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilters.java
new file mode 100644
index 0000000..2efc454
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargAttrFilters.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+/**
+ * Placeholder. This class is partially complete. The TargAttrFilters class
+ * will represent an targAttrFitlers rule.
+ */
+public class TargAttrFilters {
+
+    /**
+     * Represents an targAttrFilters rule.
+     */
+    public TargAttrFilters() {
+
+    }
+
+    /**
+     * 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.
+     */
+    public static TargAttrFilters decode(EnumTargetOperator operator,
+                                  String expression) throws AciException {
+        return new TargAttrFilters();
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Target.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Target.java
new file mode 100644
index 0000000..d3d755b
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Target.java
@@ -0,0 +1,198 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.regex.Pattern;
+import org.opends.server.core.DirectoryServer;
+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.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.LDAPURL;
+import org.opends.server.types.SearchFilter;
+
+/**
+ * A class representing an ACI target keyword.
+ */
+public class Target
+{
+    private EnumTargetOperator operator = EnumTargetOperator.EQUALITY;
+    private LDAPURL targetURL = null;
+    private DN urlDN=null;
+    private boolean isPattern=false;
+    private SearchFilter filter=null;
+    private AttributeType targetType;
+
+
+      /*
+     * TODO Save aciDN parameter and use it in matchesPattern re-write.
+     *
+     * Should the aciDN argument provided to the constructor be stored so that
+     * it can be used in the matchesPattern() method?  The DN should only be
+     * considered a potential match if it is at or below the entry containing
+     * the ACI.
+     *
+     * TODO Evaluate re-writing pattern (substring) determination code. The
+     * current code is similar to current DS6 implementation.
+     *
+     * I'm confused by the part of the constructor that generates a search
+     * filter. First, there is no substring matching rule defined for the
+     * DN syntax in the official standard, so technically trying to perform
+     * substring matching against DNs is illegal.  Although we do try to use
+     * the caseIgnoreSubstringsMatch rule, it is extremely unreliable for DNs
+     * because it's just not possible to do substring matching correctly in all
+     * cases for them.  Also, the logic in place there will only generate a
+     * filter if the DN contains a wildcard, and if it starts with a wildcard
+     * (which is handled by the targetDN.startsWith("*") clause), then you'll
+     * end up with something like "(target=**dc=example,dc=com)", which isn't
+     *  legal.
+     */
+    /**
+     * This constructor parses the target string.
+     * @param operator  An enumeration of the operation of this target.
+     * @param target A string representation of the target.
+     * @param aciDN The dn of the ACI entry used for a descendant check.
+     * @throws AciException If the target string is invalid.
+     */
+    private Target(EnumTargetOperator operator, String target, DN aciDN)
+            throws AciException {
+        this.operator = operator;
+        try {
+          String ldapURLRegex = "\\s*(ldap:///[^\\|]+)";
+          if (!Pattern.matches(ldapURLRegex, target)) {
+              int msgID = MSGID_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION;
+              String message = getMessage(msgID, target);
+              throw new AciException(msgID, message);
+          }
+          targetURL =  LDAPURL.decode(target, false);
+          urlDN=targetURL.getBaseDN();
+          String targetDN=urlDN.toNormalizedString();
+          if((targetDN.startsWith("*")) ||
+             (targetDN.indexOf("*") != -1)) {
+              this.isPattern=true;
+              String pattern="target=*"+targetDN;
+              filter=SearchFilter.createFilterFromString(pattern);
+              targetType = DirectoryServer.getAttributeType("target");
+              if (targetType == null)
+                  targetType =
+                          DirectoryServer.getDefaultAttributeType("target");
+          } else {
+              if(!urlDN.isDescendantOf(aciDN)) {
+                  int msgID = MSGID_ACI_SYNTAX_TARGET_DN_NOT_DESCENDENTOF;
+                  String message = getMessage(msgID,
+                                              urlDN.toNormalizedString(),
+                                              aciDN.toNormalizedString());
+                  throw new AciException(msgID, message);
+              }
+          }
+        }
+        catch (DirectoryException e){
+            int msgID = MSGID_ACI_SYNTAX_INVALID_TARGETKEYWORD_EXPRESSION;
+            String message = getMessage(msgID, target);
+            throw new AciException(msgID, message);
+        }
+    }
+
+    /**
+     *  Decode an expression string representing a target keyword expression.
+     * @param operator  An enumeration of the operation of this target.
+     * @param expr A string representation of the target.
+     * @param aciDN  The DN of the ACI entry used for a descendant check.
+     * @return  A Target class representing this target.
+     * @throws AciException  If the expression string is invalid.
+     */
+    public static Target decode(EnumTargetOperator operator,
+                                String expr, DN aciDN)
+            throws AciException {
+        return new Target(operator, expr, aciDN);
+    }
+
+    /**
+     * Returns the operator of this expression.
+     * @return An enumeration of the operation value.
+     */
+    public EnumTargetOperator getOperator() {
+        return operator;
+    }
+
+    /**
+     * Returns the URL DN of the expression.
+     * @return A DN of the URL.
+     */
+    public DN getDN() {
+        return urlDN;
+    }
+
+    /**
+     * Returns boolean if a pattern was seen during parsing.
+     * @return  True if the DN is a wild-card.
+     */
+    public boolean isPattern() {
+        return isPattern;
+    }
+
+    /*
+     * TODO Evaluate re-writing this method.
+     *
+     * The matchesPattern() method really needs to be rewritten.  It's using a
+     * very inefficient and very error-prone method to make the determination.
+     * If you're really going to attempt pattern matching on a DN, then I'd
+     * suggest trying a regular expression against the normalized DN rather
+     * than a filter.
+     */
+    /**
+     * This method tries to match a pattern against a DN. It builds an entry
+     * with a target attribute containing the pattern and then matches against
+     * it.
+     * @param dn  The DN to try an match.
+     * @return True if the pattern matches.
+     */
+    public boolean matchesPattern(DN dn) {
+        boolean ret;
+        String targetDN=dn.toNormalizedString();
+        LinkedHashSet<AttributeValue> values =
+            new LinkedHashSet<AttributeValue>();
+        values.add(new AttributeValue(targetType, targetDN));
+        Attribute attr = new Attribute(targetType, "target", values);
+        Entry e = new Entry(DN.nullDN(), null, null, null);
+        e.addAttribute(attr,new ArrayList<AttributeValue>());
+        try {
+            ret=filter.matchesEntry(e);
+        } catch (DirectoryException ex) {
+            //TODO information message?
+            return false;
+        }
+        return  ret;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java
new file mode 100644
index 0000000..6cb7db8
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java
@@ -0,0 +1,187 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.util.HashSet;
+import java.util.regex.Pattern;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.AttributeType;
+
+/**
+ * A class representing an ACI's targetattr keyword.
+ */
+public class TargetAttr {
+    private EnumTargetOperator operator = EnumTargetOperator.EQUALITY;
+    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*)*";
+
+    /**
+     * Constructor creating a class representing a targetattr keyword of an ACI.
+     * @param operator The operation enumeration of the targetattr
+     * expression (=, !=).
+     * @param attrString A string representing the attributes specified in
+     * the targetattr expression (ie, dn || cn).
+     * @throws AciException If the attrs string is invalid.
+     */
+    private TargetAttr(EnumTargetOperator operator, String attrString)
+    throws AciException {
+        this.operator = operator;
+        if (attrString != null) {
+            if (Pattern.matches(allAttrsRegex, attrString) ){
+                allAttributes = true ;
+            } else {
+                if (Pattern.matches(noAttrsRegex, 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", "");
+                        String[] attributeArray=
+                             separatorPattern.split(attrString);
+                        //Add each element of array to attributes HashSet
+                        //after converting it to AttributeType.
+                        arrayToAttributeTypes(attributeArray);
+                    } else {
+                      int msgID =
+                         MSGID_ACI_SYNTAX_INVALID_TARGETATTRKEYWORD_EXPRESSION;
+                      String message = getMessage(msgID, operator);
+                      throw new AciException(msgID, message);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Converts each element of an array of attribute type strings
+     * to attribute types and adds them to the attributes HashSet.
+     * @param attributeArray The array of attribute type strings.
+     */
+    private void arrayToAttributeTypes(String[] attributeArray) {
+        for (int i=0, n=attributeArray.length; i < n; i++) {
+            String attribute=attributeArray[i].toLowerCase();
+            AttributeType attributeType;
+            if((attributeType =
+                DirectoryServer.getAttributeType(attribute)) == null)
+                attributeType =
+                    DirectoryServer.getDefaultAttributeType(attribute);
+            attributes.add(attributeType);
+        }
+    }
+    /**
+     * Returns the operator enumeration of the targetattr expression.
+     * @return The operator enumeration.
+     */
+    public EnumTargetOperator getOperator() {
+        return operator;
+    }
+
+    /**
+     * This flag is set if the parsing code saw:
+     * targetattr="*" or targetattr != "*".
+     * @return True if all attributes was seen.
+     */
+    public boolean isAllAttributes() {
+        return allAttributes;
+    }
+
+    /**
+     * Return array holding each attribute type to be evaluated
+     * in the expression.
+     * @return Array holding each attribute types.
+     */
+    public HashSet<AttributeType> getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * Decodes an targetattr expression string into a targetattr class suitable
+     * for evaluation.
+     * @param operator The operator enumeration of the expression.
+     * @param expr The expression string to be decoded.
+     * @return A TargetAttr suitable to evaluate this ACI's targetattrs.
+     * @throws AciException If the expression string is invalid.
+     */
+    public static TargetAttr decode(EnumTargetOperator operator, String expr)
+            throws AciException  {
+        return new TargetAttr(operator, expr);
+    }
+
+    /**
+     * Perform two checks to see if a specified attribute type is applicable.
+     * First, check the targetAttr's isAllAttributes() boolean. The
+     * isAllAttributes boolean is set true when the string:
+     *
+     *       targetattrs="*"
+     *
+     * is  seen when an ACI is parsed. If the isAllAttributes boolean is
+     * true, the second check is skipped and the TargetAttr's operator is
+     * checked to see if the method should return false (NOT_EQUALITY)
+     * instead of true.
+     *
+     * If the isAllAttributes boolean is false, then the TargeAttr's
+     * attribute type HashSet is searched to see if it contains the
+     * specified attribute type. That result could be negated depending
+     * on if the TargetAttr's operator is NOT_EQUALITY.
+     *
+     * @param a The attribute type to evaluate.
+     * @param targetAttr The ACI's TargetAttr class to evaluate against.
+     * @return The boolean result of the above tests and application
+     * TargetAttr's operator value applied to the test result.
+     */
+    public static boolean isApplicable(AttributeType a,
+                          TargetAttr targetAttr) {
+      boolean ret;
+      if(targetAttr.isAllAttributes()) {
+          ret =
+             !targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY);
+      }  else {
+          ret=false;
+          HashSet<AttributeType> attributes=targetAttr.getAttributes();
+          if(attributes.contains(a))
+              ret=true;
+          if(targetAttr.getOperator().equals(EnumTargetOperator.NOT_EQUALITY))
+              ret = !ret;
+      }
+      return ret;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetFilter.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetFilter.java
new file mode 100644
index 0000000..14cf8a4
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetFilter.java
@@ -0,0 +1,103 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.SearchFilter;
+
+/**
+ * This class represents a targetfilter keyword of an aci.
+ *
+ */
+public class TargetFilter {
+    private EnumTargetOperator op = EnumTargetOperator.EQUALITY;
+    private SearchFilter filter;
+
+    /**
+     * Class representing a targetfilter keyword.
+     * @param op The operation of the targetfilter expression (=, !=)
+     * @param filter The filter itself.
+     */
+    private TargetFilter(EnumTargetOperator op, SearchFilter filter) {
+        this.op=op;
+        this.filter=filter;
+    }
+
+    /**
+     * Decode a aci's targetfilter string.
+     * @param op The operation enumeration of the expression.
+     * @param expr A string representing the target filter.
+     * @return A TargetFilter class suitable for using in a match.
+     * @throws AciException If the expression string is invalid.
+     */
+    public static TargetFilter decode(EnumTargetOperator op, String expr)
+    throws AciException {
+        SearchFilter filter;
+        try {
+            filter = SearchFilter.createFilterFromString(expr);
+        } catch (DirectoryException ex) {
+            int msgID =
+                MSGID_ACI_SYNTAX_INVALID_TARGETFILTERKEYWORD_EXPRESSION;
+            String message = getMessage(msgID, expr);
+            throw new AciException(msgID, message);
+        }
+        return new TargetFilter(op, filter);
+    }
+
+    /**
+     * Checks if a targetfilter matches an evaluation context.
+     * @param matchCtx The evaluation context to use in the matching.
+     * @return True if the target filter matched the context.
+     */
+    public boolean isApplicable(AciTargetMatchContext matchCtx) {
+        boolean ret;
+        ret=matchesFilter(matchCtx.getResourceEntry());
+        if(op.equals(EnumTargetOperator.NOT_EQUALITY))
+            ret = !ret;
+        return ret;
+    }
+
+    /**
+     * Checks the filter against an entry taken from the match context.
+     * @param e The entry from the evaluation context above.
+     * @return True if the filter matches the entry.
+     */
+    private boolean matchesFilter(Entry e) {
+        boolean ret;
+        try {
+            ret=filter.matchesEntry(e);
+        } catch (DirectoryException ex) {
+            //TODO information message?
+            return false;
+        }
+        return ret;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java
new file mode 100644
index 0000000..f96f484
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TimeOfDay.java
@@ -0,0 +1,121 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import org.opends.server.util.TimeThread;
+import java.util.regex.Pattern;
+
+/**
+ * This class represents the timeofday keyword in a bind rule.
+ */
+public class TimeOfDay implements KeywordBindRule {
+    private static final String timeofdayRegex = "[0-2]\\d[0-5]\\d";
+    private EnumBindRuleType type=null;
+    private int timeRef;
+
+    /**
+     * Constructor to create a timeofday keyword class.
+     * @param timeVal The time value to check for (0-2359).
+     * @param type An enumeration of the type of the expression.
+     */
+    private TimeOfDay(int timeVal, EnumBindRuleType type) {
+        this.timeRef=timeVal;
+        this.type=type;
+    }
+
+    /**
+     * Decodes a string representation of a timeofday bind rule expression.
+     * @param expr A string representation of the expression.
+     * @param type An enumeration of the type of the expression.
+     * @return  A TimeOfDay class representing the expression.
+     * @throws AciException If the expression is invalid.
+     */
+    public static TimeOfDay decode(String expr,  EnumBindRuleType type)
+    throws AciException  {
+        if (!Pattern.matches(timeofdayRegex, expr))
+        {
+            int msgID = MSGID_ACI_SYNTAX_INVALID_TIMEOFDAY;
+            String message = getMessage(msgID,expr);
+            throw new AciException(msgID, message);
+         }
+        int valueAsInt = Integer.parseInt(expr);
+        if ((valueAsInt < 0) || (valueAsInt > 2359))
+        {
+            int msgID = MSGID_ACI_SYNTAX_INVALID_TIMEOFDAY_RANGE;
+            String message = getMessage(msgID,expr);
+            throw new AciException(msgID, message);
+        }
+
+        return new TimeOfDay(valueAsInt, type);
+    }
+
+    /**
+     * Evaluates the timeofday bind rule using the evaluation context
+     * passed into the method.
+     * @param evalCtx  The evaluation context to use for the evaluation.
+     * @return  An enumeration result representing the result of the
+     * evaluation.
+     */
+    public EnumEvalResult evaluate(AciEvalContext evalCtx) {
+        EnumEvalResult matched=EnumEvalResult.FALSE;
+
+        int currentTime=TimeThread.getHourAndMinute();
+        //check the type
+        switch (type) {
+        case LESS_OR_EQUAL_BINDRULE_TYPE:
+            if (currentTime <= timeRef)
+            {
+                matched=EnumEvalResult.TRUE;
+            }
+            break;
+
+        case LESS_BINDRULE_TYPE:
+            if (currentTime < timeRef)
+            {
+                matched=EnumEvalResult.TRUE;
+            }
+            break;
+
+        case GREATER_OR_EQUAL_BINDRULE_TYPE:
+            if (currentTime >= timeRef)
+            {
+                matched=EnumEvalResult.TRUE;
+            }
+            break;
+
+        case GREATER_BINDRULE_TYPE:
+            if (currentTime > timeRef)
+            {
+                matched=EnumEvalResult.TRUE;
+            }
+        }
+        return matched.getRet(type, false);
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
new file mode 100644
index 0000000..7d409e7
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
@@ -0,0 +1,388 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.protocols.internal.InternalSearchOperation;
+import org.opends.server.types.*;
+/*
+ * TODO Evaluate making this class more efficient.
+ *
+ * This class isn't as efficient as it could be.  For example, the evalVAL()
+ * method should be able to use cached versions of the attribute type and
+ * filter. The evalURL() and evalDN() methods should also be able to use a
+ * cached version of the attribute type.
+ */
+/**
+ * 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 {
+        USERDN, GROUPDN, ROLEDN, URL, VALUE
+    }
+    private  static String f="objectclass=*";
+    private  String attrStr=null;
+    private  String attrVal=null;
+    private UserAttrType userAttrType=null;
+    private EnumBindRuleType type=null;
+    private ParentInheritance parentInheritance=null;
+
+    /**
+     * Create an non-USERDN/GROUPDN instance of the userattr keyword class.
+     * @param attrStr The attribute name in string form. Kept in string form
+     * until processing.
+     * @param attrVal The attribute value in string form -- used in the USERDN
+     * evaluation for the parent hierarchy expression.
+     * @param userAttrType The userattr type of the rule
+     * "USERDN, GROUPDN, ...".
+     * @param type The bind rule type "=, !=".
+     */
+    private UserAttr(String attrStr, String attrVal, UserAttrType userAttrType,
+            EnumBindRuleType type) {
+        this.attrStr=attrStr;
+        this.attrVal=attrVal;
+        this.userAttrType=userAttrType;
+        this.type=type;
+    }
+
+    /**
+     * Create an USERDN or GROUPDN  instance of the userattr keyword class.
+     * @param userAttrType The userattr type of the rule (USERDN or GROUPDN)
+     * only.
+     * @param type The bind rule type "=, !=".
+     * @param parentInheritance The parent inheritance class to use for parent
+     * inheritance checks if any.
+     */
+    private UserAttr(UserAttrType userAttrType, EnumBindRuleType type,
+                     ParentInheritance parentInheritance) {
+        this.userAttrType=userAttrType;
+        this.type=type;
+        this.parentInheritance=parentInheritance;
+    }
+    /**
+     * Decode an string containing the userattr bind rule expression.
+     * @param expression The expression string.
+     * @param type The bind rule type.
+     * @return A class suitable for evaluating a userattr bind rule.
+     * @throws AciException If the string contains an invalid expression.
+     */
+    public static KeywordBindRule decode(String expression,
+                                         EnumBindRuleType type)
+    throws AciException {
+        String[] vals=expression.split("#");
+        if(vals.length != 2) {
+            int msgID = MSGID_ACI_SYNTAX_INVALID_USERATTR_EXPRESSION;
+            String message = getMessage(msgID, expression);
+            throw new AciException(msgID, message);
+        }
+        UserAttrType userAttrType=getType(vals[1]);
+        switch (userAttrType) {
+                case GROUPDN:
+                case USERDN: {
+                    ParentInheritance parentInheritance =
+                            new ParentInheritance(vals[0], false);
+                    return new UserAttr (userAttrType, type, parentInheritance);
+                }
+                case ROLEDN: {
+                    //Even though parent inheritance is invalid for the ROLEDN
+                    //keyword, we are going to up a simple parent inheritance
+                    //class so that most of the evaluate methods in this class
+                    //can be re-used. The true boolean means to skip parsing,
+                    //except for a quick validation parse.
+                    ParentInheritance parentInheritance =
+                            new ParentInheritance(vals[0], true);
+                     return new UserAttr(userAttrType, type, parentInheritance);
+                }
+         }
+         return new UserAttr(vals[0], vals[1], userAttrType, type);
+    }
+
+    /**
+     * Evaluate the expression using an evaluation context.
+     * @param evalCtx   The evaluation context to use in the evaluation of the
+     * userattr expression.
+     * @return  An enumeration containing the result of the evaluation.
+     */
+    public EnumEvalResult evaluate(AciEvalContext evalCtx) {
+        EnumEvalResult matched;
+        boolean undefined=false;
+
+        switch(userAttrType) {
+        case ROLEDN:
+        case GROUPDN:
+        case USERDN: {
+            matched=evalDNKeywords(evalCtx);
+            break;
+        }
+        case URL: {
+            matched=evalURL(evalCtx);
+            break;
+        }
+        default:
+            matched=evalVAL(evalCtx);
+        }
+        if(matched == EnumEvalResult.ERR)
+            undefined=true;
+        return matched.getRet(type, undefined);
+    }
+
+    /** Evaluate a VALUE userattr type. Look in client entry for an
+     *  attribute value and in the resource entry for the same
+     *  value. If both entries have the same value than return true.
+     * @param evalCtx The evaluation context to use.
+     * @return An enumeration containing the result of the
+     * evaluation.
+     */
+    private EnumEvalResult evalVAL(AciEvalContext evalCtx) {
+        EnumEvalResult matched= EnumEvalResult.FALSE;
+        boolean undefined=false;
+        AttributeType attrType;
+        if((attrType = DirectoryServer.getAttributeType(attrStr)) == null)
+            attrType = DirectoryServer.getDefaultAttributeType(attrStr);
+        try {
+            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;
+                }
+            }
+        } catch (DirectoryException ex) {
+            undefined = true;
+            matched = EnumEvalResult.ERR;
+        }
+        return matched.getRet(type, undefined);
+    }
+
+    /**
+     * Parses the substring after the '#' character to determine the userattr
+     * type.
+     * @param expr The string with the substring.
+     * @return An enumeration containing the type.
+     * @throws AciException If the substring contains an invalid type (roledn
+     * or groupdn).
+     */
+    private static UserAttrType getType(String expr) throws AciException {
+        UserAttrType userAttrType;
+        if(expr.equalsIgnoreCase("userdn"))
+            userAttrType=UserAttrType.USERDN;
+        else if(expr.equalsIgnoreCase("groupdn")) {
+             userAttrType=UserAttrType.GROUPDN;
+      /*
+            int msgID = MSGID_ACI_SYNTAX_INVALID_USERATTR_KEYWORD;
+            String message = getMessage(msgID, "The groupdn userattr" +
+                    "keyword is not supported.");
+            throw new AciException(msgID, message);
+        */
+        } else if(expr.equalsIgnoreCase("roledn")) {
+            userAttrType=UserAttrType.ROLEDN;
+            /*
+            int msgID = MSGID_ACI_SYNTAX_INVALID_USERATTR_KEYWORD;
+            String message = getMessage(msgID, "The roledn userattr" +
+                    "keyword is not supported.");
+            throw new AciException(msgID, message);
+            */
+        } else if(expr.equalsIgnoreCase("ldapurl"))
+            userAttrType=UserAttrType.URL;
+        else
+            userAttrType=UserAttrType.VALUE;
+        return userAttrType;
+    }
+
+    /**
+     * Evaluate an URL userattr type. Look into the resource entry for the
+     * specified attribute and values. Assume it is an URL. Decode it an try
+     * and match it against the client entry attribute.
+     * @param evalCtx  The evaluation context to evaluate with.
+     * @return An enumeration containing a result of the URL evaluation.
+     */
+    private EnumEvalResult evalURL(AciEvalContext evalCtx) {
+        EnumEvalResult matched= EnumEvalResult.FALSE;
+        boolean undefined=false;
+        AttributeType attrType;
+        if((attrType = DirectoryServer.getAttributeType(attrStr)) == null)
+            attrType = DirectoryServer.getDefaultAttributeType(attrStr);
+        List<Attribute> attrs=evalCtx.getResourceEntry().getAttribute(attrType);
+        if(!attrs.isEmpty()) {
+            for(Attribute a : attrs) {
+                LinkedHashSet<AttributeValue> vals=a.getValues();
+                for(AttributeValue v : vals) {
+                    String urlStr=v.getStringValue();
+                    LDAPURL url;
+                    try {
+                       url=LDAPURL.decode(urlStr, true);
+                    } catch (DirectoryException e) {
+                        break;
+                    }
+                    matched=UserDN.evalURL(evalCtx, url);
+                    if(matched != EnumEvalResult.FALSE)
+                        break;
+                }
+                if(matched == EnumEvalResult.TRUE)
+                    break;
+                if(matched == EnumEvalResult.ERR) {
+                    undefined=true;
+                    break;
+                }
+            }
+        }
+        return matched.getRet(type, undefined);
+    }
+
+    /**
+     * Evaluate the DN type userattr keywords. These are roledn, userdn and
+     * groupdn. The processing is the same for all three, although roledn is
+     * a slightly different. For the roledn userattr keyword, a very simple
+     * parent inheritance class was created. The rest of the processing is the
+     * same for all three keywords.
+     *
+     * @param evalCtx The evaluation context to evaluate with.
+     * @return An enumeration containing a result of the USERDN evaluation.
+     */
+    private EnumEvalResult evalDNKeywords(AciEvalContext evalCtx) {
+        EnumEvalResult matched= EnumEvalResult.FALSE;
+        boolean undefined=false, stop=false;
+        int numLevels=parentInheritance.getNumLevels();
+        int[] levels=parentInheritance.getLevels();
+        AttributeType attrType=parentInheritance.getAttributeType();
+        for(int i=0;((i < numLevels) && !stop); i++ ) {
+            //The ROLEDN keyword will always enter this statement. The others
+            //might. For the add operation, the resource itself (level 0)
+            //must never be allowed to give access.
+            if(levels[i] == 0) {
+                if(evalCtx.isAddOperation()) {
+                    undefined=true;
+                } else if (evalCtx.getResourceEntry().hasAttribute(attrType)) {
+                    matched =
+                        evalEntryAttr(evalCtx.getResourceEntry(),
+                                evalCtx,attrType);
+                   if(matched.equals(EnumEvalResult.TRUE))
+                        stop=true;
+                }
+            } else {
+                try {
+                    DN pDN=
+                        getDNParentLevel(levels[i], evalCtx.getResourceDN());
+                    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 =
+                        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;
+                        }
+                    }
+                } catch (DirectoryException ex) {
+                    undefined=true;
+                    stop=true;
+                    matched=EnumEvalResult.ERR;
+                }
+            }
+        }
+        return matched.getRet(type, undefined);
+    }
+
+    /**
+     * This method returns a parent DN based on the level. Not very
+     * sophisticated but it works.
+     * @param l The level.
+     * @param dn The DN to get the parent of.
+     * @return Parent DN based on the level or null if the level is greater
+     * than the  rdn count.
+     */
+    private DN getDNParentLevel(int l, DN dn) {
+        int rdns=dn.getNumComponents();
+        if(l > rdns)
+            return null;
+        DN theDN=dn;
+        for(int i=0; i < l;i++) {
+            theDN=theDN.getParent();
+        }
+        return theDN;
+    }
+
+
+    /**
+     * This method evaluates the user attribute type and calls the correct
+     * evalaution method. The three user attribute types that can be selected
+     * are ROLEDN, USERDN or GROUPDN.
+     * @param e The entry to use in the evaluation.
+     * @param evalCtx The evaluation context to use in the evaluation.
+     * @param attributeType The attribute type to use in the evaluation.
+     * @return The result of the evaluation routine.
+     */
+    private EnumEvalResult evalEntryAttr(Entry e, AciEvalContext evalCtx,
+                                         AttributeType attributeType) {
+        EnumEvalResult result=EnumEvalResult.FALSE;
+        switch (userAttrType) {
+            case USERDN: {
+                result=UserDN.evaluate(e, evalCtx.getClientDN(),
+                                       attributeType);
+                break;
+            }
+            case ROLEDN:
+                result=RoleDN.evaluate(e, evalCtx, attributeType);
+                break;
+            case GROUPDN: {
+                result=GroupDN.evaluate(e, evalCtx, attributeType);
+                break;
+            }
+        }
+        return result;
+    }
+
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java
new file mode 100644
index 0000000..49da707
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserDN.java
@@ -0,0 +1,385 @@
+/*
+ * 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 static org.opends.server.authorization.dseecompat.AciMessages.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
+
+import java.util.*;
+import org.opends.server.types.*;
+import org.opends.server.core.DirectoryServer;
+
+/**
+ * This class represents the userdn keyword in a bind rule.
+ */
+public class UserDN implements KeywordBindRule {
+    /*
+     * A dummy URL for invalid URLs such as: all, parent, anyone, self.
+     */
+    private static String urlStr="ldap:///";
+
+    /**
+     * This list holds a list of objects representing a EnumUserDNType
+     * URL mapping.
+     */
+    List<UserDNTypeURL> urlList=null;
+    private EnumBindRuleType type=null;
+    private AttributeType userDNAttrType;
+    /**
+     * Constructor that creates the userdn class. It also sets up an attribute
+     * type ("userdn") needed  for wild-card matching.
+     * @param type The type of  operation.
+     * @param urlList  A list of enumerations containing the URL type and URL
+     * object that can be retrieved at evaluation time.
+     */
+    private UserDN(EnumBindRuleType type, List<UserDNTypeURL> urlList) {
+       this.type=type;
+       this.urlList=urlList;
+       userDNAttrType = DirectoryServer.getAttributeType("userdn");
+       if (userDNAttrType == null)
+          userDNAttrType = DirectoryServer.getDefaultAttributeType("userdn");
+    }
+
+    /**
+     * Decodes an expression string representing a userdn bind rule.
+     * @param expression The string representation of the userdn bind rule
+     * expression.
+     * @param type An enumeration of the type of the bind rule.
+     * @return A KeywordBindRule class that represents the bind rule.
+     * @throws AciException If the expression failed to LDAP URL decode.
+     */
+    public static KeywordBindRule decode(String expression,
+            EnumBindRuleType type) throws AciException {
+
+        String[] vals=expression.split("[|][|]");
+        List<UserDNTypeURL> urlList = new LinkedList<UserDNTypeURL>();
+         for(int i=0, m=vals.length; i < m; i++)
+        {
+            StringBuilder value = new StringBuilder(vals[i].trim());
+           /*
+            * TODO Evaluate using a wild-card in the dn portion of LDAP url.
+            * The current implementation (DS6) does not treat a "*"
+            * as a wild-card.
+            *
+            * Is it allowed to have a full LDAP URL (i.e., including a base,
+            * scope, and filter) in which the base DN contains asterisks to
+            * make it a wildcard?  If so, then I don't think that the current
+            * implementation handles that correctly.  It will probably fail
+            * when attempting to create the LDAP URL because the base DN isn't a
+            * valid DN.
+            */
+            EnumUserDNType userDNType = UserDN.getType(value);
+            LDAPURL url;
+            try {
+               url=LDAPURL.decode(value.toString(), true);
+            } catch (DirectoryException de) {
+                int msgID = MSGID_ACI_SYNTAX_INVALID_USERDN_URL;
+                String message = getMessage(msgID, de.getErrorMessage());
+                throw new AciException(msgID, message);
+            }
+            UserDNTypeURL dnTypeURL=new UserDNTypeURL(userDNType, url);
+            urlList.add(dnTypeURL);
+        }
+        return new UserDN(type, urlList);
+      }
+
+    /**
+     * This method determines the type of the DN (suffix in URL terms)
+     * part of a URL, by examining the full URL itself for known strings
+     * such as (corresponding type shown in parenthesis)
+     *
+     *      "ldap:///anyone"    (EnumUserDNType.ANYONE)
+     *      "ldap:///parent"    (EnumUserDNType.PARENT)
+     *      "ldap:///all"       (EnumUserDNType.ALL)
+     *      "ldap:///self"      (EnumUserDNType.SELF)
+     *
+     * If one of the four above are found, the URL is replaced with a dummy
+     * pattern "ldap:///". This is done because the above four are invalid
+     * URLs; but the syntax is valid for an userdn keyword expression. The
+     * dummy URLs are never used.
+     *
+     * If none of the above are found, it determine if the URL DN is a
+     * substring pattern, such as:
+     *
+     *      "ldap:///uid=*, dc=example, dc=com" (EnumUserDNType.PATTERN)
+     *
+     * If none of the above are determined, it checks if the URL
+     * is a complete URL with scope and filter defined:
+     *
+     *  "ldap:///uid=test,dc=example,dc=com??sub?(cn=j*)"  (EnumUserDNType.URL)
+     *
+     * If none of these those types can be identified, it defaults to
+     * EnumUserDNType.DN.
+     *
+     * @param bldr A string representation of the URL that can be modified.
+     * @return  The user DN type of the URL.
+     */
+    private static EnumUserDNType getType(StringBuilder bldr) {
+        EnumUserDNType type;
+        String str=bldr.toString();
+
+        if(str.indexOf("?") != -1) {
+            type = EnumUserDNType.URL;
+        } else  if(str.equalsIgnoreCase("ldap:///self")) {
+            type = EnumUserDNType.SELF;
+            bldr.replace(0, bldr.length(), urlStr);
+        } else if(str.equalsIgnoreCase("ldap:///anyone")) {
+            type = EnumUserDNType.ANYONE;
+            bldr.replace(0, bldr.length(), urlStr);
+        } else if(str.equalsIgnoreCase("ldap:///parent")) {
+            type = EnumUserDNType.PARENT;
+            bldr.replace(0, bldr.length(), urlStr);
+        } else if(str.equalsIgnoreCase("ldap:///all")) {
+            type = EnumUserDNType.ALL;
+            bldr.replace(0, bldr.length(), urlStr);
+        } else if(str.indexOf("*") != -1) {
+            type = EnumUserDNType.DNPATTERN;
+        } else {
+            type = EnumUserDNType.DN;
+        }
+        return type;
+    }
+
+    /**
+     * Performs the evaluation of a userdn bind rule based on the
+     * evaluation context passed to it. The evaluation stops when there
+     * are no more UserDNTypeURLs to evaluate or if an UserDNTypeURL
+     * evaluates to true.
+     * @param evalCtx The evaluation context to evaluate with.
+     * @return  An evaluation result enumeration containing the result
+     * of the evaluation.
+     */
+    public EnumEvalResult evaluate(AciEvalContext evalCtx) {
+        EnumEvalResult matched = EnumEvalResult.FALSE;
+        boolean undefined=false;
+
+        boolean isAnonUser=evalCtx.isAnonymousUser();
+        Iterator<UserDNTypeURL> it=urlList.iterator();
+        for(; it.hasNext() && matched != EnumEvalResult.TRUE &&
+                matched != EnumEvalResult.ERR;) {
+            UserDNTypeURL dnTypeURL=it.next();
+            //Handle anonymous checks here
+            if(isAnonUser) {
+                if(dnTypeURL.getUserDNType() == EnumUserDNType.ANYONE)
+                    matched = EnumEvalResult.TRUE;
+            }  else
+                matched=evalNonAnonymous(evalCtx, dnTypeURL);
+        }
+        return matched.getRet(type, undefined);
+    }
+
+    /**
+     * Performs an evaluation of a single UserDNTypeURL of a userdn bind
+     * rule using the evaluation context provided. This method is called
+     * for the non-anonymous user case.
+     * @param evalCtx  The evaluation context to evaluate with.
+     * @param dnTypeURL The URL dn type mapping to evaluate.
+     * @return An evaluation result enumeration containing the result
+     * of the evaluation.
+     */
+    private EnumEvalResult evalNonAnonymous(AciEvalContext evalCtx,
+                                            UserDNTypeURL dnTypeURL) {
+        DN clientDN=evalCtx.getClientDN();
+        DN resDN=evalCtx.getResourceDN();
+        EnumEvalResult matched = EnumEvalResult.FALSE;
+        EnumUserDNType type=dnTypeURL.getUserDNType();
+        LDAPURL url=dnTypeURL.getURL();
+        switch (type) {
+            case URL:
+            {
+                matched = evalURL(evalCtx, url);
+                break;
+            }
+            case ANYONE:
+            {
+                matched = EnumEvalResult.TRUE;
+                break;
+            }
+            case SELF:
+            {
+                if (clientDN.equals(resDN)) matched = EnumEvalResult.TRUE;
+                break;
+            }
+            case PARENT:
+            {
+                DN parentDN = resDN.getParent();
+                if ((parentDN != null) &&
+                        (parentDN.equals(clientDN)))
+                    matched = EnumEvalResult.TRUE;
+                break;
+            }
+            case ALL:
+            {
+                matched = EnumEvalResult.TRUE;
+                break;
+            }
+            case DNPATTERN:
+            {
+                matched = evalDNPattern(evalCtx, url);
+                break;
+            }
+            case DN:
+            {
+                try
+                {
+                    DN dn = url.getBaseDN();
+                    if (clientDN.equals(dn))
+                        matched = EnumEvalResult.TRUE;
+                } catch (DirectoryException ex) {
+                    //TODO add message
+                }
+            }
+        }
+        return matched;
+    }
+
+    /*
+     * TODO Evaluate making this more efficient.
+     *
+     * The evalDNPattern() method looks like it suffers from the
+     * same problem as the matchesPattern() method in the Target
+     * class.  Creating a dummy entry and attempting to do substring
+     * matching on a DN is a pretty expensive and error-prone approach.
+     * Using a regular expression would likely be much more efficient and
+     *  should be simpler.
+     */
+    /**
+     * This method evaluates a DN pattern userdn expression. It creates a
+     * dummy entry and a substring filter and applies the filter to the
+     * entry.
+     * @param evalCtx  The evaluation context to use.
+     * @param url The LDAP URL containing the pattern.
+     * @return An enumeration evaluation result.
+     */
+    private EnumEvalResult evalDNPattern(AciEvalContext evalCtx, LDAPURL url) {
+        boolean rc;
+        EnumEvalResult ret=EnumEvalResult.TRUE;
+        String urlDN;
+        SearchFilter filter;
+        try {
+            urlDN=url.getBaseDN().toNormalizedString();
+            String pattern="userdn="+urlDN;
+            filter=SearchFilter.createFilterFromString(pattern);
+        } catch (DirectoryException ex) {
+            return EnumEvalResult.FALSE;
+        }
+        LinkedHashSet<AttributeValue> vals =
+                new LinkedHashSet<AttributeValue>();
+        String userDNStr=evalCtx.getClientDN().toNormalizedString();
+        vals.add(new AttributeValue(userDNAttrType, userDNStr));
+        Attribute attr = new Attribute(userDNAttrType, "userdn", vals);
+        Entry e = new Entry(DN.nullDN(), null, null, null);
+        e.addAttribute(attr,new ArrayList<AttributeValue>());
+        try {
+            rc=filter.matchesEntry(e);
+        } catch (DirectoryException ex) {
+            return EnumEvalResult.FALSE;
+        }
+        if(!rc)
+            ret=EnumEvalResult.FALSE;
+        return ret;
+    }
+
+
+    /**
+     * This method evaluates an URL userdn expression. Something like:
+     * ldap:///suffix??sub?(filter). It also searches for the client DN
+     * entry and saves it in the evaluation context for repeat evaluations
+     * that might come later in processing.
+     *
+     * @param evalCtx  The evaluation context to use.
+     * @param url URL containing the URL to use in the evaluation.
+     * @return An enumeration of the evaluation result.
+     */
+    public static EnumEvalResult evalURL(AciEvalContext evalCtx, LDAPURL url) {
+        EnumEvalResult ret=EnumEvalResult.FALSE;
+        DN urlDN;
+        SearchFilter filter;
+        try {
+            urlDN=url.getBaseDN();
+            filter=url.getFilter();
+        } catch (DirectoryException ex) {
+            return EnumEvalResult.FALSE;
+        }
+        SearchScope scope=url.getScope();
+        if(scope == SearchScope.WHOLE_SUBTREE) {
+            if(!evalCtx.getClientDN().isDescendantOf(urlDN))
+                return EnumEvalResult.FALSE;
+        } else if(scope == SearchScope.SINGLE_LEVEL) {
+            DN parent=evalCtx.getClientDN().getParent();
+            if((parent != null) && !parent.equals(urlDN))
+                return EnumEvalResult.FALSE;
+        } else {
+            if(!evalCtx.getClientDN().equals(urlDN))
+                return EnumEvalResult.FALSE;
+        }
+        try {
+            if(filter.matchesEntry(evalCtx.getClientEntry()))
+                ret=EnumEvalResult.TRUE;
+        } catch (DirectoryException ex) {
+            return EnumEvalResult.FALSE;
+        }
+        return ret;
+    }
+
+    /*
+     * TODO Evaluate making this method more efficient.
+     *
+     * The evalDNEntryAttr method isn't as efficient as it could be.  It would
+     * probably be faster to to convert the clientDN to an AttributeValue and
+     * see if the entry has that value than to decode each value as a DN and
+     * see if it matches the clientDN.
+     */
+    /**
+     * This method searches an entry for an attribute value that is
+     * treated as a DN. That DN is then compared against the client
+     * DN.
+     * @param e The entry to get the attribute type from.
+     * @param clientDN The client authorization DN to check for.
+     * @param attrType The attribute type from the bind rule.
+     * @return An enumeration with the result.
+     */
+    public static EnumEvalResult evaluate(Entry e, DN clientDN,
+                                           AttributeType attrType) {
+        EnumEvalResult matched= EnumEvalResult.FALSE;
+        List<Attribute> attrs =  e.getAttribute(attrType);
+        LinkedHashSet<AttributeValue> vals = attrs.get(0).getValues();
+        for(AttributeValue v : vals) {
+            try {
+                DN dn=DN.decode(v.getStringValue());
+                if(dn.equals(clientDN)) {
+                    matched=EnumEvalResult.TRUE;
+                    break;
+                }
+            } catch (DirectoryException ex) {
+                break;
+            }
+        }
+        return matched;
+    }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserDNTypeURL.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserDNTypeURL.java
new file mode 100644
index 0000000..11ea4c7
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/UserDNTypeURL.java
@@ -0,0 +1,71 @@
+/*
+ * 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.LDAPURL;
+
+/**
+ * The UserDNTypeURL class contains the EnumUserDNType and the URL value,
+ * 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.
+     */
+    private LDAPURL url;
+
+    /**
+     * Create a class representing the "userdn" URL decoded by the
+     * UserDN.decode() method.
+     * @param dnType The type of the URL determined by examining the DN
+     * or suffix.
+     * @param url The URL itself from the ACI "userdn" string expression.
+     */
+    UserDNTypeURL(EnumUserDNType dnType, LDAPURL url) {
+        this.url=url;
+        this.dnType=dnType;
+    }
+
+    /**
+     * Returns the DN type.
+     * @return The DN type of the URL.
+     */
+    public EnumUserDNType getUserDNType() {
+        return this.dnType;
+    }
+
+    /** Returns the URL.
+     * @return The URL decoded by the UserDN.decode() method.
+     */
+    public LDAPURL getURL() {
+        return this.url;
+    }
+}

--
Gitblit v1.10.0