From dd94891ad6946da5646fffdf11631144725b5636 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Thu, 24 Sep 2026 08:03:16 +0000
Subject: [PATCH] [#1051] Replicate a change made under the Relax Rules control like any other (#1053)
---
opendj-server-legacy/src/main/java/org/opends/server/plugins/LastModPlugin.java | 143 +++++++++++++++++++++++++++++++----------------
1 files changed, 94 insertions(+), 49 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/plugins/LastModPlugin.java b/opendj-server-legacy/src/main/java/org/opends/server/plugins/LastModPlugin.java
index a7970cd..b42d677 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/plugins/LastModPlugin.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/plugins/LastModPlugin.java
@@ -13,6 +13,7 @@
*
* Copyright 2006-2008 Sun Microsystems, Inc.
* Portions Copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
*/
package org.opends.server.plugins;
@@ -32,6 +33,7 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.ModificationType;
+import org.forgerock.opendj.ldap.schema.AttributeType;
import org.forgerock.opendj.server.config.meta.PluginCfgDefn;
import org.forgerock.opendj.server.config.server.LastModPluginCfg;
import org.forgerock.opendj.server.config.server.PluginCfg;
@@ -47,6 +49,7 @@
import org.opends.server.types.operation.PreOperationAddOperation;
import org.opends.server.types.operation.PreOperationModifyDNOperation;
import org.opends.server.types.operation.PreOperationModifyOperation;
+import org.opends.server.workflowelement.localbackend.LocalBackendWorkflowElement;
/**
* This class implements a Directory Server plugin that will add the
@@ -117,25 +120,31 @@
doPreOperation(PreOperationAddOperation addOperation)
{
// Create the attribute list for the creatorsName attribute, if appropriate.
- AttributeBuilder builder = new AttributeBuilder(getCreatorsNameAttributeType());
- DN creatorDN = addOperation.getAuthorizationDN();
- if (creatorDN == null)
+ if (!isSuppliedUnderRelaxRules(addOperation, getCreatorsNameAttributeType()))
{
- // This must mean that the operation was performed anonymously.
- // Even so, we still need to update the creatorsName attribute.
- builder.add(ByteString.empty());
+ AttributeBuilder builder = new AttributeBuilder(getCreatorsNameAttributeType());
+ DN creatorDN = addOperation.getAuthorizationDN();
+ if (creatorDN == null)
+ {
+ // This must mean that the operation was performed anonymously.
+ // Even so, we still need to update the creatorsName attribute.
+ builder.add(ByteString.empty());
+ }
+ else
+ {
+ builder.add(creatorDN.toString());
+ }
+ addOperation.setAttribute(getCreatorsNameAttributeType(), builder.toAttributeList());
}
- else
- {
- builder.add(creatorDN.toString());
- }
- addOperation.setAttribute(getCreatorsNameAttributeType(), builder.toAttributeList());
// Create the attribute list for the createTimestamp attribute.
- List<Attribute> timeList = Attributes.createAsList(
- getCreateTimestampAttributeType(), OP_ATTR_CREATE_TIMESTAMP, getGMTTime());
- addOperation.setAttribute(getCreateTimestampAttributeType(), timeList);
+ if (!isSuppliedUnderRelaxRules(addOperation, getCreateTimestampAttributeType()))
+ {
+ List<Attribute> timeList = Attributes.createAsList(
+ getCreateTimestampAttributeType(), OP_ATTR_CREATE_TIMESTAMP, getGMTTime());
+ addOperation.setAttribute(getCreateTimestampAttributeType(), timeList);
+ }
// We shouldn't ever need to return a non-success result.
return PluginResult.PreOperation.continueOperationProcessing();
@@ -148,49 +157,55 @@
doPreOperation(PreOperationModifyOperation modifyOperation)
{
// Create the modifiersName attribute.
- AttributeBuilder builder = new AttributeBuilder(getModifiersNameAttributeType());
- DN modifierDN = modifyOperation.getAuthorizationDN();
- if (modifierDN == null)
+ if (!isSuppliedUnderRelaxRules(modifyOperation, getModifiersNameAttributeType()))
{
- // This must mean that the operation was performed anonymously.
- // Even so, we still need to update the modifiersName attribute.
- builder.add(ByteString.empty());
- }
- else
- {
- builder.add(modifierDN.toString());
- }
- Attribute nameAttr = builder.toAttribute();
- try
- {
- modifyOperation.addModification(new Modification(ModificationType.REPLACE,
- nameAttr, true));
- }
- catch (DirectoryException de)
- {
- logger.traceException(de);
+ AttributeBuilder builder = new AttributeBuilder(getModifiersNameAttributeType());
+ DN modifierDN = modifyOperation.getAuthorizationDN();
+ if (modifierDN == null)
+ {
+ // This must mean that the operation was performed anonymously.
+ // Even so, we still need to update the modifiersName attribute.
+ builder.add(ByteString.empty());
+ }
+ else
+ {
+ builder.add(modifierDN.toString());
+ }
+ Attribute nameAttr = builder.toAttribute();
+ try
+ {
+ modifyOperation.addModification(new Modification(ModificationType.REPLACE,
+ nameAttr, true));
+ }
+ catch (DirectoryException de)
+ {
+ logger.traceException(de);
- // This should never happen.
- return PluginResult.PreOperation.stopProcessing(
- DirectoryConfig.getServerErrorResultCode(), de.getMessageObject());
+ // This should never happen.
+ return PluginResult.PreOperation.stopProcessing(
+ DirectoryConfig.getServerErrorResultCode(), de.getMessageObject());
+ }
}
// Create the modifyTimestamp attribute.
- Attribute timeAttr = Attributes.create(getModifyTimestampAttributeType(),
- OP_ATTR_MODIFY_TIMESTAMP, getGMTTime());
- try
+ if (!isSuppliedUnderRelaxRules(modifyOperation, getModifyTimestampAttributeType()))
{
- modifyOperation.addModification(new Modification(ModificationType.REPLACE,
- timeAttr, true));
- }
- catch (DirectoryException de)
- {
- logger.traceException(de);
+ Attribute timeAttr = Attributes.create(getModifyTimestampAttributeType(),
+ OP_ATTR_MODIFY_TIMESTAMP, getGMTTime());
+ try
+ {
+ modifyOperation.addModification(new Modification(ModificationType.REPLACE,
+ timeAttr, true));
+ }
+ catch (DirectoryException de)
+ {
+ logger.traceException(de);
- // This should never happen.
- return PluginResult.PreOperation.stopProcessing(
- DirectoryConfig.getServerErrorResultCode(), de.getMessageObject());
+ // This should never happen.
+ return PluginResult.PreOperation.stopProcessing(
+ DirectoryConfig.getServerErrorResultCode(), de.getMessageObject());
+ }
}
@@ -198,6 +213,36 @@
return PluginResult.PreOperation.continueOperationProcessing();
}
+ /**
+ * Indicates whether a client relaxing the rules supplies the provided attribute in the entry it
+ * adds: such a value is kept, the way it is kept when the change is replayed on another replica.
+ */
+ private static boolean isSuppliedUnderRelaxRules(PreOperationAddOperation addOperation, AttributeType type)
+ {
+ return LocalBackendWorkflowElement.isRelaxRulesRequested(addOperation)
+ && addOperation.getOperationalAttributes().containsKey(type);
+ }
+
+ /**
+ * Indicates whether a client relaxing the rules modifies the provided attribute: such a value is
+ * kept, the way it is kept when the change is replayed on another replica.
+ */
+ private static boolean isSuppliedUnderRelaxRules(PreOperationModifyOperation modifyOperation, AttributeType type)
+ {
+ if (!LocalBackendWorkflowElement.isRelaxRulesRequested(modifyOperation))
+ {
+ return false;
+ }
+ for (Modification m : modifyOperation.getModifications())
+ {
+ if (m.getAttribute().getAttributeDescription().getAttributeType().equals(type))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
--
Gitblit v1.10.0