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/LocalBackendModifyOperation.java | 222 +++++----
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java | 185 ++++++
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java | 176 ++++---
opends/src/server/org/opends/server/types/AbstractOperation.java | 84 ++
opends/src/server/org/opends/server/types/DirectoryException.java | 85 +++
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java | 119 ++--
opends/src/server/org/opends/server/api/AccessControlHandler.java | 37 +
opends/resource/config/config.ldif | 2
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java | 164 ++++--
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java | 41 +
opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java | 63 +-
opends/src/server/org/opends/server/core/OperationWrapper.java | 42 +
opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java | 2
opends/src/server/org/opends/server/types/Operation.java | 46 +
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java | 133 +++--
15 files changed, 951 insertions(+), 450 deletions(-)
diff --git a/opends/resource/config/config.ldif b/opends/resource/config/config.ldif
index a37d147..ec03cbd 100644
--- a/opends/resource/config/config.ldif
+++ b/opends/resource/config/config.ldif
@@ -77,7 +77,7 @@
ds-cfg-global-aci: (extop="1.3.6.1.4.1.26027.1.6.1 || 1.3.6.1.4.1.26027.1.6.3 || 1.3.6.1.4.1.4203.1.11.1 || 1.3.6.1.4.1.1466.20037 || 1.3.6.1.4.1.4203.1.11.3") (version 3.0; acl "Anonymous extended operation access"; allow(read) userdn="ldap:///anyone";)
ds-cfg-global-aci: (targetcontrol="2.16.840.1.113730.3.4.2 || 2.16.840.1.113730.3.4.17 || 2.16.840.1.113730.3.4.19 || 1.3.6.1.4.1.4203.1.10.2 || 1.3.6.1.4.1.42.2.27.8.5.1 || 2.16.840.1.113730.3.4.16 || 1.2.840.113556.1.4.1413") (version 3.0; acl "Anonymous control access"; allow(read) userdn="ldap:///anyone";)
ds-cfg-global-aci: (targetcontrol="1.3.6.1.1.12 || 1.3.6.1.1.13.1 || 1.3.6.1.1.13.2 || 1.2.840.113556.1.4.319 || 1.2.826.0.1.3344810.2.3 || 2.16.840.1.113730.3.4.18 || 2.16.840.1.113730.3.4.9 || 1.2.840.113556.1.4.473 || 1.3.6.1.4.1.42.2.27.9.5.9") (version 3.0; acl "Authenticated users control access"; allow(read) userdn="ldap:///all";)
-ds-cfg-global-aci: (targetattr!="userPassword||authPassword||changes||changeNumber||changeType||changeTime||targetDN||newRDN||newSuperior||deleteOldRDN||targetEntryUUID||changeInitiatorsName||changeLogCookie||includedAttributes")(version 3.0; acl "Anonymous read access"; allow (read,search,compare) userdn="ldap:///anyone";)
+ds-cfg-global-aci: (targetattr!="userPassword||authPassword||changes||changeNumber||changeType||changeTime||debugsearchindex||targetDN||newRDN||newSuperior||deleteOldRDN||targetEntryUUID||changeInitiatorsName||changeLogCookie||includedAttributes")(version 3.0; acl "Anonymous read access"; allow (read,search,compare) userdn="ldap:///anyone";)
ds-cfg-global-aci: (targetattr="audio||authPassword||description||displayName||givenName||homePhone||homePostalAddress||initials||jpegPhoto||labeledURI||mobile||pager||postalAddress||postalCode||preferredLanguage||telephoneNumber||userPassword")(version 3.0; acl "Self entry modification"; allow (write) userdn="ldap:///self";)
ds-cfg-global-aci: (targetattr="userPassword||authPassword")(version 3.0; acl "Self entry read"; allow (read,search,compare) userdn="ldap:///self";)
ds-cfg-global-aci: (target="ldap:///cn=schema")(targetscope="base")(targetattr="objectClass||attributeTypes||dITContentRules||dITStructureRules||ldapSyntaxes||matchingRules||matchingRuleUse||nameForms||objectClasses")(version 3.0; acl "User-Visible Schema Operational Attributes"; allow (read,search,compare) userdn="ldap:///anyone";)
diff --git a/opends/src/server/org/opends/server/api/AccessControlHandler.java b/opends/src/server/org/opends/server/api/AccessControlHandler.java
index b7e5d72..abd412d 100644
--- a/opends/src/server/org/opends/server/api/AccessControlHandler.java
+++ b/opends/src/server/org/opends/server/api/AccessControlHandler.java
@@ -23,7 +23,7 @@
*
*
* Copyright 2006-2009 Sun Microsystems, Inc.
- * Portions Copyright 2011 ForgeRock AS
+ * Portions Copyright 2011-2013 ForgeRock AS
*/
package org.opends.server.api;
@@ -55,6 +55,7 @@
public abstract class AccessControlHandler
<T extends AccessControlHandlerCfg>
{
+
/**
* Initializes the access control handler implementation based on
* the information in the provided configuration entry.
@@ -115,6 +116,40 @@
public abstract void finalizeAccessControlHandler();
+ /**
+ * Checks whether the ACIs prevent sending information about the provided
+ * entry, or entryDN if entry is null.
+ *
+ * @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 operation
+ * the operation for which to check if ACIs prevent information
+ * disclosure
+ * @return true if the information for this entry can be disclosed, false
+ * otherwise.
+ * @throws DirectoryException
+ * If an error occurred while performing the access control check.
+ */
+ public boolean canDiscloseInformation(Entry entry, DN entryDN,
+ Operation operation) throws DirectoryException
+ {
+ if (entry == null)
+ {
+ entry = DirectoryServer.getEntry(entryDN);
+ }
+ if (entry == null)
+ {
+ // no such entry exist, let's be safe and forbid any info disclosure.
+ return false;
+ }
+ return maySend(operation, new SearchResultEntry(entry, operation
+ .getResponseControls()));
+ }
/**
* Indicates whether the provided add operation is allowed based on
diff --git a/opends/src/server/org/opends/server/core/OperationWrapper.java b/opends/src/server/org/opends/server/core/OperationWrapper.java
index 0f29a37..421a00c 100644
--- a/opends/src/server/org/opends/server/core/OperationWrapper.java
+++ b/opends/src/server/org/opends/server/core/OperationWrapper.java
@@ -86,6 +86,13 @@
operation.appendErrorMessage(message);
}
+ /** {@inheritDoc} */
+ @Override
+ public void appendMaskedErrorMessage(Message maskedMessage)
+ {
+ operation.appendMaskedErrorMessage(maskedMessage);
+ }
+
/**
* {@inheritDoc}
*/
@@ -208,6 +215,20 @@
return operation.getErrorMessage();
}
+ /** {@inheritDoc} */
+ @Override
+ public MessageBuilder getMaskedErrorMessage()
+ {
+ return operation.getMaskedErrorMessage();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ResultCode getMaskedResultCode()
+ {
+ return operation.getMaskedResultCode();
+ }
+
/**
* {@inheritDoc}
*/
@@ -462,6 +483,20 @@
operation.setInternalOperation(isInternalOperation);
}
+ /** {@inheritDoc} */
+ @Override
+ public void setMaskedErrorMessage(MessageBuilder maskedErrorMessage)
+ {
+ operation.setMaskedErrorMessage(maskedErrorMessage);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setMaskedResultCode(ResultCode maskedResultCode)
+ {
+ operation.setMaskedResultCode(maskedResultCode);
+ }
+
/**
* {@inheritDoc}
*/
@@ -539,6 +574,13 @@
return false;
}
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "Wrapped " + operation.toString();
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java b/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
index 2ae8ddd..2fc8ea6 100644
--- a/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
+++ b/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
@@ -447,9 +447,7 @@
{
appendAbandonRequest(abandonOperation, buffer);
}
- buffer.append(" result=");
- buffer.append(abandonOperation.getResultCode().getIntValue());
- appendMessage(buffer, abandonOperation);
+ appendResultCodeAndMessage(buffer, abandonOperation);
logAdditionalLogItems(abandonOperation, buffer);
@@ -506,10 +504,7 @@
{
appendAddRequest(addOperation, buffer);
}
- buffer.append(" result=");
- buffer.append(addOperation.getResultCode().getIntValue());
-
- appendMessage(buffer, addOperation);
+ appendResultCodeAndMessage(buffer, addOperation);
logAdditionalLogItems(addOperation, buffer);
@@ -569,10 +564,7 @@
{
appendBindRequest(bindOperation, buffer);
}
- buffer.append(" result=");
- buffer.append(bindOperation.getResultCode().getIntValue());
-
- appendMessage(buffer, bindOperation);
+ appendResultCodeAndMessage(buffer, bindOperation);
final Message failureMessage = bindOperation.getAuthFailureReason();
if (failureMessage != null)
@@ -674,10 +666,7 @@
{
appendCompareRequest(compareOperation, buffer);
}
- buffer.append(" result=");
- buffer.append(compareOperation.getResultCode().getIntValue());
-
- appendMessage(buffer, compareOperation);
+ appendResultCodeAndMessage(buffer, compareOperation);
logAdditionalLogItems(compareOperation, buffer);
@@ -773,10 +762,7 @@
{
appendDeleteRequest(deleteOperation, buffer);
}
- buffer.append(" result=");
- buffer.append(deleteOperation.getResultCode().getIntValue());
-
- appendMessage(buffer, deleteOperation);
+ appendResultCodeAndMessage(buffer, deleteOperation);
logAdditionalLogItems(deleteOperation, buffer);
@@ -885,11 +871,7 @@
}
appendLabel(buffer, "oid", oid);
}
-
- buffer.append(" result=");
- buffer.append(extendedOperation.getResultCode().getIntValue());
-
- appendMessage(buffer, extendedOperation);
+ appendResultCodeAndMessage(buffer, extendedOperation);
logAdditionalLogItems(extendedOperation, buffer);
@@ -946,10 +928,7 @@
{
appendModifyDNRequest(modifyDNOperation, buffer);
}
- buffer.append(" result=");
- buffer.append(modifyDNOperation.getResultCode().getIntValue());
-
- appendMessage(buffer, modifyDNOperation);
+ appendResultCodeAndMessage(buffer, modifyDNOperation);
logAdditionalLogItems(modifyDNOperation, buffer);
@@ -1009,10 +988,7 @@
{
appendModifyRequest(modifyOperation, buffer);
}
- buffer.append(" result=");
- buffer.append(modifyOperation.getResultCode().getIntValue());
-
- appendMessage(buffer, modifyOperation);
+ appendResultCodeAndMessage(buffer, modifyOperation);
logAdditionalLogItems(modifyOperation, buffer);
@@ -1072,10 +1048,7 @@
{
appendSearchRequest(searchOperation, buffer);
}
- buffer.append(" result=");
- buffer.append(searchOperation.getResultCode().getIntValue());
-
- appendMessage(buffer, searchOperation);
+ appendResultCodeAndMessage(buffer, searchOperation);
buffer.append(" nentries=");
buffer.append(searchOperation.getEntriesSent());
@@ -1267,14 +1240,28 @@
}
}
- private void appendMessage(final StringBuilder buffer,
- final Operation operation)
+ private void appendResultCodeAndMessage(StringBuilder buffer,
+ Operation operation)
{
+ buffer.append(" result=");
+ buffer.append(operation.getResultCode().getIntValue());
+
final MessageBuilder msg = operation.getErrorMessage();
if ((msg != null) && (msg.length() > 0))
{
appendLabel(buffer, "message", msg);
}
+
+ if (operation.getMaskedResultCode() != null)
+ {
+ buffer.append(" maskedResult=");
+ buffer.append(operation.getMaskedResultCode().getIntValue());
+ }
+ final MessageBuilder maskedMsg = operation.getMaskedErrorMessage();
+ if (maskedMsg != null && maskedMsg.length() > 0)
+ {
+ appendLabel(buffer, "maskedMessage", maskedMsg);
+ }
}
private void appendEtime(final StringBuilder buffer,
diff --git a/opends/src/server/org/opends/server/types/AbstractOperation.java b/opends/src/server/org/opends/server/types/AbstractOperation.java
index d58d4d1..390f082 100644
--- a/opends/src/server/org/opends/server/types/AbstractOperation.java
+++ b/opends/src/server/org/opends/server/types/AbstractOperation.java
@@ -42,7 +42,6 @@
import org.opends.server.types.operation.PreParseOperation;
import org.opends.server.util.Validator;
-
/**
* This class defines a generic operation that may be processed by the
* Directory Server. Specific subclasses should implement specific
@@ -139,6 +138,12 @@
private ResultCode resultCode;
/**
+ * The real, masked result code for this operation that will not be included
+ * in the response to the client, but will be logged.
+ */
+ private ResultCode maskedResultCode;
+
+ /**
* Additional information that should be included in the log but not sent to
* the client.
*/
@@ -151,6 +156,12 @@
private MessageBuilder errorMessage;
/**
+ * The real, masked error message for this operation that will not be included
+ * in the response to the client, but will be logged.
+ */
+ private MessageBuilder maskedErrorMessage;
+
+ /**
* Indicates whether this operation needs to be synchronized to other copies
* of the data.
*/
@@ -355,6 +366,20 @@
/** {@inheritDoc} */
@Override
+ public final ResultCode getMaskedResultCode()
+ {
+ return maskedResultCode;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final void setMaskedResultCode(ResultCode maskedResultCode)
+ {
+ this.maskedResultCode = maskedResultCode;
+ }
+
+ /** {@inheritDoc} */
+ @Override
public final MessageBuilder getErrorMessage()
{
return errorMessage;
@@ -364,14 +389,7 @@
@Override
public final void setErrorMessage(MessageBuilder errorMessage)
{
- if (errorMessage == null)
- {
- this.errorMessage = new MessageBuilder();
- }
- else
- {
- this.errorMessage = errorMessage;
- }
+ this.errorMessage = errorMessage;
}
/** {@inheritDoc} */
@@ -380,20 +398,44 @@
{
if (errorMessage == null)
{
- errorMessage = new MessageBuilder(message);
+ errorMessage = new MessageBuilder();
}
- else
+ else if (errorMessage.length() > 0)
{
- if (errorMessage.length() > 0)
- {
- errorMessage.append(" ");
- }
-
- errorMessage.append(message);
+ errorMessage.append(" ");
}
+ errorMessage.append(message);
}
+ /** {@inheritDoc} */
+ @Override
+ public final MessageBuilder getMaskedErrorMessage()
+ {
+ return maskedErrorMessage;
+ }
+ /** {@inheritDoc} */
+ @Override
+ public final void setMaskedErrorMessage(MessageBuilder maskedErrorMessage)
+ {
+ this.maskedErrorMessage = maskedErrorMessage;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public final void appendMaskedErrorMessage(Message maskedMessage)
+ {
+ if (maskedErrorMessage == null)
+ {
+ maskedErrorMessage = new MessageBuilder();
+ }
+ else if (maskedErrorMessage.length() > 0)
+ {
+ maskedErrorMessage.append(" ");
+ }
+
+ maskedErrorMessage.append(maskedMessage);
+ }
/**
* {@inheritDoc}
@@ -460,11 +502,13 @@
public final void setResponseData(
DirectoryException directoryException)
{
- this.resultCode = directoryException.getResultCode();
- this.matchedDN = directoryException.getMatchedDN();
- this.referralURLs = directoryException.getReferralURLs();
+ this.resultCode = directoryException.getResultCode();
+ this.maskedResultCode = directoryException.getMaskedResultCode();
+ this.matchedDN = directoryException.getMatchedDN();
+ this.referralURLs = directoryException.getReferralURLs();
appendErrorMessage(directoryException.getMessageObject());
+ appendMaskedErrorMessage(directoryException.getMaskedMessage());
}
diff --git a/opends/src/server/org/opends/server/types/DirectoryException.java b/opends/src/server/org/opends/server/types/DirectoryException.java
index 14b1730..673ca86 100644
--- a/opends/src/server/org/opends/server/types/DirectoryException.java
+++ b/opends/src/server/org/opends/server/types/DirectoryException.java
@@ -23,17 +23,13 @@
*
*
* Copyright 2006-2008 Sun Microsystems, Inc.
+ * Portions Copyright 2013 ForgeRock AS
*/
package org.opends.server.types;
-import org.opends.messages.Message;
-
-
-
-
import java.util.List;
-
+import org.opends.messages.Message;
/**
* This class defines an exception that may be thrown if a problem
@@ -58,16 +54,38 @@
- // The matched DN for this directory exception.
+ /** The matched DN returned to the client for this directory exception. */
private final DN matchedDN;
- // The set of referral URLs for this directory exception.
+ /** The set of referral URLs for this directory exception. */
private final List<String> referralURLs;
- // The result code for this directory exception.
+ /**
+ * The result code returned to the client for this directory exception. Note:
+ * for security considerations (information leak) this result code might not
+ * be the underlying reason why the directory server refused to execute the
+ * operation.
+ *
+ * @see #maskedResultCode for the underlying reason why the directory server
+ * refused to execute the operation
+ */
private final ResultCode resultCode;
+ /**
+ * If set, this is the real message for this directory exception that cannot
+ * be returned to the client, but will be logged.
+ *
+ * @see #getMessage() for the message returned to the client
+ */
+ private Message maskedMessage;
+ /**
+ * If set, this is the real result code for this directory exception that
+ * cannot be returned to the client, but will be logged.
+ *
+ * @see #resultCode for the reason code returned to the client
+ */
+ private ResultCode maskedResultCode;
/**
* Creates a new directory exception with the provided information.
@@ -224,5 +242,52 @@
{
return referralURLs;
}
-}
+ /**
+ * Returns the real, masked message for this directory exception that cannot
+ * be returned to the client, but will be logged.
+ *
+ * @return the real, masked message
+ * @see #getMessage() for the message returned to the client
+ */
+ public Message getMaskedMessage()
+ {
+ return maskedMessage;
+ }
+
+ /**
+ * Returns the real result code for this directory exception that cannot be
+ * returned to the client, but will be logged.
+ *
+ * @return the real, masked result code
+ * @see #getResultCode() for the result code returned to the client
+ */
+ public ResultCode getMaskedResultCode()
+ {
+ return maskedResultCode;
+ }
+
+ /**
+ * Sets the real message for this directory exception that cannot be returned
+ * to the client, but will be logged.
+ *
+ * @param maskedMessage
+ * the real, masked message to set
+ */
+ public void setMaskedMessage(Message maskedMessage)
+ {
+ this.maskedMessage = maskedMessage;
+ }
+
+ /**
+ * Sets the real result code for this directory exception that cannot be
+ * returned to the client, but will be logged.
+ *
+ * @param maskedResultCode
+ * the real, masked result code to set
+ */
+ public void setMaskedResultCode(ResultCode maskedResultCode)
+ {
+ this.maskedResultCode = maskedResultCode;
+ }
+}
diff --git a/opends/src/server/org/opends/server/types/Operation.java b/opends/src/server/org/opends/server/types/Operation.java
index 11772ca..12da6d8 100644
--- a/opends/src/server/org/opends/server/types/Operation.java
+++ b/opends/src/server/org/opends/server/types/Operation.java
@@ -211,6 +211,23 @@
public abstract void setResultCode(ResultCode resultCode);
/**
+ * Retrieves the real, masked result code for this operation.
+ *
+ * @return The real, masked result code associated for this operation, or
+ * {@code UNDEFINED} if the operation has not yet completed.
+ */
+ ResultCode getMaskedResultCode();
+
+ /**
+ * Specifies the real, masked result code for this operation. This method may
+ * not be called by post-response plugins.
+ *
+ * @param maskedResultCode
+ * The real, masked result code for this operation.
+ */
+ void setMaskedResultCode(ResultCode maskedResultCode);
+
+ /**
* Retrieves the error message for this operation. Its contents may
* be altered by pre-parse, pre-operation, and post-operation
* plugins, but not by post-response plugins.
@@ -238,6 +255,35 @@
public abstract void appendErrorMessage(Message message);
/**
+ * Retrieves the real, masked error message for this operation. Its contents
+ * may be altered by pre-parse, pre-operation, and post-operation plugins, but
+ * not by post-response plugins.
+ *
+ * @return The real, masked error message for this operation.
+ */
+ MessageBuilder getMaskedErrorMessage();
+
+ /**
+ * Specifies the real, masked error message for this operation. This method
+ * may not be called by post-response plugins.
+ *
+ * @param maskedErrorMessage
+ * The real, masked error message for this operation.
+ */
+ void setMaskedErrorMessage(MessageBuilder maskedErrorMessage);
+
+ /**
+ * Appends the provided message to the real, masked error message buffer. If
+ * the buffer has not yet been created, then this will create it first and
+ * then add the provided message. This method may not be called by
+ * post-response plugins.
+ *
+ * @param maskedMessage
+ * The message to append to the real, masked error message
+ */
+ void appendMaskedErrorMessage(Message maskedMessage);
+
+ /**
* Returns an unmodifiable list containing the additional log items for this
* operation, which should be written to the log but not included in the
* response to the client.
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 4f09823..cacf2bf 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
@@ -160,34 +160,40 @@
// Check for a request to cancel this operation.
checkIfCanceled(false);
-
- BooleanHolder executePostOpPlugins = new BooleanHolder(false);
- processAdd(clientConnection, executePostOpPlugins);
-
- PluginConfigManager pluginConfigManager =
- DirectoryServer.getPluginConfigManager();
-
- // Invoke the post-operation or post-synchronization add plugins.
- if (isSynchronizationOperation())
+ try
{
- if (getResultCode() == ResultCode.SUCCESS)
+ BooleanHolder executePostOpPlugins = new BooleanHolder(false);
+ processAdd(clientConnection, executePostOpPlugins);
+
+ PluginConfigManager pluginConfigManager =
+ DirectoryServer.getPluginConfigManager();
+
+ // Invoke the post-operation or post-synchronization add plugins.
+ if (isSynchronizationOperation())
{
- pluginConfigManager.invokePostSynchronizationAddPlugins(this);
+ if (getResultCode() == ResultCode.SUCCESS)
+ {
+ pluginConfigManager.invokePostSynchronizationAddPlugins(this);
+ }
+ }
+ else if (executePostOpPlugins.value)
+ {
+ // FIXME -- Should this also be done while holding the locks?
+ PluginResult.PostOperation postOpResult =
+ pluginConfigManager.invokePostOperationAddPlugins(this);
+ if (!postOpResult.continueProcessing())
+ {
+ setResultCode(postOpResult.getResultCode());
+ appendErrorMessage(postOpResult.getErrorMessage());
+ setMatchedDN(postOpResult.getMatchedDN());
+ setReferralURLs(postOpResult.getReferralURLs());
+ return;
+ }
}
}
- else if (executePostOpPlugins.value)
+ finally
{
- // FIXME -- Should this also be done while holding the locks?
- PluginResult.PostOperation postOpResult =
- pluginConfigManager.invokePostOperationAddPlugins(this);
- if (!postOpResult.continueProcessing())
- {
- setResultCode(postOpResult.getResultCode());
- appendErrorMessage(postOpResult.getErrorMessage());
- setMatchedDN(postOpResult.getMatchedDN());
- setReferralURLs(postOpResult.getReferralURLs());
- return;
- }
+ LocalBackendWorkflowElement.filterNonDisclosableMatchedDN(this);
}
// Register a post-response call-back which will notify persistent
@@ -269,9 +275,8 @@
entryLock = LockManager.lockWrite(entryDN);
if (entryLock == null)
{
- setResultCode(ResultCode.BUSY);
- appendErrorMessage(ERR_ADD_CANNOT_LOCK_ENTRY.get(String
- .valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entryDN, ResultCode.BUSY,
+ ERR_ADD_CANNOT_LOCK_ENTRY.get(String.valueOf(entryDN)));
return;
}
@@ -286,8 +291,8 @@
provider.handleConflictResolution(this);
if (!result.continueProcessing())
{
- setResultCode(result.getResultCode());
- appendErrorMessage(result.getErrorMessage());
+ setResultCodeAndMessageNoInfoDisclosure(entryDN,
+ result.getResultCode(), result.getErrorMessage());
setMatchedDN(result.getMatchedDN());
setReferralURLs(result.getReferralURLs());
return;
@@ -333,9 +338,9 @@
// above the parent results in a correct referral.
if (DirectoryServer.entryExists(entryDN))
{
- setResultCode(ResultCode.ENTRY_ALREADY_EXISTS);
- appendErrorMessage(ERR_ADD_ENTRY_ALREADY_EXISTS.get(String
- .valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entryDN,
+ ResultCode.ENTRY_ALREADY_EXISTS,
+ ERR_ADD_ENTRY_ALREADY_EXISTS.get(String.valueOf(entryDN)));
return;
}
@@ -347,12 +352,24 @@
if (parentEntry == null)
{
- setMatchedDN(findMatchedDN(parentDN));
+ final DN matchedDN = findMatchedDN(parentDN);
+ setMatchedDN(matchedDN);
// The parent doesn't exist, so this add can't be successful.
- setResultCode(ResultCode.NO_SUCH_OBJECT);
- appendErrorMessage(ERR_ADD_NO_PARENT.get(String.valueOf(entryDN),
- String.valueOf(parentDN)));
+ if (matchedDN != null)
+ {
+ // check whether matchedDN allows to disclose info
+ setResultCodeAndMessageNoInfoDisclosure(matchedDN,
+ ResultCode.NO_SUCH_OBJECT, ERR_ADD_NO_PARENT.get(String
+ .valueOf(entryDN), String.valueOf(parentDN)));
+ }
+ else
+ {
+ // no matched DN either, so let's return normal error code
+ setResultCode(ResultCode.NO_SUCH_OBJECT);
+ appendErrorMessage(ERR_ADD_NO_PARENT.get(String.valueOf(entryDN),
+ String.valueOf(parentDN)));
+ }
return;
}
}
@@ -429,9 +446,10 @@
if (!AccessControlConfigManager.getInstance().getAccessControlHandler()
.isAllowed(this))
{
- setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
- appendErrorMessage(ERR_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS
- .get(String.valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entryDN,
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ ERR_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS.get(
+ String.valueOf(entryDN)));
return;
}
}
@@ -470,17 +488,17 @@
switch (DirectoryServer.getWritabilityMode())
{
case DISABLED:
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(ERR_ADD_SERVER_READONLY.get(String
- .valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entryDN,
+ ResultCode.UNWILLING_TO_PERFORM,
+ ERR_ADD_SERVER_READONLY.get(String.valueOf(entryDN)));
return;
case INTERNAL_ONLY:
if (!(isInternalOperation() || isSynchronizationOperation()))
{
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(ERR_ADD_SERVER_READONLY.get(String
- .valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entryDN,
+ ResultCode.UNWILLING_TO_PERFORM,
+ ERR_ADD_SERVER_READONLY.get(String.valueOf(entryDN)));
return;
}
break;
@@ -489,17 +507,17 @@
switch (backend.getWritabilityMode())
{
case DISABLED:
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(ERR_ADD_BACKEND_READONLY.get(String
- .valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entryDN,
+ ResultCode.UNWILLING_TO_PERFORM,
+ ERR_ADD_BACKEND_READONLY.get(String.valueOf(entryDN)));
return;
case INTERNAL_ONLY:
if (!(isInternalOperation() || isSynchronizationOperation()))
{
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(ERR_ADD_BACKEND_READONLY.get(String
- .valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entryDN,
+ ResultCode.UNWILLING_TO_PERFORM,
+ ERR_ADD_BACKEND_READONLY.get(String.valueOf(entryDN)));
return;
}
break;
@@ -556,7 +574,6 @@
}
setResponseData(de);
- return;
}
finally
{
@@ -619,7 +636,7 @@
}
private boolean checkHasReadOnlyAttributes(
- Map<AttributeType, List<Attribute>> attributes)
+ Map<AttributeType, List<Attribute>> attributes) throws DirectoryException
{
for (AttributeType at : attributes.keySet())
{
@@ -627,10 +644,10 @@
{
if (!(isInternalOperation() || isSynchronizationOperation()))
{
- setResultCode(ResultCode.CONSTRAINT_VIOLATION);
- appendErrorMessage(ERR_ADD_ATTR_IS_NO_USER_MOD.get(String
- .valueOf(entryDN), at.getNameOrOID()));
-
+ setResultCodeAndMessageNoInfoDisclosure(entryDN,
+ ResultCode.CONSTRAINT_VIOLATION,
+ ERR_ADD_ATTR_IS_NO_USER_MOD.get(
+ String.valueOf(entryDN), at.getNameOrOID()));
return true;
}
}
@@ -638,6 +655,23 @@
return false;
}
+ private DirectoryException newDirectoryException(DN entryDN,
+ ResultCode resultCode, Message message) throws DirectoryException
+ {
+ return LocalBackendWorkflowElement.newDirectoryException(this, null,
+ entryDN, resultCode, message, ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ ERR_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS.get(String.valueOf(entryDN)));
+ }
+
+ private void setResultCodeAndMessageNoInfoDisclosure(DN entryDN,
+ ResultCode resultCode, Message message) throws DirectoryException
+ {
+ LocalBackendWorkflowElement.setResultCodeAndMessageNoInfoDisclosure(this,
+ null, entryDN, resultCode, message,
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ ERR_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS.get(String.valueOf(entryDN)));
+ }
+
/**
* Acquire a read lock on the parent of the entry to add.
*
@@ -679,7 +713,7 @@
parentLock = LockManager.lockRead(parentDN);
if (parentLock == null)
{
- throw new DirectoryException(ResultCode.BUSY,
+ throw newDirectoryException(entryDN, ResultCode.BUSY,
ERR_ADD_CANNOT_LOCK_PARENT.get(
String.valueOf(entryDN),
String.valueOf(parentDN)));
@@ -736,7 +770,7 @@
}
else
{
- throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
+ throw newDirectoryException(entryDN, ResultCode.CONSTRAINT_VIOLATION,
ERR_ADD_MISSING_RDN_ATTRIBUTE.get(
String.valueOf(entryDN), n));
}
@@ -1056,7 +1090,7 @@
{
if (at.isObsolete())
{
- throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
+ throw newDirectoryException(entryDN, ResultCode.CONSTRAINT_VIOLATION,
WARN_ADD_ATTR_IS_OBSOLETE.get(
String.valueOf(entryDN),
at.getNameOrOID()));
@@ -1067,7 +1101,7 @@
{
if (at.isObsolete())
{
- throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
+ throw newDirectoryException(entryDN, ResultCode.CONSTRAINT_VIOLATION,
WARN_ADD_ATTR_IS_OBSOLETE.get(
String.valueOf(entryDN),
at.getNameOrOID()));
@@ -1078,7 +1112,7 @@
{
if (oc.isObsolete())
{
- throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
+ throw newDirectoryException(entryDN, ResultCode.CONSTRAINT_VIOLATION,
WARN_ADD_OC_IS_OBSOLETE.get(
String.valueOf(entryDN),
oc.getNameOrOID()));
@@ -1179,7 +1213,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
- throw new DirectoryException(de.getResultCode(),
+ throw newDirectoryException(entryDN, de.getResultCode(),
ERR_ADD_CANNOT_PROCESS_ASSERTION_FILTER.get(
String.valueOf(entryDN),
de.getMessageObject()));
@@ -1199,7 +1233,7 @@
{
if (!filter.matchesEntry(entry))
{
- throw new DirectoryException(ResultCode.ASSERTION_FAILED,
+ throw newDirectoryException(entryDN, ResultCode.ASSERTION_FAILED,
ERR_ADD_ASSERTION_FAILED.get(String
.valueOf(entryDN)));
}
@@ -1216,7 +1250,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
- throw new DirectoryException(de.getResultCode(),
+ throw newDirectoryException(entryDN, de.getResultCode(),
ERR_ADD_CANNOT_PROCESS_ASSERTION_FILTER.get(
String.valueOf(entryDN),
de.getMessageObject()));
@@ -1296,7 +1330,7 @@
{
if ((backend == null) || (! backend.supportsControl(oid)))
{
- throw new DirectoryException(
+ throw newDirectoryException(entryDN,
ResultCode.UNAVAILABLE_CRITICAL_EXTENSION,
ERR_ADD_UNSUPPORTED_CRITICAL_CONTROL.get(
String.valueOf(entryDN), oid));
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 54f46d3..3a30f8e 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
@@ -31,6 +31,7 @@
import java.util.Set;
import java.util.concurrent.locks.Lock;
+import org.opends.messages.Message;
import org.opends.server.api.Backend;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.plugin.PluginResult;
@@ -132,27 +133,33 @@
// Check for a request to cancel this operation.
checkIfCanceled(false);
-
- BooleanHolder executePostOpPlugins = new BooleanHolder(false);
- processCompare(executePostOpPlugins);
-
- // Check for a request to cancel this operation.
- checkIfCanceled(false);
-
- // Invoke the post-operation compare plugins.
- if (executePostOpPlugins.value)
+ try
{
- PluginResult.PostOperation postOpResult =
- DirectoryServer.getPluginConfigManager()
- .invokePostOperationComparePlugins(this);
- if (!postOpResult.continueProcessing())
+ BooleanHolder executePostOpPlugins = new BooleanHolder(false);
+ processCompare(executePostOpPlugins);
+
+ // Check for a request to cancel this operation.
+ checkIfCanceled(false);
+
+ // Invoke the post-operation compare plugins.
+ if (executePostOpPlugins.value)
{
- setResultCode(postOpResult.getResultCode());
- appendErrorMessage(postOpResult.getErrorMessage());
- setMatchedDN(postOpResult.getMatchedDN());
- setReferralURLs(postOpResult.getReferralURLs());
+ PluginResult.PostOperation postOpResult =
+ DirectoryServer.getPluginConfigManager()
+ .invokePostOperationComparePlugins(this);
+ if (!postOpResult.continueProcessing())
+ {
+ setResultCode(postOpResult.getResultCode());
+ appendErrorMessage(postOpResult.getErrorMessage());
+ setMatchedDN(postOpResult.getMatchedDN());
+ setReferralURLs(postOpResult.getReferralURLs());
+ }
}
}
+ finally
+ {
+ LocalBackendWorkflowElement.filterNonDisclosableMatchedDN(this);
+ }
}
private void processCompare(BooleanHolder executePostOpPlugins)
@@ -170,7 +177,7 @@
// If the target entry is in the server configuration, then make sure the
// requester has the CONFIG_READ privilege.
if (DirectoryServer.getConfigHandler().handlesEntry(entryDN)
- && (!clientConnection.hasPrivilege(Privilege.CONFIG_READ, this)))
+ && !clientConnection.hasPrivilege(Privilege.CONFIG_READ, this))
{
appendErrorMessage(ERR_COMPARE_CONFIG_INSUFFICIENT_PRIVILEGES.get());
setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
@@ -183,16 +190,16 @@
// Grab a read lock on the entry.
final Lock readLock = LockManager.lockRead(entryDN);
- if (readLock == null)
- {
- setResultCode(ResultCode.BUSY);
- appendErrorMessage(ERR_COMPARE_CANNOT_LOCK_ENTRY.get(String
- .valueOf(entryDN)));
- return;
- }
try
{
+ if (readLock == null)
+ {
+ setResultCodeAndMessageNoInfoDisclosure(null, entryDN, ResultCode.BUSY,
+ ERR_COMPARE_CANNOT_LOCK_ENTRY.get(String.valueOf(entryDN)));
+ return;
+ }
+
// Get the entry. If it does not exist, then fail.
try
{
@@ -216,27 +223,14 @@
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
- setResultCode(de.getResultCode());
- appendErrorMessage(de.getMessageObject());
+ setResultCodeAndMessageNoInfoDisclosure(entry, entryDN,
+ de.getResultCode(), de.getMessageObject());
return;
}
// Check to see if there are any controls in the request. If so, then
// see if there is any special processing required.
- try
- {
- handleRequestControls();
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResponseData(de);
- return;
- }
+ handleRequestControls();
// Check to see if the client has permission to perform the
@@ -253,9 +247,10 @@
if (!AccessControlConfigManager.getInstance().getAccessControlHandler()
.isAllowed(this))
{
- setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
- appendErrorMessage(ERR_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS
- .get(String.valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entry, entryDN,
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ ERR_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS.get(String
+ .valueOf(entryDN)));
return;
}
}
@@ -331,12 +326,40 @@
}
}
}
+ catch (DirectoryException de)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, de);
+ }
+
+ setResponseData(de);
+ }
finally
{
- LockManager.unlock(entryDN, readLock);
+ if (readLock != null)
+ {
+ LockManager.unlock(entryDN, readLock);
+ }
}
}
+ private DirectoryException newDirectoryException(Entry entry,
+ ResultCode resultCode, Message message) throws DirectoryException
+ {
+ return LocalBackendWorkflowElement.newDirectoryException(this, entry, null,
+ resultCode, message, ResultCode.NO_SUCH_OBJECT,
+ ERR_COMPARE_NO_SUCH_ENTRY.get(String.valueOf(entryDN)));
+ }
+
+ private void setResultCodeAndMessageNoInfoDisclosure(Entry entry, DN entryDN,
+ ResultCode realResultCode, Message realMessage) throws DirectoryException
+ {
+ LocalBackendWorkflowElement.setResultCodeAndMessageNoInfoDisclosure(this,
+ entry, entryDN, realResultCode, realMessage, ResultCode.NO_SUCH_OBJECT,
+ ERR_COMPARE_NO_SUCH_ENTRY.get(String.valueOf(entryDN)));
+ }
+
private DN findMatchedDN(DN entryDN)
{
try
@@ -400,7 +423,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
- throw new DirectoryException(de.getResultCode(),
+ throw newDirectoryException(entry, de.getResultCode(),
ERR_COMPARE_CANNOT_PROCESS_ASSERTION_FILTER.get(
String.valueOf(entryDN),
de.getMessageObject()));
@@ -420,7 +443,7 @@
{
if (!filter.matchesEntry(entry))
{
- throw new DirectoryException(ResultCode.ASSERTION_FAILED,
+ throw newDirectoryException(entry, ResultCode.ASSERTION_FAILED,
ERR_COMPARE_ASSERTION_FAILED.get(String
.valueOf(entryDN)));
}
@@ -437,7 +460,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
- throw new DirectoryException(de.getResultCode(),
+ throw newDirectoryException(entry, de.getResultCode(),
ERR_COMPARE_CANNOT_PROCESS_ASSERTION_FILTER.get(
String.valueOf(entryDN),
de.getMessageObject()));
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 d28ac4b..9f09437 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
@@ -144,31 +144,38 @@
// Check for a request to cancel this operation.
checkIfCanceled(false);
- BooleanHolder executePostOpPlugins = new BooleanHolder(false);
- processDelete(executePostOpPlugins);
-
- // Invoke the post-operation or post-synchronization delete plugins.
- PluginConfigManager pluginConfigManager =
- DirectoryServer.getPluginConfigManager();
- if (isSynchronizationOperation())
+ try
{
- if (getResultCode() == ResultCode.SUCCESS)
+ BooleanHolder executePostOpPlugins = new BooleanHolder(false);
+ processDelete(executePostOpPlugins);
+
+ // Invoke the post-operation or post-synchronization delete plugins.
+ PluginConfigManager pluginConfigManager =
+ DirectoryServer.getPluginConfigManager();
+ if (isSynchronizationOperation())
{
- pluginConfigManager.invokePostSynchronizationDeletePlugins(this);
+ if (getResultCode() == ResultCode.SUCCESS)
+ {
+ pluginConfigManager.invokePostSynchronizationDeletePlugins(this);
+ }
+ }
+ else if (executePostOpPlugins.value)
+ {
+ PluginResult.PostOperation postOpResult =
+ pluginConfigManager.invokePostOperationDeletePlugins(this);
+ if (!postOpResult.continueProcessing())
+ {
+ setResultCode(postOpResult.getResultCode());
+ appendErrorMessage(postOpResult.getErrorMessage());
+ setMatchedDN(postOpResult.getMatchedDN());
+ setReferralURLs(postOpResult.getReferralURLs());
+ return;
+ }
}
}
- else if (executePostOpPlugins.value)
+ finally
{
- PluginResult.PostOperation postOpResult =
- pluginConfigManager.invokePostOperationDeletePlugins(this);
- if (!postOpResult.continueProcessing())
- {
- setResultCode(postOpResult.getResultCode());
- appendErrorMessage(postOpResult.getErrorMessage());
- setMatchedDN(postOpResult.getMatchedDN());
- setReferralURLs(postOpResult.getReferralURLs());
- return;
- }
+ LocalBackendWorkflowElement.filterNonDisclosableMatchedDN(this);
}
// Register a post-response call-back which will notify persistent
@@ -227,16 +234,16 @@
// Grab a write lock on the entry.
final Lock entryLock = LockManager.lockWrite(entryDN);
- if (entryLock == null)
- {
- setResultCode(ResultCode.BUSY);
- appendErrorMessage(ERR_DELETE_CANNOT_LOCK_ENTRY.get(String
- .valueOf(entryDN)));
- return;
- }
try
{
+ if (entryLock == null)
+ {
+ setResultCodeAndMessageNoInfoDisclosure(entry, ResultCode.BUSY,
+ ERR_DELETE_CANNOT_LOCK_ENTRY.get(String.valueOf(entryDN)));
+ return;
+ }
+
// Get the entry to delete. If it doesn't exist, then fail.
entry = backend.getEntry(entryDN);
if (entry == null)
@@ -272,9 +279,10 @@
if (!AccessControlConfigManager.getInstance().getAccessControlHandler()
.isAllowed(this))
{
- setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
- appendErrorMessage(ERR_DELETE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS
- .get(String.valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entry,
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ ERR_DELETE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS.get(String
+ .valueOf(entryDN)));
return;
}
}
@@ -322,17 +330,17 @@
switch (DirectoryServer.getWritabilityMode())
{
case DISABLED:
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(ERR_DELETE_SERVER_READONLY.get(String
- .valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entry,
+ ResultCode.UNWILLING_TO_PERFORM,
+ ERR_DELETE_SERVER_READONLY.get(String.valueOf(entryDN)));
return;
case INTERNAL_ONLY:
if (!(isInternalOperation() || isSynchronizationOperation()))
{
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(ERR_DELETE_SERVER_READONLY.get(String
- .valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entry,
+ ResultCode.UNWILLING_TO_PERFORM,
+ ERR_DELETE_SERVER_READONLY.get(String.valueOf(entryDN)));
return;
}
}
@@ -340,17 +348,17 @@
switch (backend.getWritabilityMode())
{
case DISABLED:
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(ERR_DELETE_BACKEND_READONLY.get(String
- .valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entry,
+ ResultCode.UNWILLING_TO_PERFORM,
+ ERR_DELETE_BACKEND_READONLY.get(String.valueOf(entryDN)));
return;
case INTERNAL_ONLY:
if (!(isInternalOperation() || isSynchronizationOperation()))
{
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(ERR_DELETE_BACKEND_READONLY.get(String
- .valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(entry,
+ ResultCode.UNWILLING_TO_PERFORM,
+ ERR_DELETE_BACKEND_READONLY.get(String.valueOf(entryDN)));
return;
}
}
@@ -368,9 +376,10 @@
{
if (dn.isDescendantOf(entryDN))
{
- setResultCode(ResultCode.NOT_ALLOWED_ON_NONLEAF);
- appendErrorMessage(ERR_DELETE_HAS_SUB_BACKEND.get(String
- .valueOf(entryDN), String.valueOf(dn)));
+ setResultCodeAndMessageNoInfoDisclosure(entry,
+ ResultCode.NOT_ALLOWED_ON_NONLEAF,
+ ERR_DELETE_HAS_SUB_BACKEND.get(String.valueOf(entryDN),
+ String.valueOf(dn)));
return;
}
}
@@ -407,15 +416,33 @@
}
setResponseData(de);
- return;
}
finally
{
- LockManager.unlock(entryDN, entryLock);
+ if (entryLock != null)
+ {
+ LockManager.unlock(entryDN, entryLock);
+ }
processSynchPostOperationPlugins();
}
}
+ private DirectoryException newDirectoryException(Entry entry,
+ ResultCode resultCode, Message message) throws DirectoryException
+ {
+ return LocalBackendWorkflowElement.newDirectoryException(this, entry, null,
+ resultCode, message, ResultCode.NO_SUCH_OBJECT,
+ ERR_DELETE_NO_SUCH_ENTRY.get(String.valueOf(entryDN)));
+ }
+
+ private void setResultCodeAndMessageNoInfoDisclosure(Entry entry,
+ ResultCode resultCode, Message message) throws DirectoryException
+ {
+ LocalBackendWorkflowElement.setResultCodeAndMessageNoInfoDisclosure(this,
+ entry, null, resultCode, message, ResultCode.NO_SUCH_OBJECT,
+ ERR_DELETE_NO_SUCH_ENTRY.get(String.valueOf(entryDN)));
+ }
+
private DN findMatchedDN(DN entryDN)
{
try
@@ -480,7 +507,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
- throw new DirectoryException(de.getResultCode(),
+ throw newDirectoryException(entry, de.getResultCode(),
ERR_DELETE_CANNOT_PROCESS_ASSERTION_FILTER.get(
String.valueOf(entryDN),
de.getMessageObject()));
@@ -500,7 +527,7 @@
{
if (!filter.matchesEntry(entry))
{
- throw new DirectoryException(ResultCode.ASSERTION_FAILED,
+ throw newDirectoryException(entry, ResultCode.ASSERTION_FAILED,
ERR_DELETE_ASSERTION_FAILED.get(String
.valueOf(entryDN)));
}
@@ -517,7 +544,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
- throw new DirectoryException(de.getResultCode(),
+ throw newDirectoryException(entry, de.getResultCode(),
ERR_DELETE_CANNOT_PROCESS_ASSERTION_FILTER.get(
String.valueOf(entryDN),
de.getMessageObject()));
@@ -591,7 +618,7 @@
{
if ((backend == null) || (! backend.supportsControl(oid)))
{
- throw new DirectoryException(
+ throw newDirectoryException(entry,
ResultCode.UNAVAILABLE_CRITICAL_EXTENSION,
ERR_DELETE_UNSUPPORTED_CRITICAL_CONTROL.get(
String.valueOf(entryDN), oid));
@@ -617,8 +644,8 @@
SynchronizationProviderResult result =
provider.handleConflictResolution(this);
if (! result.continueProcessing()) {
- setResultCode(result.getResultCode());
- appendErrorMessage(result.getErrorMessage());
+ setResultCodeAndMessageNoInfoDisclosure(entry,
+ result.getResultCode(), result.getErrorMessage());
setMatchedDN(result.getMatchedDN());
setReferralURLs(result.getReferralURLs());
returnVal = false;
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 28c9399..06114da 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
@@ -178,31 +178,38 @@
// Check for a request to cancel this operation.
checkIfCanceled(false);
- BooleanHolder executePostOpPlugins = new BooleanHolder(false);
- processModifyDN(executePostOpPlugins);
-
- // Invoke the post-operation or post-synchronization modify DN plugins.
- PluginConfigManager pluginConfigManager =
- DirectoryServer.getPluginConfigManager();
- if (isSynchronizationOperation())
+ try
{
- if (getResultCode() == ResultCode.SUCCESS)
+ BooleanHolder executePostOpPlugins = new BooleanHolder(false);
+ processModifyDN(executePostOpPlugins);
+
+ // Invoke the post-operation or post-synchronization modify DN plugins.
+ PluginConfigManager pluginConfigManager =
+ DirectoryServer.getPluginConfigManager();
+ if (isSynchronizationOperation())
{
- pluginConfigManager.invokePostSynchronizationModifyDNPlugins(this);
+ if (getResultCode() == ResultCode.SUCCESS)
+ {
+ pluginConfigManager.invokePostSynchronizationModifyDNPlugins(this);
+ }
+ }
+ else if (executePostOpPlugins.value)
+ {
+ PluginResult.PostOperation postOpResult =
+ pluginConfigManager.invokePostOperationModifyDNPlugins(this);
+ if (!postOpResult.continueProcessing())
+ {
+ setResultCode(postOpResult.getResultCode());
+ appendErrorMessage(postOpResult.getErrorMessage());
+ setMatchedDN(postOpResult.getMatchedDN());
+ setReferralURLs(postOpResult.getReferralURLs());
+ return;
+ }
}
}
- else if (executePostOpPlugins.value)
+ finally
{
- PluginResult.PostOperation postOpResult =
- pluginConfigManager.invokePostOperationModifyDNPlugins(this);
- if (!postOpResult.continueProcessing())
- {
- setResultCode(postOpResult.getResultCode());
- appendErrorMessage(postOpResult.getErrorMessage());
- setMatchedDN(postOpResult.getMatchedDN());
- setReferralURLs(postOpResult.getReferralURLs());
- return;
- }
+ LocalBackendWorkflowElement.filterNonDisclosableMatchedDN(this);
}
// Register a post-response call-back which will notify persistent
@@ -328,51 +335,42 @@
// Acquire write locks for the current and new DN.
final Lock currentLock = LockManager.lockWrite(entryDN);
- if (currentLock == null)
- {
- setResultCode(ResultCode.BUSY);
- appendErrorMessage(ERR_MODDN_CANNOT_LOCK_CURRENT_DN.get(String
- .valueOf(entryDN)));
- return;
- }
-
Lock newLock = null;
- try
- {
- newLock = LockManager.lockWrite(newDN);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, e);
- }
-
- LockManager.unlock(entryDN, currentLock);
-
- if (newLock != null)
- {
- LockManager.unlock(newDN, newLock);
- }
-
- setResultCode(DirectoryServer.getServerErrorResultCode());
- appendErrorMessage(ERR_MODDN_EXCEPTION_LOCKING_NEW_DN.get(String
- .valueOf(entryDN), String.valueOf(newDN), getExceptionMessage(e)));
- return;
- }
-
- if (newLock == null)
- {
- LockManager.unlock(entryDN, currentLock);
-
- setResultCode(ResultCode.BUSY);
- appendErrorMessage(ERR_MODDN_CANNOT_LOCK_NEW_DN.get(String
- .valueOf(entryDN), String.valueOf(newDN)));
- return;
- }
try
{
+ if (currentLock == null)
+ {
+ setResultCodeAndMessageNoInfoDisclosure(null, entryDN, ResultCode.BUSY,
+ ERR_MODDN_CANNOT_LOCK_CURRENT_DN.get(String.valueOf(entryDN)));
+ return;
+ }
+
+ try
+ {
+ newLock = LockManager.lockWrite(newDN);
+ if (newLock == null)
+ {
+ setResultCodeAndMessageNoInfoDisclosure(null, newDN, ResultCode.BUSY,
+ ERR_MODDN_CANNOT_LOCK_NEW_DN.get(String.valueOf(entryDN), String
+ .valueOf(newDN)));
+ return;
+ }
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ TRACER.debugCaught(DebugLogLevel.ERROR, e);
+ }
+
+ setResultCodeAndMessageNoInfoDisclosure(null, newDN,
+ DirectoryServer.getServerErrorResultCode(),
+ ERR_MODDN_EXCEPTION_LOCKING_NEW_DN.get(String.valueOf(entryDN),
+ String.valueOf(newDN), getExceptionMessage(e)));
+ return;
+ }
+
// Check for a request to cancel this operation.
checkIfCanceled(false);
@@ -410,9 +408,10 @@
if (!AccessControlConfigManager.getInstance().getAccessControlHandler()
.isAllowed(this))
{
- setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
- appendErrorMessage(ERR_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS
- .get(String.valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(currentEntry, entryDN,
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ ERR_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS.get(String
+ .valueOf(entryDN)));
return;
}
}
@@ -430,7 +429,7 @@
// init the modifications
addModification(null);
- List<Modification> modifications = this.getModifications();
+ List<Modification> modifications = getModifications();
if (!handleConflictResolution())
{
@@ -567,12 +566,34 @@
}
finally
{
- LockManager.unlock(entryDN, currentLock);
- LockManager.unlock(newDN, newLock);
+ if (currentLock != null)
+ {
+ LockManager.unlock(entryDN, currentLock);
+ }
+ if (newLock != null)
+ {
+ LockManager.unlock(newDN, newLock);
+ }
processSynchPostOperationPlugins();
}
}
+ private DirectoryException newDirectoryException(Entry entry, DN entryDN,
+ ResultCode resultCode, Message message) throws DirectoryException
+ {
+ return LocalBackendWorkflowElement.newDirectoryException(this, entry,
+ entryDN, resultCode, message, ResultCode.NO_SUCH_OBJECT,
+ ERR_MODDN_NO_CURRENT_ENTRY.get(String.valueOf(entryDN)));
+ }
+
+ private void setResultCodeAndMessageNoInfoDisclosure(Entry entry, DN entryDN,
+ ResultCode realResultCode, Message realMessage) throws DirectoryException
+ {
+ LocalBackendWorkflowElement.setResultCodeAndMessageNoInfoDisclosure(this,
+ entry, entryDN, realResultCode, realMessage, ResultCode.NO_SUCH_OBJECT,
+ ERR_MODDN_NO_CURRENT_ENTRY.get(String.valueOf(entryDN)));
+ }
+
private DN findMatchedDN(DN entryDN)
{
try
@@ -637,10 +658,11 @@
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
- throw new DirectoryException(de.getResultCode(),
- ERR_MODDN_CANNOT_PROCESS_ASSERTION_FILTER.get(
- String.valueOf(entryDN),
- de.getMessageObject()));
+ throw newDirectoryException(currentEntry, entryDN,
+ de.getResultCode(),
+ ERR_MODDN_CANNOT_PROCESS_ASSERTION_FILTER.get(
+ String.valueOf(entryDN),
+ de.getMessageObject()));
}
// Check if the current user has permission to make
@@ -657,7 +679,8 @@
{
if (!filter.matchesEntry(currentEntry))
{
- throw new DirectoryException(ResultCode.ASSERTION_FAILED,
+ throw newDirectoryException(currentEntry, entryDN,
+ ResultCode.ASSERTION_FAILED,
ERR_MODDN_ASSERTION_FAILED.get(String
.valueOf(entryDN)));
}
@@ -674,10 +697,11 @@
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
- throw new DirectoryException(de.getResultCode(),
- ERR_MODDN_CANNOT_PROCESS_ASSERTION_FILTER.get(
- String.valueOf(entryDN),
- de.getMessageObject()));
+ throw newDirectoryException(currentEntry, entryDN,
+ de.getResultCode(),
+ ERR_MODDN_CANNOT_PROCESS_ASSERTION_FILTER.get(
+ String.valueOf(entryDN),
+ de.getMessageObject()));
}
}
else if (oid.equals(OID_LDAP_NOOP_OPENLDAP_ASSIGNED))
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 0704a5c..910a7ed 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -70,8 +70,6 @@
*/
private static final DebugTracer TRACER = getTracer();
-
-
/**
* The backend in which the target entry exists.
*/
@@ -295,40 +293,47 @@
// Check for a request to cancel this operation.
checkIfCanceled(false);
- BooleanHolder executePostOpPlugins = new BooleanHolder(false);
- processModify(executePostOpPlugins);
-
- // If the password policy request control was included, then make sure we
- // send the corresponding response control.
- if (pwPolicyControlRequested)
+ try
{
- addResponseControl(new PasswordPolicyResponseControl(null, 0,
- pwpErrorType));
- }
+ BooleanHolder executePostOpPlugins = new BooleanHolder(false);
+ processModify(executePostOpPlugins);
- // Invoke the post-operation or post-synchronization modify plugins.
- PluginConfigManager pluginConfigManager =
- DirectoryServer.getPluginConfigManager();
- if (isSynchronizationOperation())
- {
- if (getResultCode() == ResultCode.SUCCESS)
+ // If the password policy request control was included, then make sure we
+ // send the corresponding response control.
+ if (pwPolicyControlRequested)
{
- pluginConfigManager.invokePostSynchronizationModifyPlugins(this);
+ addResponseControl(new PasswordPolicyResponseControl(null, 0,
+ pwpErrorType));
+ }
+
+ // Invoke the post-operation or post-synchronization modify plugins.
+ PluginConfigManager pluginConfigManager =
+ DirectoryServer.getPluginConfigManager();
+ if (isSynchronizationOperation())
+ {
+ if (getResultCode() == ResultCode.SUCCESS)
+ {
+ pluginConfigManager.invokePostSynchronizationModifyPlugins(this);
+ }
+ }
+ else if (executePostOpPlugins.value)
+ {
+ // FIXME -- Should this also be done while holding the locks?
+ PluginResult.PostOperation postOpResult =
+ pluginConfigManager.invokePostOperationModifyPlugins(this);
+ if (!postOpResult.continueProcessing())
+ {
+ setResultCode(postOpResult.getResultCode());
+ appendErrorMessage(postOpResult.getErrorMessage());
+ setMatchedDN(postOpResult.getMatchedDN());
+ setReferralURLs(postOpResult.getReferralURLs());
+ return;
+ }
}
}
- else if (executePostOpPlugins.value)
+ finally
{
- // FIXME -- Should this also be done while holding the locks?
- PluginResult.PostOperation postOpResult =
- pluginConfigManager.invokePostOperationModifyPlugins(this);
- if (!postOpResult.continueProcessing())
- {
- setResultCode(postOpResult.getResultCode());
- appendErrorMessage(postOpResult.getErrorMessage());
- setMatchedDN(postOpResult.getMatchedDN());
- setReferralURLs(postOpResult.getReferralURLs());
- return;
- }
+ LocalBackendWorkflowElement.filterNonDisclosableMatchedDN(this);
}
@@ -407,16 +412,16 @@
// Acquire a write lock on the target entry.
final Lock entryLock = LockManager.lockWrite(entryDN);
- if (entryLock == null)
- {
- setResultCode(ResultCode.BUSY);
- appendErrorMessage(ERR_MODIFY_CANNOT_LOCK_ENTRY.get(String
- .valueOf(entryDN)));
- return;
- }
try
{
+ if (entryLock == null)
+ {
+ setResultCodeAndMessageNoInfoDisclosure(currentEntry, ResultCode.BUSY,
+ ERR_MODIFY_CANNOT_LOCK_ENTRY.get(String.valueOf(entryDN)));
+ return;
+ }
+
// Check for a request to cancel this operation.
checkIfCanceled(false);
@@ -480,12 +485,9 @@
// Create a duplicate of the entry and apply the changes to it.
modifiedEntry = currentEntry.duplicate(false);
- if (!noOp)
+ if (!noOp && !handleConflictResolution())
{
- if (!handleConflictResolution())
- {
- return;
- }
+ return;
}
handleSchemaProcessing();
@@ -505,9 +507,10 @@
if (!AccessControlConfigManager.getInstance().getAccessControlHandler()
.isAllowed(this))
{
- setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
- appendErrorMessage(ERR_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS
- .get(String.valueOf(entryDN)));
+ setResultCodeAndMessageNoInfoDisclosure(modifiedEntry,
+ ResultCode.INSUFFICIENT_ACCESS_RIGHTS,
+ ERR_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS.get(String
+ .valueOf(entryDN)));
return;
}
}
@@ -620,15 +623,33 @@
}
setResponseData(de);
- return;
}
finally
{
- LockManager.unlock(entryDN, entryLock);
+ if (entryLock != null)
+ {
+ LockManager.unlock(entryDN, entryLock);
+ }
processSynchPostOperationPlugins();
}
}
+ private DirectoryException newDirectoryException(Entry entry,
+ ResultCode resultCode, Message message) throws DirectoryException
+ {
+ return LocalBackendWorkflowElement.newDirectoryException(this, entry, null,
+ resultCode, message, ResultCode.NO_SUCH_OBJECT,
+ ERR_MODIFY_NO_SUCH_ENTRY.get(String.valueOf(entryDN)));
+ }
+
+ private void setResultCodeAndMessageNoInfoDisclosure(Entry entry,
+ ResultCode realResultCode, Message realMessage) throws DirectoryException
+ {
+ LocalBackendWorkflowElement.setResultCodeAndMessageNoInfoDisclosure(this,
+ entry, null, realResultCode, realMessage, ResultCode.NO_SUCH_OBJECT,
+ ERR_MODIFY_NO_SUCH_ENTRY.get(String.valueOf(entryDN)));
+ }
+
private DN findMatchedDN(DN entryDN)
{
try
@@ -694,7 +715,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
- throw new DirectoryException(de.getResultCode(),
+ throw newDirectoryException(currentEntry, de.getResultCode(),
ERR_MODIFY_CANNOT_PROCESS_ASSERTION_FILTER.get(
String.valueOf(entryDN),
de.getMessageObject()));
@@ -714,9 +735,9 @@
{
if (!filter.matchesEntry(currentEntry))
{
- throw new DirectoryException(ResultCode.ASSERTION_FAILED,
- ERR_MODIFY_ASSERTION_FAILED.get(String
- .valueOf(entryDN)));
+ throw newDirectoryException(currentEntry,
+ ResultCode.ASSERTION_FAILED,
+ ERR_MODIFY_ASSERTION_FAILED.get(String.valueOf(entryDN)));
}
}
catch (DirectoryException de)
@@ -731,7 +752,7 @@
TRACER.debugCaught(DebugLogLevel.ERROR, de);
}
- throw new DirectoryException(de.getResultCode(),
+ throw newDirectoryException(currentEntry, de.getResultCode(),
ERR_MODIFY_CANNOT_PROCESS_ASSERTION_FILTER.get(
String.valueOf(entryDN),
de.getMessageObject()));
@@ -825,7 +846,7 @@
{
if ((backend == null) || (! backend.supportsControl(oid)))
{
- throw new DirectoryException(
+ throw newDirectoryException(currentEntry,
ResultCode.UNAVAILABLE_CRITICAL_EXTENSION,
ERR_MODIFY_UNSUPPORTED_CRITICAL_CONTROL.get(
String.valueOf(entryDN), oid));
@@ -858,8 +879,9 @@
if (! (isInternalOperation() || isSynchronizationOperation() ||
m.isInternal()))
{
- throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
- ERR_MODIFY_ATTR_IS_NO_USER_MOD.get(
+ throw newDirectoryException(currentEntry,
+ ResultCode.CONSTRAINT_VIOLATION,
+ ERR_MODIFY_ATTR_IS_NO_USER_MOD.get(
String.valueOf(entryDN), a.getName()));
}
}
@@ -875,8 +897,9 @@
if (! (isInternalOperation() || isSynchronizationOperation() ||
m.isInternal()))
{
- throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
- ERR_MODIFY_ATTR_IS_OBSOLETE.get(
+ throw newDirectoryException(currentEntry,
+ ResultCode.CONSTRAINT_VIOLATION,
+ ERR_MODIFY_ATTR_IS_OBSOLETE.get(
String.valueOf(entryDN), a.getName()));
}
}
@@ -1379,7 +1402,7 @@
// attribute.
if (attr.isEmpty())
{
- throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+ throw newDirectoryException(currentEntry, ResultCode.PROTOCOL_ERROR,
ERR_MODIFY_ADD_NO_VALUES.get(String.valueOf(entryDN),
attr.getName()));
}
@@ -1403,15 +1426,17 @@
if (!syntax.isHumanReadable() || syntax.isBinary())
{
// Value is not human-readable
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- ERR_MODIFY_ADD_INVALID_SYNTAX_NO_VALUE.get(
- String.valueOf(entryDN), attr.getName(), invalidReason));
+ throw newDirectoryException(currentEntry,
+ ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ ERR_MODIFY_ADD_INVALID_SYNTAX_NO_VALUE.get(
+ String.valueOf(entryDN), attr.getName(), invalidReason));
}
else
{
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- ERR_MODIFY_ADD_INVALID_SYNTAX.get(String.valueOf(entryDN), attr
- .getName(), v.getValue().toString(), invalidReason));
+ throw newDirectoryException(currentEntry,
+ ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ ERR_MODIFY_ADD_INVALID_SYNTAX.get(String.valueOf(entryDN),
+ attr.getName(), v.getValue().toString(), invalidReason));
}
}
}
@@ -1455,16 +1480,16 @@
// Add the provided attribute or merge an existing attribute with
// the values of the new attribute. If there are any duplicates,
// then fail.
- List<AttributeValue> duplicateValues =
- new LinkedList<AttributeValue>();
+ List<AttributeValue> duplicateValues = new LinkedList<AttributeValue>();
modifiedEntry.addAttribute(attr, duplicateValues);
if (!duplicateValues.isEmpty() && !permissiveModify)
{
String duplicateValuesStr = collectionToString(duplicateValues, ", ");
- throw new DirectoryException(ResultCode.ATTRIBUTE_OR_VALUE_EXISTS,
- ERR_MODIFY_ADD_DUPLICATE_VALUE.get(String.valueOf(entryDN), attr
- .getName(), duplicateValuesStr));
+ throw newDirectoryException(currentEntry,
+ ResultCode.ATTRIBUTE_OR_VALUE_EXISTS,
+ ERR_MODIFY_ADD_DUPLICATE_VALUE.get(
+ String.valueOf(entryDN), attr.getName(), duplicateValuesStr));
}
}
@@ -1505,16 +1530,16 @@
ObjectClass oc = DirectoryServer.getObjectClass(lowerName);
if (oc == null)
{
- Message message = ERR_ENTRY_ADD_UNKNOWN_OC.get(name, String
- .valueOf(entryDN));
- throw new DirectoryException(ResultCode.OBJECTCLASS_VIOLATION, message);
+ throw newDirectoryException(currentEntry,
+ ResultCode.OBJECTCLASS_VIOLATION,
+ ERR_ENTRY_ADD_UNKNOWN_OC.get(name, String.valueOf(entryDN)));
}
if (oc.isObsolete())
{
- Message message = ERR_ENTRY_ADD_OBSOLETE_OC.get(name, String
- .valueOf(entryDN));
- throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
+ throw newDirectoryException(currentEntry,
+ ResultCode.CONSTRAINT_VIOLATION,
+ ERR_ENTRY_ADD_OBSOLETE_OC.get(name, String.valueOf(entryDN)));
}
}
}
@@ -1551,10 +1576,10 @@
(! modifiedEntry.hasValue(t, attr.getOptions(),
rdn.getAttributeValue(t))))
{
- throw new DirectoryException(ResultCode.NOT_ALLOWED_ON_RDN,
- ERR_MODIFY_DELETE_RDN_ATTR.get(
- String.valueOf(entryDN),
- attr.getName()));
+ throw newDirectoryException(currentEntry,
+ ResultCode.NOT_ALLOWED_ON_RDN,
+ ERR_MODIFY_DELETE_RDN_ATTR.get(
+ String.valueOf(entryDN), attr.getName()));
}
}
else
@@ -1563,10 +1588,10 @@
{
String missingValuesStr = collectionToString(missingValues, ", ");
- throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE,
- ERR_MODIFY_DELETE_MISSING_VALUES.get(
- String.valueOf(entryDN), attr.getName(),
- missingValuesStr));
+ throw newDirectoryException(currentEntry,
+ ResultCode.NO_SUCH_ATTRIBUTE,
+ ERR_MODIFY_DELETE_MISSING_VALUES.get(
+ String.valueOf(entryDN), attr.getName(), missingValuesStr));
}
}
}
@@ -1574,7 +1599,7 @@
{
if (! permissiveModify)
{
- throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE,
+ throw newDirectoryException(currentEntry, ResultCode.NO_SUCH_ATTRIBUTE,
ERR_MODIFY_DELETE_NO_SUCH_ATTR.get(
String.valueOf(entryDN), attr.getName()));
}
@@ -1615,15 +1640,17 @@
if (!syntax.isHumanReadable() || syntax.isBinary())
{
// Value is not human-readable
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- ERR_MODIFY_REPLACE_INVALID_SYNTAX_NO_VALUE.get(
- String.valueOf(entryDN), attr.getName(), invalidReason));
+ throw newDirectoryException(currentEntry,
+ ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ ERR_MODIFY_REPLACE_INVALID_SYNTAX_NO_VALUE.get(
+ String.valueOf(entryDN), attr.getName(), invalidReason));
}
else
{
- throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
- ERR_MODIFY_REPLACE_INVALID_SYNTAX.get(String.valueOf(entryDN),
- attr.getName(), v.getValue().toString(), invalidReason));
+ throw newDirectoryException(currentEntry,
+ ResultCode.INVALID_ATTRIBUTE_SYNTAX,
+ ERR_MODIFY_REPLACE_INVALID_SYNTAX.get(String.valueOf(entryDN),
+ attr.getName(), v.getValue().toString(), invalidReason));
}
}
}
@@ -1673,7 +1700,7 @@
&& (!modifiedEntry.hasValue(t, attr.getOptions(), rdn
.getAttributeValue(t))))
{
- throw new DirectoryException(ResultCode.NOT_ALLOWED_ON_RDN,
+ throw newDirectoryException(modifiedEntry, ResultCode.NOT_ALLOWED_ON_RDN,
ERR_MODIFY_DELETE_RDN_ATTR.get(String.valueOf(entryDN), attr
.getName()));
}
@@ -1699,7 +1726,7 @@
RDN rdn = modifiedEntry.getDN().getRDN();
if ((rdn != null) && rdn.hasAttributeType(t))
{
- throw new DirectoryException(ResultCode.NOT_ALLOWED_ON_RDN,
+ throw newDirectoryException(modifiedEntry, ResultCode.NOT_ALLOWED_ON_RDN,
ERR_MODIFY_INCREMENT_RDN.get(String.valueOf(entryDN),
attr.getName()));
}
@@ -1708,14 +1735,14 @@
// an integer.
if (attr.isEmpty())
{
- throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+ throw newDirectoryException(modifiedEntry, ResultCode.PROTOCOL_ERROR,
ERR_MODIFY_INCREMENT_REQUIRES_VALUE.get(String.valueOf(entryDN), attr
.getName()));
}
if (attr.size() > 1)
{
- throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+ throw newDirectoryException(modifiedEntry, ResultCode.PROTOCOL_ERROR,
ERR_MODIFY_INCREMENT_REQUIRES_SINGLE_VALUE.get(String
.valueOf(entryDN), attr.getName()));
}
@@ -1743,7 +1770,8 @@
Attribute a = modifiedEntry.getExactAttribute(t, attr.getOptions());
if (a == null)
{
- throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
+ throw newDirectoryException(modifiedEntry,
+ ResultCode.CONSTRAINT_VIOLATION,
ERR_MODIFY_INCREMENT_REQUIRES_EXISTING_VALUE.get(String
.valueOf(entryDN), attr.getName()));
}
@@ -2110,8 +2138,8 @@
SynchronizationProviderResult result =
provider.handleConflictResolution(this);
if (! result.continueProcessing()) {
- setResultCode(result.getResultCode());
- appendErrorMessage(result.getErrorMessage());
+ setResultCodeAndMessageNoInfoDisclosure(modifiedEntry,
+ result.getResultCode(), result.getErrorMessage());
setMatchedDN(result.getMatchedDN());
setReferralURLs(result.getReferralURLs());
returnVal = false;
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
index b832090..19035f9 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
@@ -23,7 +23,7 @@
*
*
* Copyright 2008-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2012 ForgeRock AS
+ * Portions copyright 2011-2013 ForgeRock AS
*/
package org.opends.server.workflowelement.localbackend;
@@ -138,26 +138,33 @@
// Check for a request to cancel this operation.
checkIfCanceled(false);
- BooleanHolder executePostOpPlugins = new BooleanHolder(false);
- processSearch(wfe, executePostOpPlugins);
-
- // Check for a request to cancel this operation.
- checkIfCanceled(false);
-
- // Invoke the post-operation search plugins.
- if (executePostOpPlugins.value)
+ try
{
- PluginResult.PostOperation postOpResult =
- DirectoryServer.getPluginConfigManager()
- .invokePostOperationSearchPlugins(this);
- if (!postOpResult.continueProcessing())
+ BooleanHolder executePostOpPlugins = new BooleanHolder(false);
+ processSearch(wfe, executePostOpPlugins);
+
+ // Check for a request to cancel this operation.
+ checkIfCanceled(false);
+
+ // Invoke the post-operation search plugins.
+ if (executePostOpPlugins.value)
{
- setResultCode(postOpResult.getResultCode());
- appendErrorMessage(postOpResult.getErrorMessage());
- setMatchedDN(postOpResult.getMatchedDN());
- setReferralURLs(postOpResult.getReferralURLs());
+ PluginResult.PostOperation postOpResult =
+ DirectoryServer.getPluginConfigManager()
+ .invokePostOperationSearchPlugins(this);
+ if (!postOpResult.continueProcessing())
+ {
+ setResultCode(postOpResult.getResultCode());
+ appendErrorMessage(postOpResult.getErrorMessage());
+ setMatchedDN(postOpResult.getMatchedDN());
+ setReferralURLs(postOpResult.getReferralURLs());
+ }
}
}
+ finally
+ {
+ LocalBackendWorkflowElement.filterNonDisclosableMatchedDN(this);
+ }
}
private void processSearch(LocalBackendWorkflowElement wfe,
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.
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java
index 5a51700..cc5a676 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/authorization/dseecompat/TargetControlTestCase.java
@@ -353,7 +353,7 @@
base, filter, "aclRights mail description", false, false,
0 /* disallowed but non-critical */);
LDIFModify(aciRight, superUser, PWD, OID_LDAP_READENTRY_PREREAD,
- LDAPResultCode.INSUFFICIENT_ACCESS_RIGHTS);
+ LDAPResultCode.NO_SUCH_OBJECT);
deleteAttrFromEntry (base, "aci");
String aciAllow=makeAddLDIF("aci", base, controlWC, ALLOW_ALL);
LDIFModify(aciAllow, DIR_MGR_DN, PWD);
--
Gitblit v1.10.0