From 4068dc7889c3fa045a180bfdcf5124733d34563b Mon Sep 17 00:00:00 2001
From: ludovicp <ludovicp@localhost>
Date: Mon, 07 Jun 2010 08:59:50 +0000
Subject: [PATCH] Add support for MS AD Permissive Modify Control (Issue/Enhancement #4238)

---
 opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java                                     |    1 
 opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java |   30 ++++++++++----
 opendj-sdk/opends/src/server/org/opends/server/types/Entry.java                                              |   43 +++++++++++++++++----
 opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java                                     |    6 +++
 4 files changed, 62 insertions(+), 18 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
index deaba0e..a5a22c4 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -2712,6 +2712,7 @@
     supportedControls.add(OID_MATCHED_VALUES);
     supportedControls.add(OID_LDAP_SUBENTRIES);
     supportedControls.add(OID_PASSWORD_POLICY_CONTROL);
+    supportedControls.add(OID_PERMISSIVE_MODIFY_CONTROL);
     supportedControls.add(OID_REAL_ATTRS_ONLY);
     supportedControls.add(OID_VIRTUAL_ATTRS_ONLY);
     supportedControls.add(OID_ACCOUNT_USABLE_CONTROL);
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/Entry.java b/opendj-sdk/opends/src/server/org/opends/server/types/Entry.java
index 5e86373..14e1b4f 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/Entry.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/Entry.java
@@ -1781,14 +1781,17 @@
    * checking will be performed.
    *
    * @param  mod  The modification to apply to this entry.
-   *
+   * @param  relaxConstraints indicates if the modification constraints are
+   *                          relaxed to match the ones of a set (add existing
+   *                          value and delete absent value do not fail)
+   * 
    * @throws  DirectoryException  If a problem occurs while attempting
    *                              to apply the modification.  Note
    *                              that even if a problem occurs, then
    *                              the entry may have been altered in
    *                              some way.
    */
-  public void applyModification(Modification mod)
+  public void applyModification(Modification mod, boolean relaxConstraints)
          throws DirectoryException
   {
     Attribute     a = mod.getAttribute();
@@ -1816,11 +1819,14 @@
           {
             if (objectClasses.containsKey(oc))
             {
-              Message message =
+              if (!relaxConstraints)
+              {
+                Message message =
                   ERR_ENTRY_DUPLICATE_VALUES.get(a.getName());
-              throw new DirectoryException(
+                throw new DirectoryException(
                              ResultCode.ATTRIBUTE_OR_VALUE_EXISTS,
                              message);
+              }
             }
             else
             {
@@ -1835,10 +1841,13 @@
           {
             if (objectClasses.remove(oc) == null)
             {
-              Message message =
+              if (! relaxConstraints)
+              {
+                Message message =
                   ERR_ENTRY_NO_SUCH_VALUE.get(a.getName());
-              throw new DirectoryException(
+                throw new DirectoryException(
                              ResultCode.NO_SUCH_ATTRIBUTE, message);
+              }
             }
           }
           objectClassAttribute = null;
@@ -1871,7 +1880,7 @@
         LinkedList<AttributeValue> duplicateValues =
              new LinkedList<AttributeValue>();
         addAttribute(a, duplicateValues);
-        if (! duplicateValues.isEmpty())
+        if ((! duplicateValues.isEmpty()) && (! relaxConstraints))
         {
           Message message =
               ERR_ENTRY_DUPLICATE_VALUES.get(a.getName());
@@ -1885,7 +1894,7 @@
         LinkedList<AttributeValue> missingValues =
              new LinkedList<AttributeValue>();
         removeAttribute(a, missingValues);
-        if (! missingValues.isEmpty())
+        if ((! missingValues.isEmpty()) && (! relaxConstraints))
         {
           Message message = ERR_ENTRY_NO_SUCH_VALUE.get(a.getName());
           throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE,
@@ -1909,7 +1918,23 @@
     }
   }
 
-
+  /**
+   * Applies the provided modification to this entry.  No schema
+   * checking will be performed.
+   *
+   * @param  mod  The modification to apply to this entry.
+   *
+   * @throws  DirectoryException  If a problem occurs while attempting
+   *                              to apply the modification.  Note
+   *                              that even if a problem occurs, then
+   *                              the entry may have been altered in
+   *                              some way.
+   */
+  public void applyModification(Modification mod)
+         throws DirectoryException
+  {
+      applyModification(mod, false);
+  }
 
   /**
    * Applies all of the provided modifications to this entry.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java b/opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java
index 72e896c..75f5e0d 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/util/ServerConstants.java
@@ -2275,6 +2275,12 @@
        "2.16.840.1.113730.3.4.2";
 
 
+  /**
+   * The OID for the Permissive Modify control, defined and used by MSAD
+   */
+  public static final String OID_PERMISSIVE_MODIFY_CONTROL =
+      "1.2.840.113556.1.4.1413";
+
 
   /**
    * The OID for the server-side sort request control.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java b/opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
index b8e1d38..c011803 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -120,6 +120,11 @@
   protected boolean noOp;
 
   /**
+   * Indicates whether the request included the Permissive Modify control.
+   */
+  protected boolean permissiveModify = false;
+
+  /**
    * Indicates whether this modify operation includees a password change.
    */
   protected boolean passwordChanged;
@@ -287,7 +292,7 @@
   public void addModification(Modification modification)
     throws DirectoryException
   {
-    modifiedEntry.applyModification(modification);
+    modifiedEntry.applyModification(modification, permissiveModify);
     super.addModification(modification);
   }
 
@@ -839,6 +844,10 @@
         {
           noOp = true;
         }
+        else if (oid.equals(OID_PERMISSIVE_MODIFY_CONTROL))
+        {
+          permissiveModify = true;
+        }
         else if (oid.equals(OID_LDAP_READENTRY_PREREAD))
         {
           preReadRequest =
@@ -1496,7 +1505,7 @@
     LinkedList<AttributeValue> duplicateValues =
       new LinkedList<AttributeValue>();
     modifiedEntry.addAttribute(attr, duplicateValues);
-    if (!duplicateValues.isEmpty())
+    if (!duplicateValues.isEmpty() && !permissiveModify)
     {
       StringBuilder buffer = new StringBuilder();
       Iterator<AttributeValue> iterator = duplicateValues.iterator();
@@ -1604,18 +1613,21 @@
       }
       else
       {
-        StringBuilder buffer = new StringBuilder();
-        Iterator<AttributeValue> iterator = missingValues.iterator();
-        buffer.append(iterator.next().getValue().toString());
-        while (iterator.hasNext())
+        if (! permissiveModify)
         {
-          buffer.append(", ");
+          StringBuilder buffer = new StringBuilder();
+          Iterator<AttributeValue> iterator = missingValues.iterator();
           buffer.append(iterator.next().getValue().toString());
-        }
+          while (iterator.hasNext())
+          {
+            buffer.append(", ");
+            buffer.append(iterator.next().getValue().toString());
+          }
 
-        throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE,
+          throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE,
                        ERR_MODIFY_DELETE_MISSING_VALUES.get(
                             String.valueOf(entryDN), attr.getName(), buffer));
+        }
       }
     }
     else

--
Gitblit v1.10.0