OPENDJ-948 (CR-1873) unauthorized disclosure of directory contents
This commit addresses information disclosure for:
- result code: change from info disclosing result codes to a default result code that hides the ACI-protected info to the current operation.
- error message (additional information): any message containing the entryDN will be filtered out if the entryDN is ACI-protected.
- matchedDN: check whether the matchedDN is ACI-protected
- debugsearchindex
Information disclosing result code and error message are now saved as masked result code and masked message and are logged as such when they are present.
config.ldif:
Added "debugsearchindex" to an ACI to prevent Anonymous Read Access. If this is not enough, then we would need to create a new ACI.
AccessControlHandler.java:
Added canDiscloseInformation().
Operation.java, AbstractOperation.java, OperationWrapper.java:
Added getMaskedResultCode(), setMaskedResultCode(), getMaskedErrorMessage(), setMaskedErrorMessage(), appendMaskedErrorMessage().
In setReponseData(), copied the masked result code and error message.
DirectoryException.java:
Added getMaskedResultCode(), setMaskedResultCode(), getMaskedErrorMessage(), setMaskedErrorMessage().
LocalBackendWorkflowElement.java:
Used javadocs.
Created method newDirectoryException(), setResultCodeAndMessageNoInfoDisclosure() and filterNonDisclosableMatchedDN().
LocalBackend*Operation.java:
Added setResultCodeAndMessageNoInfoDisclosure() and newDirectoryException() forwarding to the corresponding LocalBackendWorkflowElement methods + extensively made use of these methods.
In processLocal*() methods, added a try/finally to call LocalBackendWorkflowElement.filterNonDisclosableMatchedDN().
Moved some blocks of code under the protection of try/catch blocks to ensure proper error handling when calling the exception throwing setResultCodeAndMessageNoInfoDisclosure() + as a consequence, moved some null checks to the finally blocks.
Removed some try/catch duplicating outer try/catch blocks.
LocalBackendModifyOperation.java:
In processLocalModify(), removed try/catch around checkWritability() because catch is duplicated with outer try/catch.
Used StaticUtils.collectionToString().
TextAccessLogPublisher.java:
Renamed appendMessage() into appendResultCodeAndMessage() + integrated there logging of "result" + added logging of "maskedResult" and "maskedMessage".
| | |
| | | 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";) |
| | |
| | | * |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011 ForgeRock AS |
| | | * Portions Copyright 2011-2013 ForgeRock AS |
| | | */ |
| | | package org.opends.server.api; |
| | | |
| | |
| | | public abstract class AccessControlHandler |
| | | <T extends AccessControlHandlerCfg> |
| | | { |
| | | |
| | | /** |
| | | * Initializes the access control handler implementation based on |
| | | * the information in the provided configuration entry. |
| | |
| | | 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 |
| | |
| | | operation.appendErrorMessage(message); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void appendMaskedErrorMessage(Message maskedMessage) |
| | | { |
| | | operation.appendMaskedErrorMessage(maskedMessage); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | |
| | | return operation.getErrorMessage(); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public MessageBuilder getMaskedErrorMessage() |
| | | { |
| | | return operation.getMaskedErrorMessage(); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public ResultCode getMaskedResultCode() |
| | | { |
| | | return operation.getMaskedResultCode(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | |
| | | operation.setInternalOperation(isInternalOperation); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void setMaskedErrorMessage(MessageBuilder maskedErrorMessage) |
| | | { |
| | | operation.setMaskedErrorMessage(maskedErrorMessage); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void setMaskedResultCode(ResultCode maskedResultCode) |
| | | { |
| | | operation.setMaskedResultCode(maskedResultCode); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | |
| | | return false; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String toString() |
| | | { |
| | | return "Wrapped " + operation.toString(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | |
| | | { |
| | | appendAbandonRequest(abandonOperation, buffer); |
| | | } |
| | | buffer.append(" result="); |
| | | buffer.append(abandonOperation.getResultCode().getIntValue()); |
| | | appendMessage(buffer, abandonOperation); |
| | | appendResultCodeAndMessage(buffer, abandonOperation); |
| | | |
| | | logAdditionalLogItems(abandonOperation, buffer); |
| | | |
| | |
| | | { |
| | | appendAddRequest(addOperation, buffer); |
| | | } |
| | | buffer.append(" result="); |
| | | buffer.append(addOperation.getResultCode().getIntValue()); |
| | | |
| | | appendMessage(buffer, addOperation); |
| | | appendResultCodeAndMessage(buffer, addOperation); |
| | | |
| | | logAdditionalLogItems(addOperation, buffer); |
| | | |
| | |
| | | { |
| | | 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) |
| | |
| | | { |
| | | appendCompareRequest(compareOperation, buffer); |
| | | } |
| | | buffer.append(" result="); |
| | | buffer.append(compareOperation.getResultCode().getIntValue()); |
| | | |
| | | appendMessage(buffer, compareOperation); |
| | | appendResultCodeAndMessage(buffer, compareOperation); |
| | | |
| | | logAdditionalLogItems(compareOperation, buffer); |
| | | |
| | |
| | | { |
| | | appendDeleteRequest(deleteOperation, buffer); |
| | | } |
| | | buffer.append(" result="); |
| | | buffer.append(deleteOperation.getResultCode().getIntValue()); |
| | | |
| | | appendMessage(buffer, deleteOperation); |
| | | appendResultCodeAndMessage(buffer, deleteOperation); |
| | | |
| | | logAdditionalLogItems(deleteOperation, buffer); |
| | | |
| | |
| | | } |
| | | appendLabel(buffer, "oid", oid); |
| | | } |
| | | |
| | | buffer.append(" result="); |
| | | buffer.append(extendedOperation.getResultCode().getIntValue()); |
| | | |
| | | appendMessage(buffer, extendedOperation); |
| | | appendResultCodeAndMessage(buffer, extendedOperation); |
| | | |
| | | logAdditionalLogItems(extendedOperation, buffer); |
| | | |
| | |
| | | { |
| | | appendModifyDNRequest(modifyDNOperation, buffer); |
| | | } |
| | | buffer.append(" result="); |
| | | buffer.append(modifyDNOperation.getResultCode().getIntValue()); |
| | | |
| | | appendMessage(buffer, modifyDNOperation); |
| | | appendResultCodeAndMessage(buffer, modifyDNOperation); |
| | | |
| | | logAdditionalLogItems(modifyDNOperation, buffer); |
| | | |
| | |
| | | { |
| | | appendModifyRequest(modifyOperation, buffer); |
| | | } |
| | | buffer.append(" result="); |
| | | buffer.append(modifyOperation.getResultCode().getIntValue()); |
| | | |
| | | appendMessage(buffer, modifyOperation); |
| | | appendResultCodeAndMessage(buffer, modifyOperation); |
| | | |
| | | logAdditionalLogItems(modifyOperation, buffer); |
| | | |
| | |
| | | { |
| | | appendSearchRequest(searchOperation, buffer); |
| | | } |
| | | buffer.append(" result="); |
| | | buffer.append(searchOperation.getResultCode().getIntValue()); |
| | | |
| | | appendMessage(buffer, searchOperation); |
| | | appendResultCodeAndMessage(buffer, searchOperation); |
| | | |
| | | buffer.append(" nentries="); |
| | | buffer.append(searchOperation.getEntriesSent()); |
| | |
| | | } |
| | | } |
| | | |
| | | 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, |
| | |
| | | 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 |
| | |
| | | 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. |
| | | */ |
| | |
| | | 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. |
| | | */ |
| | |
| | | |
| | | /** {@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; |
| | |
| | | @Override |
| | | public final void setErrorMessage(MessageBuilder errorMessage) |
| | | { |
| | | if (errorMessage == null) |
| | | { |
| | | this.errorMessage = new MessageBuilder(); |
| | | } |
| | | else |
| | | { |
| | | this.errorMessage = errorMessage; |
| | | } |
| | | this.errorMessage = errorMessage; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | |
| | | { |
| | | 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} |
| | |
| | | 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()); |
| | | } |
| | | |
| | | |
| | |
| | | * |
| | | * |
| | | * 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 |
| | |
| | | |
| | | |
| | | |
| | | // 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. |
| | |
| | | { |
| | | 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; |
| | | } |
| | | } |
| | |
| | | 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. |
| | |
| | | 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. |
| | |
| | | // 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 |
| | |
| | | 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; |
| | | } |
| | | |
| | |
| | | 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; |
| | |
| | | // 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; |
| | | } |
| | | |
| | |
| | | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | } |
| | | |
| | | setResponseData(de); |
| | | return; |
| | | } |
| | | finally |
| | | { |
| | |
| | | } |
| | | |
| | | private boolean checkHasReadOnlyAttributes( |
| | | Map<AttributeType, List<Attribute>> attributes) |
| | | Map<AttributeType, List<Attribute>> attributes) throws DirectoryException |
| | | { |
| | | for (AttributeType at : attributes.keySet()) |
| | | { |
| | |
| | | { |
| | | 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; |
| | | } |
| | | } |
| | |
| | | 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. |
| | | * |
| | |
| | | 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))); |
| | |
| | | } |
| | | else |
| | | { |
| | | throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, |
| | | throw newDirectoryException(entryDN, ResultCode.CONSTRAINT_VIOLATION, |
| | | ERR_ADD_MISSING_RDN_ATTRIBUTE.get( |
| | | String.valueOf(entryDN), n)); |
| | | } |
| | |
| | | { |
| | | 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())); |
| | |
| | | { |
| | | 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())); |
| | |
| | | { |
| | | 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())); |
| | |
| | | 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())); |
| | |
| | | { |
| | | if (!filter.matchesEntry(entry)) |
| | | { |
| | | throw new DirectoryException(ResultCode.ASSERTION_FAILED, |
| | | throw newDirectoryException(entryDN, ResultCode.ASSERTION_FAILED, |
| | | ERR_ADD_ASSERTION_FAILED.get(String |
| | | .valueOf(entryDN))); |
| | | } |
| | |
| | | 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())); |
| | |
| | | { |
| | | 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)); |
| | |
| | | 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; |
| | |
| | | // 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) |
| | |
| | | // 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); |
| | |
| | | |
| | | // 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 |
| | | { |
| | |
| | | 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 |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | 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 |
| | |
| | | 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())); |
| | |
| | | { |
| | | if (!filter.matchesEntry(entry)) |
| | | { |
| | | throw new DirectoryException(ResultCode.ASSERTION_FAILED, |
| | | throw newDirectoryException(entry, ResultCode.ASSERTION_FAILED, |
| | | ERR_COMPARE_ASSERTION_FAILED.get(String |
| | | .valueOf(entryDN))); |
| | | } |
| | |
| | | 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())); |
| | |
| | | // 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 |
| | |
| | | |
| | | // 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) |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | { |
| | | 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; |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | 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 |
| | |
| | | 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())); |
| | |
| | | { |
| | | if (!filter.matchesEntry(entry)) |
| | | { |
| | | throw new DirectoryException(ResultCode.ASSERTION_FAILED, |
| | | throw newDirectoryException(entry, ResultCode.ASSERTION_FAILED, |
| | | ERR_DELETE_ASSERTION_FAILED.get(String |
| | | .valueOf(entryDN))); |
| | | } |
| | |
| | | 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())); |
| | |
| | | { |
| | | 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)); |
| | |
| | | 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; |
| | |
| | | // 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 |
| | |
| | | |
| | | // 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); |
| | | |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | |
| | | // init the modifications |
| | | addModification(null); |
| | | List<Modification> modifications = this.getModifications(); |
| | | List<Modification> modifications = getModifications(); |
| | | |
| | | if (!handleConflictResolution()) |
| | | { |
| | |
| | | } |
| | | 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 |
| | |
| | | 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 |
| | |
| | | { |
| | | 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))); |
| | | } |
| | |
| | | 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)) |
| | |
| | | */ |
| | | private static final DebugTracer TRACER = getTracer(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * The backend in which the target entry exists. |
| | | */ |
| | |
| | | // 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); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | // 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); |
| | | |
| | |
| | | // 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(); |
| | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | 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 |
| | |
| | | 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())); |
| | |
| | | { |
| | | 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) |
| | |
| | | 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())); |
| | |
| | | { |
| | | 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)); |
| | |
| | | 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())); |
| | | } |
| | | } |
| | |
| | | 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())); |
| | | } |
| | | } |
| | |
| | | // 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())); |
| | | } |
| | |
| | | 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)); |
| | | } |
| | | } |
| | | } |
| | |
| | | // 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)); |
| | | } |
| | | } |
| | | |
| | |
| | | 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))); |
| | | } |
| | | } |
| | | } |
| | |
| | | (! 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 |
| | |
| | | { |
| | | 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)); |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | 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())); |
| | | } |
| | |
| | | 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)); |
| | | } |
| | | } |
| | | } |
| | |
| | | && (!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())); |
| | | } |
| | |
| | | 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())); |
| | | } |
| | |
| | | // 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())); |
| | | } |
| | |
| | | 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())); |
| | | } |
| | |
| | | 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; |
| | |
| | | * |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2012 ForgeRock AS |
| | | * Portions copyright 2011-2013 ForgeRock AS |
| | | */ |
| | | package org.opends.server.workflowelement.localbackend; |
| | | |
| | |
| | | // 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, |
| | |
| | | */ |
| | | package org.opends.server.workflowelement.localbackend; |
| | | |
| | | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.TreeMap; |
| | |
| | | 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 |
| | |
| | | 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"; |
| | | |
| | | |
| | |
| | | List<Message> unacceptableReasons |
| | | ) |
| | | { |
| | | boolean isAcceptable = |
| | | processWorkflowElementConfig(configuration, false); |
| | | |
| | | return isAcceptable; |
| | | return processWorkflowElementConfig(configuration, false); |
| | | } |
| | | |
| | | |
| | |
| | | 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>()); |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | 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; |
| | |
| | | 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. |
| | |
| | | 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); |