Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
information: "Portions copyright [year] [name of copyright owner]".

Copyright 2017 ForgeRock AS.
Portions Copyright 2024 3A Systems LLC.
Portions Copyright 2024-2026 3A Systems, LLC.
////

:figure-caption!:
Expand Down Expand Up @@ -539,6 +539,6 @@ member: uid=tmorris,ou=People,dc=example,dc=com
----
By default, the referential integrity plugin is configured to manage `member` and `uniqueMember` attributes. These attributes take values that are DNs, and are indexed for equality by default for the default backend. Before you add an additional attribute to manage, make sure that it has DN syntax and that it is indexed for equality. OpenDJ directory server requires that the attribute be indexed because an unindexed search for integrity would potentially consume too many of the server's resources. Attribute syntax is explained in xref:../admin-guide/chap-schema.adoc#chap-schema["Managing Schema"] in the __Administration Guide__. For instructions on indexing attributes, see xref:../admin-guide/chap-indexing.adoc#configure-indexes["Configuring and Rebuilding Indexes"] in the __Administration Guide__.

You can also configure the referential integrity plugin to check that new entries added to groups actually exist in the directory by setting the `check-references` property to `true`. You can specify additional criteria once you have activated the check. To ensure that entries added must match a filter, set the `check-references-filter-criteria` to identify the attribute and the filter. For example, you can specify that group members must be person entries by setting `check-references-filter-criteria` to `member:(objectclass=person)`. To ensure that entries must be located in the same naming context, set `check-references-scope-criteria` to `naming-context`.
You can also configure the referential integrity plugin to check that new entries added to groups actually exist in the directory by setting the `check-references` property to `true`. You can specify additional criteria once you have activated the check. To ensure that entries added must match a filter, set the `check-references-filter-criteria` to identify the attribute and the filter. For example, you can specify that group members must be person entries by setting `check-references-filter-criteria` to `member:(objectclass=person)`. To ensure that entries must be located in the same naming context, set `check-references-scope-criteria` to `naming-context`. The check runs when entries are added and modified, so the plugin must be registered for the `preOperationAdd` and `preOperationModify` plugin types, as the default configuration is. When the plugin is enabled, OpenDJ refuses to set `check-references` to `true` if `plugin-type` lacks either of them, and it refuses to enable a plugin configured that way. A plugin already configured that way when the server starts is loaded with a warning, and it does not check references until the types are added. Plugin types take effect when the plugin is enabled, so add them before enabling the plugin, or disable and re-enable it afterwards.


2 changes: 2 additions & 0 deletions opendj-server-legacy/resource/config/config.ldif
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,8 @@ ds-cfg-plugin-type: postOperationDelete
ds-cfg-plugin-type: postOperationModifyDN
ds-cfg-plugin-type: subordinateModifyDN
ds-cfg-plugin-type: subordinateDelete
ds-cfg-plugin-type: preOperationAdd
ds-cfg-plugin-type: preOperationModify
ds-cfg-attribute-type: member
ds-cfg-attribute-type: uniqueMember
ds-cfg-invoke-for-internal-operations: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -105,6 +106,9 @@ public class ReferentialIntegrityPlugin
{
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();

/** The plugin types {@code check-references} needs: the references are checked in these hooks. */
private static final Set<PluginCfgDefn.PluginType> CHECK_REFERENCES_PLUGIN_TYPES = Collections.unmodifiableSet(
EnumSet.of(PluginCfgDefn.PluginType.PREOPERATIONADD, PluginCfgDefn.PluginType.PREOPERATIONMODIFY));


/** Current plugin configuration. */
Expand Down Expand Up @@ -169,11 +173,19 @@ public final void initializePlugin(Set<PluginType> pluginTypes,
pluginCfg.addReferentialIntegrityChangeListener(this);
LinkedList<LocalizableMessage> unacceptableReasons = new LinkedList<>();

if (!isConfigurationAcceptable(pluginCfg, unacceptableReasons))
if (!isConfigurationAcceptableIgnoringCheckReferencesPluginTypes(pluginCfg, unacceptableReasons))
{
throw new ConfigException(unacceptableReasons.getFirst());
}

// Enabling the plugin or changing its configuration is refused without these types, but a configuration
// already stored without them (the entry shipped before issue #1118) is loaded with a warning: refusing
// it would also stop the delete and modify DN clean-up, which does not need them.
for (PluginCfgDefn.PluginType t : getMissingCheckReferencesPluginTypes(pluginCfg))
{
logger.warn(WARN_PLUGIN_REFERENT_CHECK_REFERENCES_WITHOUT_PLUGIN_TYPE.get(pluginCfg.dn(), t, t));
}

applyConfigurationChange(pluginCfg);

// Set up log file. Note: it is not allowed to change once the plugin is active.
Expand Down Expand Up @@ -255,9 +267,39 @@ public ConfigChangeResult applyConfigurationChange(
public boolean isConfigurationAcceptable(PluginCfg configuration,
List<LocalizableMessage> unacceptableReasons)
{
boolean isAcceptable = true;
ReferentialIntegrityPluginCfg pluginCfg =
(ReferentialIntegrityPluginCfg) configuration;
boolean isAcceptable = isConfigurationAcceptableIgnoringCheckReferencesPluginTypes(pluginCfg, unacceptableReasons);

for (PluginCfgDefn.PluginType t : getMissingCheckReferencesPluginTypes(pluginCfg))
{
isAcceptable = false;
unacceptableReasons.add(ERR_PLUGIN_REFERENT_CHECK_REFERENCES_WITHOUT_PLUGIN_TYPE.get(t, t));
}
return isAcceptable;
}

/**
* Returns the plugin types {@code check-references} needs that the configuration does not list. The references
* are checked in the pre-operation add and modify hooks, which the plugin manager only calls for the plugin types
* listed in the configuration.
*/
private static Set<PluginCfgDefn.PluginType> getMissingCheckReferencesPluginTypes(
ReferentialIntegrityPluginCfg pluginCfg)
{
if (!pluginCfg.isCheckReferences())
{
return Collections.emptySet();
}
Set<PluginCfgDefn.PluginType> missing = EnumSet.copyOf(CHECK_REFERENCES_PLUGIN_TYPES);
missing.removeAll(pluginCfg.getPluginType());
return missing;
}

private boolean isConfigurationAcceptableIgnoringCheckReferencesPluginTypes(
ReferentialIntegrityPluginCfg pluginCfg, List<LocalizableMessage> unacceptableReasons)
{
boolean isAcceptable = true;

for (PluginCfgDefn.PluginType t : pluginCfg.getPluginType())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ public final class Upgrade
"cn: End Transaction",
"ds-cfg-java-class: org.opends.server.extensions.EndTransactionExtendedOperation",
"ds-cfg-enabled: true" };
static final String REFERENTIAL_INTEGRITY_PLUGIN_FILTER =
"(objectClass=ds-cfg-referential-integrity-plugin)";
static final String[] ADD_REFERENTIAL_INTEGRITY_PRE_OPERATION_PLUGIN_TYPES = {
"add: ds-cfg-plugin-type",
"ds-cfg-plugin-type: preOperationAdd",
"ds-cfg-plugin-type: preOperationModify" };

static
{
Expand Down Expand Up @@ -638,6 +644,16 @@ public String toString() {
START_TRANSACTION_HANDLER_ENTRY),
addConfigEntry(END_TRANSACTION_HANDLER_ENTRY));

/* See issue #1118: the shipped Referential Integrity plugin entry lacked the pre-operation plugin
* types that check-references runs in, so turning check-references on checked nothing. The plugin
* now refuses check-references without them, so every referential integrity plugin entry gets them:
* the add is permissive, and the upgrade schema matches plugin types ignoring case, so a type an
* administrator already added is not added a second time. */
register("5.2.0",
modifyConfigEntry(INFO_UPGRADE_TASK_ADD_REFERENTIAL_INTEGRITY_PRE_OPERATION_PLUGIN_TYPES.get(),
REFERENTIAL_INTEGRITY_PLUGIN_FILTER,
ADD_REFERENTIAL_INTEGRITY_PRE_OPERATION_PLUGIN_TYPES));

/*
* See issue #746. Builds before #661 (fixed in 5.1.2) shipped a duplicate
* org.openidentityplatform.opendj.opendj-server-legacy.jar alongside opendj.jar in lib/.
Expand Down Expand Up @@ -763,7 +779,7 @@ private static UpgradeTask convertJEBackendsToPDBBackends(final String objectCla
* @return A list containing all the tasks which are required in order to upgrade
* from {@code fromVersion} to {@code toVersion}.
*/
private static List<UpgradeTask> getUpgradeTasks(final BuildVersion fromVersion, final BuildVersion toVersion)
static List<UpgradeTask> getUpgradeTasks(final BuildVersion fromVersion, final BuildVersion toVersion)
{
final List<UpgradeTask> tasks = new LinkedList<>();
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,12 @@ private static Schema getUpgradeSchema()
+ " EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
+ " X-ORIGIN 'OpenDS Directory Server' )", false);

// Adds ds-cfg-plugin-type / ignore match syntax: dsconfig writes plugin types in lower case,
// while config.ldif spells them in camel case (issue #1118)
sb.addAttributeType("( 1.3.6.1.4.1.26027.1.1.54 NAME 'ds-cfg-plugin-type'"
+ " EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15"
+ " X-ORIGIN 'OpenDS Directory Server' )", false);

return sb.toSchema().asNonStrictSchema();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,3 +354,13 @@ ERR_PLUGIN_REFERENT_NAMINGCONTEXT_MISMATCH_128=The entry referenced by the \
the configured naming contexts
ERR_PLUGIN_REFERENT_EXCEPTION_129=The opration could not be processed \
due to an unexpected exception: '%s'
ERR_PLUGIN_REFERENT_CHECK_REFERENCES_WITHOUT_PLUGIN_TYPE_131=The property \
'check-references' is set to true, but the property 'plugin-type' does not list \
'%s', so the references added by that operation would not be checked. Add '%s' to \
'plugin-type', then disable and re-enable the plugin, or set 'check-references' to false
WARN_PLUGIN_REFERENT_CHECK_REFERENCES_WITHOUT_PLUGIN_TYPE_132=The Referential \
Integrity plugin %s has 'check-references' set to true, but its property \
'plugin-type' does not list '%s', so the references added by that operation are \
not checked. The plugin is loaded and still removes the references to deleted and \
renamed entries. Add '%s' to 'plugin-type', then disable and re-enable the plugin, \
or set 'check-references' to false
Original file line number Diff line number Diff line change
Expand Up @@ -2738,3 +2738,5 @@ INFO_UPGRADE_TASK_ADD_SUBORDINATE_BASE_DN_TO_GLOBAL_CONFIG=Adding subordinate-ba
Global configuration
INFO_UPGRADE_TASK_ADD_TRANSACTION_EXTENDED_OPERATIONS=Adding configuration for LDAP transactions \
extended operation handlers (RFC 5805)
INFO_UPGRADE_TASK_ADD_REFERENTIAL_INTEGRITY_PRE_OPERATION_PLUGIN_TYPES=Adding the pre-operation add \
and modify plugin types to the referential integrity plugins
Loading
Loading