TestModifyDNOperation.java revision 9aa1482c49865483f798f91ef7d16f03cc3ec811
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2006-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2015 ForgeRock AS.
* Portions copyright 2013 Manuel Gaupp
*/
package org.opends.server.core;
import java.net.Socket;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import javax.naming.Context;
import javax.naming.InvalidNameException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.TestCaseUtils;
import org.opends.server.controls.ProxiedAuthV1Control;
import org.opends.server.controls.ProxiedAuthV2Control;
import org.opends.server.plugins.InvocationCounterPlugin;
import org.opends.server.plugins.ShortCircuitPlugin;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.ldap.BindRequestProtocolOp;
import org.opends.server.protocols.ldap.BindResponseProtocolOp;
import org.opends.server.protocols.ldap.LDAPControl;
import org.opends.server.protocols.ldap.LDAPMessage;
import org.opends.server.protocols.ldap.LDAPResultCode;
import org.opends.server.protocols.ldap.ModifyDNRequestProtocolOp;
import org.opends.server.protocols.ldap.ModifyDNResponseProtocolOp;
import org.opends.server.tools.LDAPModify;
import org.opends.server.tools.LDAPWriter;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.CancelRequest;
import org.opends.server.types.CancelResult;
import org.opends.server.types.Control;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import org.opends.server.types.LockManager.DNLock;
import org.opends.server.types.Operation;
import org.opends.server.types.RDN;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.forgerock.opendj.ldap.ResultCode.*;
import static org.opends.server.protocols.internal.InternalClientConnection.*;
import static org.opends.server.util.ServerConstants.*;
import static org.testng.Assert.*;
@SuppressWarnings("javadoc")
public class TestModifyDNOperation extends OperationTestCase
{
private Entry entry;
private InternalClientConnection proxyUserConn;
@BeforeClass
public void setUp() throws Exception
{
TestCaseUtils.startServer();
TestCaseUtils.initializeTestBackend(true);
TestCaseUtils.clearBackend("userRoot");
// Add the example.com entry
TestCaseUtils.addEntry(
"dn: dc=example,dc=com",
"objectclass: top",
"objectclass: domain",
"dc: example",
"aci: (targetattr=\"*\")(version 3.0; acl \"Proxy Rights\"; " +
"allow(proxy) userdn=\"ldap:///uid=proxy.user,o=test\";)"
);
// Add the people entry
TestCaseUtils.addEntry(
"dn: ou=People,dc=example,dc=com",
"objectclass: top",
"objectclass: organizationalUnit",
"ou: People"
);
// Add a test entry.
entry = TestCaseUtils.addEntry(
"dn: uid=user.0,ou=People,dc=example,dc=com",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"givenName: Aaccf",
"sn: Amar",
"cn: Aaccf Amar",
"initials: AQA",
"employeeNumber: 0",
"uid: user.0",
"mail: user.0@example.com",
"userPassword: password",
"telephoneNumber: 380-535-2354",
"homePhone: 707-626-3913",
"pager: 456-345-7750",
"mobile: 366-674-7274",
"street: 99262 Eleventh Street",
"l: Salem",
"st: NM",
"postalCode: 36530",
"postalAddress: Aaccf Amar$99262 Eleventh Street$Salem, NM 36530",
"description: This is the description for Aaccf Amar."
);
// Add a user capable of using the proxied authorization control.
TestCaseUtils.addEntry(
"dn: uid=proxy.user,o=test",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: proxy.user",
"givenName: Proxy",
"sn: User",
"cn: Proxy User",
"userPassword: password",
"ds-privilege-name: bypass-acl",
"ds-privilege-name: proxied-auth");
proxyUserConn = new InternalClientConnection(dn("uid=proxy.user,o=test"));
}
/**
* Invokes a number of operation methods on the provided modify operation
* for which all processing has been completed. This method is used for
* tests that bypass the referential integrity plugin for whatever reason.
*
* @param modifyDNOperation The operation to be tested.
*/
private void
examineCompletedOPNoExtraPluginCounts(ModifyDNOperation modifyDNOperation)
{
assertTrue(modifyDNOperation.getProcessingStartTime() > 0);
assertTrue(modifyDNOperation.getProcessingStopTime() > 0);
assertTrue(modifyDNOperation.getProcessingTime() >= 0);
// assertEquals(InvocationCounterPlugin.getPreParseCount(), 1);
// assertEquals(InvocationCounterPlugin.getPreOperationCount(), 1);
// assertEquals(InvocationCounterPlugin.getPostOperationCount(), 1);
ensurePostReponseHasRun();
// assertEquals(InvocationCounterPlugin.getPostResponseCount(), 1);
}
/**
* Invokes a number of operation methods on the provided modify operation
* for which all processing has been completed. The counters
* postResponseCount and preParseCount are incremented twice when
* referential integrity plugin is enabled.
*
* @param modifyDNOperation The operation to be tested.
*/
private void examineCompletedOperation(ModifyDNOperation modifyDNOperation)
{
assertTrue(modifyDNOperation.getProcessingStartTime() > 0);
assertTrue(modifyDNOperation.getProcessingStopTime() > 0);
assertTrue(modifyDNOperation.getProcessingTime() >= 0);
// assertEquals(InvocationCounterPlugin.getPreParseCount(), 2);
// assertEquals(InvocationCounterPlugin.getPreOperationCount(), 1);
// assertEquals(InvocationCounterPlugin.getPostOperationCount(), 1);
ensurePostReponseHasRun();
// assertEquals(InvocationCounterPlugin.getPostResponseCount(), 2);
}
/**
* Invokes a number of operation methods on the provided modify operation
* for which the pre-operation plugin was not called.
*
* @param modifyDNOperation The operation to be tested.
*/
private void examineIncompleteOperation(ModifyDNOperation modifyDNOperation,
ResultCode resultCode)
{
assertEquals(modifyDNOperation.getResultCode(), resultCode);
assertTrue(modifyDNOperation.getErrorMessage().length() > 0);
assertTrue(modifyDNOperation.getProcessingStartTime() > 0);
assertTrue(modifyDNOperation.getProcessingStopTime() > 0);
assertTrue(modifyDNOperation.getProcessingTime() >= 0);
assertTrue(modifyDNOperation.getErrorMessage().length() > 0);
// assertEquals(InvocationCounterPlugin.getPreParseCount(), 1);
// assertEquals(InvocationCounterPlugin.getPreOperationCount(), 0);
// assertEquals(InvocationCounterPlugin.getPostOperationCount(), 1);
ensurePostReponseHasRun();
// assertEquals(InvocationCounterPlugin.getPostResponseCount(), 1);
}
/**
* Invokes a number of operation methods on the provided modify operation
* for which an error was found during parsing.
*
* @param modifyDNOperation The operation to be tested.
*/
private void examineUnparsedOperation(ModifyDNOperation modifyDNOperation, ResultCode resultCode)
{
assertEquals(modifyDNOperation.getResultCode(), resultCode);
assertTrue(modifyDNOperation.getErrorMessage().length() > 0);
assertTrue(modifyDNOperation.getProcessingStartTime() > 0);
assertTrue(modifyDNOperation.getProcessingStopTime() > 0);
assertTrue(modifyDNOperation.getProcessingTime() >= 0);
assertTrue(modifyDNOperation.getErrorMessage().length() > 0);
// assertEquals(InvocationCounterPlugin.getPreParseCount(), 1);
// assertEquals(InvocationCounterPlugin.getPreOperationCount(), 0);
// assertEquals(InvocationCounterPlugin.getPostOperationCount(), 0);
ensurePostReponseHasRun();
// assertEquals(InvocationCounterPlugin.getPostResponseCount(), 1);
}
@Override
protected Operation[] createTestOperations() throws Exception
{
return new ModifyDNOperation[] {
newModifyDNOperationRaw("cn=test,ou=test", "cn=test2", true, "dc=example,dc=com"),
newModifyDNOperation("cn=test,ou=test", "cn=test2", true, "dc=example,dc=com")
};
}
private ModifyDNOperation runModifyDNOperation(
String entryDN, String newRDN, boolean deleteOldRDN, String newSuperior) throws DirectoryException
{
ModifyDNOperation op = newModifyDNOperation(entryDN, newRDN, deleteOldRDN, newSuperior);
op.run();
return op;
}
private ModifyDNOperation runModifyDNOperationRaw(
String entryDN, String newRDN, boolean deleteOldRDN, String newSuperior)
{
ModifyDNOperation op = newModifyDNOperationRaw(entryDN, newRDN, deleteOldRDN, newSuperior);
op.run();
return op;
}
private ModifyDNOperationBasis newModifyDNOperation(
String entryDN, String newRDN, boolean deleteOldRDN, String newSuperior) throws DirectoryException
{
return new ModifyDNOperationBasis(getRootConnection(), nextOperationID(), nextMessageID(),
Collections.<Control> emptyList(), dn(entryDN), rdn(newRDN), deleteOldRDN, dn(newSuperior));
}
private ModifyDNOperationBasis newModifyDNOperationRaw(
String entryDN, String newRDN, boolean deleteOldRDN, String newSuperior)
{
return new ModifyDNOperationBasis(getRootConnection(), nextOperationID(), nextMessageID(),
Collections.<Control> emptyList(), b(entryDN), b(newRDN), deleteOldRDN, b(newSuperior));
}
private ModifyDNOperation runModifyDNOperation(
InternalClientConnection conn, String entryDN, String newRDN, boolean deleteOldRDN, Control control) throws DirectoryException
{
ModifyDNOperation op = new ModifyDNOperationBasis(conn, nextOperationID(), nextMessageID(),
Collections.singletonList(control), dn(entryDN), rdn(newRDN), deleteOldRDN, null);
op.run();
return op;
}
private ModifyDNOperation runModifyDNOperationRaw(
String entryDN, String newRDN, boolean deleteOldRDN, String newSuperior, Control control)
{
ModifyDNOperation op = new ModifyDNOperationBasis(proxyUserConn, nextOperationID(), nextMessageID(),
Collections.singletonList(control), b(entryDN), b(newRDN), deleteOldRDN, b(newSuperior));
op.run();
return op;
}
private ByteString b(String s)
{
return s != null ? ByteString.valueOfUtf8(s) : null;
}
private DN dn(String s) throws DirectoryException
{
return s != null ? DN.valueOf(s) : null;
}
private RDN rdn(String s) throws DirectoryException
{
return s != null ? RDN.decode(s) : null;
}
private void assertSuccessAndEntryExists(ModifyDNOperation modifyDNOperation,
String entryDN, boolean user0Exists, boolean userTest0Exists)
throws DirectoryException
{
assertSuccess(modifyDNOperation);
final Entry newEntry = DirectoryServer.getEntry(dn(entryDN));
assertNotNull(newEntry);
final RDN rdn = newEntry.getName().rdn();
for (int i = 0; i < rdn.getNumValues(); i++)
{
AttributeType attribute = rdn.getAttributeType(i);
assertEquals(newEntry.hasValue(attribute, null, b("user.0")), user0Exists);
assertEquals(newEntry.hasValue(attribute, null, b("user.test0")), userTest0Exists);
}
}
@Test
public void testRawModify() throws Exception
{
String oldEntryDN = "uid=user.0,ou=People,dc=example,dc=com";
String newEntryDN = "uid=user.test0,ou=People,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperationRaw(oldEntryDN, "uid=user.test0", false, null);
assertSuccessAndEntryExists(modifyDNOperation, newEntryDN, true, true);
examineCompletedOperation(modifyDNOperation);
InvocationCounterPlugin.resetAllCounters();
modifyDNOperation = runModifyDNOperationRaw(newEntryDN, "uid=user.0", true, null);
assertSuccessAndEntryExists(modifyDNOperation, oldEntryDN, true, false);
examineCompletedOperation(modifyDNOperation);
}
@Test
public void testProcessedModify() throws Exception
{
String oldEntryDN = "uid=user.0,ou=People,dc=example,dc=com";
String newEntryDN = "uid=user.test0,ou=People,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperation(oldEntryDN, "uid=user.test0", false, null);
assertSuccessAndEntryExists(modifyDNOperation, newEntryDN, true, true);
examineCompletedOperation(modifyDNOperation);
InvocationCounterPlugin.resetAllCounters();
modifyDNOperation = runModifyDNOperation(newEntryDN, "uid=user.0", true, null);
assertSuccessAndEntryExists(modifyDNOperation, oldEntryDN, true, false);
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
{
String oldEntryDN = "uid=user.0,ou=People,dc=example,dc=com";
String newEntryDN = "uid=USER.0,ou=People,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperation(oldEntryDN, "uid=USER.0", true, null);
assertSuccess(modifyDNOperation);
Entry newEntry = DirectoryServer.getEntry(dn(oldEntryDN));
assertNotNull(newEntry);
assertEquals(newEntry.getName().toString(), newEntryDN);
assertAttrValue(newEntry, "uid", "USER.0");
examineCompletedOperation(modifyDNOperation);
InvocationCounterPlugin.resetAllCounters();
modifyDNOperation = runModifyDNOperation(newEntryDN, "uid=user.0", true, null);
assertSuccess(modifyDNOperation);
assertNotNull(DirectoryServer.getEntry(dn(oldEntryDN)));
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");
String oldEntryDN = "uid=userid.0,ou=People,dc=example,dc=com";
String newEntryDN = "uid=UserID.0+cn=Test,ou=People,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperation(oldEntryDN, "uid=UserID.0+cn=Test", false, null);
assertSuccess(modifyDNOperation);
assertEntryAttrValue(newEntryDN, "uid", "UserID.0");
examineCompletedOperation(modifyDNOperation);
TestCaseUtils.deleteEntry(dn(newEntryDN));
}
private void assertEntryAttrValue(String entryDN, String attrName, String expectedAttrValue)
throws DirectoryException
{
Entry newEntry = DirectoryServer.getEntry(dn(entryDN));
assertNotNull(newEntry);
assertEquals(newEntry.getName().toString(), entryDN);
assertAttrValue(newEntry, attrName, expectedAttrValue);
}
private void assertAttrValue(Entry newEntry, String attrName, String expectedAttrValue)
{
AttributeType at = DirectoryServer.getAttributeTypeOrNull(attrName);
List<Attribute> attrList = newEntry.getAttribute(at);
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();
ByteString valueFromRDN = newEntry.getName().rdn().getAttributeValue(at);
assertEquals(valueFromEntry, valueFromRDN);
assertEquals(valueFromEntry, b(expectedAttrValue));
}
/**
* 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");
String oldEntryDN = "uid=userid.0,ou=People,dc=example,dc=com";
String newEntryDN = "uid=userid.0+sn=JENSEN,ou=People,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperation(oldEntryDN, "uid=userid.0+sn=JENSEN", false, null);
assertSuccess(modifyDNOperation);
assertEntryAttrValue(newEntryDN, "sn", "JENSEN");
examineCompletedOperation(modifyDNOperation);
TestCaseUtils.deleteEntry(dn(newEntryDN));
}
private void assertSuccess(ModifyDNOperation op)
{
assertEquals(op.getResultCode(), SUCCESS);
assertEquals(op.getErrorMessage().length(), 0);
}
@Test
public void testRawDeleteOldRDNModify() throws Exception
{
String oldEntryDN = "uid=user.0,ou=People,dc=example,dc=com";
String newEntryDN = "uid=user.test0,ou=People,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperationRaw(oldEntryDN, "uid=user.test0", true, null);
assertSuccessAndEntryExists(modifyDNOperation, newEntryDN, false, true);
examineCompletedOperation(modifyDNOperation);
InvocationCounterPlugin.resetAllCounters();
modifyDNOperation = runModifyDNOperationRaw(newEntryDN, "uid=user.0", true, null);
assertSuccessAndEntryExists(modifyDNOperation, oldEntryDN, true, false);
examineCompletedOperation(modifyDNOperation);
}
@Test
public void testProcessedDeleteOldRDNModify() throws Exception
{
String oldEntryDN = "uid=user.0,ou=People,dc=example,dc=com";
String newEntryDN = "uid=user.test0,ou=People,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperation(oldEntryDN, "uid=user.test0", true, null);
CancelRequest cancelRequest = new CancelRequest(false, LocalizableMessage.raw("testCancelBeforeStartup"));
CancelResult cancelResult = modifyDNOperation.cancel(cancelRequest);
assertEquals(cancelResult.getResultCode(), TOO_LATE);
assertSuccessAndEntryExists(modifyDNOperation, newEntryDN, false, true);
examineCompletedOperation(modifyDNOperation);
InvocationCounterPlugin.resetAllCounters();
modifyDNOperation = runModifyDNOperation(newEntryDN, "uid=user.0", true, null);
assertSuccessAndEntryExists(modifyDNOperation, oldEntryDN, true, false);
examineCompletedOperation(modifyDNOperation);
}
@Test
public void testRawNewSuperiorModify() throws Exception
{
String oldEntryDN = "uid=user.0,ou=People,dc=example,dc=com";
String newEntryDN = "uid=user.test0,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation =
runModifyDNOperationRaw(oldEntryDN, "uid=user.test0", true, "dc=example,dc=com");
assertSuccessAndEntryExists(modifyDNOperation, newEntryDN, false, true);
examineCompletedOPNoExtraPluginCounts(modifyDNOperation);
InvocationCounterPlugin.resetAllCounters();
modifyDNOperation = runModifyDNOperationRaw(newEntryDN, "uid=user.0", true, "ou=People,dc=example,dc=com");
assertSuccessAndEntryExists(modifyDNOperation, oldEntryDN, true, false);
examineCompletedOPNoExtraPluginCounts(modifyDNOperation);
}
@Test
public void testProcessedNewSuperiorModify() throws Exception
{
String oldEntryDN = "uid=user.0,ou=People,dc=example,dc=com";
String newEntryDN = "uid=user.test0,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperation(oldEntryDN, "uid=user.test0", true, "dc=example,dc=com");
assertSuccessAndEntryExists(modifyDNOperation, newEntryDN, false, true);
examineCompletedOPNoExtraPluginCounts(modifyDNOperation);
InvocationCounterPlugin.resetAllCounters();
modifyDNOperation = runModifyDNOperation(newEntryDN, "uid=user.0", true, "ou=People,dc=example,dc=com");
assertSuccessAndEntryExists(modifyDNOperation, oldEntryDN, true, false);
examineCompletedOPNoExtraPluginCounts(modifyDNOperation);
}
@Test
public void testRawRDNModify() throws Exception
{
String oldEntryDN = "uid=user.0,ou=People,dc=example,dc=com";
String newEntryDN = "cn=Aaccf Amar Test,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation =
runModifyDNOperation(oldEntryDN, "cn=Aaccf Amar Test", true, "dc=example,dc=com");
assertSuccess(modifyDNOperation);
Entry entry = assertCnAttrValues(newEntryDN, oldEntryDN);
assertNull(entry.getAttribute("uid"));
examineCompletedOPNoExtraPluginCounts(modifyDNOperation);
InvocationCounterPlugin.resetAllCounters();
modifyDNOperation = runModifyDNOperation(newEntryDN, "uid=user.0", false, "ou=People,dc=example,dc=com");
assertSuccess(modifyDNOperation);
Entry newOldEntry = assertCnAttrValues(oldEntryDN, newEntryDN);
for(Attribute attribute : newOldEntry.getAttribute("uid"))
{
assertTrue(attribute.contains(b("user.0")));
}
examineCompletedOPNoExtraPluginCounts(modifyDNOperation);
}
private Entry assertCnAttrValues(String entryDN1, String entryDN2) throws DirectoryException
{
Entry entry = DirectoryServer.getEntry(dn(entryDN1));
assertNotNull(entry);
assertNull(DirectoryServer.getEntry(dn(entryDN2)));
for (Attribute attribute : entry.getAttribute("cn"))
{
assertTrue(attribute.contains(b("Aaccf Amar Test")));
assertTrue(attribute.contains(b("Aaccf Amar")));
}
return entry;
}
@Test
public void testInvalidEntryModify() throws Exception
{
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperation(
"uid=user.invalid,ou=People,dc=example,dc=com", "uid=user.test0", true, "dc=example,dc=com");
examineIncompleteOperation(modifyDNOperation, NO_SUCH_OBJECT);
}
@Test
public void testInvalidRDNModify() throws Exception
{
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperation(
"uid=user.0,ou=People,dc=example,dc=com", "invalid=invalid", true, "dc=example,dc=com");
examineIncompleteOperation(modifyDNOperation, OBJECTCLASS_VIOLATION);
}
@Test
public void testInvalidSuperiorModify() throws Exception
{
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperation(
"uid=user.0,ou=People,dc=example,dc=com", "uid=user.test0", true, "dc=invalid,dc=com");
examineIncompleteOperation(modifyDNOperation, NO_SUCH_OBJECT);
}
@Test
public void testRawNoSuchDNModify() throws Exception
{
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation =
runModifyDNOperationRaw("invalid DN", "uid=user.test0", true, "dc=example,dc=com");
examineUnparsedOperation(modifyDNOperation, INVALID_DN_SYNTAX);
}
@Test
public void testRawNoSuchRDNModify() throws Exception
{
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation =
runModifyDNOperationRaw("uid=user.0,ou=People,dc=example,dc=com", "invalid RDN", true, "dc=example,dc=com");
examineUnparsedOperation(modifyDNOperation, INVALID_DN_SYNTAX);
}
@Test
public void testRawInvalidSuperiorModify() throws Exception
{
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation =
runModifyDNOperationRaw("uid=user.0,ou=People,dc=example,dc=com", "uid=user.test0", true, "invalid superior");
examineUnparsedOperation(modifyDNOperation, INVALID_DN_SYNTAX);
}
@Test
public void testModifySuffix() throws Exception
{
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperation("dc=example,dc=com", "dc=exampletest", true, null);
examineIncompleteOperation(modifyDNOperation, UNWILLING_TO_PERFORM);
}
@Test
public void testRawProxyAuthV1Modify() throws Exception
{
ProxiedAuthV1Control authV1Control = new ProxiedAuthV1Control(b("cn=Directory Manager,cn=Root DNs,cn=config"));
String oldEntryDN = "uid=user.0,ou=People,dc=example,dc=com";
String newEntryDN = "uid=user.test0,ou=People,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperationRaw(oldEntryDN, "uid=user.test0", false, null, authV1Control);
assertSuccessAndEntryExists(modifyDNOperation, newEntryDN, true, true);
examineCompletedOperation(modifyDNOperation);
InvocationCounterPlugin.resetAllCounters();
modifyDNOperation = runModifyDNOperationRaw(newEntryDN, "uid=user.0", true, null, authV1Control);
assertSuccessAndEntryExists(modifyDNOperation, oldEntryDN, true, false);
examineCompletedOperation(modifyDNOperation);
}
@Test
public void testProcessedProxyAuthV1Modify() throws Exception
{
ProxiedAuthV1Control authV1Control = new ProxiedAuthV1Control(b("cn=Directory Manager,cn=Root DNs,cn=config"));
String oldEntryDN = "uid=user.0,ou=People,dc=example,dc=com";
String newEntryDN = "uid=user.test0,ou=People,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation =
runModifyDNOperation(proxyUserConn, oldEntryDN, "uid=user.test0", false, authV1Control);
assertSuccessAndEntryExists(modifyDNOperation, newEntryDN, true, true);
examineCompletedOperation(modifyDNOperation);
InvocationCounterPlugin.resetAllCounters();
modifyDNOperation = runModifyDNOperation(proxyUserConn, newEntryDN, "uid=user.0", true, authV1Control);
assertSuccessAndEntryExists(modifyDNOperation, oldEntryDN, true, false);
examineCompletedOperation(modifyDNOperation);
}
@Test
public void testProcessedProxyAuthV1DeniedModify() throws Exception
{
ProxiedAuthV1Control authV1Control = new ProxiedAuthV1Control(b("cn=nonexistent,o=test"));
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation =
runModifyDNOperation(proxyUserConn, "uid=user.0,ou=People,dc=example,dc=com", "uid=user.test0", false, authV1Control);
examineIncompleteOperation(modifyDNOperation, AUTHORIZATION_DENIED);
}
@Test
public void testProcessedProxyAuthV2Modify() throws Exception
{
ProxiedAuthV2Control authV2Control = new ProxiedAuthV2Control(b("dn:cn=Directory Manager,cn=Root DNs,cn=config"));
String oldEntryDN = "uid=user.0,ou=People,dc=example,dc=com";
String newEntryDN = "uid=user.test0,ou=People,dc=example,dc=com";
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation =
runModifyDNOperation(proxyUserConn, oldEntryDN, "uid=user.test0", false, authV2Control);
assertSuccessAndEntryExists(modifyDNOperation, newEntryDN, true, true);
examineCompletedOperation(modifyDNOperation);
InvocationCounterPlugin.resetAllCounters();
modifyDNOperation = runModifyDNOperation(proxyUserConn, newEntryDN, "uid=user.0", true, authV2Control);
assertSuccessAndEntryExists(modifyDNOperation, oldEntryDN, true, false);
examineCompletedOperation(modifyDNOperation);
}
@Test
public void testProcessedProxyAuthV2DeniedModify() throws Exception
{
ProxiedAuthV2Control authV2Control = new ProxiedAuthV2Control(b("dn:cn=nonexistent,o=test"));
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation =
runModifyDNOperation(proxyUserConn, "uid=user.0,ou=People,dc=example,dc=com", "uid=user.test0", false, authV2Control);
examineIncompleteOperation(modifyDNOperation, AUTHORIZATION_DENIED);
}
@Test
public void testProcessedProxyAuthV2CriticalityModify() throws Exception
{
Control authV2Control = new LDAPControl(OID_PROXIED_AUTH_V2, false, b("dn:cn=nonexistent,o=test"));
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation =
runModifyDNOperation(proxyUserConn, "uid=user.0,ou=People,dc=example,dc=com", "uid=user.test0", false, authV2Control);
examineIncompleteOperation(modifyDNOperation, PROTOCOL_ERROR);
}
@Test
public void testProcessedUnsupportedControlModify() throws Exception
{
LDAPControl assertControl = new LDAPControl("1.1.1.1.1.1", true);
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = runModifyDNOperation(getRootConnection(), "uid=user.0,ou=People,dc=example,dc=com", "uid=user.test0", false, assertControl);
examineIncompleteOperation(modifyDNOperation, UNAVAILABLE_CRITICAL_EXTENSION);
}
@Test
public void testShortCircuitModify() throws Exception
{
// Since we are going to be watching the post-response count, we need to
// wait for the server to become idle before kicking off the next request to
// ensure that any remaining post-response processing from the previous
// operation has completed.
assertTrue(DirectoryServer.getWorkQueue().waitUntilIdle(10000));
// Establish a connection to the server.
try (Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()))
{
InvocationCounterPlugin.resetAllCounters();
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
LDAPWriter w = new LDAPWriter(s);
TestCaseUtils.configureSocket(s);
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(b("cn=Directory Manager"), 3, b("password"));
LDAPMessage bindMessage = new LDAPMessage(1, bindRequest);
w.writeMessage(bindMessage);
bindMessage = r.readMessage();
BindResponseProtocolOp bindResponse = bindMessage.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
assertTrue(DirectoryServer.getWorkQueue().waitUntilIdle(10000));
InvocationCounterPlugin.resetAllCounters();
ModifyDNRequestProtocolOp modifyRequest =
new ModifyDNRequestProtocolOp(b(entry.getName().toString()), b("uid=user.test0"), false);
LDAPMessage message = new LDAPMessage(2, modifyRequest,
ShortCircuitPlugin.createShortCircuitControlList(80, "PreOperation"));
w.writeMessage(message);
message = r.readMessage();
ModifyDNResponseProtocolOp modifyResponse = message.getModifyDNResponseProtocolOp();
assertEquals(modifyResponse.getResultCode(), 80);
// assertEquals(InvocationCounterPlugin.waitForPostResponse(), 1);
}
}
@Test(groups = "slow")
public void testWriteLockModify() throws Exception
{
// We need the operation to be run in a separate thread because we are going
// to write lock the entry in the test case thread and check that the
// modify DN operation does not proceed.
// Establish a connection to the server.
try (Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()))
{
org.opends.server.tools.LDAPReader r = new org.opends.server.tools.LDAPReader(s);
LDAPWriter w = new LDAPWriter(s);
TestCaseUtils.configureSocket(s);
BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(b("cn=Directory Manager"), 3, b("password"));
LDAPMessage message = new LDAPMessage(1, bindRequest);
w.writeMessage(message);
message = r.readMessage();
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
assertEquals(bindResponse.getResultCode(), LDAPResultCode.SUCCESS);
// Since we are going to be watching the post-response count, we need to
// wait for the server to become idle before kicking off the next request
// to ensure that any remaining post-response processing from the previous
// operation has completed.
assertTrue(DirectoryServer.getWorkQueue().waitUntilIdle(10000));
final DNLock writeLock = DirectoryServer.getLockManager().tryWriteLockEntry(entry.getName());
assertNotNull(writeLock);
try
{
InvocationCounterPlugin.resetAllCounters();
//long modifyDNRequests = ldapStatistics.getModifyDNRequests();
//long modifyDNResponses = ldapStatistics.getModifyDNResponses();
ModifyDNRequestProtocolOp modifyRequest =
new ModifyDNRequestProtocolOp(b(entry.getName().toString()), b("uid=user.test0"), false);
message = new LDAPMessage(2, modifyRequest);
w.writeMessage(message);
message = r.readMessage();
ModifyDNResponseProtocolOp modifyResponse = message.getModifyDNResponseProtocolOp();
assertEquals(modifyResponse.getResultCode(), LDAPResultCode.BUSY);
// assertEquals(InvocationCounterPlugin.getPreParseCount(), 1);
// assertEquals(InvocationCounterPlugin.getPreOperationCount(), 0);
// assertEquals(InvocationCounterPlugin.getPostOperationCount(), 0);
// // The post response might not have been called yet.
// assertEquals(InvocationCounterPlugin.waitForPostResponse(), 1);
// assertEquals(ldapStatistics.getModifyDNRequests(), modifyDNRequests+1);
// assertEquals(ldapStatistics.getModifyDNResponses(),
// modifyDNResponses+1);
} finally
{
writeLock.unlock();
}
}
}
/**
* Tests performing a modify DN operation in which the new RDN contains an
* attribute type marked OBSOLETE in the server schema.
*/
@Test
public void testModifyDNWithObsoleteAttribute()
throws Exception
{
TestCaseUtils.initializeTestBackend(true);
String path = TestCaseUtils.createTempFile(
"dn: cn=schema",
"changetype: modify",
"add: attributeTypes",
"attributeTypes: ( testmodifydnwithobsoleteattribute-oid " +
"NAME 'testModifyDNWithObsoleteAttribute' OBSOLETE " +
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
"X-ORGIN 'SchemaBackendTestCase' )");
String attrName = "testmodifydnwithobsoleteattribute";
assertFalse(DirectoryServer.getSchema().hasAttributeType(attrName));
String[] args =
{
"-h", "127.0.0.1",
"-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
"-D", "cn=Directory Manager",
"-w", "password",
"-f", path
};
assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
assertTrue(DirectoryServer.getSchema().hasAttributeType(attrName));
path = TestCaseUtils.createTempFile(
"dn: cn=oldrdn,o=test",
"changetype: add",
"objectClass: top",
"objectClass: device",
"objectClass: extensibleObject",
"cn: oldrdn",
"",
"dn: cn=oldrdn,o=test",
"changetype: moddn",
"newRDN: testModifyDNWithObsoleteAttribute=foo",
"deleteOldRDN: 0"
);
args = new String[]
{
"-h", "127.0.0.1",
"-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
"-D", "cn=Directory Manager",
"-w", "password",
"-f", path
};
assertFalse(LDAPModify.mainModify(args, false, null, null) == 0);
}
/**
* Tests a subtree rename operation to ensure that subordinate modify DN
* plugins will be invoked as expected.
*/
@Test
public void testSubordinateModifyDNPluginsForSubtreeRename()
throws Exception
{
try
{
InvocationCounterPlugin.resetAllCounters();
TestCaseUtils.clearBackend("userRoot", "dc=example,dc=com");
TestCaseUtils.addEntries(
"dn: ou=People,dc=example,dc=com",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: People",
"",
"dn: uid=first.test,ou=People,dc=example,dc=com",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: first.test",
"givenName: First",
"sn: Test",
"cn: First Test",
"userPassword: Password",
"ou: People",
"",
"dn: uid=second.test,ou=People,dc=example,dc=com",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: second.test",
"givenName: Second",
"sn: Test",
"cn: Second Test",
"userPassword: Password");
assertTrue(DirectoryServer.entryExists(
dn("uid=first.test,ou=People,dc=example,dc=com")));
assertFalse(DirectoryServer.entryExists(
dn("uid=first.test,ou=Users,dc=example,dc=com")));
ModifyDNOperation modifyDNOperation =
getRootConnection().processModifyDN("ou=People,dc=example,dc=com", "ou=Users", true);
assertSuccess(modifyDNOperation);
// assertEquals(InvocationCounterPlugin.getSubordinateModifyDNCount(), 2);
assertFalse(DirectoryServer.entryExists(
dn("uid=first.test,ou=People,dc=example,dc=com")));
assertTrue(DirectoryServer.entryExists(
dn("uid=first.test,ou=Users,dc=example,dc=com")));
}
finally
{
// Other tests in this class rely on a predefined structure, so we need to
// make sure to put it back to the way it should be.
setUp();
InvocationCounterPlugin.resetAllCounters();
}
}
/**
* Tests a subtree move operation to ensure that subordinate modify DN
* plugins will be invoked as expected.
*/
@Test
public void testSubordinateModifyDNPluginsForSubtreeMove()
throws Exception
{
try
{
InvocationCounterPlugin.resetAllCounters();
TestCaseUtils.clearBackend("userRoot", "dc=example,dc=com");
TestCaseUtils.addEntries(
"dn: ou=Org 1,dc=example,dc=com",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: Org 1",
"",
"dn: ou=Org 2,dc=example,dc=com",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: Org 2",
"",
"dn: ou=Org 1.1,ou=Org 1,dc=example,dc=com",
"objectClass: top",
"objectClass: organizationalUnit",
"ou: Org 1.1",
"",
"dn: uid=first.test,ou=Org 1.1,ou=Org 1,dc=example,dc=com",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: first.test",
"givenName: First",
"sn: Test",
"cn: First Test",
"userPassword: Password",
"ou: Org 1.1",
"",
"dn: uid=second.test,ou=Org 1.1,ou=Org 1,dc=example,dc=com",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"objectClass: inetOrgPerson",
"uid: second.test",
"givenName: Second",
"sn: Test",
"cn: Second Test",
"userPassword: Password");
assertTrue(DirectoryServer.entryExists(
dn("uid=first.test,ou=Org 1.1,ou=Org 1,dc=example,dc=com")));
assertFalse(DirectoryServer.entryExists(
dn("uid=first.test,ou=Org 2.1,ou=Org 2,dc=example,dc=com")));
ModifyDNOperation modifyDNOperation =
getRootConnection().processModifyDN("ou=Org 1.1,ou=Org 1,dc=example,dc=com",
"ou=Org 2.1", true,
"ou=Org 2,dc=example,dc=com");
assertSuccess(modifyDNOperation);
// assertEquals(InvocationCounterPlugin.getSubordinateModifyDNCount(), 2);
assertFalse(DirectoryServer.entryExists(
dn("uid=first.test,ou=Org 1.1,ou=Org 1,dc=example,dc=com")));
assertTrue(DirectoryServer.entryExists(
dn("uid=first.test,ou=Org 2.1,ou=Org 2,dc=example,dc=com")));
}
finally
{
// Other tests in this class rely on a predefined structure, so we need to
// make sure to put it back to the way it should be.
setUp();
InvocationCounterPlugin.resetAllCounters();
}
}
@Test
public void testCancelBeforeStartup() throws Exception
{
InvocationCounterPlugin.resetAllCounters();
ModifyDNOperation modifyDNOperation = newModifyDNOperation(
"uid=user.invalid,ou=People,dc=example,dc=com", "uid=user.test0", true, "dc=example,dc=com");
CancelRequest cancelRequest = new CancelRequest(false,
LocalizableMessage.raw("testCancelBeforeStartup"));
modifyDNOperation.abort(cancelRequest);
modifyDNOperation.run();
assertEquals(modifyDNOperation.getResultCode(), CANCELLED);
}
/**
* Tests whether an invalid rdn is allowed during an modrdn operation.
* This test uses a valid attribute type with an empty value.
*
* @throws Exception
*/
@Test(expectedExceptions=InvalidNameException.class)
public void testInvalidModRDN() throws Exception
{
Hashtable<String,String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
String url = "ldap://localhost:" + TestCaseUtils.getServerLdapPort()
+"/dc=example,dc=com";
env.put(Context.PROVIDER_URL,url);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "cn=directory manager");
env.put(Context.SECURITY_CREDENTIALS, "password");
env.put("java.naming.ldap.deleteRDN", "true"); // default is 'true'
/* Create the initial context */
DirContext ctx = new InitialDirContext(env);
try
{
ctx.rename("uid=user.0,ou=People,dc=example,dc=com",
"uid=,ou=People,dc=example,dc=com");
}
finally
{
/* Close the context when it's done */
ctx.close();
}
}
}