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

6 files modified
2 files added
360 ■■■■■ changed files
.github/workflows/build.yml 20 ●●●●● patch | view | raw | blame | history
opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Utils.java 32 ●●●●● patch | view | raw | blame | history
opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/ControlArgumentTestCase.java 134 ●●●●● patch | view | raw | blame | history
opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/LDAPSearchTestCase.java 12 ●●●●● patch | view | raw | blame | history
opendj-openidm-account-change-notification-handler/pom.xml 7 ●●●●● patch | view | raw | blame | history
opendj-openidm-account-change-notification-handler/src/main/java/org/forgerock/openidm/accountchange/OpenidmAccountStatusNotificationHandler.java 40 ●●●●● patch | view | raw | blame | history
opendj-openidm-account-change-notification-handler/src/test/java/org/forgerock/openidm/accountchange/OpenidmAccountStatusNotificationHandlerTestCase.java 113 ●●●●● patch | view | raw | blame | history
opendj-packages/opendj-docker/bootstrap/setup.sh 2 ●●●●● patch | view | raw | blame | history
.github/workflows/build.yml
@@ -564,6 +564,16 @@
          timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test_custom | grep -q \"healthy\"; do sleep 10; done'
          docker exec test_custom 'sh' '-c' '/opt/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword custom_password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1'
          docker kill test_custom
      - name: Docker test base DN with a space
        # the shell must hand the base DN to dsconfig as one value, or the bootstrap stops at
        # "creating backend" (#1157)
        shell: bash
        run: |
          trap 'code=$?; echo "::group::container logs (test_base_dn)"; docker logs test_base_dn 2>&1 || true; echo "::endgroup::"; exit $code' ERR
          docker run --rm -it -d --memory="512m" -e ADD_BASE_ENTRY="--addBaseEntry" -e BASE_DN="o=My Company,c=US" --name=test_base_dn localhost:5000/${GITHUB_REPOSITORY,,}:${{ env.release_version }}
          timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test_base_dn | grep -q \"healthy\"; do sleep 10; done'
          docker exec test_base_dn 'sh' '-c' '/opt/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "o=My Company,c=US" --searchScope base "(objectClass=*)" 1.1 | grep -qx "dn: o=My Company,c=US"'
          docker kill test_base_dn
      - name: Docker test arbitrary uid
        # OpenShift runs a container under an arbitrary uid that is only in group 0 (#1088)
        shell: bash
@@ -1010,6 +1020,16 @@
          timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test_custom | grep -q \"healthy\"; do sleep 10; done'
          docker exec test_custom 'sh' '-c' '/opt/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword custom_password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1'
          docker kill test_custom
      - name: Docker test base DN with a space
        # the shell must hand the base DN to dsconfig as one value, or the bootstrap stops at
        # "creating backend" (#1157)
        shell: bash
        run: |
          trap 'code=$?; echo "::group::container logs (test_base_dn)"; docker logs test_base_dn 2>&1 || true; echo "::endgroup::"; exit $code' ERR
          docker run --rm -it -d --memory="1g" -e ADD_BASE_ENTRY="--addBaseEntry" -e BASE_DN="o=My Company,c=US" --name=test_base_dn localhost:5000/${GITHUB_REPOSITORY,,}:${{ env.release_version }}-alpine
          timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test_base_dn | grep -q \"healthy\"; do sleep 10; done'
          docker exec test_base_dn 'sh' '-c' '/opt/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "o=My Company,c=US" --searchScope base "(objectClass=*)" 1.1 | grep -qx "dn: o=My Company,c=US"'
          docker kill test_base_dn
      - name: Docker test arbitrary uid
        # OpenShift runs a container under an arbitrary uid that is only in group 0 (#1088)
        shell: bash
opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/Utils.java
@@ -18,8 +18,10 @@
 */
package com.forgerock.opendj.ldap.tools;
import static com.forgerock.opendj.cli.ArgumentConstants.OPTION_LONG_CONTROL;
import static com.forgerock.opendj.cli.ArgumentConstants.USE_SYSTEM_STREAM_TOKEN;
import static com.forgerock.opendj.cli.CliConstants.NO_WRAPPING_BY_DEFAULT;
import static com.forgerock.opendj.cli.CliMessages.ERR_FILEARG_CANNOT_READ_FILE;
import static com.forgerock.opendj.cli.Utils.filterExitCode;
import static com.forgerock.opendj.cli.Utils.readBytesFromFile;
import static com.forgerock.opendj.cli.Utils.secondsToTimeString;
@@ -313,19 +315,21 @@
    /**
     * Parse the specified command line argument to create the appropriate
     * LDAPControl. The argument string should be in the format
     * controloid[:criticality[:value|::b64value|:<fileurl]]
     * controloid[:criticality[:value|::b64value|:<filePath]]
     * <p>
     * Everything after the second colon is the value, so the value, the
     * base64 string and the file path may all contain colons.
     *
     * @param argString
     *            The argument string containing the encoded control
     *            information.
     * @return The control decoded from the provided string, or
     *         <CODE>null</CODE> if an error occurs while parsing the argument
     *         value.
     * @return The control decoded from the provided string.
     * @throws org.forgerock.opendj.ldap.DecodeException
     *             If an error occurs.
     *             If the criticality is invalid, the base64 value cannot be
     *             decoded or the file cannot be read.
     */
    private static GenericControl getControl(final String argString) throws DecodeException {
        final String[] control = argString.split(":");
        final String[] control = argString.split(":", 3);
        final int nbControlElements = control.length;
        final String controlOID = readControlID(control[0]);
@@ -339,14 +343,20 @@
        }
        final ByteString controlValue;
        if (control[2].isEmpty()) {
            controlValue = ByteString.valueOfBase64(control[3]);
        if (control[2].startsWith(":")) {
            try {
                controlValue = ByteString.valueOfBase64(control[2].substring(1));
            } catch (final LocalizedIllegalArgumentException e) {
                throw DecodeException.error(e.getMessageObject(), e);
            }
        } else if (control[2].startsWith("<")) {
            // Read data from the file.
            final String filePath = control[2].substring(1);
            try {
                controlValue = ByteString.wrap(readBytesFromFile(control[2].substring(1)));
            } catch (final Exception e) {
                return null;
                controlValue = ByteString.wrap(readBytesFromFile(filePath));
            } catch (final IOException e) {
                throw DecodeException.error(
                        ERR_FILEARG_CANNOT_READ_FILE.get(filePath, OPTION_LONG_CONTROL, e.getMessage()), e);
            }
        } else {
            controlValue = ByteString.valueOfUtf8(control[2]);
opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/ControlArgumentTestCase.java
New file
@@ -0,0 +1,134 @@
/*
 * 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 com.forgerock.opendj.ldap.tools;
import static com.forgerock.opendj.ldap.tools.ToolsMessages.ERR_TOOL_INVALID_CONTROL_STRING;
import static com.forgerock.opendj.util.OperatingSystem.isWindows;
import static org.fest.assertions.Assertions.assertThat;
import static org.testng.Assert.fail;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.controls.Control;
import org.forgerock.testng.ForgeRockTestCase;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.forgerock.opendj.cli.CommonArguments;
import com.forgerock.opendj.cli.StringArgument;
/** Tests the parsing of the {@code -J/--control} argument by {@link Utils#readControls(StringArgument)}. */
@Test
public final class ControlArgumentTestCase extends ForgeRockTestCase {
    @DataProvider
    public Object[][] validControls() {
        return new Object[][] {
            { "1.2.3.4", "1.2.3.4", false, null },
            { "1.2.3.4:true", "1.2.3.4", true, null },
            { "1.2.3.4:FALSE:value", "1.2.3.4", false, "value" },
            { "1.2.3.4:true:", "1.2.3.4", true, "" },
            { "pwpolicy:true", "1.3.6.1.4.1.42.2.27.8.5.1", true, null },
            // Everything after the second colon is the value, colons included.
            { "2.16.840.1.113730.3.4.18:true:dn:uid=bjensen,ou=People,dc=example,dc=com",
              "2.16.840.1.113730.3.4.18", true, "dn:uid=bjensen,ou=People,dc=example,dc=com" },
            { "2.16.840.1.113730.3.4.18:true:u:bjensen", "2.16.840.1.113730.3.4.18", true, "u:bjensen" },
            { "1.2.3.4:false:urn:example:value", "1.2.3.4", false, "urn:example:value" },
            { "1.2.3.4:false:ldap://host:1389/dc=example", "1.2.3.4", false, "ldap://host:1389/dc=example" },
            // The base64 form decodes to a value that can itself hold colons.
            { "1.2.3.4:true::" + base64("dn:uid=bjensen"), "1.2.3.4", true, "dn:uid=bjensen" },
            { "1.2.3.4:true::", "1.2.3.4", true, "" },
        };
    }
    @Test(dataProvider = "validControls")
    public void testValidControl(final String argument, final String oid, final boolean critical,
            final String value) throws Exception {
        final Control control = readSingleControl(argument);
        assertThat(control.getOID()).isEqualTo(oid);
        assertThat(control.isCritical()).isEqualTo(critical);
        if (value == null) {
            assertThat(control.hasValue()).isFalse();
        } else {
            assertThat(control.hasValue()).isTrue();
            assertThat(control.getValue().toString()).isEqualTo(value);
        }
    }
    @Test
    public void testValueReadFromFileWhosePathHoldsAColon() throws Exception {
        // On Windows the drive letter puts a colon in every absolute path; elsewhere the file name carries one.
        final File dir = Files.createTempDirectory("control-value").toFile();
        final File file = new File(dir, isWindows() ? "control-value.ber" : "control:value.ber");
        try {
            final byte[] bytes = { 0x04, 0x03, 'a', ':', 'b' };
            Files.write(file.toPath(), bytes);
            final Control control = readSingleControl("1.2.3.4:true:<" + file.getAbsolutePath());
            assertThat(control.getOID()).isEqualTo("1.2.3.4");
            assertThat(control.isCritical()).isTrue();
            assertThat(control.getValue()).isEqualTo(ByteString.wrap(bytes));
        } finally {
            file.delete();
            dir.delete();
        }
    }
    @DataProvider
    public Object[][] invalidControls() {
        final String missingFile = new File(System.getProperty("java.io.tmpdir"), "no-such-dir-1156/value.ber")
                .getAbsolutePath();
        return new Object[][] {
            { "1.2.3.4:invalidcriticality" },
            { "1.2.3.4:invalidcriticality:value" },
            { "1.2.3.4:true:<" + missingFile },
            { "1.2.3.4:true::not*base64" },
        };
    }
    @Test(dataProvider = "invalidControls")
    public void testInvalidControlIsReportedAsAnInvalidControlString(final String argument) throws Exception {
        try {
            readControls(argument);
            fail("Expected the control '" + argument + "' to be rejected");
        } catch (final LDAPToolException e) {
            assertThat(e.getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue());
            assertThat(e.getMessage()).isEqualTo(ERR_TOOL_INVALID_CONTROL_STRING.get(argument).toString());
        }
    }
    private static Control readSingleControl(final String argument) throws Exception {
        final List<Control> controls = readControls(argument);
        assertThat(controls).hasSize(1);
        return controls.get(0);
    }
    private static List<Control> readControls(final String argument) throws Exception {
        final StringArgument controlArg = CommonArguments.controlArgument();
        controlArg.addValue(argument);
        controlArg.setPresent(true);
        return Utils.readControls(controlArg);
    }
    private static String base64(final String value) {
        return ByteString.valueOfBytes(value.getBytes(StandardCharsets.UTF_8)).toBase64String();
    }
}
opendj-ldap-toolkit/src/test/java/com/forgerock/opendj/ldap/tools/LDAPSearchTestCase.java
@@ -12,6 +12,7 @@
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 *  Copyright 2016 ForgeRock AS.
 *  Portions Copyright 2026 3A Systems, LLC.
 */
package com.forgerock.opendj.ldap.tools;
@@ -142,6 +143,11 @@
        argLists.add(args("-b", "", "-J", "1.2.3.4:invalidcriticality", "(objectClass=*)"));
        reasonList.add(ERR_TOOL_INVALID_CONTROL_STRING.get("1.2.3.4:invalidcriticality"));
        argLists.add(args("-b", "", "-J", "1.2.3.4:true:<src/test/resources/no-such-control-value.ber",
                          "(objectClass=*)"));
        reasonList.add(ERR_TOOL_INVALID_CONTROL_STRING.get(
                "1.2.3.4:true:<src/test/resources/no-such-control-value.ber"));
        argLists.add(args("-b", "", "-s", "invalid", "(objectClass=*)"));
        reasonList.add(ERR_MCARG_VALUE_NOT_ALLOWED.get("searchScope", "invalid"));
@@ -236,6 +242,12 @@
    }
    @Test
    public void testLdapSearchWithControlValueHoldingColons() throws Exception {
        controls.add(ProxiedAuthV2RequestControl.newControl("dn:uid=bjensen,ou=People,dc=example,dc=com"));
        runToolOnMockedServer("-J", "2.16.840.1.113730.3.4.18:true:dn:uid=bjensen,ou=People,dc=example,dc=com");
    }
    @Test
    public void testLdapSearchWithSimplePaged() throws Exception {
        controls.add(SimplePagedResultsControl.newControl(true, 10, ByteString.empty()));
        runToolOnMockedServer("--simplePageSize", "10");
opendj-openidm-account-change-notification-handler/pom.xml
@@ -70,6 +70,13 @@
      <groupId>org.openidentityplatform.commons.http-framework</groupId>
      <artifactId>client-apache-async</artifactId>
    </dependency>
    <!-- Test dependencies (TestNG is inherited from the parent, BouncyCastle comes with opendj-server-legacy) -->
    <dependency>
      <groupId>org.openidentityplatform.commons</groupId>
      <artifactId>build-tools</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  
  <build><finalName>${project.groupId}.${project.artifactId}</finalName>
opendj-openidm-account-change-notification-handler/src/main/java/org/forgerock/openidm/accountchange/OpenidmAccountStatusNotificationHandler.java
@@ -337,14 +337,44 @@
            OpenidmAccountStatusNotificationHandlerCfg configuration) throws ConfigException {
        X509TrustManager trustMgr = (X509TrustManager) trustMgrs[0];
        String serverCertSubject = configuration.getCertificateSubjectDN().toString();
        for (X509Certificate cert : trustMgr.getAcceptedIssuers()) {
            String subjectX500Principal = cert.getSubjectX500Principal().getName(X500Principal.CANONICAL);
            if (serverCertSubject.equalsIgnoreCase(subjectX500Principal)) {
        DN serverCertSubject = configuration.getCertificateSubjectDN();
        X509Certificate cert = findCertificateBySubject(serverCertSubject, trustMgr.getAcceptedIssuers());
        if (cert == null) {
            throw new ConfigException(ERR_OPENIDM_PWSYNC_INVALID_SERVERKEYALIAS.get(serverCertSubject));
        }
        return cert;
    }
    /**
     * Returns the certificate whose subject is the provided DN.
     * <p>
     * Names are compared, not strings: {@code DN.toString()} and the JDK's canonical form serialise the same
     * name differently (escaped {@code =}, repeated spaces, the order of the AVAs of a multi-valued RDN,
     * attribute types written as an OID with a BER hex string), and {@link X500Principal#equals(Object)}
     * compares the canonical forms of both sides.
     *
     * @param subjectDN
     *            The subject DN of the certificate to find.
     * @param certificates
     *            The certificates to search.
     * @return The first certificate whose subject is {@code subjectDN}, or {@code null} if there is none,
     *         including when the JDK cannot parse {@code subjectDN} as an X.500 name.
     */
    static X509Certificate findCertificateBySubject(DN subjectDN, X509Certificate... certificates) {
        X500Principal subject;
        try {
            subject = new X500Principal(subjectDN.toString());
        } catch (IllegalArgumentException e) {
            // An attribute type without a keyword known to the JDK, such as "mail": no certificate subject
            logger.traceException(e);
            return null;
        }
        for (X509Certificate cert : certificates) {
            if (subject.equals(cert.getSubjectX500Principal())) {
                return cert;
            }
        }
        throw new ConfigException(ERR_OPENIDM_PWSYNC_INVALID_SERVERKEYALIAS.get(serverCertSubject));
        return null;
    }
    private TrustManager[] getTrustManagers(OpenidmAccountStatusNotificationHandlerCfg configuration)
opendj-openidm-account-change-notification-handler/src/test/java/org/forgerock/openidm/accountchange/OpenidmAccountStatusNotificationHandlerTestCase.java
New file
@@ -0,0 +1,113 @@
/*
 * 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.forgerock.openidm.accountchange;
import static org.forgerock.openidm.accountchange.OpenidmAccountStatusNotificationHandler.findCertificateBySubject;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertSame;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.testng.ForgeRockTestCase;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
 * Tests how the handler finds the OpenIDM certificate named by {@code certificate-subject-dn}
 * among the certificates of its truststore (issue #1154).
 */
@SuppressWarnings("javadoc")
@Test(groups = { "precommit" })
public class OpenidmAccountStatusNotificationHandlerTestCase extends ForgeRockTestCase {
    private KeyPair keyPair;
    @BeforeClass
    public void generateKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        generator.initialize(2048);
        keyPair = generator.generateKeyPair();
    }
    @DataProvider
    public Object[][] sameName() {
        return new Object[][] {
            // The subject of the sample configuration
            { "CN=localhost, O=OpenIDM Self-Signed Certificate, OU=None, L=None, ST=None, C=None" },
            // DN.toString() escapes '=' in a value, the JDK's canonical form does not
            { "CN=idm=1,O=Example" },
            // The JDK's canonical form collapses internal spaces
            { "CN=idm  node,O=Example" },
            // The JDK's canonical form sorts the AVAs of a multi-valued RDN
            { "OU=sync+CN=idm,O=Example" },
            // The JDK's canonical form writes EMAILADDRESS as an OID with a BER hex string
            { "EMAILADDRESS=idm@example.com,CN=idm,O=Example" },
            // ... and DC, which it encodes as an IA5String, as a BER hex string
            { "UID=idm,DC=example,DC=com" },
        };
    }
    @Test(dataProvider = "sameName")
    public void findsTheCertificateWhoseSubjectIsTheConfiguredDN(String name) throws Exception {
        X509Certificate cert = certificate(name);
        assertSame(findCertificateBySubject(DN.valueOf(name), certificate("CN=other,O=Example"), cert), cert);
    }
    @Test
    public void findsTheCertificateWhateverTheCaseAndTheAVAOrderOfTheConfiguredDN() throws Exception {
        X509Certificate cert = certificate("CN=idm+OU=sync,O=Example");
        assertSame(findCertificateBySubject(DN.valueOf("ou=SYNC+cn=IDM,o=example"), cert), cert);
    }
    @Test
    public void findsNoCertificateWhenNoSubjectIsTheConfiguredDN() throws Exception {
        assertNull(findCertificateBySubject(DN.valueOf("CN=idm,O=Example"),
                certificate("CN=idm,O=Other"), certificate("CN=idm2,O=Example")));
    }
    @Test
    public void findsNoCertificateWhenTheJDKCannotParseTheConfiguredDN() throws Exception {
        // X500Principal does not know the "mail" keyword: the DN cannot name a certificate subject
        assertNull(findCertificateBySubject(DN.valueOf("mail=idm@example.com,O=Example"),
                certificate("CN=idm,O=Example")));
    }
    /** Returns a self-signed certificate whose subject is encoded as keytool encodes it. */
    private X509Certificate certificate(String subject) throws Exception {
        X500Principal name = new X500Principal(subject);
        Instant now = Instant.now();
        JcaX509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(name, BigInteger.ONE,
                Date.from(now.minus(1, ChronoUnit.DAYS)), Date.from(now.plus(1, ChronoUnit.DAYS)), name,
                keyPair.getPublic());
        return new JcaX509CertificateConverter().getCertificate(
                builder.build(new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate())));
    }
}
opendj-packages/opendj-docker/bootstrap/setup.sh
@@ -84,7 +84,7 @@
echo "creating backend: $BACKEND_TYPE db-directory: ${BACKEND_DB_DIRECTORY}"
/opt/opendj/bin/dsconfig create-backend -h localhost -p $ADMIN_PORT --bindDN "$ROOT_USER_DN" --bindPasswordFile "$PASSWORD_FILE" \
  --backend-name=userRoot --type $BACKEND_TYPE --set base-dn:$BASE_DN --set "db-directory:$BACKEND_DB_DIRECTORY" \
  --backend-name=userRoot --type $BACKEND_TYPE --set "base-dn:$BASE_DN" --set "db-directory:$BACKEND_DB_DIRECTORY" \
  --set enabled:true --no-prompt --trustAll || exit 1
if [ "$ADD_BASE_ENTRY" = "--addBaseEntry"  ]; then