From 9601c91e13687792aba32c9361213c709cd312fc Mon Sep 17 00:00:00 2001
From: Nemanja Lukic <nemanja.lukic@forgerock.com>
Date: Thu, 24 Nov 2011 14:35:30 +0000
Subject: [PATCH] Patch for OPENDJ-221
---
opendj-sdk/opends/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java | 505 ++++++++++++++---
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java | 993 +++++++++++++++++++++++++++++++++++
opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/ReferentialIntegrityPluginConfiguration.xml | 93 +++
opendj-sdk/opends/src/admin/messages/ReferentialIntegrityPluginCfgDefn.properties | 9
opendj-sdk/opends/src/messages/messages/plugin.properties | 16
opendj-sdk/opends/resource/schema/02-config.ldif | 19
6 files changed, 1,519 insertions(+), 116 deletions(-)
diff --git a/opendj-sdk/opends/resource/schema/02-config.ldif b/opendj-sdk/opends/resource/schema/02-config.ldif
index 5758ef8..c08368e 100644
--- a/opendj-sdk/opends/resource/schema/02-config.ldif
+++ b/opendj-sdk/opends/resource/schema/02-config.ldif
@@ -2717,6 +2717,20 @@
NAME 'ds-cfg-check-substrings'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.53
+ NAME 'ds-cfg-check-references'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
+ SINGLE-VALUE
+ X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.54
+ NAME 'ds-cfg-check-references-filter-criteria'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.55
+ NAME 'ds-cfg-check-references-scope-criteria'
+ SINGLE-VALUE
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ X-ORIGIN 'OpenDJ Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
NAME 'ds-cfg-access-control-handler'
SUP top
@@ -3917,7 +3931,10 @@
MUST ds-cfg-attribute-type
MAY ( ds-cfg-base-dn $
ds-cfg-update-interval $
- ds-cfg-log-file )
+ ds-cfg-log-file $
+ ds-cfg-check-references $
+ ds-cfg-check-references-filter-criteria $
+ ds-cfg-check-references-scope-criteria )
X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.120
NAME 'ds-cfg-smtp-account-status-notification-handler'
diff --git a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/ReferentialIntegrityPluginConfiguration.xml b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/ReferentialIntegrityPluginConfiguration.xml
index 1cf8344..9e33f6d 100644
--- a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/ReferentialIntegrityPluginConfiguration.xml
+++ b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/ReferentialIntegrityPluginConfiguration.xml
@@ -24,6 +24,7 @@
!
!
! Copyright 2007-2010 Sun Microsystems, Inc.
+ ! Portions copyright 2011 profiq s.r.o.
! -->
<adm:managed-object name="referential-integrity-plugin"
plural-name="referential-integrity-plugins"
@@ -68,6 +69,8 @@
<adm:value>postoperationmodifydn</adm:value>
<adm:value>subordinatemodifydn</adm:value>
<adm:value>subordinatedelete</adm:value>
+ <adm:value>preoperationadd</adm:value>
+ <adm:value>preoperationmodify</adm:value>
</adm:defined>
</adm:default-behavior>
</adm:property-override>
@@ -168,4 +171,94 @@
</ldap:attribute>
</adm:profile>
</adm:property>
+ <adm:property name="check-references">
+ <adm:synopsis>
+ Specifies whether or not reference attributes must refer to existing
+ entries.
+ </adm:synopsis>
+ <adm:description>
+ When this property is set to true, this plugin will ensure that any new
+ references added as part of an add or modify operation point to existing
+ entries, and that the referenced entries match the filter criteria for the
+ referencing attribute, if specified.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>false</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-check-references</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="check-references-filter-criteria"
+ multi-valued="true" mandatory="false">
+ <adm:synopsis>
+ Specifies additional filter criteria which will be enforced when checking
+ references.
+ </adm:synopsis>
+ <adm:description>
+ If a reference attribute has filter criteria defined then this plugin
+ will ensure that any new references added as part of an add or modify
+ operation refer to an existing entry which matches the specified filter.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:undefined />
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>^[^:]+:\\(.+\\)$</adm:regex>
+ <adm:usage>ATTRIBUTE:FILTER</adm:usage>
+ <adm:synopsis>An attribute-filter mapping.</adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-check-references-filter-criteria</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="check-references-scope-criteria">
+ <adm:synopsis>
+ Specifies whether or not referenced entries must reside within the same
+ naming context as the entry containing the reference.
+ </adm:synopsis>
+ <adm:description>
+ The reference scope will only be enforced when reference checking is
+ enabled.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>global</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:enumeration>
+ <adm:value name="global">
+ <adm:synopsis>
+ References may refer to existing entries located anywhere in the
+ Directory.
+ </adm:synopsis>
+ </adm:value>
+ <adm:value name="naming-context">
+ <adm:synopsis>
+ References must refer to existing entries located within the same
+ naming context.
+ </adm:synopsis>
+ </adm:value>
+ </adm:enumeration>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-check-references-scope-criteria</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
</adm:managed-object>
diff --git a/opendj-sdk/opends/src/admin/messages/ReferentialIntegrityPluginCfgDefn.properties b/opendj-sdk/opends/src/admin/messages/ReferentialIntegrityPluginCfgDefn.properties
index 9410d3a..274baa6 100644
--- a/opendj-sdk/opends/src/admin/messages/ReferentialIntegrityPluginCfgDefn.properties
+++ b/opendj-sdk/opends/src/admin/messages/ReferentialIntegrityPluginCfgDefn.properties
@@ -6,6 +6,15 @@
property.attribute-type.description=At least one attribute type must be specified, and the syntax of any attributes must be either a distinguished name (1.3.6.1.4.1.1466.115.121.1.12) or name and optional UID (1.3.6.1.4.1.1466.115.121.1.34).
property.base-dn.synopsis=Specifies the base DN that limits the scope within which referential integrity is maintained.
property.base-dn.default-behavior.alias.synopsis=Referential integrity is maintained in all public naming contexts.
+property.check-references.synopsis=Specifies whether or not reference attributes must refer to existing entries.
+property.check-references.description=When this property is set to true, this plugin will ensure that any new references added as part of an add or modify operation point to existing entries, and that the referenced entries match the filter criteria for the referencing attribute, if specified.
+property.check-references-filter-criteria.synopsis=Specifies additional filter criteria which will be enforced when checking references.
+property.check-references-filter-criteria.description=If a reference attribute has filter criteria defined then this plugin will ensure that any new references added as part of an add or modify operation refer to an existing entry which matches the specified filter.
+property.check-references-filter-criteria.syntax.string.pattern.synopsis=An attribute-filter mapping.
+property.check-references-scope-criteria.synopsis=Specifies whether or not referenced entries must reside within the same naming context as the entry containing the reference.
+property.check-references-scope-criteria.description=The reference scope will only be enforced when reference checking is enabled.
+property.check-references-scope-criteria.syntax.enumeration.value.global.synopsis=References may refer to existing entries located anywhere in the Directory.
+property.check-references-scope-criteria.syntax.enumeration.value.naming-context.synopsis=References must refer to existing entries located within the same naming context.
property.enabled.synopsis=Indicates whether the plug-in is enabled for use.
property.invoke-for-internal-operations.synopsis=Indicates whether the plug-in should be invoked for internal operations.
property.invoke-for-internal-operations.description=Any plug-in that can be invoked for internal operations must ensure that it does not create any new internal operatons that can cause the same plug-in to be re-invoked.
diff --git a/opendj-sdk/opends/src/messages/messages/plugin.properties b/opendj-sdk/opends/src/messages/messages/plugin.properties
index 7510d6a..5e8971c 100644
--- a/opendj-sdk/opends/src/messages/messages/plugin.properties
+++ b/opendj-sdk/opends/src/messages/messages/plugin.properties
@@ -436,3 +436,19 @@
already been defined in the configuration
SEVERE_ERR_PLUGIN_ATTR_CLEANUP_EQUAL_VALUES_123=The mapping '%s:%s' maps the \
attribute to itself
+SEVERE_ERR_PLUGIN_REFERENT_ATTR_NOT_LISTED_124=The property \
+ 'check-references-filter-criteria' specifies filtering criteria for attribute \
+ '%s', but this attribute is not listed in the 'attribute-type' property.
+SEVERE_ERR_PLUGIN_REFERENT_BAD_FILTER_125=The filtering criteria '%s' specified \
+ in property 'check-references-filter-criteria' is invalid because the filter \
+ could not be decoded: '%s'.
+SEVERE_ERR_PLUGIN_REFERENT_ENTRY_MISSING_126=The entry referenced by the value \
+ '%s' of the attribute '%s' in the entry '%s' does not exist in any of the configured \
+ naming contexts.
+SEVERE_ERR_PLUGIN_REFERENT_FILTER_MISMATCH_127=The entry referenced by the value \
+ '%s' of the attribute '%s' in the entry '%s' does not match the filter '%s'.
+SEVERE_ERR_PLUGIN_REFERENT_NAMINGCONTEXT_MISMATCH_128=The entry referenced by the \
+ value '%s' of the attribute '%s' in the entry '%s' does not belong to any of \
+ the configured naming contexts.
+SEVERE_ERR_PLUGIN_REFERENT_EXCEPTION_129=The opration could not be processed \
+ due to an unexpected exception: '%s'.
\ No newline at end of file
diff --git a/opendj-sdk/opends/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java b/opendj-sdk/opends/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java
index aab71ce..b83976f 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/plugins/ReferentialIntegrityPlugin.java
@@ -24,11 +24,15 @@
*
* Copyright 2008-2010 Sun Microsystems, Inc.
* Portions copyright 2011 ForgeRock AS.
+ * Portions copyright 2011 profiq s.r.o.
*/
package org.opends.server.plugins;
+import java.util.Iterator;
+import org.opends.server.types.operation.PreOperationAddOperation;
+import org.opends.server.types.operation.PreOperationModifyOperation;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
@@ -50,6 +54,8 @@
import org.opends.server.admin.std.server.PluginCfg;
import org.opends.server.admin.std.meta.PluginCfgDefn;
import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.meta.ReferentialIntegrityPluginCfgDefn
+ .CheckReferencesScopeCriteria;
import org.opends.server.api.Backend;
import org.opends.server.api.DirectoryThread;
import org.opends.server.api.ServerShutdownListener;
@@ -153,6 +159,12 @@
//when the plugin is in background processing mode.
private BufferedWriter writer;
+ /* Specifies the mapping between the attribute type (specified in the
+ * attributeTypes list) and the filter which the plugin should use
+ * to verify the integrity of the value of the given attribute.
+ */
+ private LinkedHashMap<AttributeType, SearchFilter> attrFiltMap =
+ new LinkedHashMap<AttributeType, SearchFilter>();
/**
@@ -163,64 +175,14 @@
throws ConfigException
{
pluginCfg.addReferentialIntegrityChangeListener(this);
- currentConfiguration = pluginCfg;
+ LinkedList<Message> unacceptableReasons = new LinkedList<Message>();
- for (PluginType t : pluginTypes)
+ if (!isConfigurationAcceptable(pluginCfg, unacceptableReasons))
{
- switch (t)
- {
- case POST_OPERATION_DELETE:
- case POST_OPERATION_MODIFY_DN:
- case SUBORDINATE_MODIFY_DN:
- case SUBORDINATE_DELETE:
- // These are acceptable.
- break;
-
- default:
- throw new
- ConfigException(ERR_PLUGIN_REFERENT_INVALID_PLUGIN_TYPE.get(
- t.toString()));
- }
+ throw new ConfigException(unacceptableReasons.getFirst());
}
- Set<DN> cfgBaseDNs = pluginCfg.getBaseDN();
- if ((cfgBaseDNs == null) || cfgBaseDNs.isEmpty())
- {
- cfgBaseDNs = DirectoryServer.getPublicNamingContexts().keySet();
- }
- else
- {
- baseDNs.addAll(cfgBaseDNs);
- }
-
- // Iterate through all of the defined attribute types and ensure that they
- // have acceptable syntaxes and that they are indexed for equality below all
- // base DNs.
- for (AttributeType type : pluginCfg.getAttributeType())
- {
- if (! isAttributeSyntaxValid(type))
- {
- throw new ConfigException(
- ERR_PLUGIN_REFERENT_INVALID_ATTRIBUTE_SYNTAX.get(
- type.getNameOrOID(),
- type.getSyntax().getSyntaxName()));
- }
-
- for (DN baseDN : cfgBaseDNs)
- {
- Backend b = DirectoryServer.getBackend(baseDN);
- if ((b != null) && (! b.isIndexed(type, IndexType.EQUALITY)))
- {
- throw new ConfigException(ERR_PLUGIN_REFERENT_ATTR_UNINDEXED.get(
- pluginCfg.dn().toString(),
- type.getNameOrOID(),
- b.getBackendID()));
- }
- }
-
- attributeTypes.add(type);
- }
-
+ applyConfigurationChange(pluginCfg);
// Set up log file. Note: it is not allowed to change once the plugin is
// active.
@@ -261,10 +223,42 @@
newAttributeTypes.add(type);
}
+ // Load the attribute-filter mapping
+
+ LinkedHashMap<AttributeType, SearchFilter> newAttrFiltMap =
+ new LinkedHashMap<AttributeType, SearchFilter>();
+
+ for (String attrFilt : newConfiguration.getCheckReferencesFilterCriteria())
+ {
+ int sepInd = attrFilt.lastIndexOf(":");
+ String attr = attrFilt.substring(0, sepInd);
+ String filtStr = attrFilt.substring(sepInd + 1);
+
+ AttributeType attrType =
+ DirectoryServer.getAttributeType(attr.toLowerCase());
+
+ try
+ {
+ SearchFilter filter =
+ SearchFilter.createFilterFromString(filtStr);
+ newAttrFiltMap.put(attrType, filter);
+ }
+ catch (DirectoryException de)
+ {
+ /* This should never happen because the filter has already
+ * been verified.
+ */
+ logError(de.getMessageObject());
+ }
+ }
+
//User is not allowed to change the logfile name, append a message that the
//server needs restarting for change to take effect.
+ // The first time the plugin is initialised the 'logFileName' is
+ // not initialised, so in order to verify if it is equal to the new
+ // log file name, we have to make sure the variable is not null.
String newLogFileName=newConfiguration.getLogFile();
- if(!logFileName.equals(newLogFileName))
+ if(logFileName != null && !logFileName.equals(newLogFileName))
{
adminActionRequired=true;
messages.add(
@@ -275,6 +269,7 @@
//Switch to the new lists.
baseDNs = newConfiguredBaseDNs;
attributeTypes = newAttributeTypes;
+ attrFiltMap = newAttrFiltMap;
//If the plugin is enabled and the interval has changed, process that
//change. The change might start or stop the background processing thread.
@@ -294,9 +289,109 @@
public boolean isConfigurationAcceptable(PluginCfg configuration,
List<Message> unacceptableReasons)
{
- ReferentialIntegrityPluginCfg cfg =
+ boolean isAcceptable = true;
+ ReferentialIntegrityPluginCfg pluginCfg =
(ReferentialIntegrityPluginCfg) configuration;
- return isConfigurationChangeAcceptable(cfg, unacceptableReasons);
+
+ for (PluginCfgDefn.PluginType t : pluginCfg.getPluginType())
+ {
+ switch (t)
+ {
+ case POSTOPERATIONDELETE:
+ case POSTOPERATIONMODIFYDN:
+ case SUBORDINATEMODIFYDN:
+ case SUBORDINATEDELETE:
+ case PREOPERATIONMODIFY:
+ case PREOPERATIONADD:
+ // These are acceptable.
+ break;
+
+ default:
+ isAcceptable = false;
+ unacceptableReasons.add(ERR_PLUGIN_REFERENT_INVALID_PLUGIN_TYPE.get(
+ t.toString()));
+ }
+ }
+
+ Set<DN> cfgBaseDNs = pluginCfg.getBaseDN();
+ if ((cfgBaseDNs == null) || cfgBaseDNs.isEmpty())
+ {
+ cfgBaseDNs = DirectoryServer.getPublicNamingContexts().keySet();
+ }
+
+ // Iterate through all of the defined attribute types and ensure that they
+ // have acceptable syntaxes and that they are indexed for equality below all
+ // base DNs.
+ Set<AttributeType> attributeTypes = pluginCfg.getAttributeType();
+ for (AttributeType type : attributeTypes)
+ {
+ if (! isAttributeSyntaxValid(type))
+ {
+ isAcceptable = false;
+ unacceptableReasons.add(
+ ERR_PLUGIN_REFERENT_INVALID_ATTRIBUTE_SYNTAX.get(
+ type.getNameOrOID(),
+ type.getSyntax().getSyntaxName()));
+ }
+
+ for (DN baseDN : cfgBaseDNs)
+ {
+ Backend b = DirectoryServer.getBackend(baseDN);
+ if ((b != null) && (!b.isIndexed(type, IndexType.EQUALITY)))
+ {
+ isAcceptable = false;
+ unacceptableReasons.add(ERR_PLUGIN_REFERENT_ATTR_UNINDEXED.get(
+ pluginCfg.dn().toString(),
+ type.getNameOrOID(),
+ b.getBackendID()));
+ }
+ }
+ }
+
+ /* Iterate through the attribute-filter mapping and verify that the
+ * map contains attributes listed in the attribute-type parameter
+ * and that the filter is valid.
+ */
+
+ for (String attrFilt : pluginCfg.getCheckReferencesFilterCriteria())
+ {
+ int sepInd = attrFilt.lastIndexOf(":");
+ String attr = attrFilt.substring(0, sepInd).trim();
+ String filtStr = attrFilt.substring(sepInd + 1).trim();
+
+ /* TODO: strip the ;options part? */
+
+ /* Get the attribute type for the given attribute. The attribute
+ * type has to be present in the attributeType list.
+ */
+
+ AttributeType attrType =
+ DirectoryServer.getAttributeType(attr.toLowerCase());
+
+ if (attrType == null || !attributeTypes.contains(attrType))
+ {
+ isAcceptable = false;
+ unacceptableReasons.add(
+ ERR_PLUGIN_REFERENT_ATTR_NOT_LISTED.get(attr));
+ }
+
+ /* Verify the filter.
+ */
+
+ try
+ {
+ SearchFilter.createFilterFromString(filtStr);
+ }
+ catch (DirectoryException de)
+ {
+ isAcceptable = false;
+ unacceptableReasons.add(
+ ERR_PLUGIN_REFERENT_BAD_FILTER.get(filtStr, de.getMessage()));
+ }
+
+ }
+
+ return isAcceptable;
}
@@ -307,61 +402,10 @@
ReferentialIntegrityPluginCfg configuration,
List<Message> unacceptableReasons)
{
- boolean configAcceptable = true;
- for (PluginCfgDefn.PluginType pluginType : configuration.getPluginType())
- {
- switch (pluginType)
- {
- case POSTOPERATIONDELETE:
- case POSTOPERATIONMODIFYDN:
- case SUBORDINATEMODIFYDN:
- case SUBORDINATEDELETE:
- // These are acceptable.
- break;
- default:
- unacceptableReasons.add(ERR_PLUGIN_REFERENT_INVALID_PLUGIN_TYPE.
- get(pluginType.toString()));
- configAcceptable = false;
- }
- }
-
- // Iterate through the set of base DNs that we will check and ensure that
- // the corresponding backend is indexed appropriately.
- Set<DN> cfgBaseDNs = configuration.getBaseDN();
- if ((cfgBaseDNs == null) || cfgBaseDNs.isEmpty())
- {
- cfgBaseDNs = DirectoryServer.getPublicNamingContexts().keySet();
- }
-
- //Iterate through attributes and check that each has a valid syntax
- for (AttributeType type : configuration.getAttributeType())
- {
- if (!isAttributeSyntaxValid(type))
- {
- unacceptableReasons.add(
- ERR_PLUGIN_REFERENT_INVALID_ATTRIBUTE_SYNTAX.get(
- type.getNameOrOID(), type.getSyntax().getSyntaxName()));
- configAcceptable = false;
- }
-
- for (DN baseDN : cfgBaseDNs)
- {
- Backend b = DirectoryServer.getBackend(baseDN);
- if ((b != null) && (! b.isIndexed(type, IndexType.EQUALITY)))
- {
- unacceptableReasons.add(ERR_PLUGIN_REFERENT_ATTR_UNINDEXED.get(
- configuration.dn().toString(),
- type.getNameOrOID(), b.getBackendID()));
- configAcceptable = false;
- }
- }
- }
-
- return configAcceptable;
+ return isConfigurationAcceptable(configuration, unacceptableReasons);
}
-
/**
* {@inheritDoc}
*/
@@ -1057,4 +1101,247 @@
}
}
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PluginResult.PreOperation doPreOperation(
+ PreOperationModifyOperation modifyOperation)
+ {
+ /* Skip the integrity checks if the enforcing is not enabled
+ */
+
+ if (!currentConfiguration.isCheckReferences())
+ {
+ return PluginResult.PreOperation.continueOperationProcessing();
+ }
+
+ final List<Modification> mods = modifyOperation.getModifications();
+ final Entry entry = modifyOperation.getModifiedEntry();
+
+ for (Modification mod : mods)
+ {
+ final ModificationType modType = mod.getModificationType();
+
+ /* Process only ADD and REPLACE modification types.
+ */
+ if ((modType != ModificationType.ADD)
+ && (modType != ModificationType.REPLACE))
+ {
+ break;
+ }
+
+ AttributeType attrType = mod.getAttribute().getAttributeType();
+ Set<String> attrOptions = mod.getAttribute().getOptions();
+ Attribute modifiedAttribute = entry.getExactAttribute(attrType,
+ attrOptions);
+ if (modifiedAttribute != null)
+ {
+ PluginResult.PreOperation result =
+ isIntegrityMaintained(modifiedAttribute, entry.getDN());
+ if (result.getResultCode() != ResultCode.SUCCESS)
+ {
+ return result;
+ }
+ }
+ }
+
+ /* At this point, everything is fine.
+ */
+ return PluginResult.PreOperation.continueOperationProcessing();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PluginResult.PreOperation doPreOperation(
+ PreOperationAddOperation addOperation)
+ {
+ /* Skip the integrity checks if the enforcing is not enabled.
+ */
+
+ if (!currentConfiguration.isCheckReferences())
+ {
+ return PluginResult.PreOperation.continueOperationProcessing();
+ }
+
+ final Entry entry = addOperation.getEntryToAdd();
+
+ for (AttributeType attrType : attributeTypes)
+ {
+ final List<Attribute> attrs = entry.getAttribute(attrType, false);
+
+ if (attrs != null)
+ {
+ PluginResult.PreOperation result =
+ isIntegrityMaintained(attrs, entry.getDN());
+ if (result.getResultCode() != ResultCode.SUCCESS)
+ {
+ return result;
+ }
+ }
+ }
+
+ /* If we reahed this point, everything is fine.
+ */
+ return PluginResult.PreOperation.continueOperationProcessing();
+ }
+
+ /**
+ * Verifies that the integrity of values is maintained.
+ * @param attrs Attribute list which refers to another entry in the
+ * directory.
+ * @param entryDN DN of the entry which contains the <CODE>attr</CODE>
+ * attribute.
+ * @return The SUCCESS if the integrity is maintained or
+ * CONSTRAINT_VIOLATION oherwise
+ */
+ private PluginResult.PreOperation
+ isIntegrityMaintained(List<Attribute> attrs, DN entryDN)
+ {
+ PluginResult.PreOperation result = null;
+ for(Attribute attr : attrs)
+ {
+ result = isIntegrityMaintained(attr, entryDN);
+ if (result != PluginResult.PreOperation.continueOperationProcessing())
+ {
+ return result;
+ }
+ }
+
+ return PluginResult.PreOperation.continueOperationProcessing();
+ }
+
+ /**
+ * Verifies that the integrity of values is maintained.
+ * @param attr Attribute which refers to another entry in the
+ * directory.
+ * @param entryDN DN of the entry which contains the <CODE>attr</CODE>
+ * attribute.
+ * @return The SUCCESS if the integrity is maintained or
+ * CONSTRAINT_VIOLATION oherwise
+ */
+ private PluginResult.PreOperation isIntegrityMaintained(Attribute attr,
+ DN entryDN)
+ {
+ /* Verify that the entry belongs to one of the configured naming
+ * contexts.
+ */
+
+ boolean isLocal = false;
+
+ if (baseDNs.isEmpty())
+ {
+ baseDNs = DirectoryServer.getPublicNamingContexts().keySet();
+ }
+
+ for (DN baseDN : baseDNs)
+ {
+ if (entryDN.matchesBaseAndScope(baseDN, SearchScope.SUBORDINATE_SUBTREE))
+ {
+ isLocal = true;
+ break;
+ }
+ }
+
+ /* If the entry does not belong to any of the configured naming
+ * contexts continue further operation processing without checking
+ * the integrity.
+ */
+
+ if (!isLocal)
+ {
+ return PluginResult.PreOperation.continueOperationProcessing();
+ }
+
+ /* Iterate over the list of attributes */
+
+ Iterator<AttributeValue> attrValIt = attr.iterator();
+
+ try
+ {
+ while (attrValIt.hasNext())
+ {
+ AttributeValue attrVal = attrValIt.next();
+ DN valueEntryDN = null;
+ Entry valueEntry = null;
+
+ valueEntryDN = DN.decode(attrVal.getNormalizedValue());
+
+ if (currentConfiguration.getCheckReferencesScopeCriteria()
+ == CheckReferencesScopeCriteria.NAMING_CONTEXT)
+ {
+ boolean matches = false;
+
+ for (DN baseDN : baseDNs)
+ {
+ if (entryDN.matchesBaseAndScope(baseDN,
+ SearchScope.SUBORDINATE_SUBTREE))
+ {
+ matches = true;
+ break;
+ }
+ }
+
+ if (!matches)
+ {
+ return PluginResult.PreOperation.stopProcessing(
+ ResultCode.CONSTRAINT_VIOLATION,
+ ERR_PLUGIN_REFERENT_NAMINGCONTEXT_MISMATCH.get(
+ valueEntryDN.toString(),
+ attr.getName(),
+ entryDN.toString()
+ )
+ );
+ }
+
+ valueEntry = DirectoryServer.getEntry(valueEntryDN);
+ }
+ else
+ {
+ valueEntry = DirectoryServer.getEntry(valueEntryDN);
+ }
+
+ /* Verify that the value entry exists in the backend.
+ */
+
+ if (valueEntry == null)
+ {
+ return PluginResult.PreOperation.stopProcessing(
+ ResultCode.CONSTRAINT_VIOLATION,
+ ERR_PLUGIN_REFERENT_ENTRY_MISSING.get(
+ valueEntryDN.toString(),
+ attr.getName(),
+ entryDN.toString()
+ ));
+ }
+
+ /* Verify that the value entry conforms to the filter.
+ */
+
+ SearchFilter filter = attrFiltMap.get(attr.getAttributeType());
+ if (filter != null && !filter.matchesEntry(valueEntry))
+ {
+ return PluginResult.PreOperation.stopProcessing(
+ ResultCode.CONSTRAINT_VIOLATION,
+ ERR_PLUGIN_REFERENT_FILTER_MISMATCH.get(
+ valueEntry.getDN().toString(),
+ attr.getName(),
+ entryDN.toString(),
+ filter.toString())
+ );
+ }
+ }
+ }
+ catch (DirectoryException de)
+ {
+ return PluginResult.PreOperation.stopProcessing(
+ ResultCode.OTHER,
+ ERR_PLUGIN_REFERENT_EXCEPTION.get(de.getLocalizedMessage()));
+ }
+
+ return PluginResult.PreOperation.continueOperationProcessing();
+ }
}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java
index b5e1e49..868c7ae 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/ReferentialIntegrityPluginTestCase.java
@@ -23,6 +23,7 @@
*
*
* Copyright 2008-2010 Sun Microsystems, Inc.
+ * Portions copyright 2011 profiq s.r.o.
*/
package org.opends.server.plugins;
@@ -59,6 +60,10 @@
private String dsConfigBaseDN="ds-cfg-base-dn";
private String dsConfigUpdateInterval=
"ds-cfg-update-interval";
+ private String dsConfigEnforceIntegrity = "ds-cfg-check-references";
+ private String dsConfigAttrFiltMapping =
+ "ds-cfg-check-references-filter-criteria";
+ private String dsConfigPluginType = "ds-cfg-plugin-type";
//Suffixes to use for non-public naming context tests.
private String exSuffix="dc=example,dc=com";
@@ -427,7 +432,77 @@
"ds-cfg-base-dn: ou=dept, dc=example,dc=com",
"ds-cfg-base-dn: ou=people, o=test",
"ds-cfg-update-interval: 300 seconds",
- "ds-cfg-log-file: logs/test"
+ "ds-cfg-log-file: logs/test",
+ "",
+ // check-references, default
+ "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-check-references: false",
+ "",
+ // check-references enabled
+ "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-base-dn: dc=example, dc=com",
+ "ds-cfg-check-references: true",
+ "",
+ // check-references enabled, check-references-filter-criteria set
+ "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-base-dn: dc=example, dc=com",
+ "ds-cfg-check-references: true",
+ "ds-cfg-check-references-filter-criteria: member:(objectclass=person)",
+ "",
+ // check-references disabled, check-references-filter-criteria set
+ "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-check-references: false",
+ "ds-cfg-check-references-filter-criteria: member:(objectclass=person)"
);
Object[][] array = new Object[entries.size()][1];
for (int i=0; i < array.length; i++)
@@ -576,7 +651,121 @@
"ds-cfg-base-dn: ou=dept, dc=example,dc=com",
"ds-cfg-base-dn: ou=people, o=test",
"ds-cfg-update-interval: 300 seconds",
- "ds-cfg-log-file: /hopefully/doesn't/file/exist"
+ "ds-cfg-log-file: /hopefully/doesn't/file/exist",
+ "",
+ // check-references bad value
+ "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-base-dn: dc=example, dc=com",
+ "ds-cfg-check-references: bad",
+ "ds-cfg-check-references-filter-criteria: member:(objectclass=person)",
+ "",
+ // check-references enabled, attrbute not on the list
+ "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-base-dn: dc=example, dc=com",
+ "ds-cfg-check-references: true",
+ "ds-cfg-check-references-filter-criteria: manager:(objectclass=person)",
+ "",
+ // check-references true, bad filter
+ "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-base-dn: dc=example, dc=com",
+ "ds-cfg-check-references: true",
+ "ds-cfg-check-references-filter-criteria: member:bad",
+ "",
+ // check-references true, attr-filt bad format
+ "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-base-dn: dc=example, dc=com",
+ "ds-cfg-check-references: true",
+ "ds-cfg-check-references-filter-criteria: bad",
+ "",
+ // check-references true, no filter
+ "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-base-dn: dc=example, dc=com",
+ "ds-cfg-check-references: true",
+ "ds-cfg-check-references-filter-criteria: member:",
+ "",
+ // check-references true, null:null
+ "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-base-dn: dc=example, dc=com",
+ "ds-cfg-check-references: true",
+ "ds-cfg-check-references-filter-criteria: :"
);
Object[][] array = new Object[entries.size()][1];
for (int i=0; i < array.length; i++)
@@ -640,6 +829,8 @@
@BeforeMethod
public void clearConfigEntries() throws Exception {
deleteAttrsEntry(configDN, dsConfigBaseDN);
+ deleteAttrsEntry(configDN, dsConfigEnforceIntegrity);
+ deleteAttrsEntry(configDN, dsConfigAttrFiltMapping);
//Hopefully put an attribute type there that won't impact the rest of the
//unit tests.
replaceAttrEntry(configDN, dsConfigAttrType,"seeAlso");
@@ -847,7 +1038,7 @@
* @param attrValStrings The values to add to the entry.
*
*/
- private void
+ private ModifyOperation
addAttrEntry(DN dn, String attrTypeString, String... attrValStrings) {
LinkedList<Modification> mods = new LinkedList<Modification>();
AttributeType attrType = getAttrType(attrTypeString);
@@ -858,7 +1049,7 @@
mods.add(new Modification(ModificationType.ADD, builder.toAttribute()));
InternalClientConnection conn =
InternalClientConnection.getRootConnection();
- conn.processModify(dn, mods);
+ return conn.processModify(dn, mods);
}
/**
@@ -871,7 +1062,7 @@
* @param attrValStrings The values to replace in the the entry.
*
*/
- private void
+ private ModifyOperation
replaceAttrEntry(DN dn, String attrTypeString, String... attrValStrings) {
LinkedList<Modification> mods = new LinkedList<Modification>();
AttributeType attrType = getAttrType(attrTypeString);
@@ -882,7 +1073,7 @@
mods.add(new Modification(ModificationType.REPLACE, builder.toAttribute()));
InternalClientConnection conn =
InternalClientConnection.getRootConnection();
- conn.processModify(dn, mods);
+ return conn.processModify(dn, mods);
}
@@ -1062,4 +1253,794 @@
false, null);
assertEquals(modDNop.getResultCode(), ResultCode.SUCCESS);
}
+
+ /**
+ * Test case:
+ * - integrity is enforced on the attribute 'manager'
+ * - value of the 'manager' attribute should match the filter:
+ * (objectclass=person)
+ * - add a user 'manager' to the 'dc=example,dc=com'
+ * - add a user 'employee' with the attribute manager which points to the
+ * entry 'manager'
+ * - SUCCESS
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityAddUserWitManagerFilterNoNC()
+ throws Exception
+ {
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "false");
+ replaceAttrEntry(configDN, dsConfigPluginType,
+ "postoperationdelete",
+ "postoperationmodifydn",
+ "subordinatemodifydn",
+ "subordinatedelete",
+ "preoperationadd",
+ "preoperationmodify");
+ deleteAttrsEntry(configDN, dsConfigBaseDN);
+ replaceAttrEntry(configDN, dsConfigEnforceIntegrity, "true");
+ replaceAttrEntry(configDN, dsConfigAttrType, "manager");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "manager:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ Entry entry = null;
+ AddOperation addOperation = null;
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ entry = makeEntry("uid=manager,ou=people,ou=dept,o=test");
+
+ addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ entry = 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: uid=manager,ou=people,ou=dept,o=test");
+
+ addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+ /**
+ * Test case:
+ * - integrity is enforced on the attribute 'manager'
+ * - value of the 'manager' attribute should match the filter:
+ * (objectclass=person)
+ * - add a user 'manager' to the 'dc=example,dc=com'
+ * - add a user 'employee' with the attribute manager which points to the
+ * entry 'manager'
+ * - SUCCESS
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityAddUserWitManagerFilter()
+ 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");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "manager:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ Entry entry = null;
+ AddOperation addOperation = null;
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ entry = makeEntry("uid=manager,ou=people,ou=dept,dc=example,dc=com");
+
+ addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ entry = 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: uid=manager,ou=people,ou=dept,dc=example,dc=com");
+
+ addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+ /**
+ * Test case:
+ * - integrity is enforced on the attribute 'manager'
+ * - value of the 'manager' attribute should match the filter:
+ * (objectclass=person)
+ * - add a user 'employee' with the attribute manager which points to the
+ * entry 'manager' which doesn't exist
+ * - CONSTRAINT VIOLATION
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityAddUserWithMissingManagerEntry()
+ 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");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "manager:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ Entry entry = null;
+ AddOperation addOperation = null;
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ entry = 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: uid=bad,ou=people,ou=dept,dc=example,dc=com");
+
+ addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(),
+ ResultCode.CONSTRAINT_VIOLATION);
+ }
+
+ /**
+ * Test case:
+ * - integrity is enforced on the attribute 'manager'
+ * - value of the 'manager' attribute should match the filter:
+ * (objectclass=groupOfNames)
+ * - add a user 'manager' with the object class 'person' to the
+ * 'dc=example,dc=com'
+ * - add a user 'employee' with the attribute manager which points to the
+ * entry 'manager'
+ * - CONSTRAINT VIOLATION
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityAddUserWitManagerFilterMismatch()
+ 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");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "manager:(objectclass=gropuOfNames)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ Entry entry = null;
+ AddOperation addOperation = null;
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ entry = makeEntry("uid=manager,ou=people,ou=dept,dc=example,dc=com");
+
+ addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ entry = 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: uid=manager,ou=people,ou=dept,dc=example,dc=com");
+
+ addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(),
+ ResultCode.CONSTRAINT_VIOLATION);
+ }
+
+ /**
+ * Test case:
+ * - integrity is enforced on the attribute 'manager'
+ * - value of the 'manager' attribute should match the filter:
+ * (objectclass=person)
+ * - add a user 'manager' to the 'o=test'
+ * - add a user 'employee' with the attribute manager which points to the
+ * entry 'manager'
+ * - SUCCESS
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityAddUserWithManagerNC()
+ throws Exception
+ {
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "false");
+ replaceAttrEntry(configDN, dsConfigPluginType,
+ "postoperationdelete",
+ "postoperationmodifydn",
+ "subordinatemodifydn",
+ "subordinatedelete",
+ "preoperationadd",
+ "preoperationmodify");
+ addAttrEntry(configDN, dsConfigBaseDN,
+ "dc=example,dc=com",
+ "o=test");
+ replaceAttrEntry(configDN, dsConfigEnforceIntegrity, "true");
+ replaceAttrEntry(configDN, dsConfigAttrType, "manager");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "manager:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ Entry entry = null;
+ AddOperation addOperation = null;
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ entry = makeEntry("uid=manager,ou=people,ou=dept,o=test");
+
+ addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ entry = 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: uid=manager,ou=people,ou=dept,o=test");
+
+ addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(),
+ ResultCode.SUCCESS);
+ }
+
+ /**
+ * Test case:
+ * - integrity is enforced on the attribute 'member'
+ * - value of the 'manager' attribute should match the filter:
+ * (objectclass=person)
+ * - add a group 'referent group' to the 'dc=example,dc=com' with the
+ * 'member' attribute pointing to the existing user entries
+ * - SUCCESS
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityAddGroupWithFilter()
+ 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, "member");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "member:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ Entry entry = TestCaseUtils.makeEntry(
+ "dn: cn=referent group,ou=groups,dc=example,dc=com",
+ "objectclass: top",
+ "objectclass: groupofnames",
+ "cn: refetent group",
+ "member: uid=user.1,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=user.2,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=user.3,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=user.4,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=user.5,ou=people,ou=dept,dc=example,dc=com"
+ );
+
+ AddOperation addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+ /**
+ * Test case:
+ * - integrity is enforced on the attribute 'member'
+ * - value of the 'manager' attribute should match the filter:
+ * (objectclass=person)
+ * - add a group 'referent group' to the 'dc=example,dc=com' with the
+ * 'member' attribute pointing to the existing user entries and one missing
+ * - CONSTRAINT VIOLATION
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityAddGroupWithMissingMember()
+ 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, "member");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "member:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ Entry entry = TestCaseUtils.makeEntry(
+ "dn: cn=referent group,ou=groups,dc=example,dc=com",
+ "objectclass: top",
+ "objectclass: groupofnames",
+ "cn: refetent group",
+ "member: uid=user.1,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=user.2,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=bad,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=user.4,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=user.5,ou=people,ou=dept,dc=example,dc=com"
+ );
+
+ AddOperation addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(),
+ ResultCode.CONSTRAINT_VIOLATION);
+ }
+
+ /**
+ * Test case:
+ * - integrity is enforced on the attribute 'member'
+ * - value of the 'manager' attribute should match the filter:
+ * (objectclass=person)
+ * - add a group 'referent group' to the 'dc=example,dc=com' with the
+ * 'member' attribute pointing to the existing user entries and one entry
+ * being of object class groupOfNames
+ * - CONSTRAINT VIOLATION
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityAddGroupMemberFilterMismatch()
+ 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, "member");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "member:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ Entry entry = TestCaseUtils.makeEntry(
+ "dn: cn=referent group,ou=groups,dc=example,dc=com",
+ "objectclass: top",
+ "objectclass: groupofnames",
+ "cn: refetent group",
+ "member: uid=user.1,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=user.2,ou=people,ou=dept,dc=example,dc=com",
+ "member: cn=group,ou=groups,dc=example,dc=com",
+ "member: uid=user.4,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=user.5,ou=people,ou=dept,dc=example,dc=com"
+ );
+
+ AddOperation addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(),
+ ResultCode.CONSTRAINT_VIOLATION);
+ }
+
+ /**
+ * Test case:
+ * - integrity is enforced on the attribute 'member'
+ * - value of the 'manager' attribute should match the filter:
+ * (objectclass=person)
+ * - add a group 'referent group' to the 'dc=example,dc=com' with the
+ * 'member' attribute pointing to the existing user entries with one memeber
+ * belonging to 'o=test' naming context
+ * - SUCCESS
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityAddGroupMemberNC()
+ throws Exception
+ {
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "false");
+ replaceAttrEntry(configDN, dsConfigPluginType,
+ "postoperationdelete",
+ "postoperationmodifydn",
+ "subordinatemodifydn",
+ "subordinatedelete",
+ "preoperationadd",
+ "preoperationmodify");
+ addAttrEntry(configDN, dsConfigBaseDN,
+ "dc=example,dc=com",
+ "o=test");
+ replaceAttrEntry(configDN, dsConfigEnforceIntegrity, "true");
+ replaceAttrEntry(configDN, dsConfigAttrType, "member");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "member:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ Entry entry = TestCaseUtils.makeEntry(
+ "dn: cn=referent group,ou=groups,dc=example,dc=com",
+ "objectclass: top",
+ "objectclass: groupofnames",
+ "cn: refetent group",
+ "member: uid=user.1,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=user.2,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=user.3,ou=people,ou=dept,o=test",
+ "member: uid=user.4,ou=people,ou=dept,dc=example,dc=com",
+ "member: uid=user.5,ou=people,ou=dept,dc=example,dc=com"
+ );
+
+ AddOperation addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(),
+ ResultCode.SUCCESS);
+ }
+
+ /**
+ * Test case:
+ * - employee entry exists
+ * - manager entry exists
+ * - add 'manager' attribute to the manager entry
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityModifyUserAddManagerFilter()
+ 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");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "manager:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ Entry entry = makeEntry("uid=manager,ou=people,ou=dept,dc=example,dc=com");
+
+ AddOperation addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ ModifyOperation modOperation = addAttrEntry(DN.decode(user1),
+ "manager", "uid=manager,ou=people,ou=dept,dc=example,dc=com");
+ assertEquals(modOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+ /**
+ * Test case:
+ * - employee entry exists with 'manager' attribute pointing to the
+ * manager entry
+ * - manager entry exists
+ * - user.2 entry exists
+ * - modify 'manager' attribute to the 'user.2' entry
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityModifyUserModifyManagerFilter()
+ 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");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "manager:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ Entry entry = makeEntry("uid=manager,ou=people,ou=dept,dc=example,dc=com");
+
+ AddOperation addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ ModifyOperation modOperation = addAttrEntry(DN.decode(user1),
+ "manager", "uid=manager,ou=people,ou=dept,dc=example,dc=com");
+ assertEquals(modOperation.getResultCode(), ResultCode.SUCCESS);
+
+ modOperation = replaceAttrEntry(DN.decode(user1),
+ "manager", user2);
+ assertEquals(modOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+ /**
+ * Test case:
+ * - filter is set to posixAccount
+ * - employee entry exists
+ * - manager entry exists with objectclass person
+ * - add 'manager' attribute to the manager entry
+ * - constraint violation
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityModifyUserAddManagerFilterMismatch()
+ 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");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "manager:(objectclass=posixAccount)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ Entry entry = makeEntry("uid=manager,ou=people,ou=dept,dc=example,dc=com");
+
+ AddOperation addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ ModifyOperation modOperation = addAttrEntry(DN.decode(user1),
+ "manager", "uid=manager,ou=people,ou=dept,dc=example,dc=com");
+ assertEquals(modOperation.getResultCode(),
+ ResultCode.CONSTRAINT_VIOLATION);
+ }
+
+ /**
+ * Test case:
+ * - employee entry exists in dc=example,dc=com
+ * - manager entry exists in o=other
+ * - add 'manager' attribute to the employee poiting to the manager
+ * entry
+ * - SUCCESS
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityModifyUserAddManagerNC()
+ throws Exception
+ {
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "false");
+ replaceAttrEntry(configDN, dsConfigPluginType,
+ "postoperationdelete",
+ "postoperationmodifydn",
+ "subordinatemodifydn",
+ "subordinatedelete",
+ "preoperationadd",
+ "preoperationmodify");
+ addAttrEntry(configDN, dsConfigBaseDN,
+ "dc=example,dc=com",
+ "o=test");
+ replaceAttrEntry(configDN, dsConfigEnforceIntegrity, "true");
+ replaceAttrEntry(configDN, dsConfigAttrType, "manager");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "manager:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ InternalClientConnection conn =
+ InternalClientConnection.getRootConnection();
+
+ Entry entry = makeEntry("uid=manager,ou=people,ou=dept,o=test");
+
+ AddOperation addOperation = conn.processAdd(entry);
+ assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+
+ ModifyOperation modOperation = addAttrEntry(DN.decode(user1),
+ "manager", "uid=manager,ou=people,ou=dept,o=test");
+ assertEquals(modOperation.getResultCode(),
+ ResultCode.SUCCESS);
+ }
+
+ /**
+ * Test case:
+ * - employee entry exists
+ * - manager entry does not exist
+ * - add 'manager' attribute to the employee
+ * - constraint violation
+ * @throws Exception
+ */
+ @Test()
+ public void testEnforceIntegrityModifyUserAddManagerMissing()
+ 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");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "manager:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ ModifyOperation modOperation = addAttrEntry(DN.decode(user1),
+ "manager", "uid=manager,ou=people,ou=dept,dc=example,dc=com");
+ assertEquals(modOperation.getResultCode(),
+ ResultCode.CONSTRAINT_VIOLATION);
+ }
+
+ @Test()
+ public void testEnforceIntegrityModifyGroupAddMember()
+ 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, "member");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "member:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ ModifyOperation modOperation = addAttrEntry(DN.decode(group),
+ "member",
+ user1);
+ assertEquals(modOperation.getResultCode(), ResultCode.SUCCESS);
+ }
+
+ @Test()
+ public void testEnforceIntegrityModifyGroupAddMissingMember()
+ 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, "member");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "member:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ ModifyOperation modOperation = addAttrEntry(DN.decode(group),
+ "member", "uid=user.100,ou=people,ou=dept,dc=example,dc=com");
+ assertEquals(modOperation.getResultCode(),
+ ResultCode.CONSTRAINT_VIOLATION);
+ }
+
+ @Test()
+ public void testEnforceIntegrityModifyGroupAddMemberFilterMismatch()
+ 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, "member");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "member:(objectclass=posixaccount)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ ModifyOperation modOperation = addAttrEntry(DN.decode(group),
+ "member", "uid=user.100,ou=people,ou=dept,dc=example,dc=com");
+ assertEquals(modOperation.getResultCode(),
+ ResultCode.CONSTRAINT_VIOLATION);
+ }
+
+ @Test()
+ public void testEnforceIntegrityModifyGroupAddMemberNC()
+ throws Exception
+ {
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "false");
+ replaceAttrEntry(configDN, dsConfigPluginType,
+ "postoperationdelete",
+ "postoperationmodifydn",
+ "subordinatemodifydn",
+ "subordinatedelete",
+ "preoperationadd",
+ "preoperationmodify");
+ addAttrEntry(configDN, dsConfigBaseDN,
+ "dc=example,dc=com",
+ "o=test");
+ replaceAttrEntry(configDN, dsConfigEnforceIntegrity, "true");
+ replaceAttrEntry(configDN, dsConfigAttrType, "member");
+ addAttrEntry(configDN, dsConfigAttrFiltMapping,
+ "member:(objectclass=person)");
+ replaceAttrEntry(configDN, "ds-cfg-enabled", "true");
+
+ ModifyOperation modOperation = addAttrEntry(DN.decode(group),
+ "member", "uid=user.1,ou=people,ou=dept,o=test");
+ assertEquals(modOperation.getResultCode(),
+ ResultCode.SUCCESS);
+ }
}
--
Gitblit v1.10.0