Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2016 ForgeRock AS.
* Portions copyright 2011 profiq s.r.o.
* Portions copyright 2026 3A Systems, LLC.
*/
package org.opends.server.plugins;

Expand Down Expand Up @@ -991,10 +992,9 @@ public PluginResult.PreOperation doPreOperation(
}

final List<Modification> mods = modifyOperation.getModifications();
final Entry entry = modifyOperation.getModifiedEntry();

/* Make sure the entry belongs to one of the configured naming contexts. */
DN entryDN = entry.getName();
DN entryDN = modifyOperation.getEntryDN();
DN entryBaseDN = getEntryBaseDN(entryDN);
if (entryBaseDN == null)
{
Expand All @@ -1009,14 +1009,35 @@ public PluginResult.PreOperation doPreOperation(
if (modType != ModificationType.ADD
&& modType != ModificationType.REPLACE)
{
break;
continue;
}

Attribute modifiedAttribute = entry.getAttribute(mod.getAttribute().getAttributeDescription());
if (modifiedAttribute != null)
Attribute modifiedAttribute = mod.getAttribute();
if (modifiedAttribute != null && !modifiedAttribute.isEmpty())
{
// Only enforce referential integrity on attributes that this plugin is configured to manage.
final AttributeType modifiedAttrType = modifiedAttribute.getAttributeDescription().getAttributeType();
boolean isManagedAttributeType = false;
if (modifiedAttrType != null && attributeTypes != null)
{
for (AttributeType configuredType : attributeTypes)
{
if (modifiedAttrType.equals(configuredType)
|| modifiedAttrType.isSubTypeOf(configuredType))
{
isManagedAttributeType = true;
break;
}
}
}

if (!isManagedAttributeType)
{
// Skip integrity checks for attributes not configured for this plugin.
continue;
}
PluginResult.PreOperation result =
isIntegrityMaintained(modifiedAttribute, entryDN, entryBaseDN);
isIntegrityMaintained(modifiedAttribute, entryDN, entryBaseDN);
if (result.getResultCode() != ResultCode.SUCCESS)
{
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions copyright 2011 profiq s.r.o.
* Portions Copyright 2014-2016 ForgeRock AS.
* Portions copyright 2026 3A Systems, LLC.
*/
package org.opends.server.plugins;

Expand Down Expand Up @@ -1829,4 +1830,60 @@ public void testEnforceIntegrityModifyGroupAddMemberNC() throws Exception
"member", "uid=user.1,ou=people,ou=dept,o=test");
assertEquals(modOperation.getResultCode(), ResultCode.SUCCESS);
}

@Test
public void testEnforceIntegrityModifyGroupAddMissingUniqueMember() 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, "uniquemember");
addAttrEntry(configDN, dsConfigAttrFiltMapping,
"uniquemember:(objectclass=person)");
replaceAttrEntry(configDN, "ds-cfg-enabled", "true");

ModifyOperation modOperation = addAttrEntry(DN.valueOf(ugroup),
"uniquemember", "uid=user.100,ou=people,ou=dept,dc=example,dc=com");
assertEquals(modOperation.getResultCode(), ResultCode.CONSTRAINT_VIOLATION);
}

@Test
public void testEnforceIntegrityModifyGroupAddMissingUniqueMemberWithPriorDelete() throws Exception
{
// Configure the plugin in the same way as for the single-ADD test.
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, "uniquemember");
addAttrEntry(configDN, dsConfigAttrFiltMapping,
"uniquemember:(objectclass=person)");
replaceAttrEntry(configDN, "ds-cfg-enabled", "true");

// Ensure 'description' exists on ugroup so the DELETE modification succeeds.
addAttrEntry(DN.valueOf(ugroup), "description", "test description");
// Build a modify request with a non-ADD/REPLACE modification first,
// followed by an ADD of a uniquemember referencing a missing DN.
final ModifyRequest modifyRequest = Requests.newModifyRequest(DN.valueOf(ugroup));
modifyRequest.addModification(DELETE, "description");
modifyRequest.addModification(ADD, "uniquemember",
"uid=user.100,ou=people,ou=dept,dc=example,dc=com");

final InternalClientConnection connection = getRootConnection();
final ModifyOperation multiModOperation = connection.processModify(modifyRequest);
assertEquals(multiModOperation.getResultCode(), ResultCode.CONSTRAINT_VIOLATION);
}
}
Loading