mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Jean-Noel Rouvignac
06.13.2013 1c1400a568940232bff55fa95094716b87fc8d9a
OPENDJ-1088 (CR-2677) Wrong error message and result code when deleting branch as a user with insufficient access rights


Fixed ConcurrentModificationException introduced in r7972 for OPENDJ-475: Incorrect behaviour/result code regarding non-critical controls.
The ConcurrentModificationExcepotion was hidden via several method calls, but generally it takes such form:
1. for (Control c : Operation.getRequestControls()) - directly or via indirect calls
2. AccessControlHandler.isAllowed()
2.1. Operation.removeRequestControl()
3. ConcurrentModificationException on next loop iteration at 1.



LocalBackendWorkflowElement.java:
Replaced isControlAllowed() by removeAllDisallowedControls() that uses Iterator.remove() instead of Operation.removeRequestControl().


LocalBackend*Operation.java:
In handleRequestControls(), processControls() and processRequestControls(), called LocalBackendWorkflowElement.removeAllDisallowedControls() before the for loop + removed call to LocalBackendWorkflowElement.isControlAllowed() in the loop body.
Tiny code cleanups.

ExtendedOperationBasis.java, ECLSearchOperation.java:
Used Iterator.remove() instead of Operation.removeRequestControl().

MultimasterReplication.java:
In findDomain(), used Iterator.remove() instead of Operation.removeRequestControl() + simplified the while loop code.


Operation.java, OperationWrapper.java, PreParseOperation.java:
Removed now unused removeRequestControl().

AbstractOperation.java:
Consequence of the change to Operation.
little code tidy up.
15 files modified
338 ■■■■■ changed files
opends/src/server/org/opends/server/core/ExtendedOperationBasis.java 9 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/OperationWrapper.java 9 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/plugin/MultimasterReplication.java 17 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/AbstractOperation.java 30 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/Operation.java 10 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/operation/PreParseOperation.java 22 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java 7 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java 13 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java 25 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java 10 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java 42 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java 30 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java 32 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java 22 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java 60 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/ExtendedOperationBasis.java
@@ -33,6 +33,7 @@
import static org.opends.server.util.ServerConstants.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.opends.server.api.ClientConnection;
@@ -324,10 +325,12 @@
      // Look at the controls included in the request and ensure that all
      // critical controls are supported by the handler.
      List<Control> requestControls = getRequestControls();
      if ((requestControls != null) && (! requestControls.isEmpty()))
      if (requestControls != null && !requestControls.isEmpty())
      {
        for (Control c : requestControls)
        for (Iterator<Control> iter = requestControls.iterator(); iter
            .hasNext();)
        {
          final Control c = iter.next();
          try
          {
            if (!AccessControlConfigManager.getInstance()
@@ -345,7 +348,7 @@
              {
                // We don't want to process this non-critical control, so
                // remove it.
                removeRequestControl(c);
                iter.remove();
                continue;
              }
            }
opends/src/server/org/opends/server/core/OperationWrapper.java
@@ -406,15 +406,6 @@
   * {@inheritDoc}
   */
  @Override
  public void removeRequestControl(Control control)
  {
    operation.removeRequestControl(control);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void removeResponseControl(Control control)
  {
    operation.removeResponseControl(control);
opends/src/server/org/opends/server/replication/plugin/MultimasterReplication.java
@@ -128,8 +128,10 @@
         * running later do not generate CSN, solve conflicts and forward the
         * operation to the replication server.
         */
        for (Control c : op.getRequestControls())
        final List<Control> controls = op.getRequestControls();
        for (Iterator<Control> iter = controls.iterator(); iter.hasNext();)
        {
          Control c = iter.next();
          if (c.getOID().equals(OID_REPLICATION_REPAIR_CONTROL))
          {
            op.setSynchronizationOperation(true);
@@ -139,25 +141,20 @@
            processed and the local backend will fail if it finds a control that
            it does not know about and that is marked as critical.
            */
            List<Control> controls = op.getRequestControls();
            controls.remove(c);
            iter.remove();
            return null;
          }
        }
    }
    LDAPReplicationDomain domain;
    LDAPReplicationDomain domain = null;
    DN temp = dn;
    do
    while (domain == null && temp != null)
    {
      domain = domains.get(temp);
      temp = temp.getParentDNInSuffix();
      if (temp == null)
      {
        break;
      }
    } while (domain == null);
    }
    return domain;
  }
opends/src/server/org/opends/server/types/AbstractOperation.java
@@ -308,13 +308,6 @@
  /** {@inheritDoc} */
  @Override
  public final void removeRequestControl(Control control)
  {
    requestControls.remove(control);
  }
  /** {@inheritDoc} */
  @Override
  public final ResultCode getResultCode()
  {
    return resultCode;
@@ -404,14 +397,11 @@
  @Override
  public List<AdditionalLogItem> getAdditionalLogItems()
  {
    if (additionalLogItems == null)
    {
      return Collections.emptyList();
    }
    else
    if (additionalLogItems != null)
    {
      return Collections.unmodifiableList(additionalLogItems);
    }
    return Collections.emptyList();
  }
  /** {@inheritDoc} */
@@ -548,14 +538,11 @@
  @Override
  public final DN getAuthorizationDN()
  {
    if (authorizationEntry == null)
    {
      return DN.nullDN();
    }
    else
    if (authorizationEntry != null)
    {
      return authorizationEntry.getDN();
    }
    return DN.nullDN();
  }
  /** {@inheritDoc} */
@@ -730,7 +717,7 @@
  @Override
  public final long getProcessingTime()
  {
    return (processingStopTime - processingStartTime);
    return processingStopTime - processingStartTime;
  }
  /** {@inheritDoc} */
@@ -739,12 +726,9 @@
  {
    if(useNanoTime)
    {
      return (processingStopNanoTime - processingStartNanoTime);
      return processingStopNanoTime - processingStartNanoTime;
    }
    else
    {
      return -1;
    }
    return -1;
  }
  /** {@inheritDoc} */
opends/src/server/org/opends/server/types/Operation.java
@@ -155,16 +155,6 @@
  public abstract void addRequestControl(Control control);
  /**
   * Removes the provided control from the set of request controls for
   * this operation.  This method may only be called by pre-parse
   * plugins.
   *
   * @param  control  The control to remove from the set of request
   *                  controls for this operation.
   */
  public abstract void removeRequestControl(Control control);
  /**
   * Retrieves the set of controls to include in the response to the
   * client.  The contents of this list must not be altered.
   *
opends/src/server/org/opends/server/types/operation/PreParseOperation.java
@@ -23,19 +23,16 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS.
 *      Portions copyright 2011-2013 ForgeRock AS.
 */
package org.opends.server.types.operation;
import java.util.List;
import org.opends.messages.Message;
import org.opends.server.types.*;
import org.opends.messages.MessageBuilder;
import org.opends.server.types.AdditionalLogItem;
import org.opends.server.types.Control;
/**
 * This class defines a set of methods that are available for use by
@@ -63,17 +60,6 @@
  /**
   * Removes the provided control from the set of request controls for
   * this operation.
   *
   * @param  control  The control to remove from the set of request
   *                  controls for this operation.
   */
  public void removeRequestControl(Control control);
  /**
   * Adds the provided control to the set of controls to include in
   * the response to the client.
   *
opends/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
@@ -373,9 +373,10 @@
    List<Control> requestControls  = getRequestControls();
    if (requestControls != null && !requestControls.isEmpty())
    {
      for (Control c : requestControls)
      for (Iterator<Control> iter = requestControls.iterator(); iter.hasNext();)
      {
        String  oid = c.getOID();
        final Control c = iter.next();
        final String oid = c.getOID();
        if (!AccessControlConfigManager.getInstance().getAccessControlHandler()
            .isAllowed(baseDN, this, c))
@@ -388,7 +389,7 @@
                ERR_CONTROL_INSUFFICIENT_ACCESS_RIGHTS.get(oid));
          }
          // We don't want to process this non-critical control, so remove it.
          removeRequestControl(c);
          iter.remove();
          continue;
        }
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
@@ -1139,20 +1139,16 @@
   */
  private void processControls(DN parentDN) throws DirectoryException
  {
    LocalBackendWorkflowElement.removeAllDisallowedControls(parentDN, this);
    List<Control> requestControls = getRequestControls();
    if ((requestControls != null) && (! requestControls.isEmpty()))
    if (requestControls != null && !requestControls.isEmpty())
    {
      for (int i=0; i < requestControls.size(); i++)
      {
        Control c   = requestControls.get(i);
        String  oid = c.getOID();
        if (!LocalBackendWorkflowElement.isControlAllowed(parentDN, this, c))
        {
          // Skip disallowed non-critical controls.
          continue;
        }
        if (oid.equals(OID_LDAP_ASSERTION))
        {
          // RFC 4528 mandates support for Add operation basically
@@ -1233,8 +1229,7 @@
          // The requester must have the PROXIED_AUTH privilege in order to
          // be able to use this control.
          if (! getClientConnection().hasPrivilege(Privilege.PROXIED_AUTH,
                                                   this))
          if (!getClientConnection().hasPrivilege(Privilege.PROXIED_AUTH, this))
          {
            throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED,
                           ERR_PROXYAUTH_INSUFFICIENT_PRIVILEGES.get());
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendBindOperation.java
@@ -388,23 +388,18 @@
   * @throws  DirectoryException  If there is a problem with any of the
   *                              controls.
   */
  private void handleRequestControls()
          throws DirectoryException
  private void handleRequestControls() throws DirectoryException
  {
    LocalBackendWorkflowElement.removeAllDisallowedControls(bindDN, this);
    List<Control> requestControls = getRequestControls();
    if ((requestControls != null) && (! requestControls.isEmpty()))
    if (requestControls != null && !requestControls.isEmpty())
    {
      for (int i=0; i < requestControls.size(); i++)
      {
        Control c   = requestControls.get(i);
        String  oid = c.getOID();
        if (!LocalBackendWorkflowElement.isControlAllowed(bindDN, this, c))
        {
          // Skip disallowed non-critical controls.
          continue;
        }
        if (oid.equals(OID_AUTHZID_REQUEST))
        {
          returnAuthzID = true;
@@ -415,7 +410,6 @@
        }
        // NYI -- Add support for additional controls.
        else if (c.isCritical())
        {
          throw new DirectoryException(
@@ -520,7 +514,6 @@
        PasswordPolicy policy = pwPolicyState.getAuthenticationPolicy();
        AttributeType pwType = policy.getPasswordAttribute();
        List<Attribute> pwAttr = userEntry.getAttribute(pwType);
        if ((pwAttr == null) || (pwAttr.isEmpty()))
        {
@@ -652,8 +645,7 @@
   * @throws  DirectoryException  If a problem occurs that should cause the bind
   *                              operation to fail.
   */
  protected boolean processAnonymousSimpleBind()
          throws DirectoryException
  protected boolean processAnonymousSimpleBind() throws DirectoryException
  {
    // If the server is in lockdown mode, then fail.
    if (DirectoryServer.lockdownMode())
@@ -663,8 +655,8 @@
    }
    // If there is a bind DN, then see whether that is acceptable.
    if (DirectoryServer.bindWithDNRequiresPassword() &&
        ((bindDN != null) && (! bindDN.isNullDN())))
    if (DirectoryServer.bindWithDNRequiresPassword()
        && bindDN != null && !bindDN.isNullDN())
    {
      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
                                   ERR_BIND_DN_BUT_NO_PASSWORD.get());
@@ -693,8 +685,7 @@
   * @throws  DirectoryException  If a problem occurs that should cause the bind
   *                              operation to fail.
   */
  private boolean processSASLBind()
          throws DirectoryException
  private boolean processSASLBind() throws DirectoryException
  {
    // Get the appropriate authentication handler for this request based
    // on the SASL mechanism.  If there is none, then fail.
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
@@ -393,19 +393,15 @@
   */
  private void handleRequestControls() throws DirectoryException
  {
    LocalBackendWorkflowElement.removeAllDisallowedControls(entryDN, this);
    List<Control> requestControls = getRequestControls();
    if ((requestControls != null) && (! requestControls.isEmpty()))
    if (requestControls != null && !requestControls.isEmpty())
    {
      for (Control c : requestControls)
      {
        String  oid = c.getOID();
        if (!LocalBackendWorkflowElement.isControlAllowed(entryDN, this, c))
        {
          // Skip disallowed non-critical controls.
          continue;
        }
        if (oid.equals(OID_LDAP_ASSERTION))
        {
          LDAPAssertionRequestControl assertControl =
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
@@ -440,22 +440,16 @@
   * @throws  DirectoryException  If a problem occurs that should cause the
   *                              operation to fail.
   */
  private void handleRequestControls()
          throws DirectoryException
  private void handleRequestControls() throws DirectoryException
  {
    LocalBackendWorkflowElement.removeAllDisallowedControls(entryDN, this);
    List<Control> requestControls = getRequestControls();
    if ((requestControls != null) && (! requestControls.isEmpty()))
    if (requestControls != null && !requestControls.isEmpty())
    {
      for (Control c : requestControls)
      {
        String  oid = c.getOID();
        if (!LocalBackendWorkflowElement.isControlAllowed(entryDN, this, c))
        {
          // Skip disallowed non-critical controls.
          continue;
        }
        final String oid = c.getOID();
        if (oid.equals(OID_LDAP_ASSERTION))
        {
          LDAPAssertionRequestControl assertControl =
@@ -494,8 +488,7 @@
            if (!filter.matchesEntry(entry))
            {
              throw newDirectoryException(entry, ResultCode.ASSERTION_FAILED,
                  ERR_DELETE_ASSERTION_FAILED.get(String
                      .valueOf(entryDN)));
                  ERR_DELETE_ASSERTION_FAILED.get(String.valueOf(entryDN)));
            }
          }
          catch (DirectoryException de)
@@ -595,15 +588,12 @@
  }
  /**
   * Handle conflict resolution.
   * @return  {@code true} if processing should continue for the operation, or
   *          {@code false} if not.
   */
  private boolean handleConflictResolution() {
      boolean returnVal = true;
      for (SynchronizationProvider<?> provider :
          DirectoryServer.getSynchronizationProviders()) {
          try {
@@ -614,8 +604,7 @@
                      result.getResultCode(), result.getErrorMessage());
                  setMatchedDN(result.getMatchedDN());
                  setReferralURLs(result.getReferralURLs());
                  returnVal = false;
                  break;
                  return false;
              }
          } catch (DirectoryException de) {
              if (debugEnabled()) {
@@ -625,11 +614,10 @@
                      getConnectionID(), getOperationID(),
                      getExceptionMessage(de)));
              setResponseData(de);
              returnVal = false;
              break;
              return false;
          }
      }
      return returnVal;
      return true;
  }
  /**
@@ -648,7 +636,7 @@
              logError(ERR_DELETE_SYNCH_POSTOP_FAILED.get(getConnectionID(),
                      getOperationID(), getExceptionMessage(de)));
              setResponseData(de);
              break;
              return;
          }
      }
  }
@@ -659,8 +647,6 @@
   *          {@code false} if not.
   */
  private boolean processPreOperation() {
      boolean returnVal = true;
      for (SynchronizationProvider<?> provider :
          DirectoryServer.getSynchronizationProviders()) {
          try {
@@ -671,8 +657,7 @@
                  appendErrorMessage(result.getErrorMessage());
                  setMatchedDN(result.getMatchedDN());
                  setReferralURLs(result.getReferralURLs());
                  returnVal = false;
                  break;
                  return false;
              }
          } catch (DirectoryException de) {
              if (debugEnabled())
@@ -682,10 +667,9 @@
              logError(ERR_DELETE_SYNCH_PREOP_FAILED.get(getConnectionID(),
                      getOperationID(), getExceptionMessage(de)));
              setResponseData(de);
              returnVal = false;
              break;
              return false;
          }
      }
      return returnVal;
      return true;
  }
}
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
@@ -586,6 +586,8 @@
   */
  private void handleRequestControls() throws DirectoryException
  {
    LocalBackendWorkflowElement.removeAllDisallowedControls(entryDN, this);
    List<Control> requestControls = getRequestControls();
    if ((requestControls != null) && (! requestControls.isEmpty()))
    {
@@ -594,12 +596,6 @@
        Control c   = requestControls.get(i);
        String  oid = c.getOID();
        if (!LocalBackendWorkflowElement.isControlAllowed(entryDN, this, c))
        {
          // Skip disallowed non-critical controls.
          continue;
        }
        if (oid.equals(OID_LDAP_ASSERTION))
        {
          LDAPAssertionRequestControl assertControl =
@@ -939,8 +935,6 @@
   */
  private boolean handleConflictResolution()
  {
      boolean returnVal = true;
      for (SynchronizationProvider<?> provider :
          DirectoryServer.getSynchronizationProviders()) {
          try {
@@ -951,8 +945,7 @@
                  appendErrorMessage(result.getErrorMessage());
                  setMatchedDN(result.getMatchedDN());
                  setReferralURLs(result.getReferralURLs());
                  returnVal = false;
                  break;
                  return false;
              }
          } catch (DirectoryException de) {
              if (debugEnabled()) {
@@ -963,11 +956,10 @@
                      getExceptionMessage(de)));
              setResponseData(de);
              returnVal = false;
              break;
              return false;
          }
      }
      return returnVal;
      return true;
  }
  /**
@@ -977,8 +969,6 @@
   */
  private boolean processPreOperation()
  {
      boolean returnVal = true;
      for (SynchronizationProvider<?> provider :
          DirectoryServer.getSynchronizationProviders()) {
          try {
@@ -989,8 +979,7 @@
                  appendErrorMessage(result.getErrorMessage());
                  setMatchedDN(result.getMatchedDN());
                  setReferralURLs(result.getReferralURLs());
                  returnVal = false;
                  break;
                  return false;
              }
          } catch (DirectoryException de) {
              if (debugEnabled()) {
@@ -999,11 +988,10 @@
              logError(ERR_MODDN_SYNCH_PREOP_FAILED.get(getConnectionID(),
                      getOperationID(), getExceptionMessage(de)));
              setResponseData(de);
              returnVal = false;
              break;
              return false;
          }
      }
      return returnVal;
      return true;
  }
  /**
@@ -1022,7 +1010,7 @@
              logError(ERR_MODDN_SYNCH_POSTOP_FAILED.get(getConnectionID(),
                      getOperationID(), getExceptionMessage(de)));
              setResponseData(de);
              break;
              return;
          }
      }
  }
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -682,9 +682,10 @@
   * @throws  DirectoryException  If a problem is encountered with any of the
   *                              controls.
   */
  protected void processRequestControls()
          throws DirectoryException
  protected void processRequestControls() throws DirectoryException
  {
    LocalBackendWorkflowElement.removeAllDisallowedControls(entryDN, this);
    List<Control> requestControls = getRequestControls();
    if ((requestControls != null) && (! requestControls.isEmpty()))
    {
@@ -693,12 +694,6 @@
        Control c   = requestControls.get(i);
        String  oid = c.getOID();
        if (!LocalBackendWorkflowElement.isControlAllowed(entryDN, this, c))
        {
          // Skip disallowed non-critical controls.
          continue;
        }
        if (oid.equals(OID_LDAP_ASSERTION))
        {
          LDAPAssertionRequestControl assertControl =
@@ -2081,8 +2076,6 @@
   *          {@code false} if not.
   */
  protected boolean handleConflictResolution() {
      boolean returnVal = true;
      for (SynchronizationProvider<?> provider :
          DirectoryServer.getSynchronizationProviders()) {
          try {
@@ -2093,8 +2086,7 @@
                      result.getResultCode(), result.getErrorMessage());
                  setMatchedDN(result.getMatchedDN());
                  setReferralURLs(result.getReferralURLs());
                  returnVal = false;
                  break;
                  return false;
              }
          } catch (DirectoryException de) {
              if (debugEnabled()) {
@@ -2104,11 +2096,10 @@
                      getConnectionID(), getOperationID(),
                      getExceptionMessage(de)));
              setResponseData(de);
              returnVal = false;
              break;
              return false;
          }
      }
      return returnVal;
      return true;
  }
  /**
@@ -2117,7 +2108,6 @@
   *          {@code false} if not.
   */
  protected boolean processPreOperation() {
      boolean returnVal = true;
      for (SynchronizationProvider<?> provider :
          DirectoryServer.getSynchronizationProviders()) {
          try {
@@ -2128,8 +2118,7 @@
                  appendErrorMessage(result.getErrorMessage());
                  setMatchedDN(result.getMatchedDN());
                  setReferralURLs(result.getReferralURLs());
                  returnVal = false;
                  break;
                  return false;
              }
          } catch (DirectoryException de) {
              if (debugEnabled()) {
@@ -2138,11 +2127,10 @@
              logError(ERR_MODIFY_SYNCH_PREOP_FAILED.get(getConnectionID(),
                      getOperationID(), getExceptionMessage(de)));
              setResponseData(de);
              returnVal = false;
              break;
              return false;
          }
      }
      return returnVal;
      return true;
  }
  /**
@@ -2160,7 +2148,7 @@
              logError(ERR_MODIFY_SYNCH_POSTOP_FAILED.get(getConnectionID(),
                      getOperationID(), getExceptionMessage(de)));
              setResponseData(de);
              break;
              return;
          }
      }
  }
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
@@ -32,17 +32,8 @@
import org.opends.server.api.Backend;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.plugin.PluginResult;
import org.opends.server.controls.LDAPAssertionRequestControl;
import org.opends.server.controls.MatchedValuesControl;
import org.opends.server.controls.PersistentSearchControl;
import org.opends.server.controls.ProxiedAuthV1Control;
import org.opends.server.controls.ProxiedAuthV2Control;
import org.opends.server.controls.SubentriesControl;
import org.opends.server.core.AccessControlConfigManager;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.PersistentSearch;
import org.opends.server.core.SearchOperationWrapper;
import org.opends.server.core.SearchOperation;
import org.opends.server.controls.*;
import org.opends.server.core.*;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.*;
import org.opends.server.types.operation.PostOperationSearchOperation;
@@ -342,6 +333,8 @@
   */
  private void handleRequestControls() throws DirectoryException
  {
    LocalBackendWorkflowElement.removeAllDisallowedControls(baseDN, this);
    List<Control> requestControls  = getRequestControls();
    if ((requestControls != null) && (! requestControls.isEmpty()))
    {
@@ -350,19 +343,12 @@
        Control c   = requestControls.get(i);
        String  oid = c.getOID();
        if (!LocalBackendWorkflowElement.isControlAllowed(baseDN, this, c))
        {
          // Skip disallowed non-critical controls.
          continue;
        }
        if (oid.equals(OID_LDAP_ASSERTION))
        {
          LDAPAssertionRequestControl assertControl =
                getRequestControl(LDAPAssertionRequestControl.DECODER);
          SearchFilter assertionFilter;
          try
          {
            assertionFilter = assertControl.getSearchFilter();
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -28,6 +28,7 @@
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;
@@ -324,42 +325,51 @@
  /**
   * Determine whether or not the provided request control is permitted by the
   * access control policy. If it is not allowed, then abort the operation if
   * the control was critical, otherwise ignore it.
   * Removes all the disallowed request controls from the provided operation.
   * <p>
   * As per RFC 4511 4.1.11, if a disallowed request control is critical, then a
   * DirectoryException is thrown with unavailableCriticalExtension. Otherwise,
   * if the disallowed request control is non critical, it is removed because we
   * do not want the backend to process it.
   *
   * @param targetDN
   *          The operation target DN.
   *          the target DN on which the operation applies
   * @param op
   *          The operation.
   * @param control
   *          The request control.
   * @return {@code true} if access is allowed, or {@code false} if access is
   *         not allowed, but the control is non-critical and should be ignored.
   *          the operation currently processed
   * @throws DirectoryException
   *           If access is not allowed and the control is critical.
   *           If a disallowed request control is critical, thrown with
   *           unavailableCriticalExtension. If an error occurred while
   *           performing the access control check. For example, if an attribute
   *           could not be decoded. Care must be taken not to expose any
   *           potentially sensitive information in the exception.
   */
  static boolean isControlAllowed(DN targetDN, Operation op, Control control)
  static void removeAllDisallowedControls(DN targetDN, Operation op)
      throws DirectoryException
  {
    if (!AccessControlConfigManager.getInstance().getAccessControlHandler()
        .isAllowed(targetDN, op, control))
    final List<Control> requestControls = op.getRequestControls();
    if (requestControls != null && !requestControls.isEmpty())
    {
      // As per RFC 4511 4.1.11.
      if (control.isCritical())
      for (Iterator<Control> iter = requestControls.iterator(); iter.hasNext();)
      {
        throw new DirectoryException(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION,
            ERR_CONTROL_INSUFFICIENT_ACCESS_RIGHTS.get(control.getOID()));
      }
      else
      {
        // We do not want the backend to process this non-critical control, so
        // remove it.
        op.removeRequestControl(control);
        return false;
        final Control control = iter.next();
        if (!AccessControlConfigManager.getInstance().getAccessControlHandler()
            .isAllowed(targetDN, op, control))
        {
          // As per RFC 4511 4.1.11.
          if (control.isCritical())
          {
            throw new DirectoryException(
                ResultCode.UNAVAILABLE_CRITICAL_EXTENSION,
                ERR_CONTROL_INSUFFICIENT_ACCESS_RIGHTS.get(control.getOID()));
          }
          // We do not want the backend to process this non-critical control, so
          // remove it.
          iter.remove();
        }
      }
    }
    return true;
  }
  /**