mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Valery Kharseko
yesterday 2b2f34cd5875a0f76a7a20862c1b59bc3ccfa50e
[#1023] Delete every objectClass value a modification asks for (#1024)
3 files modified
162 ■■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/server/types/Entry.java 14 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/core/ModifyOperationTestCase.java 85 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/types/TestEntry.java 63 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/types/Entry.java
@@ -1323,27 +1323,33 @@
      return true;
    }
    boolean allSuccessful = true;
    // The objectClass attribute is present as soon as the entry has an object class: a value of
    // the modification which the entry does not have is a missing value, not an absent attribute.
    boolean attributeTypePresent = !objectClasses.isEmpty();
    MatchingRule rule = attrType.getEqualityMatchingRule();
    for (ByteString v : attribute)
    {
      String ocName = toLowerName(rule, v);
      boolean matchFound = false;
      for (ObjectClass oc : objectClasses.keySet())
      {
        if (oc.hasNameOrOID(ocName))
        {
          objectClasses.remove(oc);
          return true;
          matchFound = true;
          break;
        }
      }
      allSuccessful = false;
      if (!matchFound)
      {
      missingValues.add(v);
    }
    }
    return allSuccessful;
    return attributeTypePresent;
  }
  private boolean removeNonObjectClassAttribute(Attribute attribute, Collection<? super ByteString> missingValues)
opendj-server-legacy/src/test/java/org/opends/server/core/ModifyOperationTestCase.java
@@ -2136,6 +2136,91 @@
  /**
   * Adds the entry the object class deletes below work on: two auxiliary classes which the entry
   * can lose without breaking the schema.
   */
  private void addUserWithTwoAuxiliaryObjectClasses(String baseDN) throws Exception
  {
    TestCaseUtils.addEntry(
         "dn: uid=test.user," + baseDN,
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "objectClass: uidObject",
         "objectClass: userSecurityInformation",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User");
  }
  private void assertObjectClassesAre(String baseDN, String... objectClasses) throws Exception
  {
    Entry e = DirectoryServer.getEntry(DN.valueOf("uid=test.user," + baseDN));
    assertThat(e.getObjectClasses().values()).containsOnly(objectClasses);
  }
  /**
   * A delete of several object class values must remove every one of them, not just the first
   * (see issue #1023).
   */
  @Test(dataProvider = "baseDNs")
  public void testSuccessRemoveSeveralObjectClassValues(String baseDN) throws Exception
  {
    addUserWithTwoAuxiliaryObjectClasses(baseDN);
    RawModification mod =
        newRawModification(DELETE, "objectClass", "uidObject", "userSecurityInformation");
    ModifyOperation modifyOperation = processModify("uid=test.user," + baseDN, mod);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    retrieveSuccessfulOperationElements(modifyOperation);
    assertObjectClassesAre(baseDN, "top", "person", "organizationalPerson", "inetOrgPerson");
  }
  /**
   * A delete of several object class values one of which the entry does not have must name that
   * value: the objectClass attribute itself is there, so this is a missing value and not an
   * absent attribute.
   */
  @Test(dataProvider = "baseDNs")
  public void testFailRemoveSeveralObjectClassValuesOneOfWhichIsMissing(String baseDN)
         throws Exception
  {
    addUserWithTwoAuxiliaryObjectClasses(baseDN);
    RawModification mod = newRawModification(DELETE, "objectClass", "uidObject", "domain");
    ModifyOperation modifyOperation = processModify("uid=test.user," + baseDN, mod);
    assertEquals(modifyOperation.getResultCode(), ResultCode.NO_SUCH_ATTRIBUTE);
    assertThat(modifyOperation.getErrorMessage().toString()).contains("domain");
    retrieveFailedOperationElements(modifyOperation);
    assertObjectClassesAre(baseDN, "top", "person", "organizationalPerson", "inetOrgPerson",
        "uidObject", "userSecurityInformation");
  }
  /**
   * The permissive modify control drops the object class value which the entry does not have, and
   * the values it does have are all removed.
   */
  @Test(dataProvider = "baseDNs")
  public void testSuccessPermissiveModifyControlRemoveSeveralObjectClassValuesOneMissing(
      String baseDN) throws Exception
  {
    addUserWithTwoAuxiliaryObjectClasses(baseDN);
    ModifyRequest modifyRequest = Requests.newModifyRequest("uid=test.user," + baseDN)
        .addModification(DELETE, "objectClass", "uidObject", "domain", "userSecurityInformation")
        .addControl(newControl(OID_PERMISSIVE_MODIFY_CONTROL));
    ModifyOperation modifyOperation = getRootConnection().processModify(modifyRequest);
    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
    retrieveSuccessfulOperationElements(modifyOperation);
    assertObjectClassesAre(baseDN, "top", "person", "organizationalPerson", "inetOrgPerson");
  }
  /**
   * Tests the ability to perform a modification that adds an auxiliary
   * objectclass.
   *
opendj-server-legacy/src/test/java/org/opends/server/types/TestEntry.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2006-2008 Sun Microsystems, Inc.
 * Portions Copyright 2011-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.server.types;
@@ -26,6 +27,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -108,6 +110,67 @@
    TestCaseUtils.startServer();
  }
  /** Returns an entry to delete object class values from. */
  private Entry newTestUserEntry() throws Exception
  {
    return TestCaseUtils.makeEntry(
        "dn: cn=Test User,ou=People,dc=example,dc=com",
        "objectClass: top",
        "objectClass: person",
        "objectClass: organizationalPerson",
        "objectClass: inetOrgPerson",
        "cn: Test User",
        "sn: User");
  }
  /**
   * A delete of several object class values must remove every one of them, the way a delete of
   * several values of any other attribute does.
   */
  @Test
  public void testRemoveSeveralObjectClassValues() throws Exception
  {
    Entry e = newTestUserEntry();
    List<ByteString> missingValues = new LinkedList<>();
    assertTrue(e.removeAttribute(
        Attributes.create("objectClass", "organizationalPerson", "inetOrgPerson"), missingValues));
    assertThat(missingValues).isEmpty();
    assertThat(e.getObjectClasses().values()).containsOnly("top", "person");
  }
  /**
   * A delete of an object class value which the entry does not have must be reported as a missing
   * value, whatever the other values of the same modification are.
   */
  @Test
  public void testRemoveObjectClassValuesOneOfWhichIsMissing() throws Exception
  {
    Entry e = newTestUserEntry();
    List<ByteString> missingValues = new LinkedList<>();
    assertTrue(e.removeAttribute(
        Attributes.create("objectClass", "inetOrgPerson", "domain"), missingValues));
    assertThat(missingValues).containsOnly(ByteString.valueOfUtf8("domain"));
    assertThat(e.getObjectClasses().values()).containsOnly("top", "person", "organizationalPerson");
  }
  /** The same, with the missing value first: the walk must not stop at it. */
  @Test
  public void testRemoveObjectClassValuesTheFirstOfWhichIsMissing() throws Exception
  {
    Entry e = newTestUserEntry();
    List<ByteString> missingValues = new LinkedList<>();
    assertTrue(e.removeAttribute(
        Attributes.create("objectClass", "domain", "inetOrgPerson"), missingValues));
    assertThat(missingValues).containsOnly(ByteString.valueOfUtf8("domain"));
    assertThat(e.getObjectClasses().values()).containsOnly("top", "person", "organizationalPerson");
  }
  /**
   * Test the {@link Entry#parseAttribute(String)} method.
   */