From 5e4ad386b7091fa5ee4ecbc33182a5493ab14177 Mon Sep 17 00:00:00 2001
From: dugan <dugan@localhost>
Date: Sat, 21 Jul 2007 00:56:42 +0000
Subject: [PATCH] Add the new ACI keyword  "targetcontrol"  that can be used to enforce access based on the OID of a control. For example, a new global access control rule is also being added: 

---
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/EnumTargetKeyword.java                                  |    7 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java         |    9 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java |   41 +
 opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java                                            |   35 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AlternateRootDN.java            |   16 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java                                                |   97 +++
 opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java                    |  286 +++-------
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetAttr.java                                         |    8 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java                                         |   55 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java                          |   20 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java                   |   58 +
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java                                         |   56 ++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetControl.java                                      |  101 +++
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java                              |    7 
 opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java                                                       |   14 
 opendj-sdk/opends/resource/config/config.ldif                                                                                   |   14 
 opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java                                       |   31 +
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java      |  342 +++++++++++++
 opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java                                                        |   66 ++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java                |  207 +++++++
 opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java                                                       |    2 
 opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java                                                    |   59 -
 opendj-sdk/opends/src/server/org/opends/server/core/ExtendedOperationBasis.java                                                 |   10 
 23 files changed, 1,175 insertions(+), 366 deletions(-)

diff --git a/opendj-sdk/opends/resource/config/config.ldif b/opendj-sdk/opends/resource/config/config.ldif
index 898737d..b15bd6a 100644
--- a/opendj-sdk/opends/resource/config/config.ldif
+++ b/opendj-sdk/opends/resource/config/config.ldif
@@ -51,6 +51,8 @@
 objectClass: top
 objectClass: ds-cfg-access-control-handler
 objectClass: ds-cfg-dseecompat-access-control-handler
+ds-cfg-global-aci: (targetcontrol="2.16.840.1.113730.3.4.2 || 2.16.840.1.113730.3.4.17 || 2.16.840.1.113730.3.4.19 || 1.3.6.1.4.1.4203.1.10.2") (version 3.0; acl "Anonymous control access"; allow(read) userdn="ldap:///anyone";)
+ds-cfg-global-aci: (targetcontrol="*") (version 3.0; acl "control"; allow(read) userdn="ldap:///anyone";)
 ds-cfg-global-aci: (targetattr!="userPassword||authPassword")(version 3.0; acl "Anonymous read access"; allow (read,search,compare) userdn="ldap:///anyone";)
 ds-cfg-global-aci: (targetattr="*")(version 3.0; acl "Self entry modification"; allow (write) userdn="ldap:///self";)
 ds-cfg-global-aci: (target="ldap:///cn=schema")(targetscope="base")(targetattr="attributeTypes||dITContentRules||dITStructureRules||ldapSyntaxes||matchingRules||matchingRuleUse||nameForms||objectClasses")(version 3.0; acl "User-Visible Schema Operational Attributes"; allow (read,search,compare) userdn="ldap:///anyone";)
@@ -95,19 +97,7 @@
 objectClass: ds-cfg-alert-handler
 cn: JMX Alert Handler
 ds-cfg-alert-handler-class: org.opends.server.extensions.JMXAlertHandler
-ds-cfg-alert-handler-enabled: true
-
-dn: cn=SMTP Alert Handler,cn=Alert Handlers,cn=config
-objectClass: top
-objectClass: ds-cfg-alert-handler
-objectClass: ds-cfg-smtp-alert-handler
-cn: JMX Alert Handler
-ds-cfg-alert-handler-class: org.opends.server.extensions.SMTPAlertHandler
 ds-cfg-alert-handler-enabled: false
-ds-cfg-sender-address: opends-alerts@example.com
-ds-cfg-recipient-address: directory-administrators@example.com
-ds-cfg-message-subject: OpenDS Alert %%alert-type%%
-ds-cfg-message-body: Alert Type:  %%alert-type%%\n\nAlert ID:  %%alert-id%%\n\nAlert Message:  %%alert-message%%
 
 dn: cn=Backends,cn=config
 objectClass: top
diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java b/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
index 67f4c8e..12200ab 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
@@ -133,6 +133,26 @@
                                          addOperation);
 
 
+  /**
+   * Indicates whether the provided control is allowed based on
+   * the access control configuration and the specified
+   * operation. This method should not alter the provided
+   * operation in any way.
+   *
+   * @param  dn  A DN that can be used in the access determination.
+   *
+   * @param  op  The operation to use in the
+   *                       determination.
+   *
+   * @param control The control for which to make the determination.
+   *
+   * @return  {@code true} if the control should be allowed by the
+   *          access control configuration, or {@code false} if not.
+   */
+  public abstract boolean isAllowed(DN dn, Operation  op,
+                                    Control control);
+
+
 
   /**
    * Indicates whether the provided bind operation is allowed based on
@@ -302,44 +322,5 @@
   public abstract boolean maySend(SearchOperation searchOperation,
                                SearchResultReference searchReference);
 
-
-
-  /**
-   * Indicates whether a proxied authorization control is allowed
-   * based on the current operation and the new authorization entry.
-   *
-   * @param  operation              The operation with which the
-   *                                proxied authorization control is
-   *                                associated.
-   * @param  newAuthorizationEntry  The new authorization entry
-   *                                related to the proxied
-   *                                authorization control
-   *                                authorization ID.
-   *
-   * @return  {@code true} if the operation should be allowed to use
-   *          the proxied authorization control, or {@code false} if
-   *          not.
-   */
-  public abstract boolean isProxiedAuthAllowed(Operation operation,
-                               Entry newAuthorizationEntry);
-
-
-
-  /**
-   * Indicates whether a getEffectiveRights control is allowed
-   * based on the current operation and the control contents.
-   *
-   * @param  operation  The operation with which the
-   *                    getEffectiveRights control is associated.
-   *                    This is always a SearchOperation.
-   * @param  control    The control class containing the decoded
-   *                    getEffectiveRights control contents.
-   *
-   * @return  {@code true} if the use of the getEffectiveRights
-   *          control should be allowed, or {@code false} if not.
-   */
-  public abstract boolean isGetEffectiveRightsAllowed(
-                               SearchOperation operation,
-                               Control control);
 }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
index 272350e..d1ace9d 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/Aci.java
@@ -31,7 +31,10 @@
 import org.opends.server.types.DN;
 import static org.opends.server.messages.MessageHandler.*;
 import static org.opends.server.messages.AciMessages.*;
+import static org.opends.server.util.StaticUtils.isDigit;
+
 import java.util.regex.Pattern;
+import java.util.HashSet;
 
 /**
  * The Aci class represents ACI strings.
@@ -107,6 +110,7 @@
            ZERO_OR_MORE_WHITESPACE + AciBody.bodyRegx +
            ZERO_OR_MORE_WHITESPACE_END_PATTERN;
 
+
     /**
      * Regular expression that graciously matches an attribute type name. Must
      * begin with an ASCII letter or digit, and contain only ASCII letters,
@@ -162,6 +166,20 @@
             ZERO_OR_MORE_WHITESPACE +
                     "\\+" + ZERO_OR_MORE_WHITESPACE;
 
+    /*
+     * Regular expression used to do quick check of OID string.
+     */
+    private static final String OID_NAME = "[\\d.\\*]*";
+
+    /*
+    * Regular expression that matches one or more OID_NAME's separated by
+    * the "||" token.
+    */
+    private static final String oidListRegex  =  ZERO_OR_MORE_WHITESPACE +
+            OID_NAME + ZERO_OR_MORE_WHITESPACE + "(" +
+            LOGICAL_OR + ZERO_OR_MORE_WHITESPACE + OID_NAME +
+            ZERO_OR_MORE_WHITESPACE + ")*";
+
     /**
      * ACI_ADD is used to set the container rights for a LDAP add operation.
      */
@@ -409,6 +427,7 @@
               return false;
         }
         return AciTargets.isTargetApplicable(aci, matchCtx) &&
+                AciTargets.isTargetControlApplicable(aci, matchCtx) &&
                 AciTargets.isTargetFilterApplicable(aci, matchCtx) &&
                 AciTargets.isTargAttrFiltersApplicable(aci, matchCtx) &&
                 AciTargets.isTargetAttrApplicable(aci, matchCtx);
@@ -455,11 +474,79 @@
         return aci.evaluate(evalCtx);
     }
 
-  /**
-   * Returns the name string of this ACI.
-   * @return The name string.
-   */
+    /**
+     * Returns the name string of this ACI.
+     * @return The name string.
+     */
     public String getName() {
       return this.body.getName();
     }
-}
+
+
+  /**
+   *  Decode an OIDs expression string.
+   *
+   * @param expr A string representing the OID expression.
+   * @param msgID A message ID to be used if there is an exception.
+   *
+   * @return  Return a hash set of verfied OID strings parsed from the OID
+   *          expression.
+   *
+   * @throws AciException If the specified expression string is invalid.
+   */
+
+    public static HashSet<String> decodeOID(String expr, int msgID)
+    throws AciException {
+      HashSet<String> OIDs = new HashSet<String>();
+      //Quick check to see if the expression is valid.
+      if (Pattern.matches(oidListRegex, expr)) {
+        // Remove the spaces in the oid string and
+        // split the list.
+        Pattern separatorPattern =
+                Pattern.compile(LOGICAL_OR);
+        String oidString =
+                expr.replaceAll(ZERO_OR_MORE_WHITESPACE, "");
+        String[] oidArray=
+                separatorPattern.split(oidString);
+        //More careful analysis of each OID string.
+        for(String oid : oidArray) {
+          verifyOid(oid);
+          OIDs.add(oid);
+        }
+      } else {
+        String message = getMessage(msgID, expr);
+        throw new AciException(msgID, message);
+      }
+      return OIDs;
+    }
+
+    /**
+     *  Verfiy the specified OID string.
+     *
+     * @param oidStr The string representing an OID.
+     *
+     * @throws AciException If the specified string is invalid.
+     */
+    private static void verifyOid(String oidStr) throws AciException {
+      int pos=0, length=oidStr.length();
+      char c;
+      if(oidStr.equals("*"))
+        return;
+      boolean lastWasPeriod = false;
+      while ((pos < length) && ((c = oidStr.charAt(pos++)) != ' ')) {
+        if (c == '.') {
+          if (lastWasPeriod) {
+            int msgID = MSGID_ACI_SYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID;
+            String message = getMessage(msgID, oidStr, c, pos-1);
+            throw new AciException(msgID, message);
+          }  else
+            lastWasPeriod = true;
+        }  else if (! isDigit(c)) {
+          int msgID = MSGID_ACI_SYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID;
+          String message = getMessage(msgID, oidStr, c, pos-1);
+          throw new AciException(msgID, message);
+        }  else
+          lastWasPeriod = false;
+      }
+    }
+  }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
index 06e9a8f..54fd4dc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -107,17 +107,17 @@
      * restore the current resource entry state after a read right was
      * evaluated.
      */
-    private Entry saveResourceEntry;
+    private final Entry saveResourceEntry;
 
     /*
      * The client connection information.
      */
-    private ClientConnection clientConnection;
+    private final ClientConnection clientConnection;
 
     /*
      * The operation being evaluated.
      */
-    private Operation operation;
+    private final Operation operation;
 
     /*
      * True if a targattrfilters match was found.
@@ -138,7 +138,7 @@
      * Used to save the current authorization entry when the authorization
      * entry is switched during a proxy access check.
      */
-    private Entry saveAuthorizationEntry;
+    private final Entry saveAuthorizationEntry;
 
     /*
      * This entry is only used if proxied authorization is being used.  It is
@@ -196,7 +196,7 @@
      * Table of ACIs that have targattrfilter keywords that matched. Used
      * in geteffectiverights attributeLevel write evaluation.
      */
-    private HashMap<Aci,Aci> targAttrFilterAcis=new HashMap<Aci, Aci>();
+    private final HashMap<Aci,Aci> targAttrFilterAcis=new HashMap<Aci, Aci>();
 
     /*
      * The name of a ACI that decided an evaluation and contained a
@@ -236,6 +236,11 @@
     */
     private int evalAllAttributes=0;
 
+   /*
+   * String used to hold a control OID string.
+   */
+    private String controlOID;
+
   /**
      * This constructor is used by all currently supported LDAP operations.
      *
@@ -732,6 +737,22 @@
     }
 
     /**
+    * {@inheritDoc}
+    */
+    public String getControlOID() {
+      return controlOID;
+    }
+
+    /**
+     * Set the the controlOID value to the specified oid string.
+     *
+     * @param oid  The control oid string.
+     */
+    protected void setControlOID(String oid) {
+      this.controlOID=oid;
+    }
+
+    /**
      * {@inheritDoc}
      */
     public EnumEvalResult hasAuthenticationMethod(EnumAuthMethod authMethod,
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
index e321013..c03b0d7 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -37,7 +37,7 @@
 import static org.opends.server.messages.AciMessages.*;
 import static org.opends.server.messages.MessageHandler.getMessage;
 import static org.opends.server.schema.SchemaConstants.SYNTAX_DN_OID;
-import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
+import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
 import static org.opends.server.util.StaticUtils.toLowerCase;
 
@@ -53,7 +53,7 @@
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.types.*;
 import org.opends.server.workflowelement.localbackend.*;
-
+import org.opends.server.controls.GetEffectiveRights;
 
 
 /**
@@ -1153,32 +1153,37 @@
       return ret;
   }
 
-  //TODO Check access to control, issue #452.
-  /**
-   * Called when a proxied authorization control was decoded. Currently used
-   * to save the current authorization entry in an operation attachment, but
-   * eventually will be used to check access to the actual control.
-   * @param operation The operation to save the attachment to.
-   * @param entry  The new authorization entry.
-   * @return  True if the control is allowed access.
-   */
-  public boolean isProxiedAuthAllowed(Operation operation, Entry entry) {
-    operation.setAttachment(ORIG_AUTH_ENTRY, operation.getAuthorizationEntry());
-    return true;
-  }
 
   /**
-   * Called when a geteffectiverights request control was decoded. Currently
-   * used to save the control in the specified operation's attachment list.
-   * Eventually will be used to check access to the actual control.
-   * @param operation The operation to save the attachment to.
-   * @param c  The request control to save.
-   * @return  True if the control is allowed access.
+   * {@inheritDoc}
    */
-  public boolean isGetEffectiveRightsAllowed(SearchOperation operation,
-                                             Control c) {
-    operation.setAttachment(OID_GET_EFFECTIVE_RIGHTS, c);
-    return true;
+  @Override
+  public boolean isAllowed(DN entryDN, Operation op, Control control) {
+    boolean ret;
+    if(!(ret=skipAccessCheck(op))) {
+      Entry e = new Entry(entryDN, null, null, null);
+      AciLDAPOperationContainer operationContainer =
+              new AciLDAPOperationContainer(op, e, control.getOID());
+      ret=accessAllowed(operationContainer);
+    }
+    if(control.getOID().equals(OID_PROXIED_AUTH_V2) ||
+            control.getOID().equals(OID_PROXIED_AUTH_V1))
+      op.setAttachment(ORIG_AUTH_ENTRY, op.getAuthorizationEntry());
+    else if(control.getOID().equals(OID_GET_EFFECTIVE_RIGHTS)) {
+      try {
+        GetEffectiveRights getEffectiveRightsControl =
+                GetEffectiveRights.decodeControl(control);
+        op.setAttachment(OID_GET_EFFECTIVE_RIGHTS, getEffectiveRightsControl);
+      } catch  (LDAPException le)  {
+        int msgID=MSGID_ACI_SYNTAX_DECODE_EFFECTIVERIGHTS_FAIL;
+        String message = getMessage(msgID, le.getMessage());
+        logError(ErrorLogCategory.ACCESS_CONTROL,
+                 ErrorLogSeverity.INFORMATIONAL,
+                 message, msgID);
+        ret=false;
+      }
+    }
+    return ret;
   }
 
   //Not planned to be implemented methods.
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
index b980c79..a417b61 100644
--- 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
@@ -30,10 +30,9 @@
 import java.util.List;
 
 import org.opends.server.core.*;
-import org.opends.server.types.Modification;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.Entry;
+import org.opends.server.types.*;
 import org.opends.server.workflowelement.localbackend.*;
+import static org.opends.server.authorization.dseecompat.Aci.ACI_READ;
 
 /**
  * The AciLDAPOperationContainer is an AciContainer
@@ -65,6 +64,18 @@
     }
 
     /**
+     * Constructor interface for control evaluation.
+     *
+     * @param operation The operation to evaluate.
+     * @param e An entry built especially for control evaluation.
+     * @param oid The control's oid string.
+     */
+    public AciLDAPOperationContainer(Operation operation, Entry e, String oid) {
+      super(operation, (ACI_READ), e );
+      setControlOID(oid);
+    }
+
+    /**
      * Constructor interface for the add operation.
      * @param operation The add operation to evaluate.
      * @param rights  The rights of an add operation.
@@ -81,8 +92,7 @@
      * @param rights  The rights of a delete operation.
      */
     public AciLDAPOperationContainer(LocalBackendDeleteOperation operation,
-        int rights)
-    {
+                                     int rights) {
         super(operation, rights, operation.getEntryToDelete());
     }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
index 33f4db1..d0a5f1c 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargetMatchContext.java
@@ -118,6 +118,13 @@
      */
     public int getRights();
 
+  /**
+   * Return the oid string of the control being evaluated.
+   *
+   * @return The oid string of the control being evaluated.
+   */
+    public String getControlOID();
+
     /**
      * Checks if the container's rights has the specified rights.
      * @param  rights The rights to check for.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
index ca0a049..e55aca6 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciTargets.java
@@ -71,6 +71,11 @@
      */
     private TargAttrFilters targAttrFilters=null;
 
+   /**
+    * The ACI syntax has a targetcontrol keyword.
+    */
+    private TargetControl targetControl=null;
+
     /*
      * The number of regular expression group positions in a valid ACI target
      * expression.
@@ -139,16 +144,19 @@
      * @param targetFilter The ACI targetfilter keyword if any.
      * @param targetScope The ACI targetscope keyword if any.
      * @param targAttrFilters The ACI targAttrFilters keyword if any.
+     * @param targetControl The ACI targetControl keyword if any.
      */
     private AciTargets(Target targetEntry, TargetAttr targetAttr,
                        TargetFilter targetFilter,
                        SearchScope targetScope,
-                       TargAttrFilters targAttrFilters) {
+                       TargAttrFilters targAttrFilters,
+                       TargetControl targetControl) {
        this.target=targetEntry;
        this.targetAttr=targetAttr;
        this.targetScope=targetScope;
        this.targetFilter=targetFilter;
        this.targAttrFilters=targAttrFilters;
+       this.targetControl=targetControl;
     }
 
     /**
@@ -194,6 +202,16 @@
     public TargAttrFilters getTargAttrFilters() {
         return targAttrFilters;
     }
+
+   /**
+    * Return the class representing the ACI targetcontrol keyword. May be
+    * null.
+    * @return The targetcontrol information.
+   */
+    public TargetControl getTargetControl() {
+      return targetControl;
+    }
+
     /**
      * Decode an ACI's target part of the syntax from the string provided.
      * @param input String representing an ACI target part of syntax.
@@ -207,6 +225,7 @@
         TargetAttr targetAttr=null;
         TargetFilter targetFilter=null;
         TargAttrFilters targAttrFilters=null;
+        TargetControl targetControl=null;
         SearchScope targetScope=SearchScope.WHOLE_SUBTREE;
         Pattern targetPattern = Pattern.compile(targetRegex);
         Matcher targetMatcher = targetPattern.matcher(input);
@@ -252,6 +271,22 @@
                 }
                 break;
             }
+            case KEYWORD_TARGETCONTROL:
+            {
+                if (targetControl == null){
+                    targetControl =
+                            TargetControl.decode(targetOperator, expression);
+                }
+                else
+                {
+                    int msgID =
+                        MSGID_ACI_SYNTAX_INVALID_TARGET_DUPLICATE_KEYWORDS;
+                    String message =
+                        getMessage(msgID, "targetcontrol", input);
+                    throw new AciException(msgID, message);
+                }
+                break;
+            }
             case KEYWORD_TARGETATTR:
             {
                 if (targetAttr == null){
@@ -318,7 +353,7 @@
             }
         }
         return new AciTargets(target, targetAttr, targetFilter,
-                              targetScope, targAttrFilters);
+                              targetScope, targAttrFilters, targetControl);
     }
 
     /**
@@ -365,6 +400,23 @@
     }
 
     /**
+     * Check an ACI's targetcontrol against a target match context.
+     *
+     * @param aci The ACI to match the targetcontrol against.
+     * @param matchCtx The target match context containing the information
+     *                 needed to perform the target match.
+     * @return  True if the targetcontrol matched the target context.
+     */
+    public static boolean isTargetControlApplicable(Aci aci,
+                                            AciTargetMatchContext matchCtx) {
+      boolean ret=true;
+      TargetControl targetControl=aci.getTargets().getTargetControl();
+      if(targetControl != null)
+        ret=targetControl.isApplicable(matchCtx);
+      return ret;
+    }
+
+    /**
      * Check an ACI's targattrfilters against a target match context.
      * @param aci The ACI to match the targattrfilters against.
      * @param matchCtx  The target match context containing the information
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
index e58fe0b..e22c5fd 100644
--- 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
@@ -56,7 +56,12 @@
      * This enumeration is returned when the target keyword is
      * "targattrfilters".
      */
-    KEYWORD_TARGATTRFILTERS ("targattrfilters");
+    KEYWORD_TARGATTRFILTERS ("targattrfilters"),
+    /**
+     * This enumeration is returned when the target keyword is
+     * "targetcontrol".
+     */
+    KEYWORD_TARGETCONTROL ("targetcontrol");
 
     /*
      * The target keyword name.
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
index c28633e..9ea4fa9 100644
--- 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
@@ -59,10 +59,10 @@
      */
     private HashSet<AttributeType> attributes = new HashSet<AttributeType>();
 
-  /**
-   * HashSet of the operational attribute types parsed by the constructor.
-   */
-  private HashSet<AttributeType> opAttributes = new HashSet<AttributeType>();
+    /**
+     * HashSet of the operational attribute types parsed by the constructor.
+     */
+    private HashSet<AttributeType> opAttributes = new HashSet<AttributeType>();
 
     /*
      * Regular expression that matches one or more ATTR_NAME's separated by
diff --git a/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetControl.java b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetControl.java
new file mode 100644
index 0000000..9510888
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/TargetControl.java
@@ -0,0 +1,101 @@
+/*
+ * 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.AciMessages.*;
+import java.util.HashSet;
+
+/**
+ * This class represents an ACI's targetcontrol keyword.
+ */
+
+public class TargetControl {
+
+  /*
+   * HashSet of OID strings parsed from the decode.
+   */
+  private HashSet<String> controlOIDS = new HashSet<String>();
+
+ /*
+  * Enumeration representing the targetcontrol operator.
+  */
+
+  private EnumTargetOperator op = EnumTargetOperator.EQUALITY;
+
+  /**
+   * Creates a class that can be used to evaluate a targetcontrol.
+   *
+   * @param op The operator of the targetfilter expression (=, !=).
+   * @param controlOIDS  Set of control OIDS to use in the evaluation (may
+   *                     contain wild-card '*').
+   */
+  private TargetControl(EnumTargetOperator op, HashSet<String> controlOIDS) {
+    this.controlOIDS=controlOIDS;
+    this.op=op;
+  }
+
+  /**
+   *  Decode an targetcontrol expression string.
+   *
+   * @param operator  An enumeration representing the operator type.
+   * @param expr A string representing the targetcontrol expression.
+   * @return  A class representing the targetcontrol expression that can be
+   *          used to evaluate an ACI.
+   *
+   * @throws AciException If the specified expression string is invalid.
+   */
+  public static TargetControl decode(EnumTargetOperator operator, String expr)
+          throws AciException {
+    HashSet<String> controlOIDs =
+          Aci.decodeOID(expr,MSGID_ACI_SYNTAX_INVALID_TARGETCONTROL_EXPRESSION);
+    return new TargetControl(operator, controlOIDs);
+  }
+
+  /**
+   * Check if a targetcontrol is applicable based on the provided target match
+   * context.
+   *
+   * @param matchCtx The target match context to use in the check.
+   * @return True if the targetcontrol is applicable based on the context.
+   */
+  public boolean isApplicable(AciTargetMatchContext matchCtx) {
+    if(matchCtx.getControlOID() == null)
+      return false;
+    boolean ret = false;
+    for(String oid : controlOIDS)
+      if(oid.equals("*") || matchCtx.getControlOID().equals(oid)) {
+        ret=true;
+        break;
+      }
+   if(op.equals(EnumTargetOperator.NOT_EQUALITY))
+          ret = !ret;
+    return ret;
+  }
+}
+
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java b/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
index 46aec3a..1980fd6 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
@@ -100,7 +100,6 @@
   }
 
 
-
   /**
    * {@inheritDoc}
    */
@@ -160,6 +159,17 @@
    * {@inheritDoc}
    */
   @Override
+   public  boolean isAllowed(DN dn, Operation  op, Control control)
+   {
+     return true;
+   }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
   public boolean isAllowed(LocalBackendModifyDNOperation modifyDNOperation)
   {
     return true;
@@ -189,7 +199,6 @@
   }
 
 
-
   /**
    * {@inheritDoc}
    */
@@ -213,27 +222,5 @@
     return true;
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean isProxiedAuthAllowed(Operation operation, Entry entry)
-  {
-   return true;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean isGetEffectiveRightsAllowed(SearchOperation operation,
-                                             Control c)
-  {
-      return true;
-  }
 }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/ExtendedOperationBasis.java b/opendj-sdk/opends/src/server/org/opends/server/core/ExtendedOperationBasis.java
index 3b5b432..6955d0e 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/ExtendedOperationBasis.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/ExtendedOperationBasis.java
@@ -60,6 +60,7 @@
 import org.opends.server.types.DebugLogLevel;
 import static org.opends.server.messages.CoreMessages.*;
 import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.MessageHandler.getMessage;
 import static org.opends.server.util.ServerConstants.*;
 
 
@@ -487,6 +488,15 @@
       {
         for (Control c : requestControls)
         {
+          if (!AccessControlConfigManager.getInstance().
+                  getAccessControlHandler().
+                  isAllowed(this.getAuthorizationDN(), this, c)) {
+            setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+            int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
+            appendErrorMessage(getMessage(msgID, c.getOID()));
+            skipPostOperation=true;
+            break extendedProcessing;
+          }
           if (! c.isCritical())
           {
             // The control isn't critical, so we don't care if it's supported
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java
index 1b79d7d..da777e4 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/AciMessages.java
@@ -913,7 +913,48 @@
      public static final int MSGID_ACI_SYNTAX_INVALID_NETMASK =
          CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 90;
 
+
     /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value parse failed because a targetcontrol keyword expression
+     * did not parse.  This takes one argument, which is the targetcontrol
+     * expression from the ACI.
+     */
+
+     public static final int MSGID_ACI_SYNTAX_INVALID_TARGETCONTROL_EXPRESSION =
+         CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 91;
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value cannot be parsed because numeric OID contained an
+     * illegal character.  This takes three arguments, which are the provided
+     * value, the illegal character, and the position of that character.
+     */
+     public static final int
+            MSGID_ACI_SYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID =
+            CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 92;
+
+
+    /**
+     * The message ID for the message that will be used if an "aci" attribute
+     * type value cannot be parsed because the OID contained two
+     * consecutive periods.  This takes two arguments, which are the provided
+     * value and the position of the second period.
+     */
+    public static final int
+            MSGID_ACI_SYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID =
+            CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 93;
+
+     /**
+     * The message ID for the message that will be used the ACI handler cannot
+     * decode an geteffectiverights control. This takes one argument, the
+     * message from the decode exception.
+     */
+    public static final int
+            MSGID_ACI_SYNTAX_DECODE_EFFECTIVERIGHTS_FAIL =
+            CATEGORY_MASK_ACCESS_CONTROL | SEVERITY_MASK_SEVERE_WARNING | 94;
+
+  /**
      * Associates a set of generic messages with the message IDs defined in
      * this class.
      */
@@ -1435,5 +1476,30 @@
                  "IP address expression failed to parse because the " +
                  "netmask part of the expression \"%s\" has an invalid value");
 
+
+      registerMessage(MSGID_ACI_SYNTAX_INVALID_TARGETCONTROL_EXPRESSION,
+              "The provided Access Control Instruction (ACI) " +
+              "targetcontrol expression value \"%s\" is invalid. A valid " +
+              "targetcontrol keyword expression value requires one or more " +
+              "valid control OID strings in the following format: " +
+              "oid [|| oid1] ... [|| oidn]");
+
+        registerMessage(MSGID_ACI_SYNTAX_ILLEGAL_CHAR_IN_NUMERIC_OID,
+                "The provided Access Control Instruction (ACI) " +
+                "targetcontrol OID value \"%s\" could not be parsed " +
+                 " because the value contained an illegal character %s " +
+                 "at position %d");
+
+        registerMessage(MSGID_ACI_SYNTAX_DOUBLE_PERIOD_IN_NUMERIC_OID,
+                "The provided Access Control Instruction (ACI) " +
+                "targetcontrol OID value \"%s\" could not be parsed " +
+               " because the numeric OID " +
+               "contained two consecutive periods at position %d");
+
+        registerMessage(MSGID_ACI_SYNTAX_DECODE_EFFECTIVERIGHTS_FAIL,
+                "The access control check failed because a" +
+                " geteffectiverights control could not be" +
+                " decoded because of the following reason: \"%s\"");
+
     }
 }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
index 1c0331c..aa3b15f 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
@@ -6084,13 +6084,12 @@
 
 
   /**
-   * The message ID for the message that will be used if a search
-   * operation cannot be processed due to insufficient access rights caused
-   * by an access control check on the geteffectiverights control. This message
-   * takes a single argument, the name of the search operation's base entry.
+   * The message ID for the message that will be used if a request control
+   * cannot be used due to insufficient access rights. This message takes a
+   * single argument, which is the OID string of the control being used.
    */
   public static final
-  int MSGID_SEARCH_EFFECTIVERIGHTS_INSUFFICIENT_ACCESS_RIGHTS =
+  int MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS =
     CATEGORY_MASK_CORE | SEVERITY_MASK_SEVERE_ERROR | 611;
 
 
@@ -8348,8 +8347,9 @@
         "The entry %s cannot be modified due to insufficient access rights");
     registerMessage(MSGID_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS,
         "The entry %s cannot be searched due to insufficient access rights");
-    registerMessage(MSGID_SEARCH_EFFECTIVERIGHTS_INSUFFICIENT_ACCESS_RIGHTS,
-        "The entry %s cannot be searched due to insufficient access rights");
+    registerMessage(MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS,
+        "The request control with Object Identifier (OID) \"%s\" cannot be" +
+        " used due to insufficient access rights");
     registerMessage(MSGID_BIND_OPERATION_INSECURE_SIMPLE_BIND,
                     "Rejecting a simple bind request for user %s because the " +
                     "password policy requires secure authentication");
diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
index adc3cd7..22db5f0 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -10484,7 +10484,7 @@
                     "ERROR:  No configuration changes were specified");
     registerMessage(MSGID_CONFIGDS_PORT_ALREADY_SPECIFIED,
                     "ERROR:  You have specified the value %s for different " +
-                    "ports.");
+                    "ports");
     registerMessage(MSGID_CONFIGDS_WROTE_UPDATED_CONFIG,
                     "Successfully wrote the updated Directory Server " +
                     "configuration");
diff --git a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java b/opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
index ee3a804..5c7790c 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -56,7 +56,6 @@
 import org.opends.server.api.plugin.PostOperationPluginResult;
 import org.opends.server.api.plugin.PreOperationPluginResult;
 import org.opends.server.controls.AuthorizationIdentityResponseControl;
-import org.opends.server.controls.GetEffectiveRights;
 import org.opends.server.controls.LDAPAssertionRequestControl;
 import org.opends.server.controls.LDAPPostReadRequestControl;
 import org.opends.server.controls.LDAPPostReadResponseControl;
@@ -214,7 +213,7 @@
   /**
    * Perform a local modify operation against the local backend.
    *
-   * @param operation - The operation to perform
+   * @param localOp - The operation to perform
    */
   private void processLocalModify(LocalBackendModifyOperation localOp)
   {
@@ -392,6 +391,17 @@
             Control c   = requestControls.get(i);
             String  oid = c.getOID();
 
+            if (!AccessControlConfigManager.getInstance().
+                     getAccessControlHandler().
+                     isAllowed(entryDN, localOp, c))
+            {
+              localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+              int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
+              localOp.appendErrorMessage(getMessage(msgID, oid));
+              skipPostOperation = true;
+              break modifyProcessing;
+            }
+
             if (oid.equals(OID_LDAP_ASSERTION))
             {
               LDAPAssertionRequestControl assertControl;
@@ -459,7 +469,7 @@
             }
             else if (oid.equals(OID_LDAP_READENTRY_PREREAD))
             {
-              if (c instanceof LDAPAssertionRequestControl)
+              if (c instanceof LDAPPreReadRequestControl)
               {
                 preReadRequest = (LDAPPreReadRequestControl) c;
               }
@@ -486,7 +496,7 @@
             }
             else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
             {
-              if (c instanceof LDAPAssertionRequestControl)
+              if (c instanceof LDAPPostReadRequestControl)
               {
                 postReadRequest = (LDAPPostReadRequestControl) c;
               }
@@ -569,19 +579,6 @@
                 break modifyProcessing;
               }
 
-
-              if (AccessControlConfigManager.getInstance().
-                      getAccessControlHandler().isProxiedAuthAllowed(localOp,
-                      authorizationEntry) == false) {
-                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                localOp.appendErrorMessage(getMessage(msgID,
-                    String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break modifyProcessing;
-              }
               localOp.setAuthorizationEntry(authorizationEntry);
               if (authorizationEntry == null)
               {
@@ -650,18 +647,6 @@
                 break modifyProcessing;
               }
 
-              if (AccessControlConfigManager.getInstance().
-                  getAccessControlHandler().isProxiedAuthAllowed(localOp,
-                      authorizationEntry) == false) {
-                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                localOp.appendErrorMessage(getMessage(msgID,
-                    String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break modifyProcessing;
-              }
               localOp.setAuthorizationEntry(authorizationEntry);
               if (authorizationEntry == null)
               {
@@ -2545,6 +2530,17 @@
           Control c   = requestControls.get(i);
           String  oid = c.getOID();
 
+          if (!AccessControlConfigManager.getInstance().
+                  getAccessControlHandler().
+                  isAllowed(baseDN, localOp, c))
+          {
+            localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+            int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
+            localOp.appendErrorMessage(getMessage(msgID, oid));
+            skipPostOperation = true;
+            break searchProcessing;
+          }
+
           if (oid.equals(OID_LDAP_ASSERTION))
           {
             LDAPAssertionRequestControl assertControl;
@@ -2696,18 +2692,6 @@
               break searchProcessing;
             }
 
-            if (AccessControlConfigManager.getInstance().
-                getAccessControlHandler().isProxiedAuthAllowed(localOp,
-                    authorizationEntry) == false) {
-              localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-              int msgID = MSGID_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-              localOp.appendErrorMessage(getMessage(msgID,
-                  String.valueOf(baseDN)));
-
-              skipPostOperation = true;
-              break searchProcessing;
-            }
             localOp.setAuthorizationEntry(authorizationEntry);
             if (authorizationEntry == null)
             {
@@ -2777,18 +2761,6 @@
               break searchProcessing;
             }
 
-            if (AccessControlConfigManager.getInstance().
-                getAccessControlHandler().isProxiedAuthAllowed(localOp,
-                    authorizationEntry) == false) {
-              localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-              int msgID = MSGID_SEARCH_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-              localOp.appendErrorMessage(getMessage(msgID,
-                  String.valueOf(baseDN)));
-
-              skipPostOperation = true;
-              break searchProcessing;
-            }
             localOp.setAuthorizationEntry(authorizationEntry);
             if (authorizationEntry == null)
             {
@@ -2884,48 +2856,6 @@
           {
             localOp.setVirtualAttributesOnly(true);
           }
-          else if(oid.equals(OID_GET_EFFECTIVE_RIGHTS))
-          {
-            GetEffectiveRights effectiveRightsControl;
-            if (c instanceof GetEffectiveRights)
-            {
-              effectiveRightsControl = (GetEffectiveRights) c;
-            }
-            else
-            {
-              try
-              {
-                effectiveRightsControl = GetEffectiveRights.decodeControl(c);
-              }
-              catch (LDAPException le)
-              {
-                if (debugEnabled())
-                {
-                  TRACER.debugCaught(DebugLogLevel.ERROR, le);
-                }
-
-                localOp.setResultCode(ResultCode.valueOf(le.getResultCode()));
-                localOp.appendErrorMessage(le.getMessage());
-
-                break searchProcessing;
-              }
-            }
-
-              if (!AccessControlConfigManager.getInstance()
-                   .getAccessControlHandler().
-                    isGetEffectiveRightsAllowed(localOp,
-                        effectiveRightsControl)) {
-                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-                 int msgID =
-                        MSGID_SEARCH_EFFECTIVERIGHTS_INSUFFICIENT_ACCESS_RIGHTS;
-                 localOp.appendErrorMessage(getMessage(msgID,
-                     String.valueOf(baseDN)));
-
-                 skipPostOperation = true;
-                 break searchProcessing;
-               }
-          }
-
           // NYI -- Add support for additional controls.
           else if (c.isCritical())
           {
@@ -3151,7 +3081,7 @@
   /**
    * Perform a local bind operation against a local backend.
    *
-   * @param operation - The operation to perform
+   * @param localOp - The operation to perform
    */
   private void processLocalBind(LocalBackendBindOperation localOp)
   {
@@ -3241,6 +3171,16 @@
           Control c   = requestControls.get(i);
           String  oid = c.getOID();
 
+          if (!AccessControlConfigManager.getInstance().
+                  getAccessControlHandler(). isAllowed(bindDN, localOp, c))
+          {
+            localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+            int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
+            localOp.appendErrorMessage(getMessage(msgID, oid));
+            skipPostOperation = true;
+            break bindProcessing;
+          }
+
           if (oid.equals(OID_AUTHZID_REQUEST))
           {
             returnAuthzID = true;
@@ -4560,7 +4500,7 @@
   /**
    * Perform a local add operation against a local backend.
    *
-   * @param operation - The operation to perform
+   * @param localOp - The operation to perform
    */
   private void processLocalAdd(LocalBackendAddOperation localOp)
   {
@@ -5298,6 +5238,16 @@
             Control c   = requestControls.get(i);
             String  oid = c.getOID();
 
+            if (!AccessControlConfigManager.getInstance().
+                    getAccessControlHandler().isAllowed(parentDN, localOp, c))
+            {
+              localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+              int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
+              localOp.appendErrorMessage(getMessage(msgID, oid));
+              skipPostOperation = true;
+              break addProcessing;
+            }
+
             if (oid.equals(OID_LDAP_ASSERTION))
             {
               LDAPAssertionRequestControl assertControl;
@@ -5365,7 +5315,7 @@
             }
             else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
             {
-              if (c instanceof LDAPAssertionRequestControl)
+              if (c instanceof LDAPPostReadRequestControl)
               {
                 postReadRequest = (LDAPPostReadRequestControl) c;
               }
@@ -5448,18 +5398,6 @@
                 break addProcessing;
               }
 
-              if (AccessControlConfigManager.getInstance()
-                  .getAccessControlHandler().isProxiedAuthAllowed(localOp,
-                      authorizationEntry) == false) {
-                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                localOp.appendErrorMessage(getMessage(msgID,
-                    String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break addProcessing;
-              }
               localOp.setAuthorizationEntry(authorizationEntry);
               if (authorizationEntry == null)
               {
@@ -5528,18 +5466,6 @@
                 break addProcessing;
               }
 
-              if (AccessControlConfigManager.getInstance()
-                      .getAccessControlHandler().isProxiedAuthAllowed(localOp,
-                      authorizationEntry) == false) {
-                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                localOp.appendErrorMessage(getMessage(msgID,
-                    String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break addProcessing;
-              }
               localOp.setAuthorizationEntry(authorizationEntry);
               if (authorizationEntry == null)
               {
@@ -5945,7 +5871,7 @@
   /**
    * Performs a local delete operation against a local backend.
    *
-   * @param operation the operation to perform
+   * @param localOp the operation to perform
    */
   private void processLocalDelete(LocalBackendDeleteOperation localOp)
   {
@@ -6095,6 +6021,16 @@
             Control c   = requestControls.get(i);
             String  oid = c.getOID();
 
+            if (!AccessControlConfigManager.getInstance().
+                     getAccessControlHandler().isAllowed(entryDN, localOp, c))
+            {
+              localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+              int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
+              localOp.appendErrorMessage(getMessage(msgID, oid));
+              skipPostOperation = true;
+              break deleteProcessing;
+            }
+
             if (oid.equals(OID_LDAP_ASSERTION))
             {
               LDAPAssertionRequestControl assertControl;
@@ -6162,7 +6098,7 @@
             }
             else if (oid.equals(OID_LDAP_READENTRY_PREREAD))
             {
-              if (c instanceof LDAPAssertionRequestControl)
+              if (c instanceof LDAPPreReadRequestControl)
               {
                 preReadRequest = (LDAPPreReadRequestControl) c;
               }
@@ -6245,18 +6181,6 @@
                 break deleteProcessing;
               }
 
-              if (AccessControlConfigManager.getInstance()
-                  .getAccessControlHandler().isProxiedAuthAllowed(localOp,
-                      authorizationEntry) == false) {
-                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_DELETE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                localOp.appendErrorMessage(
-                    getMessage(msgID, String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break deleteProcessing;
-              }
               localOp.setAuthorizationEntry(authorizationEntry);
               if (authorizationEntry == null)
               {
@@ -6325,18 +6249,6 @@
                 break deleteProcessing;
               }
 
-              if (AccessControlConfigManager.getInstance()
-                  .getAccessControlHandler().isProxiedAuthAllowed(localOp,
-                      authorizationEntry) == false) {
-                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_DELETE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                localOp.appendErrorMessage(
-                    getMessage(msgID, String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break deleteProcessing;
-              }
               localOp.setAuthorizationEntry(authorizationEntry);
               if (authorizationEntry == null)
               {
@@ -6755,7 +6667,7 @@
   /**
    * Perform a local compare operation against a local backend.
    *
-   * @param operation - The operation to perform
+   * @param localOp - The operation to perform
    */
   private void processLocalCompare(LocalBackendCompareOperation localOp)
   {
@@ -6896,6 +6808,17 @@
             Control c   = requestControls.get(i);
             String  oid = c.getOID();
 
+            if (!AccessControlConfigManager.getInstance().
+                    getAccessControlHandler().
+                    isAllowed(entryDN, localOp, c))
+            {
+              localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+              int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
+              localOp.appendErrorMessage(getMessage(msgID, oid));
+              skipPostOperation = true;
+              break compareProcessing;
+            }
+
             if (oid.equals(OID_LDAP_ASSERTION))
             {
               LDAPAssertionRequestControl assertControl;
@@ -7015,18 +6938,6 @@
                 break compareProcessing;
               }
 
-              if (AccessControlConfigManager.getInstance()
-                      .getAccessControlHandler().isProxiedAuthAllowed(localOp,
-                                                 authorizationEntry) == false) {
-                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                localOp.appendErrorMessage(
-                    getMessage(msgID, String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break compareProcessing;
-              }
               localOp.setAuthorizationEntry(authorizationEntry);
               if (authorizationEntry == null)
               {
@@ -7095,18 +7006,6 @@
                 break compareProcessing;
               }
 
-              if (AccessControlConfigManager.getInstance()
-                      .getAccessControlHandler().isProxiedAuthAllowed(localOp,
-                                                 authorizationEntry) == false) {
-                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                localOp.appendErrorMessage(
-                    getMessage(msgID, String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break compareProcessing;
-              }
               localOp.setAuthorizationEntry(authorizationEntry);
               if (authorizationEntry == null)
               {
@@ -7323,7 +7222,7 @@
   /**
    * Perform a local moddn operation against the local backend.
    *
-   * @param operation - The operation to perform
+   * @param op - The operation to perform
    */
   private void processLocalModifyDN(LocalBackendModifyDNOperation op)
   {
@@ -7606,6 +7505,16 @@
             Control c   = requestControls.get(i);
             String  oid = c.getOID();
 
+            if (!AccessControlConfigManager.getInstance().
+                     getAccessControlHandler().isAllowed(entryDN,  op, c))
+            {
+              op.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+              int msgID = MSGID_CONTROL_INSUFFICIENT_ACCESS_RIGHTS;
+              op.appendErrorMessage(getMessage(msgID, oid));
+              skipPostOperation = true;
+              break modifyDNProcessing;
+            }
+
             if (oid.equals(OID_LDAP_ASSERTION))
             {
               LDAPAssertionRequestControl assertControl;
@@ -7671,7 +7580,7 @@
             }
             else if (oid.equals(OID_LDAP_READENTRY_PREREAD))
             {
-              if (c instanceof LDAPAssertionRequestControl)
+              if (c instanceof LDAPPreReadRequestControl)
               {
                 preReadRequest = (LDAPPreReadRequestControl) c;
               }
@@ -7698,7 +7607,7 @@
             }
             else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
             {
-              if (c instanceof LDAPAssertionRequestControl)
+              if (c instanceof LDAPPostReadRequestControl)
               {
                 postReadRequest = (LDAPPostReadRequestControl) c;
               }
@@ -7780,18 +7689,6 @@
                 break modifyDNProcessing;
               }
 
-              if (AccessControlConfigManager.getInstance()
-                      .getAccessControlHandler().isProxiedAuthAllowed(op,
-                      authorizationEntry) == false) {
-                op.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                op.appendErrorMessage(getMessage(msgID,
-                    String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break modifyDNProcessing;
-              }
               op.setAuthorizationEntry(authorizationEntry);
               if (authorizationEntry == null)
               {
@@ -7858,19 +7755,6 @@
 
                 break modifyDNProcessing;
               }
-              if (AccessControlConfigManager.getInstance()
-                  .getAccessControlHandler().isProxiedAuthAllowed(op,
-                                                authorizationEntry) == false) {
-                op.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                op.appendErrorMessage(getMessage(msgID,
-                    String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break modifyDNProcessing;
-              }
-
 
               op.setAuthorizationEntry(authorizationEntry);
               if (authorizationEntry == null)
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
index d516143..c588e5c 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTestCase.java
@@ -31,6 +31,8 @@
 import org.opends.server.TestCaseUtils;
 import org.opends.server.tools.LDAPModify;
 import org.opends.server.tools.LDAPSearch;
+import org.opends.server.tools.LDAPDelete;
+import org.opends.server.tools.LDAPPasswordModify;
 import static org.opends.server.util.ServerConstants.EOL;
 import org.testng.annotations.Test;
 import org.testng.Assert;
@@ -48,14 +50,86 @@
   public static final String ACCESS_HANDLER_DN =
                                        "cn=Access Control Handler,cn=config";
 
-  private static ByteArrayOutputStream oStream = new ByteArrayOutputStream();
-  private  static ThreadLocal<Map<String,File>> tempLdifFile =
+  //GLOBAL ACIs
+
+  protected final static String G_READ_ACI =
+          "(targetattr!=\"userPassword||authPassword\")" +
+                  "(version 3.0; acl \"Anonymous read access\";" +
+                  "allow (read,search,compare) userdn=\"ldap:///anyone\";)";
+
+  protected final static String G_SELF_MOD =
+          "(targetattr=\"*\")(version 3.0; acl \"Self entry modification\";" +
+                  "allow (write) userdn=\"ldap:///self\";)";
+
+  protected final static String G_SCHEMA =
+          "(target=\"ldap:///cn=schema\")(targetscope=\"base\")" +
+          "(targetattr=\"attributeTypes||dITContentRules||dITStructureRules||" +
+                  "ldapSyntaxes||matchingRules||matchingRuleUse||nameForms||" +
+                  "objectClasses\")" +
+          "(version 3.0; acl \"User-Visible Schema Operational Attributes\";" +
+                  "allow (read,search,compare) userdn=\"ldap:///anyone\";)";
+
+  protected final static String G_DSE =
+          "(target=\"ldap:///\")(targetscope=\"base\")" +
+               "(targetattr=\"namingContexts||supportedAuthPasswordSchemes||" +
+                  "supportedControl||supportedExtension||supportedFeatures||" +
+                 "supportedSASLMechanisms||vendorName||vendorVersion\")" +
+        "(version 3.0; acl \"User-Visible Root DSE Operational Attributes\"; " +
+                  "allow (read,search,compare) userdn=\"ldap:///anyone\";)";
+
+  protected final static String G_USER_OPS =
+          "(targetattr=\"createTimestamp||creatorsName||modifiersName||" +
+                  "modifyTimestamp||entryDN||entryUUID||subschemaSubentry\")" +
+                 "(version 3.0; acl \"User-Visible Operational Attributes\"; " +
+                  "allow (read,search,compare) userdn=\"ldap:///anyone\";)";
+
+  protected final static String G_CONTROL =
+          "(targetcontrol = \"*\")" +
+          "(version 3.0; acl \"Control\"; " +
+                  "allow (read) userdn=\"ldap:///anyone\";)";
+
+  private static final ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+  private  static final ThreadLocal<Map<String,File>> tempLdifFile =
            new ThreadLocal<Map<String,File>>();
 
+
+  protected String pwdModify(String bindDn, String bindPassword,
+                             String newPassword, String noOpControl,
+                             String pwdPolicyControl, int rc) {
+
+    ArrayList<String> argList=new ArrayList<String>(20);
+    argList.add("-h");
+    argList.add("127.0.0.1");
+    argList.add("-p");
+    argList.add(String.valueOf(TestCaseUtils.getServerLdapPort()));
+    argList.add("-D");
+    argList.add(bindDn);
+    argList.add("-w");
+    argList.add(bindPassword);
+    argList.add("-c");
+    argList.add(bindPassword);
+    argList.add("-n");
+    argList.add(newPassword);
+    if(noOpControl != null) {
+      argList.add("-J");
+      argList.add(noOpControl);
+    }
+    if(pwdPolicyControl != null) {
+      argList.add("-J");
+      argList.add(pwdPolicyControl);
+    }
+    String[] args = new String[argList.size()];
+    oStream.reset();
+    int ret=
+           LDAPPasswordModify.mainPasswordModify(argList.toArray(args),
+                   false, oStream, oStream);
+    Assert.assertEquals(rc, ret,  "Returned error: " + oStream.toString());
+    return oStream.toString();
+  }
+
   protected String LDAPSearchCtrl(String bindDn, String bindPassword,
                             String proxyDN, String controlStr,
-                            String base, String filter, String attr)
-          throws Exception {
+                            String base, String filter, String attr) {
     ArrayList<String> argList=new ArrayList<String>(20);
     argList.add("-h");
     argList.add("127.0.0.1");
@@ -90,10 +164,29 @@
     return oStream.toString();
   }
 
+  protected String
+  LDAPSearchParams(String bindDn,  String bindPassword,
+                               String proxyDN, String authzid,
+                               String[] attrList,
+                               String base, String filter ,String attr,
+                               boolean pwdPolicy, boolean reportAuthzID,
+                               int rc)  {
+    return _LDAPSearchParams(bindDn, bindPassword, proxyDN, authzid, attrList,
+            base, filter, attr, pwdPolicy, reportAuthzID, rc);
+  }
+
   protected String LDAPSearchParams(String bindDn, String bindPassword,
+                                    String proxyDN, String authzid,
+                                    String[] attrList,
+                                    String base, String filter ,String attr) {
+    return _LDAPSearchParams(bindDn, bindPassword, proxyDN, authzid, attrList,
+            base, filter, attr, false, false, 0);
+  }
+
+  private String _LDAPSearchParams(String bindDn, String bindPassword,
                             String proxyDN, String authzid, String[] attrList,
-                            String base, String filter ,String attr)
-          throws Exception {
+                            String base, String filter ,String attr,
+                            boolean pwdPolicy, boolean reportAuthzID, int rc) {
     ArrayList<String> argList=new ArrayList<String>(20);
     argList.add("-h");
     argList.add("127.0.0.1");
@@ -118,6 +211,12 @@
         argList.add(a);
       }
     }
+    if(pwdPolicy) {
+      argList.add("--usePasswordPolicyControl");
+    }
+    if(reportAuthzID) {
+      argList.add("-E");
+    }
     argList.add("-b");
     argList.add(base);
     argList.add("-s");
@@ -130,11 +229,59 @@
     oStream.reset();
     int retVal =
          LDAPSearch.mainSearch(argList.toArray(args), false, oStream, oStream);
-    Assert.assertEquals(0, retVal, "Returned error: " + oStream.toString());
+    Assert.assertEquals(rc, retVal, "Returned error: " + oStream.toString());
     return oStream.toString();
   }
 
+  protected void LDIFAdd(String ldif, String bindDn, String bindPassword,
+                            String controlStr, int rc) throws Exception {
+    _LDIFModify(ldif, bindDn, bindPassword, controlStr, true, rc);
+  }
+
+  protected void LDIFModify(String ldif, String bindDn, String bindPassword,
+                            String controlStr, int rc) throws Exception {
+    _LDIFModify(ldif, bindDn, bindPassword, controlStr, false, rc);
+  }
+
   protected void LDIFModify(String ldif, String bindDn, String bindPassword)
+  throws Exception {
+    _LDIFModify(ldif, bindDn, bindPassword, null, false, -1);
+  }
+
+  protected void LDIFDelete(String dn, String bindDn, String bindPassword,
+                            String controlStr, int rc) {
+    _LDIFDelete(dn, bindDn, bindPassword, controlStr, rc);
+  }
+
+  private void _LDIFDelete(String dn, String bindDn, String bindPassword,
+                           String controlStr, int rc) {
+    ArrayList<String> argList=new ArrayList<String>(20);
+    argList.add("-h");
+    argList.add("127.0.0.1");
+    argList.add("-p");
+    argList.add(String.valueOf(TestCaseUtils.getServerLdapPort()));
+    argList.add("-D");
+    argList.add(bindDn);
+    argList.add("-w");
+    argList.add(bindPassword);
+    if(controlStr != null) {
+      argList.add("-J");
+      argList.add(controlStr);
+    }
+    argList.add(dn);
+    String[] args = new String[argList.size()];
+    ldapDelete(argList.toArray(args), rc);
+  }
+
+  private void ldapDelete(String[] args, int rc) {
+    oStream.reset();
+    int retVal = LDAPDelete.mainDelete(args, false, oStream, oStream);
+    Assert.assertEquals(rc, retVal, "Returned error: " + oStream.toString());
+  }
+
+
+  private void _LDIFModify(String ldif, String bindDn, String bindPassword,
+                           String controlStr, boolean add,  int rc)
           throws Exception {
     File tempFile = getTemporaryLdifFile();
     TestCaseUtils.writeFile(tempFile, ldif);
@@ -147,19 +294,27 @@
     argList.add(bindDn);
     argList.add("-w");
     argList.add(bindPassword);
+    if(controlStr != null) {
+      argList.add("-J");
+      argList.add(controlStr);
+    }
+    if(add) {
+     argList.add("-a");
+    }
     argList.add("-f");
     argList.add(tempFile.getAbsolutePath());
     String[] args = new String[argList.size()];
-    ldapModify(argList.toArray(args));
+    ldapModify(argList.toArray(args), rc);
   }
 
-  protected void ldapModify(String[] args) {
+  private void ldapModify(String[] args, int rc) {
     oStream.reset();
-    LDAPModify.mainModify(args, false, oStream, oStream);
+    int retVal =LDAPModify.mainModify(args, false, oStream, oStream);
+    if(rc != -1)
+       Assert.assertEquals(rc, retVal, "Returned error: " + oStream.toString());
   }
 
-  protected void deleteAttrFromEntry(String dn, String attr)
-  throws Exception {
+  protected void deleteAttrFromEntry(String dn, String attr) throws Exception {
     StringBuilder ldif = new StringBuilder();
     ldif.append(TestCaseUtils.makeLdif(
             "dn: "  + dn,
@@ -168,6 +323,20 @@
     LDIFModify(ldif.toString(), DIR_MGR_DN, PWD);
   }
 
+  protected static String makeModDNLDIF(String dn, String newRDN,
+                                    String deleteOldRDN,
+                                    String newSuperior ) {
+    StringBuilder ldif = new StringBuilder();
+    ldif.append("dn: ").append(dn).append(EOL);
+    ldif.append("changetype: modrdn").append(EOL);
+    ldif.append("newrdn: ").append(newRDN).append(EOL);
+    ldif.append("deleteoldrdn: ").append(deleteOldRDN).append(EOL);
+    if(newSuperior != null)
+       ldif.append("newsuperior: ").append(newSuperior).append(EOL);
+    ldif.append(EOL);
+    return ldif.toString();
+  }
+
   protected static String makeDelLDIF(String attr, String dn, String... acis) {
     StringBuilder ldif = new StringBuilder();
     ldif.append("dn: ").append(dn).append(EOL);
@@ -179,6 +348,16 @@
     return ldif.toString();
   }
 
+  protected static String
+  makeAddEntryLDIF(String dn, String ... lines) {
+    StringBuilder ldif = new StringBuilder();
+    ldif.append("dn: ").append(dn).append(EOL);
+    ldif.append("changetype: add").append(EOL);
+    for(String l : lines)
+       ldif.append(l).append(EOL);
+    ldif.append(EOL);
+    return ldif.toString();
+  }
 
   protected static String makeAddLDIF(String attr, String dn, String... acis) {
     StringBuilder ldif = new StringBuilder();
@@ -191,7 +370,7 @@
     return ldif.toString();
   }
 
-  protected File getTemporaryLdifFile() throws IOException {
+  private File getTemporaryLdifFile() throws IOException {
     Map<String,File> tempFilesForThisThread = tempLdifFile.get();
     if (tempFilesForThisThread == null) {
       tempFilesForThisThread = new HashMap<String,File>();
@@ -313,7 +492,7 @@
   }
 
   protected HashMap<String, String>
-  getAttrMap(String resultString) throws Exception {
+  getAttrMap(String resultString) {
     StringReader r=new StringReader(resultString);
     BufferedReader br=new BufferedReader(r);
     HashMap<String, String> attrMap = new HashMap<String,String>();
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
index e28169b..6c2f536 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
@@ -38,6 +38,7 @@
 import org.opends.server.util.LDIFReader;
 import org.opends.server.util.LDIFWriter;
 import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.util.ServerConstants.*;
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -307,6 +308,12 @@
 
   //The ACIs for the proxy tests.
 
+
+  private static final String ALLOW_PROXY_CONTROL_TO_LEVEL_1=
+             buildAciValue("name", "allow proxy control", "targetcontrol",
+                     OID_PROXIED_AUTH_V2, "allow(read)",
+                     BIND_RULE_USERDN_LEVEL_1);
+
   private static final String ALLOW_PROXY_TO_IMPORT_MGR_NEW =
           buildAciValue("name", "allow proxy import new mgr new tree", "target",
                      MGR_NEW_DN_URL, "allow(import)", BIND_RULE_USERDN_PROXY);
@@ -1050,22 +1057,46 @@
                                        GLOBAL_ALLOW_MONITOR_TO_ADMIN_ACI,
                                        GLOBAL_ALLOW_BASE_DN_TO_LEVEL_1_ACI);
 
-    //Global defauls
-private static final String GLOBAL_ANONYMOUS_READ_ACI =
-       buildGlobalAciValue("name", "Anonymous read access", "targetattr!=",
-                                     "userPassword||authPassword",
-                                     "allow(read, search, compare)", BIND_RULE_USERDN_ANYONE);
+  //Global defaults
+  private static final String GLOBAL_ANONYMOUS_READ_ACI =
+          buildGlobalAciValue("name", "Anonymous read access", "targetattr!=",
+                  "userPassword||authPassword",
+                  "allow(read, search, compare)", BIND_RULE_USERDN_ANYONE);
 
-private static final String GLOBAL_SELF_WRITE_ACI =
-       buildGlobalAciValue("name", "Self entry modification", "targetattr",
-                                     "*",
-                                     "allow(write)", BIND_RULE_USERDN_SELF);
+  private static final String GLOBAL_SELF_WRITE_ACI =
+          buildGlobalAciValue("name", "Self entry modification", "targetattr",
+                  "*",
+                  "allow(write)", BIND_RULE_USERDN_SELF);
 
+  private static final String GLOBAL_SCHEMA_ACI =
+          buildGlobalAciValue("name", "User-Visible Schema Operational Attributes",
+                  "target", "ldap:///cn=schema", "targetscope", "base",
+                  "targetattr",
+                  "attributeTypes||dITContentRules||dITStructureRules||ldapSyntaxes||matchingRules||matchingRuleUse||nameForms||objectClasses",
+                  "allow(read, search, compare)", BIND_RULE_USERDN_ANYONE);
 
-private static final String GLOBAL_DEFAULT_ACIS =
+  private static final String GLOBAL_DSE_ACI = buildGlobalAciValue(
+          "name","User-Visible Root DSE Operational Attributes",
+          "target", "ldap:///", "targetscope", "base",
+          "targetattr",
+          "namingContexts||supportedAuthPasswordSchemes||supportedControl||supportedExtension||supportedFeatures||supportedSASLMechanisms||vendorName||vendorVersion",
+          "allow(read, search, compare)",BIND_RULE_USERDN_ANYONE);
+
+  private static final String GLOBAL_USER_OP_ATTRS_ACI = buildGlobalAciValue(
+          "name", "User-Visible Operational Attributes", "targetattr",
+          "createTimestamp||creatorsName||modifiersName||modifyTimestamp||entryDN||entryUUID||subschemaSubentry",
+          "allow(read, search, compare)", BIND_RULE_USERDN_ANYONE);
+
+  private static final String GLOBAL_CONTROL_ACI = buildGlobalAciValue(
+          "name", "Control", "targetcontrol", "*",
+          "allow(read)", BIND_RULE_USERDN_ANYONE);
+
+  private static final String GLOBAL_DEFAULT_ACIS =
                      makeAttrAddAciLdif(ATTR_AUTHZ_GLOBAL_ACI,ACCESS_HANDLER_DN,
                                         GLOBAL_ANONYMOUS_READ_ACI,
-                                        GLOBAL_SELF_WRITE_ACI);
+                                        GLOBAL_SELF_WRITE_ACI, GLOBAL_SCHEMA_ACI,
+                                        GLOBAL_DSE_ACI, GLOBAL_USER_OP_ATTRS_ACI,
+                                        GLOBAL_CONTROL_ACI);
 
  //ACI used to test LDAP compare.
  private static final
@@ -1102,6 +1133,10 @@
   private static final  String ACI_PROXY_IMPORT_MGR_NEW =
                    makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_IMPORT_MGR_NEW);
 
+
+private static final  String ACI_PROXY_CONTROL_LEVEL_1 =
+                  makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_CONTROL_TO_LEVEL_1);
+
  private static final  String ACI_PROXY_IMPORT_MGR =
                    makeAddAciLdif(OU_BASE_DN, ALLOW_PROXY_TO_IMPORT_MGR);
 
@@ -1769,6 +1804,7 @@
     try {
       addEntries(BASIC_LDIF__GROUP_SEARCH_TESTS, DIR_MGR_DN, DIR_MGR_PW);
       modEntries(ACI_PROXY_IMPORT_MGR, DIR_MGR_DN, DIR_MGR_PW);
+      modEntries(ACI_PROXY_CONTROL_LEVEL_1, DIR_MGR_DN, DIR_MGR_PW);
       modEntries(ACI_PROXY_IMPORT_MGR_NEW, DIR_MGR_DN, DIR_MGR_PW);
       modEntries(ACI_PROXY_EXPORT_MGR, DIR_MGR_DN, DIR_MGR_PW);
       modEntries(ACI_PROXY_EXPORT_MGR_NEW, DIR_MGR_DN, DIR_MGR_PW);
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AlternateRootDN.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AlternateRootDN.java
index 4fa4562..b6e40c1 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AlternateRootDN.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AlternateRootDN.java
@@ -32,6 +32,7 @@
 
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
+import org.testng.annotations.AfterClass;
 import org.testng.Assert;
 import org.opends.server.TestCaseUtils;
 import static org.opends.server.config.ConfigConstants.*;
@@ -55,11 +56,17 @@
        "(version 3.0; acl \"proxy" +  user3 + "\";" +
        "allow (proxy) userdn=\"ldap:///" + user3 + "\";)";
 
+  //Need an ACI to allow proxy control
+  String controlACI = "(targetcontrol=\"" + OID_PROXIED_AUTH_V2 + "\")" +
+          "(version 3.0; acl \"control\";" +
+          "allow(read) userdn=\"ldap:///" + user3 + "\";)";
+
   private static final
   String rootDNACI= "(targetattr=\"" + ATTR_USER_PASSWORD + "\")" +
         "(version 3.0; acl \"pwd search, read " + rootDN + "\";" +
         "allow(read, search) userdn=\"ldap:///" + rootDN + "\";)";
 
+
   @BeforeClass
   public void setupClass() throws Exception {
     TestCaseUtils.startServer();
@@ -68,6 +75,13 @@
     addRootEntry();
   }
 
+  @AfterClass
+  public void tearDown() throws Exception {
+    String aciLdif=makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
+            G_READ_ACI, G_SELF_MOD, G_SCHEMA, G_DSE, G_USER_OPS, G_CONTROL);
+    LDIFModify(aciLdif, DIR_MGR_DN, PWD);
+  }
+
 
   /**
    * This test uses an ACI allowing access to the userPassword attribute, based
@@ -117,7 +131,7 @@
    */
   @Test()
   public void testAlternateProxyDNs() throws Exception {
-    String aciLdif=makeAddLDIF("aci", user1, rootDNACI, proxyACI);
+    String aciLdif=makeAddLDIF("aci", user1, rootDNACI, proxyACI, controlACI);
     LDIFModify(aciLdif, DIR_MGR_DN, PWD);
     String adminDNResults =
             LDAPSearchParams(user3, PWD, adminDN, null, null,
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java
index 2d5af24..73cd2dd 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/GetEffectiveRightsTestCase.java
@@ -30,10 +30,12 @@
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.AfterClass;
 import static org.opends.server.config.ConfigConstants.*;
 import org.testng.Assert;
 import org.opends.server.TestCaseUtils;
 import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
+
 import java.util.HashMap;
 
 public class GetEffectiveRightsTestCase extends AciTestCase {
@@ -86,6 +88,12 @@
           "selfwrite_add:1,selfwrite_delete:1,proxy:0";
 
   //ACI needed to search/read aciRights attribute.
+
+  //Need an ACI to allow proxy control
+  String controlACI = "(targetcontrol=\"" + OID_GET_EFFECTIVE_RIGHTS + "\")" +
+          "(version 3.0; acl \"control\";" +
+          "allow(read) userdn=\"ldap:///anyone\";)";
+
   private static final
   String aclRightsAci = "(targetattr=\"aclRights\")" +
           "(version 3.0;acl \"aclRights access\";" +
@@ -160,10 +168,17 @@
     addEntries();
   }
 
-    @BeforeMethod
-    public void removeAcis() throws Exception {
+  @AfterClass
+  public void tearDown() throws Exception {
+       String aciLdif=makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
+               G_READ_ACI, G_SELF_MOD, G_SCHEMA, G_DSE, G_USER_OPS, G_CONTROL);
+       LDIFModify(aciLdif, DIR_MGR_DN, PWD);
+   }
+
+   @BeforeMethod
+   public void removeAcis() throws Exception {
         deleteAttrFromEntry("ou=People,o=test", "aci");
-  }
+   }
 
   /**
    * Test entry level using the -g param and anonymous dn as the authzid.
@@ -172,7 +187,8 @@
    */
   @Test()
   public void testAnonEntryLevelParams() throws Exception {
-    String aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAnonAci);
+    String aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAnonAci,
+                               controlACI);
     LDIFModify(aciLdif, DIR_MGR_DN, PWD);
     String userResults =
             LDAPSearchParams(DIR_MGR_DN, PWD, null, "dn:", null,
@@ -190,7 +206,8 @@
    */
   @Test()
   public void testSuEntryLevelParams() throws Exception {
-    String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci);
+    String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci,
+                               controlACI);
     LDIFModify(aciLdif, DIR_MGR_DN, PWD);
     aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAci);
     LDIFModify(aciLdif, DIR_MGR_DN, PWD);
@@ -242,7 +259,8 @@
    */
   @Test()
    public void testSuEntryLevelCtrl() throws Exception {
-     String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci);
+     String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci,
+                                controlACI);
      LDIFModify(aciLdif, DIR_MGR_DN, PWD);
      aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAci);
      LDIFModify(aciLdif, DIR_MGR_DN, PWD);
@@ -294,6 +312,8 @@
   */
  @Test()
   public void testBypassEntryLevelCtrl() throws Exception {
+    String aciLdif=makeAddLDIF("aci", "ou=People,o=test",  controlACI);
+    LDIFModify(aciLdif, DIR_MGR_DN, PWD);
     String userResults =
            LDAPSearchCtrl(DIR_MGR_DN, PWD, null, OID_GET_EFFECTIVE_RIGHTS,
                    base, filter, "aclRights");
@@ -311,7 +331,8 @@
    */
   @Test()
   public void testSuAttrLevelParams() throws Exception {
-    String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci);
+    String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci,
+                               controlACI);
     LDIFModify(aciLdif, DIR_MGR_DN, PWD);
     aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAci);
     LDIFModify(aciLdif, DIR_MGR_DN, PWD);
@@ -337,7 +358,8 @@
  */
 @Test()
 public void testSuAttrLevelParams2() throws Exception {
-  String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci);
+  String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci,
+                             controlACI);
   LDIFModify(aciLdif, DIR_MGR_DN, PWD);
   aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAci);
   LDIFModify(aciLdif, DIR_MGR_DN, PWD);
@@ -369,7 +391,8 @@
  */
 @Test()
 public void testSuAttrLevelParams3() throws Exception {
-  String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci);
+  String aciLdif=makeAddLDIF("aci", "ou=People,o=test", aclRightsAci,
+                            controlACI);
   LDIFModify(aciLdif, DIR_MGR_DN, PWD);
   aciLdif=makeAddLDIF("aci", "ou=People,o=test", readSearchAci);
   LDIFModify(aciLdif, DIR_MGR_DN, PWD);
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
index ae2e545..e8969e4 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetAttrTestCase.java
@@ -29,6 +29,7 @@
 
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
+import org.testng.annotations.AfterClass;
 import org.testng.Assert;
 import org.opends.server.TestCaseUtils;
 import static org.opends.server.config.ConfigConstants.*;
@@ -125,6 +126,14 @@
     addEntries();
   }
 
+  @AfterClass
+  public void tearDown() throws Exception {
+     String aciLdif=makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
+          G_READ_ACI, G_SELF_MOD, G_SCHEMA, G_DSE, G_USER_OPS, G_CONTROL);
+     LDIFModify(aciLdif, DIR_MGR_DN, PWD);
+  }
+
+
   /**
    * Test targetattr behavior using userattr bind rule.
    *
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java
new file mode 100644
index 0000000..81e47c4
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java
@@ -0,0 +1,342 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+
+
+package org.opends.server.authorization.dseecompat;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.AfterClass;
+import org.opends.server.TestCaseUtils;
+import org.opends.server.protocols.ldap.LDAPResultCode;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.config.ConfigConstants.ATTR_AUTHZ_GLOBAL_ACI;
+
+/**
+ * Unit test to test the targetcontrol ACI keyword.
+ */
+public class TargetControlTestCase extends AciTestCase {
+
+  private static final String superUser="uid=superuser,ou=admins,o=test";
+  private static final String level3User="uid=user.3,ou=People,o=test";
+  private static final String newPWD="newPWD";
+
+
+  private static final String level1User="uid=user.1,ou=People,o=test";
+  private static final String base="uid=user.3,ou=People,o=test";
+  private static final String newRDN = "uid=user.3x";
+  private static final String newSup="ou=new,o=test";
+  private static final String newDN="uid=user.4," + base;
+
+  private static final String peopleBase="ou=People,o=test";
+  private static final String adminBase="ou=Admins,o=test";
+  private static final String newPeopleDN="uid=user.4," + peopleBase;
+  private static final String newAdminDN="uid=user.4," + adminBase;
+
+
+  @BeforeClass
+  public void setupClass() throws Exception {
+    TestCaseUtils.startServer();
+    deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
+    addEntries();
+  }
+
+  @AfterClass
+  public void tearDown() throws Exception {
+       String aciLdif=makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
+               G_READ_ACI, G_SELF_MOD, G_SCHEMA, G_DSE, G_USER_OPS, G_CONTROL);
+       LDIFModify(aciLdif, DIR_MGR_DN, PWD);
+   }
+
+  private static final String[] newEntry = new String[] {
+    "objectClass: top",
+    "objectClass: person",
+    "objectClass: organizationalPerson",
+    "objectClass: inetOrgPerson",
+    "uid: john.doe",
+    "givenName: John",
+    "sn: Doe",
+    "cn: John Doe",
+    "mail: john.doe@example.com",
+    "userPassword: password",
+  };
+
+  //Valid targetcontrol statements. Not the complete ACI.
+  @DataProvider(name = "validStatements")
+  public Object[][] valids() {
+    return new Object[][] {
+            {"1.3.6.1.4.1.42.2.27.8.5.1"},
+            {"2.16.840.1.113730.3.4.18"},
+            {"*"},
+    };
+  }
+
+   //Invalid targetcontrol statements. Not the complete ACI.
+  @DataProvider(name = "invalidStatements")
+  public Object[][] invalids() {
+    return new Object[][] {
+            {"1.3.6.1.4.1.42.2.27..8.5.1"},
+            {"2.16.840.1.113730.3.XXX.18"},
+            {"2.16.840.1.113730.*.4.18"},
+            {"2.16.840,1.113730.3.4.18"},
+            {"+"},
+    };
+  }
+
+  private static final
+  String ALLOW_ALL = "(targetattr=\"*\")" +
+          "(version 3.0;acl \"aclRights access\";" +
+          "allow (all) " +
+          "userdn=\"ldap:///self\";)";
+
+  private static final
+  String aclRightsAci = "(targetattr=\"aclRights\")" +
+          "(version 3.0;acl \"aclRights access\";" +
+          "allow (search, read) " +
+          "userdn=\"ldap:///uid=superuser,ou=admins,o=test\";)";
+
+ //Disallow all controls with wild-card.
+  private static final
+  String controlNotWC = "(targetcontrol!=\"" + "*" + "\")" +
+          "(version 3.0; acl \"control\";" +
+          "allow(read) userdn=\"ldap:///" + superUser + "\";)";
+
+  //Allow all controls with wild-card.
+  private static final
+  String controlWC = "(targetcontrol=\"" + "*" + "\")" +
+          "(version 3.0; acl \"control\";" +
+          "allow(read) userdn=\"ldap:///" + superUser + "\";)";
+
+  //People branch can do any control but geteffectiverights assertion control.
+  private static final
+  String controlPeople = "(targetcontrol!=\"" +
+          OID_GET_EFFECTIVE_RIGHTS + "\")" +
+          "(target=\"ldap:///" + peopleBase + "\")" +
+          "(version 3.0; acl \"control\";" +
+          "allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
+
+  //Admin branch can only do geteffectiverights control.
+  private static final
+  String controlAdmin = "(targetcontrol=\"" + OID_GET_EFFECTIVE_RIGHTS + "\")" +
+          "(target=\"ldap:///" + adminBase + "\")" +
+          "(version 3.0; acl \"control\";" +
+          "allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
+
+  //Allow either reportauthzID or passwordpolicy controls. Used in the
+  //bind tests.
+  private static final
+  String pwdControls =
+          "(targetcontrol=\"" + OID_AUTHZID_REQUEST + "||" +
+          OID_PASSWORD_POLICY_CONTROL + "\")" +
+          "(version 3.0; acl \"control\";" +
+          "allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
+
+
+  //Allow either no-op or passwordpolicy controls. Used in the
+  //ext op tests.
+  private static final
+  String extOpControls =
+          "(targetcontrol=\"" + OID_LDAP_NOOP_OPENLDAP_ASSIGNED + "||" +
+          OID_PASSWORD_POLICY_CONTROL + "\")" +
+          "(version 3.0; acl \"control\";" +
+          "allow(read) userdn=\"ldap:///" + "anyone" + "\";)";
+
+
+  /**
+   * Test valid targetcontrol statements.
+   *
+   * @param statement The targetcontrol statement to attempt to decode.
+   * @throws AciException  If an unexpected result happens.
+   */
+  @Test(dataProvider = "validStatements")
+  public void testValidStatements(String statement) throws AciException {
+      TargetControl.decode(EnumTargetOperator.EQUALITY, statement);
+  }
+
+  /**
+   * Test invalid targetcontrol statements.
+   *
+   * @param statement The targetcontrol statement to attempt to decode.
+   * @throws Exception  If an unexpected result happens.
+   */
+  @Test(expectedExceptions= AciException.class, dataProvider="invalidStatements")
+  public void testInvalidStatements(String statement)  throws Exception {
+    try {
+      TargetControl.decode(EnumTargetOperator.EQUALITY,statement);
+    } catch (AciException e) {
+      throw e;
+    } catch (Exception e) {
+      System.out.println(
+              "Invalid targetcontrol  <" + statement +
+              "> threw wrong exception type.");
+      throw e;
+    }
+    throw new RuntimeException(
+            "Invalid targetcontrol <" + statement +
+            "> did not throw an exception.");
+  }
+
+  /**
+   * Test access to extended op controls (no-op and userPasswordPolicy).
+   *
+   * @throws Exception If an unexpected result is returned.
+   */
+  @Test()
+  public void testExtendOpControls() throws Exception {
+   String pwdLdifs =
+        makeAddLDIF("aci", peopleBase, extOpControls, ALLOW_ALL);
+    LDIFModify(pwdLdifs, DIR_MGR_DN, PWD);
+    String noOpCtrlStr=OID_LDAP_NOOP_OPENLDAP_ASSIGNED + ":true";
+    //This pwd change should return no-op since the no-op control is
+    //specified and it is allowed for authorization dn.
+    pwdModify(level3User, PWD, newPWD, noOpCtrlStr, null,
+            LDAPResultCode.NO_OPERATION);
+    //This pwd change should fail even though the no-op is specified, since
+    //since the no-op control is not allowed for this authorization dn.
+    pwdModify(superUser, PWD, newPWD, noOpCtrlStr, null,
+            LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+    deleteAttrFromEntry(peopleBase, "aci");
+  }
+
+  /**
+   * Test access to bind controls (reportAuthzID and usePasswordPolicy).
+   *
+   * @throws Exception If an unexpected result is returned.
+   */
+  @Test()
+  public void testBindControl() throws Exception {
+    String pwdLdifs =
+            makeAddLDIF("aci", peopleBase, pwdControls, ALLOW_ALL);
+    LDIFModify(pwdLdifs, DIR_MGR_DN, PWD);
+    //The bind operation control access is based on the  bind DN so this
+    //should succeed since both pwd policy and authzID control are allowed on
+    //ou=people, o=test suffix.
+    LDAPSearchParams(level3User, PWD, null, null, null,
+            superUser, filter, "aclRights mail description", true,
+            false, 0);
+    LDAPSearchParams(level3User, PWD, null, null, null,
+            superUser, filter, "aclRights mail description", true,
+            true, 0);
+    //This should fail since the both controls are not allowed for the
+    //ou=admins, o=test suffix.
+    LDAPSearchParams(superUser, PWD, null, null, null,
+            superUser, filter, "aclRights mail description", true,
+            true, LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+    deleteAttrFromEntry(peopleBase, "aci");
+  }
+
+  /**
+   * Test target from global ACI level. Two global ACIs are added, one allowing
+   * all controls except geteffective rights to the ou=people, o=test
+   * suffix. The other ACI only allows the geteffectiverights control on
+   * the ou=admin, o=test suffix. Comments in method should explain more
+   * what operations and controls are attempted.
+   *
+   * @throws Exception If an unexpected result happens.
+   */
+  @Test()
+  public void testGlobalTargets() throws Exception {
+    String globalControlAcis=
+            makeAddLDIF(ATTR_AUTHZ_GLOBAL_ACI, ACCESS_HANDLER_DN,
+                    controlAdmin, controlPeople);
+    LDIFModify(globalControlAcis, DIR_MGR_DN, PWD);
+    //Fails because geteffectiverights control not allowed on
+    //ou=people, o=test
+    LDAPSearchParams(level3User, PWD, null,
+            "dn: " + level1User, null,
+            level1User, filter, "aclRights mail description",
+            false, false, LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+    //Ok because geteffectiverights control is allowed on
+    //ou=admin, o=test
+    LDAPSearchParams(level3User, PWD, null,
+            "dn: " + level1User, null,
+            superUser, filter, "aclRights mail description",
+            false, false, 0);
+    String controlStr=OID_LDAP_ASSERTION + ":true:junk";
+    //Test add to ou=people, o=test with assertion control,
+    //should get protocol error since this control is allowed but value is
+    //junk.
+    String addEntryLDIF=makeAddEntryLDIF(newPeopleDN, newEntry);
+    LDIFAdd(addEntryLDIF, superUser, PWD, controlStr,
+            LDAPResultCode.PROTOCOL_ERROR);
+    //Test add to ou=admin, o=test with assertion control,
+    //should get access denied since this control is not allowed.
+    String addEntryLDIF1=makeAddEntryLDIF(newAdminDN, newEntry);
+    LDIFAdd(addEntryLDIF1, superUser, PWD, controlStr,
+            LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+    deleteAttrFromEntry(ACCESS_HANDLER_DN, ATTR_AUTHZ_GLOBAL_ACI);
+  }
+
+
+  /**
+   * Test wildcard access. First test "targetcontrol != *"
+   * expression. Should all be access denied. Remove that ACI and add
+   * "targetcontrol = *" expression. Use assertion control with bad filter,
+   * all should return protocol error (modify, add, delete, modifyDN). Search
+   * with geteffectiverights should succeed.
+   *
+   * @throws Exception If an unexpected result happens.
+   */
+  @Test()
+  public void testWildCard() throws Exception {
+
+    String aciDeny=makeAddLDIF("aci", base, controlNotWC);
+    String aciRight=makeAddLDIF("aci", base, aclRightsAci);
+    LDIFModify(aciDeny, DIR_MGR_DN, PWD);
+    LDAPSearchParams(superUser, PWD, null,
+            "dn: " + superUser, null,
+            base, filter, "aclRights mail description", false, false,
+            LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+    LDIFModify(aciRight, superUser, PWD, OID_LDAP_READENTRY_PREREAD,
+            LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+    deleteAttrFromEntry (base, "aci");
+    String aciAllow=makeAddLDIF("aci", base, controlWC, ALLOW_ALL);
+    LDIFModify(aciAllow, DIR_MGR_DN, PWD);
+    //Search with geteffectiverights control.
+    LDAPSearchParams(superUser, PWD, null,
+            "dn: " + superUser, null,
+            base, filter, "aclRights mail description");
+    String controlStr=OID_LDAP_ASSERTION + ":true:junk";
+    //Attempt modify. Protocol error means we  passed access control
+    LDIFModify(aciRight, superUser, PWD, controlStr ,
+            LDAPResultCode.PROTOCOL_ERROR);
+    //Attempt add, protocol error means we  passed access control
+    String addEntryLDIF=makeAddEntryLDIF(newDN, newEntry);
+    LDIFAdd(addEntryLDIF, superUser, PWD, controlStr,
+            LDAPResultCode.PROTOCOL_ERROR);
+    //Attempt delete. Protocol error means we  passed access control.
+    LDIFDelete(base, superUser, PWD, controlStr,
+            LDAPResultCode.PROTOCOL_ERROR);
+    String modDNLDIF=makeModDNLDIF(base, newRDN , "0", newSup);
+    //Attempt modify DN. Protocol error means we  passed access control.
+    LDIFModify(modDNLDIF, superUser, PWD, controlStr ,
+            LDAPResultCode.PROTOCOL_ERROR);
+    deleteAttrFromEntry(base, "aci");
+  }
+}
+

--
Gitblit v1.10.0