From fe4d6b1f8ee49c858ca2644851377ba2402d9509 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Thu, 25 Jul 2013 13:21:03 +0000
Subject: [PATCH] OPENDJ-948 (CR-1873) unauthorized disclosure of directory contents 

---
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java |  185 ++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 162 insertions(+), 23 deletions(-)

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 095cf4a..d71b152 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -27,8 +27,6 @@
  */
 package org.opends.server.workflowelement.localbackend;
 
-
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.TreeMap;
@@ -47,14 +45,13 @@
 import org.opends.server.controls.LDAPPreReadRequestControl;
 import org.opends.server.controls.LDAPPreReadResponseControl;
 import org.opends.server.core.*;
+import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.types.*;
 import org.opends.server.workflowelement.LeafWorkflowElement;
 
 import static org.opends.messages.CoreMessages.*;
 import static org.opends.server.config.ConfigConstants.*;
-
-
-
+import static org.opends.server.loggers.debug.DebugLogger.*;
 
 /**
  * This class defines a local backend workflow element; e-g an entity that
@@ -64,26 +61,34 @@
     LeafWorkflowElement<LocalBackendWorkflowElementCfg>
     implements ConfigurationChangeListener<LocalBackendWorkflowElementCfg>
 {
-  // the backend associated with the local workflow element
+  /**
+   * The tracer object for the debug logger.
+   */
+  private static final DebugTracer TRACER = getTracer();
+
+  /** the backend associated with the local workflow element. */
   private Backend backend;
 
 
-  // the set of local backend workflow elements registered with the server
+  /** the set of local backend workflow elements registered with the server. */
   private static TreeMap<String, LocalBackendWorkflowElement>
        registeredLocalBackends =
             new TreeMap<String, LocalBackendWorkflowElement>();
 
-  // The set of persistent searches registered with this work flow
-  // element.
+  /**
+   * The set of persistent searches registered with this work flow element.
+   */
   private final List<PersistentSearch> persistentSearches =
     new CopyOnWriteArrayList<PersistentSearch>();
 
-  // a lock to guarantee safe concurrent access to the registeredLocalBackends
-  // variable
+  /**
+   * a lock to guarantee safe concurrent access to the registeredLocalBackends
+   * variable.
+   */
   private static final Object registeredLocalBackendsLock = new Object();
 
 
-  // A string indicating the type of the workflow element.
+  /** A string indicating the type of the workflow element. */
   private static final String BACKEND_WORKFLOW_ELEMENT = "Backend";
 
 
@@ -177,10 +182,7 @@
       List<Message>                  unacceptableReasons
       )
   {
-    boolean isAcceptable =
-      processWorkflowElementConfig(configuration, false);
-
-    return isAcceptable;
+    return processWorkflowElementConfig(configuration, false);
   }
 
 
@@ -192,14 +194,10 @@
       LocalBackendWorkflowElementCfg configuration
       )
   {
-    // Returned result.
-    ConfigChangeResult changeResult = new ConfigChangeResult(
-        ResultCode.SUCCESS, false, new ArrayList<Message>()
-        );
-
     processWorkflowElementConfig(configuration, true);
 
-    return changeResult;
+    return new ConfigChangeResult(ResultCode.SUCCESS, false,
+        new ArrayList<Message>());
   }
 
 
@@ -354,7 +352,7 @@
       }
       else
       {
-        // We don't want the backend to process this non-critical control, so
+        // We do not want the backend to process this non-critical control, so
         // remove it.
         op.removeRequestControl(control);
         return false;
@@ -363,7 +361,148 @@
     return true;
   }
 
+  /**
+   * Returns a new {@link DirectoryException} built from the provided
+   * resultCodes and messages. Depending on whether ACIs prevent information
+   * disclosure, the provided resultCode and message will be masked and
+   * altResultCode and altMessage will be used instead.
+   *
+   * @param operation
+   *          the operation for which to check if ACIs prevent information
+   *          disclosure
+   * @param entry
+   *          the entry for which to check if ACIs prevent information
+   *          disclosure, if null, then a fake entry will be created from the
+   *          entryDN parameter
+   * @param entryDN
+   *          the entry dn for which to check if ACIs prevent information
+   *          disclosure. Only used if entry is null.
+   * @param resultCode
+   *          the result code to put on the DirectoryException if ACIs allow
+   *          disclosure. Otherwise it will be put on the DirectoryException as
+   *          a masked result code.
+   * @param message
+   *          the message to put on the DirectoryException if ACIs allow
+   *          disclosure. Otherwise it will be put on the DirectoryException as
+   *          a masked message.
+   * @param altResultCode
+   *          the result code to put on the DirectoryException if ACIs do not
+   *          allow disclosing the resultCode.
+   * @param altMessage
+   *          the result code to put on the DirectoryException if ACIs do not
+   *          allow disclosing the message.
+   * @return a new DirectoryException containing the provided resultCodes and
+   *         messages depending on ACI allowing disclosure or not
+   * @throws DirectoryException
+   *           If an error occurred while performing the access control check.
+   */
+  static DirectoryException newDirectoryException(Operation operation,
+      Entry entry, DN entryDN, ResultCode resultCode, Message message,
+      ResultCode altResultCode, Message altMessage) throws DirectoryException
+  {
+    if (AccessControlConfigManager.getInstance().getAccessControlHandler()
+        .canDiscloseInformation(entry, entryDN, operation))
+    {
+      return new DirectoryException(resultCode, message);
+    }
+    // replacement reason returned to the user
+    final DirectoryException ex =
+        new DirectoryException(altResultCode, altMessage);
+    // real underlying reason
+    ex.setMaskedResultCode(resultCode);
+    ex.setMaskedMessage(message);
+    return ex;
+  }
 
+  /**
+   * Sets the provided resultCodes and messages on the provided operation.
+   * Depending on whether ACIs prevent information disclosure, the provided
+   * resultCode and message will be masked and altResultCode and altMessage will
+   * be used instead.
+   *
+   * @param operation
+   *          the operation for which to check if ACIs prevent information
+   *          disclosure
+   * @param entry
+   *          the entry for which to check if ACIs prevent information
+   *          disclosure, if null, then a fake entry will be created from the
+   *          entryDN parameter
+   * @param entryDN
+   *          the entry dn for which to check if ACIs prevent information
+   *          disclosure. Only used if entry is null.
+   * @param resultCode
+   *          the result code to put on the DirectoryException if ACIs allow
+   *          disclosure. Otherwise it will be put on the DirectoryException as
+   *          a masked result code.
+   * @param message
+   *          the message to put on the DirectoryException if ACIs allow
+   *          disclosure. Otherwise it will be put on the DirectoryException as
+   *          a masked message.
+   * @param altResultCode
+   *          the result code to put on the DirectoryException if ACIs do not
+   *          allow disclosing the resultCode.
+   * @param altMessage
+   *          the result code to put on the DirectoryException if ACIs do not
+   *          allow disclosing the message.
+   * @throws DirectoryException
+   *           If an error occurred while performing the access control check.
+   */
+  static void setResultCodeAndMessageNoInfoDisclosure(Operation operation,
+      Entry entry, DN entryDN, ResultCode resultCode, Message message,
+      ResultCode altResultCode, Message altMessage) throws DirectoryException
+  {
+    if (AccessControlConfigManager.getInstance().getAccessControlHandler()
+        .canDiscloseInformation(entry, entryDN, operation))
+    {
+      operation.setResultCode(resultCode);
+      operation.appendErrorMessage(message);
+    }
+    else
+    {
+      // replacement reason returned to the user
+      operation.setResultCode(altResultCode);
+      operation.appendMaskedErrorMessage(altMessage);
+      // real underlying reason
+      operation.setMaskedResultCode(resultCode);
+      operation.appendMaskedErrorMessage(message);
+    }
+  }
+
+  /**
+   * Removes the matchedDN from the supplied operation if ACIs prevent its
+   * disclosure.
+   *
+   * @param operation
+   *          where to filter the matchedDN from
+   */
+  static void filterNonDisclosableMatchedDN(Operation operation)
+  {
+    if (operation.getMatchedDN() == null)
+    {
+      return;
+    }
+
+    try
+    {
+      if (!AccessControlConfigManager.getInstance().getAccessControlHandler()
+          .canDiscloseInformation(null, operation.getMatchedDN(), operation))
+      {
+        operation.setMatchedDN(null);
+      }
+    }
+    catch (DirectoryException de)
+    {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, de);
+      }
+
+      operation.setResponseData(de);
+      // At this point it is impossible to tell whether the matchedDN can be
+      // disclosed. It is probably safer to hide it by default.
+      operation.setMatchedDN(null);
+    }
+  }
 
   /**
    * Adds the post-read response control to the response if requested.

--
Gitblit v1.10.0