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

Valery Kharseko
8 hours ago cae292bd84d7397e7ebc97ca7bd471154b7f18b9
Fix java/equals-on-unrelated-types CodeQL alerts (#781)
7 files modified
4 files added
563 ■■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/browser/NodeRefresher.java 3 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/task/DeleteEntryTask.java 3 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/DuplicateEntryPanel.java 67 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanel.java 35 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/TableViewEntryPanel.java 45 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java 3 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/util/cli/LDAPConnectionConsoleInteraction.java 26 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/guitools/controlpanel/ui/DuplicateEntryPanelTestCase.java 181 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanelTestCase.java 72 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/guitools/controlpanel/ui/TableViewEntryPanelTestCase.java 69 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/util/cli/LDAPConnectionConsoleInteractionTestCase.java 59 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/browser/NodeRefresher.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2008-2010 Sun Microsystems, Inc.
 * Portions Copyright 2012-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.guitools.controlpanel.browser;
@@ -460,7 +461,7 @@
        }
        conn = connectionPool.getConnection(url);
        remoteDn = DN.valueOf(url.getRawBaseDN());
        if (remoteDn == null || "".equals(remoteDn))
        if (remoteDn.isRootDN())
        {
          /* The referral has not a target DN specified: we
             have to use the DN of the entry that contains the
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/task/DeleteEntryTask.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2008-2010 Sun Microsystems, Inc.
 * Portions Copyright 2013-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.guitools.controlpanel.task;
@@ -315,7 +316,7 @@
      while (entryDNs.hasNext())
      {
        SearchResultEntry sr = entryDNs.readEntry();
        if (!sr.getName().equals(""))
        if (!sr.getName().isRootDN())
        {
          deleteSubtreeRecursively(conn, sr.getName(), null, toNotify);
        }
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/DuplicateEntryPanel.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2009-2010 Sun Microsystems, Inc.
 * Portions Copyright 2012-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.guitools.controlpanel.ui;
@@ -43,7 +44,10 @@
import org.forgerock.opendj.ldap.AttributeDescription;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.schema.MatchingRule;
import org.forgerock.opendj.ldap.schema.Schema;
import org.opends.guitools.controlpanel.browser.BrowserController;
import org.opends.guitools.controlpanel.browser.ConnectionWithControls;
import org.opends.guitools.controlpanel.ui.nodes.BasicNode;
@@ -342,33 +346,48 @@
  @Override
  protected String getLDIF()
  {
    String dn = this.dn.getText();
    return getLDIF(entryToDuplicate, dn.getText(), rdnAttribute, new String(password.getPassword()),
        getInfo().getServerDescriptor().getSchema());
  }
  /**
   * Returns the LDIF representation of the duplicated entry.
   *
   * @param entryToDuplicate the entry that is being duplicated.
   * @param dn the DN of the new entry.
   * @param rdnAttribute the name of the attribute used in the RDN of the entry being duplicated.
   * @param password the password typed by the user, empty if the user typed none.
   * @param schema the schema of the server, {@code null} if it could not be read.
   * @return the LDIF representation of the duplicated entry.
   */
  static String getLDIF(Entry entryToDuplicate, String dn, String rdnAttribute, String password, Schema schema)
  {
    StringBuilder sb = new StringBuilder();
    sb.append("dn: ").append(dn);
    for (Attribute attr : entryToDuplicate.getAllAttributes())
    {
      AttributeDescription attrDesc = attr.getAttributeDescription();
      String attrName = attr.getAttributeDescriptionAsString();
      if (attrDesc.equals(getUserPasswordAttributeType()))
      if (attrDesc.getAttributeType().equals(getUserPasswordAttributeType()))
      {
        sb.append("\n");
        String pwd = new String(password.getPassword());
        if (!pwd.isEmpty())
        // The password is optional: the original password must not be copied and no line at all
        // must be written when the user typed none.  Writing an empty line would terminate the
        // LDIF record and silently drop every attribute that comes after this one.
        if (!password.isEmpty())
        {
          sb.append(attrName).append(": ").append(pwd);
          sb.append("\n").append(attrName).append(": ").append(password);
        }
      }
      else if (!attrName.equalsIgnoreCase(rdnAttribute))
      {
        if (!ViewEntryPanel.isEditable(attrDesc,
            getInfo().getServerDescriptor().getSchema()))
        if (!ViewEntryPanel.isEditable(attrDesc, schema))
        {
          continue;
        }
        for (ByteString value : attr)
        {
          sb.append("\n");
          if (isBinary(attrName))
          if (Utilities.hasBinarySyntax(attrName, schema))
          {
            sb.append(attrName).append(":: ").append(value.toBase64String());
          }
@@ -392,7 +411,7 @@
          for (ByteString value : attr)
          {
            sb.append("\n");
            if (oldValue.equals(value))
            if (isRDNValue(attrDesc, value, oldValue))
            {
              sb.append(attrName).append(": ").append(newValue);
            }
@@ -407,7 +426,33 @@
    return sb.toString();
  }
  private String getFirstValue(DN dn)
  /**
   * Returns whether the provided value is the value the RDN of the entry being duplicated asserts.
   * <p>
   * The attributes used in an RDN usually have a case insensitive equality matching rule
   * ({@code cn}, {@code ou} or {@code uid} for instance) and the value stored in the entry may
   * therefore differ from the value written in the DN.  The comparison must consequently be done
   * through the equality matching rule of the attribute and not with {@link String#equals(Object)}.
   */
  private static boolean isRDNValue(AttributeDescription attrDesc, ByteString value, String rdnValue)
  {
    MatchingRule equalityMatchingRule = attrDesc.getAttributeType().getEqualityMatchingRule();
    if (equalityMatchingRule != null)
    {
      try
      {
        return equalityMatchingRule.normalizeAttributeValue(value)
            .equals(equalityMatchingRule.normalizeAttributeValue(ByteString.valueOfUtf8(rdnValue)));
      }
      catch (DecodeException e)
      {
        // The values cannot be normalized: fall back to the case insensitive comparison below.
      }
    }
    return rdnValue.equalsIgnoreCase(value.toString());
  }
  private static String getFirstValue(DN dn)
  {
    return dn.rdn().getFirstAVA().getAttributeValue().toString();
  }
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanel.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2008-2010 Sun Microsystems, Inc.
 * Portions Copyright 2013-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.guitools.controlpanel.ui;
@@ -571,15 +572,7 @@
  {
    if (OBJECTCLASS_ATTRIBUTE_TYPE_NAME.equalsIgnoreCase(attr))
    {
      int nOcs = 0;
      for (ByteString v : values)
      {
        if (!"top".equals(v))
        {
          nOcs++;
        }
      }
      return nOcs > 1 ? GridBagConstraints.NORTHWEST : GridBagConstraints.WEST;
      return countObjectClassesBesidesTop(values) > 1 ? GridBagConstraints.NORTHWEST : GridBagConstraints.WEST;
    }
    else if (isSingleValue(attr))
    {
@@ -595,6 +588,26 @@
    }
  }
  /**
   * Returns the number of object classes of an entry, not counting {@code top}.
   *
   * @param values the values of the object class attribute of the entry.
   * @return the number of object classes, not counting {@code top}.
   */
  static int countObjectClassesBesidesTop(List<ByteString> values)
  {
    int nOcs = 0;
    for (ByteString v : values)
    {
      // Object class values are case insensitive.
      if (!OC_TOP.equalsIgnoreCase(v.toString()))
      {
        nOcs++;
      }
    }
    return nOcs;
  }
  private int anchor1(List<ByteString> values)
  {
    int size = values.size();
@@ -693,7 +706,7 @@
    }
    // Handle the root entry separately: most of its attributes are operational
    // so we filter a list of hardcoded attributes.
    boolean isRootEntry = "".equals(sr.getName());
    boolean isRootEntry = sr.getName().isRootDN();
    Schema schema = getInfo().getServerDescriptor().getSchema();
    if (isRootEntry)
    {
@@ -984,7 +997,7 @@
      else if (isConfirmPassword(attrName) || isPassword(attrName))
      {
        JPasswordField pf = Utilities.createPasswordField();
        if (!"".equals(v))
        if (!v.isEmpty())
        {
          pf.setText(getPasswordStringValue(getAttributeForConfirmPasswordKey(attrName), v));
        }
opendj-server-legacy/src/main/java/org/opends/guitools/controlpanel/ui/TableViewEntryPanel.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2008-2010 Sun Microsystems, Inc.
 * Portions Copyright 2014-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.guitools.controlpanel.ui;
@@ -383,6 +384,37 @@
    return tableModel.getValues(attrName);
  }
  /**
   * Returns whether the provided attribute must be displayed as an {@link ObjectClassValue}
   * instead of as a plain list of values.
   * <p>
   * The object class descriptor cannot be built without the schema, so when the schema could not
   * be read the raw values must be displayed instead: otherwise the object class attribute would
   * not be displayed at all.
   *
   * @param attrDesc the description of the attribute.
   * @param schema the schema of the server, {@code null} if it could not be read.
   * @return {@code true} if the attribute must be displayed as an {@link ObjectClassValue},
   *         {@code false} otherwise.
   */
  static boolean isObjectClassWithSchema(AttributeDescription attrDesc, Schema schema)
  {
    return schema != null && attrDesc.getAttributeType().equals(getObjectClassAttributeType());
  }
  /**
   * Returns whether the provided attribute is one of the required attributes of the entry.
   *
   * @param requiredAttrs the names of the required attributes, in lower case.
   * @param attrDesc the description of the attribute.
   * @return {@code true} if the attribute is required, {@code false} otherwise.
   */
  static boolean isRequired(Set<String> requiredAttrs, AttributeDescription attrDesc)
  {
    // The required attributes are stored in lower case since attribute names are case insensitive.
    return requiredAttrs.contains(attrDesc.getNameOrOID().toLowerCase());
  }
  /** The table model used by the tree in the panel. */
  private class LDAPEntryTableModel extends SortableTableModel
  implements Comparator<AttributeValuePair>
@@ -596,14 +628,11 @@
      for (Attribute attr : searchResult.getAllAttributes())
      {
        AttributeDescription attrDesc = attr.getAttributeDescription();
        if (attrDesc.equals(getObjectClassAttributeType()))
        if (isObjectClassWithSchema(attrDesc, schema))
        {
          if (schema != null)
          {
            ocs = attr;
            ObjectClassValue ocValue = getObjectClassDescriptor(ocs, schema);
            allSortedValues.add(new AttributeValuePair(attrDesc, ocValue));
          }
          ocs = attr;
          ObjectClassValue ocValue = getObjectClassDescriptor(ocs, schema);
          allSortedValues.add(new AttributeValuePair(attrDesc, ocValue));
        }
        else
        {
@@ -781,7 +810,7 @@
    private boolean isRequired(AttributeValuePair value)
    {
      return requiredAttrs.contains(value.attrDesc.getNameOrOID());
      return TableViewEntryPanel.isRequired(requiredAttrs, value.attrDesc);
    }
    private boolean hasValue(AttributeValuePair value)
opendj-server-legacy/src/main/java/org/opends/server/replication/server/changelog/file/FileChangelogDB.java
@@ -12,6 +12,7 @@
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2014-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.server.replication.server.changelog.file;
@@ -983,7 +984,7 @@
    private void tracePurgeDetails(final CSN purgeCSN, final CSN oldestNotPurgedCSN, final long sleepTime)
    {
      if (purgeCSN.equals(oldestNotPurgedCSN.toStringUI()))
      if (purgeCSN.equals(oldestNotPurgedCSN))
      {
        logger.trace("Purged up to %s. "
            + "now sleeping until next purge during %s",
opendj-server-legacy/src/main/java/org/opends/server/util/cli/LDAPConnectionConsoleInteraction.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2008-2010 Sun Microsystems, Inc.
 * Portions Copyright 2011-2016 ForgeRock AS.
 * Portions Copyright 2026 3A Systems, LLC.
 */
package org.opends.server.util.cli;
@@ -1603,12 +1604,10 @@
    {
      logger.warn(ERROR_CERTIFICATE_NULL_AUTH_TYPE.get());
    }
    else
    {
      app.println(ApplicationTrustManager.Cause.NOT_TRUSTED.equals(authType)
          ? INFO_CERTIFICATE_NOT_TRUSTED_TEXT_CLI.get(host, port)
          : INFO_CERTIFICATE_NAME_MISMATCH_TEXT_CLI.get(host, port, host, host, port));
    }
    // The explanation only depends on the cause of the rejection, so it must be displayed even
    // when the authentication type is unknown: otherwise the user is prompted to accept a
    // certificate without being told what is wrong with it.
    app.println(getCertificateRejectionMessage(cause, host, port));
    final X509Certificate[] chain = usedTrustManager.getLastRefusedChain();
    if (chain == null)
@@ -1625,6 +1624,21 @@
  }
  /**
   * Returns the message explaining why the certificate presented by the server was rejected.
   *
   * @param cause the reason why the certificate was rejected.
   * @param host the host name of the server.
   * @param port the port of the server.
   * @return the message explaining why the certificate was rejected.
   */
  static LocalizableMessage getCertificateRejectionMessage(ApplicationTrustManager.Cause cause, String host, int port)
  {
    return cause == ApplicationTrustManager.Cause.NOT_TRUSTED
        ? INFO_CERTIFICATE_NOT_TRUSTED_TEXT_CLI.get(host, port)
        : INFO_CERTIFICATE_NAME_MISMATCH_TEXT_CLI.get(host, port, host, host, port);
  }
  /**
   * Sets the heading that is displayed in interactive mode.
   *
   * @param heading
opendj-server-legacy/src/test/java/org/opends/guitools/controlpanel/ui/DuplicateEntryPanelTestCase.java
New file
@@ -0,0 +1,181 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions copyright [year] [name of copyright owner]".
 *
 * Copyright 2026 3A Systems, LLC.
 */
package org.opends.guitools.controlpanel.ui;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.LinkedHashMapEntry;
import org.forgerock.opendj.ldap.schema.Schema;
import org.forgerock.opendj.ldif.LDIFEntryReader;
import org.opends.server.DirectoryServerTestCase;
import org.testng.annotations.Test;
/** Tests the LDIF generated by {@link DuplicateEntryPanel}. */
@SuppressWarnings("javadoc")
public class DuplicateEntryPanelTestCase extends DirectoryServerTestCase
{
  private static final Schema SCHEMA = Schema.getCoreSchema();
  private static final String NEW_DN = "uid=user.2,ou=people,dc=example,dc=com";
  /** An entry whose RDN attribute is single valued and which holds a password. */
  private static Entry userEntry()
  {
    return new LinkedHashMapEntry(
        "dn: uid=user.1,ou=people,dc=example,dc=com",
        "objectClass: top",
        "objectClass: person",
        "objectClass: organizationalPerson",
        "objectClass: inetOrgPerson",
        "uid: user.1",
        "userPassword: {SSHA}originalHashOfTheEntryBeingDuplicated",
        "cn: User 1",
        "sn: One");
  }
  /**
   * When the user types no password, the original password must not be copied and no empty line
   * must be written: an empty line terminates the LDIF record and every attribute written after
   * the password would be silently dropped.
   */
  @Test
  public void testEmptyPasswordDoesNotTruncateTheEntry() throws Exception
  {
    String ldif = DuplicateEntryPanel.getLDIF(userEntry(), NEW_DN, "uid", "", SCHEMA);
    assertThat(ldif).doesNotContain("\n\n");
    Entry duplicate = readEntry(ldif);
    assertThat((Object) duplicate.getName()).isEqualTo(DN.valueOf(NEW_DN));
    assertThat(valuesOf(duplicate, "userPassword")).isEmpty();
    assertThat(valuesOf(duplicate, "objectClass"))
        .containsExactly("top", "person", "organizationalPerson", "inetOrgPerson");
    assertThat(valuesOf(duplicate, "uid")).containsExactly("user.2");
    assertThat(valuesOf(duplicate, "cn")).containsExactly("User 1");
    assertThat(valuesOf(duplicate, "sn")).containsExactly("One");
  }
  /** The password of the duplicated entry is the one typed by the user, not the original hash. */
  @Test
  public void testTypedPasswordReplacesTheOriginalOne() throws Exception
  {
    String ldif = DuplicateEntryPanel.getLDIF(userEntry(), NEW_DN, "uid", "typedPassword", SCHEMA);
    Entry duplicate = readEntry(ldif);
    assertThat(valuesOf(duplicate, "userPassword")).containsExactly("typedPassword");
    assertThat(valuesOf(duplicate, "sn")).containsExactly("One");
  }
  /** The value of the RDN of the new entry replaces the value of the RDN of the original entry. */
  @Test
  public void testSingleValuedRDNAttributeUsesTheNewValue() throws Exception
  {
    String ldif = DuplicateEntryPanel.getLDIF(userEntry(), NEW_DN, "uid", "", SCHEMA);
    assertThat(valuesOf(readEntry(ldif), "uid")).containsExactly("user.2");
  }
  /**
   * The attributes used in an RDN have a case insensitive equality matching rule, so the value
   * stored in the entry may differ from the value written in the DN. The old value must be
   * replaced nonetheless, otherwise the duplicated entry keeps the value of the original RDN.
   */
  @Test
  public void testMultiValuedRDNAttributeReplacesTheOldValueCaseInsensitively() throws Exception
  {
    Entry entry = new LinkedHashMapEntry(
        "dn: cn=John Smith,ou=people,dc=example,dc=com",
        "objectClass: top",
        "objectClass: person",
        "cn: john smith",
        "cn: Johnny",
        "sn: Smith");
    String ldif = DuplicateEntryPanel.getLDIF(entry, "cn=John Smith-1,ou=people,dc=example,dc=com", "cn", "", SCHEMA);
    assertThat(valuesOf(readEntry(ldif), "cn")).containsExactlyInAnyOrder("John Smith-1", "Johnny");
  }
  /** Attributes the user cannot modify must not be copied into the duplicated entry. */
  @Test
  public void testNoUserModificationAttributesAreNotCopied() throws Exception
  {
    Entry entry = new LinkedHashMapEntry(
        "dn: uid=user.1,ou=people,dc=example,dc=com",
        "objectClass: top",
        "objectClass: person",
        "uid: user.1",
        "createTimestamp: 20260101000000Z",
        "sn: One");
    String ldif = DuplicateEntryPanel.getLDIF(entry, NEW_DN, "uid", "", SCHEMA);
    Entry duplicate = readEntry(ldif);
    assertThat(valuesOf(duplicate, "createTimestamp")).isEmpty();
    assertThat(valuesOf(duplicate, "sn")).containsExactly("One");
  }
  /** Attributes with a binary syntax must be base64 encoded. */
  @Test
  public void testBinaryAttributesAreBase64Encoded() throws Exception
  {
    Entry entry = new LinkedHashMapEntry(DN.valueOf("uid=user.1,ou=people,dc=example,dc=com"))
        .addAttribute("objectClass", "top", "person")
        .addAttribute("uid", "user.1")
        .addAttribute("sn", "One")
        .addAttribute("userCertificate", ByteString.wrap(new byte[] { 0x30, 0x00, (byte) 0xFF }));
    String ldif = DuplicateEntryPanel.getLDIF(entry, NEW_DN, "uid", "", SCHEMA);
    // "MAD/" is the base64 encoding of the three bytes above.
    assertThat(ldif).contains("userCertificate:: MAD/");
    assertThat(valuesOf(readEntry(ldif), "sn")).containsExactly("One");
  }
  /**
   * Reads the generated LDIF the same way {@code AbstractNewEntryPanel.getEntry()} does: an empty
   * line terminates the record, so anything written after one is not part of the entry that is
   * added to the server.
   */
  private static Entry readEntry(String ldif) throws IOException
  {
    try (LDIFEntryReader reader = new LDIFEntryReader(new StringReader(ldif)))
    {
      return reader.readEntry();
    }
  }
  private static List<String> valuesOf(Entry entry, String attrName)
  {
    List<String> values = new ArrayList<>();
    Attribute attr = entry.getAttribute(attrName);
    if (attr != null)
    {
      for (ByteString value : attr)
      {
        values.add(value.toString());
      }
    }
    return values;
  }
}
opendj-server-legacy/src/test/java/org/opends/guitools/controlpanel/ui/SimplifiedViewEntryPanelTestCase.java
New file
@@ -0,0 +1,72 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions copyright [year] [name of copyright owner]".
 *
 * Copyright 2026 3A Systems, LLC.
 */
package org.opends.guitools.controlpanel.ui;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.forgerock.opendj.ldap.ByteString;
import org.opends.server.DirectoryServerTestCase;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/** Tests the object class counting done by {@link SimplifiedViewEntryPanel}. */
@SuppressWarnings("javadoc")
public class SimplifiedViewEntryPanelTestCase extends DirectoryServerTestCase
{
  @DataProvider
  public Object[][] objectClassValues()
  {
    return new Object[][] {
      { Collections.<String> emptyList(), 0 },
      { list("top"), 0 },
      // Object class values are case insensitive: "top" must be filtered out whatever its case is.
      { list("TOP"), 0 },
      { list("Top"), 0 },
      { list("top", "person"), 1 },
      { list("TOP", "person"), 1 },
      { list("top", "person", "organizationalPerson"), 2 },
      { list("person", "organizationalPerson"), 2 },
    };
  }
  @Test(dataProvider = "objectClassValues")
  public void testCountObjectClassesBesidesTop(List<String> objectClasses, int expectedCount)
  {
    assertThat(SimplifiedViewEntryPanel.countObjectClassesBesidesTop(byteStrings(objectClasses)))
        .isEqualTo(expectedCount);
  }
  private static List<String> list(String... values)
  {
    List<String> result = new ArrayList<>();
    Collections.addAll(result, values);
    return result;
  }
  private static List<ByteString> byteStrings(List<String> values)
  {
    List<ByteString> result = new ArrayList<>();
    for (String value : values)
    {
      result.add(ByteString.valueOfUtf8(value));
    }
    return result;
  }
}
opendj-server-legacy/src/test/java/org/opends/guitools/controlpanel/ui/TableViewEntryPanelTestCase.java
New file
@@ -0,0 +1,69 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions copyright [year] [name of copyright owner]".
 *
 * Copyright 2026 3A Systems, LLC.
 */
package org.opends.guitools.controlpanel.ui;
import static org.assertj.core.api.Assertions.assertThat;
import static org.opends.server.util.CollectionUtils.newHashSet;
import java.util.Set;
import org.forgerock.opendj.ldap.AttributeDescription;
import org.forgerock.opendj.ldap.schema.Schema;
import org.opends.server.DirectoryServerTestCase;
import org.testng.annotations.Test;
/** Tests how {@link TableViewEntryPanel} decides what to display for a given attribute. */
@SuppressWarnings("javadoc")
public class TableViewEntryPanelTestCase extends DirectoryServerTestCase
{
  private static final Schema SCHEMA = Schema.getCoreSchema();
  private static final AttributeDescription OBJECT_CLASS = AttributeDescription.valueOf("objectClass", SCHEMA);
  @Test
  public void testObjectClassIsDisplayedAsADescriptorWhenTheSchemaIsAvailable()
  {
    assertThat(TableViewEntryPanel.isObjectClassWithSchema(OBJECT_CLASS, SCHEMA)).isTrue();
  }
  /**
   * The object class descriptor cannot be built without the schema: the raw values must then be
   * displayed instead, otherwise the object class attribute disappears from the table.
   */
  @Test
  public void testObjectClassFallsBackToItsRawValuesWithoutSchema()
  {
    assertThat(TableViewEntryPanel.isObjectClassWithSchema(OBJECT_CLASS, null)).isFalse();
  }
  @Test
  public void testOtherAttributesAreNeverDisplayedAsADescriptor()
  {
    assertThat(TableViewEntryPanel.isObjectClassWithSchema(AttributeDescription.valueOf("cn", SCHEMA), SCHEMA))
        .isFalse();
  }
  /** Attribute names are case insensitive, and the required attributes are stored in lower case. */
  @Test
  public void testRequiredAttributesAreMatchedCaseInsensitively()
  {
    Set<String> requiredAttrs = newHashSet("objectclass", "sn", "cn");
    assertThat(TableViewEntryPanel.isRequired(requiredAttrs, OBJECT_CLASS)).isTrue();
    assertThat(TableViewEntryPanel.isRequired(requiredAttrs, AttributeDescription.valueOf("sn", SCHEMA))).isTrue();
    assertThat(TableViewEntryPanel.isRequired(requiredAttrs, AttributeDescription.valueOf("description", SCHEMA)))
        .isFalse();
  }
}
opendj-server-legacy/src/test/java/org/opends/server/util/cli/LDAPConnectionConsoleInteractionTestCase.java
New file
@@ -0,0 +1,59 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions copyright [year] [name of copyright owner]".
 *
 * Copyright 2026 3A Systems, LLC.
 */
package org.opends.server.util.cli;
import static org.assertj.core.api.Assertions.assertThat;
import static org.opends.messages.ToolMessages.INFO_CERTIFICATE_NAME_MISMATCH_TEXT_CLI;
import static org.opends.messages.ToolMessages.INFO_CERTIFICATE_NOT_TRUSTED_TEXT_CLI;
import org.opends.admin.ads.util.ApplicationTrustManager;
import org.opends.server.DirectoryServerTestCase;
import org.testng.annotations.Test;
/** Tests the message shown when the certificate presented by a server is rejected. */
@SuppressWarnings("javadoc")
public class LDAPConnectionConsoleInteractionTestCase extends DirectoryServerTestCase
{
  private static final String HOST = "localhost";
  private static final int PORT = 4444;
  @Test
  public void testUntrustedCertificateIsReported()
  {
    assertThat(rejectionMessage(ApplicationTrustManager.Cause.NOT_TRUSTED))
        .isEqualTo(INFO_CERTIFICATE_NOT_TRUSTED_TEXT_CLI.get(HOST, PORT).toString());
  }
  @Test
  public void testHostNameMismatchIsReported()
  {
    assertThat(rejectionMessage(ApplicationTrustManager.Cause.HOST_NAME_MISMATCH))
        .isEqualTo(INFO_CERTIFICATE_NAME_MISMATCH_TEXT_CLI.get(HOST, PORT, HOST, HOST, PORT).toString());
  }
  /** The two causes must not lead to the same message: the user needs to know what is wrong. */
  @Test
  public void testTheTwoCausesAreReportedDifferently()
  {
    assertThat(rejectionMessage(ApplicationTrustManager.Cause.NOT_TRUSTED))
        .isNotEqualTo(rejectionMessage(ApplicationTrustManager.Cause.HOST_NAME_MISMATCH));
  }
  private static String rejectionMessage(ApplicationTrustManager.Cause cause)
  {
    return LDAPConnectionConsoleInteraction.getCertificateRejectionMessage(cause, HOST, PORT).toString();
  }
}