From 3b360568a7063c65fde7d905debe5519577b10d1 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Mon, 05 Oct 2026 12:40:26 +0000
Subject: [PATCH] [#1158] Split a check-references-filter-criteria value at its first colon, so the filter can contain one (#1167)
---
opendj-server-legacy/src/test/java/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java | 77 ++++++++++++++++++++++++++++++++++++++
opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java | 27 ++++++++++---
2 files changed, 97 insertions(+), 7 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java b/opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java
index 34ac476..ddf54f5 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java
@@ -221,9 +221,9 @@
for (String attrFilt : newConfiguration.getCheckReferencesFilterCriteria())
{
- int sepInd = attrFilt.lastIndexOf(":");
- String attr = attrFilt.substring(0, sepInd);
- String filtStr = attrFilt.substring(sepInd + 1);
+ String[] attrAndFilter = splitFilterCriteria(attrFilt);
+ String attr = attrAndFilter[0];
+ String filtStr = attrAndFilter[1];
AttributeType attrType = DirectoryServer.getInstance().getServerContext().getSchema().getAttributeType(attr);
try
@@ -365,9 +365,9 @@
for (String attrFilt : pluginCfg.getCheckReferencesFilterCriteria())
{
- int sepInd = attrFilt.lastIndexOf(":");
- String attr = attrFilt.substring(0, sepInd).trim();
- String filtStr = attrFilt.substring(sepInd + 1).trim();
+ String[] attrAndFilter = splitFilterCriteria(attrFilt);
+ String attr = attrAndFilter[0];
+ String filtStr = attrAndFilter[1];
/* TODO: strip the ;options part? */
@@ -398,6 +398,21 @@
return isAcceptable;
}
+ /**
+ * Splits a check-references-filter-criteria value ({@code attribute:filter}) at its first colon: an attribute
+ * description cannot contain one, but the filter that follows it can, as in {@code (o=urn:example)} or
+ * {@code (cn:dn:=x)}. The property syntax guarantees that the value has a colon after a non-empty attribute.
+ *
+ * @param attrFilt
+ * The check-references-filter-criteria value.
+ * @return The attribute and the filter, both trimmed.
+ */
+ private static String[] splitFilterCriteria(String attrFilt)
+ {
+ int sepInd = attrFilt.indexOf(':');
+ return new String[] { attrFilt.substring(0, sepInd).trim(), attrFilt.substring(sepInd + 1).trim() };
+ }
+
@Override
public boolean isConfigurationChangeAcceptable(
ReferentialIntegrityPluginCfg configuration,
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java
index 379b3ae..be66040 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java
@@ -508,7 +508,26 @@
"ds-cfg-plugin-type: preOperationModify",
"ds-cfg-attribute-type: member",
"ds-cfg-check-references: false",
- "ds-cfg-check-references-filter-criteria: member:(objectclass=person)"
+ "ds-cfg-check-references-filter-criteria: member:(objectclass=person)",
+ "",
+ // check-references enabled, filters that contain a colon
+ "dn: cn=Referential Integrity,cn=Plugins,cn=config",
+ "objectClass: top",
+ "objectClass: ds-cfg-plugin",
+ "objectClass: ds-cfg-referential-integrity-plugin",
+ "cn: Referential Integrity",
+ "ds-cfg-java-class: org.opends.server.plugins.ReferentialIntegrityPlugin",
+ "ds-cfg-enabled: true",
+ "ds-cfg-plugin-type: postOperationDelete",
+ "ds-cfg-plugin-type: postOperationModifyDN",
+ "ds-cfg-plugin-type: subordinateModifyDN",
+ "ds-cfg-plugin-type: preOperationAdd",
+ "ds-cfg-plugin-type: preOperationModify",
+ "ds-cfg-attribute-type: member",
+ "ds-cfg-base-dn: o=test",
+ "ds-cfg-check-references: true",
+ "ds-cfg-check-references-filter-criteria: member:(o=urn:example)",
+ "ds-cfg-check-references-filter-criteria: member:(cn:dn:=x)"
);
Object[][] array = new Object[entries.size()][1];
for (int i=0; i < array.length; i++)
@@ -1639,6 +1658,62 @@
}
/**
+ * Filter criteria whose filter contains a colon, or whose attribute is followed by a space. Each filter matches the
+ * manager entry only once its description is {@code urn:example:manager}.
+ */
+ @DataProvider
+ public Object[][] filterCriteriaWithColonInFilter()
+ {
+ return new Object[][] {
+ { "manager:(description=urn:example:manager)" },
+ { "manager:(description:caseExactMatch:=urn:example:manager)" },
+ { "manager :(description=*manager)" },
+ };
+ }
+
+ /**
+ * A check-references-filter-criteria value is split at its first colon, and both of its parts are trimmed: the
+ * filter that follows the attribute can contain colons of its own, and is enforced as written.
+ */
+ @Test(dataProvider = "filterCriteriaWithColonInFilter")
+ public void testEnforceIntegrityWithColonInFilter(String filterCriteria) throws Exception
+ {
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "false");
+ replaceAttrEntry(configDN, dsConfigPluginType,
+ "postoperationdelete",
+ "postoperationmodifydn",
+ "subordinatemodifydn",
+ "subordinatedelete",
+ "preoperationadd",
+ "preoperationmodify");
+ addAttrEntry(configDN, dsConfigBaseDN, "dc=example,dc=com");
+ replaceAttrEntry(configDN, dsConfigEnforceIntegrity, "true");
+ replaceAttrEntry(configDN, dsConfigAttrType, "manager");
+ assertEquals(addAttrEntry(configDN, dsConfigAttrFiltMapping, filterCriteria).getResultCode(), ResultCode.SUCCESS);
+ assertEquals(replaceAttrEntry(configDN, "ds-cfg-enabled", "true").getResultCode(), ResultCode.SUCCESS);
+
+ String manager = "uid=manager,ou=people,ou=dept,dc=example,dc=com";
+ addEntry(manager);
+ Entry employee = TestCaseUtils.makeEntry(
+ "dn: uid=employee,ou=people,ou=dept,dc=example,dc=com",
+ "objectclass: top",
+ "objectclass: person",
+ "objectclass: organizationalperson",
+ "objectclass: inetorgperson",
+ "uid: employee",
+ "cn: employee",
+ "sn: employee",
+ "givenname: employee",
+ "manager: " + manager);
+
+ assertEquals(getRootConnection().processAdd(employee).getResultCode(), ResultCode.CONSTRAINT_VIOLATION);
+
+ assertEquals(addAttrEntry(DN.valueOf(manager), "description", "urn:example:manager").getResultCode(),
+ ResultCode.SUCCESS);
+ assertEquals(getRootConnection().processAdd(employee).getResultCode(), ResultCode.SUCCESS);
+ }
+
+ /**
* Test case:
* - integrity is enforced on the attribute 'manager'
* - value of the 'manager' attribute should match the filter:
--
Gitblit v1.10.0