27 files modified
4 files added
| | |
| | | group: ${{ github.workflow }}-${{ github.ref }} |
| | | cancel-in-progress: true |
| | | |
| | | # Nothing in this workflow writes back to the repository: the docker jobs push to |
| | | # the local registry service, not to a remote one. |
| | | permissions: |
| | | contents: read |
| | | |
| | | jobs: |
| | | build-maven: |
| | | runs-on: ${{ matrix.os }} |
| | |
| | | restore-keys: ${{ runner.os }}-m2-repository |
| | | - name: Setup MSVC Developer Command Prompt (x86) |
| | | if: runner.os == 'Windows' |
| | | uses: ilammy/msvc-dev-cmd@v1 |
| | | uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 |
| | | env: |
| | | # Opt in to Node.js 24 for this action, which still ships on Node.js 20. |
| | | # See https://github.com/ilammy/msvc-dev-cmd/issues/99 |
| | |
| | | echo "release_version=$git_version_last" >> $GITHUB_ENV |
| | | - name: Docker meta |
| | | id: meta |
| | | uses: docker/metadata-action@v6 |
| | | uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 |
| | | with: |
| | | images: | |
| | | localhost:5000/${{ github.repository }} |
| | | tags: | |
| | | type=raw,value=${{ env.release_version }} |
| | | - name: Set up QEMU |
| | | uses: docker/setup-qemu-action@v4 |
| | | uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 |
| | | - name: Set up Docker Buildx |
| | | uses: docker/setup-buildx-action@v4 |
| | | uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 |
| | | with: |
| | | driver-opts: network=host |
| | | - name: Prepare Dockerfile |
| | |
| | | cp ./opendj-server-legacy/target/package/opendj-*.zip ./opendj-packages/opendj-docker |
| | | sed -i -E '/^#COPY opendj/s/^#//' ./opendj-packages/opendj-docker/Dockerfile |
| | | - name: Build image (default) |
| | | uses: docker/build-push-action@v7 |
| | | uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 |
| | | with: |
| | | context: ./opendj-packages/opendj-docker |
| | | file: ./opendj-packages/opendj-docker/Dockerfile |
| | |
| | | echo "release_version=$git_version_last" >> $GITHUB_ENV |
| | | - name: Docker meta |
| | | id: meta |
| | | uses: docker/metadata-action@v6 |
| | | uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 |
| | | with: |
| | | images: | |
| | | localhost:5000/${{ github.repository }} |
| | |
| | | type=raw,value=alpine |
| | | type=raw,value=${{ env.release_version }}-alpine |
| | | - name: Set up QEMU |
| | | uses: docker/setup-qemu-action@v4 |
| | | uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 |
| | | - name: Set up Docker Buildx |
| | | uses: docker/setup-buildx-action@v4 |
| | | uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 |
| | | with: |
| | | driver-opts: network=host |
| | | - name: Prepare Dockerfile |
| | |
| | | cp ./opendj-server-legacy/target/package/opendj-*.zip ./opendj-packages/opendj-docker |
| | | sed -i -E '/^#COPY opendj/s/^#//' ./opendj-packages/opendj-docker/Dockerfile-alpine |
| | | - name: Build image |
| | | uses: docker/build-push-action@v7 |
| | | uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 |
| | | with: |
| | | context: ./opendj-packages/opendj-docker |
| | | file: ./opendj-packages/opendj-docker/Dockerfile-alpine |
| | |
| | | # --- C/C++ manual build (Windows native executables) ----------------- |
| | | - name: Setup MSVC Developer Command Prompt (x86) |
| | | if: matrix.language == 'c-cpp' |
| | | uses: ilammy/msvc-dev-cmd@v1 |
| | | uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 |
| | | env: |
| | | # Opt in to Node.js 24 for this action, which still ships on Node.js 20. |
| | | # See https://github.com/ilammy/msvc-dev-cmd/issues/99 |
| | |
| | | group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }} |
| | | cancel-in-progress: false |
| | | |
| | | # contents: write is required to push the generated documentation to the project wiki |
| | | # with github.token. The doc site push uses a separate PAT, not this token. |
| | | permissions: |
| | | contents: write |
| | | |
| | | jobs: |
| | | package-deploy-maven: |
| | | if: ${{ github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event=='push'}} |
| | |
| | | group: ${{ github.workflow }}-${{ github.ref }} |
| | | cancel-in-progress: false |
| | | |
| | | permissions: |
| | | contents: read |
| | | |
| | | jobs: |
| | | release-maven: |
| | | runs-on: 'ubuntu-latest' |
| | | # contents: write is required to push the release commits and tags produced by |
| | | # maven-release-plugin, to create the GitHub release and to update the wiki. |
| | | permissions: |
| | | contents: write |
| | | steps: |
| | | - name: Print github context |
| | | env: |
| | |
| | | if: ${{ env.MAVEN_USERNAME!='' && env.MAVEN_PASSWORD!='' }} |
| | | run: mvn --batch-mode -Darguments="-Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }}" -DsignTag=true -DtagNameFormat="${{ github.event.inputs.releaseVersion }}" -DreleaseVersion=${{ github.event.inputs.releaseVersion }} -DdevelopmentVersion=${{ github.event.inputs.developmentVersion }} release:prepare release:perform --file pom.xml |
| | | - name: Release on GitHub |
| | | uses: softprops/action-gh-release@v2 |
| | | uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 |
| | | with: |
| | | name: ${{ github.event.inputs.releaseVersion }} |
| | | tag_name: ${{ github.event.inputs.releaseVersion }} |
| | |
| | | runs-on: 'ubuntu-latest' |
| | | needs: |
| | | - release-maven |
| | | # packages: write is required for the GHCR login that authenticates with GITHUB_TOKEN. |
| | | permissions: |
| | | contents: read |
| | | packages: write |
| | | steps: |
| | | - uses: actions/checkout@v6 |
| | | with: |
| | |
| | | submodules: recursive |
| | | - name: Docker meta |
| | | id: meta |
| | | uses: docker/metadata-action@v6 |
| | | uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 |
| | | with: |
| | | images: | |
| | | ${{ github.repository }} |
| | |
| | | type=raw,value=latest |
| | | type=raw,value=${{ github.event.inputs.releaseVersion }} |
| | | - name: Set up QEMU |
| | | uses: docker/setup-qemu-action@v4 |
| | | uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 |
| | | - name: Set up Docker Buildx |
| | | uses: docker/setup-buildx-action@v4 |
| | | uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 |
| | | - name: Login to DockerHub |
| | | uses: docker/login-action@v4 |
| | | uses: docker/login-action@371161bbe7024a29a25c5e19bfcbc0804fe9ad2c # v4.5.2 |
| | | with: |
| | | username: ${{ secrets.DOCKER_USERNAME }} |
| | | password: ${{ secrets.DOCKER_PASSWORD }} |
| | | - name: Login to GHCR |
| | | uses: docker/login-action@v4 |
| | | uses: docker/login-action@371161bbe7024a29a25c5e19bfcbc0804fe9ad2c # v4.5.2 |
| | | with: |
| | | registry: ghcr.io |
| | | username: ${{ github.repository_owner }} |
| | | password: ${{ secrets.GITHUB_TOKEN }} |
| | | - name: Build and push image |
| | | uses: docker/build-push-action@v7 |
| | | uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 |
| | | continue-on-error: true |
| | | with: |
| | | context: ./opendj-packages/opendj-docker |
| | |
| | | runs-on: 'ubuntu-latest' |
| | | needs: |
| | | - release-maven |
| | | # packages: write is required for the GHCR login that authenticates with GITHUB_TOKEN. |
| | | permissions: |
| | | contents: read |
| | | packages: write |
| | | steps: |
| | | - uses: actions/checkout@v6 |
| | | with: |
| | |
| | | submodules: recursive |
| | | - name: Docker meta |
| | | id: meta |
| | | uses: docker/metadata-action@v6 |
| | | uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 |
| | | with: |
| | | images: | |
| | | ${{ github.repository }} |
| | |
| | | type=raw,value=alpine |
| | | type=raw,value=${{ github.event.inputs.releaseVersion }}-alpine |
| | | - name: Set up QEMU |
| | | uses: docker/setup-qemu-action@v4 |
| | | uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 |
| | | - name: Set up Docker Buildx |
| | | uses: docker/setup-buildx-action@v4 |
| | | uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 |
| | | - name: Login to DockerHub |
| | | uses: docker/login-action@v4 |
| | | uses: docker/login-action@371161bbe7024a29a25c5e19bfcbc0804fe9ad2c # v4.5.2 |
| | | with: |
| | | username: ${{ secrets.DOCKER_USERNAME }} |
| | | password: ${{ secrets.DOCKER_PASSWORD }} |
| | | - name: Login to GHCR |
| | | uses: docker/login-action@v4 |
| | | uses: docker/login-action@371161bbe7024a29a25c5e19bfcbc0804fe9ad2c # v4.5.2 |
| | | with: |
| | | registry: ghcr.io |
| | | username: ${{ github.repository_owner }} |
| | | password: ${{ secrets.GITHUB_TOKEN }} |
| | | - name: Build and push image |
| | | continue-on-error: true |
| | | uses: docker/build-push-action@v7 |
| | | uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 |
| | | with: |
| | | context: ./opendj-packages/opendj-docker |
| | | file: ./opendj-packages/opendj-docker/Dockerfile-alpine |
| | |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package com.forgerock.opendj.cli; |
| | | |
| | |
| | | throw new ArgumentException(ERR_ARG_SUBCOMMAND_DUPLICATE_ARGUMENT_NAME.get(name, argumentLongID)); |
| | | } |
| | | |
| | | if (parser.hasGlobalArgument(argumentLongID)) { |
| | | throw new ArgumentException(ERR_ARG_SUBCOMMAND_ARGUMENT_GLOBAL_CONFLICT.get(argumentLongID, name)); |
| | | } |
| | | |
| | | Character shortID = argument.getShortIdentifier(); |
| | | if (shortID != null) { |
| | | if (shortIDMap.containsKey(shortID)) { |
| | |
| | | * |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2018-2024 3A Systems, LLC. |
| | | * Portions Copyright 2018-2026 3A Systems, LLC. |
| | | */ |
| | | package com.forgerock.opendj.cli; |
| | | |
| | |
| | | private final Map<Character, Argument> globalShortIDMap = new HashMap<>(); |
| | | /** The set of global arguments defined for this parser, referenced by long ID. */ |
| | | private final Map<String, Argument> globalLongIDMap = new HashMap<>(); |
| | | /** The set of global arguments defined for this parser, referenced by argument name. */ |
| | | private final Map<String, Argument> globalArgumentMap = new HashMap<>(); |
| | | /** The total set of global arguments defined for this parser. */ |
| | | private final List<Argument> globalArgumentList = new LinkedList<>(); |
| | | /** The set of subcommands defined for this parser, referenced by subcommand name. */ |
| | |
| | | * @return <CODE>true</CODE> if a global argument exists with the specified name, or <CODE>false</CODE> if not. |
| | | */ |
| | | public boolean hasGlobalArgument(String argumentName) { |
| | | return globalArgumentMap.containsKey(argumentName); |
| | | return getGlobalArgumentForLongID(formatLongIdentifier(argumentName)) != null; |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | public void addGlobalArgument(Argument argument, ArgumentGroup group) throws ArgumentException { |
| | | String longID = argument.getLongIdentifier(); |
| | | if (globalArgumentMap.containsKey(longID)) { |
| | | throw new ArgumentException(ERR_SUBCMDPARSER_DUPLICATE_GLOBAL_ARG_NAME.get(longID)); |
| | | } |
| | | for (SubCommand s : subCommands.values()) { |
| | | if (s.getArgumentForLongIdentifier(longID) != null) { |
| | | throw new ArgumentException(ERR_SUBCMDPARSER_GLOBAL_ARG_NAME_SUBCMD_CONFLICT.get( |
| | |
| | | } |
| | | } |
| | | |
| | | if (!longArgumentsCaseSensitive()) { |
| | | longID = toLowerCase(longID); |
| | | if (globalLongIDMap.containsKey(longID)) { |
| | | throw new ArgumentException(ERR_SUBCMDPARSER_DUPLICATE_GLOBAL_ARG_LONG_ID.get(longID)); |
| | | } |
| | | longID = formatLongIdentifier(longID); |
| | | if (globalLongIDMap.containsKey(longID)) { |
| | | throw new ArgumentException(ERR_SUBCMDPARSER_DUPLICATE_GLOBAL_ARG_LONG_ID.get(longID)); |
| | | } |
| | | |
| | | for (SubCommand s : subCommands.values()) { |
| | |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package com.forgerock.opendj.cli; |
| | | |
| | |
| | | SubCommandArgumentParser.indentAndWrap(indent, buffer, wrapColumn, LocalizableMessage.raw(text)); |
| | | Assertions.assertThat(buffer.toString()).isEqualTo(expected); |
| | | } |
| | | |
| | | private static SubCommandArgumentParser newParser(final boolean longArgumentsCaseSensitive) { |
| | | return new SubCommandArgumentParser(TestSubCommandArgumentParserTestCase.class.getName(), |
| | | LocalizableMessage.raw("test description"), longArgumentsCaseSensitive); |
| | | } |
| | | |
| | | private static Argument booleanArg(final String longID) throws ArgumentException { |
| | | return BooleanArgument.builder(longID).description(LocalizableMessage.raw(longID)).buildArgument(); |
| | | } |
| | | |
| | | /** A registered global argument must be discoverable by its long identifier. */ |
| | | @Test |
| | | public void testHasGlobalArgument() throws Exception { |
| | | final SubCommandArgumentParser caseInsensitive = newParser(false); |
| | | caseInsensitive.addGlobalArgument(booleanArg("globalArg")); |
| | | Assertions.assertThat(caseInsensitive.hasGlobalArgument("globalArg")).isTrue(); |
| | | Assertions.assertThat(caseInsensitive.hasGlobalArgument("GLOBALARG")).isTrue(); |
| | | Assertions.assertThat(caseInsensitive.hasGlobalArgument("otherArg")).isFalse(); |
| | | |
| | | final SubCommandArgumentParser caseSensitive = newParser(true); |
| | | caseSensitive.addGlobalArgument(booleanArg("globalArg")); |
| | | Assertions.assertThat(caseSensitive.hasGlobalArgument("globalArg")).isTrue(); |
| | | Assertions.assertThat(caseSensitive.hasGlobalArgument("GLOBALARG")).isFalse(); |
| | | } |
| | | |
| | | /** Two global arguments sharing a long identifier must be rejected, whatever the case sensitivity. */ |
| | | @Test |
| | | public void testDuplicateGlobalArgumentIsRejected() throws Exception { |
| | | for (final boolean caseSensitive : new boolean[] { false, true }) { |
| | | final SubCommandArgumentParser aParser = newParser(caseSensitive); |
| | | aParser.addGlobalArgument(booleanArg("globalArg")); |
| | | try { |
| | | aParser.addGlobalArgument(booleanArg("globalArg")); |
| | | Assert.fail("A duplicate global argument should have been rejected " |
| | | + "(longArgumentsCaseSensitive=" + caseSensitive + ")"); |
| | | } catch (final ArgumentException expected) { |
| | | // Expected. |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** A sub-command argument must not shadow a global argument. */ |
| | | @Test |
| | | public void testSubCommandArgumentConflictingWithGlobalIsRejected() throws Exception { |
| | | final SubCommandArgumentParser aParser = newParser(false); |
| | | aParser.addGlobalArgument(booleanArg("globalArg")); |
| | | |
| | | final SubCommand subCommand = |
| | | new SubCommand(aParser, "a-sub-command", LocalizableMessage.raw("a-sub-command")); |
| | | try { |
| | | subCommand.addArgument(booleanArg("globalArg")); |
| | | Assert.fail("A sub-command argument conflicting with a global argument should have been rejected"); |
| | | } catch (final ArgumentException expected) { |
| | | // Expected. |
| | | } |
| | | } |
| | | } |
| | |
| | | * |
| | | * Copyright 2007-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2012-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.config.dsconfig; |
| | | |
| | |
| | | final Map<RelationDefinition<?, ?>, CreateSubCommandHandler<?, ?>> createHandlers = new HashMap<>(); |
| | | final Map<RelationDefinition<?, ?>, DeleteSubCommandHandler> deleteHandlers = new HashMap<>(); |
| | | final Map<RelationDefinition<?, ?>, ListSubCommandHandler> listHandlers = new HashMap<>(); |
| | | final Map<RelationDefinition<?, ?>, GetPropSubCommandHandler> getPropHandlers = new HashMap<>(); |
| | | final Map<RelationDefinition<?, ?>, SetPropSubCommandHandler> setPropHandlers = new HashMap<>(); |
| | | |
| | | for (final CreateSubCommandHandler<?, ?> ch : handlerFactory.getCreateSubCommandHandlers()) { |
| | |
| | | |
| | | for (final GetPropSubCommandHandler gh : handlerFactory.getGetPropSubCommandHandlers()) { |
| | | relations.add(gh.getRelationDefinition()); |
| | | getPropHandlers.put(gh.getRelationDefinition(), gh); |
| | | } |
| | | |
| | | for (final SetPropSubCommandHandler sh : handlerFactory.getSetPropSubCommandHandlers()) { |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.config.dsconfig; |
| | | |
| | |
| | | @Override |
| | | public MenuResult<Boolean> invoke(ConsoleApplication app) throws ClientException { |
| | | app.println(); |
| | | SortedSet<T> previousValues = new TreeSet<>(currentValues); |
| | | readPropertyValues(app, mo.getManagedObjectDefinition(), d, currentValues); |
| | | SortedSet<T> addedValues = new TreeSet<>(currentValues); |
| | | addedValues.removeAll(previousValues); |
| | | isLastChoiceReset = false; |
| | | return MenuResult.success(false); |
| | | } |
| | |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.ldap; |
| | | |
| | |
| | | |
| | | public abstract boolean hasOption(String normalizedOption); |
| | | |
| | | public abstract boolean equals(Impl other); |
| | | /** |
| | | * Options are compared by value, so this method must be kept consistent |
| | | * with {@link #hashCode()}. |
| | | */ |
| | | @Override |
| | | public abstract boolean equals(Object other); |
| | | |
| | | public abstract String firstNormalizedOption(); |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | public boolean equals(final Impl other) { |
| | | public boolean equals(final Object other) { |
| | | if (other instanceof MultiOptionImpl) { |
| | | final MultiOptionImpl tmp = (MultiOptionImpl) other; |
| | | return Arrays.equals(normalizedOptions, tmp.normalizedOptions); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public boolean equals(final Impl other) { |
| | | return other.size() == 1 && other.hasOption(normalizedOption); |
| | | public boolean equals(final Object other) { |
| | | if (other instanceof Impl) { |
| | | final Impl tmp = (Impl) other; |
| | | return tmp.size() == 1 && tmp.hasOption(normalizedOption); |
| | | } else { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | |
| | | @Override |
| | | public boolean equals(final Impl other) { |
| | | public boolean equals(final Object other) { |
| | | return this == other; |
| | | } |
| | | |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.forgerock.opendj.maven.doc; |
| | | |
| | |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | import java.util.Properties; |
| | | import java.util.Set; |
| | | import java.util.TreeMap; |
| | |
| | | import org.apache.maven.plugins.annotations.Mojo; |
| | | import org.apache.maven.plugins.annotations.Parameter; |
| | | import org.apache.maven.project.MavenProject; |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | |
| | | /** Generates an XML file of log messages found in properties files. */ |
| | | @Mojo(name = "generate-xml-messages-doc", defaultPhase = PRE_SITE) |
| | |
| | | /** A list which contains all file names, the extension is not needed. */ |
| | | @Parameter(required = true) |
| | | private List<String> messageFileNames; |
| | | /** One-line descriptions for log reference categories. */ |
| | | private static final Map<String, LocalizableMessage> CATEGORY_DESCRIPTIONS = new HashMap<>(); |
| | | static { |
| | | CATEGORY_DESCRIPTIONS.put("ACCESS_CONTROL", CATEGORY_ACCESS_CONTROL.get()); |
| | | CATEGORY_DESCRIPTIONS.put("ADMIN", CATEGORY_ADMIN.get()); |
| | | CATEGORY_DESCRIPTIONS.put("ADMIN_TOOL", CATEGORY_ADMIN_TOOL.get()); |
| | | CATEGORY_DESCRIPTIONS.put("AUDIT", CATEGORY_AUDIT.get()); |
| | | CATEGORY_DESCRIPTIONS.put("BACKEND", CATEGORY_BACKEND.get()); |
| | | CATEGORY_DESCRIPTIONS.put("CONFIG", CATEGORY_CONFIG.get()); |
| | | CATEGORY_DESCRIPTIONS.put("CORE", CATEGORY_CORE.get()); |
| | | CATEGORY_DESCRIPTIONS.put("DSCONFIG", CATEGORY_DSCONFIG.get()); |
| | | CATEGORY_DESCRIPTIONS.put("EXTENSIONS", CATEGORY_EXTENSIONS.get()); |
| | | CATEGORY_DESCRIPTIONS.put("JVM", CATEGORY_JVM.get()); |
| | | CATEGORY_DESCRIPTIONS.put("LOG", CATEGORY_LOG.get()); |
| | | CATEGORY_DESCRIPTIONS.put("PLUGIN", CATEGORY_PLUGIN.get()); |
| | | CATEGORY_DESCRIPTIONS.put("PROTOCOL", CATEGORY_PROTOCOL.get()); |
| | | CATEGORY_DESCRIPTIONS.put("QUICKSETUP", CATEGORY_QUICKSETUP.get()); |
| | | CATEGORY_DESCRIPTIONS.put("RUNTIME_INFORMATION", CATEGORY_RUNTIME_INFORMATION.get()); |
| | | CATEGORY_DESCRIPTIONS.put("SCHEMA", CATEGORY_SCHEMA.get()); |
| | | CATEGORY_DESCRIPTIONS.put("SDK", CATEGORY_SDK.get()); |
| | | CATEGORY_DESCRIPTIONS.put("SYNC", CATEGORY_SYNC.get()); |
| | | CATEGORY_DESCRIPTIONS.put("TASK", CATEGORY_TASK.get()); |
| | | CATEGORY_DESCRIPTIONS.put("THIRD_PARTY", CATEGORY_THIRD_PARTY.get()); |
| | | CATEGORY_DESCRIPTIONS.put("TOOLS", CATEGORY_TOOLS.get()); |
| | | CATEGORY_DESCRIPTIONS.put("USER_DEFINED", CATEGORY_USER_DEFINED.get()); |
| | | CATEGORY_DESCRIPTIONS.put("UTIL", CATEGORY_UTIL.get()); |
| | | CATEGORY_DESCRIPTIONS.put("VERSION", CATEGORY_VERSION.get()); |
| | | } |
| | | |
| | | /** Message giving formatting rules for string keys. */ |
| | | public static final String KEY_FORM_MSG = ".\n\nOpenDJ message property keys must be of the form\n\n" |
| | |
| | | } |
| | | |
| | | /** |
| | | * Compare message entries by unique identifier. |
| | | * Compare message entries by ordinal, then by unique identifier. |
| | | * <p> |
| | | * Entries are held in a {@code TreeSet}, so this must be a total order: |
| | | * returning 0 for entries that are not the same message drops them from |
| | | * the log reference. Entries without an ordinal sort first, as they do |
| | | * in {@link MessagePropertyKey#compareTo(MessagePropertyKey)}. |
| | | * |
| | | * @return See {@link java.lang.Comparable#compareTo(Object)}. |
| | | */ |
| | | @Override |
| | | public int compareTo(MessageRefEntry mre) { |
| | | if (this.ordinal != null && mre.ordinal != null) { |
| | | return this.ordinal.compareTo(mre.ordinal); |
| | | if (Objects.equals(ordinal, mre.ordinal)) { |
| | | return xmlId.compareTo(mre.xmlId); |
| | | } else if (ordinal == null) { |
| | | return -1; |
| | | } else if (mre.ordinal == null) { |
| | | return 1; |
| | | } else { |
| | | return ordinal.compareTo(mre.ordinal); |
| | | } |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | @Override |
| | | public int compareTo(MessagePropertyKey k) { |
| | | if (ordinal == k.ordinal) { |
| | | if (Objects.equals(ordinal, k.ordinal)) { |
| | | return description.compareTo(k.description); |
| | | } else if (ordinal != null && k.ordinal != null) { |
| | | return ordinal.compareTo(k.ordinal); |
| | | } else if (ordinal == null) { |
| | | return -1; |
| | | } else if (k.ordinal == null) { |
| | | return 1; |
| | | } else { |
| | | return 0; |
| | | return ordinal.compareTo(k.ordinal); |
| | | } |
| | | } |
| | | } |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2012-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.controlpanel.browser; |
| | | |
| | |
| | | } |
| | | 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 |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2015-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.controlpanel.browser; |
| | | |
| | |
| | | private final String name; |
| | | private final List<AbstractNodeTask> waitingQueue = new ArrayList<>(); |
| | | private final Map<BasicNode, AbstractNodeTask> workingList = new HashMap<>(); |
| | | private final Map<BasicNode, BasicNode> cancelList = new HashMap<>(); |
| | | private final ThreadGroup threadGroup; |
| | | |
| | | |
| | |
| | | // Mark the on-going task as cancelled |
| | | AbstractNodeTask task = workingList.get(node); |
| | | if (task != null) { |
| | | cancelList.put(node, node); |
| | | task.cancel(); |
| | | } |
| | | notify(); |
| | |
| | | waitingQueue.clear(); |
| | | for (Map.Entry<BasicNode, AbstractNodeTask> entry : workingList.entrySet()) |
| | | { |
| | | BasicNode node = entry.getKey(); |
| | | AbstractNodeTask task = entry.getValue(); |
| | | cancelList.put(node, node); |
| | | task.cancel(); |
| | | entry.getValue().cancel(); |
| | | } |
| | | } |
| | | |
| | |
| | | throw new IllegalArgumentException("null argument"); |
| | | } |
| | | workingList.remove(task.getNode()); |
| | | cancelList.remove(task.getNode()); |
| | | notify(); |
| | | // System.out.println("Flushed " + task + " from " + _name); |
| | | } |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.controlpanel.datamodel; |
| | | |
| | |
| | | private final IconPool iconPool = new IconPool(); |
| | | |
| | | private long poolingPeriod = 20000; |
| | | /** |
| | | * Guards the pooling thread life cycle. A dedicated lock is used on purpose: |
| | | * the pooling thread calls methods that are synchronized on this object (for |
| | | * instance {@link #regenerateDescriptor()}), so waiting for that thread to |
| | | * die while holding the monitor of this object would deadlock. |
| | | */ |
| | | private final Object poolingLock = new Object(); |
| | | /** Guarded by {@link #poolingLock}. */ |
| | | private Thread poolingThread; |
| | | private boolean stopPooling; |
| | | private boolean pooling; |
| | | /** Read by the pooling thread without any lock, hence volatile. */ |
| | | private volatile boolean stopPooling; |
| | | |
| | | private ApplicationTrustManager trustManager; |
| | | private int connectTimeout = CliConstants.DEFAULT_LDAP_CONNECT_TIMEOUT; |
| | |
| | | * specified as a parameter. This method is asynchronous and it will start |
| | | * the pooling in another thread. |
| | | */ |
| | | public synchronized void startPooling() |
| | | public void startPooling() |
| | | { |
| | | if (poolingThread != null) |
| | | synchronized (poolingLock) |
| | | { |
| | | return; |
| | | } |
| | | pooling = true; |
| | | stopPooling = false; |
| | | |
| | | poolingThread = new Thread(new Runnable() |
| | | { |
| | | @Override |
| | | public void run() |
| | | if (poolingThread != null && poolingThread.isAlive()) |
| | | { |
| | | try |
| | | return; |
| | | } |
| | | stopPooling = false; |
| | | |
| | | poolingThread = new Thread(new Runnable() |
| | | { |
| | | @Override |
| | | public void run() |
| | | { |
| | | while (!stopPooling) |
| | | try |
| | | { |
| | | cleanupTasks(); |
| | | regenerateDescriptor(); |
| | | Thread.sleep(poolingPeriod); |
| | | while (!stopPooling) |
| | | { |
| | | cleanupTasks(); |
| | | regenerateDescriptor(); |
| | | Thread.sleep(poolingPeriod); |
| | | } |
| | | } |
| | | catch (InterruptedException e) |
| | | { |
| | | // stopPooling() asked this thread to stop. |
| | | } |
| | | catch (Throwable t) |
| | | { |
| | | logger.warn(LocalizableMessage.raw("Error polling the server: " + t, t)); |
| | | } |
| | | } |
| | | catch (Throwable t) |
| | | { |
| | | } |
| | | pooling = false; |
| | | } |
| | | }); |
| | | poolingThread.start(); |
| | | }); |
| | | poolingThread.start(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Stops pooling the server. This method is synchronous, it does not return |
| | | * until the pooling is actually stopped. |
| | | */ |
| | | public synchronized void stopPooling() |
| | | public void stopPooling() |
| | | { |
| | | stopPooling = true; |
| | | while (poolingThread != null && pooling) |
| | | synchronized (poolingLock) |
| | | { |
| | | try |
| | | stopPooling = true; |
| | | boolean interrupted = false; |
| | | if (poolingThread != null) |
| | | { |
| | | poolingThread.interrupt(); |
| | | Thread.sleep(100); |
| | | // Keep interrupting the pooling thread until it dies: it may be blocked |
| | | // in an operation that swallows the interruption. Note that this must |
| | | // not be done while holding the monitor of this object, see poolingLock. |
| | | while (poolingThread.isAlive()) |
| | | { |
| | | poolingThread.interrupt(); |
| | | try |
| | | { |
| | | poolingThread.join(100); |
| | | } |
| | | catch (InterruptedException e) |
| | | { |
| | | // Do not give up the wait: this method must not return before the |
| | | // pooling thread has actually stopped. The interruption is |
| | | // propagated to the caller once the thread is dead. |
| | | interrupted = true; |
| | | } |
| | | } |
| | | poolingThread = null; |
| | | } |
| | | catch (Throwable t) |
| | | if (interrupted) |
| | | { |
| | | // do nothing; |
| | | Thread.currentThread().interrupt(); |
| | | } |
| | | } |
| | | poolingThread = null; |
| | | pooling = false; |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.controlpanel.task; |
| | | |
| | |
| | | while (entryDNs.hasNext()) |
| | | { |
| | | SearchResultEntry sr = entryDNs.readEntry(); |
| | | if (!sr.getName().equals("")) |
| | | if (!sr.getName().isRootDN()) |
| | | { |
| | | deleteSubtreeRecursively(conn, sr.getName(), null, toNotify); |
| | | } |
| | |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2012-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | |
| | | package org.opends.guitools.controlpanel.ui; |
| | |
| | | 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; |
| | |
| | | @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()); |
| | | } |
| | |
| | | for (ByteString value : attr) |
| | | { |
| | | sb.append("\n"); |
| | | if (oldValue.equals(value)) |
| | | if (isRDNValue(attrDesc, value, oldValue)) |
| | | { |
| | | sb.append(attrName).append(": ").append(newValue); |
| | | } |
| | |
| | | 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(); |
| | | } |
| | |
| | | * |
| | | * Copyright 2008-2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.controlpanel.ui; |
| | | |
| | |
| | | BackendDescriptor backend = getBackendByID(backendName.getText()); |
| | | |
| | | TreeSet<String> standardAttrNames = new TreeSet<>(); |
| | | TreeSet<String> configurationAttrNames = new TreeSet<>(); |
| | | TreeSet<String> customAttrNames = new TreeSet<>(); |
| | | for (AttributeType attr : schema.getAttributeTypes()) |
| | | { |
| | |
| | | { |
| | | standardAttrNames.add(name); |
| | | } |
| | | else if (Utilities.isConfiguration(attr)) |
| | | else if (!Utilities.isConfiguration(attr)) |
| | | { |
| | | configurationAttrNames.add(name); |
| | | } |
| | | else |
| | | { |
| | | // Configuration attributes are not offered for indexing. |
| | | customAttrNames.add(name); |
| | | } |
| | | } |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.controlpanel.ui; |
| | | |
| | |
| | | { |
| | | 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)) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 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(); |
| | |
| | | } |
| | | // 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) |
| | | { |
| | |
| | | else if (isConfirmPassword(attrName) || isPassword(attrName)) |
| | | { |
| | | JPasswordField pf = Utilities.createPasswordField(); |
| | | if (!"".equals(v)) |
| | | if (!v.isEmpty()) |
| | | { |
| | | pf.setText(getPasswordStringValue(getAttributeForConfirmPasswordKey(attrName), v)); |
| | | } |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.guitools.controlpanel.ui; |
| | | |
| | |
| | | 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> |
| | |
| | | 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 |
| | | { |
| | |
| | | |
| | | private boolean isRequired(AttributeValuePair value) |
| | | { |
| | | return requiredAttrs.contains(value.attrDesc.getNameOrOID()); |
| | | return TableViewEntryPanel.isRequired(requiredAttrs, value.attrDesc); |
| | | } |
| | | |
| | | private boolean hasValue(AttributeValuePair value) |
| | |
| | | try (final PhaseTwoProgressReporter progressReporter = new PhaseTwoProgressReporter()) |
| | | { |
| | | final List<Callable<Void>> tasks = new ArrayList<>(); |
| | | final Set<String> importedBaseDNs = new HashSet<>(); |
| | | for (Map.Entry<TreeName, Chunk> treeChunk : transaction.getChunks().entrySet()) |
| | | { |
| | | importedBaseDNs.add(treeChunk.getKey().getBaseDN()); |
| | | tasks.add(importStrategy.newPhaseTwoTask(treeChunk.getKey(), treeChunk.getValue(), progressReporter)); |
| | | } |
| | | invokeParallel(phase2ThreadNameTemplate, tasks); |
| | |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2013-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.core; |
| | | |
| | |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.util.Utils; |
| | | import org.forgerock.opendj.config.ClassPropertyDefinition; |
| | | import org.forgerock.opendj.config.server.ConfigurationAddListener; |
| | |
| | | |
| | | if (!cacheOrderMap.isEmpty() && !cacheNameToLevelMap.isEmpty()) |
| | | { |
| | | final ByteString normDN = configuration.dn().toNormalizedByteString(); |
| | | if (cacheNameToLevelMap.containsKey(normDN)) { |
| | | int currentCacheLevel = cacheNameToLevelMap.get(normDN); |
| | | final DN dn = configuration.dn(); |
| | | if (cacheNameToLevelMap.containsKey(dn)) { |
| | | int currentCacheLevel = cacheNameToLevelMap.get(dn); |
| | | |
| | | // Check if there any existing cache at the same level. |
| | | if (currentCacheLevel != configuration.getCacheLevel() && |
| | |
| | | } |
| | | entryCache.finalizeEntryCache(); |
| | | cacheOrderMap.remove(configuration.getCacheLevel()); |
| | | cacheNameToLevelMap.remove(configuration.dn().toNormalizedByteString()); |
| | | cacheNameToLevelMap.remove(configuration.dn()); |
| | | |
| | | // Push any changes made to the cache order map. |
| | | setCacheOrder(cacheOrderMap); |
| | |
| | | * @return the decoded value of x |
| | | */ |
| | | private static byte char64(char x) { |
| | | if (x < 0 || x > index_64.length) { |
| | | if (x >= index_64.length) { |
| | | return -1; |
| | | } |
| | | return index_64[x]; |
| | |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | |
| | | { |
| | | private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); |
| | | |
| | | /** |
| | | * The set of names for the account status notification types that may be |
| | | * logged by this notification handler. |
| | | */ |
| | | private static final HashSet<String> NOTIFICATION_TYPE_NAMES = new HashSet<>(); |
| | | static |
| | | { |
| | | for (AccountStatusNotificationType t : AccountStatusNotificationType.values()) |
| | | { |
| | | NOTIFICATION_TYPE_NAMES.add(t.getName()); |
| | | } |
| | | } |
| | | |
| | | /** The DN of the configuration entry for this notification handler. */ |
| | | private DN configEntryDN; |
| | | |
| | |
| | | * 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; |
| | | |
| | |
| | | |
| | | 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", |
| | |
| | | * |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2011-2016 ForgeRock AS. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | */ |
| | | package org.opends.server.util.cli; |
| | | |
| | |
| | | { |
| | | 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) |
| | |
| | | } |
| | | |
| | | /** |
| | | * 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 |
| | |
| | | ERR_SNMP_CONNHANDLER_OPENDMK_JARFILES_NOT_OPERATIONAL_1507=The required \ |
| | | classes could not be loaded using jar file '%s'. Verify that the jar file \ |
| | | is not corrupted |
| | | ERR_HTTP_ERROR_WHILE_PROCESSING_REQUEST_1508=An error occurred while processing the request \ |
| | | ERR_HTTP_ERROR_WHILE_PROCESSING_REQUEST_1539=An error occurred while processing the request \ |
| | | %s: %s |
| New file |
| | |
| | | /* |
| | | * 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * 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(); |
| | | } |
| | | } |
| | |
| | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| | | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| | | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| | | * Portions Copyright 2026 3A Systems, LLC. |
| | | * |
| | | */ |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * A stored password whose salt holds a character beyond the base64 decoding table |
| | | * must fail with the IllegalArgumentException that |
| | | * BcryptPasswordStorageScheme.passwordMatches() catches, and not with an |
| | | * ArrayIndexOutOfBoundsException escaping into bind processing. |
| | | */ |
| | | @Test(expectedExceptions = IllegalArgumentException.class) |
| | | public void checkPwRejectsSaltCharBeyondDecodingTable() { |
| | | // U+0080 is the first character past the end of the 128 entry index_64 table. |
| | | BCrypt.checkpw("secret", "$2a$10$" + ((char) 0x80) + "aaaaaaaaaaaaaaaaaaaaa"); |
| | | } |
| | | |
| | | /** |
| | | * Test for correct hashing of non-US-ASCII passwords. |
| | | */ |
| | | @Test |
| New file |
| | |
| | | /* |
| | | * 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(); |
| | | } |
| | | } |