From 5f7c5309b0977f0149fa433390e3c800c6657476 Mon Sep 17 00:00:00 2001
From: sin <sin@localhost>
Date: Wed, 06 May 2009 17:07:40 +0000
Subject: [PATCH] issue# 2656: Potential race conditions in attribute uniqueness plugin
---
opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 222 insertions(+), 11 deletions(-)
diff --git a/opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java b/opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java
index fea8161..12d3493 100644
--- a/opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java
+++ b/opends/src/server/org/opends/server/plugins/UniqueAttributePlugin.java
@@ -22,13 +22,14 @@
* CDDL HEADER END
*
*
- * Copyright 2008 Sun Microsystems, Inc.
+ * Copyright 2008-2009 Sun Microsystems, Inc.
*/
package org.opends.server.plugins;
import java.util.ArrayList;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -44,6 +45,7 @@
import org.opends.server.api.plugin.DirectoryServerPlugin;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.api.plugin.PluginResult;
+import org.opends.server.api.plugin.PluginResult.PostOperation;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.debug.DebugTracer;
@@ -65,6 +67,9 @@
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchScope;
+import org.opends.server.types.operation.PostOperationAddOperation;
+import org.opends.server.types.operation.PostOperationModifyDNOperation;
+import org.opends.server.types.operation.PostOperationModifyOperation;
import org.opends.server.types.operation.PostSynchronizationAddOperation;
import org.opends.server.types.operation.PostSynchronizationModifyDNOperation;
import org.opends.server.types.operation.PostSynchronizationModifyOperation;
@@ -118,6 +123,12 @@
+ // The data structure to store the mapping between the attribute value
+ // and the corresponding dn.
+ private ConcurrentHashMap<AttributeValue,DN> uniqueAttrValue2Dn;
+
+
+
/**
* {@inheritDoc}
*/
@@ -137,6 +148,9 @@
case PRE_OPERATION_ADD:
case PRE_OPERATION_MODIFY:
case PRE_OPERATION_MODIFY_DN:
+ case POST_OPERATION_ADD:
+ case POST_OPERATION_MODIFY:
+ case POST_OPERATION_MODIFY_DN:
case POST_SYNCHRONIZATION_ADD:
case POST_SYNCHRONIZATION_MODIFY:
case POST_SYNCHRONIZATION_MODIFY_DN:
@@ -171,6 +185,8 @@
}
}
}
+
+ uniqueAttrValue2Dn = new ConcurrentHashMap<AttributeValue,DN>();
}
@@ -215,8 +231,16 @@
{
try
{
- DN conflictDN = getConflictingEntryDN(baseDNs, entry.getDN(),
- config, v);
+ DN conflictDN = null;
+ //Raise an exception if a conflicting concurrent operation is in
+ //progress. Otherwise, store this attribute value with its
+ //corresponding DN and proceed.
+ if((conflictDN=
+ uniqueAttrValue2Dn.putIfAbsent(v, entry.getDN()))==null)
+ {
+ conflictDN = getConflictingEntryDN(baseDNs, entry.getDN(),
+ config, v);
+ }
if (conflictDN != null)
{
Message msg = ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get(
@@ -285,8 +309,16 @@
{
try
{
- DN conflictDN = getConflictingEntryDN(baseDNs, entryDN, config,
- v);
+ DN conflictDN = null;
+ //Raise an exception if a conflicting concurrent operation is in
+ //progress. Otherwise, store this attribute value with its
+ //corresponding DN and proceed.
+ if((conflictDN=
+ uniqueAttrValue2Dn.putIfAbsent(v, entryDN))==null)
+ {
+ conflictDN = getConflictingEntryDN(baseDNs, entryDN, config,
+ v);
+ }
if (conflictDN != null)
{
Message msg = ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get(
@@ -332,8 +364,16 @@
{
try
{
- DN conflictDN = getConflictingEntryDN(baseDNs, entryDN,
+ DN conflictDN = null;
+ //Raise an exception if a conflicting concurrent operation is
+ //in progress. Otherwise, store this attribute value with its
+ //corresponding DN and proceed.
+ if((conflictDN=
+ uniqueAttrValue2Dn.putIfAbsent(v, entryDN))==null)
+ {
+ conflictDN = getConflictingEntryDN(baseDNs, entryDN,
config, v);
+ }
if (conflictDN != null)
{
Message msg = ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get(
@@ -404,8 +444,16 @@
try
{
AttributeValue v = newRDN.getAttributeValue(i);
- DN conflictDN = getConflictingEntryDN(baseDNs,
+ DN conflictDN = null;
+ //Raise an exception if a conflicting concurrent operation is in
+ //progress. Otherwise, store this attribute value with its
+ //corresponding DN and proceed.
+ if((conflictDN=uniqueAttrValue2Dn.putIfAbsent(
+ v, modifyDNOperation.getEntryDN()))==null)
+ {
+ conflictDN = getConflictingEntryDN(baseDNs,
modifyDNOperation.getEntryDN(), config, v);
+ }
if (conflictDN != null)
{
Message msg = ERR_PLUGIN_UNIQUEATTR_ATTR_NOT_UNIQUE.get(
@@ -464,8 +512,12 @@
{
try
{
- DN conflictDN = getConflictingEntryDN(baseDNs, entry.getDN(),
+ DN conflictDN = null;
+ if((conflictDN=uniqueAttrValue2Dn.get(v)) == null)
+ {
+ conflictDN = getConflictingEntryDN(baseDNs, entry.getDN(),
config, v);
+ }
if (conflictDN != null)
{
Message m = ERR_PLUGIN_UNIQUEATTR_SYNC_NOT_UNIQUE.get(
@@ -538,8 +590,12 @@
{
try
{
- DN conflictDN = getConflictingEntryDN(baseDNs, entryDN, config,
+ DN conflictDN = null;
+ if((conflictDN=uniqueAttrValue2Dn.get(v)) == null)
+ {
+ conflictDN = getConflictingEntryDN(baseDNs, entryDN, config,
v);
+ }
if (conflictDN != null)
{
Message message = ERR_PLUGIN_UNIQUEATTR_SYNC_NOT_UNIQUE.get(
@@ -592,8 +648,12 @@
{
try
{
- DN conflictDN = getConflictingEntryDN(baseDNs, entryDN,
+ DN conflictDN = null;
+ if((conflictDN=uniqueAttrValue2Dn.get(v)) == null)
+ {
+ conflictDN = getConflictingEntryDN(baseDNs, entryDN,
config, v);
+ }
if (conflictDN != null)
{
Message message = ERR_PLUGIN_UNIQUEATTR_SYNC_NOT_UNIQUE.get(
@@ -671,8 +731,12 @@
try
{
AttributeValue v = newRDN.getAttributeValue(i);
- DN conflictDN = getConflictingEntryDN(baseDNs,
+ DN conflictDN = null;
+ if((conflictDN=uniqueAttrValue2Dn.get(v)) == null)
+ {
+ conflictDN = getConflictingEntryDN(baseDNs,
modifyDNOperation.getEntryDN(), config, v);
+ }
if (conflictDN != null)
{
Message m =
@@ -848,6 +912,9 @@
case PREOPERATIONADD:
case PREOPERATIONMODIFY:
case PREOPERATIONMODIFYDN:
+ case POSTOPERATIONADD:
+ case POSTOPERATIONMODIFY:
+ case POSTOPERATIONMODIFYDN:
case POSTSYNCHRONIZATIONADD:
case POSTSYNCHRONIZATIONMODIFY:
case POSTSYNCHRONIZATIONMODIFYDN:
@@ -934,5 +1001,149 @@
return alerts;
}
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public final PluginResult.PostOperation
+ doPostOperation(PostOperationAddOperation addOperation)
+ {
+ UniqueAttributePluginCfg config = currentConfiguration;
+ Entry entry = addOperation.getEntryToAdd();
+
+ Set<DN> baseDNs = getBaseDNs(config, entry.getDN());
+ if (baseDNs == null)
+ {
+ // The entry is outside the scope of this plugin.
+ return PluginResult.PostOperation.continueOperationProcessing();
+ }
+
+ //Remove the attribute value from the map.
+ for (AttributeType t : config.getType())
+ {
+ List<Attribute> attrList = entry.getAttribute(t);
+ if (attrList != null)
+ {
+ for (Attribute a : attrList)
+ {
+ for (AttributeValue v : a)
+ {
+ uniqueAttrValue2Dn.remove(v);
+ }
+ }
+ }
+ }
+
+ return PluginResult.PostOperation.continueOperationProcessing();
+ }
+
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public final PluginResult.PostOperation
+ doPostOperation(PostOperationModifyOperation modifyOperation)
+ {
+ UniqueAttributePluginCfg config = currentConfiguration;
+ DN entryDN = modifyOperation.getEntryDN();
+
+ Set<DN> baseDNs = getBaseDNs(config, entryDN);
+ if (baseDNs == null)
+ {
+ // The entry is outside the scope of this plugin.
+ return PluginResult.PostOperation.continueOperationProcessing();
+ }
+
+ for (Modification m : modifyOperation.getModifications())
+ {
+ Attribute a = m.getAttribute();
+ AttributeType t = a.getAttributeType();
+ if (! config.getType().contains(t))
+ {
+ // This modification isn't for a unique attribute.
+ continue;
+ }
+
+ switch (m.getModificationType())
+ {
+ case ADD:
+ case REPLACE:
+ for (AttributeValue v : a)
+ {
+ uniqueAttrValue2Dn.remove(v);
+ }
+ break;
+
+ case INCREMENT:
+ // We could calculate the new value, but we'll just take it from the
+ // updated entry.
+ List<Attribute> attrList =
+ modifyOperation.getModifiedEntry().getAttribute(t,
+ a.getOptions());
+ if (attrList != null)
+ {
+ for (Attribute updatedAttr : attrList)
+ {
+ if (! updatedAttr.optionsEqual(a.getOptions()))
+ {
+ continue;
+ }
+
+ for (AttributeValue v : updatedAttr)
+ {
+ uniqueAttrValue2Dn.remove(v);
+ }
+ }
+ }
+ break;
+
+ default:
+ // We don't need to look at this modification because it's not a
+ // modification type of interest.
+ continue;
+ }
+ }
+
+ return PluginResult.PostOperation.continueOperationProcessing();
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public final PluginResult.PostOperation
+ doPostOperation(PostOperationModifyDNOperation modifyDNOperation)
+ {
+ UniqueAttributePluginCfg config = currentConfiguration;
+ Set<DN> baseDNs = getBaseDNs(config,
+ modifyDNOperation.getUpdatedEntry().getDN());
+ if (baseDNs == null)
+ {
+ // The entry is outside the scope of this plugin.
+ return PostOperation.continueOperationProcessing();
+ }
+
+ RDN newRDN = modifyDNOperation.getNewRDN();
+ for (int i=0; i < newRDN.getNumValues(); i++)
+ {
+ AttributeType t = newRDN.getAttributeType(i);
+ if (! config.getType().contains(t))
+ {
+ // We aren't interested in this attribute type.
+ continue;
+ }
+ AttributeValue v = newRDN.getAttributeValue(i);
+ uniqueAttrValue2Dn.remove(v);
+ }
+ return PostOperation.continueOperationProcessing();
+ }
}
--
Gitblit v1.10.0