From 91fdf0048df4c43fe3b7412ccb7f862eab5f7669 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Wed, 02 Feb 2011 20:45:14 +0000
Subject: [PATCH] Fix issue OPENDJ-24: Fix OpenDS issue 4583: during a search op, ACI with targetfilter and targetattrs gets evaluated wrongly  https://bugster.forgerock.org/jira/browse/OPENDJ-24

---
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java   |  117 -----
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java   |  170 +++++++
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java |  118 -----
 opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java                      |   63 --
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java  |    2 
 opends/src/server/org/opends/server/api/AccessControlHandler.java                                   |   63 +-
 opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java                        |  155 ++----
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java      |   72 --
 opends/src/server/org/opends/server/core/SearchOperationBasis.java                                  |   32 
 opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java                           |   33 -
 opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java                    |   28 -
 opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java         |   44 -
 opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java                          |   44 -
 opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java  |    2 
 opends/src/server/org/opends/server/authorization/dseecompat/AciEffectiveRights.java                |  300 +++++++------
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java   |   63 --
 16 files changed, 500 insertions(+), 806 deletions(-)

diff --git a/opends/src/server/org/opends/server/api/AccessControlHandler.java b/opends/src/server/org/opends/server/api/AccessControlHandler.java
index 6f5f534..b5f3b82 100644
--- a/opends/src/server/org/opends/server/api/AccessControlHandler.java
+++ b/opends/src/server/org/opends/server/api/AccessControlHandler.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.api;
 
@@ -347,36 +348,18 @@
    * the client. Implementations <b>must not under any
    * circumstances</b> modify the search entry in any way.
    *
-   * @param searchOperation
-   *          The search operation with which the provided entry is
-   *          associated.
-   * @param searchEntry
-   *          The search result entry for which to make the
-   *          determination.
+   * @param operation
+   *          The operation currently being processed (this will
+   *          usually be a search, but may be other types of operation
+   *          when pre/post read controls are used).
+   * @param unfilteredEntry
+   *          The result entry before any attribute filtering.
    * @return {@code true} if the access control configuration allows
    *         the entry to be returned to the client, or {@code false}
    *         if not.
    */
-  public abstract boolean maySend(SearchOperation searchOperation,
-      SearchResultEntry searchEntry);
-
-
-
-  /**
-   * Filter the contents of the provided entry such that it no longer
-   * contains any attributes or values that the client is not
-   * permitted to access.
-   *
-   * @param searchOperation
-   *          The search operation with which the provided entry is
-   *          associated.
-   * @param searchEntry
-   *          The search result entry to be filtered.
-   * @return Returns the entry with filtered attributes and values
-   *         removed.
-   */
-  public abstract SearchResultEntry filterEntry(
-      SearchOperation searchOperation, SearchResultEntry searchEntry);
+  public abstract boolean maySend(Operation operation,
+      SearchResultEntry unfilteredEntry);
 
 
 
@@ -386,15 +369,18 @@
    * permitted to access.
    *
    * @param operation
-   *          The operation with which the provided entry is
-   *          associated.
-   * @param entry
-   *          The entry to be filtered.
-   * @return Returns the entry with filtered attributes and values
-   *         removed.
+   *          The operation currently being processed (this will
+   *          usually be a search, but may be other types of operation
+   *          when pre/post read controls are used).
+   * @param unfilteredEntry
+   *          The result entry before any attribute filtering.
+   * @param filteredEntry
+   *          The partially filtered result entry being returned to
+   *          the client.
    */
-  public abstract SearchResultEntry filterEntry(
-      Operation operation, Entry entry);
+  public abstract void filterEntry(Operation operation,
+      SearchResultEntry unfilteredEntry,
+      SearchResultEntry filteredEntry);
 
 
 
@@ -404,8 +390,8 @@
    *
    * @param dn
    *          A DN that can be used in the access determination.
-   * @param searchOperation
-   *          The search operation with which the provided reference
+   * @param operation
+   *          The operation with which the provided reference
    *          is associated.
    * @param searchReference
    *          The search result reference for which to make the
@@ -414,9 +400,8 @@
    *         the reference to be returned to the client, or {@code
    *         false} if not.
    */
-  public abstract boolean maySend(DN dn,
-                               SearchOperation searchOperation,
-                               SearchResultReference searchReference);
+  public abstract boolean maySend(DN dn, Operation operation,
+      SearchResultReference searchReference);
 
 
 
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
index d12f2bf..2bb31ce 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2008 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 
 package org.opends.server.authorization.dseecompat;
@@ -103,13 +104,6 @@
     private Entry resourceEntry;
 
     /*
-     * Saves the resource entry. Used in geteffectiverights evaluation to
-     * restore the current resource entry state after a read right was
-     * evaluated.
-     */
-    private final Entry saveResourceEntry;
-
-    /*
      * The client connection information.
      */
     private final ClientConnection clientConnection;
@@ -187,12 +181,6 @@
     private List<AttributeType> specificAttrs=null;
 
     /*
-     * The entry with all of its attributes available. Used in
-     * geteffectiverights read entry level evaluation.
-     */
-    private Entry fullEntry=null;
-
-    /*
      * Table of ACIs that have targattrfilter keywords that matched. Used
      * in geteffectiverights attributeLevel write evaluation.
      */
@@ -278,26 +266,29 @@
       if(origAuthorizationEntry != null)
          this.proxiedAuthorization=true;
       this.authorizationEntry=operation.getAuthorizationEntry();
+
       //The ACI_READ right at constructor time can only be the result of the
       //AciHandler.filterEntry method. This method processes the
       //geteffectiverights control, so it needs to check for it.  There are
       //two other checks done, because the resource entry passed to that method
       //is filtered (it may not contain enough attribute information
       //to evaluate correctly). See the the comments below.
-      if(operation instanceof SearchOperation && (rights == ACI_READ)) {
+      if (rights == ACI_READ) {
         //Checks if a geteffectiverights control was sent and
         //sets up the structures needed.
         GetEffectiveRightsRequestControl getEffectiveRightsControl =
               (GetEffectiveRightsRequestControl)
                       operation.getAttachment(OID_GET_EFFECTIVE_RIGHTS);
-        if(getEffectiveRightsControl != null) {
-          hasGetEffectiveRightsControl=true;
-          if(getEffectiveRightsControl.getAuthzDN() == null)
-            this.authzid=getClientDN();
-          else
-            this.authzid=getEffectiveRightsControl.getAuthzDN();
-          this.specificAttrs=getEffectiveRightsControl.getAttributes();
+        if (getEffectiveRightsControl != null
+            && operation instanceof SearchOperation)
+        {
+          hasGetEffectiveRightsControl = true;
+          if (getEffectiveRightsControl.getAuthzDN() == null)
+            this.authzid = getClientDN();
+          else this.authzid = getEffectiveRightsControl.getAuthzDN();
+          this.specificAttrs = getEffectiveRightsControl.getAttributes();
         }
+
         //If an ACI evaluated because of an Targetattr="*", then the
         //AciHandler.maySend method signaled this via adding this attachment
         //string.
@@ -311,16 +302,11 @@
         String allOpAttrs=(String)operation.getAttachment(ALL_OP_ATTRS_MATCHED);
         if(allOpAttrs != null)
           evalAllAttributes |= ACI_OP_ATTR_PLUS_MATCHED;
+      }
 
-        //The AciHandler.maySend method also adds the full attribute version of
-        //the resource entry in this attachment.
-        fullEntry=(Entry)operation.getAttachment(ALL_ATTRS_RESOURCE_ENTRY);
-      } else
-        fullEntry=this.resourceEntry;
       //Reference the current authorization entry, so it can be put back
       //if an access proxy check was performed.
       this.saveAuthorizationEntry=this.authorizationEntry;
-      this.saveResourceEntry=this.resourceEntry;
       this.rightsMask = rights;
     }
 
@@ -341,7 +327,6 @@
         this.authInfo = authInfo;
         this.authorizationEntry = authInfo.getAuthorizationEntry();
         this.saveAuthorizationEntry=this.authorizationEntry;
-        this.saveResourceEntry=this.resourceEntry;
         this.rightsMask = rights;
     }
   /**
@@ -419,28 +404,6 @@
        return this.specificAttrs;
     }
 
-  /**
-   * During the geteffectiverights entrylevel read evaluation, an entry with all
-   * of the attributes used in the AciHandler's maysend method evaluation is
-   * needed to perform the evaluation over again. This entry was saved
-   * in the operation's attachment mechanism when the container was created
-   * during the SearchOperation read evaluation.
-   *
-   * This method is used to replace the current resource entry with that saved
-   * entry to perform the entrylevel read evaluation described above and to
-   * switch back to the current resource entry when needed.
-   *
-   * @param val Specifies if the saved entry should be used or not. True if it
-   * should be used, false if the original resource entry should be used.
-   *
-   */
-    public void useFullResourceEntry(boolean val) {
-      if(val)
-        resourceEntry=fullEntry;
-      else
-        resourceEntry=saveResourceEntry;
-    }
-
    /**
     * {@inheritDoc}
     */
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciEffectiveRights.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciEffectiveRights.java
index 45296a1..a09880c 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciEffectiveRights.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciEffectiveRights.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2008 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 
 package org.opends.server.authorization.dseecompat;
@@ -186,123 +187,148 @@
    * @param e The entry to add the rights attributes to.
    * @param skipCheck  True if ACI evaluation was skipped because bypass-acl
    *                   privilege was found.
-   * @return  A SearchResultEntry with geteffectiverights information possibly
-   *          added to it.
    */
-  public static SearchResultEntry
-  addRightsToEntry(AciHandler handler, LinkedHashSet<String> searchAttributes,
-            AciLDAPOperationContainer container,SearchResultEntry e,
-            boolean skipCheck) {
-    List<AttributeType> nonRightsAttrs = new LinkedList<AttributeType>();
-    int attrMask=ACI_NULL;
-    if(aclRights == null)
-      aclRights =
-               DirectoryServer.getAttributeType(aclRightsAttrStr.toLowerCase());
-    if(aclRightsInfo == null)
-      aclRightsInfo =
-           DirectoryServer.getAttributeType(aclRightsInfoAttrStr.toLowerCase());
-    if(dnAttributeType == null)
+  public static void addRightsToEntry(AciHandler handler,
+      LinkedHashSet<String> searchAttributes,
+      AciLDAPOperationContainer container, final Entry e,
+      boolean skipCheck)
+  {
+    if (aclRights == null)
+    {
+      aclRights = DirectoryServer.getAttributeType(aclRightsAttrStr
+          .toLowerCase());
+    }
+
+    if (aclRightsInfo == null)
+    {
+      aclRightsInfo = DirectoryServer.getAttributeType(aclRightsInfoAttrStr
+          .toLowerCase());
+    }
+
+    if (dnAttributeType == null)
+    {
       dnAttributeType = DirectoryServer.getAttributeType(dnAttrStr);
-    //Check if the attributes aclRights and aclRightsInfo were requested and
-    //add attributes less those two attributes to a new list of attribute types.
-    for(String a : searchAttributes) {
-      if(a.equalsIgnoreCase(aclRightsAttrStr))
+    }
+
+    // Check if the attributes aclRights and aclRightsInfo were requested and
+    // add attributes less those two attributes to a new list of attribute
+    // types.
+    List<AttributeType> nonRightsAttrs = new LinkedList<AttributeType>();
+    int attrMask = ACI_NULL;
+    for (String a : searchAttributes)
+    {
+      if (a.equalsIgnoreCase(aclRightsAttrStr))
+      {
         attrMask |= ACL_RIGHTS;
-      else if(a.equalsIgnoreCase(aclRightsInfoAttrStr))
+      }
+      else if (a.equalsIgnoreCase(aclRightsInfoAttrStr))
+      {
         attrMask |= ACL_RIGHTS_INFO;
-      else {
-          //Check for shorthands for user attributes "*" or operational "+".
-          if(a.equals("*")) {
-              //Add objectclass.
-              AttributeType ocType =
-                      DirectoryServer.getObjectClassAttributeType();
-              nonRightsAttrs.add(ocType);
-              nonRightsAttrs.addAll(e.getUserAttributes().keySet());
-          } else if (a.equals("+"))
-              nonRightsAttrs.addAll(e.getOperationalAttributes().keySet());
-          else {
-              AttributeType attrType;
-              if((attrType =
-                  DirectoryServer.getAttributeType(a.toLowerCase())) == null)
-                  attrType =
-                      DirectoryServer.getDefaultAttributeType(a.toLowerCase());
-              nonRightsAttrs.add(attrType);
-          }
+      }
+      else
+      {
+        // Check for shorthands for user attributes "*" or operational "+".
+        if (a.equals("*"))
+        {
+          // Add objectclass.
+          AttributeType ocType = DirectoryServer.getObjectClassAttributeType();
+          nonRightsAttrs.add(ocType);
+          nonRightsAttrs.addAll(e.getUserAttributes().keySet());
+        }
+        else if (a.equals("+"))
+        {
+          nonRightsAttrs.addAll(e.getOperationalAttributes().keySet());
+        }
+        else
+        {
+          AttributeType attrType = DirectoryServer.getAttributeType(a
+              .toLowerCase());
+          if (attrType == null)
+            attrType = DirectoryServer.getDefaultAttributeType(a.toLowerCase());
+          nonRightsAttrs.add(attrType);
+        }
       }
     }
-      //If the special geteffectiverights attributes were not found or
-    //the user does not have both bypass-acl privs and is not allowed to
-    //perform rights evalation -- return the entry unchanged.
-    if(attrMask == ACI_NULL ||
-      (!skipCheck && !rightsAccessAllowed(container,handler,attrMask)))
-       return e;
-    //From here on out, geteffectiverights evaluation is being performed and the
-    //container will be manipulated. First set the flag that geteffectiverights
-    //evaluation's underway and to use the authZid for authorizationDN (they
-    //might be the same).
+
+    // If the special geteffectiverights attributes were not found or
+    // the user does not have both bypass-acl privs and is not allowed to
+    // perform rights evalation -- return the entry unchanged.
+    if (attrMask == ACI_NULL
+        || (!skipCheck && !rightsAccessAllowed(container, handler, attrMask)))
+    {
+      return;
+    }
+
+    // From here on out, geteffectiverights evaluation is being performed and
+    // the container will be manipulated. First set the flag that
+    // geteffectiverights evaluation's underway and to use the authZid for
+    // authorizationDN (they might be the same).
     container.setGetEffectiveRightsEval();
     container.useAuthzid(true);
-    //If no attributes were requested return only entryLevel rights, else
-    //return attributeLevel rights and entryLevel rights. Always try and
-    //return the specific attribute rights if they exist.
-    if(nonRightsAttrs.isEmpty()) {
-      e=addAttributeLevelRights(container,handler,attrMask,e,
-              container.getSpecificAttributes(), skipCheck, true);
-      e=addEntryLevelRights(container,handler,attrMask,e, skipCheck);
-    } else {
-      e=addAttributeLevelRights(container,handler,attrMask,e,
-              nonRightsAttrs, skipCheck, false);
-      e=addAttributeLevelRights(container,handler,attrMask,e,
-              container.getSpecificAttributes(), skipCheck, true);
-      e=addEntryLevelRights(container,handler,attrMask,e,skipCheck);
+
+    // If no attributes were requested return only entryLevel rights, else
+    // return attributeLevel rights and entryLevel rights. Always try and
+    // return the specific attribute rights if they exist.
+    if (nonRightsAttrs.isEmpty())
+    {
+      addAttributeLevelRights(container, handler, attrMask, e,
+          container.getSpecificAttributes(), skipCheck, true);
+      addEntryLevelRights(container, handler, attrMask, e, skipCheck);
     }
-    return e;
+    else
+    {
+      addAttributeLevelRights(container, handler, attrMask, e, nonRightsAttrs,
+          skipCheck, false);
+      addAttributeLevelRights(container, handler, attrMask, e,
+          container.getSpecificAttributes(), skipCheck, true);
+      addEntryLevelRights(container, handler, attrMask, e, skipCheck);
+    }
   }
 
 
+
   /**
    * Perform the attributeLevel rights evaluation on a list of specified
    * attribute types. Each attribute has an access check done for the following
    * rights: search, read, compare, add, delete, proxy, selfwrite_add,
-   * selfwrite_delete and write.
+   * selfwrite_delete and write. The special rights, selfwrite_add and
+   * selfwrite_delete, use the authZid as the attribute value to evaluate
+   * against the attribute type being evaluated. The selfwrite_add performs the
+   * access check using the ACI_WRITE_ADD right and selfwrite_delete uses
+   * ACI_WRITE_ADD right. The write right is made complicated by the
+   * targattrfilters keyword, which might depend on an unknown value of an
+   * attribute type. For this case a dummy attribute value is used to try and
+   * determine if a "?" needs to be placed in the rights string. The special
+   * flag ACI_SKIP_PROXY_CHECK is always set, so that proxy evaluation is
+   * bypassed in the Aci Handler's accessAllowed method.
    *
-   * The special rights, selfwrite_add and selfwrite_delete, use the authZid as
-   * the attribute value to evaluate against the attribute type being
-   * evaluated. The selfwrite_add performs the access check using the
-   * ACI_WRITE_ADD right and selfwrite_delete uses ACI_WRITE_ADD right.
-   *
-   * The write right is made complicated by the targattrfilters keyword, which
-   * might depend on an unknown value of an attribute type. For this case a
-   * dummy attribute value is used to try and determine if a "?" needs to be
-   * placed in the rights string.
-   *
-   * The special flag ACI_SKIP_PROXY_CHECK is always set, so that proxy
-   * evaluation is bypassed in the Aci Handler's accessAllowed method.
-   *
-   * @param container The LDAP operation container to use in the evaluations.
-   * @param handler  The Aci Handler to use in the access evaluations.
-   * @param mask  Mask specifing what rights attribute processing to perform
-   *              (aclRights or aclRightsInfo or both).
-   * @param retEntry  The entry to return.
-   * @param attrList The list of attribute types to iterate over.
-   * @param skipCheck True if ACI evaluation was skipped because bypass-acl
-   *                  privilege was found.
-   * @param  specificAttr True if this evaluation is result of specific
-   *                      attributes sent in the request.
-   * @return  A SearchResultEntry with geteffectiverights attribute level
-   *          information added to it.
+   * @param container
+   *          The LDAP operation container to use in the evaluations.
+   * @param handler
+   *          The Aci Handler to use in the access evaluations.
+   * @param mask
+   *          Mask specifing what rights attribute processing to perform
+   *          (aclRights or aclRightsInfo or both).
+   * @param retEntry
+   *          The entry to return.
+   * @param attrList
+   *          The list of attribute types to iterate over.
+   * @param skipCheck
+   *          True if ACI evaluation was skipped because bypass-acl privilege
+   *          was found.
+   * @param specificAttr
+   *          True if this evaluation is result of specific attributes sent in
+   *          the request.
    */
-  private static
-  SearchResultEntry addAttributeLevelRights(AciLDAPOperationContainer container,
-                                        AciHandler handler, int mask,
-                                        SearchResultEntry retEntry,
-                                        List<AttributeType> attrList,
-                                        boolean skipCheck,
-                                        boolean specificAttr) {
+  private static void addAttributeLevelRights(
+      AciLDAPOperationContainer container, AciHandler handler, int mask,
+      final Entry retEntry, List<AttributeType> attrList,
+      boolean skipCheck, boolean specificAttr)
+  {
 
-    //The attribute list might be null.
-    if(attrList == null)
-      return retEntry;
+    // The attribute list might be null.
+    if (attrList == null) return;
+
     for(AttributeType a : attrList) {
       StringBuilder evalInfo=new StringBuilder();
       container.setCurrentAttributeType(a);
@@ -371,33 +397,34 @@
     }
     container.setCurrentAttributeValue(null);
     container.setCurrentAttributeType(null);
-    return retEntry;
   }
 
+
+
   /**
    * Perform the attributeLevel write rights evaluation. The issue here is that
    * an ACI could contain a targattrfilters keyword that matches the attribute
-   * being evaluated.
+   * being evaluated. There is no way of knowing if the filter part of the
+   * targattrfilter would be successful or not. So if the ACI that allowed
+   * access, has an targattrfilter keyword, a "?" is used as the result of the
+   * write (depends on attribute value). If the allow ACI doesn't contain a
+   * targattrfilters keyword than a "1" is added. If the ACI denies then a "0"
+   * is added. If the skipCheck flag is true, then a 1 is used for the write
+   * access, since the client DN has bypass privs.
    *
-   * There is no way of knowing if the filter part of the targattrfilter would
-   * be successful or not. So if the ACI that allowed access, has an
-   * targattrfilter keyword, a "?" is used as the result of the write (depends
-   * on attribute value).
-   *
-   * If the allow ACI doesn't contain a targattrfilters keyword than a
-   * "1" is added. If the ACI denies then a "0" is added. If the skipCheck flag
-   * is true, then a 1 is used for the write access, since the client DN has
-   * bypass privs.
-   *
-   * @param container The LDAP operation container to use in the evaluations.
-   * @param handler The Aci Handler to use in the access evaluations.
-   * @param skipCheck True if ACI evaluation was skipped because bypass-acl
-   *                  privilege was found.
+   * @param container
+   *          The LDAP operation container to use in the evaluations.
+   * @param handler
+   *          The Aci Handler to use in the access evaluations.
+   * @param skipCheck
+   *          True if ACI evaluation was skipped because bypass-acl privilege
+   *          was found.
    * @return A string representing the rights information.
    */
-  private static
-  String attributeLevelWriteRights(AciLDAPOperationContainer container,
-                                   AciHandler handler,  boolean skipCheck){
+  private static String attributeLevelWriteRights(
+      AciLDAPOperationContainer container, AciHandler handler,
+      boolean skipCheck)
+  {
     boolean addRet=false, delRet=false;
     StringBuilder resString=new  StringBuilder();
     //If the user has bypass-acl privs and the authzid is equal to the
@@ -443,27 +470,31 @@
     return resString.toString();
   }
 
+
+
   /**
    * Perform entryLevel rights evaluation. The rights string is added to the
    * entry if the aclRights attribute was seen in the search's requested
    * attribute set.
    *
-   * @param container The LDAP operation container to use in the evaluations.
-   * @param handler The Aci Handler to use in the access evaluations.
-   * @param mask Mask specifing what rights attribute processing to perform
-   *              (aclRights or aclRightsInfo or both).
-   * @param retEntry The entry to return.
-   * @param skipCheck True if ACI evaluation was skipped because bypass-acl
-   *                  privilege was found.
-   * @return A SearchResultEntry with geteffectiverights entryLevel rights
-   *          information added to it.
+   * @param container
+   *          The LDAP operation container to use in the evaluations.
+   * @param handler
+   *          The Aci Handler to use in the access evaluations.
+   * @param mask
+   *          Mask specifing what rights attribute processing to perform
+   *          (aclRights or aclRightsInfo or both).
+   * @param retEntry
+   *          The entry to return.
+   * @param skipCheck
+   *          True if ACI evaluation was skipped because bypass-acl privilege
+   *          was found.
    */
 
-  private static SearchResultEntry
-  addEntryLevelRights(AciLDAPOperationContainer container,
-                                           AciHandler handler,
-                                           int mask, SearchResultEntry retEntry,
-                                           boolean skipCheck) {
+  private static void addEntryLevelRights(AciLDAPOperationContainer container,
+      AciHandler handler, int mask, final Entry retEntry,
+      boolean skipCheck)
+  {
     //Perform access evaluations for rights: add, delete, read, write, proxy.
     StringBuilder evalInfo=new StringBuilder();
     container.setCurrentAttributeType(null);
@@ -479,13 +510,11 @@
     container.setCurrentAttributeType(null);
     //The read right needs the entry with the full set of attributes. This was
     //saved in the Aci Handlers maysend method.
-    container.useFullResourceEntry(true);
     container.setRights(ACI_READ | ACI_SKIP_PROXY_CHECK);
     evalInfo.append(rightsString(container, handler, skipCheck, "read"));
     addEntryLevelRightsInfo(container, mask, retEntry, "read");
     evalInfo.append(',');
     //Switch back to the entry from the Aci Handler's filterentry method.
-    container.useFullResourceEntry(false);
     container.setCurrentAttributeType(null);
     container.setRights(ACI_WRITE| ACI_SKIP_PROXY_CHECK);
     evalInfo.append(rightsString(container, handler, skipCheck, "write"));
@@ -502,7 +531,6 @@
           .toString());
       retEntry.addAttribute(attr,null);
     }
-    return retEntry;
   }
 
   /**
@@ -593,7 +621,7 @@
    */
   private static
   void addAttrLevelRightsInfo(AciLDAPOperationContainer container, int mask,
-                     AttributeType aType, SearchResultEntry retEntry,
+                     AttributeType aType, Entry retEntry,
                      String rightStr) {
 
     //Check if the aclRightsInfo attribute was requested.
@@ -625,7 +653,7 @@
    */
   private static
    void addEntryLevelRightsInfo(AciLDAPOperationContainer container, int mask,
-                       SearchResultEntry retEntry,
+                       Entry retEntry,
                       String rightStr) {
 
      //Check if the aclRightsInfo attribute was requested.
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java
index 50ae0dd..fc62e3d 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciEvalContext.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2008-2010 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 
 package org.opends.server.authorization.dseecompat;
@@ -303,30 +304,13 @@
     public String rightToString();
 
     /**
-   * Return the name of the ACI that last matched a targattrfilters rule. Used
-   * in geteffectiverights control evaluation.
-   *
-   * @return The name of the ACI that last matched a targattrfilters rule.
-   */
+     * Return the name of the ACI that last matched a targattrfilters rule. Used
+     * in geteffectiverights control evaluation.
+     *
+     * @return The name of the ACI that last matched a targattrfilters rule.
+     */
     public String getTargAttrFiltersAciName();
 
-  /**
-   * The full entry with all of the attributes was saved
-   * in the operation's attachment mechanism when the container was created
-   * during the SearchOperation read evaluation. Some operations need the full
-   * entry and not the filtered entry to perform their evaluations, because they
-   * might depend attribute types and values filtered out.
-   *
-   * This method is used to replace the current resource entry with that saved
-   * entry and back.
-   *
-   * @param val Specifies if the saved entry should be used or not. {@code true}
-   * if it should be used, {@code false} if the original resource entry should
-   * be used.
-   *
-   */
-    public void useFullResourceEntry(boolean val);
-
 
     /**
      * Return the current SSF (Security Strength Factor) of the underlying
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
index f2130db..ccae97b 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2008-2010 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.authorization.dseecompat;
 
@@ -94,15 +95,6 @@
     AccessControlHandler<DseeCompatAccessControlHandlerCfg>
 {
   /**
-   * String used to save a resource entry containing all the attributes
-   * in the SearchOperation attachment list. This is only used during
-   * geteffectiverights read right processing when all of an entry'ss
-   * attributes need to examined.
-   */
-  public static final String ALL_ATTRS_RESOURCE_ENTRY =
-      "allAttrsResourceEntry";
-
-  /**
    * String used to indicate that the evaluating ACI had a all
    * operational attributes targetattr match (targetattr="+").
    */
@@ -234,46 +226,29 @@
    * {@inheritDoc}
    */
   @Override
-  public SearchResultEntry filterEntry(SearchOperation operation,
-      SearchResultEntry entry)
+  public void filterEntry(Operation operation,
+      SearchResultEntry unfilteredEntry, SearchResultEntry filteredEntry)
   {
     AciLDAPOperationContainer operationContainer =
-        new AciLDAPOperationContainer(operation, (ACI_READ), entry);
+      new AciLDAPOperationContainer(operation, (ACI_READ), unfilteredEntry);
+
     // Proxy access check has already been done for this entry in the
     // maySend method, set the seen flag to true to bypass any proxy
     // check.
     operationContainer.setSeenEntry(true);
-    SearchResultEntry returnEntry;
+
     boolean skipCheck = skipAccessCheck(operation);
     if (!skipCheck)
     {
-      returnEntry = accessAllowedAttrs(operationContainer);
+      filterEntry(operationContainer, filteredEntry);
     }
-    else
-    {
-      returnEntry = entry;
-    }
+
     if (operationContainer.hasGetEffectiveRightsControl())
     {
-      returnEntry =
-          AciEffectiveRights.addRightsToEntry(this, operation
-              .getAttributes(), operationContainer, returnEntry,
-              skipCheck);
+      AciEffectiveRights.addRightsToEntry(this,
+          ((SearchOperation) operation).getAttributes(), operationContainer,
+          filteredEntry, skipCheck);
     }
-    return returnEntry;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public SearchResultEntry filterEntry(Operation operation, Entry entry)
-  {
-    AciLDAPOperationContainer operationContainer =
-        new AciLDAPOperationContainer(operation, (ACI_READ), entry);
-    return accessAllowedAttrs(operationContainer);
   }
 
 
@@ -595,7 +570,7 @@
    * {@inheritDoc}
    */
   @Override
-  public boolean maySend(DN dn, SearchOperation operation,
+  public boolean maySend(DN dn, Operation operation,
       SearchResultReference reference)
   {
     boolean ret;
@@ -625,57 +600,55 @@
 
 
   /**
-   * Checks access on a search operation.
-   *
-   * @param operation
-   *          The search operation class containing information to check
-   *          the access on.
-   * @param entry
-   *          The entry to evaluate access.
-   * @return True if access is allowed.
+   * {@inheritDoc}
    */
   @Override
-  public boolean maySend(SearchOperation operation,
-      SearchResultEntry entry)
+  public boolean maySend(Operation operation, SearchResultEntry entry)
   {
+    if (skipAccessCheck(operation))
+    {
+      return true;
+    }
+
     AciLDAPOperationContainer operationContainer =
-        new AciLDAPOperationContainer(operation, (ACI_SEARCH), entry);
-    boolean ret;
-    if (!(ret = skipAccessCheck(operation)))
+      new AciLDAPOperationContainer(operation, (ACI_SEARCH), entry);
+
+    // Pre/post read controls are associated with other types of operation.
+    if (operation instanceof SearchOperation)
     {
       try
       {
-        ret = testFilter(operationContainer, operation.getFilter());
+        if (!testFilter(operationContainer,
+            ((SearchOperation) operation).getFilter()))
+        {
+          return false;
+        }
       }
       catch (DirectoryException ex)
       {
-        ret = false;
-      }
-      if (ret)
-      {
-        operationContainer.clearEvalAttributes(ACI_NULL);
-        operationContainer.setRights(ACI_READ);
-        ret = accessAllowedEntry(operationContainer);
-        if (ret)
-        {
-          if (!operationContainer.hasEvalUserAttributes())
-          {
-            operation.setAttachment(ALL_USER_ATTRS_MATCHED,
-                ALL_USER_ATTRS_MATCHED);
-          }
-          if (!operationContainer.hasEvalOpAttributes())
-          {
-            operation.setAttachment(ALL_OP_ATTRS_MATCHED,
-                ALL_OP_ATTRS_MATCHED);
-          }
-        }
+        return false;
       }
     }
-    // Save a copy of the full resource entry for possible
-    // userattr bind rule or geteffectiveright's evaluations in the
-    // filterEnty method.
-    operation.setAttachment(ALL_ATTRS_RESOURCE_ENTRY, entry);
-    return ret;
+
+    operationContainer.clearEvalAttributes(ACI_NULL);
+    operationContainer.setRights(ACI_READ);
+
+    if (!accessAllowedEntry(operationContainer))
+    {
+      return false;
+    }
+
+    if (!operationContainer.hasEvalUserAttributes())
+    {
+      operation.setAttachment(ALL_USER_ATTRS_MATCHED, ALL_USER_ATTRS_MATCHED);
+    }
+
+    if (!operationContainer.hasEvalOpAttributes())
+    {
+      operation.setAttachment(ALL_OP_ATTRS_MATCHED, ALL_OP_ATTRS_MATCHED);
+    }
+
+    return true;
   }
 
 
@@ -855,23 +828,21 @@
 
 
   /**
-   * Performs an access check against all of the attributes of an entry.
-   * The attributes that fail access are removed from the entry. This
-   * method performs the processing needed for the filterEntry method
-   * processing.
+   * Performs an access check against all of the attributes of an entry. The
+   * attributes that fail access are removed from the entry. This method
+   * performs the processing needed for the filterEntry method processing.
    *
    * @param container
-   *          The search or compare container which has all of the
-   *          information needed to filter the attributes for this
-   *          entry.
-   * @return The entry to send back to the client, minus any attribute
-   *         types that failed access check.
+   *          The search or compare container which has all of the information
+   *          needed to filter the attributes for this entry.
+   * @param filteredEntry
+   *          The partially filtered search result entry being returned to the
+   *          client.
    */
-  private SearchResultEntry accessAllowedAttrs(
-      AciLDAPOperationContainer container)
+  private void filterEntry(AciLDAPOperationContainer container,
+      Entry filteredEntry)
   {
-    Entry e = container.getResourceEntry();
-    List<AttributeType> typeList = getAllAttrs(e);
+    List<AttributeType> typeList = getAllAttrs(filteredEntry);
     for (AttributeType attrType : typeList)
     {
       if (container.hasAllUserAttributes() && !attrType.isOperational())
@@ -885,10 +856,9 @@
       container.setCurrentAttributeType(attrType);
       if (!accessAllowed(container))
       {
-        e.removeAttribute(attrType);
+        filteredEntry.removeAttribute(attrType);
       }
     }
-    return container.getSearchResultEntry();
   }
 
 
@@ -914,7 +884,8 @@
   {
     Entry resourceEntry = container.getResourceEntry();
     DN dn = resourceEntry.getDN();
-    List<Modification> modifications = container.getModifications();
+    List<Modification> modifications =  operation.getModifications();
+
     for (Modification m : modifications)
     {
       Attribute modAttr = m.getAttribute();
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
index 5840077..45b1454 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
@@ -23,11 +23,11 @@
  *
  *
  *      Copyright 2008-2009 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 
 package org.opends.server.authorization.dseecompat;
 
-import java.util.List;
 import org.opends.server.core.*;
 import org.opends.server.types.*;
 import org.opends.server.workflowelement.localbackend.*;
@@ -39,17 +39,6 @@
  */
 public class AciLDAPOperationContainer extends AciContainer  {
 
-    /*
-     * The entry to be returned if this is a LDAP search.
-     */
-    private SearchResultEntry searchEntry;
-
-    /*
-     * The list of modifications if this operation is a LDAP
-     * modify.
-     */
-    private List<Modification>  modifications;
-
     /**
      * Constructor interface for all currently supported LDAP operations.
      * @param operation The compare operation to evaluate.
@@ -60,7 +49,6 @@
       int rights, Entry entry)
     {
       super(operation, rights, entry);
-      this.searchEntry = new SearchResultEntry(entry);
     }
 
 
@@ -149,7 +137,6 @@
         int rights)
     {
         super(operation, rights, operation.getCurrentEntry());
-        this.modifications=operation.getModifications();
     }
 
     /**
@@ -163,33 +150,4 @@
                                      Entry entry) {
         super(operation, rights,  entry);
     }
-
-    /**
-     * Constructor interface for the LDAP search operation.
-     * @param operation The search operation.
-     * @param rights The rights of a search operation.
-     * @param entry The entry to be evaluated for this search.
-     */
-    public AciLDAPOperationContainer(SearchOperation operation,
-        int rights,
-        SearchResultEntry entry)
-    {
-        super(operation, rights,  entry);
-        this.searchEntry = entry;
-    }
-
-    /**
-     * Retrieve the search result entry of the search operation.
-     * @return The search result entry.
-     */
-    public SearchResultEntry getSearchResultEntry() {
-        return this.searchEntry;
-    }
-
-    /** Retrieve the list of modifications if this is a LDAP modify.
-     * @return The list of LDAP modifications to made on the resource entry.
-     */
-    public  List<Modification>  getModifications() {
-        return modifications;
-    }
 }
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java b/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
index c496469..bf1173c 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
+++ b/opends/src/server/org/opends/server/authorization/dseecompat/UserAttr.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2008 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 
 package org.opends.server.authorization.dseecompat;
@@ -174,29 +175,26 @@
      * @return  An enumeration containing the result of the evaluation.
      */
     public EnumEvalResult evaluate(AciEvalContext evalCtx) {
-        EnumEvalResult matched;
-       //The working resource entry might be filtered and not have an
-       //attribute type that is needed to perform these evaluations. The
-       //evalCtx has a copy of the non-filtered entry, switch to it for these
-       //evaluations.
-       evalCtx.useFullResourceEntry(true);
-        switch(userAttrType) {
-        case ROLEDN:
-        case GROUPDN:
-        case USERDN: {
-            matched=evalDNKeywords(evalCtx);
-            break;
-        }
-        case URL: {
-            matched=evalURL(evalCtx);
-            break;
-        }
-        default:
-            matched=evalVAL(evalCtx);
-        }
-        //Switch back to the working resource entry.
-        evalCtx.useFullResourceEntry(false);
-        return matched;
+      EnumEvalResult matched;
+      //The working resource entry might be filtered and not have an
+      //attribute type that is needed to perform these evaluations. The
+      //evalCtx has a copy of the non-filtered entry, switch to it for these
+      //evaluations.
+      switch(userAttrType) {
+      case ROLEDN:
+      case GROUPDN:
+      case USERDN: {
+        matched=evalDNKeywords(evalCtx);
+        break;
+      }
+      case URL: {
+        matched=evalURL(evalCtx);
+        break;
+      }
+      default:
+        matched=evalVAL(evalCtx);
+      }
+      return matched;
     }
 
     /** Evaluate a VALUE userattr type. Look in client entry for an
diff --git a/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java b/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
index c5c888a..40ebc16 100644
--- a/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
+++ b/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.core;
 
@@ -48,13 +49,6 @@
       extends AccessControlHandler<AccessControlHandlerCfg>
 {
   /**
-   * The single handler instance.
-   */
-  private static DefaultAccessControlHandler instance = null;
-
-
-
-  /**
    * Create a new default access control handler.
    */
   public DefaultAccessControlHandler()
@@ -204,22 +198,21 @@
    * {@inheritDoc}
    */
   @Override
-  public boolean maySend(SearchOperation searchOperation,
-                         SearchResultEntry searchEntry)
+  public boolean maySend(Operation operation, SearchResultEntry unfilteredEntry)
   {
     return true;
   }
 
 
+
   /**
    * {@inheritDoc}
    */
   @Override
-  public SearchResultEntry filterEntry(SearchOperation searchOperation,
-                                       SearchResultEntry searchEntry)
+  public void filterEntry(Operation operation,
+      SearchResultEntry unfilteredEntry, SearchResultEntry filteredEntry)
   {
-    // No implementation required.
-    return searchEntry;
+    return;
   }
 
 
@@ -228,19 +221,7 @@
    * {@inheritDoc}
    */
   @Override
-  public SearchResultEntry filterEntry(Operation operation, Entry entry)
-  {
-    // No implementation required.
-    return new SearchResultEntry(entry);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean maySend(DN dn, SearchOperation searchOperation,
+  public boolean maySend(DN dn, Operation operation,
                          SearchResultReference searchReference)
   {
     return true;
diff --git a/opends/src/server/org/opends/server/core/SearchOperationBasis.java b/opends/src/server/org/opends/server/core/SearchOperationBasis.java
index 715c3fb..ace7465 100644
--- a/opends/src/server/org/opends/server/core/SearchOperationBasis.java
+++ b/opends/src/server/org/opends/server/core/SearchOperationBasis.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2010 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.core;
 
@@ -691,12 +692,13 @@
     }
 
     // Check to see if the entry can be read by the client.
+    SearchResultEntry unfilteredSearchEntry = new SearchResultEntry(entry,
+        controls);
     if (evaluateAci)
     {
-      SearchResultEntry tmpSearchEntry = new SearchResultEntry(entry,
-        controls);
-      if (AccessControlConfigManager.getInstance()
-          .getAccessControlHandler().maySend(this, tmpSearchEntry) == false) {
+      if (AccessControlConfigManager.getInstance().getAccessControlHandler()
+          .maySend(this, unfilteredSearchEntry) == false)
+      {
         return true;
       }
     }
@@ -705,7 +707,7 @@
     // of requested attributes.
 
     // NOTE: that this copy will include the objectClass attribute.
-    Entry entryToReturn =
+    Entry filteredEntry =
         entry.filterEntry(getAttributes(), typesOnly,
             isVirtualAttributesOnly(), isRealAttributesOnly());
 
@@ -721,7 +723,7 @@
       // dealt with later.
       AttributeType attrType = DirectoryServer.getObjectClassAttributeType();
       Iterator<String> ocIterator =
-           entryToReturn.getObjectClasses().values().iterator();
+           filteredEntry.getObjectClasses().values().iterator();
       while (ocIterator.hasNext())
       {
         String ocName = ocIterator.next();
@@ -735,7 +737,7 @@
 
 
       // Next, the set of user attributes (incl. objectClass attribute).
-      for (Map.Entry<AttributeType, List<Attribute>> e : entryToReturn
+      for (Map.Entry<AttributeType, List<Attribute>> e : filteredEntry
           .getUserAttributes().entrySet())
       {
         AttributeType t = e.getKey();
@@ -762,7 +764,7 @@
 
 
       // Then the set of operational attributes.
-      for (Map.Entry<AttributeType, List<Attribute>> e : entryToReturn
+      for (Map.Entry<AttributeType, List<Attribute>> e : filteredEntry
           .getOperationalAttributes().entrySet())
       {
         AttributeType t = e.getKey();
@@ -790,8 +792,8 @@
 
 
     // Convert the provided entry to a search result entry.
-    SearchResultEntry searchEntry = new SearchResultEntry(entryToReturn,
-                                                          controls);
+    SearchResultEntry filteredSearchEntry = new SearchResultEntry(
+        filteredEntry, controls);
 
     // Strip out any attributes that the client does not have access to.
 
@@ -799,24 +801,24 @@
     // values that the client is not permitted to see.
     if (evaluateAci)
     {
-      searchEntry = AccessControlConfigManager.getInstance()
-        .getAccessControlHandler().filterEntry(this, searchEntry);
+      AccessControlConfigManager.getInstance().getAccessControlHandler()
+          .filterEntry(this, unfilteredSearchEntry, filteredSearchEntry);
     }
 
     // Invoke any search entry plugins that may be registered with the server.
     PluginResult.IntermediateResponse pluginResult =
          DirectoryServer.getPluginConfigManager().
-              invokeSearchResultEntryPlugins(this, searchEntry);
+              invokeSearchResultEntryPlugins(this, filteredSearchEntry);
 
     // Send the entry to the client.
     if (pluginResult.sendResponse())
     {
       // Log the entry sent to the client.
-      logSearchResultEntry(this, searchEntry);
+      logSearchResultEntry(this, filteredSearchEntry);
 
       try
       {
-        sendSearchEntry(searchEntry);
+        sendSearchEntry(filteredSearchEntry);
 
         incrementEntriesSent();
       }
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
index 8214122..3ca1ef8 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2008-2010 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.workflowelement.localbackend;
 
@@ -55,7 +56,6 @@
 import org.opends.server.api.plugin.PluginResult;
 import org.opends.server.controls.LDAPAssertionRequestControl;
 import org.opends.server.controls.LDAPPostReadRequestControl;
-import org.opends.server.controls.LDAPPostReadResponseControl;
 import org.opends.server.controls.PasswordPolicyErrorType;
 import org.opends.server.controls.PasswordPolicyResponseControl;
 import org.opends.server.controls.ProxiedAuthV1Control;
@@ -263,7 +263,7 @@
 
         // Invoke any conflict resolution processing that might be needed by the
         // synchronization provider.
-        for (SynchronizationProvider provider :
+        for (SynchronizationProvider<?> provider :
              DirectoryServer.getSynchronizationProviders())
         {
           try
@@ -643,7 +643,7 @@
           }
           else
           {
-            for (SynchronizationProvider provider :
+            for (SynchronizationProvider<?> provider :
                  DirectoryServer.getSynchronizationProviders())
             {
               try
@@ -676,11 +676,8 @@
             backend.addEntry(entry, this);
           }
 
-          if (postReadRequest != null)
-          {
-            addPostReadResponse();
-          }
-
+          LocalBackendWorkflowElement.addPostReadResponse(this,
+              postReadRequest, entry);
 
           if (! noOp)
           {
@@ -700,7 +697,7 @@
       }
       finally
       {
-        for (SynchronizationProvider provider :
+        for (SynchronizationProvider<?> provider :
           DirectoryServer.getSynchronizationProviders())
         {
           try
@@ -1204,7 +1201,7 @@
       // Encode the password.
       if (passwordPolicy.usesAuthPasswordSyntax())
       {
-        for (PasswordStorageScheme s : defaultStorageSchemes)
+        for (PasswordStorageScheme<?> s : defaultStorageSchemes)
         {
           ByteString encodedValue = s.encodeAuthPassword(value);
           builder.add(AttributeValues.create(
@@ -1213,7 +1210,7 @@
       }
       else
       {
-        for (PasswordStorageScheme s : defaultStorageSchemes)
+        for (PasswordStorageScheme<?> s : defaultStorageSchemes)
         {
           ByteString encodedValue = s.encodePasswordWithScheme(value);
           builder.add(AttributeValues.create(
@@ -1609,58 +1606,5 @@
       }
     }
   }
-
-
-
-  /**
-   * Adds the post-read response control to the response.
-   */
-  protected void addPostReadResponse()
-  {
-    Entry addedEntry = entry.duplicate(true);
-
-    if (! postReadRequest.allowsAttribute(
-               DirectoryServer.getObjectClassAttributeType()))
-    {
-      addedEntry.removeAttribute(DirectoryServer.getObjectClassAttributeType());
-    }
-
-    if (! postReadRequest.returnAllUserAttributes())
-    {
-      Iterator<AttributeType> iterator =
-           addedEntry.getUserAttributes().keySet().iterator();
-      while (iterator.hasNext())
-      {
-        AttributeType attrType = iterator.next();
-        if (! postReadRequest.allowsAttribute(attrType))
-        {
-          iterator.remove();
-        }
-      }
-    }
-
-    if (! postReadRequest.returnAllOperationalAttributes())
-    {
-      Iterator<AttributeType> iterator =
-           addedEntry.getOperationalAttributes().keySet().iterator();
-      while (iterator.hasNext())
-      {
-        AttributeType attrType = iterator.next();
-        if (! postReadRequest.allowsAttribute(attrType))
-        {
-          iterator.remove();
-        }
-      }
-    }
-
-    // Check access controls on the entry and strip out
-    // any not allowed attributes.
-    SearchResultEntry searchEntry =
-      AccessControlConfigManager.getInstance().
-      getAccessControlHandler().filterEntry(this, addedEntry);
-    LDAPPostReadResponseControl responseControl =
-      new LDAPPostReadResponseControl(searchEntry);
-    addResponseControl(responseControl);
-  }
 }
 
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
index 1c42ff6..b37d0ae 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2008-2009 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.workflowelement.localbackend;
 
@@ -52,7 +53,6 @@
 import static org.opends.messages.CoreMessages.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
 
 
 
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
index c33d77f..d15fd66 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
@@ -23,12 +23,12 @@
  *
  *
  *      Copyright 2008-2009 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.workflowelement.localbackend;
 
 
 
-import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.locks.Lock;
 
@@ -46,7 +46,6 @@
 import org.opends.server.core.PersistentSearch;
 import org.opends.server.core.PluginConfigManager;
 import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.AttributeType;
 import org.opends.server.types.CanceledOperationException;
 import org.opends.server.types.Control;
 import org.opends.server.types.DebugLogLevel;
@@ -57,7 +56,6 @@
 import org.opends.server.types.Privilege;
 import org.opends.server.types.ResultCode;
 import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
 import org.opends.server.types.SynchronizationProviderResult;
 import org.opends.server.types.operation.PostOperationDeleteOperation;
 import org.opends.server.types.operation.PostResponseDeleteOperation;
@@ -410,7 +408,8 @@
           }
 
 
-          processPreReadControl();
+          LocalBackendWorkflowElement.addPreReadResponse(this,
+              preReadRequest, entry);
 
 
           if (! noOp)
@@ -662,62 +661,6 @@
 
 
   /**
-   * Performs any processing needed for the LDAP pre-read control.
-   */
-  protected void processPreReadControl()
-  {
-    if (preReadRequest != null)
-    {
-      Entry entryCopy = entry.duplicate(true);
-
-      if (! preReadRequest.allowsAttribute(
-                 DirectoryServer.getObjectClassAttributeType()))
-      {
-        entryCopy.removeAttribute(
-             DirectoryServer.getObjectClassAttributeType());
-      }
-
-      if (! preReadRequest.returnAllUserAttributes())
-      {
-        Iterator<AttributeType> iterator =
-             entryCopy.getUserAttributes().keySet().iterator();
-        while (iterator.hasNext())
-        {
-          AttributeType attrType = iterator.next();
-          if (! preReadRequest.allowsAttribute(attrType))
-          {
-            iterator.remove();
-          }
-        }
-      }
-
-      if (! preReadRequest.returnAllOperationalAttributes())
-      {
-        Iterator<AttributeType> iterator =
-             entryCopy.getOperationalAttributes().keySet().iterator();
-        while (iterator.hasNext())
-        {
-          AttributeType attrType = iterator.next();
-          if (! preReadRequest.allowsAttribute(attrType))
-          {
-            iterator.remove();
-          }
-        }
-      }
-
-      // Check access controls on the entry and strip out
-      // any not allowed attributes.
-      SearchResultEntry searchEntry =
-        AccessControlConfigManager.getInstance().
-        getAccessControlHandler().filterEntry(this, entryCopy);
-      LDAPPreReadResponseControl responseControl =
-           new LDAPPreReadResponseControl(preReadRequest.isCritical(),
-                                          searchEntry);
-      addResponseControl(responseControl);
-    }
-  }
-
-  /**
    * Handle conflict resolution.
    * @return  {@code true} if processing should continue for the operation, or
    *          {@code false} if not.
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
index 2be70b8..4fb55d9 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
@@ -23,12 +23,12 @@
  *
  *
  *      Copyright 2008-2010 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.workflowelement.localbackend;
 
 
 
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.locks.Lock;
@@ -42,9 +42,7 @@
 import org.opends.server.api.plugin.PluginResult;
 import org.opends.server.controls.LDAPAssertionRequestControl;
 import org.opends.server.controls.LDAPPostReadRequestControl;
-import org.opends.server.controls.LDAPPostReadResponseControl;
 import org.opends.server.controls.LDAPPreReadRequestControl;
-import org.opends.server.controls.LDAPPreReadResponseControl;
 import org.opends.server.controls.ProxiedAuthV1Control;
 import org.opends.server.controls.ProxiedAuthV2Control;
 import org.opends.server.core.AccessControlConfigManager;
@@ -71,7 +69,6 @@
 import org.opends.server.types.RDN;
 import org.opends.server.types.ResultCode;
 import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
 import org.opends.server.types.SynchronizationProviderResult;
 import org.opends.server.types.operation.PostOperationModifyDNOperation;
 import org.opends.server.types.operation.PostResponseModifyDNOperation;
@@ -631,7 +628,10 @@
 
           // Attach the pre-read and/or post-read controls to the response if
           // appropriate.
-          processReadEntryControls();
+          LocalBackendWorkflowElement.addPreReadResponse(this,
+              preReadRequest, currentEntry);
+          LocalBackendWorkflowElement.addPostReadResponse(this,
+              postReadRequest, newEntry);
 
 
           if (! noOp)
@@ -1077,114 +1077,6 @@
 
 
   /**
-   * Performs any necessary processing to create the pre-read and/or post-read
-   * response controls and attach them to the response.
-   */
-  protected void processReadEntryControls()
-  {
-    if (preReadRequest != null)
-    {
-      Entry entry = currentEntry.duplicate(true);
-
-      if (! preReadRequest.allowsAttribute(
-                 DirectoryServer.getObjectClassAttributeType()))
-      {
-        entry.removeAttribute(
-             DirectoryServer.getObjectClassAttributeType());
-      }
-
-      if (! preReadRequest.returnAllUserAttributes())
-      {
-        Iterator<AttributeType> iterator =
-             entry.getUserAttributes().keySet().iterator();
-        while (iterator.hasNext())
-        {
-          AttributeType attrType = iterator.next();
-          if (! preReadRequest.allowsAttribute(attrType))
-          {
-            iterator.remove();
-          }
-        }
-      }
-
-      if (! preReadRequest.returnAllOperationalAttributes())
-      {
-        Iterator<AttributeType> iterator =
-             entry.getOperationalAttributes().keySet().iterator();
-        while (iterator.hasNext())
-        {
-          AttributeType attrType = iterator.next();
-          if (! preReadRequest.allowsAttribute(attrType))
-          {
-            iterator.remove();
-          }
-        }
-      }
-
-      // Check access controls on the entry and strip out
-      // any not allowed attributes.
-      SearchResultEntry searchEntry =
-        AccessControlConfigManager.getInstance().
-        getAccessControlHandler().filterEntry(this, entry);
-      LDAPPreReadResponseControl responseControl =
-           new LDAPPreReadResponseControl(preReadRequest.isCritical(),
-                                          searchEntry);
-
-      addResponseControl(responseControl);
-    }
-
-    if (postReadRequest != null)
-    {
-      Entry entry = newEntry.duplicate(true);
-
-      if (! postReadRequest.allowsAttribute(
-                 DirectoryServer.getObjectClassAttributeType()))
-      {
-        entry.removeAttribute(
-             DirectoryServer.getObjectClassAttributeType());
-      }
-
-      if (! postReadRequest.returnAllUserAttributes())
-      {
-        Iterator<AttributeType> iterator =
-             entry.getUserAttributes().keySet().iterator();
-        while (iterator.hasNext())
-        {
-          AttributeType attrType = iterator.next();
-          if (! postReadRequest.allowsAttribute(attrType))
-          {
-            iterator.remove();
-          }
-        }
-      }
-
-      if (! postReadRequest.returnAllOperationalAttributes())
-      {
-        Iterator<AttributeType> iterator =
-             entry.getOperationalAttributes().keySet().iterator();
-        while (iterator.hasNext())
-        {
-          AttributeType attrType = iterator.next();
-          if (! postReadRequest.allowsAttribute(attrType))
-          {
-            iterator.remove();
-          }
-        }
-      }
-
-      // Check access controls on the entry and strip out
-      // any not allowed attributes.
-      SearchResultEntry searchEntry =
-        AccessControlConfigManager.getInstance().
-        getAccessControlHandler().filterEntry(this, entry);
-      LDAPPostReadResponseControl responseControl =
-           new LDAPPostReadResponseControl(searchEntry);
-
-      addResponseControl(responseControl);
-    }
-  }
-
-  /**
    * Handle conflict resolution.
    * @return  {@code true} if processing should continue for the operation, or
    *          {@code false} if not.
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
index c011803..d92813e 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2008-2009 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.workflowelement.localbackend;
 
@@ -52,9 +53,7 @@
 import org.opends.server.api.plugin.PluginResult;
 import org.opends.server.controls.LDAPAssertionRequestControl;
 import org.opends.server.controls.LDAPPostReadRequestControl;
-import org.opends.server.controls.LDAPPostReadResponseControl;
 import org.opends.server.controls.LDAPPreReadRequestControl;
-import org.opends.server.controls.LDAPPreReadResponseControl;
 import org.opends.server.controls.PasswordPolicyErrorType;
 import org.opends.server.controls.PasswordPolicyResponseControl;
 import org.opends.server.controls.ProxiedAuthV1Control;
@@ -652,7 +651,10 @@
 
           // Handle any processing that may be needed for the pre-read and/or
           // post-read controls.
-          handleReadEntryProcessing();
+          LocalBackendWorkflowElement.addPreReadResponse(this,
+              preReadRequest, currentEntry);
+          LocalBackendWorkflowElement.addPostReadResponse(this,
+              postReadRequest, modifiedEntry);
 
 
           if (! noOp)
@@ -2108,115 +2110,6 @@
 
 
   /**
-   * Handles any processing that is required for the LDAP pre-read and/or
-   * post-read controls.
-   */
-  protected void handleReadEntryProcessing()
-  {
-    if (preReadRequest != null)
-    {
-      Entry entry = currentEntry.duplicate(true);
-
-      if (! preReadRequest.allowsAttribute(
-                 DirectoryServer.getObjectClassAttributeType()))
-      {
-        entry.removeAttribute(
-                   DirectoryServer.getObjectClassAttributeType());
-      }
-
-      if (! preReadRequest.returnAllUserAttributes())
-      {
-        Iterator<AttributeType> iterator =
-             entry.getUserAttributes().keySet().iterator();
-        while (iterator.hasNext())
-        {
-          AttributeType attrType = iterator.next();
-          if (! preReadRequest.allowsAttribute(attrType))
-          {
-            iterator.remove();
-          }
-        }
-      }
-
-      if (! preReadRequest.returnAllOperationalAttributes())
-      {
-        Iterator<AttributeType> iterator =
-             entry.getOperationalAttributes().keySet().iterator();
-        while (iterator.hasNext())
-        {
-          AttributeType attrType = iterator.next();
-          if (! preReadRequest.allowsAttribute(attrType))
-          {
-            iterator.remove();
-          }
-        }
-      }
-
-      // Check access controls on the entry and strip out
-      // any not allowed attributes.
-      SearchResultEntry searchEntry =
-        AccessControlConfigManager.getInstance().
-        getAccessControlHandler().filterEntry(this, entry);
-      LDAPPreReadResponseControl responseControl =
-           new LDAPPreReadResponseControl(preReadRequest.isCritical(),
-                                          searchEntry);
-      getResponseControls().add(responseControl);
-    }
-
-    if (postReadRequest != null)
-    {
-      Entry entry = modifiedEntry.duplicate(true);
-
-      if (! postReadRequest.allowsAttribute(
-                 DirectoryServer.getObjectClassAttributeType()))
-      {
-        entry.removeAttribute(
-                   DirectoryServer.getObjectClassAttributeType());
-      }
-
-      if (! postReadRequest.returnAllUserAttributes())
-      {
-        Iterator<AttributeType> iterator =
-             entry.getUserAttributes().keySet().iterator();
-        while (iterator.hasNext())
-        {
-          AttributeType attrType = iterator.next();
-          if (! postReadRequest.allowsAttribute(attrType))
-          {
-            iterator.remove();
-          }
-        }
-      }
-
-      if (! postReadRequest.returnAllOperationalAttributes())
-      {
-        Iterator<AttributeType> iterator =
-             entry.getOperationalAttributes().keySet().iterator();
-        while (iterator.hasNext())
-        {
-          AttributeType attrType = iterator.next();
-          if (! postReadRequest.allowsAttribute(attrType))
-          {
-            iterator.remove();
-          }
-        }
-      }
-
-      // Check access controls on the entry and strip out
-      // any not allowed attributes.
-      SearchResultEntry searchEntry =
-        AccessControlConfigManager.getInstance().
-        getAccessControlHandler().filterEntry(this, entry);
-      LDAPPostReadResponseControl responseControl =
-           new LDAPPostReadResponseControl(searchEntry);
-
-      getResponseControls().add(responseControl);
-    }
-  }
-
-
-
-  /**
    * Handle conflict resolution.
    * @return  {@code true} if processing should continue for the operation, or
    *          {@code false} if not.
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
index 6c5d318..def6b50 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -23,12 +23,14 @@
  *
  *
  *      Copyright 2008-2010 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.workflowelement.localbackend;
 
 
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.TreeMap;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -41,15 +43,11 @@
 import org.opends.server.admin.std.server.RootCfg;
 import org.opends.server.api.Backend;
 import org.opends.server.config.ConfigException;
-import org.opends.server.core.AddOperation;
-import org.opends.server.core.BindOperation;
-import org.opends.server.core.CompareOperation;
-import org.opends.server.core.DeleteOperation;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.core.ModifyDNOperation;
-import org.opends.server.core.ModifyOperation;
-import org.opends.server.core.PersistentSearch;
-import org.opends.server.core.SearchOperation;
+import org.opends.server.controls.LDAPPostReadRequestControl;
+import org.opends.server.controls.LDAPPostReadResponseControl;
+import org.opends.server.controls.LDAPPreReadRequestControl;
+import org.opends.server.controls.LDAPPreReadResponseControl;
+import org.opends.server.core.*;
 import org.opends.server.types.*;
 import org.opends.server.workflowelement.LeafWorkflowElement;
 
@@ -326,6 +324,160 @@
 
 
   /**
+   * Adds the post-read response control to the response if requested.
+   *
+   * @param operation
+   *          The update operation.
+   * @param postReadRequest
+   *          The request control, if present.
+   * @param entry
+   *          The post-update entry.
+   */
+  static void addPostReadResponse(final Operation operation,
+      final LDAPPostReadRequestControl postReadRequest, final Entry entry)
+  {
+    if (postReadRequest == null)
+    {
+      return;
+    }
+
+    // Even though the associated update succeeded, we should still check
+    // whether or not we should return the entry.
+    final SearchResultEntry unfilteredEntry =
+      new SearchResultEntry(entry, null);
+    if (AccessControlConfigManager.getInstance().getAccessControlHandler()
+        .maySend(operation, unfilteredEntry) == false)
+    {
+      return;
+    }
+
+    final SearchResultEntry filteredEntry = new SearchResultEntry(
+        entry.duplicate(true), null);
+
+    if (!postReadRequest.allowsAttribute(DirectoryServer
+        .getObjectClassAttributeType()))
+    {
+      filteredEntry.removeAttribute(DirectoryServer
+          .getObjectClassAttributeType());
+    }
+
+    if (!postReadRequest.returnAllUserAttributes())
+    {
+      Iterator<AttributeType> iterator = filteredEntry.getUserAttributes()
+          .keySet().iterator();
+      while (iterator.hasNext())
+      {
+        final AttributeType attrType = iterator.next();
+        if (!postReadRequest.allowsAttribute(attrType))
+        {
+          iterator.remove();
+        }
+      }
+    }
+
+    if (!postReadRequest.returnAllOperationalAttributes())
+    {
+      final Iterator<AttributeType> iterator = filteredEntry
+          .getOperationalAttributes().keySet().iterator();
+      while (iterator.hasNext())
+      {
+        AttributeType attrType = iterator.next();
+        if (!postReadRequest.allowsAttribute(attrType))
+        {
+          iterator.remove();
+        }
+      }
+    }
+
+    // Strip out any attributes which access control denies access to.
+    AccessControlConfigManager.getInstance().getAccessControlHandler()
+        .filterEntry(operation, unfilteredEntry, filteredEntry);
+
+    final LDAPPostReadResponseControl responseControl =
+      new LDAPPostReadResponseControl(filteredEntry);
+    operation.addResponseControl(responseControl);
+  }
+
+
+
+  /**
+   * Adds the pre-read response control to the response if requested.
+   *
+   * @param operation
+   *          The update operation.
+   * @param preReadRequest
+   *          The request control, if present.
+   * @param entry
+   *          The pre-update entry.
+   */
+  static void addPreReadResponse(final Operation operation,
+      final LDAPPreReadRequestControl preReadRequest, final Entry entry)
+  {
+    if (preReadRequest == null)
+    {
+      return;
+    }
+
+    // Even though the associated update succeeded, we should still check
+    // whether or not we should return the entry.
+    final SearchResultEntry unfilteredEntry =
+      new SearchResultEntry(entry, null);
+    if (AccessControlConfigManager.getInstance().getAccessControlHandler()
+        .maySend(operation, unfilteredEntry) == false)
+    {
+      return;
+    }
+
+    final SearchResultEntry filteredEntry = new SearchResultEntry(
+        entry.duplicate(true), null);
+
+    if (!preReadRequest.allowsAttribute(DirectoryServer
+        .getObjectClassAttributeType()))
+    {
+      filteredEntry.removeAttribute(DirectoryServer
+          .getObjectClassAttributeType());
+    }
+
+    if (!preReadRequest.returnAllUserAttributes())
+    {
+      Iterator<AttributeType> iterator = filteredEntry.getUserAttributes()
+          .keySet().iterator();
+      while (iterator.hasNext())
+      {
+        final AttributeType attrType = iterator.next();
+        if (!preReadRequest.allowsAttribute(attrType))
+        {
+          iterator.remove();
+        }
+      }
+    }
+
+    if (!preReadRequest.returnAllOperationalAttributes())
+    {
+      final Iterator<AttributeType> iterator = filteredEntry
+          .getOperationalAttributes().keySet().iterator();
+      while (iterator.hasNext())
+      {
+        AttributeType attrType = iterator.next();
+        if (!preReadRequest.allowsAttribute(attrType))
+        {
+          iterator.remove();
+        }
+      }
+    }
+
+    // Strip out any attributes which access control denies access to.
+    AccessControlConfigManager.getInstance().getAccessControlHandler()
+        .filterEntry(operation, unfilteredEntry, filteredEntry);
+
+    final LDAPPreReadResponseControl responseControl =
+      new LDAPPreReadResponseControl(filteredEntry);
+    operation.addResponseControl(responseControl);
+  }
+
+
+
+  /**
    * Registers a local backend with the server.
    *
    * @param localBackend  the local backend to register with the server
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
index 0ed63aa..818bc54 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/AciTests.java
@@ -2081,7 +2081,7 @@
    * @throws Exception
    *           If an unexpected exception occurred.
    */
-  @Test(enabled=false)
+  @Test
   public void testSearchTargetFilterAndAttributes() throws Exception
   {
     addEntries(BASIC_LDIF__GROUP_SEARCH_TESTS, DIR_MGR_DN, DIR_MGR_PW);

--
Gitblit v1.10.0