From 5bb8041f09a8dd5c1b769b08b2188caee41758bf Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 23 Apr 2013 10:22:34 +0000
Subject: [PATCH] Fix OPENDJ-625: ModifyDN does not allow the same (normalized) DN

---
 opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java                        |    4 +
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java |  174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 177 insertions(+), 1 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
index 64ebea0..9f4adcc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -24,6 +24,7 @@
  *
  *      Copyright 2006-2010 Sun Microsystems, Inc.
  *      Portions Copyright 2011-2013 ForgeRock AS
+ *      Portions copyright 2013 Manuel Gaupp
  */
 package org.opends.server.backends.jeb;
 import org.opends.messages.Message;
@@ -2428,7 +2429,8 @@
     try
     {
       // Check whether the renamed entry already exists.
-      if (dn2id.get(txn, entry.getDN(), LockMode.DEFAULT) != null)
+      if (!currentDN.equals(entry.getDN()) &&
+          dn2id.get(txn, entry.getDN(), LockMode.DEFAULT) != null)
       {
         Message message = ERR_JEB_MODIFYDN_ALREADY_EXISTS.get(
             entry.getDN().toString());
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java
index 764d72e..617df76 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java
@@ -24,6 +24,7 @@
  *
  *      Copyright 2006-2010 Sun Microsystems, Inc.
  *      Portions copyright 2011 ForgeRock AS.
+ *      Portions copyright 2013 Manuel Gaupp
  */
 package org.opends.server.core;
 
@@ -394,6 +395,179 @@
     examineCompletedOperation(modifyDNOperation);
   }
 
+  /**
+   * Test if it's possible to modify an rdn to a value that matches the current value
+   * by changing the case of some characters
+   */
+  @Test
+  public void testModifySameDN() throws Exception
+  {
+    ArrayList<Control> noControls = new ArrayList<Control>(0);
+    InvocationCounterPlugin.resetAllCounters();
+
+    InternalClientConnection conn =
+         InternalClientConnection.getRootConnection();
+    
+    ModifyDNOperationBasis modifyDNOperation =
+         new ModifyDNOperationBasis(conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(),
+                               noControls,
+                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
+                               RDN.decode("uid=USER.0"), true,
+                               null);
+    
+    modifyDNOperation.run();
+    assertEquals(modifyDNOperation.getResultCode(),
+                 ResultCode.SUCCESS);
+    assertEquals(modifyDNOperation.getErrorMessage().length(), 0);
+    Entry newEntry = DirectoryServer.getEntry(DN.decode(
+        "uid=user.0,ou=People,dc=example,dc=com"));
+    assertNotNull(newEntry);
+    
+    assertTrue(newEntry.getDN().toString().equals("uid=USER.0,ou=People,dc=example,dc=com"));
+    
+    AttributeType at = DirectoryServer.getAttributeType("uid");
+    List<Attribute> attrList = newEntry.getAttribute(at);
+
+    // There should be only one value for "uid"
+    assertEquals(attrList.size(),1);
+
+    // Because deleteOldRDN is true, the values from RDN and the entry have to be identical
+    ByteString valueFromEntry = attrList.get(0).iterator().next().getValue();
+    ByteString valueFromRDN = newEntry.getDN().getRDN().getAttributeValue(at).getValue();
+    assertEquals(valueFromEntry,valueFromRDN);
+
+    examineCompletedOperation(modifyDNOperation);
+    InvocationCounterPlugin.resetAllCounters();
+
+    modifyDNOperation =
+         new ModifyDNOperationBasis(conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(),
+                               noControls,
+                               DN.decode("uid=USER.0,ou=People,dc=example,dc=com"),
+                               RDN.decode("uid=user.0"), true,
+                               null);
+
+    modifyDNOperation.run();
+    assertEquals(modifyDNOperation.getResultCode(),
+                 ResultCode.SUCCESS);
+    assertEquals(modifyDNOperation.getErrorMessage().length(), 0);
+    newEntry = DirectoryServer.getEntry(DN.decode(
+        "uid=user.0,ou=People,dc=example,dc=com"));
+    assertNotNull(newEntry);
+
+    examineCompletedOperation(modifyDNOperation);
+  }  
+  
+  /**
+   * Add another attribute to the RDN and change case of the existing value
+   */
+  @Test
+  public void testModifyDNchangeCaseAndAddValue() throws Exception
+  {
+    TestCaseUtils.addEntry(
+         "dn: uid=userid.0,ou=People,dc=example,dc=com",
+         "objectClass: top",
+         "objectClass: person",
+         "objectClass: organizationalPerson",
+         "objectClass: inetOrgPerson",
+         "uid: userid.0",
+         "givenName: Babs",
+         "sn: Jensen",
+         "cn: Babs Jensen");
+    
+    ArrayList<Control> noControls = new ArrayList<Control>(0);
+    InvocationCounterPlugin.resetAllCounters();
+
+    InternalClientConnection conn =
+         InternalClientConnection.getRootConnection();
+    
+    ModifyDNOperationBasis modifyDNOperation =
+         new ModifyDNOperationBasis(conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(),
+                               noControls,
+                               DN.decode("uid=userid.0,ou=People,dc=example,dc=com"),
+                               RDN.decode("uid=UserID.0+cn=Test"), false,
+                               null);
+    
+    modifyDNOperation.run();
+    assertEquals(modifyDNOperation.getResultCode(),
+                 ResultCode.SUCCESS);
+    assertEquals(modifyDNOperation.getErrorMessage().length(), 0);
+    Entry newEntry = DirectoryServer.getEntry(DN.decode(
+        "uid=userid.0+cn=test,ou=People,dc=example,dc=com"));
+    assertNotNull(newEntry);
+    
+    assertTrue(newEntry.getDN().toString().equals("uid=UserID.0+cn=Test,ou=People,dc=example,dc=com"));
+    
+    AttributeType at = DirectoryServer.getAttributeType("uid");
+    List<Attribute> attrList = newEntry.getAttribute(at);
+
+    // There should be only one value for "uid"
+    assertEquals(attrList.size(),1);
+
+    // Even though the value of the RDN changed, the representation of the entry's value should be preserved
+    ByteString valueFromEntry = attrList.get(0).iterator().next().getValue();
+    ByteString valueFromRDN = newEntry.getDN().getRDN().getAttributeValue(at).getValue();
+    assertEquals(valueFromEntry,ByteString.valueOf("userid.0"));
+
+    examineCompletedOperation(modifyDNOperation);
+    TestCaseUtils.deleteEntry(DN.decode("uid=UserID.0+cn=Test,ou=People,dc=example,dc=com"));
+  }
+  
+  /**
+   * Add a value to the RDN which is already part of the entry, but with another string representation
+   */
+  @Test
+  public void testModifyDNchangeCaseOfExistingEntryValue() throws Exception
+  {
+    TestCaseUtils.addEntry(
+         "dn: uid=userid.0,ou=People,dc=example,dc=com",
+         "objectClass: top",
+         "objectClass: person",
+         "objectClass: organizationalPerson",
+         "objectClass: inetOrgPerson",
+         "uid: userid.0",
+         "givenName: Babs",
+         "sn: Jensen",
+         "cn: Babs Jensen");
+    
+    ArrayList<Control> noControls = new ArrayList<Control>(0);
+    InvocationCounterPlugin.resetAllCounters();
+
+    InternalClientConnection conn =
+         InternalClientConnection.getRootConnection();
+    
+    ModifyDNOperationBasis modifyDNOperation =
+         new ModifyDNOperationBasis(conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(),
+                               noControls,
+                               DN.decode("uid=userid.0,ou=People,dc=example,dc=com"),
+                               RDN.decode("uid=userid.0+sn=JENSEN"), false,
+                               null);
+    
+    modifyDNOperation.run();
+    assertEquals(modifyDNOperation.getResultCode(),
+                 ResultCode.SUCCESS);
+    assertEquals(modifyDNOperation.getErrorMessage().length(), 0);
+    Entry newEntry = DirectoryServer.getEntry(DN.decode(
+        "uid=userid.0+sn=jensen,ou=People,dc=example,dc=com"));
+    assertNotNull(newEntry);
+    
+    assertTrue(newEntry.getDN().toString().equals("uid=userid.0+sn=JENSEN,ou=People,dc=example,dc=com"));
+    
+    AttributeType at = DirectoryServer.getAttributeType("sn");
+    List<Attribute> attrList = newEntry.getAttribute(at);
+
+    // There should be only one value for "sn"
+    assertEquals(attrList.size(),1);
+
+    // Even though the representation of the sn value differs in the RDN,
+    // the representation of the entry's value should be preserved
+    ByteString valueFromEntry = attrList.get(0).iterator().next().getValue();
+    ByteString valueFromRDN = newEntry.getDN().getRDN().getAttributeValue(at).getValue();
+    assertEquals(valueFromEntry,ByteString.valueOf("Jensen"));
+
+    examineCompletedOperation(modifyDNOperation);
+    TestCaseUtils.deleteEntry(DN.decode("uid=userid.0+sn=Jensen,ou=People,dc=example,dc=com"));
+  }
+  
   @Test
   public void testRawDeleteOldRDNModify() throws Exception
   {

--
Gitblit v1.10.0