From fbda6e0892dcfcc8dd43d21f6fb134aabb8d0cac Mon Sep 17 00:00:00 2001
From: jarnou <jarnou@localhost>
Date: Tue, 03 Jul 2007 09:29:17 +0000
Subject: [PATCH] Commits the refactoring of the core server to provide support for proxy/distribution/virtual functionnalities. This includes the new set of local operations, as well as the workflow and networkgroup support.
---
opends/src/server/org/opends/server/core/ModifyOperation.java | 2933 -----------------------------------------------------------
1 files changed, 26 insertions(+), 2,907 deletions(-)
diff --git a/opends/src/server/org/opends/server/core/ModifyOperation.java b/opends/src/server/org/opends/server/core/ModifyOperation.java
index e9661d4..ab03679 100644
--- a/opends/src/server/org/opends/server/core/ModifyOperation.java
+++ b/opends/src/server/org/opends/server/core/ModifyOperation.java
@@ -26,244 +26,29 @@
*/
package org.opends.server.core;
-
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
import java.util.List;
-import java.util.concurrent.locks.Lock;
-import org.opends.server.api.AttributeSyntax;
-import org.opends.server.api.Backend;
-import org.opends.server.api.ChangeNotificationListener;
-import org.opends.server.api.ClientConnection;
-import org.opends.server.api.PasswordStorageScheme;
-import org.opends.server.api.SynchronizationProvider;
-import org.opends.server.api.plugin.PostOperationPluginResult;
-import org.opends.server.api.plugin.PreOperationPluginResult;
-import org.opends.server.api.plugin.PreParsePluginResult;
-import org.opends.server.controls.LDAPAssertionRequestControl;
-import org.opends.server.controls.LDAPPreReadRequestControl;
-import org.opends.server.controls.LDAPPreReadResponseControl;
-import org.opends.server.controls.LDAPPostReadRequestControl;
-import org.opends.server.controls.LDAPPostReadResponseControl;
-import org.opends.server.controls.ProxiedAuthV1Control;
-import org.opends.server.controls.ProxiedAuthV2Control;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.ldap.LDAPAttribute;
-import org.opends.server.protocols.ldap.LDAPModification;
-import org.opends.server.schema.AuthPasswordSyntax;
-import org.opends.server.schema.BooleanSyntax;
-import org.opends.server.schema.UserPasswordSyntax;
-import org.opends.server.types.AcceptRejectWarn;
-import org.opends.server.types.AccountStatusNotificationType;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.ByteString;
-import org.opends.server.types.CancelledOperationException;
-import org.opends.server.types.CancelRequest;
-import org.opends.server.types.CancelResult;
-import org.opends.server.types.Control;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DisconnectReason;
import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ErrorLogCategory;
-import org.opends.server.types.ErrorLogSeverity;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.LockManager;
+import org.opends.server.types.DirectoryException;
import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
import org.opends.server.types.Operation;
-import org.opends.server.types.OperationType;
-import org.opends.server.types.Privilege;
import org.opends.server.types.RawModification;
-import org.opends.server.types.RDN;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SynchronizationProviderResult;
-import org.opends.server.types.operation.PreParseModifyOperation;
-import org.opends.server.types.operation.PreOperationModifyOperation;
-import org.opends.server.types.operation.PostOperationModifyOperation;
-import org.opends.server.types.operation.PostResponseModifyOperation;
-
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.core.CoreConstants.*;
-import static org.opends.server.loggers.AccessLogger.*;
-import static org.opends.server.loggers.ErrorLogger.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.server.messages.CoreMessages.*;
-import static org.opends.server.messages.MessageHandler.getMessage;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
/**
- * This class defines an operation that may be used to modify an entry in the
- * Directory Server.
+ * This interface defines an operation used to modify an entry in
+ * the Directory Server.
*/
-public class ModifyOperation
- extends Operation
- implements PreParseModifyOperation, PreOperationModifyOperation,
- PostOperationModifyOperation, PostResponseModifyOperation
+public interface ModifyOperation extends Operation
{
/**
- * The tracer object for the debug logger.
- */
- private static final DebugTracer TRACER = getTracer();
-
- // The raw, unprocessed entry DN as included by the client request.
- private ByteString rawEntryDN;
-
- // The cancel request that has been issued for this modify operation.
- private CancelRequest cancelRequest;
-
- // The DN of the entry for the modify operation.
- private DN entryDN;
-
- // The proxied authorization target DN for this operation.
- private DN proxiedAuthorizationDN;
-
- // The current entry, before any changes are applied.
- private Entry currentEntry;
-
- // The modified entry that will be stored in the backend.
- private Entry modifiedEntry;
-
- // The set of clear-text current passwords (if any were provided).
- private List<AttributeValue> currentPasswords;
-
- // The set of clear-text new passwords (if any were provided).
- private List<AttributeValue> newPasswords;
-
- // The set of response controls for this modify operation.
- private List<Control> responseControls;
-
- // The raw, unprocessed set of modifications as included in the client
- // request.
- private List<RawModification> rawModifications;
-
- // The set of modifications for this modify operation.
- private List<Modification> modifications;
-
- // The change number that has been assigned to this operation.
- private long changeNumber;
-
- // The time that processing started on this operation.
- private long processingStartTime;
-
- // The time that processing ended on this operation.
- private long processingStopTime;
-
-
-
- /**
- * Creates a new modify operation with the provided information.
- *
- * @param clientConnection The client connection with which this operation
- * is associated.
- * @param operationID The operation ID for this operation.
- * @param messageID The message ID of the request with which this
- * operation is associated.
- * @param requestControls The set of controls included in the request.
- * @param rawEntryDN The raw, unprocessed DN of the entry to modify,
- * as included in the client request.
- * @param rawModifications The raw, unprocessed set of modifications for
- * this modify operation as included in the client
- * request.
- */
- public ModifyOperation(ClientConnection clientConnection, long operationID,
- int messageID, List<Control> requestControls,
- ByteString rawEntryDN,
- List<RawModification> rawModifications)
- {
- super(clientConnection, operationID, messageID, requestControls);
-
-
- this.rawEntryDN = rawEntryDN;
- this.rawModifications = rawModifications;
-
- entryDN = null;
- modifications = null;
- currentEntry = null;
- modifiedEntry = null;
- responseControls = new ArrayList<Control>();
- cancelRequest = null;
- changeNumber = -1;
-
- currentPasswords = null;
- newPasswords = null;
- }
-
-
-
- /**
- * Creates a new modify operation with the provided information.
- *
- * @param clientConnection The client connection with which this operation
- * is associated.
- * @param operationID The operation ID for this operation.
- * @param messageID The message ID of the request with which this
- * operation is associated.
- * @param requestControls The set of controls included in the request.
- * @param entryDN The entry DN for the modify operation.
- * @param modifications The set of modifications for this modify
- * operation.
- */
- public ModifyOperation(ClientConnection clientConnection, long operationID,
- int messageID, List<Control> requestControls,
- DN entryDN, List<Modification> modifications)
- {
- super(clientConnection, operationID, messageID, requestControls);
-
-
- this.entryDN = entryDN;
- this.modifications = modifications;
-
- rawEntryDN = new ASN1OctetString(entryDN.toString());
-
- rawModifications = new ArrayList<RawModification>(modifications.size());
- for (Modification m : modifications)
- {
- rawModifications.add(new LDAPModification(m.getModificationType(),
- new LDAPAttribute(m.getAttribute())));
- }
-
- currentEntry = null;
- modifiedEntry = null;
- responseControls = new ArrayList<Control>();
- cancelRequest = null;
- changeNumber = -1;
-
- currentPasswords = null;
- newPasswords = null;
- }
-
-
-
- /**
* Retrieves the raw, unprocessed entry DN as included in the client request.
* The DN that is returned may or may not be a valid DN, since no validation
* will have been performed upon it.
*
* @return The raw, unprocessed entry DN as included in the client request.
*/
- public final ByteString getRawEntryDN()
- {
- return rawEntryDN;
- }
-
-
+ public abstract ByteString getRawEntryDN();
/**
* Specifies the raw, unprocessed entry DN as included in the client request.
@@ -272,14 +57,7 @@
* @param rawEntryDN The raw, unprocessed entry DN as included in the client
* request.
*/
- public final void setRawEntryDN(ByteString rawEntryDN)
- {
- this.rawEntryDN = rawEntryDN;
-
- entryDN = null;
- }
-
-
+ public abstract void setRawEntryDN(ByteString rawEntryDN);
/**
* Retrieves the DN of the entry to modify. This should not be called by
@@ -289,12 +67,7 @@
* @return The DN of the entry to modify, or <CODE>null</CODE> if the raw
* entry DN has not yet been processed.
*/
- public final DN getEntryDN()
- {
- return entryDN;
- }
-
-
+ public abstract DN getEntryDN();
/**
* Retrieves the set of raw, unprocessed modifications as included in the
@@ -305,12 +78,7 @@
* @return The set of raw, unprocessed modifications as included in the
* client request.
*/
- public final List<RawModification> getRawModifications()
- {
- return rawModifications;
- }
-
-
+ public abstract List<RawModification> getRawModifications();
/**
* Adds the provided modification to the set of raw modifications for this
@@ -319,28 +87,15 @@
* @param rawModification The modification to add to the set of raw
* modifications for this modify operation.
*/
- public final void addRawModification(RawModification rawModification)
- {
- rawModifications.add(rawModification);
-
- modifications = null;
- }
-
-
+ public abstract void addRawModification(RawModification rawModification);
/**
* Specifies the raw modifications for this modify operation.
*
* @param rawModifications The raw modifications for this modify operation.
*/
- public final void setRawModifications(List<RawModification> rawModifications)
- {
- this.rawModifications = rawModifications;
-
- modifications = null;
- }
-
-
+ public abstract void setRawModifications(
+ List<RawModification> rawModifications);
/**
* Retrieves the set of modifications for this modify operation. Its contents
@@ -350,12 +105,7 @@
* <CODE>null</CODE> if the modifications have not yet been
* processed.
*/
- public final List<Modification> getModifications()
- {
- return modifications;
- }
-
-
+ public abstract List<Modification> getModifications();
/**
* Adds the provided modification to the set of modifications to this modify
@@ -367,112 +117,8 @@
* @throws DirectoryException If an unexpected problem occurs while applying
* the modification to the entry.
*/
- public final void addModification(Modification modification)
- throws DirectoryException
- {
- modifiedEntry.applyModification(modification);
- modifications.add(modification);
- }
-
-
-
- /**
- * Retrieves the current entry before any modifications are applied. This
- * will not be available to pre-parse plugins.
- *
- * @return The current entry, or <CODE>null</CODE> if it is not yet
- * available.
- */
- public final Entry getCurrentEntry()
- {
- return currentEntry;
- }
-
-
-
- /**
- * Retrieves the modified entry that is to be written to the backend. This
- * will be available to pre-operation plugins, and if such a plugin does make
- * a change to this entry, then it is also necessary to add that change to
- * the set of modifications to ensure that the update will be consistent.
- *
- * @return The modified entry that is to be written to the backend, or
- * <CODE>null</CODE> if it is not yet available.
- */
- public final Entry getModifiedEntry()
- {
- return modifiedEntry;
- }
-
-
-
- /**
- * Retrieves the set of clear-text current passwords for the user, if
- * available. This will only be available if the modify operation contains
- * one or more delete elements that target the password attribute and provide
- * the values to delete in the clear. It will not be available to pre-parse
- * plugins.
- *
- * @return The set of clear-text current password values as provided in the
- * modify request, or <CODE>null</CODE> if there were none or this
- * information is not yet available.
- */
- public final List<AttributeValue> getCurrentPasswords()
- {
- return currentPasswords;
- }
-
-
-
- /**
- * Retrieves the set of clear-text new passwords for the user, if available.
- * This will only be available if the modify operation contains one or more
- * add or replace elements that target the password attribute and provide the
- * values in the clear. It will not be available to pre-parse plugins.
- *
- * @return The set of clear-text new passwords as provided in the modify
- * request, or <CODE>null</CODE> if there were none or this
- * information is not yet available.
- */
- public final List<AttributeValue> getNewPasswords()
- {
- return newPasswords;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final long getProcessingStartTime()
- {
- return processingStartTime;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final long getProcessingStopTime()
- {
- return processingStopTime;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final long getProcessingTime()
- {
- return (processingStopTime - processingStartTime);
- }
-
-
+ public abstract void addModification(Modification modification)
+ throws DirectoryException;
/**
* Retrieves the change number that has been assigned to this operation.
@@ -481,12 +127,7 @@
* if none has been assigned yet or if there is no applicable
* synchronization mechanism in place that uses change numbers.
*/
- public final long getChangeNumber()
- {
- return changeNumber;
- }
-
-
+ public abstract long getChangeNumber();
/**
* Specifies the change number that has been assigned to this operation by the
@@ -495,131 +136,7 @@
* @param changeNumber The change number that has been assigned to this
* operation by the synchronization mechanism.
*/
- public final void setChangeNumber(long changeNumber)
- {
- this.changeNumber = changeNumber;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final void disconnectClient(DisconnectReason disconnectReason,
- boolean sendNotification, String message,
- int messageID)
- {
- // Before calling clientConnection.disconnect, we need to mark this
- // operation as cancelled so that the attempt to cancel it later won't cause
- // an unnecessary delay.
- setCancelResult(CancelResult.CANCELED);
-
- clientConnection.disconnect(disconnectReason, sendNotification, message,
- messageID);
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final OperationType getOperationType()
- {
- // Note that no debugging will be done in this method because it is a likely
- // candidate for being called by the logging subsystem.
-
- return OperationType.MODIFY;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final String[][] getRequestLogElements()
- {
- // Note that no debugging will be done in this method because it is a likely
- // candidate for being called by the logging subsystem.
-
- return new String[][]
- {
- new String[] { LOG_ELEMENT_ENTRY_DN, String.valueOf(rawEntryDN) }
- };
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final String[][] getResponseLogElements()
- {
- // Note that no debugging will be done in this method because it is a likely
- // candidate for being called by the logging subsystem.
-
- String resultCode = String.valueOf(getResultCode().getIntValue());
-
- String errorMessage;
- StringBuilder errorMessageBuffer = getErrorMessage();
- if (errorMessageBuffer == null)
- {
- errorMessage = null;
- }
- else
- {
- errorMessage = errorMessageBuffer.toString();
- }
-
- String matchedDNStr;
- DN matchedDN = getMatchedDN();
- if (matchedDN == null)
- {
- matchedDNStr = null;
- }
- else
- {
- matchedDNStr = matchedDN.toString();
- }
-
- String referrals;
- List<String> referralURLs = getReferralURLs();
- if ((referralURLs == null) || referralURLs.isEmpty())
- {
- referrals = null;
- }
- else
- {
- StringBuilder buffer = new StringBuilder();
- Iterator<String> iterator = referralURLs.iterator();
- buffer.append(iterator.next());
-
- while (iterator.hasNext())
- {
- buffer.append(", ");
- buffer.append(iterator.next());
- }
-
- referrals = buffer.toString();
- }
-
- String processingTime =
- String.valueOf(processingStopTime - processingStartTime);
-
- return new String[][]
- {
- new String[] { LOG_ELEMENT_RESULT_CODE, resultCode },
- new String[] { LOG_ELEMENT_ERROR_MESSAGE, errorMessage },
- new String[] { LOG_ELEMENT_MATCHED_DN, matchedDNStr },
- new String[] { LOG_ELEMENT_REFERRAL_URLS, referrals },
- new String[] { LOG_ELEMENT_PROCESSING_TIME, processingTime }
- };
- }
-
-
+ public abstract void setChangeNumber(long changeNumber);
/**
* Retrieves the proxied authorization DN for this operation if proxied
@@ -629,2415 +146,17 @@
* authorization has been requested, or {@code null} if proxied
* authorization has not been requested.
*/
- public DN getProxiedAuthorizationDN()
- {
- return proxiedAuthorizationDN;
- }
-
-
+ public abstract DN getProxiedAuthorizationDN();
/**
- * {@inheritDoc}
+ * Set the proxied authorization DN for this operation if proxied
+ * authorization has been requested.
+ *
+ * @param proxiedAuthorizationDN
+ * The proxied authorization DN for this operation if proxied
+ * authorization has been requested, or {@code null} if proxied
+ * authorization has not been requested.
*/
- @Override()
- public final List<Control> getResponseControls()
- {
- return responseControls;
- }
+ public abstract void setProxiedAuthorizationDN(DN proxiedAuthorizationDN);
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final void addResponseControl(Control control)
- {
- responseControls.add(control);
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final void removeResponseControl(Control control)
- {
- responseControls.remove(control);
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final void run()
- {
- setResultCode(ResultCode.UNDEFINED);
-
-
- // Get the plugin config manager that will be used for invoking plugins.
- PluginConfigManager pluginConfigManager =
- DirectoryServer.getPluginConfigManager();
- boolean skipPostOperation = false;
-
-
- // Start the processing timer.
- processingStartTime = System.currentTimeMillis();
-
-
- // Check for and handle a request to cancel this operation.
- if (cancelRequest != null)
- {
- indicateCancelled(cancelRequest);
- processingStopTime = System.currentTimeMillis();
- return;
- }
-
-
- // Create a labeled block of code that we can break out of if a problem is
- // detected.
-modifyProcessing:
- {
- // Invoke the pre-parse modify plugins.
- PreParsePluginResult preParseResult =
- pluginConfigManager.invokePreParseModifyPlugins(this);
- if (preParseResult.connectionTerminated())
- {
- // There's no point in continuing with anything. Log the request and
- // result and return.
- setResultCode(ResultCode.CANCELED);
-
- int msgID = MSGID_CANCELED_BY_PREPARSE_DISCONNECT;
- appendErrorMessage(getMessage(msgID));
-
- processingStopTime = System.currentTimeMillis();
-
- logModifyRequest(this);
- logModifyResponse(this);
- pluginConfigManager.invokePostResponseModifyPlugins(this);
- return;
- }
- else if (preParseResult.sendResponseImmediately())
- {
- skipPostOperation = true;
- logModifyRequest(this);
- break modifyProcessing;
- }
- else if (preParseResult.skipCoreProcessing())
- {
- skipPostOperation = false;
- break modifyProcessing;
- }
-
-
- // Log the modify request message.
- logModifyRequest(this);
-
-
- // Check for and handle a request to cancel this operation.
- if (cancelRequest != null)
- {
- indicateCancelled(cancelRequest);
- processingStopTime = System.currentTimeMillis();
- logModifyResponse(this);
- pluginConfigManager.invokePostResponseModifyPlugins(this);
- return;
- }
-
-
- // Process the entry DN to convert it from the raw form to the form
- // required for the rest of the modify processing.
- try
- {
- if (entryDN == null)
- {
- entryDN = DN.decode(rawEntryDN);
- }
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResultCode(de.getResultCode());
- appendErrorMessage(de.getErrorMessage());
- skipPostOperation = true;
-
- break modifyProcessing;
- }
-
-
- // Process the modifications to convert them from their raw form to the
- // form required for the rest of the modify processing.
- if (modifications == null)
- {
- modifications = new ArrayList<Modification>(rawModifications.size());
- for (RawModification m : rawModifications)
- {
- try
- {
- modifications.add(m.toModification());
- }
- catch (LDAPException le)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, le);
- }
-
- setResultCode(ResultCode.valueOf(le.getResultCode()));
- appendErrorMessage(le.getMessage());
-
- break modifyProcessing;
- }
- }
- }
-
- if (modifications.isEmpty())
- {
- setResultCode(ResultCode.CONSTRAINT_VIOLATION);
- appendErrorMessage(getMessage(MSGID_MODIFY_NO_MODIFICATIONS,
- String.valueOf(entryDN)));
- break modifyProcessing;
- }
-
-
- // If the user must change their password before doing anything else, and
- // if the target of the modify operation isn't the user's own entry, then
- // reject the request.
- if ((! isInternalOperation()) && clientConnection.mustChangePassword())
- {
- DN authzDN = getAuthorizationDN();
- if ((authzDN != null) && (! authzDN.equals(entryDN)))
- {
- // The user will not be allowed to do anything else before
- // the password gets changed.
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_MUST_CHANGE_PASSWORD;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
- }
-
-
- // Check for and handle a request to cancel this operation.
- if (cancelRequest != null)
- {
- indicateCancelled(cancelRequest);
- processingStopTime = System.currentTimeMillis();
- logModifyResponse(this);
- pluginConfigManager.invokePostResponseModifyPlugins(this);
- return;
- }
-
-
- // Acquire a write lock on the target entry.
- Lock entryLock = null;
- for (int i=0; i < 3; i++)
- {
- entryLock = LockManager.lockWrite(entryDN);
- if (entryLock != null)
- {
- break;
- }
- }
-
- if (entryLock == null)
- {
- setResultCode(DirectoryServer.getServerErrorResultCode());
- appendErrorMessage(getMessage(MSGID_MODIFY_CANNOT_LOCK_ENTRY,
- String.valueOf(entryDN)));
-
- skipPostOperation = true;
- break modifyProcessing;
- }
-
-
- try
- {
- // Check for and handle a request to cancel this operation.
- if (cancelRequest != null)
- {
- indicateCancelled(cancelRequest);
- processingStopTime = System.currentTimeMillis();
- logModifyResponse(this);
- pluginConfigManager.invokePostResponseModifyPlugins(this);
- return;
- }
-
-
- // Get the entry to modify. If it does not exist, then fail.
- try
- {
- currentEntry = DirectoryServer.getEntry(entryDN);
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResultCode(de.getResultCode());
- appendErrorMessage(de.getErrorMessage());
- setMatchedDN(de.getMatchedDN());
- setReferralURLs(de.getReferralURLs());
-
- break modifyProcessing;
- }
-
- if (currentEntry == null)
- {
- setResultCode(ResultCode.NO_SUCH_OBJECT);
- appendErrorMessage(getMessage(MSGID_MODIFY_NO_SUCH_ENTRY,
- String.valueOf(entryDN)));
-
- // See if one of the entry's ancestors exists.
- DN parentDN = entryDN.getParentDNInSuffix();
- while (parentDN != null)
- {
- try
- {
- if (DirectoryServer.entryExists(parentDN))
- {
- setMatchedDN(parentDN);
- break;
- }
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, e);
- }
- break;
- }
-
- parentDN = parentDN.getParentDNInSuffix();
- }
-
- break modifyProcessing;
- }
-
- // Check to see if there are any controls in the request. If so, then
- // see if there is any special processing required.
- boolean noOp = false;
- LDAPPreReadRequestControl preReadRequest = null;
- LDAPPostReadRequestControl postReadRequest = null;
- List<Control> requestControls = getRequestControls();
- if ((requestControls != null) && (! requestControls.isEmpty()))
- {
- for (int i=0; i < requestControls.size(); i++)
- {
- Control c = requestControls.get(i);
- String oid = c.getOID();
-
- if (oid.equals(OID_LDAP_ASSERTION))
- {
- LDAPAssertionRequestControl assertControl;
- if (c instanceof LDAPAssertionRequestControl)
- {
- assertControl = (LDAPAssertionRequestControl) c;
- }
- else
- {
- try
- {
- assertControl = LDAPAssertionRequestControl.decodeControl(c);
- requestControls.set(i, assertControl);
- }
- catch (LDAPException le)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, le);
- }
-
- setResultCode(ResultCode.valueOf(le.getResultCode()));
- appendErrorMessage(le.getMessage());
-
- break modifyProcessing;
- }
- }
-
- try
- {
- // FIXME -- We need to determine whether the current user has
- // permission to make this determination.
- SearchFilter filter = assertControl.getSearchFilter();
- if (! filter.matchesEntry(currentEntry))
- {
- setResultCode(ResultCode.ASSERTION_FAILED);
-
- appendErrorMessage(getMessage(MSGID_MODIFY_ASSERTION_FAILED,
- String.valueOf(entryDN)));
-
- break modifyProcessing;
- }
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResultCode(ResultCode.PROTOCOL_ERROR);
-
- int msgID = MSGID_MODIFY_CANNOT_PROCESS_ASSERTION_FILTER;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- de.getErrorMessage()));
-
- break modifyProcessing;
- }
- }
- else if (oid.equals(OID_LDAP_NOOP_OPENLDAP_ASSIGNED))
- {
- noOp = true;
- }
- else if (oid.equals(OID_LDAP_READENTRY_PREREAD))
- {
- if (c instanceof LDAPAssertionRequestControl)
- {
- preReadRequest = (LDAPPreReadRequestControl) c;
- }
- else
- {
- try
- {
- preReadRequest = LDAPPreReadRequestControl.decodeControl(c);
- requestControls.set(i, preReadRequest);
- }
- catch (LDAPException le)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, le);
- }
-
- setResultCode(ResultCode.valueOf(le.getResultCode()));
- appendErrorMessage(le.getMessage());
-
- break modifyProcessing;
- }
- }
- }
- else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
- {
- if (c instanceof LDAPAssertionRequestControl)
- {
- postReadRequest = (LDAPPostReadRequestControl) c;
- }
- else
- {
- try
- {
- postReadRequest = LDAPPostReadRequestControl.decodeControl(c);
- requestControls.set(i, postReadRequest);
- }
- catch (LDAPException le)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, le);
- }
-
- setResultCode(ResultCode.valueOf(le.getResultCode()));
- appendErrorMessage(le.getMessage());
-
- break modifyProcessing;
- }
- }
- }
- else if (oid.equals(OID_PROXIED_AUTH_V1))
- {
- // The requester must have the PROXIED_AUTH privilige in order to
- // be able to use this control.
- if (! clientConnection.hasPrivilege(Privilege.PROXIED_AUTH, this))
- {
- int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
- appendErrorMessage(getMessage(msgID));
- setResultCode(ResultCode.AUTHORIZATION_DENIED);
- break modifyProcessing;
- }
-
-
- ProxiedAuthV1Control proxyControl;
- if (c instanceof ProxiedAuthV1Control)
- {
- proxyControl = (ProxiedAuthV1Control) c;
- }
- else
- {
- try
- {
- proxyControl = ProxiedAuthV1Control.decodeControl(c);
- }
- catch (LDAPException le)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, le);
- }
-
- setResultCode(ResultCode.valueOf(le.getResultCode()));
- appendErrorMessage(le.getMessage());
-
- break modifyProcessing;
- }
- }
-
-
- Entry authorizationEntry;
- try
- {
- authorizationEntry = proxyControl.getAuthorizationEntry();
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResultCode(de.getResultCode());
- appendErrorMessage(de.getErrorMessage());
-
- break modifyProcessing;
- }
- if (AccessControlConfigManager.getInstance().
- getAccessControlHandler().isProxiedAuthAllowed(this,
- authorizationEntry) == false) {
- setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
- int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
-
- skipPostOperation = true;
- break modifyProcessing;
- }
-
- setAuthorizationEntry(authorizationEntry);
- if (authorizationEntry == null)
- {
- proxiedAuthorizationDN = DN.nullDN();
- }
- else
- {
- proxiedAuthorizationDN = authorizationEntry.getDN();
- }
- }
- else if (oid.equals(OID_PROXIED_AUTH_V2))
- {
- // The requester must have the PROXIED_AUTH privilige in order to
- // be able to use this control.
- if (! clientConnection.hasPrivilege(Privilege.PROXIED_AUTH, this))
- {
- int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
- appendErrorMessage(getMessage(msgID));
- setResultCode(ResultCode.AUTHORIZATION_DENIED);
- break modifyProcessing;
- }
-
-
- ProxiedAuthV2Control proxyControl;
- if (c instanceof ProxiedAuthV2Control)
- {
- proxyControl = (ProxiedAuthV2Control) c;
- }
- else
- {
- try
- {
- proxyControl = ProxiedAuthV2Control.decodeControl(c);
- }
- catch (LDAPException le)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, le);
- }
-
- setResultCode(ResultCode.valueOf(le.getResultCode()));
- appendErrorMessage(le.getMessage());
-
- break modifyProcessing;
- }
- }
-
-
- Entry authorizationEntry;
- try
- {
- authorizationEntry = proxyControl.getAuthorizationEntry();
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResultCode(de.getResultCode());
- appendErrorMessage(de.getErrorMessage());
-
- break modifyProcessing;
- }
-
- if (AccessControlConfigManager.getInstance().
- getAccessControlHandler().isProxiedAuthAllowed(this,
- authorizationEntry) == false) {
- setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
- int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
-
- skipPostOperation = true;
- break modifyProcessing;
- }
- setAuthorizationEntry(authorizationEntry);
- if (authorizationEntry == null)
- {
- proxiedAuthorizationDN = DN.nullDN();
- }
- else
- {
- proxiedAuthorizationDN = authorizationEntry.getDN();
- }
- }
-
- // NYI -- Add support for additional controls.
- else if (c.isCritical())
- {
- Backend backend = DirectoryServer.getBackend(entryDN);
- if ((backend == null) || (! backend.supportsControl(oid)))
- {
- setResultCode(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION);
-
- int msgID = MSGID_MODIFY_UNSUPPORTED_CRITICAL_CONTROL;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- oid));
-
- break modifyProcessing;
- }
- }
- }
- }
-
-
- // Get the password policy state object for the entry that can be used
- // to perform any appropriate password policy processing. Also, see if
- // the entry is being updated by the end user or an administrator.
- PasswordPolicyState pwPolicyState;
- boolean selfChange = entryDN.equals(getAuthorizationDN());
- try
- {
- // FIXME -- Need a way to enable debug mode.
- pwPolicyState = new PasswordPolicyState(currentEntry, false, false);
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResultCode(de.getResultCode());
- appendErrorMessage(de.getErrorMessage());
-
- break modifyProcessing;
- }
-
-
- // Create a duplicate of the entry and apply the changes to it.
- modifiedEntry = currentEntry.duplicate(false);
-
- if (! noOp)
- {
- // Invoke any conflict resolution processing that might be needed by
- // the synchronization provider.
- for (SynchronizationProvider provider :
- DirectoryServer.getSynchronizationProviders())
- {
- try
- {
- SynchronizationProviderResult result =
- provider.handleConflictResolution(this);
- if (! result.continueOperationProcessing())
- {
- break modifyProcessing;
- }
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- logError(ErrorLogCategory.SYNCHRONIZATION,
- ErrorLogSeverity.SEVERE_ERROR,
- MSGID_MODIFY_SYNCH_CONFLICT_RESOLUTION_FAILED,
- getConnectionID(), getOperationID(),
- getExceptionMessage(de));
-
- setResponseData(de);
- break modifyProcessing;
- }
- }
- }
-
-
- // Declare variables used for password policy state processing.
- boolean passwordChanged = false;
- boolean currentPasswordProvided = false;
- boolean isEnabled = true;
- boolean enabledStateChanged = false;
- int numPasswords;
- if (currentEntry.hasAttribute(
- pwPolicyState.getPolicy().getPasswordAttribute()))
- {
- // It may actually have more than one, but we can't tell the
- // difference if the values are encoded, and its enough for our
- // purposes just to know that there is at least one.
- numPasswords = 1;
- }
- else
- {
- numPasswords = 0;
- }
-
-
- // If it's not an internal or synchronization operation, then iterate
- // through the set of modifications to see if a password is included in
- // the changes. If so, then add the appropriate state changes to the
- // set of modifications.
- if (! (isInternalOperation() || isSynchronizationOperation()))
- {
- for (Modification m : modifications)
- {
- if (m.getAttribute().getAttributeType().equals(
- pwPolicyState.getPolicy().getPasswordAttribute()))
- {
- passwordChanged = true;
- if (! selfChange)
- {
- if (! clientConnection.hasPrivilege(Privilege.PASSWORD_RESET,
- this))
- {
- int msgID = MSGID_MODIFY_PWRESET_INSUFFICIENT_PRIVILEGES;
- appendErrorMessage(getMessage(msgID));
- setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
- break modifyProcessing;
- }
- }
-
- break;
- }
- }
- }
-
-
- for (Modification m : modifications)
- {
- Attribute a = m.getAttribute();
- AttributeType t = a.getAttributeType();
-
-
- // If the attribute type is marked "NO-USER-MODIFICATION" then fail
- // unless this is an internal operation or is related to
- // synchronization in some way.
- if (t.isNoUserModification())
- {
- if (! (isInternalOperation() || isSynchronizationOperation() ||
- m.isInternal()))
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(getMessage(MSGID_MODIFY_ATTR_IS_NO_USER_MOD,
- String.valueOf(entryDN),
- a.getName()));
- break modifyProcessing;
- }
- }
-
- // If the attribute type is marked "OBSOLETE" and the modification
- // is setting new values, then fail unless this is an internal
- // operation or is related to synchronization in some way.
- if (t.isObsolete())
- {
- if (a.hasValue() &&
- (m.getModificationType() != ModificationType.DELETE))
- {
- if (! (isInternalOperation() || isSynchronizationOperation() ||
- m.isInternal()))
- {
- setResultCode(ResultCode.CONSTRAINT_VIOLATION);
- appendErrorMessage(getMessage(MSGID_MODIFY_ATTR_IS_OBSOLETE,
- String.valueOf(entryDN),
- a.getName()));
- break modifyProcessing;
- }
- }
- }
-
-
- // See if the attribute is one which controls the privileges available
- // for a user. If it is, then the client must have the
- // PRIVILEGE_CHANGE privilege.
- if (t.hasName(OP_ATTR_PRIVILEGE_NAME))
- {
- if (! clientConnection.hasPrivilege(Privilege.PRIVILEGE_CHANGE,
- this))
- {
- int msgID = MSGID_MODIFY_CHANGE_PRIVILEGE_INSUFFICIENT_PRIVILEGES;
- appendErrorMessage(getMessage(msgID));
- setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
- break modifyProcessing;
- }
- }
-
-
- // If the modification is updating the password attribute, then
- // perform any necessary password policy processing. This processing
- // should be skipped for synchronization operations.
- boolean isPassword
- = t.equals(pwPolicyState.getPolicy().getPasswordAttribute());
- if (isPassword && (!(isSynchronizationOperation())))
- {
- // If the attribute contains any options, then reject it. Passwords
- // will not be allowed to have options. Skipped for internal
- // operations.
- if(!isInternalOperation())
- {
- if (a.hasOptions())
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_PASSWORDS_CANNOT_HAVE_OPTIONS;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
-
-
- // If it's a self change, then see if that's allowed.
- if (selfChange &&
- (! pwPolicyState.getPolicy().allowUserPasswordChanges()))
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_NO_USER_PW_CHANGES;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
-
-
- // If we require secure password changes, then makes sure it's a
- // secure communication channel.
- if (pwPolicyState.getPolicy().requireSecurePasswordChanges() &&
- (! clientConnection.isSecure()))
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_REQUIRE_SECURE_CHANGES;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
-
-
- // If it's a self change and it's not been long enough since the
- // previous change, then reject it.
- if (selfChange && pwPolicyState.isWithinMinimumAge())
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_WITHIN_MINIMUM_AGE;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
- }
-
- // Check to see whether this will adding, deleting, or replacing
- // password values (increment doesn't make any sense for passwords).
- // Then perform the appropriate type of processing for that kind of
- // modification.
- boolean isAdd = false;
- LinkedHashSet<AttributeValue> pwValues = a.getValues();
- LinkedHashSet<AttributeValue> encodedValues =
- new LinkedHashSet<AttributeValue>();
- switch (m.getModificationType())
- {
- case ADD:
- case REPLACE:
- int passwordsToAdd = pwValues.size();
-
- if (m.getModificationType() == ModificationType.ADD)
- {
- numPasswords += passwordsToAdd;
- isAdd = true;
- }
- else
- {
- numPasswords = passwordsToAdd;
- }
- // If there were multiple password values provided, then make
- // sure that's OK.
-
- if (! isInternalOperation() &&
- ! pwPolicyState.getPolicy().allowExpiredPasswordChanges() &&
- (passwordsToAdd > 1))
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_MULTIPLE_VALUES_NOT_ALLOWED;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
-
- // Iterate through the password values and see if any of them
- // are pre-encoded. If so, then check to see if we'll allow it.
- // Otherwise, store the clear-text values for later validation
- // and update the attribute with the encoded values.
- for (AttributeValue v : pwValues)
- {
- if (pwPolicyState.passwordIsPreEncoded(v.getValue()))
- {
- if ((!isInternalOperation()) &&
- ! pwPolicyState.getPolicy().allowPreEncodedPasswords())
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_NO_PREENCODED_PASSWORDS;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
- else
- {
- encodedValues.add(v);
- }
- }
- else
- {
- if (isAdd)
- {
- // Make sure that the password value doesn't already
- // exist.
- if (pwPolicyState.passwordMatches(v.getValue()))
- {
- setResultCode(ResultCode.ATTRIBUTE_OR_VALUE_EXISTS);
-
- int msgID = MSGID_MODIFY_PASSWORD_EXISTS;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
- }
-
- if (newPasswords == null)
- {
- newPasswords = new LinkedList<AttributeValue>();
- }
-
- newPasswords.add(v);
-
- try
- {
- for (ByteString s :
- pwPolicyState.encodePassword(v.getValue()))
- {
- encodedValues.add(new AttributeValue(
- a.getAttributeType(), s));
- }
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResultCode(de.getResultCode());
- appendErrorMessage(de.getErrorMessage());
- break modifyProcessing;
- }
- }
- }
-
- a.setValues(encodedValues);
-
- break;
-
- case DELETE:
- // Iterate through the password values and see if any of them
- // are pre-encoded. We will never allow pre-encoded passwords
- // for user password changes, but we will allow them for
- // administrators. For each clear-text value, verify that at
- // least one value in the entry matches and replace the
- // clear-text value with the appropriate encoded forms.
- for (AttributeValue v : pwValues)
- {
- if (pwPolicyState.passwordIsPreEncoded(v.getValue()))
- {
- if ((!isInternalOperation()) && selfChange)
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_NO_PREENCODED_PASSWORDS;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
- else
- {
- encodedValues.add(v);
- }
- }
- else
- {
- List<Attribute> attrList = currentEntry.getAttribute(t);
- if ((attrList == null) || (attrList.isEmpty()))
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_NO_EXISTING_VALUES;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
- boolean found = false;
- for (Attribute attr : attrList)
- {
- for (AttributeValue av : attr.getValues())
- {
- if (pwPolicyState.getPolicy().usesAuthPasswordSyntax())
- {
- if (AuthPasswordSyntax.isEncoded(av.getValue()))
- {
- try
- {
- StringBuilder[] compoenents =
- AuthPasswordSyntax.decodeAuthPassword(
- av.getStringValue());
- PasswordStorageScheme scheme =
- DirectoryServer.
- getAuthPasswordStorageScheme(
- compoenents[0].toString());
- if (scheme != null)
- {
- if (scheme.authPasswordMatches(
- v.getValue(),
- compoenents[1].toString(),
- compoenents[2].toString()))
- {
- encodedValues.add(av);
- found = true;
- }
- }
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResultCode(de.getResultCode());
-
- int msgID = MSGID_MODIFY_CANNOT_DECODE_PW;
- appendErrorMessage(
- getMessage(msgID, de.getErrorMessage()));
- break modifyProcessing;
- }
- }
- else
- {
- if (av.equals(v))
- {
- encodedValues.add(v);
- found = true;
- }
- }
- }
- else
- {
- if (UserPasswordSyntax.isEncoded(av.getValue()))
- {
- try
- {
- String[] compoenents =
- UserPasswordSyntax.decodeUserPassword(
- av.getStringValue());
- PasswordStorageScheme scheme =
- DirectoryServer.getPasswordStorageScheme(
- toLowerCase(compoenents[0]));
- if (scheme != null)
- {
- if (scheme.passwordMatches(
- v.getValue(),
- new ASN1OctetString(compoenents[1])))
- {
- encodedValues.add(av);
- found = true;
- }
- }
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResultCode(de.getResultCode());
-
- int msgID = MSGID_MODIFY_CANNOT_DECODE_PW;
- appendErrorMessage(getMessage(msgID,
- de.getErrorMessage()));
- break modifyProcessing;
- }
- }
- else
- {
- if (av.equals(v))
- {
- encodedValues.add(v);
- found = true;
- }
- }
- }
- }
- }
-
- if (found)
- {
- if (currentPasswords == null)
- {
- currentPasswords = new LinkedList<AttributeValue>();
- }
- currentPasswords.add(v);
-
- numPasswords--;
- }
- else
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_INVALID_PASSWORD;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
-
- currentPasswordProvided = true;
- }
- }
-
- a.setValues(encodedValues);
-
- break;
-
- default:
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_INVALID_MOD_TYPE_FOR_PASSWORD;
- appendErrorMessage(getMessage(msgID,
- String.valueOf(m.getModificationType()), a.getName()));
-
- break modifyProcessing;
- }
- }
- else
- {
- // See if it's an attribute used to maintain the account
- // enabled/disabled state.
- AttributeType disabledAttr =
- DirectoryServer.getAttributeType(OP_ATTR_ACCOUNT_DISABLED,
- true);
- if (t.equals(disabledAttr))
- {
- enabledStateChanged = true;
- for (AttributeValue v : a.getValues())
- {
- try
- {
- isEnabled = (! BooleanSyntax.decodeBooleanValue(
- v.getNormalizedValue()));
- }
- catch (DirectoryException de)
- {
- setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
- int msgID = MSGID_MODIFY_INVALID_DISABLED_VALUE;
- String message =
- getMessage(msgID, OP_ATTR_ACCOUNT_DISABLED,
- String.valueOf(de.getErrorMessage()));
- appendErrorMessage(message);
- break modifyProcessing;
- }
- }
- }
- }
-
-
- switch (m.getModificationType())
- {
- case ADD:
- // Make sure that one or more values have been provided for the
- // attribute.
- LinkedHashSet<AttributeValue> newValues = a.getValues();
- if ((newValues == null) || newValues.isEmpty())
- {
- setResultCode(ResultCode.PROTOCOL_ERROR);
- appendErrorMessage(getMessage(MSGID_MODIFY_ADD_NO_VALUES,
- String.valueOf(entryDN),
- a.getName()));
- break modifyProcessing;
- }
-
-
- // Make sure that all the new values are valid according to the
- // associated syntax.
- if (DirectoryServer.checkSchema())
- {
- AcceptRejectWarn syntaxPolicy =
- DirectoryServer.getSyntaxEnforcementPolicy();
- AttributeSyntax syntax = t.getSyntax();
-
- if (syntaxPolicy == AcceptRejectWarn.REJECT)
- {
- StringBuilder invalidReason = new StringBuilder();
-
- for (AttributeValue v : newValues)
- {
- if (! syntax.valueIsAcceptable(v.getValue(), invalidReason))
- {
- setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
- int msgID = MSGID_MODIFY_ADD_INVALID_SYNTAX;
- appendErrorMessage(getMessage(msgID,
- String.valueOf(entryDN),
- a.getName(),
- v.getStringValue(),
- invalidReason.toString()));
-
- break modifyProcessing;
- }
- }
- }
- else if (syntaxPolicy == AcceptRejectWarn.WARN)
- {
- StringBuilder invalidReason = new StringBuilder();
-
- for (AttributeValue v : newValues)
- {
- if (! syntax.valueIsAcceptable(v.getValue(), invalidReason))
- {
- setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
- int msgID = MSGID_MODIFY_ADD_INVALID_SYNTAX;
- logError(ErrorLogCategory.SCHEMA,
- ErrorLogSeverity.SEVERE_WARNING, msgID,
- String.valueOf(entryDN), a.getName(),
- v.getStringValue(), invalidReason.toString());
-
- invalidReason = new StringBuilder();
- }
- }
- }
- }
-
-
- // Add the provided attribute or merge an existing attribute with
- // the values of the new attribute. If there are any duplicates,
- // then fail.
- LinkedList<AttributeValue> duplicateValues =
- new LinkedList<AttributeValue>();
- if (a.getAttributeType().isObjectClassType())
- {
- try
- {
- modifiedEntry.addObjectClasses(newValues);
- break;
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResponseData(de);
- break modifyProcessing;
- }
- }
- else
- {
- modifiedEntry.addAttribute(a, duplicateValues);
- if (duplicateValues.isEmpty())
- {
- break;
- }
- else
- {
- StringBuilder buffer = new StringBuilder();
- Iterator<AttributeValue> iterator =
- duplicateValues.iterator();
- buffer.append(iterator.next().getStringValue());
- while (iterator.hasNext())
- {
- buffer.append(", ");
- buffer.append(iterator.next().getStringValue());
- }
-
- setResultCode(ResultCode.ATTRIBUTE_OR_VALUE_EXISTS);
-
- int msgID = MSGID_MODIFY_ADD_DUPLICATE_VALUE;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- a.getName(),
- buffer.toString()));
-
- break modifyProcessing;
- }
- }
-
-
- case DELETE:
- // Remove the specified attribute values or the entire attribute
- // from the value. If there are any specified values that were
- // not present, then fail. If the RDN attribute value would be
- // removed, then fail.
- LinkedList<AttributeValue> missingValues =
- new LinkedList<AttributeValue>();
- boolean attrExists =
- modifiedEntry.removeAttribute(a, missingValues);
-
- if (attrExists)
- {
- if (missingValues.isEmpty())
- {
- RDN rdn = modifiedEntry.getDN().getRDN();
- if ((rdn != null) && rdn.hasAttributeType(t) &&
- (! modifiedEntry.hasValue(t, a.getOptions(),
- rdn.getAttributeValue(t))))
- {
- setResultCode(ResultCode.NOT_ALLOWED_ON_RDN);
-
- int msgID = MSGID_MODIFY_DELETE_RDN_ATTR;
- appendErrorMessage(getMessage(msgID,
- String.valueOf(entryDN),
- a.getName()));
- break modifyProcessing;
- }
-
- break;
- }
- else
- {
- StringBuilder buffer = new StringBuilder();
- Iterator<AttributeValue> iterator = missingValues.iterator();
- buffer.append(iterator.next().getStringValue());
- while (iterator.hasNext())
- {
- buffer.append(", ");
- buffer.append(iterator.next().getStringValue());
- }
-
- setResultCode(ResultCode.NO_SUCH_ATTRIBUTE);
-
- int msgID = MSGID_MODIFY_DELETE_MISSING_VALUES;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- a.getName(),
- buffer.toString()));
-
- break modifyProcessing;
- }
- }
- else
- {
- setResultCode(ResultCode.NO_SUCH_ATTRIBUTE);
-
- int msgID = MSGID_MODIFY_DELETE_NO_SUCH_ATTR;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- a.getName()));
- break modifyProcessing;
- }
-
-
- case REPLACE:
- // If it is the objectclass attribute, then treat that separately.
- if (a.getAttributeType().isObjectClassType())
- {
- try
- {
- modifiedEntry.setObjectClasses(a.getValues());
- break;
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResponseData(de);
- break modifyProcessing;
- }
- }
-
-
- // If the provided attribute does not have any values, then we
- // will simply remove the attribute from the entry (if it exists).
- if (! a.hasValue())
- {
- modifiedEntry.removeAttribute(t, a.getOptions());
- RDN rdn = modifiedEntry.getDN().getRDN();
- if ((rdn != null) && rdn.hasAttributeType(t) &&
- (! modifiedEntry.hasValue(t, a.getOptions(),
- rdn.getAttributeValue(t))))
- {
- setResultCode(ResultCode.NOT_ALLOWED_ON_RDN);
-
- int msgID = MSGID_MODIFY_DELETE_RDN_ATTR;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- a.getName()));
- break modifyProcessing;
- }
- break;
- }
-
-
- // Make sure that all the new values are valid according to the
- // associated syntax.
- newValues = a.getValues();
- if (DirectoryServer.checkSchema())
- {
- AcceptRejectWarn syntaxPolicy =
- DirectoryServer.getSyntaxEnforcementPolicy();
- AttributeSyntax syntax = t.getSyntax();
-
- if (syntaxPolicy == AcceptRejectWarn.REJECT)
- {
- StringBuilder invalidReason = new StringBuilder();
-
- for (AttributeValue v : newValues)
- {
- if (! syntax.valueIsAcceptable(v.getValue(), invalidReason))
- {
- setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
- int msgID = MSGID_MODIFY_REPLACE_INVALID_SYNTAX;
- appendErrorMessage(getMessage(msgID,
- String.valueOf(entryDN),
- a.getName(),
- v.getStringValue(),
- invalidReason.toString()));
-
- break modifyProcessing;
- }
- }
- }
- else if (syntaxPolicy == AcceptRejectWarn.WARN)
- {
- StringBuilder invalidReason = new StringBuilder();
-
- for (AttributeValue v : newValues)
- {
- if (! syntax.valueIsAcceptable(v.getValue(), invalidReason))
- {
- setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
- int msgID = MSGID_MODIFY_REPLACE_INVALID_SYNTAX;
- logError(ErrorLogCategory.SCHEMA,
- ErrorLogSeverity.SEVERE_WARNING, msgID,
- String.valueOf(entryDN), a.getName(),
- v.getStringValue(), invalidReason.toString());
-
- invalidReason = new StringBuilder();
- }
- }
- }
- }
-
-
- // If the provided attribute does not have any options, then we
- // will simply use it in place of any existing attribute of the
- // provided type (or add it if it doesn't exist).
- if (! a.hasOptions())
- {
- List<Attribute> attrList = new ArrayList<Attribute>(1);
- attrList.add(a);
- modifiedEntry.putAttribute(t, attrList);
-
- RDN rdn = modifiedEntry.getDN().getRDN();
- if ((rdn != null) && rdn.hasAttributeType(t) &&
- (! modifiedEntry.hasValue(t, a.getOptions(),
- rdn.getAttributeValue(t))))
- {
- setResultCode(ResultCode.NOT_ALLOWED_ON_RDN);
-
- int msgID = MSGID_MODIFY_DELETE_RDN_ATTR;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- a.getName()));
- break modifyProcessing;
- }
- break;
- }
-
-
- // See if there is an existing attribute of the provided type. If
- // not, then we'll use the new one.
- List<Attribute> attrList = modifiedEntry.getAttribute(t);
- if ((attrList == null) || attrList.isEmpty())
- {
- attrList = new ArrayList<Attribute>(1);
- attrList.add(a);
- modifiedEntry.putAttribute(t, attrList);
-
- RDN rdn = modifiedEntry.getDN().getRDN();
- if ((rdn != null) && rdn.hasAttributeType(t) &&
- (! modifiedEntry.hasValue(t, a.getOptions(),
- rdn.getAttributeValue(t))))
- {
- setResultCode(ResultCode.NOT_ALLOWED_ON_RDN);
-
- int msgID = MSGID_MODIFY_DELETE_RDN_ATTR;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- a.getName()));
- break modifyProcessing;
- }
- break;
- }
-
-
- // There must be an existing occurrence of the provided attribute
- // in the entry. If there is a version with exactly the set of
- // options provided, then replace it. Otherwise, add a new one.
- boolean found = false;
- for (int i=0; i < attrList.size(); i++)
- {
- if (attrList.get(i).optionsEqual(a.getOptions()))
- {
- attrList.set(i, a);
- found = true;
- break;
- }
- }
-
- if (! found)
- {
- attrList.add(a);
- }
-
- RDN rdn = modifiedEntry.getDN().getRDN();
- if ((rdn != null) && rdn.hasAttributeType(t) &&
- (! modifiedEntry.hasValue(t, a.getOptions(),
- rdn.getAttributeValue(t))))
- {
- setResultCode(ResultCode.NOT_ALLOWED_ON_RDN);
-
- int msgID = MSGID_MODIFY_DELETE_RDN_ATTR;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- a.getName()));
- break modifyProcessing;
- }
- break;
-
-
- case INCREMENT:
- // The specified attribute type must not be an RDN attribute.
- rdn = modifiedEntry.getDN().getRDN();
- if ((rdn != null) && rdn.hasAttributeType(t))
- {
- setResultCode(ResultCode.NOT_ALLOWED_ON_RDN);
- appendErrorMessage(getMessage(MSGID_MODIFY_INCREMENT_RDN,
- String.valueOf(entryDN),
- a.getName()));
- }
-
-
- // The provided attribute must have a single value, and it must be
- // an integer.
- LinkedHashSet<AttributeValue> values = a.getValues();
- if ((values == null) || values.isEmpty())
- {
- setResultCode(ResultCode.PROTOCOL_ERROR);
-
- int msgID = MSGID_MODIFY_INCREMENT_REQUIRES_VALUE;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- a.getName()));
-
- break modifyProcessing;
- }
- else if (values.size() > 1)
- {
- setResultCode(ResultCode.PROTOCOL_ERROR);
-
- int msgID = MSGID_MODIFY_INCREMENT_REQUIRES_SINGLE_VALUE;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- a.getName()));
- break modifyProcessing;
- }
-
- AttributeValue v = values.iterator().next();
-
- long incrementValue;
- try
- {
- incrementValue = Long.parseLong(v.getNormalizedStringValue());
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, e);
- }
-
- setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
- int msgID = MSGID_MODIFY_INCREMENT_PROVIDED_VALUE_NOT_INTEGER;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- a.getName(), v.getStringValue()));
-
- break modifyProcessing;
- }
-
-
- // Get the corresponding attribute from the entry and make sure
- // that it has a single integer value.
- attrList = modifiedEntry.getAttribute(t, a.getOptions());
- if ((attrList == null) || attrList.isEmpty())
- {
- setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-
- int msgID = MSGID_MODIFY_INCREMENT_REQUIRES_EXISTING_VALUE;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- a.getName()));
-
- break modifyProcessing;
- }
-
- boolean updated = false;
- for (Attribute attr : attrList)
- {
- LinkedHashSet<AttributeValue> valueList = attr.getValues();
- if ((valueList == null) || valueList.isEmpty())
- {
- continue;
- }
-
- LinkedHashSet<AttributeValue> newValueList =
- new LinkedHashSet<AttributeValue>(valueList.size());
- for (AttributeValue existingValue : valueList)
- {
- long newIntValue;
- try
- {
- long existingIntValue =
- Long.parseLong(existingValue.getStringValue());
- newIntValue = existingIntValue + incrementValue;
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, e);
- }
-
- setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
- int msgID = MSGID_MODIFY_INCREMENT_REQUIRES_INTEGER_VALUE;
- appendErrorMessage(getMessage(msgID,
- String.valueOf(entryDN),
- a.getName(),
- existingValue.getStringValue()));
- break modifyProcessing;
- }
-
- ByteString newValue =
- new ASN1OctetString(String.valueOf(newIntValue));
- newValueList.add(new AttributeValue(t, newValue));
- }
-
- attr.setValues(newValueList);
- updated = true;
- }
-
- if (! updated)
- {
- setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-
- int msgID = MSGID_MODIFY_INCREMENT_REQUIRES_EXISTING_VALUE;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
- a.getName()));
-
- break modifyProcessing;
- }
-
- break;
-
- default:
- }
- }
-
-
- // If there was a password change, then perform any additional checks
- // that may be necessary.
- if (passwordChanged)
- {
- // If it was a self change, then see if the current password was
- // provided and handle accordingly.
- if (selfChange &&
- pwPolicyState.getPolicy().requireCurrentPassword() &&
- (! currentPasswordProvided))
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_PW_CHANGE_REQUIRES_CURRENT_PW;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
-
-
- // If this change would result in multiple password values, then see
- // if that's OK.
- if ((numPasswords > 1) &&
- (! pwPolicyState.getPolicy().allowMultiplePasswordValues()))
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_MULTIPLE_PASSWORDS_NOT_ALLOWED;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
-
-
- // If any of the password values should be validated, then do so now.
- if (selfChange ||
- (! pwPolicyState.getPolicy().skipValidationForAdministrators()))
- {
- if (newPasswords != null)
- {
- HashSet<ByteString> clearPasswords = new HashSet<ByteString>();
- clearPasswords.addAll(pwPolicyState.getClearPasswords());
-
- if (currentPasswords != null)
- {
- if (clearPasswords.isEmpty())
- {
- for (AttributeValue v : currentPasswords)
- {
- clearPasswords.add(v.getValue());
- }
- }
- else
- {
- // NOTE: We can't rely on the fact that Set doesn't allow
- // duplicates because technically it's possible that the
- // values aren't duplicates if they are ASN.1 elements with
- // different types (like 0x04 for a standard universal octet
- // string type versus 0x80 for a simple password in a bind
- // operation). So we have to manually check for duplicates.
- for (AttributeValue v : currentPasswords)
- {
- ByteString pw = v.getValue();
-
- boolean found = false;
- for (ByteString s : clearPasswords)
- {
- if (Arrays.equals(s.value(), pw.value()))
- {
- found = true;
- break;
- }
- }
-
- if (! found)
- {
- clearPasswords.add(pw);
- }
- }
- }
- }
-
- for (AttributeValue v : newPasswords)
- {
- StringBuilder invalidReason = new StringBuilder();
- if (! pwPolicyState.passwordIsAcceptable(this, modifiedEntry,
- v.getValue(),
- clearPasswords,
- invalidReason))
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_PW_VALIDATION_FAILED;
- appendErrorMessage(getMessage(msgID,
- invalidReason.toString()));
- break modifyProcessing;
- }
- }
- }
- }
- }
-
-
- // Check to see if the client has permission to perform the
- // modify.
- // The access control check is not made any earlier because the
- // handler needs access to the modified entry.
-
- // FIXME: for now assume that this will check all permission
- // pertinent to the operation. This includes proxy authorization
- // and any other controls specified.
-
- // FIXME: earlier checks to see if the entry already exists may
- // have already exposed sensitive information to the client.
- if (!AccessControlConfigManager.getInstance()
- .getAccessControlHandler().isAllowed(this)) {
- setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
- int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
- appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
-
- skipPostOperation = true;
- break modifyProcessing;
- }
-
- boolean wasLocked = false;
- if (passwordChanged)
- {
- // See if the account was locked for any reason.
- wasLocked = pwPolicyState.lockedDueToIdleInterval() ||
- pwPolicyState.lockedDueToMaximumResetAge() ||
- pwPolicyState.lockedDueToFailures();
-
- // Update the password policy state attributes in the user's entry.
- // If the modification fails, then these changes won't be applied.
- pwPolicyState.setPasswordChangedTime();
- pwPolicyState.clearFailureLockout();
- pwPolicyState.clearGraceLoginTimes();
- pwPolicyState.clearWarnedTime();
-
- if(pwPolicyState.getPolicy().forceChangeOnAdd()
- || pwPolicyState.getPolicy().forceChangeOnReset())
- {
- if (selfChange)
- {
- pwPolicyState.setMustChangePassword(false);
- }
- else
- {
- pwPolicyState.setMustChangePassword(
- pwPolicyState.getPolicy().forceChangeOnReset());
- }
- }
-
- if (pwPolicyState.getPolicy().getRequireChangeByTime() > 0)
- {
- pwPolicyState.setRequiredChangeTime();
- }
- modifications.addAll(pwPolicyState.getModifications());
- //Apply pwd Policy modifications to modified entry.
- try {
- modifiedEntry.applyModifications(pwPolicyState.getModifications());
- } catch (DirectoryException e) {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, e);
- }
-
- setResponseData(e);
- break modifyProcessing;
- }
- }
- else if ((! isInternalOperation()) &&
- pwPolicyState.mustChangePassword())
- {
- // The user will not be allowed to do anything else before
- // the password gets changed.
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
- int msgID = MSGID_MODIFY_MUST_CHANGE_PASSWORD;
- appendErrorMessage(getMessage(msgID));
- break modifyProcessing;
- }
-
- // Make sure that the new entry is valid per the server schema.
- if (DirectoryServer.checkSchema())
- {
- StringBuilder invalidReason = new StringBuilder();
- if (! modifiedEntry.conformsToSchema(null, false, false, false,
- invalidReason))
- {
- setResultCode(ResultCode.OBJECTCLASS_VIOLATION);
- appendErrorMessage(getMessage(MSGID_MODIFY_VIOLATES_SCHEMA,
- String.valueOf(entryDN),
- invalidReason.toString()));
- break modifyProcessing;
- }
- }
-
- // Check for and handle a request to cancel this operation.
- if (cancelRequest != null)
- {
- indicateCancelled(cancelRequest);
- processingStopTime = System.currentTimeMillis();
- logModifyResponse(this);
- pluginConfigManager.invokePostResponseModifyPlugins(this);
- return;
- }
-
- // If the operation is not a synchronization operation,
- // Invoke the pre-operation modify plugins.
- if (!isSynchronizationOperation())
- {
- PreOperationPluginResult preOpResult =
- pluginConfigManager.invokePreOperationModifyPlugins(this);
- if (preOpResult.connectionTerminated())
- {
- // There's no point in continuing with anything. Log the result
- // and return.
- setResultCode(ResultCode.CANCELED);
-
- int msgID = MSGID_CANCELED_BY_PREOP_DISCONNECT;
- appendErrorMessage(getMessage(msgID));
-
- processingStopTime = System.currentTimeMillis();
-
- logModifyResponse(this);
- pluginConfigManager.invokePostResponseModifyPlugins(this);
- return;
- }
- else if (preOpResult.sendResponseImmediately())
- {
- skipPostOperation = true;
- break modifyProcessing;
- }
- else if (preOpResult.skipCoreProcessing())
- {
- skipPostOperation = false;
- break modifyProcessing;
- }
- }
-
-
- // Check for and handle a request to cancel this operation.
- if (cancelRequest != null)
- {
- indicateCancelled(cancelRequest);
- processingStopTime = System.currentTimeMillis();
- logModifyResponse(this);
- pluginConfigManager.invokePostResponseModifyPlugins(this);
- return;
- }
-
-
- // Actually perform the modify operation. This should also include
- // taking care of any synchronization that might be needed.
- Backend backend = DirectoryServer.getBackend(entryDN);
- if (backend == null)
- {
- setResultCode(ResultCode.NO_SUCH_OBJECT);
- appendErrorMessage(getMessage(MSGID_MODIFY_NO_BACKEND_FOR_ENTRY,
- String.valueOf(entryDN)));
- break modifyProcessing;
- }
-
- try
- {
- // If it is not a private backend, then check to see if the server or
- // backend is operating in read-only mode.
- if (! backend.isPrivateBackend())
- {
- switch (DirectoryServer.getWritabilityMode())
- {
- case DISABLED:
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(getMessage(MSGID_MODIFY_SERVER_READONLY,
- String.valueOf(entryDN)));
- break modifyProcessing;
-
- case INTERNAL_ONLY:
- if (! (isInternalOperation() || isSynchronizationOperation()))
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(getMessage(MSGID_MODIFY_SERVER_READONLY,
- String.valueOf(entryDN)));
- break modifyProcessing;
- }
- }
-
- switch (backend.getWritabilityMode())
- {
- case DISABLED:
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(getMessage(MSGID_MODIFY_BACKEND_READONLY,
- String.valueOf(entryDN)));
- break modifyProcessing;
-
- case INTERNAL_ONLY:
- if (! (isInternalOperation() || isSynchronizationOperation()))
- {
- setResultCode(ResultCode.UNWILLING_TO_PERFORM);
- appendErrorMessage(getMessage(MSGID_MODIFY_BACKEND_READONLY,
- String.valueOf(entryDN)));
- break modifyProcessing;
- }
- }
- }
-
-
- if (noOp)
- {
- appendErrorMessage(getMessage(MSGID_MODIFY_NOOP));
-
- // FIXME -- We must set a result code other than SUCCESS.
- }
- else
- {
- for (SynchronizationProvider provider :
- DirectoryServer.getSynchronizationProviders())
- {
- try
- {
- SynchronizationProviderResult result =
- provider.doPreOperation(this);
- if (! result.continueOperationProcessing())
- {
- break modifyProcessing;
- }
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- logError(ErrorLogCategory.SYNCHRONIZATION,
- ErrorLogSeverity.SEVERE_ERROR,
- MSGID_MODIFY_SYNCH_PREOP_FAILED, getConnectionID(),
- getOperationID(), getExceptionMessage(de));
-
- setResponseData(de);
- break modifyProcessing;
- }
- }
-
- backend.replaceEntry(modifiedEntry, this);
-
-
- // If the modification was successful, then see if there's any other
- // work that we need to do here before handing off to postop
- // plugins.
- if (passwordChanged)
- {
- if (selfChange)
- {
- AuthenticationInfo authInfo =
- clientConnection.getAuthenticationInfo();
- if (authInfo.getAuthenticationDN().equals(entryDN))
- {
- clientConnection.setMustChangePassword(false);
- }
-
- int msgID = MSGID_MODIFY_PASSWORD_CHANGED;
- String message = getMessage(msgID);
- pwPolicyState.generateAccountStatusNotification(
- AccountStatusNotificationType.PASSWORD_CHANGED, entryDN,
- msgID, message);
- }
- else
- {
- int msgID = MSGID_MODIFY_PASSWORD_RESET;
- String message = getMessage(msgID);
- pwPolicyState.generateAccountStatusNotification(
- AccountStatusNotificationType.PASSWORD_RESET, entryDN,
- msgID, message);
- }
- }
-
- if (enabledStateChanged)
- {
- if (isEnabled)
- {
- int msgID = MSGID_MODIFY_ACCOUNT_ENABLED;
- String message = getMessage(msgID);
- pwPolicyState.generateAccountStatusNotification(
- AccountStatusNotificationType.ACCOUNT_ENABLED, entryDN,
- msgID, message);
- }
- else
- {
- int msgID = MSGID_MODIFY_ACCOUNT_DISABLED;
- String message = getMessage(msgID);
- pwPolicyState.generateAccountStatusNotification(
- AccountStatusNotificationType.ACCOUNT_DISABLED, entryDN,
- msgID, message);
- }
- }
-
- if (wasLocked)
- {
- int msgID = MSGID_MODIFY_ACCOUNT_UNLOCKED;
- String message = getMessage(msgID);
- pwPolicyState.generateAccountStatusNotification(
- AccountStatusNotificationType.ACCOUNT_UNLOCKED, entryDN,
- msgID, message);
- }
- }
-
- if (preReadRequest != null)
- {
- Entry entry = currentEntry.duplicate(true);
-
- if (! preReadRequest.allowsAttribute(
- DirectoryServer.getObjectClassAttributeType()))
- {
- entry.removeAttribute(
- DirectoryServer.getObjectClassAttributeType());
- }
-
- if (! preReadRequest.returnAllUserAttributes())
- {
- Iterator<AttributeType> iterator =
- entry.getUserAttributes().keySet().iterator();
- while (iterator.hasNext())
- {
- AttributeType attrType = iterator.next();
- if (! preReadRequest.allowsAttribute(attrType))
- {
- iterator.remove();
- }
- }
- }
-
- if (! preReadRequest.returnAllOperationalAttributes())
- {
- Iterator<AttributeType> iterator =
- entry.getOperationalAttributes().keySet().iterator();
- while (iterator.hasNext())
- {
- AttributeType attrType = iterator.next();
- if (! preReadRequest.allowsAttribute(attrType))
- {
- iterator.remove();
- }
- }
- }
-
- // FIXME -- Check access controls on the entry to see if it should
- // be returned or if any attributes need to be stripped
- // out..
- SearchResultEntry searchEntry = new SearchResultEntry(entry);
- LDAPPreReadResponseControl responseControl =
- new LDAPPreReadResponseControl(preReadRequest.getOID(),
- preReadRequest.isCritical(),
- searchEntry);
-
- responseControls.add(responseControl);
- }
-
- if (postReadRequest != null)
- {
- Entry entry = modifiedEntry.duplicate(true);
-
- if (! postReadRequest.allowsAttribute(
- DirectoryServer.getObjectClassAttributeType()))
- {
- entry.removeAttribute(
- DirectoryServer.getObjectClassAttributeType());
- }
-
- if (! postReadRequest.returnAllUserAttributes())
- {
- Iterator<AttributeType> iterator =
- entry.getUserAttributes().keySet().iterator();
- while (iterator.hasNext())
- {
- AttributeType attrType = iterator.next();
- if (! postReadRequest.allowsAttribute(attrType))
- {
- iterator.remove();
- }
- }
- }
-
- if (! postReadRequest.returnAllOperationalAttributes())
- {
- Iterator<AttributeType> iterator =
- entry.getOperationalAttributes().keySet().iterator();
- while (iterator.hasNext())
- {
- AttributeType attrType = iterator.next();
- if (! postReadRequest.allowsAttribute(attrType))
- {
- iterator.remove();
- }
- }
- }
-
- // FIXME -- Check access controls on the entry to see if it should
- // be returned or if any attributes need to be stripped
- // out..
- SearchResultEntry searchEntry = new SearchResultEntry(entry);
- LDAPPostReadResponseControl responseControl =
- new LDAPPostReadResponseControl(postReadRequest.getOID(),
- postReadRequest.isCritical(),
- searchEntry);
-
- responseControls.add(responseControl);
- }
-
- setResultCode(ResultCode.SUCCESS);
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- setResultCode(de.getResultCode());
- appendErrorMessage(de.getErrorMessage());
- setMatchedDN(de.getMatchedDN());
- setReferralURLs(de.getReferralURLs());
-
- break modifyProcessing;
- }
- catch (CancelledOperationException coe)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, coe);
- }
-
- CancelResult cancelResult = coe.getCancelResult();
-
- setCancelResult(cancelResult);
- setResultCode(cancelResult.getResultCode());
-
- String message = coe.getMessage();
- if ((message != null) && (message.length() > 0))
- {
- appendErrorMessage(message);
- }
-
- break modifyProcessing;
- }
- }
- finally
- {
- LockManager.unlock(entryDN, entryLock);
-
- for (SynchronizationProvider provider :
- DirectoryServer.getSynchronizationProviders())
- {
- try
- {
- provider.doPostOperation(this);
- }
- catch (DirectoryException de)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, de);
- }
-
- logError(ErrorLogCategory.SYNCHRONIZATION,
- ErrorLogSeverity.SEVERE_ERROR,
- MSGID_MODIFY_SYNCH_POSTOP_FAILED, getConnectionID(),
- getOperationID(), getExceptionMessage(de));
-
- setResponseData(de);
- break;
- }
- }
- }
- }
-
-
- // Indicate that it is now too late to attempt to cancel the operation.
- setCancelResult(CancelResult.TOO_LATE);
-
-
- // Invoke the post-operation modify plugins.
- if (! skipPostOperation)
- {
- // FIXME -- Should this also be done while holding the locks?
- PostOperationPluginResult postOpResult =
- pluginConfigManager.invokePostOperationModifyPlugins(this);
- if (postOpResult.connectionTerminated())
- {
- // There's no point in continuing with anything. Log the result and
- // return.
- setResultCode(ResultCode.CANCELED);
-
- int msgID = MSGID_CANCELED_BY_PREOP_DISCONNECT;
- appendErrorMessage(getMessage(msgID));
-
- processingStopTime = System.currentTimeMillis();
-
- logModifyResponse(this);
- pluginConfigManager.invokePostResponseModifyPlugins(this);
- return;
- }
- }
-
-
- // Notify any change notification listeners that might be registered with
- // the server.
- if (getResultCode() == ResultCode.SUCCESS)
- {
- for (ChangeNotificationListener changeListener :
- DirectoryServer.getChangeNotificationListeners())
- {
- try
- {
- changeListener.handleModifyOperation(this, currentEntry,
- modifiedEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_MODIFY_ERROR_NOTIFYING_CHANGE_LISTENER;
- String message = getMessage(msgID, getExceptionMessage(e));
- logError(ErrorLogCategory.CORE_SERVER, ErrorLogSeverity.SEVERE_ERROR,
- message, msgID);
- }
- }
- }
-
-
- // Stop the processing timer.
- processingStopTime = System.currentTimeMillis();
-
-
- // Send the modify response to the client.
- clientConnection.sendResponse(this);
-
-
- // Log the modify response.
- logModifyResponse(this);
-
-
- // Notify any persistent searches that might be registered with the server.
- if (getResultCode() == ResultCode.SUCCESS)
- {
- for (PersistentSearch persistentSearch :
- DirectoryServer.getPersistentSearches())
- {
- try
- {
- persistentSearch.processModify(this, currentEntry, modifiedEntry);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, e);
- }
-
- int msgID = MSGID_MODIFY_ERROR_NOTIFYING_PERSISTENT_SEARCH;
- String message = getMessage(msgID, String.valueOf(persistentSearch),
- getExceptionMessage(e));
- logError(ErrorLogCategory.CORE_SERVER, ErrorLogSeverity.SEVERE_ERROR,
- message, msgID);
-
- DirectoryServer.deregisterPersistentSearch(persistentSearch);
- }
- }
- }
-
-
- // Invoke the post-response modify plugins.
- pluginConfigManager.invokePostResponseModifyPlugins(this);
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final CancelResult cancel(CancelRequest cancelRequest)
- {
- this.cancelRequest = cancelRequest;
-
- CancelResult cancelResult = getCancelResult();
- long stopWaitingTime = System.currentTimeMillis() + 5000;
- while ((cancelResult == null) &&
- (System.currentTimeMillis() < stopWaitingTime))
- {
- try
- {
- Thread.sleep(50);
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, e);
- }
- }
-
- cancelResult = getCancelResult();
- }
-
- if (cancelResult == null)
- {
- // This can happen in some rare cases (e.g., if a client disconnects and
- // there is still a lot of data to send to that client), and in this case
- // we'll prevent the cancel thread from blocking for a long period of
- // time.
- cancelResult = CancelResult.CANNOT_CANCEL;
- }
-
- return cancelResult;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final CancelRequest getCancelRequest()
- {
- return cancelRequest;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- protected boolean setCancelRequest(CancelRequest cancelRequest)
- {
- this.cancelRequest = cancelRequest;
- return true;
- }
-
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
- public final void toString(StringBuilder buffer)
- {
- buffer.append("ModifyOperation(connID=");
- buffer.append(clientConnection.getConnectionID());
- buffer.append(", opID=");
- buffer.append(operationID);
- buffer.append(", dn=");
- buffer.append(rawEntryDN);
- buffer.append(")");
- }
-}
-
+}
\ No newline at end of file
--
Gitblit v1.10.0