Repository navigation
[#1172] Refuse a second check-references-filter-criteria value for an attribute type, and enforce all the filters of a configuration that already has one - #1174
Conversation
maximthomas
left a comment
There was a problem hiding this comment.
praise: The fix closes the "last value wins" gap where it starts, and keeps stored configurations loading.
getDuplicateFilterCriteriagroups byAttributeType, so the name, the OID andmanager :all land on one key, andERR_PLUGIN_REFERENT_DUPLICATE_FILTER_CRITERIA_133names every value.testDuplicateFilterCriteriaAreAllEnforcedrefuses a manager that matches only the first filter, then one that matches only the second, so neither filter alone can pass for the AND.isConfigurationLoadableloads a stored duplicate configuration withWARN_PLUGIN_REFERENT_DUPLICATE_FILTER_CRITERIA_134, so the delete and modify DN clean-up keeps running after an upgrade.
question (non-blocking): Should set enabled:false be accepted on a plugin that was loaded at boot with duplicate filter criteria?
opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java:299-304, :468
initializePlugin registers the plugin's own change listener (:183). isConfigurationChangeAcceptable delegates to isConfigurationAcceptable, and its duplicate loop refuses whatever enabled says. ConfigurationHandler.replaceEntry (:620-628) asks every listener on the DN, so an operator who sees the 134 warning and runs dsconfig set-plugin-prop --set enabled:false gets ERR_CONFIG_FILE_MODIFY_REJECTED_BY_CHANGE_LISTENER. The disable only goes through if the same modify also drops a value. PluginConfigManager itself skips a disabled configuration. The PR body says changing the configuration is refused, but it does not say the disable is. The #1118 arm already behaves this way at BASE. Minor as it stands; Major if a disable was meant to stay possible. If it was, one change fixes both arms:
@Override
public boolean isConfigurationChangeAcceptable(
ReferentialIntegrityPluginCfg configuration,
List<LocalizableMessage> unacceptableReasons)
{
// A disabled plugin checks no references: let the disable through, as PluginConfigManager does.
return configuration.isEnabled()
? isConfigurationAcceptable(configuration, unacceptableReasons)
: isConfigurationLoadable(configuration, unacceptableReasons);
}Pin: initialise a plugin from duplicateFilterCriteriaEntry(first, second), then call isConfigurationChangeAcceptable on the same entry with ds-cfg-enabled: false. It returns false at this head and true with the change.
suggestion (non-blocking): No test pins that getDuplicateFilterCriteria groups values by attribute type.
opendj-server-legacy/src/main/java/org/opends/server/plugins/ReferentialIntegrityPlugin.java:323, :241
Each multi-value fixture names one type twice: the duplicateFilterCriteria provider, and validConfigs at ReferentialIntegrityPluginTestCase.java:532-533. Take a mutant that files every value under one key, or flags any configuration with size() > 1. It refuses the ordinary member:(…) + uniqueMember:(…) configuration, and all 75 cases stay green. An AND across types at :241 would survive the same way.
/** Issue #1172: filter criteria for two different attribute types are not duplicates. */
@Test
public void testFilterCriteriaForTwoAttributeTypesAreAcceptable() throws Exception
{
Entry e = TestCaseUtils.makeEntry(
"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: subordinateDelete",
"ds-cfg-plugin-type: preOperationAdd",
"ds-cfg-plugin-type: preOperationModify",
"ds-cfg-attribute-type: manager",
"ds-cfg-attribute-type: member",
"ds-cfg-base-dn: dc=example,dc=com",
"ds-cfg-check-references: true",
"ds-cfg-check-references-filter-criteria: manager:(employeeType=manager)",
"ds-cfg-check-references-filter-criteria: member:(objectclass=person)");
List<LocalizableMessage> reasons = new ArrayList<>();
boolean acceptable = new ReferentialIntegrityPlugin().isConfigurationAcceptable(
InitializationUtils.getConfiguration(ReferentialIntegrityPluginCfgDefn.getInstance(), e), reasons);
assertTrue(acceptable, reasons.toString());
}Pin: green at BASE and at this head, red under the single-key mutant.
question (non-blocking): Should the colon-in-filter validConfigs entry keep two member: values, now that #1172 refuses that shape?
opendj-server-legacy/src/test/java/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java:532-533
This entry comes from the stacked #1158 commit, and #1172 leaves it as it is. testInitializeWithValidConfigs loads it through isConfigurationLoadable, which logs message 134 and ANDs the filters. isConfigurationAcceptable refuses the same entry with message 133. So the case runs the legacy warning road, which testDuplicateFilterCriteriaIsLoadedWithWarning already covers, and not a clean load. No #1158 mutant survives, so this is about what the fixture means.
"ds-cfg-check-references-filter-criteria: member:(&(o=urn:example)(cn:dn:=x))"Pin: replace both lines with the one above. The case becomes a clean load, and it still covers a colon inside the filter.
issue (non-blocking): The new Developer's Guide sentence says OpenDJ refuses a second value for the same attribute. That is not true while the plugin is disabled.
opendj-doc-generated-ref/src/main/asciidoc/server-dev-guide/chap-groups.adoc:542
cn=Referential Integrity ships with ds-cfg-enabled: false. A disabled plugin has no instance and no listener of its own, and PluginConfigManager accepts any change to a disabled configuration. So the second value is stored, and the refusal only comes at set enabled:true. The check-references sentence in the same paragraph is already qualified with "When the plugin is enabled".
When the plugin is enabled, OpenDJ refuses a second value for the same attribute, and it refuses to enable a plugin configured that way. A configuration that already has one when the server starts is loaded with a warning and requires all of its filters.…d and every modification of a modify, not only the first (#1175) Fixes #1173 ## Problem With `check-references: true`, the Referential Integrity plugin checks references in its two `doPreOperation` hooks, and both returned after their first check: ```java if (result.getResultCode() != ResultCode.SUCCESS) { return result; } ``` A reference that passes yields `PluginResult.PreOperation.continueOperationProcessing()`, whose result code is `null`, not `SUCCESS`, so the condition also held for a check that passed. As a result: - **add**: only the first managed attribute type was checked. An entry that did not hold that attribute had none of its references checked, because an empty attribute list passes too. - **modify**: only the first ADD or REPLACE modification of a managed attribute was checked, and the ones after it were not. ## Fix Both hooks now return early only when processing must stop (`!result.continueProcessing()`). `isIntegrityMaintained(List<Attribute>, …)` already worked that way: it compares with `continueOperationProcessing()`. ## Tests `ReferentialIntegrityPluginTestCase`, with `check-references` on `manager` and `seeAlso` below `dc=example,dc=com`, and the data provider `missingReferenceNextToAnother`: a missing reference in one attribute, next to a valid reference in the other attribute or alone. Both attributes take both places, because the order in which the plugin checks attribute types is an implementation detail. - `testEnforceIntegrityAddChecksEveryAttributeType`: adding an entry with a missing reference in either attribute is refused with `CONSTRAINT_VIOLATION`. - `testEnforceIntegrityModifyChecksEveryModification`: a modify request whose second modification adds a missing reference is refused. Its first modification replaces the other managed attribute with a valid reference, or, in the rows without one, replaces `description`, which the plugin does not manage. The plugin configuration these tests share moved into a helper, `enableCheckReferences`. Without the fix, 4 of the 69 tests fail with `expected [Constraint Violation] but found [Success]`: - add `[seeAlso, manager]` and `[seeAlso, null]`, because the plugin checks `manager` first; - modify `[manager, seeAlso]` and `[seeAlso, manager]`. The two modify rows without a valid reference passed even before the fix, since an unmanaged first modification was already skipped; they guard that case. With the fix the class passes 69/69. Found while working on #1172 (PR #1174), whose test has to check `continueProcessing()` for the same reason.
…riteria value for an attribute type, and enforce all the filters of a configuration that already has one Enabling the Referential Integrity plugin or changing its configuration is refused when two check-references-filter-criteria values name the same attribute type, by the same spelling, by another name or the OID of the type, or with a space before the colon. Only one of them used to be enforced: the one whose value sorts last. A configuration stored with such values is still loaded when the server starts, with a warning, and a reference then has to match all of their filters.
… with a warning be disabled A plugin loaded at startup with two check-references-filter-criteria values for one attribute type, or with check-references but without the pre-operation plugin types (OpenIdentityPlatform#1118), refused to be disabled: its own change listener checked the new configuration as if the plugin stayed enabled. A disabled configuration is now only checked for what loading needs, as the plugin manager does; enabling it again is still refused. The guide says that the second value is refused only while the plugin is enabled. New tests pin that filter criteria for two attribute types are not duplicates, and that each filter applies to its own attribute type only.
534d03e to
cb3d276
Compare
|
@maximthomas all four points are taken in cb3d276. #1167 is merged, so the branch is now rebased onto master 6e6cbc7 and carries only the #1172 commits. question: disabling a plugin loaded with a warning: a disable was meant to stay possible, so this was a bug, in the #1118 arm too. suggestion: grouping by attribute type: added as question: the colon-in-filter issue: the guide sentence: replaced with your wording. Run locally:
|
maximthomas
left a comment
There was a problem hiding this comment.
praise: The round-1 feedback is resolved in the code, the documentation and the tests.
isConfigurationChangeAcceptablenow branches onisEnabled(). A plugin loaded with the #1118 or #1172 warning can be disabled without first fixing its configuration, and enabling that same configuration is still refused (testDuplicateFilterCriteriaCanBeDisabled,testCheckReferencesWithoutPreOperationTypesCanBeDisabled).chap-groups.adoc:542now limits the refusal to "When the plugin is enabled", which is when PluginConfigManager actually checks it.testDuplicateFilterCriteriaAreAllEnforcedhas two "matches only one" steps, so neither filter alone can be the one enforced
Fixes #1172
Problem
ReferentialIntegrityPlugin.applyConfigurationChangestored eachcheck-references-filter-criteriavalue withnewAttrFiltMap.put(attrType, filter), so a later value for the same attribute type overwrote an earlier one, while the validation checked each value on its own and accepted the configuration. Which filter was enforced depended on the sort order of the normalized values: the one that sorts last won. Affected pairs: the same spelling (manager:(a)+manager:(b)), a name and an OID or alias of the same type (manager+0.9.2342.19200300.100.1.10), and, since #1158, a space before the colon (manager:(a)+manager :(b)).Fix
The approach follows #1118 in the same plugin: refuse what is being configured now, load what is already stored.
AttributeType, so by OID): newERR_PLUGIN_REFERENT_DUPLICATE_FILTER_CRITERIA_133, one reason per attribute type, naming the attribute and all of its values.WARN_PLUGIN_REFERENT_DUPLICATE_FILTER_CRITERIA_134, and the filters of one attribute type are combined in an AND filter: a reference has to match all of them. Refusing it would stop the plugin from loading, including the delete and modify DN clean-up; keeping "last one wins" would keep an arbitrary choice.PluginConfigManagerdoes, and enabling it again is still refused.isConfigurationAcceptableIgnoringCheckReferencesPluginTypesis renamedisConfigurationLoadable, since it now lets through both the The shipped Referential Integrity plugin entry lacks the preOperationAdd and preOperationModify plugin types, so check-references checks nothing #1118 and the Referential integrity: two check-references-filter-criteria values for the same attribute type are both accepted, but only one is enforced #1172 cases.chap-groups.adoc) say that an attribute has one filter, that several criteria go into one AND filter, and that a second value is refused while the plugin is enabled. The XML has no(&…)example: the description goes into the generated Javadoc ofopendj-config, where&fails doclint (bad HTML entity).Message ordinals 133–134 in
plugin.properties: no other open PR changes that file.Tests
ReferentialIntegrityPluginTestCase, each for the three pairs above (manager:(employeeType=manager)with(description=approved)asmanager:, as the OID, and asmanager :):testDuplicateFilterCriteriaIsNotAcceptable:isConfigurationAcceptableis false, with one reason namingmanagerand both values.testDuplicateFilterCriteriaIsLoadedWithWarning:initializePluginsucceeds and logs message 134 with the DN, the attribute and both values.testDuplicateFilterCriteriaAreAllEnforced: a plugin loaded with both values refuses an employee whose manager matches only(employeeType=manager), refuses one whose manager matches only(description=approved), and accepts one whose manager matches both. The two "only one" steps make sure that neither filter alone is the one enforced.testDuplicateFilterCriteriaIsRejected: on the running plugin, addingmanager :(description=approved)next tomanager:(employeeType=manager)is refused, and the reason names both values.testDuplicateFilterCriteriaCanBeDisabled, andtestCheckReferencesWithoutPreOperationTypesCanBeDisabledfor the The shipped Referential Integrity plugin entry lacks the preOperationAdd and preOperationModify plugin types, so check-references checks nothing #1118 configurations: a plugin loaded with the warning accepts its configuration withenabled: false, and still refuses it withenabled: true.testFilterCriteriaForTwoAttributeTypesAreNotDuplicates:manager:(…)withmember:(…)is acceptable, and a manager that matches only themanagerfilter is accepted.The #1158 case of
validConfigswith a colon inside the filter now has one value,member:(&(o=urn:example)(cn:dn:=x)), so that it stays a clean load.Without the fix (on #1167) the 10 cases of the first round fail and the other 65 pass. With it the class passes 82/82. The 6 disable cases fail with the first round's
isConfigurationChangeAcceptable, andtestFilterCriteriaForTwoAttributeTypesAreNotDuplicatesfails when every value is grouped under the first attribute type, whether in the duplicate check or in the filters that are enforced.Related
While writing the enforcement test I found that both
doPreOperationhooks stop after their first check, because a passing check's result code isnullrather thanSUCCESS; that is why the test checkscontinueProcessing(). Not changed here: tracked in #1173.