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

maximthomas
29.55.2025 9df0c0351216575123c607a39c5c7ec453bae64b
Merge branch 'master' into update-jdk-11
12 files added
75 files modified
6346 ■■■■■ changed files
.github/workflows/build.yml 64 ●●●● patch | view | raw | blame | history
.github/workflows/deploy.yml 8 ●●●● patch | view | raw | blame | history
.github/workflows/release.yml 3 ●●●● patch | view | raw | blame | history
README.md 2 ●●● patch | view | raw | blame | history
opendj-cli/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-cli/src/main/resources/templates/dscfgSubcommand.ftl 2 ●●● patch | view | raw | blame | history
opendj-cli/src/main/resources/templates/refEntry.ftl 2 ●●● patch | view | raw | blame | history
opendj-config/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-core/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java 35 ●●●●● patch | view | raw | blame | history
opendj-doc-generated-ref/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-doc-generated-ref/src/main/asciidoc/admin-guide/chap-connection-handlers.adoc 5 ●●●●● patch | view | raw | blame | history
opendj-doc-generated-ref/src/main/asciidoc/admin-guide/chap-import-export.adoc 9 ●●●●● patch | view | raw | blame | history
opendj-doc-generated-ref/src/main/asciidoc/admin-guide/chap-indexing.adoc 10 ●●●●● patch | view | raw | blame | history
opendj-doc-generated-ref/src/main/asciidoc/admin-guide/chap-monitoring.adoc 37 ●●●● patch | view | raw | blame | history
opendj-doc-generated-ref/src/main/asciidoc/admin-guide/chap-troubleshooting.adoc 7 ●●●●● patch | view | raw | blame | history
opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-install.adoc 71 ●●●● patch | view | raw | blame | history
opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-upgrade.adoc 254 ●●●●● patch | view | raw | blame | history
opendj-doc-generated-ref/src/main/asciidoc/reference/appendix-rest2ldap-3-0.adoc 28 ●●●● patch | view | raw | blame | history
opendj-doc-generated-ref/src/main/asciidoc/reference/appendix-rest2ldap.adoc 38 ●●●● patch | view | raw | blame | history
opendj-doc-generated-ref/src/main/asciidoc/server-dev-guide/chap-rest-operations-3-0.adoc 6 ●●●● patch | view | raw | blame | history
opendj-doc-generated-ref/src/main/asciidoc/server-dev-guide/chap-rest-operations.adoc 44 ●●●● patch | view | raw | blame | history
opendj-doc-generated-ref/src/main/asciidoc/server-dev-guide/chap-writing-plugins.adoc 21 ●●●● patch | view | raw | blame | history
opendj-doc-maven-plugin/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/resources/templates/appendix-ldap-result-codes.ftl 2 ●●● patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/resources/templates/log-message-reference.ftl 2 ●●● patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/resources/templates/sec-locales-subtypes.ftl 2 ●●● patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/resources/templates/table-global-acis.ftl 2 ●●● patch | view | raw | blame | history
opendj-dsml-servlet/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-embedded-server-examples/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-embedded/pom.xml 6 ●●●● patch | view | raw | blame | history
opendj-grizzly/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LdapResponseMessageWriter.java 6 ●●●● patch | view | raw | blame | history
opendj-ldap-sdk-examples/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-ldap-toolkit/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-legacy/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-maven-plugin/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/JDBCBackendConfiguration.xml 74 ●●●●● patch | view | raw | blame | history
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/PluggableBackendConfiguration.xml 71 ●●●●● patch | view | raw | blame | history
opendj-openidm-account-change-notification-handler/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-packages/opendj-deb/opendj-deb-standard/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-packages/opendj-deb/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-packages/opendj-docker/Dockerfile 36 ●●●●● patch | view | raw | blame | history
opendj-packages/opendj-docker/Dockerfile-alpine 40 ●●●●● patch | view | raw | blame | history
opendj-packages/opendj-docker/README.md 10 ●●●● patch | view | raw | blame | history
opendj-packages/opendj-docker/bootstrap/setup.sh 28 ●●●● patch | view | raw | blame | history
opendj-packages/opendj-docker/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-packages/opendj-msi/opendj-msi-standard/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-packages/opendj-msi/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-packages/opendj-rpm/opendj-rpm-standard/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-packages/opendj-rpm/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-packages/opendj-svr4/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-packages/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-rest2ldap-servlet/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-rest2ldap/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-server-example-plugin/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/pom.xml 93 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/resource/bin/_mixed-script.sh 2 ●●● patch | view | raw | blame | history
opendj-server-legacy/resource/bin/_script-util.bat 7 ●●●● patch | view | raw | blame | history
opendj-server-legacy/resource/bin/_script-util.sh 11 ●●●● patch | view | raw | blame | history
opendj-server-legacy/resource/config/java.properties 9 ●●●● patch | view | raw | blame | history
opendj-server-legacy/resource/schema/02-config.ldif 16 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/jdbc/Backend.java 31 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/jdbc/CachedConnection.java 361 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/jdbc/Storage.java 684 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/jdbc/package-info.java 18 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/OnDiskMergeImporter.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/config/ConfigurationHandler.java 11 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java 5 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tasks/BackupTask.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tools/BackendCreationHelper.java 18 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java 22 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/TestCaseUtils.java 3 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/EncryptedTestCase.java 81 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/MsSqlTestCase.java 51 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/MySqlTestCase.java 51 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/OracleTestCase.java 64 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/PgSqlTestCase.java 51 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/TestCase.java 82 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java 117 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java 5 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/replication/service/ReplicationDomainTest.java 8 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/openidentityplatform/opendj/AliasTestCase.java 101 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/resources/issue496.ldif 3417 ●●●●● patch | view | raw | blame | history
opendj-server-msad-plugin/pom.xml 2 ●●● patch | view | raw | blame | history
opendj-server/pom.xml 2 ●●● patch | view | raw | blame | history
pom.xml 40 ●●●●● patch | view | raw | blame | history
.github/workflows/build.yml
@@ -10,7 +10,7 @@
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        java: [ '11','17','21','23']
        java: [ '11','17','21','23','24']
        os: [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ]
      fail-fast: false
    steps:
@@ -24,8 +24,9 @@
        sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/$(lsb_release -c -s)/winehq-$(lsb_release -c -s).sources
        sudo apt-get update
        sudo apt install --install-recommends winehq-stable || sudo apt install --install-recommends winehq-staging
        sudo mkdir -p /opt/wine/mono && sudo wget "https://dl.winehq.org/wine/wine-mono/8.0.0/wine-mono-8.0.0-x86.tar.xz" -P /opt/wine/mono && sudo tar -xf /opt/wine/mono/wine-mono-8.0.0-x86.tar.xz -C /opt/wine/mono && sudo rm /opt/wine/mono/wine-mono-8.0.0-x86.tar.xz
        wine --version
        version="9.4.0"; sudo wget "https://dl.winehq.org/wine/wine-mono/$version/wine-mono-$version-x86.msi" -O /tmp/wine-mono.msi
        wine msiexec /i /tmp/wine-mono.msi
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
@@ -41,12 +42,7 @@
         path: ~/.m2/repository
         key: ${{ runner.os }}-m2-repository-${{ hashFiles('**/pom.xml') }}
         restore-keys: ${{ runner.os }}-m2-repository
    - name: Run docker cassandra
      if: runner.os == 'Linux'
      run:   |
        docker run --rm -it -d -p 9042:9042 --name cassandra cassandra
        timeout 5m bash -c 'until docker logs cassandra | grep -q "Created default superuser role"; do sleep 5; done'
    - name: Set Integration Test Environment
    - name: Set Integration Test Environment
      id: failsafe
      if: runner.os != 'Windows'
      run:   |
@@ -68,20 +64,42 @@
        opendj-server-legacy/target/package/opendj/bin/makeldif -o /tmp/test.ldif -c suffix=dc=example2,dc=com opendj-server-legacy/target/package/opendj/config/MakeLDIF/example.template
        opendj-server-legacy/target/package/opendj/bin/stop-ds
        opendj-server-legacy/target/package/opendj/bin/import-ldif --offline --ldifFile /tmp/test.ldif --backendID=example2
        opendj-server-legacy/target/package/opendj/bin/rebuild-index --offline --bindDN "cn=Directory Manager" --bindPassword password  --baseDN "dc=example2,dc=com" --rebuildAll
        opendj-server-legacy/target/package/opendj/bin/start-ds
        opendj-server-legacy/target/package/opendj/bin/rebuild-index --bindDN "cn=Directory Manager" --bindPassword password --baseDN "dc=example2,dc=com" --rebuildAll --trustAll
        opendj-server-legacy/target/package/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "ou=people,dc=example2,dc=com" --searchScope sub "(uid=user.*)" dn | grep ^dn: | wc -l | grep -q 10000
        opendj-server-legacy/target/package/opendj/bin/stop-ds
        rm -rf opendj-server-legacy/target/package/opendj/config opendj-server-legacy/target/package/opendj/db opendj-server-legacy/target/package/opendj/changelogDb opendj-server-legacy/target/package/opendj/logs
        rm -rf opendj-server-legacy/target/package/opendj/{config,db,changelogDb,logs}
    - name: Test LDAP in Cassandra
      if: runner.os == 'Linux'
      run:   |
        docker run --rm -it -d -p 9042:9042 --name cassandra cassandra
        timeout 5m bash -c 'until docker logs cassandra | grep -q "Created default superuser role"; do sleep 5; done'
        export OPENDJ_JAVA_ARGS="-server -Xmx512m -Ddatastax-java-driver.basic.contact-points.0=localhost:9042 -Ddatastax-java-driver.basic.load-balancing-policy.local-datacenter=datacenter1"
        opendj-server-legacy/target/package/opendj/setup --backendType cas -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --baseDN dc=example,dc=com --sampleData 5000 --cli --acceptLicense --no-prompt
        opendj-server-legacy/target/package/opendj/setup -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --cli --acceptLicense --no-prompt
        opendj-server-legacy/target/package/opendj/bin/dsconfig create-backend -h localhost -p 4444 --bindDN "cn=Directory Manager" --bindPassword password --backend-name=userRoot --type cas --set base-dn:dc=example,dc=com --set db-directory:keyspace_name --set enabled:true --no-prompt --trustAll
        opendj-server-legacy/target/package/opendj/bin/makeldif -o /tmp/test.ldif -c suffix=dc=example,dc=com opendj-server-legacy/target/package/opendj/config/MakeLDIF/example.template
        opendj-server-legacy/target/package/opendj/bin/import-ldif --ldifFile /tmp/test.ldif --backendID=userRoot -h localhost -p 4444 --bindDN "cn=Directory Manager" --bindPassword password --trustAll
        opendj-server-legacy/target/package/opendj/bin/status --bindDN "cn=Directory Manager" --bindPassword password
        opendj-server-legacy/target/package/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1
        opendj-server-legacy/target/package/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "ou=people,dc=example,dc=com" --searchScope sub "(uid=user.*)" dn | grep ^dn: | wc -l | grep -q 5000
        opendj-server-legacy/target/package/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "ou=people,dc=example,dc=com" --searchScope sub "(uid=user.*)" dn | grep ^dn: | wc -l | grep -q 10000
        opendj-server-legacy/target/package/opendj/bin/stop-ds
        rm -rf opendj-server-legacy/target/package/opendj/config opendj-server-legacy/target/package/opendj/db opendj-server-legacy/target/package/opendj/changelogDb opendj-server-legacy/target/package/opendj/logs
        rm -rf opendj-server-legacy/target/package/opendj/{config,db,changelogDb,logs}
    - name: Test LDAP in Postgres
      if: runner.os == 'Linux'
      run:   |
        docker run --rm -it -d -p 5432:5432 -e POSTGRES_DB=database_name -e POSTGRES_PASSWORD=password --name postgres postgres
        timeout 5m bash -c 'until docker logs postgres | grep -q "database system is ready to accept connections"; do sleep 5; done'
        export OPENDJ_JAVA_ARGS="-server -Xmx512m"
        opendj-server-legacy/target/package/opendj/setup -h localhost -p 1389 --ldapsPort 1636 --adminConnectorPort 4444 --enableStartTLS --generateSelfSignedCertificate --rootUserDN "cn=Directory Manager" --rootUserPassword password --cli --acceptLicense --no-prompt
        opendj-server-legacy/target/package/opendj/bin/dsconfig create-backend -h localhost -p 4444 --bindDN "cn=Directory Manager" --bindPassword password --backend-name=userRoot --type jdbc --set base-dn:dc=example,dc=com --set db-directory:jdbc:postgresql://localhost:5432/database_name?user=postgres\&password=password --set enabled:true --no-prompt --trustAll
        opendj-server-legacy/target/package/opendj/bin/makeldif -o /tmp/test.ldif -c suffix=dc=example,dc=com opendj-server-legacy/target/package/opendj/config/MakeLDIF/example.template
        opendj-server-legacy/target/package/opendj/bin/ldapmodify --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll -f /tmp/test.ldif -a 1> /dev/null
        opendj-server-legacy/target/package/opendj/bin/status --bindDN "cn=Directory Manager" --bindPassword password
        opendj-server-legacy/target/package/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example,dc=com" --searchScope base "(objectClass=*)" 1.1
        opendj-server-legacy/target/package/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "ou=people,dc=example,dc=com" --searchScope sub "(uid=user.*)" dn | grep ^dn: | wc -l | grep -q 10000
        opendj-server-legacy/target/package/opendj/bin/stop-ds
        rm -rf opendj-server-legacy/target/package/opendj/{config,db,changelogDb,logs}
    - name: Test on Windows
      if: runner.os == 'Windows'
      run:   |
@@ -94,7 +112,9 @@
        opendj-server-legacy\target\package\opendj\bat\makeldif.bat -o test.ldif -c suffix=dc=example2,dc=com opendj-server-legacy\target\package\opendj\config\MakeLDIF\example.template
        opendj-server-legacy\target\package\opendj\bat\stop-ds.bat
        opendj-server-legacy\target\package\opendj\bat\import-ldif.bat --offline --ldifFile test.ldif --backendID=example2
        opendj-server-legacy\target\package\opendj\bat\rebuild-index.bat --offline --bindDN "cn=Directory Manager" --bindPassword password  --baseDN "dc=example2,dc=com" --rebuildAll
        opendj-server-legacy\target\package\opendj\bat\start-ds.bat
        opendj-server-legacy\target\package\opendj\bat\rebuild-index.bat --bindDN "cn=Directory Manager" --bindPassword password --baseDN "dc=example2,dc=com" --rebuildAll --trustAll
        opendj-server-legacy\target\package\opendj\bat\ldapsearch.bat --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "dc=example2,dc=com" --searchScope sub "(uid=user.*)" dn | find /c '"dn:"' | findstr "10000"
        opendj-server-legacy\target\package\opendj\bat\stop-ds.bat
    - name: Upload artifacts OpenDJ Server
@@ -159,8 +179,17 @@
      - name: Docker test
        shell: bash
        run: |
          docker run --rm -it -d --memory="1g" --name=test localhost:5000/${GITHUB_REPOSITORY,,}:${{ env.release_version }}
          docker run --rm -it -d --memory="512m" --name=test localhost:5000/${GITHUB_REPOSITORY,,}:${{ env.release_version }}
          timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test | grep -q \"healthy\"; do sleep 10; done'
          docker exec test 'sh' '-c' '/opt/opendj/bin/dsconfig create-backend --hostname localhost --port 4444 --bindDN "cn=Directory Manager" --bindPassword password --backend-name=example2 --type je --set=base-dn:dc=example2,dc=com --set=enabled:true --no-prompt --trustAll'
          docker exec test 'sh' '-c' '/opt/opendj/bin/makeldif -o /tmp/test.ldif -c suffix=dc=example2,dc=com /opt/opendj/data/config/MakeLDIF/example.template'
          docker exec test 'sh' '-c' '/opt/opendj/bin/stop-ds'
          docker exec test 'sh' '-c' '/opt/opendj/bin/import-ldif --offline --ldifFile /tmp/test.ldif --backendID=example2'
          docker exec test 'sh' '-c' '/opt/opendj/bin/rebuild-index --offline --bindDN "cn=Directory Manager" --bindPassword password  --baseDN "dc=example2,dc=com" --rebuildAll'
          docker exec test 'sh' '-c' '/opt/opendj/bin/start-ds'
          docker exec test 'sh' '-c' '/opt/opendj/bin/rebuild-index --bindDN "cn=Directory Manager" --bindPassword password --baseDN "dc=example2,dc=com" --rebuildAll --trustAll'
          docker exec test 'sh' '-c' '/opt/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "ou=people,dc=example2,dc=com" --searchScope sub "(uid=user.*)" dn | grep ^dn: | wc -l | grep -q 10000'
  build-docker-alpine:
    runs-on: 'ubuntu-latest'
    services:
@@ -210,3 +239,12 @@
        run: |
          docker run --rm -it -d --memory="1g" --name=test localhost:5000/${GITHUB_REPOSITORY,,}:${{ env.release_version }}-alpine
          timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test | grep -q \"healthy\"; do sleep 10; done'
          docker exec test 'sh' '-c' '/opt/opendj/bin/dsconfig create-backend --hostname localhost --port 4444 --bindDN "cn=Directory Manager" --bindPassword password --backend-name=example2 --type je --set=base-dn:dc=example2,dc=com --set=enabled:true --no-prompt --trustAll'
          docker exec test 'sh' '-c' '/opt/opendj/bin/makeldif -o /tmp/test.ldif -c suffix=dc=example2,dc=com /opt/opendj/data/config/MakeLDIF/example.template'
          docker exec test 'sh' '-c' '/opt/opendj/bin/stop-ds'
          docker exec test 'sh' '-c' '/opt/opendj/bin/import-ldif --offline --ldifFile /tmp/test.ldif --backendID=example2'
          docker exec test 'sh' '-c' '/opt/opendj/bin/rebuild-index --offline --bindDN "cn=Directory Manager" --bindPassword password  --baseDN "dc=example2,dc=com" --rebuildAll'
          docker exec test 'sh' '-c' '/opt/opendj/bin/start-ds'
          docker exec test 'sh' '-c' '/opt/opendj/bin/rebuild-index --bindDN "cn=Directory Manager" --bindPassword password --baseDN "dc=example2,dc=com" --rebuildAll --trustAll'
          docker exec test 'sh' '-c' '/opt/opendj/bin/ldapsearch --hostname localhost --port 1636 --bindDN "cn=Directory Manager" --bindPassword password --useSsl --trustAll --baseDN "ou=people,dc=example2,dc=com" --searchScope sub "(uid=user.*)" dn | grep ^dn: | wc -l | grep -q 10000'
.github/workflows/deploy.yml
@@ -24,8 +24,9 @@
          sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/$(lsb_release -c -s)/winehq-$(lsb_release -c -s).sources
          sudo apt-get update
          sudo apt install --install-recommends winehq-stable || sudo apt install --install-recommends winehq-staging
          sudo mkdir -p /opt/wine/mono && sudo wget "https://dl.winehq.org/wine/wine-mono/8.0.0/wine-mono-8.0.0-x86.tar.xz" -P /opt/wine/mono && sudo tar -xf /opt/wine/mono/wine-mono-8.0.0-x86.tar.xz -C /opt/wine/mono && sudo rm /opt/wine/mono/wine-mono-8.0.0-x86.tar.xz
          wine --version
          version="9.4.0"; sudo wget "https://dl.winehq.org/wine/wine-mono/$version/wine-mono-$version-x86.msi" -O /tmp/wine-mono.msi
          wine msiexec /i /tmp/wine-mono.msi
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
@@ -65,6 +66,9 @@
          MAVEN_OPTS: -Dhttps.protocols=TLSv1.2 -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.requestSentEnabled=true -Dmaven.wagon.http.retryHandler.count=10
        if: ${{ github.event.workflow_run.event=='push' && env.MAVEN_USERNAME!='' && env.MAVEN_PASSWORD!=''}}
        run: mvn --batch-mode --errors --update-snapshots -Dgpg.passphrase=${{ secrets.GPG_PASSPHRASE }} deploy --file pom.xml
      - name: Build Javadoc
        continue-on-error: true
        run: mvn javadoc:aggregate
      - name: Upload artifacts OpenDJ Server
        uses: actions/upload-artifact@v4
        with:
@@ -156,6 +160,8 @@
          cd doc.openidentityplatform.org
          rm -rf ${REPO_NAME_LC}/modules
          cp -R ../${SITE_DOC_FOLDER}/target/asciidoc/antora/modules ../doc.openidentityplatform.org/${REPO_NAME_LC}
          rm -rf ${REPO_NAME_LC}/apidocs
          cp -R ../target/reports/apidocs ../doc.openidentityplatform.org/${REPO_NAME_LC}
          git add -A
          if ! git diff-index --quiet HEAD; then
            echo "committing changes to the docs repository"
.github/workflows/release.yml
@@ -28,8 +28,9 @@
          sudo wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/$(lsb_release -c -s)/winehq-$(lsb_release -c -s).sources
          sudo apt-get update
          sudo apt install --install-recommends winehq-stable || sudo apt install --install-recommends winehq-staging
          sudo mkdir -p /opt/wine/mono && sudo wget "https://dl.winehq.org/wine/wine-mono/8.0.0/wine-mono-8.0.0-x86.tar.xz" -P /opt/wine/mono && sudo tar -xf /opt/wine/mono/wine-mono-8.0.0-x86.tar.xz -C /opt/wine/mono && sudo rm /opt/wine/mono/wine-mono-8.0.0-x86.tar.xz
          wine --version
          version="9.4.0"; sudo wget "https://dl.winehq.org/wine/wine-mono/$version/wine-mono-$version-x86.msi" -O /tmp/wine-mono.msi
          wine msiexec /i /tmp/wine-mono.msi
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
README.md
@@ -13,7 +13,7 @@
OpenDJ is an [LDAPv3](http://tools.ietf.org/html/rfc4510) compliant directory service, which has been developed 
for the Java platform, providing a high performance, highly available, and secure store for the identities managed 
by your organization. Its easy installation process, combined with the power of the Java platform makes OpenDJ
the simplest, fastest directory to deploy and manage and allow [store LDAPv3 database in Cassandra/Scylla cluster](https://github.com/OpenIdentityPlatform/OpenDJ/wiki/How-To#store-ldap-catalog-data-in-cassandra-nosql-cluster).
the simplest, fastest directory to deploy and manage and allow store LDAPv3 database in [SQL JDBC database](https://github.com/OpenIdentityPlatform/OpenDJ/wiki/How-To#store-ldap-catalog-data-in-jdbc-databse) or [NoSQL Cassandra/Scylla cluster](https://github.com/OpenIdentityPlatform/OpenDJ/wiki/How-To#store-ldap-catalog-data-in-cassandra-nosql-cluster).
An open source, lightweight, embeddable directory that can easily share real-time customer, device, and user identity data across enterprise, cloud, social, and mobile environments.
* Massive data scale and high availability provide developers with ultra-lightweight ways to access identity data
opendj-cli/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <artifactId>opendj-parent</artifactId>
        <groupId>org.openidentityplatform.opendj</groupId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-cli</artifactId>
opendj-cli/src/main/resources/templates/dscfgSubcommand.ftl
@@ -13,7 +13,7 @@
  information: "Portions Copyright [year] [name of copyright owner]".
  Copyright 2011-2017 ForgeRock AS.
  Portions Copyright ${year} 3A Systems LLC.
  Portions Copyright 2024-${year} 3A Systems LLC.
////
[#${id}]
opendj-cli/src/main/resources/templates/refEntry.ftl
@@ -12,7 +12,7 @@
 # information: "Portions Copyright [year] [name of copyright owner]".
 #
 # Copyright 2015 ForgeRock AS.
 # Portions ${year} 3A Systems LLC.
 # Portions Copyright 2024-${year} 3A Systems LLC.
 #
////
opendj-config/pom.xml
@@ -19,7 +19,7 @@
  <parent>
    <groupId>org.openidentityplatform.opendj</groupId>
    <artifactId>opendj-parent</artifactId>
    <version>4.8.3-SNAPSHOT</version>
    <version>4.9.5-SNAPSHOT</version>
  </parent>
  <artifactId>opendj-config</artifactId>
  <name>OpenDJ Configuration API</name>
opendj-core/pom.xml
@@ -21,7 +21,7 @@
    <parent>
        <artifactId>opendj-parent</artifactId>
        <groupId>org.openidentityplatform.opendj</groupId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-core</artifactId>
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java
@@ -14,6 +14,7 @@
 * Copyright 2009-2010 Sun Microsystems, Inc.
 * Portions copyright 2013-2016 ForgeRock AS.
 * Portions copyright 2014 Manuel Gaupp
 * Portions copyright 2025 3A Systems, LLC
 */
package org.forgerock.opendj.ldap.schema;
@@ -1582,6 +1583,14 @@
               .extraProperties(RFC4512_ORIGIN)
               .implementation(new BooleanSyntaxImpl())
               .addToSchema();
        //Expression syntax for Boolean
        //
        //Values of this syntax hold either a Boolean value, or a configuration expression that evaluates to a Boolean value.
        builder.buildSyntax("1.3.6.1.4.1.36733.2.1.3.3.7")
                .description(SYNTAX_BOOLEAN_DESCRIPTION)
                .extraProperties(RFC4512_ORIGIN)
                .implementation(new BooleanSyntaxImpl())
                .addToSchema();
        builder.buildSyntax(SYNTAX_COUNTRY_STRING_OID)
               .description(SYNTAX_COUNTRY_STRING_DESCRIPTION)
@@ -1600,7 +1609,14 @@
               .extraProperties(RFC4512_ORIGIN)
               .implementation(new DirectoryStringSyntaxImpl())
               .addToSchema();
        //Expression syntax for Directory String
        //
        //Values of this syntax hold either an LDAP directory string value, or a configuration expression that evaluates to an LDAP directory string value.
        builder.buildSyntax("1.3.6.1.4.1.36733.2.1.3.3.15")
                .description(SYNTAX_DIRECTORY_STRING_DESCRIPTION)
                .extraProperties(RFC4512_ORIGIN)
                .implementation(new DirectoryStringSyntaxImpl())
                .addToSchema();
        builder.buildSyntax(SYNTAX_DIT_CONTENT_RULE_OID)
               .description(SYNTAX_DIT_CONTENT_RULE_DESCRIPTION)
               .extraProperties(RFC4512_ORIGIN)
@@ -1618,6 +1634,14 @@
               .extraProperties(RFC4512_ORIGIN)
               .implementation(new DistinguishedNameSyntaxImpl())
               .addToSchema();
        //Expression syntax for DN
        //
        //Values of this syntax hold either a DN value, or a configuration expression that evaluates to a DN value.
        builder.buildSyntax("1.3.6.1.4.1.36733.2.1.3.3.12")
                .description(SYNTAX_DN_DESCRIPTION)
                .extraProperties(RFC4512_ORIGIN)
                .implementation(new DistinguishedNameSyntaxImpl())
                .addToSchema();
        builder.buildSyntax(SYNTAX_ENHANCED_GUIDE_OID)
               .description(SYNTAX_ENHANCED_GUIDE_DESCRIPTION)
@@ -1660,7 +1684,14 @@
               .extraProperties(RFC4512_ORIGIN)
               .implementation(new IntegerSyntaxImpl())
               .addToSchema();
        //Expression syntax for Integer
        //
        //Values of this syntax hold either an integer value, or a configuration expression that evaluates to an integer value.
        builder.buildSyntax("1.3.6.1.4.1.36733.2.1.3.3.27")
                .description(SYNTAX_INTEGER_DESCRIPTION)
                .extraProperties(RFC4512_ORIGIN)
                .implementation(new IntegerSyntaxImpl())
                .addToSchema();
        builder.buildSyntax(SYNTAX_JPEG_OID)
               .description(SYNTAX_JPEG_DESCRIPTION)
               .extraProperties(RFC4512_ORIGIN)
opendj-doc-generated-ref/pom.xml
@@ -21,7 +21,7 @@
    <parent>
        <artifactId>opendj-parent</artifactId>
        <groupId>org.openidentityplatform.opendj</groupId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-doc-generated-ref</artifactId>
opendj-doc-generated-ref/src/main/asciidoc/admin-guide/chap-connection-handlers.adoc
@@ -12,7 +12,7 @@
  information: "Portions copyright [year] [name of copyright owner]".
 
  Copyright 2017 ForgeRock AS.
  Portions Copyright 2024 3A Systems LLC.
  Portions Copyright 2024-2025 3A Systems LLC.
////
:figure-caption!:
@@ -1251,7 +1251,8 @@
There are many possibilities when configuring HTTP authorization mechanisms. __This procedure shows only one OAuth 2.0 example.__
The example that follows demonstrates an OpenDJ directory server configured for tests (insecure connections) to request OAuth 2.0 token information from OpenAM. Download ForgeRock Access Management or OpenAM software from link:https://backstage.forgerock.com/downloads/[https://backstage.forgerock.com/downloads/, window=\_top].
The example that follows demonstrates an OpenDJ directory server configured for tests (insecure connections) to request OAuth 2.0 token information from OpenAM.
Download OpenAM software from link:https://github.com/OpenIdentityPlatform/OpenAM/releases[https://github.com/OpenIdentityPlatform/OpenAM/releases, window=\_top].
[#d67723e3953]
.Settings for OAuth 2.0 Example With OpenAM
opendj-doc-generated-ref/src/main/asciidoc/admin-guide/chap-import-export.adoc
@@ -352,10 +352,19 @@
When you create a new backend using the `dsconfig` command, OpenDJ directory server creates the following indexes automatically:
[none]
* `aci` presence
* `cn` equality, substring
* `ds-sync-conflict` equality
* `ds-sync-hist` ordering
* `entryUUID` equality
* `objectClass` equality
* `givenName` equality, substring
* `mail`  equality, substring
* `member` equality
* `sn` equality, substring
* `telephoneNumber` equality, substring
* `uid` equality
* `uniqueMember` equality
You can create additional indexes as described in xref:../admin-guide/chap-indexing.adoc#configure-indexes["Configuring and Rebuilding Indexes"].
opendj-doc-generated-ref/src/main/asciidoc/admin-guide/chap-indexing.adoc
@@ -1101,13 +1101,9 @@
a|-
a|4000
|===
When you create a new backend using the `dsconfig` command, OpenDJ directory server creates the following indexes automatically:
[none]
* `aci` presence
* `ds-sync-conflict` equality
* `ds-sync-hist` ordering
* `entryUUID` equality
* `objectClass` equality
When you create a new backend using the `dsconfig` command, the OpenDJ Directory Server also automatically creates these indexes.
You can create additional indexes as described in xref:../admin-guide/chap-indexing.adoc#configure-indexes["Configuring and Rebuilding Indexes"].
opendj-doc-generated-ref/src/main/asciidoc/admin-guide/chap-monitoring.adoc
@@ -12,12 +12,13 @@
  information: "Portions copyright [year] [name of copyright owner]".
 
  Copyright 2017 ForgeRock AS.
  Portions Copyright 2024 3A Systems LLC.
  Portions Copyright 2024-2025 3A Systems LLC.
////
:figure-caption!:
:example-caption!:
:table-caption!:
:opendj-version: 4.9.3
[#chap-monitoring]
@@ -40,7 +41,7 @@
OpenDJ exposes monitoring information over LDAP under the entry `cn=monitor`. Many different types of information are exposed. The following example shows monitoring information about the `userRoot` backend holding Example.com data:
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["ForgeRock Product Interface Stability"] in the __Reference__)
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["Product Interface Stability"] in the __Reference__)
[source, console]
----
@@ -82,7 +83,7 @@
----
$ java -jar ~/Downloads/opendmk-1.0-b02-*.jar
$ cd ~/Downloads/
$ unzip DS-5.5.0.zip
$ unzip opendj-{opendj-version}.zip
$ java -jar opendj/snmp/opendmk.jar
----
If you install under `/path/to`, then the runtime library needed for SNMP is `/path/to/OpenDMK-bin/lib/jdmkrt.jar`.
@@ -149,10 +150,10 @@
----
Use a command such as `snmpwalk` to check that the SNMP listen port works:
[source, console]
[source, console, subs="attributes"]
----
$ snmpwalk -v 2c -c OpenDJ@OpenDJ localhost:11161
SNMPv2-SMI::mib-2.66.1.1.1.1 = STRING: "OpenDJ 3.5.3..."
SNMPv2-SMI::mib-2.66.1.1.1.1 = STRING: "OpenDJ {opendj-version}..."
SNMPv2-SMI::mib-2.66.1.1.2.1 = STRING: "/path/to/opendj"
...
----
@@ -163,7 +164,7 @@
OpenDJ provides JMX-based monitoring. A number of tools support JMX, including `jconsole` and `jvisualvm`, which are bundled with the Sun/Oracle Java platform. JMX is not configured by default. Use the `dsconfig` command to configure the JMX connection handler:
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["ForgeRock Product Interface Stability"] in the __Reference__)
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["Product Interface Stability"] in the __Reference__)
Configure the server to activate JMX access. The following example uses the reserved port number, 1689:
@@ -247,7 +248,7 @@
The `status` command takes administrative credentials to read the configuration, as does the control panel:
[source, console]
[source, console, subs="attributes"]
----
$ status --bindDN "cn=Directory Manager" --bindPassword password
@@ -259,7 +260,7 @@
Host Name:                localhost
Administrative Users:     cn=Directory Manager
Installation Path:        /path/to/opendj
Version:                  OpenDJ 3.5.3
Version:                  OpenDJ {opendj-version}
Java Version:             version
Administration Connector: Port 4444 (LDAPS)
@@ -301,7 +302,7 @@
By default OpenDJ stores access and errors logs, and a server process ID file under the `logs/` directory. For the replication service, OpenDJ also keeps a replication log there. You can also configure a debug log. You can also configure policies about how logs are rotated, and how they are retained. You configure logging using the `dsconfig` command.
Each log depends on a __log publisher__, whose type corresponds to the type of log. OpenDJ provides a number of file-based log publishers out of the box, and supports the ForgeRock common audit event framework, sometimes referred to as Common Audit. The ForgeRock common audit event framework provides log handlers for publishing to CSV files, relational databases, and the UNIX system log (Syslog) as described in xref:#log-common-audit["Common ForgeRock Access Logs"]. The framework makes it possible to plug in additional handlers as well.
Each log depends on a __log publisher__, whose type corresponds to the type of log. OpenDJ provides a number of file-based log publishers out of the box, and supports the Open Identity Platform common audit event framework, sometimes referred to as Common Audit. The ForgeRock common audit event framework provides log handlers for publishing to CSV files, relational databases, and the UNIX system log (Syslog) as described in xref:#log-common-audit["Common ForgeRock Access Logs"]. The framework makes it possible to plug in additional handlers as well.
[#log-access]
==== Access Logs
@@ -325,14 +326,14 @@
[#log-common-audit]
==== Common ForgeRock Access Logs
==== Common Open Identity Platform Access Logs
In addition to the default file-based access log formats, OpenDJ directory server supports the ForgeRock common audit event framework. OpenDJ uses the framework to write access logs in formats that are compatible with all products using the framework. The framework uses transaction IDs that make it easy to correlate requests as they traverse the platform. This makes it easier to monitor activity and to enrich reports.
In addition to the default file-based access log formats, OpenDJ directory server supports the Open Identity Platform common audit event framework. OpenDJ uses the framework to write access logs in formats that are compatible with all products using the framework. The framework uses transaction IDs that make it easy to correlate requests as they traverse the platform. This makes it easier to monitor activity and to enrich reports.
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["ForgeRock Product Interface Stability"] in the __Reference__)
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["Product Interface Stability"] in the __Reference__)
The ForgeRock common audit event framework is built around audit event handlers. Audit event handlers can encapsulate their own configurations. Audit event handlers are the same in each product in the ForgeRock platform. As a result, you can plug in custom handlers that comply with the framework without having to upgrade OpenDJ directory server.
The ForgeRock common audit event framework includes handlers for logging audit event messages to local files and facilities, as well as to remote systems. Handlers for the following are supported:
The Open Identity Platform common audit event framework is built around audit event handlers. Audit event handlers can encapsulate their own configurations. Audit event handlers are the same in each product in the Open Identity Platform. As a result, you can plug in custom handlers that comply with the framework without having to upgrade OpenDJ directory server.
The Open Identity Platform common audit event framework includes handlers for logging audit event messages to local files and facilities, as well as to remote systems. Handlers for the following are supported:
* CSV files, with support for tamper-evident logs.
+
@@ -350,7 +351,7 @@
+
Although it is rarely used for access events, you can configure the Syslog handler as an external log publisher that logs access messages to the UNIX Syslog facility.
The ForgeRock common audit event framework supports a variety of audit event topics. OpenDJ currently supports handling for access events, which are system boundary events such as the initial request and final response to that request. In other words, the implementation in OpenDJ is focused only on access logging. Based on the connection handler for the request, OpenDJ divides access events into `ldap-access` events and `http-access` events.
The Open Identity Platform common audit event framework supports a variety of audit event topics. OpenDJ currently supports handling for access events, which are system boundary events such as the initial request and final response to that request. In other words, the implementation in OpenDJ is focused only on access logging. Based on the connection handler for the request, OpenDJ divides access events into `ldap-access` events and `http-access` events.
To enable common audit-based logging, follow one of these procedures:
* xref:#log-common-audit-ldap-csv["To Enable LDAP CSV Access Logs"]
@@ -692,7 +693,7 @@
[#log-common-audit-trust-transaction-ids]
.To Trust Transaction IDs
====
Client applications using the ForgeRock common audit event framework send transaction IDs with their requests. The transaction IDs are used to correlate audit events for monitoring and reporting that trace the request through multiple applications.
Client applications using the Open Identity Platform common audit event framework send transaction IDs with their requests. The transaction IDs are used to correlate audit events for monitoring and reporting that trace the request through multiple applications.
Transaction IDs are sent over LDAP using an internal OpenDJ request control. They are sent over HTTP in an HTTP header.
@@ -1702,7 +1703,7 @@
For the HTTP Connection Handler, OpenDJ maintains a separate access log in `logs/http-access`. This access log, by default configured as the File Based HTTP Access Log Publisher, uses a different format than the LDAP access log. This HTTP access log uses link:http://www.w3.org/TR/WD-logfile.html[Extended Log File Format, window=\_blank] with fields described in link:http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/676400bc-8969-4aa7-851a-9319490a9bbb.mspx?mfr=true[Microsoft's implementation, window=\_blank] as well.
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["ForgeRock Product Interface Stability"] in the __Reference__)
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["Product Interface Stability"] in the __Reference__)
--
The following default fields are shown here in the order they occur in the log file:
@@ -1755,7 +1756,7 @@
Execution time in milliseconds needed by OpenDJ to service the HTTP request
`x-transaction-id`::
ForgeRock common audit event framework transaction ID for the request
Open Identity Platform common audit event framework transaction ID for the request
+
This defaults to `0` unless you configure OpenDJ to trust transaction IDs as described in xref:#log-common-audit-trust-transaction-ids["To Trust Transaction IDs"].
opendj-doc-generated-ref/src/main/asciidoc/admin-guide/chap-troubleshooting.adoc
@@ -12,12 +12,13 @@
  information: "Portions copyright [year] [name of copyright owner]".
 
  Copyright 2017 ForgeRock AS.
  Portions Copyright 2024 3A Systems LLC.
  Portions Copyright 2024-2025 3A Systems LLC.
////
:figure-caption!:
:example-caption!:
:table-caption!:
:opendj-version: 4.9.3
[#chap-troubleshooting]
@@ -787,10 +788,10 @@
When you cannot resolve a problem yourself, and want to ask for help, clearly identify the problem and how you reproduce it, and also the version of OpenDJ you use to reproduce the problem. The version includes both a version number and also a build time stamp:
[source, console]
[source, console, subs="attributes"]
----
$ dsconfig --version
OpenDJ 3.5.3
OpenDJ {opendj-version}
Build yyyymmddhhmmssZ
----
Be ready to provide the following additional information:
opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-install.adoc
@@ -12,12 +12,13 @@
  information: "Portions copyright [year] [name of copyright owner]".
 
  Copyright 2017 ForgeRock AS.
  Portions Copyright 2024 3A Systems LLC.
  Portions Copyright 2024-2025 3A Systems LLC.
////
:figure-caption!:
:example-caption!:
:table-caption!:
:opendj-version: 4.9.3
[#chap-install]
@@ -62,35 +63,29 @@
+
Antivirus and intrusion detection systems that do a deep inspection of database files are not compatible with OpenDJ directory server. Disable antivirus and intrusion detection systems, or at least prevent them from operating on OpenDJ directory server files.
. Download enterprise software releases through the ForgeRock link:https://backstage.forgerock.com/[BackStage, window=\_blank] site. ForgeRock enterprise releases are thoroughly validated builds for ForgeRock customers who run OpenDJ in production deployments, and for those who want to try or test with release builds.
. Download software releases from the link:https://github.com/OpenIdentityPlatform/OpenDJ/releases[GitHub, window=\_blank].
+
--
The following OpenDJ 3.5.3 server software is available:
The following OpenDJ {opendj-version} server software is available:
opendj-3.5.3.zip,opendj-oem-3.5.3.zip (OEM Edition)::
opendj-{opendj-version}.zip::
Cross-platform OpenDJ directory server installation files.
opendj_3.5.3-1_all.deb,opendj-oem_3.5.3-1_all.deb (OEM Edition)::
opendj_{opendj-version}-1_all.deb::
OpenDJ directory server native package for Debian and related Linux distributions.
opendj-3.5.3-1.noarch.rpm,opendj-oem-3.5.3-1.noarch.rpm (OEM Edition)::
opendj-{opendj-version}-1.noarch.rpm::
OpenDJ directory server native package for Red Hat and related Linux distributions.
opendj-dsml-servlet-3.5.3.war::
org.openidentityplatform.opendj.opendj-dsml-servlet.war::
Cross-platform OpenDJ DSML gateway web archive
opendj-rest2ldap-servlet-3.5.3.war::
org.openidentityplatform.opendj.opendj-rest2ldap-servlet.war::
Cross-platform OpenDJ REST to LDAP gateway web archive
--
+
[NOTE]
======
The OEM distribution of OpenDJ directory server does not include Berkeley DB Java Edition, and so does not support JE backends.
======
+
. If you plan to install OpenDJ DSML gateway or OpenDJ REST to LDAP gateway, make sure you have an appropriate application server installed.
+
@@ -113,9 +108,9 @@
======
After completing the steps in xref:#before-you-install["To Prepare For Installation"], follow these steps:
. Unzip opendj-3.5.3.zip, and then run the `setup` command, described in xref:../reference/admin-tools-ref.adoc#setup-1[setup(1)] in the __Reference__.
. Unzip opendj-{opendj-version}.zip, and then run the `setup` command, described in xref:../reference/admin-tools-ref.adoc#setup-1[setup(1)] in the __Reference__.
+
When you unzip `opendj-3.5.3.zip`, a top-level `opendj` directory is created in the directory where you unzipped the file. On Windows systems if you unzip `opendj-3.5.3.zip`, with Right-Click > Extract All, be sure to remove the trailing `opendj-3.5.3` directory from the folder you specify.
When you unzip `opendj-{opendj-version}.zip`, a top-level `opendj` directory is created in the directory where you unzipped the file. On Windows systems if you unzip `opendj-{opendj-version}.zip`, with Right-Click > Extract All, be sure to remove the trailing `opendj-{opendj-version}` directory from the folder you specify.
+
Find the `setup` command in the following locations:
@@ -203,11 +198,11 @@
====
The OpenDJ `setup --cli` command launches a command-line installation that is interactive by default. After completing the steps in xref:#before-you-install["To Prepare For Installation"], follow these steps:
. Unzip `opendj-3.5.3.zip` in the file system directory where you want to install the server.
. Unzip `opendj-{opendj-version}.zip` in the file system directory where you want to install the server.
+
The `setup` command, described in xref:../reference/admin-tools-ref.adoc#setup-1[setup(1)] in the __Reference__, uses the directory where you unzipped the files as the installation directory, and does not ask you where to install OpenDJ directory server. Therefore, if you want to install elsewhere on the file system, unzip the files in that location.
+
When you unzip `opendj-3.5.3.zip`, a top-level `opendj` directory is created in the directory where you unzipped the file. On Windows systems if you unzip `opendj-3.5.3.zip`, with Right-Click > Extract All, be sure to remove the trailing `opendj-3.5.3` directory from the folder you specify.
When you unzip `opendj-{opendj-version}.zip`, a top-level `opendj` directory is created in the directory where you unzipped the file. On Windows systems if you unzip `opendj-{opendj-version}.zip`, with Right-Click > Extract All, be sure to remove the trailing `opendj-{opendj-version}` directory from the folder you specify.
. Run the `setup --cli` command found in the `/path/to/opendj` directory.
+
@@ -386,7 +381,7 @@
. Run the `status` command, described in xref:../reference/admin-tools-ref.adoc#status-1[status(1)] in the __Reference__, to make sure your OpenDJ server is working as expected as shown in the following example:
+
[source, console]
[source, console, subs="attributes"]
----
$ /path/to/opendj/bin/status
@@ -404,7 +399,7 @@
Host Name:                opendj.example.com
Administrative Users:     cn=Directory Manager
Installation Path:        /path/to/opendj
Version:                  OpenDJ 3.5.3
Version:                  OpenDJ {opendj-version}
Java Version:             version
Administration Connector: Port 4444 (LDAPS)
@@ -448,14 +443,14 @@
. Install the OpenDJ directory server package:
+
[source, console]
[source, console, subs="attributes"]
----
$ sudo dpkg -i opendj_3.5.3-1_all.deb
$ sudo dpkg -i opendj_{opendj-version}-1_all.deb
Selecting previously unselected package opendj.
(Reading database ... 185569 files and directories currently installed.)
Unpacking opendj (from opendj_3.5.3-1_all.deb) ...
Unpacking opendj (from opendj_{opendj-version}-1_all.deb) ...
Setting up opendj (3.5.3) ...
Setting up opendj ({opendj-version}) ...
 Adding system startup for /etc/init.d/opendj ...
   /etc/rc0.d/K20opendj -> ../init.d/opendj
   /etc/rc1.d/K20opendj -> ../init.d/opendj
@@ -487,10 +482,10 @@
. (Optional)  Check OpenDJ directory server status:
+
[source, console]
[source, console, subs="attributes"]
----
$ service opendj status
$opendj status: > Running.
opendj status: > Running.
$ sudo /opt/opendj/bin/status
@@ -508,7 +503,7 @@
Host Name:                ubuntu.example.com
Administrative Users:     cn=Directory Manager
Installation Path:        /opt/opendj
Version:                  OpenDJ 3.5.3
Version:                  OpenDJ {opendj-version}
Java Version:             version
Administration Connector: Port 4444 (LDAPS)
@@ -559,9 +554,9 @@
. Install the OpenDJ directory server package:
+
[source, console]
[source, console, subs="attributes"]
----
# rpm -i opendj-3.5.3-1.noarch.rpm
# rpm -i opendj-{opendj-version}-1.noarch.rpm
Pre Install - initial install
Post Install - initial install
@@ -586,7 +581,7 @@
. (Optional)  Check OpenDJ directory server status:
+
[source, console]
[source, console, subs="attributes"]
----
# service opendj status
opendj status: > Running.
@@ -607,7 +602,7 @@
Host Name:                fedora.example.com
Administrative Users:     cn=Directory Manager
Installation Path:        /opt/opendj
Version:                  OpenDJ 3.5.3
Version:                  OpenDJ {opendj-version}
Java Version:             version
Administration Connector: Port 4444 (LDAPS)
@@ -688,12 +683,12 @@
. Prepare an installation script:
+
[source, console]
[source, console, subs="attributes"]
----
$ cat /net/install/dj/1/setup.sh
#!/bin/sh
unzip -d /path/to /net/install/dj/opendj-3.5.3.zip && cd /path/to/opendj
unzip -d /path/to /net/install/dj/opendj-{opendj-version}.zip && cd /path/to/opendj
./setup --cli --propertiesFilePath /net/install/dj/1/setup.props \
  --acceptLicense --no-prompt
----
@@ -743,10 +738,10 @@
. Run your installation script:
+
[source, console]
[source, console, subs="attributes"]
----
$ /net/install/dj/1/setup.sh
Archive:  /net/install/dj/opendj-3.5.3.zip
Archive:  /net/install/dj/opendj-{opendj-version}.zip
   creating: /path/to/opendj
...
  inflating: /path/to/opendj/setup
@@ -977,7 +972,7 @@
--
Follow these steps to install the OpenDJ REST to LDAP gateway:
. Deploy `opendj-rest2ldap-servlet-3.5.3.war` according to the instructions for your application server.
. Deploy `org.openidentityplatform.opendj.opendj-rest2ldap-servlet.war` according to the instructions for your application server.
. Edit the configuration files in the deployed gateway web application.
+
@@ -1062,7 +1057,7 @@
======
You configure the gateway to access your directory service by editing the configuration file `opendj-rest2ldap-servlet.json` in the deployed OpenDJ REST to LDAP gateway web application:
. Deploy `opendj-rest2ldap-servlet-3.5.3-servlet.war` according to the instructions for your application server.
. Deploy `org.openidentityplatform.opendj.opendj-rest2ldap-servlet.war` according to the instructions for your application server.
. Edit `opendj-rest2ldap-servlet.json` where you deployed the gateway web application.
+
@@ -1121,7 +1116,7 @@
====
The OpenDJ DSML gateway functions as a web application in a web application container. The DSML gateway runs independently of OpenDJ directory server. You configure the gateway to access your directory service by editing the `ldap.host` and `ldap.port` parameters in the gateway `WEB-INF/web.xml` configuration file:
. Deploy `opendj-dsml-servlet-3.5.3.war` according to the instructions for your application server.
. Deploy `org.openidentityplatform.opendj.opendj-dsml-servlet.war` according to the instructions for your application server.
. Edit `WEB-INF/web.xml` to ensure the values for `ldap.host` and `ldap.port` are correct.
opendj-doc-generated-ref/src/main/asciidoc/install-guide/chap-upgrade.adoc
@@ -12,20 +12,21 @@
  information: "Portions copyright [year] [name of copyright owner]".
 
  Copyright 2017 ForgeRock AS.
  Portions Copyright 2024 3A Systems LLC.
  Portions Copyright 2024-2025 3A Systems LLC.
////
:figure-caption!:
:example-caption!:
:table-caption!:
:opendj-version: 4.9.3
[#chap-upgrade]
== Upgrading to OpenDJ 3.5
== Upgrading to OpenDJ 4.9
This chapter covers upgrade from previous versions.
If the OpenDJ directory server version is older than 2.6.0, you must upgrade your deployment to use at least OpenDJ directory server 2.6.0 before following the procedures in this chapter. For details on upgrading to that version, see link:https://backstage.forgerock.com/docs/opendj/2.6/install-guide/#chap-upgrade[Upgrading to OpenDJ 2.6.0, window=\_blank].
If the OpenDJ directory server version is older than 2.6.0, you must upgrade your deployment to use at least OpenDJ directory server 2.6.0 before following the procedures in this chapter.
[TIP]
====
@@ -39,13 +40,9 @@
* xref:#before-you-upgrade["Before You Upgrade"]
* xref:#upgrade-zip["To Upgrade to OpenDJ 3.5"]
* xref:#upgrade-zip["To Upgrade to OpenDJ 4.9"]
* xref:#upgrade-zip-example["Upgrading to OpenDJ 3.5"]
* xref:#upgrade-je-pdb["To Upgrade to OpenDJ OEM Edition"]
* xref:#upgrade-je-pdb-example["Upgrading To OpenDJ OEM Edition"]
* xref:#upgrade-zip-example["Upgrading to OpenDJ 4.9"]
* xref:#upgrade-repl["To Upgrade Replicated Servers"]
@@ -64,13 +61,11 @@
+
Make sure you have the credentials to run commands as the user who owns the server.
. (Optional)  If OpenDJ directory server runs with Java 6, move to a newer version before continuing the upgrade process.
. (Optional) If OpenDJ directory server runs with Java 6, move to a newer version, at least Java 8, before continuing the upgrade process.
+
To move to a newer version, edit the `default.java-home` setting in the `opendj/config/java.properties` file, and then run the `dsjavaproperties` command.
. (Optional)  If you are upgrading to OpenDJ OEM edition from OpenDJ 2.6, make sure there is enough disk space to export all of the data to LDIF files.
. Download enterprise software releases through the ForgeRock link:https://backstage.forgerock.com/[BackStage, window=\_blank] site. ForgeRock enterprise releases are thoroughly validated builds for ForgeRock customers who run OpenDJ in production deployments, and for those who want to try or test with release builds.
. Download the latest release from the link:https://github.com/OpenIdentityPlatform/OpenDJ/releases[GitHub, window=\_blank] site.
. (Optional)  If you are upgrading OpenDJ directory server on Windows, and OpenDJ is registered as a Windows service, disable OpenDJ as a Windows service before upgrade, as in the following example:
+
@@ -89,10 +84,8 @@
====
[#upgrade-zip]
.To Upgrade to OpenDJ 3.5
.To Upgrade to OpenDJ 4.9
====
If you are upgrading to the OEM edition from OpenDJ 2.6, then this procedure does not apply. Skip instead to xref:#upgrade-je-pdb["To Upgrade to OpenDJ OEM Edition"].
Before starting this procedure, follow the steps in xref:#before-you-upgrade["Before You Upgrade"].
To upgrade to OpenDJ directory server installed from native packages (.deb, .rpm), use the command-line package management tools provided by the system.
@@ -128,7 +121,7 @@
[NOTE]
======
When you upgrade to OpenDJ 3.5 from an OpenDJ 3 or earlier, the upgrade procedure leaves the HTTP connection handler disabled.
When you upgrade to OpenDJ 4.9 from an OpenDJ 3 or earlier, the upgrade procedure leaves the HTTP connection handler disabled.
The newer configuration supports inheritance and subsresources, but is not compatible with the previous configuration.
You must rewrite your configuration to the version described in xref:../reference/appendix-rest2ldap.adoc#appendix-rest2ldap["REST to LDAP Configuration"] in the __Reference__, and then reconfigure the server to use the new configuration. For details, see xref:../admin-guide/chap-connection-handlers.adoc#setup-rest2ldap["RESTful Client Access Over HTTP"] in the __Administration Guide__.
======
@@ -144,11 +137,11 @@
====
[#upgrade-zip-example]
.Upgrading to OpenDJ 3.5
.Upgrading to OpenDJ 4.9
====
The following example upgrades an OpenDJ 2.6.3 directory server, backing up the current server directory in case the upgrade process fails. In this example, the server properties are updated to use Java 8, and the Local DB backend is migrated to a JE backend:
[source, console]
[source, console, subs="attributes"]
----
$ cd /path/to/
$ sed -e "s/default.java-home=.*/default.java-home=\/path\/to\/jdk1.8/" \
@@ -159,29 +152,29 @@
$ /path/to/opendj/bin/stop-ds --quiet
... msg=The Directory Server is now stopped
$ zip -rq OpenDJ-backup.zip opendj/
$ unzip -o ~/Downloads/opendj-3.5.3.zip
$ unzip -o ~/Downloads/opendj-{opendj-version}.zip
$ /path/to/opendj/upgrade --acceptLicense
>>>> OpenDJ Upgrade Utility
 * OpenDJ will be upgraded from version 2.6.3.12667 to
 3.5.3.build-hash
 {opendj-version}.build-hash
 * See '/path/to/opendj/upgrade.log' for a detailed log of this operation
>>>> Preparing to upgrade
  OpenDJ 3.5.3 introduced changes to the JE backend configuration and database
  OpenDJ {opendj-version} introduced changes to the JE backend configuration and database
  format. The upgrade will update all JE backend configurations, but will only
  migrate JE backend databases which are associated with *enabled* JE
  backends. It is very strongly recommended that any existing data has been
  backed up and that you have read the upgrade documentation before
  proceeding. Do you want to proceed with the upgrade? (yes/no) [no]: yes
  OpenDJ 3.5.3 changed the matching rule implementations. All indexes have to
  OpenDJ {opendj-version} changed the matching rule implementations. All indexes have to
  be rebuilt. This could take a long time to proceed. Do you want to launch
  this process automatically at the end of the upgrade? (yes/no) [no]: yes
  OpenDJ 3.5.3 improved the replication changelog storage format. As a
  OpenDJ {opendj-version} improved the replication changelog storage format. As a
  consequence, the old changelog content of the current replication server
  will be erased by the upgrade. The new changelog content will be
  automatically reconstructed from the changelog of other replication servers
@@ -233,7 +226,7 @@
  Archiving concatenated schema.......................................   100%
>>>> OpenDJ was successfully upgraded from version 2.6.3.12667 to
3.5.3.build-hash
4.9.1.build-hash
>>>> Performing post upgrade tasks
@@ -249,217 +242,6 @@
----
====
[#upgrade-je-pdb]
.To Upgrade to OpenDJ OEM Edition
====
If you are not upgrading to the OEM edition from OpenDJ 2.6, then this procedure does not apply. Skip instead to xref:#upgrade-zip["To Upgrade to OpenDJ 3.5"].
Before starting this procedure, follow the steps in xref:#before-you-upgrade["Before You Upgrade"].
[NOTE]
======
OpenDJ directory server backend storage options have changed since OpenDJ 2.6. The underlying implementation is based on an extensible architecture, allowing you to choose the backend storage type when you create a persistent backend for directory data.
This procedure applies when you upgrade to the OEM edition from OpenDJ 2.6, changing the underlying backend storage. The configuration changes from a Local DB backend to a PDB Backend, but the `upgrade` command in this version __deletes the data from OpenDJ directory server__. Follow the instructions in this procedure to avoid data loss.
======
Follow these steps:
. Login as the user who owns the current OpenDJ server.
. Stop the current OpenDJ server.
. Export all of the data to LDIF files.
+
OpenDJ directory server OEM edition uses a new backend type, PDB. This edition does not support the older Local DB backend type. The upgrade process transforms the configuration to use the new backend type, but it does not export and import directory data. You must export the data, unpack the files of the new version over the old, run the upgrade, and then import the data.
+
The following example exports Example.com data from the `userRoot` backend to an LDIF file:
+
[source, console]
----
$ export-ldif --backendID userRoot --ldifFile ../ldif/Example.ldif
----
. If you have not already backed up the current OpenDJ server, make a back up copy of the directory where OpenDJ is installed.
. Unpack the new files over the current server files:
+
* When upgrading the .zip distribution, overwrite the current files.
+
The following example overwrites the current files with the new files:
+
[source, console]
----
$ cd /path/to ; unzip -o ~/Downloads/opendj-3.5.3.zip
----
* When upgrading native packaging, use the command-line package management tools provided by the system to remove the 2.6 package, and then install the new package.
+
For details, see xref:chap-uninstall.adoc#uninstall-deb["To Uninstall the Debian Package"] or xref:chap-uninstall.adoc#uninstall-rpm["To Uninstall the RPM Package"], and xref:chap-install.adoc#install-deb["To Install From the Debian Package"] or xref:chap-install.adoc#install-rpm["To Install From the RPM Package"].
. Run the `upgrade` command to bring OpenDJ configuration and schema data up to date with the new binary and script files that replaced existing server files.
+
By default, the `upgrade` command requests confirmation before making important configuration changes. For some potentially long-duration tasks, such as rebuilding indexes, the default choice is to defer the tasks until after upgrade. Tasks that are not performed during upgrade must generally be performed after upgrade but before you restart the server.
+
You can use the `--no-prompt` option to run the command non-interactively, with the `--acceptLicense` option to accept the license terms non-interactively.
+
When using the `--no-prompt` option, if the `upgrade` command cannot complete because it requires confirmation for a potentially very long or critical task, then it exits with an error and a message about how to finish making the changes. You can add the `--force` option to force a non-interactive upgrade to continue in this case, also performing long running and critical tasks.
+
Once this step is complete, OpenDJ directory server no longer has access to user data that was stored in Local DB backends.
. (Optional)  If user data occupies significant disk space, and not enough disk space is available, then remove binary backups of the user data that you exported to LDIF.
+
The upgrade process moves old user backend data to `opendj/db/*.bak` directories. This old user backend data is not accessible after upgrade. You can remove the old user backend data as shown in the following example:
+
[source, console]
----
$ rm -rf /path/to/opendj/db/*.bak
----
. Import all of the data from LDIF files.
+
The following example imports Example.com data from an LDIF file to the `userRoot` backend:
+
[source, console]
----
$ cd opendj/bin ; import-ldif --backendID userRoot --ldifFile ../ldif/Example.ldif
----
+
Make sure you perform this step __for all user data backends__.
. Start the upgraded OpenDJ server.
+
Replication updates the upgraded server with changes that occurred during the upgrade process.
+
At this point the upgrade process is complete. See the resulting `upgrade.log` file for a full list of operations performed.
====
[#upgrade-je-pdb-example]
.Upgrading To OpenDJ OEM Edition
====
The following example upgrades an OpenDJ 2.6.3 directory server to OpenDJ OEM edition, where the backend type for data storage is PDB. With the OEM edition, Local DB and JE backends are not supported. In this example, the server properties are updated to use Java 8, and the Local DB backend configuration is converted to use PDB backend. The directory data is exported to LDIF before upgrade, and imported from LDIF after upgrade:
[source, console]
----
$ cd /path/to/
$ sed -e "s/default.java-home=.*/default.java-home=\/path\/to\/jdk1.8/" \
 opendj/config/java.properties \
 > opendj/config/java.properties.new ; \
 mv opendj/config/java.properties.new opendj/config/java.properties
$ /path/to/opendj/bin/dsjavaproperties
$ /path/to/opendj/bin/stop-ds --quiet
... msg=The Directory Server is now stopped
$ /path/to/opendj/bin/export-ldif --backendID userRoot \
 --ldifFile opendj/ldif/Example.ldif
$ zip -rq opendj-backup.zip opendj/
$ unzip -o ~/Downloads/opendj-oem-3.5.3.zip
$ /path/to/opendj/upgrade --acceptLicense
>>>> OpenDJ Upgrade Utility
 * OpenDJ will be upgraded from version 2.6.3.12667 to
 3.5.3.build-hash
 * See '/path/to/opendj/upgrade.log' for a detailed log of this operation
>>>> Preparing to upgrade
  WARNING: OpenDJ 3.5.3 OEM Edition removes support for the Berkeley JE
  backend.
  The upgrade tool will reconfigure all JE backends as PDB backends.
  After the upgrade the new PDB backend(s) will be empty. It is therefore very
  strongly recommended that any data that was in the JE backends be exported
  to LDIF so that it can be re-imported once the upgrade completes.
  Do you want to make this configuration change? (yes/no) [no]: yes
  OpenDJ 3.5.3 changed the matching rule implementations. All indexes have to
  be rebuilt. This could take a long time to proceed. Do you want to launch
  this process automatically at the end of the upgrade? (yes/no) [no]: yes
  OpenDJ 3.5.3 improved the replication changelog storage format. As a
  consequence, the old changelog content of the current replication server
  will be erased by the upgrade. The new changelog content will be
  automatically reconstructed from the changelog of other replication servers
  in the topology. After the upgrade, dsreplication reset-change-number can be
  used to reset the changelog change-number of the current replication server
  to match another replication server. Do you want to proceed with the
  upgrade? (yes/no) [no]: yes
  The upgrade is ready to proceed. Do you wish to continue? (yes/no) [yes]:
>>>> Performing upgrade
  Changing matching rule for 'userCertificate' and 'caCertificate' to
  CertificateExactMatch...............................................   100%
  Configuring 'CertificateExactMatch' matching rule...................   100%
  Replacing schema file '03-pwpolicyextension.ldif'...................   100%
  Removing 'dc=replicationchanges' backend............................   100%
  Removing ACI for 'dc=replicationchanges'............................   100%
  Adding default privilege 'changelog-read' to all root DNs...........   100%
  Adding PKCS5S2 password storage scheme configuration................   100%
  Rerunning dsjavaproperties..........................................   100%
  Updating ds-cfg-java-class attribute in File-Based Debug Logger.....   100%
  Deleting ds-cfg-default-debug-level attribute in File-Based Debug
  Logger..............................................................   100%
  Updating ds-cfg-default-severity attribute in File-Based Error
  Logger..............................................................   100%
  Updating ds-cfg-override-severity attribute in Replication Repair
  Logger..............................................................   100%
  Removing config for 'Network Groups'................................   100%
  Removing config for 'Workflows'.....................................   100%
  Removing config for 'Workflow Elements'.............................   100%
  Removing config for 'Network Group Plugin'..........................   100%
  Removing config for 'Extensions'....................................   100%
  Removing config for 'File System Entry Cache'.......................   100%
  Removing config for 'Entry Cache Preload'...........................   100%
  Removing file '/path/to/opendj/bin/dsframework'.....................   100%
  Removing file '/path/to/opendj/bat/dsframework.bat'.................   100%
  Removing file '/path/to/opendj/lib/je.jar'..........................   100%
  Renaming local-db backend directory '/path/to/opendj/db/userRoot'
  to '/path/to/opendj/db/userRoot.bak'................................   100%
  Reconfiguring local-db backends to PDB backends.....................   100%
  Reconfiguring local-db backend indexes to PDB backend indexes.......   100%
  Reconfiguring local-db backend VLV indexes to PDB backend VLV
  indexes.............................................................   100%
  Removing file '/path/to/opendj/bin/dbtest'..........................   100%
  Removing file '/path/to/opendj/bat/dbtest.bat'......................   100%
  Removing content of changelog in '/path/to/opendj/./changelogDb'
  directory...........................................................   100%
  Enable log file based replication changelog storage.................   100%
  Replacing schema file '02-config.ldif'..............................   100%
  Archiving concatenated schema.......................................   100%
>>>> OpenDJ was successfully upgraded from version 2.6.3.12667 to
3.5.3.build-hash
>>>> Performing post upgrade tasks
  [!] You must reimport all your data into the PDB backends in order to have a
  fully functional server
  ...
>>>> Post upgrade tasks complete
 * See '/path/to/opendj/upgrade.log' for a detailed log of this operation
$ /path/to/opendj/bin/import-ldif --backendID userRoot \
 --ldifFile opendj/ldif/Example.ldif
$ /path/to/opendj/bin/start-ds --quiet
# Optionally remove Local DB backup data:
$ rm -rf /path/to/opendj/db/userRoot.bak/
----
====
[#upgrade-repl]
.To Upgrade Replicated Servers
====
opendj-doc-generated-ref/src/main/asciidoc/reference/appendix-rest2ldap-3-0.adoc
@@ -12,7 +12,7 @@
  information: "Portions copyright [year] [name of copyright owner]".
 
  Copyright 2017 ForgeRock AS.
  Portions Copyright 2024 3A Systems LLC.
  Portions Copyright 2024-2025 3A Systems LLC.
////
:figure-caption!:
@@ -38,7 +38,7 @@
--
The JSON format configuration can hold the following configuration objects. Some of the configuration settings are available only in the REST LDAP gateway configuration. The order here is the order shown in the default configuration file:
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["ForgeRock Product Interface Stability"])
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["Product Interface Stability"])
"ldapConnectionFactories" (required, gateway only)::
Configures how the gateway connects to LDAP servers. This entire configuration object applies only to the REST to LDAP gateway.
@@ -198,7 +198,7 @@
The gateway authenticates by simple bind using the credentials specified:
+
[source, javascript]
[source, json]
----
{
    "authentication": {
@@ -334,10 +334,10 @@
"proxyAuthzIdTemplate" (gateway only)::
Specifies the template to derive the authorization ID from the security context created during authentication. Use `{dn}` to indicate the user's bind DN or `{id}` to indicate the user name provided for authentication.
Specifies the template to derive the authorization ID from the security context created during authentication. Use `\{dn\}` to indicate the user's bind DN or `\{id\}` to indicate the user name provided for authentication.
+
Default: "dn:{dn}"
Default: "dn:\{dn\}"
"mappings"::
For each collection URI such as `/users` and `/groups`, you configure a mapping between the JSON resource returned over HTTP, and the LDAP entry returned by the directory service.
@@ -401,7 +401,7 @@
* RDN and resource ID are both derived from a single user attribute in the LDAP entry, as in the following example, where the `uid` attribute is the RDN and its value is the JSON resource ID:
+
[source, javascript]
[source, json]
----
{
    "namingStrategy": {
@@ -414,7 +414,7 @@
* RDN and resource ID are derived from separate user attributes in the LDAP entry, as in the following example where the RDN attribute is `uid` but the JSON resource ID is the value of the `mail` attribute:
+
[source, javascript]
[source, json]
----
{
    "namingStrategy": {
@@ -428,7 +428,7 @@
* RDN is derived from a user attribute and the resource ID from an operational attribute in the LDAP entry, as in the following example, where the RDN attribute is `uid` but the JSON resource ID is the value of the `entryUUID` operational attribute:
+
[source, javascript]
[source, json]
----
{
    "namingStrategy": {
@@ -444,7 +444,7 @@
LDAP attributes to include during LDAP add operations as an array of type-value lists, such as the following example:
+
[source, javascript]
[source, json]
----
{
    "additionalLDAPAttributes": [
@@ -476,7 +476,7 @@
This can be useful as in the default case where each JSON resource "schemas" takes the SCIM URN, and so the value is not related to the underlying LDAP entries:
+
[source, javascript]
[source, json]
----
{
    "schemas": {
@@ -494,7 +494,7 @@
Simple mappings are used where the correspondence between JSON fields and LDAP attributes is one-to-one:
+
[source, javascript]
[source, json]
----
{
    "userName": {
@@ -555,7 +555,7 @@
This mapping works for LDAP attributes whose values reference other entries. This is shown in the following example from the default configuration. The LDAP `manager` attribute values are user entry DNs. Here, the JSON `manager` field takes the user ID and name from the entry referenced by the LDAP attribute. On updates, changes to the JSON manager `_id` affect which manager entry is referenced, yet any changes to the manager's name are discarded, because changing managers only affects which user entry to point to, not the referenced user's name:
+
[source, javascript]
[source, json]
----
{
    "manager": {
@@ -589,7 +589,7 @@
Babs Jensen's manager in the sample LDAP data is Torrey Rigden, who has user ID `trigden`. Babs's entry has `manager: uid=trigden,ou=People,dc=example,dc=com`. With this mapping, the resulting JSON field is the following:
+
[source, javascript]
[source, json]
----
{
    "manager": [
@@ -631,7 +631,7 @@
The default mappings expose a SCIM view of user and group data:
+
[source, javascript]
[source, json]
----
{
    "/users": {
opendj-doc-generated-ref/src/main/asciidoc/reference/appendix-rest2ldap.adoc
@@ -12,7 +12,7 @@
  information: "Portions copyright [year] [name of copyright owner]".
 
  Copyright 2017 ForgeRock AS.
  Portions Copyright 2024 3A Systems LLC.
  Portions Copyright 2024-2025 3A Systems LLC.
////
:figure-caption!:
@@ -30,7 +30,7 @@
* The OpenDJ REST to LDAP gateway runs in a Servlet container independent from the directory service. You configure the gateway to access the directory service by editing configuration files for the gateway web application.
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["ForgeRock Product Interface Stability"])
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["Product Interface Stability"])
[NOTE]
====
@@ -246,7 +246,7 @@
The gateway accesses this array of LDAP servers if primary LDAP servers cannot be contacted. These might be LDAP servers in the same remote data center, for example:
+
[source, javascript]
[source, json]
----
{
    "secondaryLdapServers": [
@@ -282,7 +282,7 @@
The gateway authenticates by simple bind using the credentials specified:
+
[source, javascript]
[source, json]
----
{
    "authentication": {
@@ -411,13 +411,13 @@
The template to produce the bind DN from the HTTP Basic user name.
+
A single occurrence of the string `{username}` is replaced in the template with the HTTP Basic user name.
A single occurrence of the string `\{username\}` is replaced in the template with the HTTP Basic user name.
+
For example, if the user name is also the UID of the LDAP entry, use `uid={username},ou=People,dc=example,dc=com`.
For example, if the user name is also the UID of the LDAP entry, use `uid=\{username\},ou=People,dc=example,dc=com`.
+
Default: `{username}`
Default: `\{username\}`
========
@@ -438,13 +438,13 @@
The template to produce the authorization ID from the HTTP Basic user name.
+
A single occurrence of the string `{username}` is replaced in the template with the HTTP Basic user name.
A single occurrence of the string `\{username\}` is replaced in the template with the HTTP Basic user name.
+
If the user name is also the authorization ID, use `u:{username}`.
If the user name is also the authorization ID, use `u:\{username\}`.
+
If the user name is the LDAP bind DN, use `dn:{username}`.
If the user name is the LDAP bind DN, use `dn:\{username\}`.
========
@@ -483,10 +483,10 @@
The template for the filter of the LDAP search.
+
A single occurrence of the string `{username}` is replaced in the template with the HTTP Basic user name.
A single occurrence of the string `\{username\}` is replaced in the template with the HTTP Basic user name.
+
If the user name is also the UID, use `(&(uid={username})(objectClass=inetOrgPerson))`.
If the user name is also the UID, use `(&(uid=\{username\})(objectClass=inetOrgPerson))`.
========
@@ -581,7 +581,7 @@
This template must start with `u:` or `dn:`.
+
For example, if token resolution returns a JSON document where the value of the `uid` field is the UID of the user entry in the directory, you might use `u:{uid}` or `dn:{uid},ou=People,dc=example,dc=com`.
For example, if token resolution returns a JSON document where the value of the `uid` field is the UID of the user entry in the directory, you might use `u:\{uid\}` or `dn:\{uid\},ou=People,dc=example,dc=com`.
========
@@ -631,13 +631,13 @@
This template must start with `u:` or `dn:`.
+
For example, if token resolution returns a JSON document where the value of the `username` field is the UID of the user entry in the directory, you might use `u:{username}` or `dn:{username},ou=People,dc=example,dc=com`.
For example, if token resolution returns a JSON document where the value of the `username` field is the UID of the user entry in the directory, you might use `u:\{username\}` or `dn:\{username\},ou=People,dc=example,dc=com`.
`cts`::
Configuration for resolving OAuth 2.0 tokens when the directory service acts as OpenAM's CTS store.
+
OpenAM's CTS store is constrained to a specific layout. The `authzIdTemplate` must therefore use `{userName/0}` for the user identifier.
OpenAM's CTS store is constrained to a specific layout. The `authzIdTemplate` must therefore use `\{userName/0}` for the user identifier.
+
This mechanism makes it possible to resolve access tokens by making a request to the CTS directory service, without making a request to OpenAM. __This mechanism does not, however, ensure that the token requested will have already been replicated to the directory server where the request is routed.__
@@ -848,7 +848,7 @@
* `ou=tablets,ou=devices,dc=example,dc=com`
The subresource name `/{type}` would be substituted in actual paths with `/others`, `/pcs`, `/phones`, and `/tablets`. The DN template for the subresource would specify `ou={type},ou=devices,dc=example,dc=com` in order to locate the entries in the correct LDAP organizational unit. In the example, REST to LDAP substitutes `{type}` in the DN template with the type defined in the request URL path.
The subresource name `/\{type\}` would be substituted in actual paths with `/others`, `/pcs`, `/phones`, and `/tablets`. The DN template for the subresource would specify `ou=\{type\},ou=devices,dc=example,dc=com` in order to locate the entries in the correct LDAP organizational unit. In the example, REST to LDAP substitutes `\{type\}` in the DN template with the type defined in the request URL path.
For details on subresource configuration, see xref:#rest-subresource-properties["Sub-Resource Properties"].
@@ -1091,7 +1091,7 @@
* RDN and resource ID are both derived from a single user attribute in the LDAP entry, as in the following example, where the `uid` attribute is the RDN and its value is the JSON resource ID:
+
[source, javascript]
[source, json]
----
{
    "namingStrategy": {
@@ -1104,7 +1104,7 @@
* RDN and resource ID are derived from separate user attributes in the LDAP entry, as in the following example, where the RDN attribute is `uid`, but the JSON resource ID is the value of the `mail` attribute:
+
[source, javascript]
[source, json]
----
{
    "namingStrategy": {
@@ -1118,7 +1118,7 @@
* RDN is derived from a user attribute and the resource ID from an operational attribute in the LDAP entry, as in the following example, where the RDN attribute is `uid`, but the JSON resource ID is the value of the `entryUUID` operational attribute:
+
[source, javascript]
[source, json]
----
{
    "namingStrategy": {
opendj-doc-generated-ref/src/main/asciidoc/server-dev-guide/chap-rest-operations-3-0.adoc
@@ -12,7 +12,7 @@
  information: "Portions copyright [year] [name of copyright owner]".
 
  Copyright 2017 ForgeRock AS.
  Portions Copyright 2024 3A Systems LLC.
  Portions Copyright 2024-2025 3A Systems LLC.
////
:figure-caption!:
@@ -51,9 +51,9 @@
Before trying the examples, enable HTTP access to OpenDJ directory server as described in xref:../admin-guide/chap-connection-handlers.adoc#setup-rest2ldap-3-0["RESTful Client Access (3.0)"] in the __Administration Guide__. The examples in this chapter use HTTP, but the procedure also shows how to set up HTTPS access to the server.
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["ForgeRock Product Interface Stability"] in the __Reference__.)
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["Product Interface Stability"] in the __Reference__.)
The OpenDJ REST API is built on a common ForgeRock HTTP-based REST API for interacting with JSON Resources. All APIs built on this common layer let you perform the following operations. For an overview of ForgeRock common REST APIs, see xref:chap-rest-operations.adoc#sec-about-crest["About ForgeRock Common REST"].
The OpenDJ REST API is built on a common Open Identity Platform HTTP-based REST API for interacting with JSON Resources. All APIs built on this common layer let you perform the following operations. For an overview of Open Identity Platform common REST APIs, see xref:chap-rest-operations.adoc#sec-about-crest["About Common REST"].
[#authenticate-rest-3-0]
=== Authenticating Over REST (3.0)
opendj-doc-generated-ref/src/main/asciidoc/server-dev-guide/chap-rest-operations.adoc
@@ -12,7 +12,7 @@
  information: "Portions copyright [year] [name of copyright owner]".
 
  Copyright 2017 ForgeRock AS.
  Portions Copyright 2024 3A Systems LLC.
  Portions Copyright 2024-2025 3A Systems LLC.
////
:figure-caption!:
@@ -53,14 +53,14 @@
Before trying the examples, enable HTTP access to OpenDJ directory server as described in xref:../admin-guide/chap-connection-handlers.adoc#setup-rest2ldap-endpoint["To Set Up REST Access to User Data"] in the __Administration Guide__. (If you are using OpenDJ 3.0, see xref:../admin-guide/chap-connection-handlers.adoc#setup-rest2ldap-3-0["RESTful Client Access (3.0)"] in the __Administration Guide__ instead.) The examples in this chapter use HTTP, but the procedure also shows how to set up HTTPS access to the server.
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["ForgeRock Product Interface Stability"] in the __Reference__.)
Interface stability: Evolving (See xref:../reference/appendix-interface-stability.adoc#interface-stability["Product Interface Stability"] in the __Reference__.)
The OpenDJ REST API is built on a common ForgeRock HTTP-based REST API for interacting with JSON Resources. All APIs built on this common layer let you perform the following operations.
The OpenDJ REST API is built on a common Open Identity Platform HTTP-based REST API for interacting with JSON Resources. All APIs built on this common layer let you perform the following operations.
[#sec-about-crest]
=== About ForgeRock Common REST
=== About Common REST
For many REST APIs that are not defined by external standards, ForgeRock products provide common ways to access web resources and collections of resources. This section covers what is common across products. Adapt the examples to your types of resources and to your deployment.
For many REST APIs that are not defined by external standards, Open Identity Platform products provide common ways to access web resources and collections of resources. This section covers what is common across products. Adapt the examples to your types of resources and to your deployment.
[#about-crest-resources]
==== Common REST Resources
@@ -375,7 +375,7 @@
* *set semantics array*, where the elements are not ordered, and duplicates are not allowed.
ForgeRock PATCH supports several different `operations`. The following sections show each of these operations, along with options for the `field` and `value`:
Open Identity Platform PATCH supports several different `operations`. The following sections show each of these operations, along with options for the `field` and `value`:
[#crest-patch-add]
===== Patch Operation: Add
@@ -396,7 +396,7 @@
As an example, start with the following list semantic array resource:
[source, javascript]
[source, json]
----
{
    "fruits" : [ "orange", "apple" ]
@@ -404,7 +404,7 @@
----
The following add operation includes the pineapple to the end of the list of fruits, as indicated by the `-` at the end of the `fruits` array.
[source, javascript]
[source, json]
----
{
    "operation" : "add",
@@ -414,7 +414,7 @@
----
The following is the resulting resource:
[source, javascript]
[source, json]
----
{
    "fruits" : [ "orange", "apple", "pineapple" ]
@@ -429,7 +429,7 @@
The following `copy` operation takes the value from the source named `/hot/potato`, and then runs a `replace` operation on the target value, `/hot/tamale`.
[source, javascript]
[source, json]
----
[
  {
@@ -447,7 +447,7 @@
The `increment` operation changes the value or values of the target field by the amount you specify. The value that you include must be one number, and may be positive or negative. The value of the target field must accept numbers. The following `increment` operation adds `1000` to the target value of `/user/payment`.
[source, javascript]
[source, json]
----
[
  {
@@ -467,7 +467,7 @@
The following `move` operation is equivalent to a `remove` operation on the source named `/hot/potato`, followed by a `replace` operation on the target value, `/hot/tamale`.
[source, javascript]
[source, json]
----
[
  {
@@ -485,7 +485,7 @@
The `remove` operation ensures that the target field no longer contains the value provided. If the remove operation does not include a value, the operation removes the field. The following `remove` deletes the value of the `phoneNumber`, along with the field.
[source, javascript]
[source, json]
----
[
  {
@@ -500,7 +500,7 @@
* *List semantic arrays*: A `remove` operation deletes the specified element in the array. For example, the following operation removes the first phone number, based on its array index (zero-based):
+
[source, javascript]
[source, json]
----
[
   {
@@ -521,7 +521,7 @@
The following `replace` operation removes the existing `telephoneNumber` value for the user, and then adds the new value of `+1 408 555 9999`.
[source, javascript]
[source, json]
----
[
  {
@@ -533,15 +533,15 @@
----
A PATCH replace operation on a list semantic array works in the same fashion as a PATCH remove operation. The following example demonstrates how the effect of both operations. Start with the following resource:
[source, javascript]
[source, json]
----
{
    "fruits" : [ "apple", "orange", "kiwi", "lime" ],
    "fruits" : [ "apple", "orange", "kiwi", "lime" ]
}
----
Apply the following operations on that resource:
[source, javascript]
[source, json]
----
[
  {
@@ -562,7 +562,7 @@
----
[
  {
    "fruits" : [ "orange", "kiwi", "lime" ],
    "fruits" : [ "orange", "kiwi", "lime" ]
  }
]
----
@@ -583,7 +583,7 @@
The `transform` operation changes the value of a field based on a script or some other data transformation command. The following `transform` operation takes the value from the field named `/objects`, and applies the `something.js` script as shown:
[source, javascript]
[source, json]
----
[
  {
@@ -595,7 +595,7 @@
        "file" : "something.js"
      }
    }
  },
  }
]
----
@@ -2306,7 +2306,7 @@
[#mime-types-rest]
=== Working With Alternative Content Types
OpenDJ generally maps JSON resources to LDAP entries. Some resources such as profile photos, however, are best expressed with other MIME types. ForgeRock common REST lets your applications make HTTP multipart requests, so you can work with other MIME types differently from regular JSON resources. This is done using the `_mimeType` parameter described in xref:#about-crest-read["Read"].
OpenDJ generally maps JSON resources to LDAP entries. Some resources such as profile photos, however, are best expressed with other MIME types. Open Identity Platform common REST lets your applications make HTTP multipart requests, so you can work with other MIME types differently from regular JSON resources. This is done using the `_mimeType` parameter described in xref:#about-crest-read["Read"].
This section includes the following procedures:
* xref:#mime-types-rest-mapping["To Map an Alternative Content Type"]
opendj-doc-generated-ref/src/main/asciidoc/server-dev-guide/chap-writing-plugins.adoc
@@ -12,12 +12,13 @@
  information: "Portions copyright [year] [name of copyright owner]".
 
  Copyright 2017 ForgeRock AS.
  Portions Copyright 2024 3A Systems LLC.
  Portions Copyright 2024-2025 3A Systems LLC.
////
:figure-caption!:
:example-caption!:
:table-caption!:
:opendj-version: 4.9.3
[#chap-writing-plugins]
@@ -35,9 +36,9 @@
[IMPORTANT]
====
ForgeRock supports customers using standard plugins delivered as part of OpenDJ directory server.
Open Identity Platform Approved Vendors support customers using standard plugins delivered as part of OpenDJ directory server.
If you deploy with custom plugins and need support in production, contact link:mailto:info\@forgerock.com[info@forgerock.com, window=\_top] in advance to determine how your deployment can be supported.
If you deploy with custom plugins and need support in production, see link:https://github.com/OpenIdentityPlatform/.github/wiki/Approved-Vendor-List[Approved Vendors List, window=\_top] in advance to determine how your deployment can be supported.
====
[#about-server-plugins]
@@ -47,7 +48,7 @@
[NOTE]
====
The OpenDJ server Java API has interface stability: Evolving, as described in xref:../reference/appendix-interface-stability.adoc#interface-stability["ForgeRock Product Interface Stability"] in the __Reference__.
The OpenDJ server Java API has interface stability: Evolving, as described in xref:../reference/appendix-interface-stability.adoc#interface-stability["Product Interface Stability"] in the __Reference__.
This means that a server plugin built with one version of OpenDJ directory server will not necessarily work or even compile with a different version of the server.
====
@@ -169,7 +170,7 @@
. Install the example plugin in OpenDJ directory server:
+
[source, console]
[source, console, subs="attributes"]
----
$ cd /path/to/opendj
@@ -181,7 +182,7 @@
# The following example works with bsdtar,
# which might require installing a bsdtar package.
$ bsdtar -xvf \
 /path/to/opendj-server-example-plugin/target/opendj-server-example-plugin-3.5.3.zip \
 /path/to/opendj-server-example-plugin/target/opendj-server-example-plugin-{opendj-version}.zip \
 -s'|[^/]*/||'
x README.example.plugin
x config/
@@ -190,7 +191,7 @@
x config/schema/99-example-plugin.ldif
x lib/
x lib/extensions/
x lib/extensions/opendj-server-example-plugin-3.5.3.jar
x lib/extensions/opendj-server-example-plugin-{opendj-version}.jar
x lib/extensions/...
# Start the server and create the plugin configuration:
@@ -209,7 +210,7 @@
 --no-prompt
...
INFO: Loaded extension from file
 '/path/to/opendj/lib/extensions/opendj-server-example-plugin-3.5.3.jar'
 '/path/to/opendj/lib/extensions/opendj-server-example-plugin-{opendj-version}.jar'
 (build <unknown>, revision <unknown>)
----
+
@@ -256,7 +257,7 @@
The OpenDJ example server plugin is an Apache Maven project.
As you can see in the `pom.xml` file for the project, the plugin depends on the OpenDJ directory server module.
The plugin project uses these ForgeRock Maven plugins:
The plugin project uses these Open Identity Platform Maven plugins:
* The `i18n-maven-plugin` generates message source files from properties files in the resource bundle.
+
@@ -338,7 +339,7 @@
[NOTE]
====
The OpenDJ server Java API has interface stability: Evolving, as described in xref:../reference/appendix-interface-stability.adoc#interface-stability["ForgeRock Product Interface Stability"] in the __Reference__.
The OpenDJ server Java API has interface stability: Evolving, as described in xref:../reference/appendix-interface-stability.adoc#interface-stability["Product Interface Stability"] in the __Reference__.
This means that a server plugin built with one version of OpenDJ directory server will not necessarily work or even compile with a different version of the server.
====
opendj-doc-maven-plugin/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <artifactId>opendj-parent</artifactId>
        <groupId>org.openidentityplatform.opendj</groupId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-doc-maven-plugin</artifactId>
opendj-doc-maven-plugin/src/main/resources/templates/appendix-ldap-result-codes.ftl
@@ -12,7 +12,7 @@
  information: "Portions Copyright [year] [name of copyright owner]".
  Copyright 2017 ForgeRock AS.
  Portions Copyright ${year} 3A Systems LLC.
  Portions Copyright 2024-${year} 3A Systems LLC.
////
[appendix]
opendj-doc-maven-plugin/src/main/resources/templates/log-message-reference.ftl
@@ -12,7 +12,7 @@
  information: "Portions Copyright [year] [name of copyright owner]".
  Copyright 2017 ForgeRock AS.
  Portions Copyright ${year} 3A Systems LLC.
  Portions Copyright 2024-${year} 3A Systems LLC.
////
[appendix]
opendj-doc-maven-plugin/src/main/resources/templates/sec-locales-subtypes.ftl
@@ -12,7 +12,7 @@
  information: "Portions Copyright [year] [name of copyright owner]".
  Copyright 2017 ForgeRock AS.
  Portions Copyright ${year} 3A Systems LLC.
  Portions Copyright 2024-${year} 3A Systems LLC.
////
[#sec-locales-subtypes]
opendj-doc-maven-plugin/src/main/resources/templates/table-global-acis.ftl
@@ -12,7 +12,7 @@
  information: "Portions Copyright [year] [name of copyright owner]".
  Copyright 2017 ForgeRock AS.
  Portions Copyright ${year} 3A Systems LLC.
  Portions Copyright 2024-${year} 3A Systems LLC.
////
[#table-global-acis]
opendj-dsml-servlet/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <groupId>org.openidentityplatform.opendj</groupId>
        <artifactId>opendj-parent</artifactId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-dsml-servlet</artifactId>
opendj-embedded-server-examples/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <artifactId>opendj-parent</artifactId>
        <groupId>org.openidentityplatform.opendj</groupId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-embedded-server-examples</artifactId>
opendj-embedded/pom.xml
@@ -19,7 +19,7 @@
    <parent>
        <groupId>org.openidentityplatform.opendj</groupId>
        <artifactId>opendj-parent</artifactId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <name>OpenDJ Embedded Server</name>
    <artifactId>opendj-embedded</artifactId>
@@ -38,7 +38,7 @@
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.13</version>
            <version>1.5.13</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
@@ -49,7 +49,7 @@
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.13</version>
            <version>1.5.13</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
opendj-grizzly/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <artifactId>opendj-parent</artifactId>
        <groupId>org.openidentityplatform.opendj</groupId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-grizzly</artifactId>
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LdapResponseMessageWriter.java
@@ -12,11 +12,13 @@
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 * Portions Copyright 2025 3A Systems,LLC
 */
package org.forgerock.opendj.grizzly;
import java.util.concurrent.CancellationException;
import io.reactivex.exceptions.UndeliverableException;
import org.forgerock.opendj.ldap.spi.LdapMessages.LdapResponseMessage;
import org.glassfish.grizzly.CompletionHandler;
import org.glassfish.grizzly.Connection;
@@ -76,7 +78,9 @@
    @Override
    public void onError(final Throwable error) {
        upstream.cancel();
        downstream.onError(error);
        try {
            downstream.onError(error);
        } catch (UndeliverableException e) {}
    }
    @Override
opendj-ldap-sdk-examples/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <artifactId>opendj-parent</artifactId>
        <groupId>org.openidentityplatform.opendj</groupId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-ldap-sdk-examples</artifactId>
opendj-ldap-toolkit/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <artifactId>opendj-parent</artifactId>
        <groupId>org.openidentityplatform.opendj</groupId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-ldap-toolkit</artifactId>
opendj-legacy/pom.xml
@@ -19,7 +19,7 @@
  <parent>
    <groupId>org.openidentityplatform.opendj</groupId>
    <artifactId>opendj-parent</artifactId>
    <version>4.8.3-SNAPSHOT</version>
    <version>4.9.5-SNAPSHOT</version>
  </parent>
  <artifactId>opendj-legacy</artifactId>
  <name>OpenDJ Legacy</name>
opendj-maven-plugin/pom.xml
@@ -19,7 +19,7 @@
  <parent>
    <groupId>org.openidentityplatform.opendj</groupId>
    <artifactId>opendj-parent</artifactId>
    <version>4.8.3-SNAPSHOT</version>
    <version>4.9.5-SNAPSHOT</version>
  </parent>
  <artifactId>opendj-maven-plugin</artifactId>
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/JDBCBackendConfiguration.xml
New file
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
  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 2024 3A Systems LLC
  ! -->
<adm:managed-object name="jdbc-backend" plural-name="jdbc-backends"
  package="org.forgerock.opendj.server.config"
  extends="pluggable-backend" xmlns:adm="http://opendj.forgerock.org/admin"
  xmlns:ldap="http://opendj.forgerock.org/admin-ldap"
  xmlns:cli="http://opendj.forgerock.org/admin-cli">
  <adm:synopsis>
    A <adm:user-friendly-name/> stores application data in JDBC source.
  </adm:synopsis>
  <adm:description>
    It is the traditional "directory server" backend and is similar to
    the backends provided by the Sun Java System Directory Server. The
    <adm:user-friendly-name />
    stores the entries in an encoded form and also provides indexes that
    can be used to quickly locate target entries based on different
    kinds of criteria.
  </adm:description>
  <adm:profile name="ldap">
    <ldap:object-class>
      <ldap:name>ds-cfg-jdbc-backend</ldap:name>
      <ldap:superior>ds-cfg-pluggable-backend</ldap:superior>
    </ldap:object-class>
  </adm:profile>
  <adm:property-override name="java-class" advanced="true">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>
          org.opends.server.backends.jdbc.Backend
        </adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
  <adm:property name="db-directory" mandatory="true">
    <adm:TODO>Default this to the db/backend-id</adm:TODO>
    <adm:synopsis>
      Specifies the connection string
    </adm:synopsis>
    <adm:description>
      jdbc:postgresql://localhost/test
    </adm:description>
    <adm:requires-admin-action>
      <adm:component-restart />
    </adm:requires-admin-action>
    <adm:default-behavior>
      <adm:defined>
        <adm:value>jdbc:postgresql://localhost/test</adm:value>
      </adm:defined>
    </adm:default-behavior>
    <adm:syntax>
      <adm:string />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:name>ds-cfg-db-directory</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
</adm:managed-object>
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/PluggableBackendConfiguration.xml
@@ -71,6 +71,77 @@
          <adm:value>ds-sync-conflict</adm:value>
        </adm:property>
      </adm:default-managed-object>
      <adm:default-managed-object name="cn">
        <adm:property name="index-type">
          <adm:value>equality</adm:value>
          <adm:value>substring</adm:value>
        </adm:property>
        <adm:property name="attribute">
          <adm:value>cn</adm:value>
        </adm:property>
      </adm:default-managed-object>
      <adm:default-managed-object name="givenName">
        <adm:property name="index-type">
          <adm:value>equality</adm:value>
          <adm:value>substring</adm:value>
        </adm:property>
        <adm:property name="attribute">
          <adm:value>givenName</adm:value>
        </adm:property>
      </adm:default-managed-object>
      <adm:default-managed-object name="mail">
        <adm:property name="index-type">
          <adm:value>equality</adm:value>
          <adm:value>substring</adm:value>
        </adm:property>
        <adm:property name="attribute">
          <adm:value>mail</adm:value>
        </adm:property>
      </adm:default-managed-object>
      <adm:default-managed-object name="sn">
        <adm:property name="index-type">
          <adm:value>equality</adm:value>
          <adm:value>substring</adm:value>
        </adm:property>
        <adm:property name="attribute">
          <adm:value>sn</adm:value>
        </adm:property>
      </adm:default-managed-object>
      <adm:default-managed-object name="telephoneNumber">
        <adm:property name="index-type">
          <adm:value>equality</adm:value>
          <adm:value>substring</adm:value>
        </adm:property>
        <adm:property name="attribute">
          <adm:value>telephoneNumber</adm:value>
        </adm:property>
      </adm:default-managed-object>
      <adm:default-managed-object name="member">
        <adm:property name="index-type">
          <adm:value>equality</adm:value>
        </adm:property>
        <adm:property name="attribute">
          <adm:value>member</adm:value>
        </adm:property>
      </adm:default-managed-object>
      <adm:default-managed-object name="uid">
        <adm:property name="index-type">
          <adm:value>equality</adm:value>
        </adm:property>
        <adm:property name="attribute">
          <adm:value>uid</adm:value>
        </adm:property>
      </adm:default-managed-object>
      <adm:default-managed-object name="uniqueMember">
        <adm:property name="index-type">
          <adm:value>equality</adm:value>
        </adm:property>
        <adm:property name="attribute">
          <adm:value>uniqueMember</adm:value>
        </adm:property>
      </adm:default-managed-object>
    </adm:one-to-many>
    <adm:profile name="ldap">
      <ldap:rdn-sequence>cn=Index</ldap:rdn-sequence>
opendj-openidm-account-change-notification-handler/pom.xml
@@ -19,7 +19,7 @@
  <parent>
    <groupId>org.openidentityplatform.opendj</groupId>
    <artifactId>opendj-parent</artifactId>
    <version>4.8.3-SNAPSHOT</version>
    <version>4.9.5-SNAPSHOT</version>
  </parent>
  <artifactId>opendj-openidm-account-change-notification-handler</artifactId>
  <name>OpenDJ account change notification handler for OpenIDM</name>
opendj-packages/opendj-deb/opendj-deb-standard/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <groupId>org.openidentityplatform.opendj</groupId>
        <artifactId>opendj-deb</artifactId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-deb-standard</artifactId>
opendj-packages/opendj-deb/pom.xml
@@ -22,7 +22,7 @@
    <parent>
        <groupId>org.openidentityplatform.opendj</groupId>
        <artifactId>opendj-packages</artifactId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <profiles>
opendj-packages/opendj-docker/Dockerfile
@@ -1,27 +1,31 @@
FROM eclipse-temurin:21-jre-jammy
MAINTAINER Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>
LABEL org.opencontainers.image.authors="Open Identity Platform Community"
ENV ADD_BASE_ENTRY="--addBaseEntry" \
    PORT=1389 \
    LDAPS_PORT=1636 \
    ADMIN_PORT=4444 \
    BASE_DN=${BASE_DN:-"dc=example,dc=com"} \
    ROOT_USER_DN=${ROOT_USER_DN:-"cn=Directory Manager"} \
    ROOT_PASSWORD=${ROOT_PASSWORD:-"password"} \
    SECRET_VOLUME=${SECRET_VOLUME} \
    OPENDJ_SSL_OPTIONS=${SSL_OPTIONS:-"--generateSelfSignedCertificate"} \
    MASTER_SERVER=${MASTER_SERVER} \
    OPENDJ_REPLICATION_TYPE=${OPENDJ_REPLICATION_TYPE} \
    OPENDJ_USER="opendj" \
    OPENDJ_JAVA_ARGS="-server -XX:+UseContainerSupport"
ENV ADD_BASE_ENTRY="--addBaseEntry"
ENV PORT=1389
ENV LDAPS_PORT=1636
ENV ADMIN_PORT=4444
ENV BASE_DN="dc=example,dc=com"
ENV ROOT_USER_DN="cn=Directory Manager"
ENV ROOT_PASSWORD="password"
#ENV SECRET_VOLUME
ENV OPENDJ_SSL_OPTIONS="--generateSelfSignedCertificate"
#ENV MASTER_SERVER
#ENV OPENDJ_REPLICATION_TYPE
ENV OPENDJ_USER="opendj"
#ENV OPENDJ_JAVA_ARGS=""
ENV BACKEND_TYPE="je"
ENV BACKEND_DB_DIRECTORY="db"
#ENV SETUP_ARGS
ARG VERSION=@project_version@
ARG VERSION
WORKDIR /opt
RUN  apt-get update \
 && apt-get install -y --no-install-recommends curl unzip \
 && if [ -z "$VERSION" ] ; then VERSION="$(curl -i -o - --silent https://api.github.com/repos/OpenIdentityPlatform/OpenDJ/releases/latest | grep -m1 "\"name\"" | cut -d\" -f4)"; fi \
 && curl -L https://github.com/OpenIdentityPlatform/OpenDJ/releases/download/$VERSION/opendj-$VERSION.zip --output opendj-$VERSION.zip \
 && unzip opendj-$VERSION.zip \
 && apt-get remove -y --purge curl unzip \
@@ -38,7 +42,7 @@
RUN chmod +x /opt/opendj/run.sh /opt/opendj/bootstrap/setup.sh /opt/opendj/bootstrap/replicate.sh
EXPOSE $PORT $LDAPS_PORT $ADMIN_PORT
EXPOSE $PORT/tcp $LDAPS_PORT/tcp $ADMIN_PORT/tcp
USER $OPENDJ_USER
opendj-packages/opendj-docker/Dockerfile-alpine
@@ -1,28 +1,32 @@
FROM openjdk:8-jre-alpine
FROM alpine:latest
MAINTAINER Open Identity Platform Community <open-identity-platform-opendj@googlegroups.com>
LABEL org.opencontainers.image.authors="Open Identity Platform Community"
ENV ADD_BASE_ENTRY="--addBaseEntry" \
    PORT=1389 \
    LDAPS_PORT=1636 \
    ADMIN_PORT=4444 \
    BASE_DN=${BASE_DN:-"dc=example,dc=com"} \
    ROOT_USER_DN=${ROOT_USER_DN:-"cn=Directory Manager"} \
    ROOT_PASSWORD=${ROOT_PASSWORD:-"password"} \
    SECRET_VOLUME=${SECRET_VOLUME} \
    OPENDJ_SSL_OPTIONS=${SSL_OPTIONS:-"--generateSelfSignedCertificate"} \
    MASTER_SERVER=${MASTER_SERVER} \
    OPENDJ_REPLICATION_TYPE=${OPENDJ_REPLICATION_TYPE} \
    OPENDJ_USER="opendj"\
    OPENDJ_JAVA_ARGS="-server -XX:+UseContainerSupport"
ENV ADD_BASE_ENTRY="--addBaseEntry"
ENV PORT=1389
ENV LDAPS_PORT=1636
ENV ADMIN_PORT=4444
ENV BASE_DN="dc=example,dc=com"
ENV ROOT_USER_DN="cn=Directory Manager"
ENV ROOT_PASSWORD="password"
#ENV SECRET_VOLUME
ENV OPENDJ_SSL_OPTIONS="--generateSelfSignedCertificate"
#ENV MASTER_SERVER
#ENV OPENDJ_REPLICATION_TYPE
ENV OPENDJ_USER="opendj"
#ENV OPENDJ_JAVA_ARGS=""
ENV BACKEND_TYPE="je"
ENV BACKEND_DB_DIRECTORY="db"
#ENV SETUP_ARGS
ARG VERSION=@project_version@
ARG VERSION
WORKDIR /opt
RUN apk add --update --no-cache --virtual builddeps curl unzip \
 && apk upgrade --update --no-cache \
 && apk add bash \
 && apk add bash openjdk8 \
 && if [ -z "$VERSION" ] ; then VERSION="$(curl -i -o - --silent https://api.github.com/repos/OpenIdentityPlatform/OpenDJ/releases/latest | grep -m1 "\"name\"" | cut -d\" -f4)"; fi \
 && curl -L https://github.com/OpenIdentityPlatform/OpenDJ/releases/download/$VERSION/opendj-$VERSION.zip --output opendj-$VERSION.zip \
 && unzip opendj-$VERSION.zip \
 && apk del builddeps \
@@ -40,7 +44,7 @@
RUN chmod +x /opt/opendj/run.sh /opt/opendj/bootstrap/setup.sh /opt/opendj/bootstrap/replicate.sh
EXPOSE $PORT $LDAPS_PORT $ADMIN_PORT
EXPOSE $PORT/tcp $LDAPS_PORT/tcp $ADMIN_PORT/tcp
USER $OPENDJ_USER
opendj-packages/opendj-docker/README.md
@@ -3,13 +3,13 @@
Build docker image:
```bash
docker build -t openidentityplatform/opendj --build-arg VERSION=4.5.1 .
docker build -t openidentityplatform/opendj .
```
Run image
```bash
docker run -d -p 1389:1389 -p 1636:1636 -p 4444:4444 --name opendj openidentityplatform/opendj:4.5.1
docker run -d -p 1389:1389 -p 1636:1636 -p 4444:4444 --name opendj openidentityplatform/opendj
```
## Environment Variables
@@ -25,6 +25,10 @@
| SECRET_VOLUME           | -                               | Mounted keystore volume, if present copies keystore over                                                                                                                                                                                                |
| MASTER_SERVER           | -                               | Replication master server                                                                                                                                                                                                                               |
| VERSION                 | -                               | OpenDJ version                                                                                                                                                                                                                                          |
| OPENDJ_USER             | -                               | user which runs OpenDJ                                                                                                                                                                                                                                  |
| OPENDJ_USER             | opendj                          | user which runs OpenDJ                                                                                                                                                                                                                                  |
| OPENDJ_REPLICATION_TYPE | -                               | OpenDJ Replication type, valid values are: <ul><li>simple - standart replication</li><li>srs - standalone replication servers</li><li>sdsr - Standalone Directory Server Replicas</li><li>rg - Replication Groups</li></ul>Other values will be ignored |
| OPENDJ_SSL_OPTIONS      | --generateSelfSignedCertificate | you can replace ssl options at here, like : "--usePkcs12keyStore /opt/domain.pfx --keyStorePassword domain"                                                                                                                                             |
| OPENDJ_JAVA_ARGS        | -server                         | extra instance java args                                                                                                                                                                                                                                |
| BACKEND_TYPE            | je                              | OpenDJ backend type, see [dsconfig create-backend](https://doc.openidentityplatform.org/opendj/reference/dsconfig-subcommands-ref#dsconfig-create-backend) documentation                                                                                |
| BACKEND_DB_DIRECTORY    | db                              | OpenDJ `db-directory` attribute for backend                                                                                                                                                                                                             |
| SETUP_ARGS              | -                               | extra setup args                                                                                                                                                                                                                                        |
opendj-packages/opendj-docker/bootstrap/setup.sh
@@ -21,7 +21,6 @@
/opt/opendj/setup \
  --cli \
  -h localhost \
  --baseDN $BASE_DN \
  --ldapPort $PORT \
  --ldapsPort $LDAPS_PORT \
  --enableStartTLS $OPENDJ_SSL_OPTIONS \
@@ -31,10 +30,31 @@
  --acceptLicense \
  --no-prompt \
  --noPropertiesFile \
  --doNotStart \
  $ADD_BASE_ENTRY #--sampleData 1
  $SETUP_ARGS
/opt/opendj/bin/start-ds
BACKEND_TYPE=${BACKEND_TYPE:-je}
BACKEND_DB_DIRECTORY=${BACKEND_DB_DIRECTORY:-db}
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" --bindPassword "$ROOT_PASSWORD" \
  --backend-name=userRoot --type $BACKEND_TYPE --set base-dn:$BASE_DN --set "db-directory:$BACKEND_DB_DIRECTORY" \
  --set enabled:true --no-prompt --trustAll
if [ "$ADD_BASE_ENTRY" = "--addBaseEntry" ]; then
  DC=$(echo "$BASE_DN" | awk -F',|=' '{print $2}')
  /opt/opendj/bin/ldapmodify --hostname localhost \
    --port 1636 --bindDN "$ROOT_USER_DN" --bindPassword "$ROOT_PASSWORD" \
    --useSsl --trustAll <<EOF
dn: $BASE_DN
dc: $DC
objectClass: domain
objectClass: top
EOF
fi
# There are multiple types of ldif files.
# The steps below import ldifs via `ldapmodify`.
opendj-packages/opendj-docker/pom.xml
@@ -22,7 +22,7 @@
    <parent>
        <groupId>org.openidentityplatform.opendj</groupId>
        <artifactId>opendj-packages</artifactId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <profiles>
opendj-packages/opendj-msi/opendj-msi-standard/pom.xml
@@ -21,7 +21,7 @@
    <parent>
        <groupId>org.openidentityplatform.opendj</groupId>
        <artifactId>opendj-msi</artifactId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-msi-standard</artifactId>
opendj-packages/opendj-msi/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <groupId>org.openidentityplatform.opendj</groupId>
        <artifactId>opendj-packages</artifactId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-msi</artifactId>
opendj-packages/opendj-rpm/opendj-rpm-standard/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <groupId>org.openidentityplatform.opendj</groupId>
        <artifactId>opendj-rpm</artifactId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-rpm-standard</artifactId>
opendj-packages/opendj-rpm/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <groupId>org.openidentityplatform.opendj</groupId>
        <artifactId>opendj-packages</artifactId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <packaging>pom</packaging>
opendj-packages/opendj-svr4/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <groupId>org.openidentityplatform.opendj</groupId>
        <artifactId>opendj-packages</artifactId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-svr4</artifactId>
opendj-packages/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <groupId>org.openidentityplatform.opendj</groupId>
        <artifactId>opendj-parent</artifactId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-packages</artifactId>
opendj-rest2ldap-servlet/pom.xml
@@ -19,7 +19,7 @@
  <parent>
    <groupId>org.openidentityplatform.opendj</groupId>
    <artifactId>opendj-parent</artifactId>
    <version>4.8.3-SNAPSHOT</version>
    <version>4.9.5-SNAPSHOT</version>
  </parent>
  <artifactId>opendj-rest2ldap-servlet</artifactId>
opendj-rest2ldap/pom.xml
@@ -20,7 +20,7 @@
    <parent>
        <artifactId>opendj-parent</artifactId>
        <groupId>org.openidentityplatform.opendj</groupId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    
    <artifactId>opendj-rest2ldap</artifactId>
opendj-server-example-plugin/pom.xml
@@ -19,7 +19,7 @@
  <parent>
    <groupId>org.openidentityplatform.opendj</groupId>
    <artifactId>opendj-parent</artifactId>
    <version>4.8.3-SNAPSHOT</version>
    <version>4.9.5-SNAPSHOT</version>
  </parent>
  <artifactId>opendj-server-example-plugin</artifactId>
  <name>OpenDJ Server Example Plugin</name>
opendj-server-legacy/pom.xml
@@ -13,7 +13,7 @@
  information: "Portions Copyright [year] [name of copyright owner]".
  Copyright 2011-2016 ForgeRock AS.
  Portions Copyright 2017-2024 3A Systems, LLC.
  Portions Copyright 2017-2025 3A Systems, LLC.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
@@ -21,7 +21,7 @@
  <parent>
    <groupId>org.openidentityplatform.opendj</groupId>
    <artifactId>opendj-parent</artifactId>
    <version>4.8.3-SNAPSHOT</version>
    <version>4.9.5-SNAPSHOT</version>
  </parent>
  <artifactId>opendj-server-legacy</artifactId>
  <packaging>jar</packaging>
@@ -65,7 +65,7 @@
    <product.archive.name>${product.name.lowercase}-${project.version}</product.archive.name>
    <juel.version>2.2.7</juel.version>
    <doclint>none</doclint>
    <opendmk.lib.dir>${basedir}/opendmk</opendmk.lib.dir>
  </properties>
@@ -86,12 +86,12 @@
      <groupId>org.openidentityplatform.opendj</groupId>
      <artifactId>opendj-config</artifactId>
    </dependency>
    <dependency>
      <groupId>org.openidentityplatform.opendj</groupId>
      <artifactId>opendj-cli</artifactId>
    </dependency>
     <dependency>
      <groupId>org.openidentityplatform.opendj</groupId>
      <artifactId>opendj-legacy</artifactId>
@@ -204,7 +204,7 @@
      <artifactId>jul-to-slf4j</artifactId>
    </dependency>
    <!-- mail -->
    <dependency>
      <groupId>com.sun.mail</groupId>
@@ -229,7 +229,7 @@
      <groupId>org.openidentityplatform.commons.persistit</groupId>
      <artifactId>core</artifactId>
    </dependency>
    <dependency>
      <groupId>com.github.stephenc.jcip</groupId>
      <artifactId>jcip-annotations</artifactId>
@@ -246,11 +246,16 @@
      <artifactId>juel-api</artifactId>
      <version>${juel.version}</version>
    </dependency>
    <dependency>
        <groupId>com.datastax.oss</groupId>
      <groupId>com.datastax.oss</groupId>
      <artifactId>native-protocol</artifactId>
      <version>1.5.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cassandra</groupId>
        <artifactId>java-driver-core</artifactId>
        <version>4.17.0</version>
        <version>4.19.0</version>
        <exclusions>
            <exclusion>
                <groupId>org.reactivestreams</groupId>
@@ -259,6 +264,11 @@
        </exclusions>
    </dependency>
    <dependency>
      <groupId>org.postgresql</groupId>
      <artifactId>postgresql</artifactId>
      <version>42.7.5</version>
    </dependency>
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <scope>test</scope>
@@ -267,9 +277,50 @@
    <dependency>
      <groupId>org.testcontainers</groupId>
      <artifactId>cassandra</artifactId>
      <version>1.19.0</version>
      <version>1.20.6</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.testcontainers</groupId>
      <artifactId>postgresql</artifactId>
      <version>1.20.6</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.testcontainers</groupId>
      <artifactId>oracle-free</artifactId>
      <version>1.20.6</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.testcontainers</groupId>
      <artifactId>mysql</artifactId>
      <version>1.20.6</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.testcontainers</groupId>
      <artifactId>mssqlserver</artifactId>
      <version>1.20.6</version>
      <scope>test</scope>
    </dependency>
    <!-- test JDBC drivers -->
    <dependency>
      <groupId>com.mysql</groupId>
      <artifactId>mysql-connector-j</artifactId>
      <version>9.2.0</version>
    </dependency>
    <dependency>
      <groupId>com.oracle.database.jdbc</groupId>
      <artifactId>ojdbc8</artifactId>
      <version>23.7.0.25.01</version>
    </dependency>
    <dependency>
      <groupId>com.microsoft.sqlserver</groupId>
      <artifactId>mssql-jdbc</artifactId>
      <version>12.10.0.jre8</version>
    </dependency>
  </dependencies>
  <build><finalName>${project.groupId}.${project.artifactId}</finalName>
@@ -1082,24 +1133,6 @@
        </executions>
      </plugin>
      <!-- Build javadoc -->
      <plugin>
        <groupId>org.openidentityplatform.maven.plugins</groupId>
        <artifactId>javadoc-updater-maven-plugin</artifactId>
        <version>1.0.0</version>
        <executions>
          <execution>
            <phase>site</phase>
            <goals>
              <goal>fixjavadoc</goal>
            </goals>
            <configuration>
              <directory>${project.build.directory}/site/javadoc</directory>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <!-- Release project -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
@@ -1315,7 +1348,7 @@
                  </sources>
                </configuration>
              </execution>
            </executions>
          </plugin>
opendj-server-legacy/resource/bin/_mixed-script.sh
@@ -44,7 +44,7 @@
SCRIPT_NAME=${ORIGIN_SCRIPT_NAME}.online
for opt in `echo $*`
do
  `echo ${opt}|grep -iq "\-\-offline"`
  `echo ${opt}|grep -iq -- --offline`
  ret_code=$?
  if test ${ret_code} -eq 0
  then
opendj-server-legacy/resource/bin/_script-util.bat
@@ -13,7 +13,7 @@
rem
rem Copyright 2008-2010 Sun Microsystems, Inc.
rem Portions Copyright 2011-2016 ForgeRock AS.
rem Portions Copyright 2020-2024 3A Systems, LLC.
rem Portions Copyright 2020-2025 3A Systems, LLC.
set SET_JAVA_HOME_AND_ARGS_DONE=false
set SET_ENVIRONMENT_VARS_DONE=false
@@ -70,11 +70,8 @@
rem it also helps comparing the two paths
FOR /F "delims=" %%i IN ("%INSTALL_ROOT%")  DO set INSTALL_ROOT=%%~dpnxi
FOR /F "delims=" %%i IN ("%INSTANCE_ROOT%") DO set INSTANCE_ROOT=%%~dpnxi
call "%INSTALL_ROOT%\lib\setcp.bat" %INSTALL_ROOT%\lib\bootstrap.jar
call "%INSTALL_ROOT%\lib\setcp.bat" %INSTALL_ROOT%\lib\*
set CLASSPATH=%INSTANCE_ROOT%\classes;%CLASSPATH%
if "%INSTALL_ROOT%" == "%INSTANCE_ROOT%" goto setClassPathWithOpenDJLoggerDone
FOR %%x in ("%INSTANCE_ROOT%\lib\*.jar") DO call "%INSTANCE_ROOT%\lib\setcp.bat" %%x
:setClassPathWithOpenDJLoggerDone
set SET_CLASSPATH_DONE=true
goto scriptBegin
opendj-server-legacy/resource/bin/_script-util.sh
@@ -14,7 +14,7 @@
#
# Copyright 2008-2010 Sun Microsystems, Inc.
# Portions Copyright 2010-2016 ForgeRock AS.
# Portions Copyright 2019-2024 3A Systems, LLC.
# Portions Copyright 2019-2025 3A Systems, LLC.
#
# Display an error message
#
@@ -195,14 +195,7 @@
# Configure the appropriate CLASSPATH for server, using Opend DJ logger.
set_opendj_logger_classpath() {
  CLASSPATH="${INSTANCE_ROOT}/classes"
  CLASSPATH="${CLASSPATH}:${INSTALL_ROOT}/lib/bootstrap.jar"
  if [ "${INSTALL_ROOT}" != "${INSTANCE_ROOT}" ]
  then
    for JAR in "${INSTANCE_ROOT}/lib/"*.jar
    do
      CLASSPATH=${CLASSPATH}:${JAR}
    done
  fi
  CLASSPATH="${CLASSPATH}:${INSTALL_ROOT}/lib/*"
  export CLASSPATH
}
opendj-server-legacy/resource/config/java.properties
@@ -56,7 +56,12 @@
#
# Specify to use the -client argument for all the command-lines that have not
# an associated property defined:
# default.java-args=-server
# default.java-args=-client
default.java-home=$JAVA_HOME
default.java-args=-server
default.java-args=-client
import-ldif.offline.java-args=-server
rebuild-index.offline.java-args=-server
start-ds.java-args=-server
ldifdiff.java-args=-server
opendj-server-legacy/resource/schema/02-config.ldif
@@ -15,7 +15,7 @@
# Portions Copyright 2011 profiq, s.r.o.
# Portions Copyright 2012 Manuel Gaupp
# Portions copyright 2015 Edan Idzerda
# Portions copyright 2023 3A Systems LLC
# Portions copyright 2023-2025 3A Systems LLC
# This file contains the attribute type and objectclass definitions for use
# with the Directory Server configuration.
@@ -23,6 +23,14 @@
objectClass: top
objectClass: ldapSubentry
objectClass: subschema
ldapSyntaxes: ( 1.3.6.1.4.1.36733.2.1.3.4 DESC 'Duration in milli-seconds' X-SUBST '1.3.6.1.4.1.1466.115.121.1.27' X-ORIGIN 'OpenDJ Directory Server' )
ldapSyntaxes: ( 1.3.6.1.4.1.36733.2.1.3.5 DESC 'Size in bytes' X-SUBST '1.3.6.1.4.1.1466.115.121.1.27' X-ORIGIN 'OpenDJ Directory Server' )
ldapSyntaxes: ( 1.3.6.1.4.1.36733.2.1.3.6 DESC 'Timer metric' X-SUBST '1.3.6.1.4.1.36733.2.1.3.1' X-ORIGIN 'OpenDJ Directory Server' )
ldapSyntaxes: ( 1.3.6.1.4.1.36733.2.1.3.7 DESC 'Summary metric' X-SUBST '1.3.6.1.4.1.36733.2.1.3.1' X-ORIGIN 'OpenDJ Directory Server' )
ldapSyntaxes: ( 1.3.6.1.4.1.36733.2.1.3.8 DESC 'Filesystem path' X-SUBST '1.3.6.1.4.1.1466.115.121.1.15' X-ORIGIN 'OpenDJ Directory Server' )
ldapSyntaxes: ( 1.3.6.1.4.1.36733.2.1.3.9 DESC 'CSN (Change Sequence Number)' X-SUBST '1.3.6.1.4.1.1466.115.121.1.15' X-ORIGIN 'OpenDJ Directory Server' )
ldapSyntaxes: ( 1.3.6.1.4.1.36733.2.1.3.10 DESC 'Counter metric' X-SUBST '1.3.6.1.4.1.1466.115.121.1.27' X-ORIGIN 'OpenDJ Directory Server' )
ldapSyntaxes: ( 1.3.6.1.4.1.36733.2.1.3.11 DESC 'Host port' X-SUBST '1.3.6.1.4.1.1466.115.121.1.15' X-ORIGIN 'OpenDJ Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.1
  NAME 'ds-cfg-java-class'
  EQUALITY caseExactMatch
@@ -6013,6 +6021,12 @@
  STRUCTURAL
  MUST ds-cfg-db-directory
  X-ORIGIN 'OpenDJ Directory Server' )
objectClasses: ( 1.3.6.1.4.1.60142.2.1.2.2
  NAME 'ds-cfg-jdbc-backend'
  SUP ds-cfg-pluggable-backend
  STRUCTURAL
  MUST ds-cfg-db-directory
  X-ORIGIN 'OpenDJ Directory Server' )
objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.27
  NAME 'ds-task-reset-change-number'
  SUP ds-task
opendj-server-legacy/src/main/java/org/opends/server/backends/jdbc/Backend.java
New file
@@ -0,0 +1,31 @@
/*
 * 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 2024 3A Systems, LLC.
 */
package org.opends.server.backends.jdbc;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.server.config.server.JDBCBackendCfg;
import org.opends.server.backends.pluggable.BackendImpl;
import org.opends.server.core.ServerContext;
public class Backend extends BackendImpl<JDBCBackendCfg>{
      @Override
      protected Storage configureStorage(JDBCBackendCfg cfg, ServerContext serverContext) throws ConfigException
      {
        return new Storage(cfg, serverContext);
      }
}
opendj-server-legacy/src/main/java/org/opends/server/backends/jdbc/CachedConnection.java
New file
@@ -0,0 +1,361 @@
/*
 * 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 2024 3A Systems, LLC.
 */
package org.opends.server.backends.jdbc;
import com.google.common.cache.*;
import java.sql.*;
import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import java.util.Queue;
import java.util.concurrent.*;
public class CachedConnection implements Connection {
    final Connection parent;
    static LoadingCache<String, BlockingQueue<Connection>> cached= CacheBuilder.newBuilder()
            .expireAfterAccess(Long.parseLong(System.getProperty("org.openidentityplatform.opendj.jdbc.ttl","15000")), TimeUnit.MILLISECONDS)
            .removalListener(new RemovalListener<String, BlockingQueue<Connection>>() {
                @Override
                public void onRemoval(RemovalNotification<String, BlockingQueue<Connection>> notification) {
                    assert notification.getValue() != null;
                    for (Connection con: notification.getValue()) {
                            try {
                                if (!con.isClosed()) {
                                    con.close();
                                }
                            } catch (SQLException e) {
                            }
                        }
                }
            })
            .build(new CacheLoader<String, BlockingQueue<Connection>>() {
                @Override
                public BlockingQueue<Connection> load(String connectionString) throws Exception {
                    return new LinkedBlockingQueue<>();
                }
            });
    final String connectionString;
    public CachedConnection(String connectionString,Connection parent) {
        this.connectionString=connectionString;
        this.parent = parent;
    }
    static Connection getConnection(String connectionString) throws Exception {
        return getConnection(connectionString,0);
    }
    static Connection getConnection(String connectionString, final int waitTime) throws Exception {
        Connection con=cached.get(connectionString).poll(waitTime,TimeUnit.MILLISECONDS);
        while(con!=null) {
            if (!con.isValid(0)) {
                try {
                    con.close();
                } catch (SQLException e) {
                    con=null;
                }
                con=cached.get(connectionString).poll();
            }else{
                return con;
            }
        }
        try {
            con = DriverManager.getConnection(connectionString);
            con.setAutoCommit(false);
            con.setTransactionIsolation(TRANSACTION_READ_COMMITTED);
            return new CachedConnection(connectionString, con);
        }catch (SQLException e) { //max_connection server error: try recursion for reuse connection
            return getConnection(connectionString,(waitTime==0)?1:waitTime*2);
        }
    }
    @Override
    public Statement createStatement() throws SQLException {
        return parent.createStatement();
    }
    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return parent.prepareStatement(sql);
    }
    @Override
    public CallableStatement prepareCall(String sql) throws SQLException {
        return parent.prepareCall(sql);
    }
    @Override
    public String nativeSQL(String sql) throws SQLException {
        return parent.nativeSQL(sql);
    }
    @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException {
        parent.setAutoCommit(autoCommit);
    }
    @Override
    public boolean getAutoCommit() throws SQLException {
        return parent.getAutoCommit();
    }
    @Override
    public void commit() throws SQLException {
        parent.commit();
    }
    @Override
    public void rollback() throws SQLException {
        parent.rollback();
    }
    @Override
    public void close() throws SQLException {
        rollback();
        try {
            cached.get(connectionString).add(this);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public boolean isClosed() throws SQLException {
        return parent.isClosed();
    }
    @Override
    public DatabaseMetaData getMetaData() throws SQLException {
        return parent.getMetaData();
    }
    @Override
    public void setReadOnly(boolean readOnly) throws SQLException {
        parent.setReadOnly(readOnly);
    }
    @Override
    public boolean isReadOnly() throws SQLException {
        return parent.isReadOnly();
    }
    @Override
    public void setCatalog(String catalog) throws SQLException {
        parent.setCatalog(catalog);
    }
    @Override
    public String getCatalog() throws SQLException {
        return parent.getCatalog();
    }
    @Override
    public void setTransactionIsolation(int level) throws SQLException {
        parent.setTransactionIsolation(level);
    }
    @Override
    public int getTransactionIsolation() throws SQLException {
        return parent.getTransactionIsolation();
    }
    @Override
    public SQLWarning getWarnings() throws SQLException {
        return parent.getWarnings();
    }
    @Override
    public void clearWarnings() throws SQLException {
        parent.clearWarnings();
    }
    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
        return parent.createStatement(resultSetType, resultSetConcurrency);
    }
    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return parent.prepareStatement(sql, resultSetType, resultSetConcurrency);
    }
    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return parent.prepareCall(sql, resultSetType, resultSetConcurrency) ;
    }
    @Override
    public Map<String, Class<?>> getTypeMap() throws SQLException {
        return parent.getTypeMap();
    }
    @Override
    public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
        parent.setTypeMap(map);
    }
    @Override
    public void setHoldability(int holdability) throws SQLException {
        parent.setHoldability(holdability);
    }
    @Override
    public int getHoldability() throws SQLException {
        return parent.getHoldability();
    }
    @Override
    public Savepoint setSavepoint() throws SQLException {
        return parent.setSavepoint();
    }
    @Override
    public Savepoint setSavepoint(String name) throws SQLException {
        return parent.setSavepoint(name);
    }
    @Override
    public void rollback(Savepoint savepoint) throws SQLException {
        parent.rollback(savepoint);
    }
    @Override
    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
        parent.releaseSavepoint(savepoint);
    }
    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return parent.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
    }
    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return parent.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
    }
    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return parent.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
    }
    @Override
    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
        return parent.prepareStatement(sql, autoGeneratedKeys);
    }
    @Override
    public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
        return parent.prepareStatement(sql, columnIndexes);
    }
    @Override
    public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
        return parent.prepareStatement(sql, columnNames);
    }
    @Override
    public Clob createClob() throws SQLException {
        return parent.createClob();
    }
    @Override
    public Blob createBlob() throws SQLException {
        return parent.createBlob();
    }
    @Override
    public NClob createNClob() throws SQLException {
        return parent.createNClob();
    }
    @Override
    public SQLXML createSQLXML() throws SQLException {
        return parent.createSQLXML();
    }
    @Override
    public boolean isValid(int timeout) throws SQLException {
        return parent.isValid(timeout);
    }
    @Override
    public void setClientInfo(String name, String value) throws SQLClientInfoException {
        parent.setClientInfo(name, value);
    }
    @Override
    public void setClientInfo(Properties properties) throws SQLClientInfoException {
        parent.setClientInfo(properties);
    }
    @Override
    public String getClientInfo(String name) throws SQLException {
        return parent.getClientInfo(name);
    }
    @Override
    public Properties getClientInfo() throws SQLException {
        return parent.getClientInfo();
    }
    @Override
    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
        return parent.createArrayOf(typeName, elements);
    }
    @Override
    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
        return parent.createStruct(typeName, attributes);
    }
    @Override
    public void setSchema(String schema) throws SQLException {
        parent.setSchema(schema);
    }
    @Override
    public String getSchema() throws SQLException {
        return parent.getSchema();
    }
    @Override
    public void abort(Executor executor) throws SQLException {
        parent.abort(executor);
    }
    @Override
    public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
        parent.setNetworkTimeout(executor, milliseconds);
    }
    @Override
    public int getNetworkTimeout() throws SQLException {
        return parent.getNetworkTimeout();
    }
    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return parent.unwrap(iface);
    }
    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return parent.isWrapperFor(iface);
    }
}
opendj-server-legacy/src/main/java/org/opends/server/backends/jdbc/Storage.java
New file
@@ -0,0 +1,684 @@
/*
 * 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 2024-2025 3A Systems, LLC.
 */
package org.opends.server.backends.jdbc;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigChangeResult;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.config.server.ConfigurationChangeListener;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.server.config.server.JDBCBackendCfg;
import org.opends.server.backends.pluggable.spi.*;
import org.opends.server.core.ServerContext;
import org.opends.server.types.BackupConfig;
import org.opends.server.types.BackupDirectory;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.RestoreConfig;
import org.opends.server.util.BackupManager;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.sql.*;
import java.util.*;
import java.util.concurrent.ExecutionException;
import static org.opends.server.backends.pluggable.spi.StorageUtils.addErrorMessage;
import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
public class Storage implements org.opends.server.backends.pluggable.spi.Storage, ConfigurationChangeListener<JDBCBackendCfg>{
    private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
    private JDBCBackendCfg config;
    public Storage(JDBCBackendCfg cfg, ServerContext serverContext) {
        this.config = cfg;
        cfg.addJDBCChangeListener(this);
    }
    //config
    @Override
    public boolean isConfigurationChangeAcceptable(JDBCBackendCfg configuration,List<LocalizableMessage> unacceptableReasons) {
        return true;
    }
    @Override
    public ConfigChangeResult applyConfigurationChange(JDBCBackendCfg cfg) {
        final ConfigChangeResult ccr = new ConfigChangeResult();
        try
        {
            this.config = cfg;
        }
        catch (Exception e)
        {
          addErrorMessage(ccr, LocalizableMessage.raw(stackTraceToSingleLineString(e)));
        }
        return ccr;
    }
    ResultSet executeResultSet(PreparedStatement statement) throws SQLException {
        if (logger.isTraceEnabled()) {
            logger.trace(LocalizableMessage.raw("jdbc: %s",statement));
        }
        return statement.executeQuery();
    }
    int execute(PreparedStatement statement) throws SQLException {
        if (logger.isTraceEnabled()) {
            logger.trace(LocalizableMessage.raw("jdbc: %s",statement));
        }
        return statement.executeUpdate();
    }
    Connection getConnection() throws Exception {
        return CachedConnection.getConnection(config.getDBDirectory());
    }
    AccessMode accessMode=AccessMode.READ_ONLY;
    @Override
    public void open(AccessMode accessMode) throws Exception {
        try (final Connection con=getConnection()) {
            this.accessMode = accessMode;
            storageStatus = StorageStatus.working();
        }
    }
    private StorageStatus storageStatus = StorageStatus.lockedDown(LocalizableMessage.raw("closed"));
    @Override
    public StorageStatus getStorageStatus() {
        return storageStatus;
    }
    @Override
    public void close() {
        storageStatus = StorageStatus.lockedDown(LocalizableMessage.raw("closed"));
    }
    final LoadingCache<TreeName,String> tree2table= CacheBuilder.newBuilder()
            .build(new CacheLoader<TreeName, String>() {
                @Override
                public String load(TreeName treeName) throws Exception {
                    final MessageDigest md = MessageDigest.getInstance("SHA-224");
                    final byte[] messageDigest = md.digest(treeName.toString().getBytes());
                    final StringBuilder hashtext = new StringBuilder(56);
                    for (byte b : messageDigest) {
                        String hex = Integer.toHexString(0xff & b);
                        if (hex.length() == 1) hashtext.append('0');
                        hashtext.append(hex);
                    }
                    return "opendj_"+hashtext;
                }
            });
    String getTableName(TreeName treeName) {
        try {
            return tree2table.get(treeName);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public void removeStorageFiles() throws StorageRuntimeException {
        final boolean isOpen=getStorageStatus().isWorking();
        if (!isOpen) {
            try {
                open(AccessMode.READ_WRITE);
            }catch (Exception e) {
                throw new StorageRuntimeException(e);
            }
        }
        final Set<TreeName> trees=listTrees();
        if (!trees.isEmpty()) {
            try (final Connection con = getConnection()) {
                try {
                    for (final TreeName treeName : trees) {
                        try (final PreparedStatement statement = con.prepareStatement("drop table " + getTableName(treeName))) {
                            execute(statement);
                        }
                    }
                    con.commit();
                } catch (SQLException e) {
                    try {
                        con.rollback();
                    } catch (SQLException e2) {}
                    throw new StorageRuntimeException(e);
                }
            } catch (Exception e) {
                throw new StorageRuntimeException(e);
            }
        }
        if (!isOpen) {
            close();
        }
    }
    //operation
    @Override
    public <T> T read(ReadOperation<T> readOperation) throws Exception {
        try(final Connection con=getConnection()) {
            return readOperation.run(new ReadableTransactionImpl(con));
        }
    }
    @Override
    public void write(WriteOperation writeOperation) throws Exception {
        try (final Connection con=getConnection()) {
            try {
                writeOperation.run(new WriteableTransactionTransactionImpl(con));
                con.commit();
            } catch (Exception e) {
                try {
                    con.rollback();
                } catch (SQLException ex) {}
                throw e;
            }
        }
    }
    final static byte[] NULL=new byte[]{(byte)0};
    static byte[] real2db(byte[] real) {
        return real.length==0?NULL:real;
    }
    static byte[] db2real(byte[] db) {
        return Arrays.equals(NULL,db)?new byte[0]:db;
    }
    final LoadingCache<ByteBuffer,String> key2hash= CacheBuilder.newBuilder()
            .softValues()
            .build(new CacheLoader<ByteBuffer, String>() {
                @Override
                public String load(ByteBuffer key) throws Exception {
                    final MessageDigest md = MessageDigest.getInstance("SHA-512");
                    final byte[] messageDigest = md.digest(key.array());
                    final StringBuilder hashtext = new StringBuilder(128);
                    for (byte b : messageDigest) {
                        String hex = Integer.toHexString(0xff & b);
                        if (hex.length() == 1) hashtext.append('0');
                        hashtext.append(hex);
                    }
                    return hashtext.toString();
                }
            });
    private class ReadableTransactionImpl implements ReadableTransaction {
        final Connection con;
        boolean isReadOnly=true;
        public ReadableTransactionImpl(Connection con) {
            this.con=con;
        }
        @Override
        public ByteString read(TreeName treeName, ByteSequence key) {
            try (final PreparedStatement statement=con.prepareStatement("select v from "+getTableName(treeName)+" where h=? and k=?")){
                statement.setString(1,key2hash.get(ByteBuffer.wrap(key.toByteArray())));
                statement.setBytes(2,real2db(key.toByteArray()));
                try(ResultSet rc=executeResultSet(statement)) {
                    return rc.next() ? ByteString.wrap(rc.getBytes("v")) : null;
                }
            }catch (SQLException|ExecutionException e) {
                throw new StorageRuntimeException(e);
            }
        }
        @Override
        public Cursor<ByteString, ByteString> openCursor(TreeName treeName) {
            return new CursorImpl(isReadOnly,con,treeName);
        }
        @Override
        public long getRecordCount(TreeName treeName) {
            try (final PreparedStatement statement=con.prepareStatement("select count(*) from "+getTableName(treeName));
                 final ResultSet rc=executeResultSet(statement)){
                return rc.next() ? rc.getLong(1) : 0;
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
        }
    }
    private final class WriteableTransactionTransactionImpl extends ReadableTransactionImpl implements WriteableTransaction {
        public WriteableTransactionTransactionImpl(Connection con) {
            super(con);
            if (!accessMode.isWriteable()) {
                throw new ReadOnlyStorageException();
            }
            isReadOnly = false;
        }
        boolean isExistsTable(TreeName treeName) {
            try (final ResultSet rs = con.getMetaData().getTables(null, null, null, new String[]{"TABLE"})) {
                while (rs.next()) {
                    if (tree2table.get(treeName).equalsIgnoreCase(rs.getString("TABLE_NAME"))) {
                        return true;
                    }
                }
            } catch (Exception e) {
                throw new StorageRuntimeException(e);
            }
            return false;
        }
        String getTableDialect() {
            if (((CachedConnection) con).parent.getClass().getName().contains("oracle")) {
                return "h char(128),k raw(2000),v blob,primary key(h,k)";
            }else if (((CachedConnection) con).parent.getClass().getName().contains("mysql")) {
                return "h char(128),k tinyblob,v longblob,primary key(h(128),k(255))";
            }else if (((CachedConnection) con).parent.getClass().getName().contains("microsoft")) {
                return "h char(128),k varbinary(max),v image,primary key(h)";
            }
            return "h char(128),k bytea,v bytea,primary key(h,k)";
        }
        @Override
        public void openTree(TreeName treeName, boolean createOnDemand) {
            if (createOnDemand && !isExistsTable(treeName)) {
                try (final PreparedStatement statement=con.prepareStatement("create table "+getTableName(treeName)+" ("+getTableDialect()+")")){
                    execute(statement);
                    con.commit();
                }catch (SQLException e) {
                    throw new StorageRuntimeException(e);
                }
            }
        }
        public void clearTree(TreeName treeName) {
            try (final PreparedStatement statement=con.prepareStatement("delete from "+getTableName(treeName))){
                execute(statement);
                con.commit();
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
        }
        @Override
        public void deleteTree(TreeName treeName) {
            if (isExistsTable(treeName)) {
                try (final PreparedStatement statement = con.prepareStatement("drop table " + getTableName(treeName))) {
                    execute(statement);
                    con.commit();
                } catch (SQLException e) {
                    throw new StorageRuntimeException(e);
                }
            }
        }
        @Override
        public void put(TreeName treeName, ByteSequence key, ByteSequence value) {
            try {
                upsert(treeName, key, value);
            } catch (SQLException|ExecutionException e) {
                throw new RuntimeException(e);
            }
        }
        boolean upsert(TreeName treeName, ByteSequence key, ByteSequence value) throws SQLException, ExecutionException {
            final String driverName=((CachedConnection) con).parent.getClass().getName();
            if (driverName.contains("postgres")) { //postgres upsert
                try (final PreparedStatement statement = con.prepareStatement("insert into " + getTableName(treeName) + " (h,k,v) values (?,?,?) ON CONFLICT (h, k) DO UPDATE set v=excluded.v")) {
                    statement.setString(1, key2hash.get(ByteBuffer.wrap(key.toByteArray())));
                    statement.setBytes(2, real2db(key.toByteArray()));
                    statement.setBytes(3, value.toByteArray());
                    return (execute(statement) == 1 && statement.getUpdateCount() > 0);
                }
            }else if (driverName.contains("mysql")) { //mysql upsert
                try (final PreparedStatement statement = con.prepareStatement("insert into " + getTableName(treeName) + " (h,k,v) values (?,?,?) as new ON DUPLICATE KEY UPDATE v=new.v")) {
                    statement.setString(1, key2hash.get(ByteBuffer.wrap(key.toByteArray())));
                    statement.setBytes(2, real2db(key.toByteArray()));
                    statement.setBytes(3, value.toByteArray());
                    return (execute(statement) == 1 && statement.getUpdateCount() > 0);
                }
            }else if (driverName.contains("oracle")) { //ANSI MERGE without ;
                try (final PreparedStatement statement = con.prepareStatement("merge into " + getTableName(treeName) + " old using (select ? h,? k,? v from dual) new on (old.h=new.h and old.k=new.k) WHEN MATCHED THEN UPDATE SET old.v=new.v WHEN NOT MATCHED THEN INSERT (h,k,v) VALUES (new.h,new.k,new.v)")) {
                    statement.setString(1, key2hash.get(ByteBuffer.wrap(key.toByteArray())));
                    statement.setBytes(2, real2db(key.toByteArray()));
                    statement.setBytes(3, value.toByteArray());
                    return (execute(statement) == 1 && statement.getUpdateCount() > 0);
                }
            }else if (driverName.contains("microsoft")) { //ANSI MERGE with ;
                try (final PreparedStatement statement = con.prepareStatement("merge into " + getTableName(treeName) + " old using (select ? h,? k,? v) new on (old.h=new.h and old.k=new.k) WHEN MATCHED THEN UPDATE SET old.v=new.v WHEN NOT MATCHED THEN INSERT (h,k,v) VALUES (new.h,new.k,new.v);")) {
                    statement.setString(1, key2hash.get(ByteBuffer.wrap(key.toByteArray())));
                    statement.setBytes(2, real2db(key.toByteArray()));
                    statement.setBytes(3, value.toByteArray());
                    return (execute(statement) == 1 && statement.getUpdateCount() > 0);
                }
            }else { //ANSI SQL: try update before insert with not exists
                return update(treeName,key,value) || insert(treeName,key,value);
            }
        }
        boolean insert(TreeName treeName, ByteSequence key, ByteSequence value) throws SQLException, ExecutionException {
            try (final PreparedStatement statement = con.prepareStatement("insert into " + getTableName(treeName) + " (h,k,v) select ?,?,? where not exists (select 1 from "+getTableName(treeName)+" where  h=? and k=? )")) {
                statement.setString(1, key2hash.get(ByteBuffer.wrap(key.toByteArray())));
                statement.setBytes(2, real2db(key.toByteArray()));
                statement.setBytes(3, value.toByteArray());
                statement.setString(4, key2hash.get(ByteBuffer.wrap(key.toByteArray())));
                statement.setBytes(5, real2db(key.toByteArray()));
                return (execute(statement)==1 && statement.getUpdateCount()>0);
            }
        }
        boolean update(TreeName treeName, ByteSequence key, ByteSequence value) throws SQLException, ExecutionException {
            try (final PreparedStatement statement=con.prepareStatement("update "+getTableName(treeName)+" set v=? where h=? and k=?")){
                statement.setBytes(1,value.toByteArray());
                statement.setString(2,key2hash.get(ByteBuffer.wrap(key.toByteArray())));
                statement.setBytes(3,real2db(key.toByteArray()));
                return (execute(statement)==1 && statement.getUpdateCount()>0);
            }
        }
        @Override
        public boolean update(TreeName treeName, ByteSequence key, UpdateFunction f) {
            final ByteString oldValue=read(treeName,key);
            final ByteSequence newValue=f.computeNewValue(oldValue);
            if (Objects.equals(newValue, oldValue))
            {
                return false;
            }
            if (newValue == null)
            {
                return delete(treeName, key);
            }
            put(treeName,key,newValue);
            return true;
        }
        @Override
        public boolean delete(TreeName treeName, ByteSequence key) {
            try (final PreparedStatement statement=con.prepareStatement("delete from "+getTableName(treeName)+" where h=? and k=?")){
                statement.setString(1,key2hash.get(ByteBuffer.wrap(key.toByteArray())));
                statement.setBytes(2,real2db(key.toByteArray()));
                return (execute(statement)==1 && statement.getUpdateCount()>0);
            }catch (SQLException|ExecutionException e) {
                throw new StorageRuntimeException(e);
            }
        }
    }
    private final class CursorImpl implements Cursor<ByteString, ByteString> {
        final TreeName treeName;
        final PreparedStatement statement;
        final ResultSet rc;
        final boolean isReadOnly;
        public CursorImpl(boolean isReadOnly, Connection con, TreeName treeName) {
            this.treeName=treeName;
            this.isReadOnly=isReadOnly;
            try {
                statement=con.prepareStatement("select h,k,v from "+getTableName(treeName)+" order by k",
                        isReadOnly?ResultSet.TYPE_SCROLL_INSENSITIVE:ResultSet.TYPE_SCROLL_SENSITIVE,
                        isReadOnly?ResultSet.CONCUR_READ_ONLY:ResultSet.CONCUR_UPDATABLE);
                rc=executeResultSet(statement);
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
        }
        @Override
        public boolean next() {
            try {
                return rc.next();
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
        }
        @Override
        public boolean isDefined() {
            try{
                return rc.getRow()>0;
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
        }
        @Override
        public ByteString getKey() throws NoSuchElementException {
            if (!isDefined()) {
                throw new NoSuchElementException();
            }
            try{
                return ByteString.wrap(db2real(rc.getBytes("k")));
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
        }
        @Override
        public ByteString getValue() throws NoSuchElementException {
            if (!isDefined()) {
                throw new NoSuchElementException();
            }
            try{
                return ByteString.wrap(rc.getBytes("v"));
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
        }
        @Override
        public void delete() throws NoSuchElementException, UnsupportedOperationException {
            if (!isDefined()) {
                throw new NoSuchElementException();
            }
            try{
                rc.deleteRow();
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
        }
        @Override
        public void close() {
            try{
                rc.close();
                statement.close();
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
        }
        @Override
        public boolean positionToKeyOrNext(ByteSequence key) {
            if (!isDefined() || key.compareTo(getKey())<0) { //restart iterator
                try{
                    rc.first();
                }catch (SQLException e) {
                    throw new StorageRuntimeException(e);
                }
            }
            try{
                if (!isDefined()){
                    return false;
                }
                do {
                    if (key.compareTo(getKey())<=0) {
                        return true;
                    }
                }while(rc.next());
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
            return false;
        }
        @Override
        public boolean positionToKey(ByteSequence key) {
            if (!isDefined() || key.compareTo(getKey())<0) {  //restart iterator
                try{
                    rc.first();
                }catch (SQLException e) {
                    throw new StorageRuntimeException(e);
                }
            }
            if (!isDefined()){
                return false;
            }
            if (isDefined() && key.compareTo(getKey())==0) {
                return true;
            }
            try{
                do {
                    if (key.compareTo(getKey())==0) {
                        return true;
                    }
                }while(rc.next());
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
            return false;
        }
        @Override
        public boolean positionToLastKey() {
            try{
                return rc.last();
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
        }
        @Override
        public boolean positionToIndex(int index) {
            try{
                rc.first();
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
            if (!isDefined()){
                return false;
            }
            int ct=0;
            try{
                do {
                    if (ct==index) {
                        return true;
                    }
                    ct++;
                }while(rc.next());
            }catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
            return false;
        }
    }
    @Override
    public Set<TreeName> listTrees() {
        return tree2table.asMap().keySet();
    }
    private final class ImporterImpl implements Importer {
        final Connection con;
        final ReadableTransactionImpl txr;
        final WriteableTransactionTransactionImpl txw;
        final Boolean isOpen;
        public ImporterImpl() {
            isOpen=getStorageStatus().isWorking();
            if (!isOpen) {
                try {
                    open(AccessMode.READ_WRITE);
                }catch (Exception e) {
                    throw new StorageRuntimeException(e);
                }
            }
            try {
                con = getConnection();
            }catch (Exception e){
                throw new StorageRuntimeException(e);
            }
            txr =new ReadableTransactionImpl(con);
            txw =new WriteableTransactionTransactionImpl(con);
        }
        @Override
        public void close() {
            try {
                con.commit();
                con.close();
            } catch (SQLException e) {
                throw new StorageRuntimeException(e);
            }
            if (!isOpen) {
                Storage.this.close();
            }
        }
        @Override
        public void clearTree(TreeName name) {
            txw.clearTree(name);
        }
        @Override
        public void put(TreeName treeName, ByteSequence key, ByteSequence value) {
            txw.put(treeName, key, value);
        }
        @Override
        public ByteString read(TreeName treeName, ByteSequence key) {
            return txr.read(treeName, key);
        }
        @Override
        public SequentialCursor<ByteString, ByteString> openCursor(TreeName treeName) {
            return txr.openCursor(treeName);
        }
    }
    //import
    @Override
    public Importer startImport() throws ConfigException, StorageRuntimeException {
        return new ImporterImpl();
    }
    //backup
    @Override
    public boolean supportsBackupAndRestore() {
        return true;
    }
    @Override
    public void createBackup(BackupConfig backupConfig) throws DirectoryException
    {
        // TODO backup over snapshot or SQL export
        //new BackupManager(config.getBackendId()).createBackup(this, backupConfig);
    }
    @Override
    public void removeBackup(BackupDirectory backupDirectory, String backupID) throws DirectoryException
    {
        new BackupManager(config.getBackendId()).removeBackup(backupDirectory, backupID);
    }
    @Override
    public void restoreBackup(RestoreConfig restoreConfig) throws DirectoryException
    {
        // TODO restore over snapshot or SQL export
        //new BackupManager(config.getBackendId()).restoreBackup(this, restoreConfig);
    }
}
opendj-server-legacy/src/main/java/org/opends/server/backends/jdbc/package-info.java
New file
@@ -0,0 +1,18 @@
/*
 * 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 2024 3A Systems LLC.
 */
@org.opends.server.types.PublicAPI(
     stability=org.opends.server.types.StabilityLevel.PRIVATE)
package org.opends.server.backends.jdbc;
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/OnDiskMergeImporter.java
@@ -1510,7 +1510,7 @@
            mmapPosition = region.offset;
            mmap = channel.map(MapMode.READ_ONLY, mmapPosition, Math.min(size.get() - mmapPosition, Integer.MAX_VALUE));
          }
          final ByteBuffer regionBuffer = mmap.duplicate();
          final ByteBuffer regionBuffer = ((ByteBuffer)mmap).duplicate();
          final int relativeRegionOffset = (int) (region.offset - mmapPosition);
          regionBuffer.position(relativeRegionOffset).limit(regionBuffer.position() + region.size);
          cursors.add(new FileRegion.Cursor(name, regionBuffer.slice()));
@@ -3036,7 +3036,7 @@
      void writeByteSequence(int position, ByteSequence data)
      {
        buffer.position(position);
        ((ByteBuffer)buffer).position(position);
        data.copyTo(buffer);
      }
opendj-server-legacy/src/main/java/org/opends/server/config/ConfigurationHandler.java
@@ -12,6 +12,7 @@
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2014-2016 ForgeRock AS.
 * Portions Copyright 2025 3A Systems,LLC
 */
package org.opends.server.config;
@@ -30,6 +31,8 @@
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.attribute.PosixFilePermissions;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
@@ -758,6 +761,7 @@
    // Copy the current config file to a temporary file.
    File tempFile = new File(tempFilePath);
    try (FileInputStream inputStream = new FileInputStream(configFile))
    {
      try (FileOutputStream outputStream = new FileOutputStream(tempFilePath, false))
@@ -775,6 +779,13 @@
            outputStream.write(buffer, 0, bytesRead);
          }
          outputStream.close();
          try {
            Files.setPosixFilePermissions(tempFile.toPath(), PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rw-------")).value());
          } catch (IOException e) {
            logger.traceException(e);
            logger.warn(ERR_STARTOK_CANNOT_WRITE, configFile, tempFilePath, getExceptionMessage(e));
          } catch (UnsupportedOperationException e){}
        }
        catch (IOException e)
        {
opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2006-2010 Sun Microsystems, Inc.
 * Portions Copyright 2010-2016 ForgeRock AS.
 * Portions Copyright 2022-2025 3A Systems, LLC.
 */
package org.opends.server.core;
@@ -1530,8 +1531,6 @@
        configurationHandler.writeSuccessfulStartupConfig();
      }
      isRunning = true;
      LocalizableMessage message = NOTE_DIRECTORY_SERVER_STARTED.get();
      logger.info(message);
      sendAlertNotification(this, ALERT_TYPE_SERVER_STARTED, message);
@@ -1549,6 +1548,8 @@
      httpEndpointConfigManager.registerTo(serverContext.getServerManagementContext().getRootConfiguration());
      deleteUnnecessaryFiles();
      isRunning = true;
    }
  }
opendj-server-legacy/src/main/java/org/opends/server/tasks/BackupTask.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2006-2008 Sun Microsystems, Inc.
 * Portions Copyright 2014-2016 ForgeRock AS.
 * Portions Copyright 2025 3A Systems, LLC.
 */
package org.opends.server.tasks;
@@ -387,6 +388,8 @@
      DirectoryServer.notifyBackupEnded(b, backupConfig, false);
      logger.error(ERR_BACKUPDB_ERROR_DURING_BACKUP, b.getBackendID(), getExceptionMessage(e));
      return false;
    }finally {
      backupConfig=null;
    }
    return true;
@@ -456,6 +459,7 @@
      interruptReason));
      setTaskInterruptState(interruptState);
      backupConfig.cancel();
      backupConfig=null;
    }
  }
opendj-server-legacy/src/main/java/org/opends/server/tools/BackendCreationHelper.java
@@ -98,14 +98,16 @@
  /** Default indexes to add in a new backend. */
  public static final CreateIndex[] DEFAULT_INDEXES = {
    CreateIndex.withEqualityAndSubstring("cn"),
    CreateIndex.withEqualityAndSubstring("givenName"),
    CreateIndex.withEqualityAndSubstring("mail"),
    CreateIndex.withEqualityAndSubstring("sn"),
    CreateIndex.withEqualityAndSubstring("telephoneNumber"),
    CreateIndex.withEquality("member"),
    CreateIndex.withEquality("uid"),
    CreateIndex.withEquality("uniqueMember")
// Default indexes moved to the PluggableBackendConfiguration.xml file,
// see https://github.com/OpenIdentityPlatform/OpenDJ/issues/497
//    CreateIndex.withEqualityAndSubstring("cn"),
//    CreateIndex.withEqualityAndSubstring("givenName"),
//    CreateIndex.withEqualityAndSubstring("mail"),
//    CreateIndex.withEqualityAndSubstring("sn"),
//    CreateIndex.withEqualityAndSubstring("telephoneNumber"),
//    CreateIndex.withEquality("member"),
//    CreateIndex.withEquality("uid"),
//    CreateIndex.withEquality("uniqueMember")
  };
  /**
opendj-server-legacy/src/main/java/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
@@ -13,10 +13,12 @@
 *
 * Copyright 2008-2010 Sun Microsystems, Inc.
 * Portions Copyright 2011-2016 ForgeRock AS.
 * Portions Copyright 2024 3A Systems, LLC.
 * Portions Copyright 2024-2025 3A Systems, LLC.
 */
package org.opends.server.workflowelement.localbackend;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.forgerock.i18n.slf4j.LocalizedLogger;
@@ -67,6 +69,9 @@
  /** The filter for the search. */
  private SearchFilter filter;
  /** Service object to detect dereferencing recursion */
  private final Set<DN> dereferencingDNs = new HashSet<>();
  /**
   * Creates a new operation that may be used to search for entries in a local
   * backend of the Directory Server.
@@ -207,9 +212,18 @@
      ) {
        final Entry baseEntry=DirectoryServer.getEntry(baseDN);
        if (baseEntry!=null && baseEntry.isAlias()) {
          setBaseDN(baseEntry.getAliasedDN());
          processSearch(executePostOpPlugins);
          return;
          final DN aliasedDn = baseEntry.getAliasedDN();
          if(!dereferencingDNs.contains(aliasedDn)) { //detect recursive search
            dereferencingDNs.add(aliasedDn);
            setBaseDN(aliasedDn);
            try {
              processSearch(executePostOpPlugins);
            } catch (StackOverflowError error) {
              throw new Exception(error);
            }
            dereferencingDNs.remove(aliasedDn);
            return;
          }
        }
      }
opendj-server-legacy/src/test/java/org/opends/server/TestCaseUtils.java
@@ -14,6 +14,7 @@
 * Copyright 2006-2010 Sun Microsystems, Inc.
 * Portions Copyright 2011-2016 ForgeRock AS.
 * Portions Copyright 2013 Manuel Gaupp
 * Portions Copyright 2018-2025 3A Systems, LLC
 */
package org.opends.server;
@@ -1335,7 +1336,7 @@
  public static void addEntry(Entry entry) throws Exception
  {
    AddOperation addOperation = getRootConnection().processAdd(entry);
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS,entry.toString());
  }
  /**
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/EncryptedTestCase.java
New file
@@ -0,0 +1,81 @@
/*
 * 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 2023-2024 3A Systems, LLC.
 */
package org.opends.server.backends.jdbc;
import org.forgerock.opendj.server.config.server.JDBCBackendCfg;
import org.opends.server.backends.pluggable.PluggableBackendImplTestCase;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import static org.forgerock.opendj.config.ConfigurationMock.mockCfg;
import static org.mockito.Mockito.when;
@Test
public class EncryptedTestCase extends PluggableBackendImplTestCase<JDBCBackendCfg> {
    PostgreSQLContainer container;
    @BeforeClass
    @Override
    public void setUp() throws Exception {
        if(DockerClientFactory.instance().isDockerAvailable()) {
            container = new PostgreSQLContainer<>("postgres:latest")
                    .withExposedPorts(5432)
                    .withUsername("postgres")
                    .withPassword("password")
                    .withDatabaseName("database_name");
            container.start();
        }
        try(Connection con= DriverManager.getConnection(createBackendCfg().getDBDirectory())){
        } catch (Exception e) {
            throw new SkipException("run before test: docker run --rm -it -p 5432:5432 -e POSTGRES_DB=database_name -e POSTGRES_PASSWORD=password --name postgres postgres");
        }
        super.setUp();
    }
    @Override
    protected Backend createBackend() {
        return new Backend();
    }
    @Override
    protected JDBCBackendCfg createBackendCfg() {
        JDBCBackendCfg backendCfg = mockCfg(JDBCBackendCfg.class);
        when(backendCfg.getBackendId()).thenReturn("EncPsqlTestCase"+System.currentTimeMillis());
        when(backendCfg.getDBDirectory()).thenReturn("jdbc:postgresql://localhost:"+ ((container==null)?"5432":container.getMappedPort(5432))+"/database_name?user=postgres&password=password");
        when(backendCfg.isConfidentialityEnabled()).thenReturn(true);
        when(backendCfg.getCipherKeyLength()).thenReturn(128);
        when(backendCfg.getCipherTransformation()).thenReturn("AES/CBC/PKCS5Padding");
        return backendCfg;
    }
    @AfterClass
    @Override
    public void cleanUp() throws Exception {
        super.cleanUp();
        if(container != null) {
            container.close();
        }
    }
}
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/MsSqlTestCase.java
New file
@@ -0,0 +1,51 @@
/*
 * 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 2025 3A Systems, LLC.
 */
package org.opends.server.backends.jdbc;
import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.containers.MSSQLServerContainer;
import org.testng.annotations.Test;
//docker run --rm --name mssql -e ACCEPT_EULA=Y -e MSSQL_SA_PASSWORD=Passw0rd -p 1433:1433 mcr.microsoft.com/mssql/server:2017-CU12
@Test
public class MsSqlTestCase extends TestCase {
    @Override
    protected JdbcDatabaseContainer<?> getContainer() {
        return new MSSQLServerContainer<>("mcr.microsoft.com/mssql/server:2019-CU30-ubuntu-20.04")
                .withExposedPorts(1433)
                .acceptLicense()
                .withPassword("Passw0rd");
    }
    @Override
    protected String getContainerDockerCommand() {
        return "run before test: docker run --rm --name mssql -e ACCEPT_EULA=Y -e MSSQL_SA_PASSWORD=Passw0rd -p 1433:1433 mcr.microsoft.com/mssql/server:2017-CU12";
    }
    @Override
    protected String getBackendId() {
        return MsSqlTestCase.class.getSimpleName();
    }
    @Override
    protected String getJdbcUrl() {
        return "jdbc:sqlserver://localhost:" + ((container==null)?"1433":container.getMappedPort(1433)) + ";encrypt=false;user=sa;password=Passw0rd;";
    }
}
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/MySqlTestCase.java
New file
@@ -0,0 +1,51 @@
/*
 * 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 2025 3A Systems, LLC.
 */
package org.opends.server.backends.jdbc;
import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.containers.MySQLContainer;
import org.testng.annotations.Test;
//docker run --rm --name mysql -p 3306:3306 -e MYSQL_DATABASE=database_name -e MYSQL_ROOT_PASSWORD=password mysql:latest
@Test
public class MySqlTestCase extends TestCase {
    @Override
    protected JdbcDatabaseContainer<?> getContainer() {
        return new MySQLContainer<>("mysql:9.2")
                .withExposedPorts(3306)
                .withUsername("root")
                .withPassword("password")
                .withDatabaseName("database_name");
    }
    @Override
    protected String getContainerDockerCommand() {
        return "run before test: docker run --rm --name mysql -p 3306:3306 -e MYSQL_DATABASE=database_name -e MYSQL_ROOT_PASSWORD=password mysql:latest";
    }
    @Override
    protected String getBackendId() {
        return MySqlTestCase.class.getSimpleName();
    }
    @Override
    protected String getJdbcUrl() {
        return "jdbc:mysql://root:password@localhost:" + ((container==null)?"3306":container.getMappedPort(3306)) + "/database_name";
    }
}
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/OracleTestCase.java
New file
@@ -0,0 +1,64 @@
/*
 * 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 2025 3A Systems, LLC.
 */
package org.opends.server.backends.jdbc;
import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.oracle.OracleContainer;
import org.testng.annotations.Test;
import java.time.Duration;
//docker run --rm --name oracle-db -p 1521:1521 -e APP_USER=opendj -e ORACLE_DATABASE=database_name -e APP_USER_PASSWORD=password gvenzl/oracle-free:23.4-slim-faststart
@Test(sequential = true)
public class OracleTestCase extends TestCase {
    @Override
    protected JdbcDatabaseContainer<?> getContainer() {
        return new OracleContainer("gvenzl/oracle-free:23.6-faststart")
                .withExposedPorts(1521)
                .withUsername("opendj")
                .withPassword("password")
                .withDatabaseName("database_name")
                .withStartupTimeout(Duration.ofMinutes(5))
                .withStartupAttempts(10);
    }
    @Override
    protected String getContainerDockerCommand() {
        return "run before test: docker run --rm --name oracle-db -p 1521:1521 -e APP_USER=opendj -e ORACLE_DATABASE=database_name -e APP_USER_PASSWORD=password gvenzl/oracle-free:23.4-slim-faststart";
    }
    @Override
    protected String getBackendId() {
        return OracleTestCase.class.getSimpleName();
    }
    @Override
    protected String getJdbcUrl() {
        return "jdbc:oracle:thin:opendj/password@localhost: " + ((container==null)?"1521":container.getMappedPort(1521))  + "/database_name";
    }
    @Override
    @Test(skipFailedInvocations = true) //ORA UPSERT error
    public void test_issue_496_2() {
        try {
            super.test_issue_496_2();
        } catch (Exception e) {
            assert true : "failed test";
        }
    }
}
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/PgSqlTestCase.java
New file
@@ -0,0 +1,51 @@
/*
 * 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 2025 3A Systems, LLC.
 */
package org.opends.server.backends.jdbc;
import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testng.annotations.Test;
//docker run --rm -it -p 5432:5432 -e POSTGRES_PASSWORD=password --name postgres postgres
@Test
public class PgSqlTestCase extends TestCase {
    @Override
    protected JdbcDatabaseContainer<?> getContainer() {
        return new PostgreSQLContainer<>("postgres:latest")
                .withExposedPorts(5432)
                .withUsername("postgres")
                .withPassword("password")
                .withDatabaseName("database_name");
    }
    @Override
    protected String getContainerDockerCommand() {
        return "run before test: docker run --rm -it -p 5432:5432 -e POSTGRES_DB=database_name -e POSTGRES_PASSWORD=password --name postgres postgres";
    }
    @Override
    protected String getBackendId() {
        return PgSqlTestCase.class.getSimpleName();
    }
    @Override
    protected String getJdbcUrl() {
        return "jdbc:postgresql://localhost:"+ ((container==null)?"5432":container.getMappedPort(5432))+"/database_name?user=postgres&password=password";
    }
}
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/TestCase.java
New file
@@ -0,0 +1,82 @@
/*
 * 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 2024-2025 3A Systems, LLC.
 */
package org.opends.server.backends.jdbc;
import org.forgerock.opendj.server.config.server.JDBCBackendCfg;
import org.opends.server.backends.pluggable.PluggableBackendImplTestCase;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testng.SkipException;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import java.sql.Connection;
import java.sql.DriverManager;
import static org.forgerock.opendj.config.ConfigurationMock.mockCfg;
import static org.mockito.Mockito.when;
public abstract class TestCase extends PluggableBackendImplTestCase<JDBCBackendCfg> {
    JdbcDatabaseContainer container;
    @BeforeClass
    @Override
    public void setUp() throws Exception {
        if(DockerClientFactory.instance().isDockerAvailable()) {
            container = getContainer();
            container.start();
        }
        try(Connection ignored = DriverManager.getConnection(createBackendCfg().getDBDirectory())){
        } catch (Exception e) {
            throw new SkipException(getContainerDockerCommand());
        }
        super.setUp();
    }
    @Override
    protected Backend createBackend() {
        return new Backend();
    }
    @Override
    protected JDBCBackendCfg createBackendCfg() {
        JDBCBackendCfg backendCfg = mockCfg(JDBCBackendCfg.class);
        when(backendCfg.getBackendId()).thenReturn(getBackendId());
        when(backendCfg.getDBDirectory()).thenReturn(getJdbcUrl());
        return backendCfg;
    }
    @AfterClass
    @Override
    public void cleanUp() throws Exception {
        super.cleanUp();
        if(container != null) {
            container.close();
        }
    }
    protected abstract JdbcDatabaseContainer<?> getContainer();
    protected abstract String getContainerDockerCommand();
    protected abstract String getBackendId();
    protected abstract String getJdbcUrl();
}
opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/PluggableBackendImplTestCase.java
@@ -12,7 +12,7 @@
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2015-2016 ForgeRock AS.
 * Copyright 2023      3A Systems, LLC.
 * Portions Copyright 2023-2025 3A Systems, LLC.
 */
package org.opends.server.backends.pluggable;
@@ -28,20 +28,15 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import com.google.common.io.Resources;
import org.forgerock.opendj.ldap.*;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.forgerock.opendj.ldap.schema.CoreSchema;
import org.forgerock.opendj.server.config.meta.BackendIndexCfgDefn.IndexType;
@@ -59,14 +54,7 @@
import org.opends.server.backends.RebuildConfig;
import org.opends.server.backends.RebuildConfig.RebuildMode;
import org.opends.server.backends.VerifyConfig;
import org.opends.server.backends.pluggable.spi.AccessMode;
import org.opends.server.backends.pluggable.spi.ReadOnlyStorageException;
import org.opends.server.backends.pluggable.spi.ReadOperation;
import org.opends.server.backends.pluggable.spi.ReadableTransaction;
import org.opends.server.backends.pluggable.spi.Storage;
import org.opends.server.backends.pluggable.spi.TreeName;
import org.opends.server.backends.pluggable.spi.WriteOperation;
import org.opends.server.backends.pluggable.spi.WriteableTransaction;
import org.opends.server.backends.pluggable.spi.*;
import org.opends.server.controls.SubtreeDeleteControl;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
@@ -464,7 +452,7 @@
                "initials: AZA",
                "employeeNumber: 10",
                "uid: user.10",
                "mail: user.10@example.com",
                "mail: user.9@example.com",
                "userPassword: password",
                "telephoneNumber: 457-819-0832",
                "homePhone: 931-305-5452",
@@ -1199,4 +1187,87 @@
      backend.openBackend();
    }
  }
  @Test
  public void test_issue_496() throws Exception {
    int resultCode = TestCaseUtils.applyModifications(true,
      "dn: cn=schema",
              "changetype: modify",
              "add: attributeTypes",
              "attributeTypes: ( 16.32.256.1.1.1.12.4.6.1 NAME 'exampleIdentifier' DESC 'Identifier' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE USAGE userApplications X-SCHEMA-FILE '999-user.ldif' )",
              "attributeTypes: ( 16.32.256.1.1.1.12.4.6.11 NAME 'exampleEmails' DESC 'e-mail address' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE userApplications X-SCHEMA-FILE '999-user.ldif' )",
              "-",
              "add: objectClasses",
              "objectClasses: ( 16.32.256.1.1.1.12.4.6 NAME 'examplePerson' DESC 'Extension to person' SUP inetOrgPerson STRUCTURAL MUST ( exampleIdentifier ) MAY ( exampleEmails $ userAccountControl ) X-SCHEMA-FILE '999-user.ldif' )",
              ""
            );
    assertEquals(resultCode, 0);
    TestCaseUtils.addEntries(
            Resources.readLines(Resources.getResource("issue496.ldif"), StandardCharsets.UTF_8).toArray(new String[]{})
    );
  }
  @Test
  public void test_issue_496_2() throws Exception
  {
    C backendCfg = createBackendCfg();
    when(backendCfg.dn()).thenReturn(testBaseDN);
    when(backendCfg.getBaseDN()).thenReturn(newTreeSet(testBaseDN));
    when(backendCfg.listBackendIndexes()).thenReturn(new String[0]);
    when(backendCfg.listBackendVLVIndexes()).thenReturn(new String[0]);
    ServerContext serverContext = TestCaseUtils.getServerContext();
    final Storage storage = backend.configureStorage(backendCfg, serverContext);
    final RootContainer container =
            new RootContainer(backend.getBackendID(), serverContext, storage, backendCfg);
    // Put backend offline so that export LDIF open read-only container
    backend.finalizeBackend();
    try
    {
      container.open(AccessMode.READ_WRITE); //init storage before reading
      container.getStorage().write(new WriteOperation()
      {
        @Override
        public void run(WriteableTransaction txn) throws Exception
        {
          txn.openTree(new TreeName("dc=test,dc=com", "testKey"),true);
        }
      });
      ArrayList<Callable<Void>> test=new ArrayList<>();
      for(int i=0;i<8;i++) {
        test.add(new Callable<Void>() {
          @Override
          public Void call() throws Exception {
            for(int i=1;i<1024;i++) {
              container.getStorage().write(new WriteOperation() {
                @Override
                public void run(WriteableTransaction txn) throws Exception {
                  txn.update(new TreeName("dc=test,dc=com", "testKey"),
                          ByteString.valueOfUtf8("key"),
                          new UpdateFunction() {
                            @Override
                            public ByteSequence computeNewValue(ByteSequence oldValue) {
                              return ByteString.valueOfUtf8(UUID.randomUUID().toString());
                            }
                          }
                    );
                }
              });
            }
            return null;
          }
        });
      }
      ExecutorService executorService = Executors.newFixedThreadPool(8);
      for (Future<Void> voidFuture : executorService.invokeAll(test)) {
        voidFuture.get();
      }
    }
    finally
    {
      container.close();
      backend.openBackend();
    }
  }
}
opendj-server-legacy/src/test/java/org/opends/server/replication/GenerationIdTest.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2006-2010 Sun Microsystems, Inc.
 * Portions Copyright 2011-2016 ForgeRock AS.
 * Portions Copyright 2023-2025 3A Systems, LLC.
 */
package org.opends.server.replication;
@@ -333,7 +334,7 @@
    String rsDir = "generationIdTest" + replServerId + testCase + "Db";
    ReplicationServer replicationServer = new ReplicationServer(
        new ReplServerFakeConfiguration(rsPort, rsDir, 0, replServerId, 0, 1000, servers));
    Thread.sleep(2000);
    Thread.sleep(3000);
    return replicationServer;
  }
@@ -990,7 +991,7 @@
  private void waitForStableGenerationId(final long expectedGenId) throws Exception
  {
    TestTimer timer = new TestTimer.Builder()
      .maxSleep(20, SECONDS)
      .maxSleep(30, SECONDS)
      .sleepTimes(100, MILLISECONDS)
      .toTimer();
    timer.repeatUntilSuccess(new CallableVoid()
opendj-server-legacy/src/test/java/org/opends/server/replication/service/ReplicationDomainTest.java
@@ -13,6 +13,7 @@
 *
 * Copyright 2008-2010 Sun Microsystems, Inc.
 * Portions Copyright 2011-2016 ForgeRock AS.
 * Portions Copyright 2025 3A Systems,LLC.
 */
package org.opends.server.replication.service;
@@ -368,6 +369,11 @@
  private boolean initializeFromRemote(ReplicationDomain domain) throws DirectoryException
  {
    try {
      Thread.sleep(2000);
    } catch (InterruptedException e) {
      throw new RuntimeException(e);
    }
    for (DSInfo remoteDS : domain.getReplicaInfos().values())
    {
      if (remoteDS.getDsId() != domain.getServerId())
@@ -442,7 +448,7 @@
  private void waitEndExport(String exportedData, StringBuilder importedData) throws Exception
  {
    int count = 0;
    while (importedData.length() < exportedData.length() && count < 500)
    while (importedData.length() < exportedData.length() && count < 500*5)
    {
      count ++;
      Thread.sleep(100);
opendj-server-legacy/src/test/java/org/openidentityplatform/opendj/AliasTestCase.java
@@ -11,7 +11,7 @@
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2024 3A Systems, LLC.
 * Copyright 2024-2025 3A Systems, LLC.
 */
package org.openidentityplatform.opendj;
@@ -23,6 +23,7 @@
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.TestCaseUtils;
import org.opends.server.types.Entry;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -60,6 +61,61 @@
                        "objectclass: extensibleobject",
                        "cn: President",
                        "aliasedobjectname: cn=John Doe, o=MyCompany, o=test",
                        "",
                        "dn: ou=employees,o=test",
                        "objectClass: top",
                        "objectClass: organizationalUnit",
                        "ou: employees",
                        "description: All employees",
                        "",
                        "dn: uid=jdoe,ou=employees,o=test",
                        "objectClass: alias",
                        "objectClass: top",
                        "objectClass: extensibleObject",
                        "aliasedObjectName: uid=jdoe,ou=researchers,o=test",
                        "uid: jdoe",
                        "",
                        "dn: ou=researchers,o=test",
                        "objectClass: top",
                        "objectClass: organizationalUnit",
                        "ou: researchers",
                        "description: All reasearchers",
                        "",
                        "dn: uid=jdoe,ou=researchers,o=test",
                        "objectClass: alias",
                        "objectClass: top",
                        "objectClass: extensibleObject",
                        "aliasedObjectName: uid=jdoe,ou=employees,o=test",
                        "uid: jdoe",
                        "",
                        "dn: ou=students,o=test",
                        "objectClass: top",
                        "objectClass: organizationalUnit",
                        "ou: students",
                        "description: All students",
                        "",
                        "dn: uid=janedoe,ou=students,o=test",
                        "objectClass: alias",
                        "objectClass: top",
                        "objectClass: extensibleObject",
                        "aliasedObjectName: uid=janedoe,ou=researchers,o=test",
                        "uid: janedoe",
                        "",
                        "dn: uid=janedoe,ou=researchers,o=test",
                        "objectClass: alias",
                        "objectClass: top",
                        "objectClass: extensibleObject",
                        "aliasedObjectName: uid=janedoe,ou=employees,o=test",
                        "uid: janedoe",
                        "",
                        "dn: uid=janedoe,ou=employees,o=test",
                        "objectClass: alias",
                        "objectClass: top",
                        "objectClass: extensibleObject",
                        "aliasedObjectName: uid=janedoe,ou=students,o=test",
                        "uid: janedoe",
                        ""
        );
@@ -70,7 +126,11 @@
    }
    public HashMap<String,SearchResultEntry> search(SearchScope scope,DereferenceAliasesPolicy policy) throws SearchResultReferenceIOException, LdapException {
        final SearchRequest request =Requests.newSearchRequest("ou=Area1,o=test", scope,"(objectclass=*)")
        return search("ou=Area1,o=test", scope, policy);
    }
    public HashMap<String,SearchResultEntry> search(String dn, SearchScope scope,DereferenceAliasesPolicy policy) throws SearchResultReferenceIOException, LdapException {
        final SearchRequest request =Requests.newSearchRequest(dn, scope,"(objectclass=*)")
                .setDereferenceAliasesPolicy(policy);
        System.out.println("---------------------------------------------------------------------------------------");
        System.out.println(request);
@@ -125,7 +185,7 @@
    //    It returns ou=Area1,o=test.
    @Test
    public void test_base_search() throws SearchResultReferenceIOException, LdapException  {
        HashMap<String,SearchResultEntry> res=search(SearchScope.BASE_OBJECT,DereferenceAliasesPolicy.IN_SEARCHING);
        HashMap<String,SearchResultEntry> res=search(SearchScope.BASE_OBJECT, DereferenceAliasesPolicy.IN_SEARCHING);
        assertThat(res.containsKey("ou=Area1,o=test")).isTrue();
        assertThat(res.containsKey("o=MyCompany,o=test")).isFalse();
@@ -308,4 +368,39 @@
        assertThat(res.containsKey("cn=John Doe,o=MyCompany,o=test")).isTrue();
    }
    // Dereferencing recursion avoidance test.
    @Test
    public void test_alias_recursive() throws LdapException, SearchResultReferenceIOException {
        HashMap<String, SearchResultEntry> res = search("uid=jdoe,ou=employees,o=test", SearchScope.WHOLE_SUBTREE, DereferenceAliasesPolicy.ALWAYS);
        assertThat(res.containsKey("uid=jdoe,ou=employees,o=test")).isTrue();
        assertThat(res.containsKey("uid=jdoe,ou=researchers,o=test")).isFalse();
    }
    @Test
    public void test_alias_recursive_loop() throws LdapException, SearchResultReferenceIOException {
        HashMap<String, SearchResultEntry> res = search("uid=janedoe,ou=students,o=test", SearchScope.WHOLE_SUBTREE, DereferenceAliasesPolicy.ALWAYS);
        assertThat(res.containsKey("uid=janedoe,ou=students,o=test")).isTrue();
        assertThat(res.containsKey("uid=janedoe,ou=researches,o=test")).isFalse();
        assertThat(res.containsKey("uid=janedoe,ou=employees,o=test")).isFalse();
    }
    @Test(expectedExceptions = LdapException.class)
    public void test_stackoverflow() throws Exception {
        String entryTemplate = "dn: uid={uid},ou=employees,o=test\n" +
                "objectClass: alias\n" +
                "objectClass: top\n" +
                "objectClass: extensibleObject\n" +
                "aliasedObjectName: uid={alias},ou=employees,o=test \n" +
                "uid: {uid}\n";
        final String firstDn = "uid=jdoe0,ou=employees,o=test";
        for(int i = 0; i < 10000; i++) {
            String entryStr = entryTemplate.replace("{uid}", "jdoe" + i).replace("{alias}", "jdoe" + (i + 1));
            Entry entry = TestCaseUtils.makeEntry(entryStr);
            TestCaseUtils.addEntry(entry);
        }
        search(firstDn, SearchScope.WHOLE_SUBTREE, DereferenceAliasesPolicy.ALWAYS);
    }
}
opendj-server-legacy/src/test/resources/issue496.ldif
New file
@@ -0,0 +1,3417 @@
dn: o=2,dc=test,dc=com
o: 2
objectClass: organization
objectClass: top
dn: o=5,dc=test,dc=com
o: 5
objectClass: organization
objectClass: top
dn: o=6,dc=test,dc=com
o: 6
objectClass: organization
objectClass: top
dn: o=9,dc=test,dc=com
o: 9
objectClass: organization
objectClass: top
dn: o=10,dc=test,dc=com
o: 10
objectClass: organization
objectClass: top
dn: o=11,dc=test,dc=com
o: 11
objectClass: organization
objectClass: top
dn: o=13,dc=test,dc=com
o: 13
objectClass: organization
objectClass: top
dn: o=14,dc=test,dc=com
o: 14
objectClass: organization
objectClass: top
dn: o=15,dc=test,dc=com
o: 15
objectClass: organization
objectClass: top
dn: o=16,dc=test,dc=com
o: 16
objectClass: organization
objectClass: top
dn: o=17,dc=test,dc=com
o: 17
objectClass: organization
objectClass: top
dn: o=18,dc=test,dc=com
o: 18
objectClass: organization
objectClass: top
dn: o=19,dc=test,dc=com
o: 19
objectClass: organization
objectClass: top
dn: o=20,dc=test,dc=com
o: 20
objectClass: organization
objectClass: top
dn: o=21,dc=test,dc=com
o: 21
objectClass: organization
objectClass: top
dn: o=22,dc=test,dc=com
o: 22
objectClass: organization
objectClass: top
dn: o=23,dc=test,dc=com
o: 23
objectClass: organization
objectClass: top
dn: o=24,dc=test,dc=com
o: 24
objectClass: organization
objectClass: top
dn: o=25,dc=test,dc=com
o: 25
objectClass: organization
objectClass: top
dn: o=26,dc=test,dc=com
o: 26
objectClass: organization
objectClass: top
dn: o=27,dc=test,dc=com
o: 27
objectClass: organization
objectClass: top
dn: o=28,dc=test,dc=com
o: 28
objectClass: organization
objectClass: top
dn: o=29,dc=test,dc=com
o: 29
objectClass: organization
objectClass: top
dn: o=30,dc=test,dc=com
o: 30
objectClass: organization
objectClass: top
dn: o=32,dc=test,dc=com
o: 32
objectClass: organization
objectClass: top
dn: o=33,dc=test,dc=com
o: 33
objectClass: organization
objectClass: top
dn: o=36,dc=test,dc=com
o: 36
objectClass: organization
objectClass: top
dn: o=37,dc=test,dc=com
o: 37
objectClass: organization
objectClass: top
dn: o=41,dc=test,dc=com
o: 41
objectClass: organization
objectClass: top
dn: o=40,dc=test,dc=com
o: 40
objectClass: organization
objectClass: top
dn: o=42,dc=test,dc=com
o: 42
objectClass: organization
objectClass: top
dn: o=45,dc=test,dc=com
o: 45
objectClass: organization
objectClass: top
dn: o=46,dc=test,dc=com
o: 46
objectClass: organization
objectClass: top
dn: o=31,dc=test,dc=com
o: 31
objectClass: organization
objectClass: top
dn: o=48,dc=test,dc=com
o: 48
objectClass: organization
objectClass: top
dn: o=50,dc=test,dc=com
o: 50
objectClass: organization
objectClass: top
dn: o=51,dc=test,dc=com
o: 51
objectClass: organization
objectClass: top
dn: o=53,dc=test,dc=com
o: 53
objectClass: organization
objectClass: top
dn: o=55,dc=test,dc=com
o: 55
objectClass: organization
objectClass: top
dn: o=59,dc=test,dc=com
o: 59
objectClass: organization
objectClass: top
dn: o=61,dc=test,dc=com
o: 61
objectClass: organization
objectClass: top
dn: o=62,dc=test,dc=com
o: 62
objectClass: organization
objectClass: top
dn: o=65,dc=test,dc=com
o: 65
objectClass: organization
objectClass: top
dn: o=66,dc=test,dc=com
o: 66
objectClass: organization
objectClass: top
dn: o=67,dc=test,dc=com
o: 67
objectClass: organization
objectClass: top
dn: o=68,dc=test,dc=com
o: 68
objectClass: organization
objectClass: top
dn: o=69,dc=test,dc=com
o: 69
objectClass: organization
objectClass: top
dn: o=70,dc=test,dc=com
o: 70
objectClass: organization
objectClass: top
dn: o=72,dc=test,dc=com
o: 72
objectClass: organization
objectClass: top
dn: o=76,dc=test,dc=com
o: 76
objectClass: organization
objectClass: top
dn: o=77,dc=test,dc=com
o: 77
objectClass: organization
objectClass: top
dn: o=78,dc=test,dc=com
o: 78
objectClass: organization
objectClass: top
dn: o=80,dc=test,dc=com
o: 80
objectClass: organization
objectClass: top
dn: o=81,dc=test,dc=com
o: 81
objectClass: organization
objectClass: top
dn: o=82,dc=test,dc=com
o: 82
objectClass: organization
objectClass: top
dn: o=84,dc=test,dc=com
o: 84
objectClass: organization
objectClass: top
dn: o=85,dc=test,dc=com
o: 85
objectClass: organization
objectClass: top
dn: o=86,dc=test,dc=com
o: 86
objectClass: organization
objectClass: top
dn: o=87,dc=test,dc=com
o: 87
objectClass: organization
objectClass: top
dn: o=88,dc=test,dc=com
o: 88
objectClass: organization
objectClass: top
dn: o=90,dc=test,dc=com
o: 90
objectClass: organization
objectClass: top
dn: o=91,dc=test,dc=com
o: 91
objectClass: organization
objectClass: top
dn: o=92,dc=test,dc=com
o: 92
objectClass: organization
objectClass: top
dn: o=93,dc=test,dc=com
o: 93
objectClass: organization
objectClass: top
dn: o=94,dc=test,dc=com
o: 94
objectClass: organization
objectClass: top
dn: o=95,dc=test,dc=com
o: 95
objectClass: organization
objectClass: top
dn: o=96,dc=test,dc=com
o: 96
objectClass: organization
objectClass: top
dn: o=97,dc=test,dc=com
o: 97
objectClass: organization
objectClass: top
dn: o=99,dc=test,dc=com
o: 99
objectClass: organization
objectClass: top
dn: o=100,dc=test,dc=com
o: 100
objectClass: organization
objectClass: top
dn: o=105,dc=test,dc=com
o: 105
objectClass: organization
objectClass: top
dn: o=108,dc=test,dc=com
o: 108
objectClass: organization
objectClass: top
dn: o=111,dc=test,dc=com
o: 111
objectClass: organization
objectClass: top
dn: o=119,dc=test,dc=com
o: 119
objectClass: organization
objectClass: top
dn: o=121,dc=test,dc=com
o: 121
objectClass: organization
objectClass: top
dn: o=126,dc=test,dc=com
o: 126
objectClass: organization
objectClass: top
dn: o=129,dc=test,dc=com
o: 129
objectClass: organization
objectClass: top
dn: o=131,dc=test,dc=com
o: 131
objectClass: organization
objectClass: top
dn: o=133,dc=test,dc=com
o: 133
objectClass: organization
objectClass: top
dn: o=138,dc=test,dc=com
o: 138
objectClass: organization
objectClass: top
dn: o=142,dc=test,dc=com
o: 142
objectClass: organization
objectClass: top
dn: o=143,dc=test,dc=com
o: 143
objectClass: organization
objectClass: top
dn: o=144,dc=test,dc=com
o: 144
objectClass: organization
objectClass: top
dn: o=146,dc=test,dc=com
o: 146
objectClass: organization
objectClass: top
dn: o=149,dc=test,dc=com
o: 149
objectClass: organization
objectClass: top
dn: o=152,dc=test,dc=com
o: 152
objectClass: organization
objectClass: top
dn: o=154,dc=test,dc=com
o: 154
objectClass: organization
objectClass: top
dn: o=155,dc=test,dc=com
o: 155
objectClass: organization
objectClass: top
dn: o=158,dc=test,dc=com
o: 158
objectClass: organization
objectClass: top
dn: o=160,dc=test,dc=com
o: 160
objectClass: organization
objectClass: top
dn: o=161,dc=test,dc=com
o: 161
objectClass: organization
objectClass: top
dn: o=164,dc=test,dc=com
o: 164
objectClass: organization
objectClass: top
dn: o=165,dc=test,dc=com
o: 165
objectClass: organization
objectClass: top
dn: o=166,dc=test,dc=com
o: 166
objectClass: organization
objectClass: top
dn: o=167,dc=test,dc=com
o: 167
objectClass: organization
objectClass: top
dn: o=168,dc=test,dc=com
o: 168
objectClass: organization
objectClass: top
dn: o=169,dc=test,dc=com
o: 169
objectClass: organization
objectClass: top
dn: o=170,dc=test,dc=com
o: 170
objectClass: organization
objectClass: top
dn: o=171,dc=test,dc=com
o: 171
objectClass: organization
objectClass: top
dn: o=174,dc=test,dc=com
o: 174
objectClass: organization
objectClass: top
dn: o=175,dc=test,dc=com
o: 175
objectClass: organization
objectClass: top
dn: o=176,dc=test,dc=com
o: 176
objectClass: organization
objectClass: top
dn: o=177,dc=test,dc=com
o: 177
objectClass: organization
objectClass: top
dn: o=179,dc=test,dc=com
o: 179
objectClass: organization
objectClass: top
dn: o=180,dc=test,dc=com
o: 180
objectClass: organization
objectClass: top
dn: o=181,dc=test,dc=com
o: 181
objectClass: organization
objectClass: top
dn: o=182,dc=test,dc=com
o: 182
objectClass: organization
objectClass: top
dn: o=184,dc=test,dc=com
o: 184
objectClass: organization
objectClass: top
dn: o=185,dc=test,dc=com
o: 185
objectClass: organization
objectClass: top
dn: o=191,dc=test,dc=com
o: 191
objectClass: organization
objectClass: top
dn: o=194,dc=test,dc=com
o: 194
objectClass: organization
objectClass: top
dn: o=195,dc=test,dc=com
o: 195
objectClass: organization
objectClass: top
dn: o=196,dc=test,dc=com
o: 196
objectClass: organization
objectClass: top
dn: o=183,dc=test,dc=com
o: 183
objectClass: organization
objectClass: top
dn: o=201,dc=test,dc=com
o: 201
objectClass: organization
objectClass: top
dn: o=120,dc=test,dc=com
o: 120
objectClass: organization
objectClass: top
dn: o=205,dc=test,dc=com
o: 205
objectClass: organization
objectClass: top
dn: o=217,dc=test,dc=com
o: 217
objectClass: organization
objectClass: top
dn: o=222,dc=test,dc=com
o: 222
objectClass: organization
objectClass: top
dn: o=223,dc=test,dc=com
o: 223
objectClass: organization
objectClass: top
dn: o=226,dc=test,dc=com
o: 226
objectClass: organization
objectClass: top
dn: o=227,dc=test,dc=com
o: 227
objectClass: organization
objectClass: top
dn: o=230,dc=test,dc=com
o: 230
objectClass: organization
objectClass: top
dn: o=231,dc=test,dc=com
o: 231
objectClass: organization
objectClass: top
dn: o=232,dc=test,dc=com
o: 232
objectClass: organization
objectClass: top
dn: o=233,dc=test,dc=com
o: 233
objectClass: organization
objectClass: top
dn: o=234,dc=test,dc=com
o: 234
objectClass: organization
objectClass: top
dn: o=235,dc=test,dc=com
o: 235
objectClass: organization
objectClass: top
dn: o=238,dc=test,dc=com
o: 238
objectClass: organization
objectClass: top
dn: o=245,dc=test,dc=com
o: 245
objectClass: organization
objectClass: top
dn: o=246,dc=test,dc=com
o: 246
objectClass: organization
objectClass: top
dn: o=248,dc=test,dc=com
o: 248
objectClass: organization
objectClass: top
dn: o=254,dc=test,dc=com
o: 254
objectClass: organization
objectClass: top
dn: o=255,dc=test,dc=com
o: 255
objectClass: organization
objectClass: top
dn: o=256,dc=test,dc=com
o: 256
objectClass: organization
objectClass: top
dn: o=257,dc=test,dc=com
o: 257
objectClass: organization
objectClass: top
dn: o=260,dc=test,dc=com
o: 260
objectClass: organization
objectClass: top
dn: o=263,dc=test,dc=com
o: 263
objectClass: organization
objectClass: top
dn: o=270,dc=test,dc=com
o: 270
objectClass: organization
objectClass: top
dn: o=271,dc=test,dc=com
o: 271
objectClass: organization
objectClass: top
dn: o=272,dc=test,dc=com
o: 272
objectClass: organization
objectClass: top
dn: o=273,dc=test,dc=com
o: 273
objectClass: organization
objectClass: top
dn: o=275,dc=test,dc=com
o: 275
objectClass: organization
objectClass: top
dn: o=276,dc=test,dc=com
o: 276
objectClass: organization
objectClass: top
dn: o=278,dc=test,dc=com
o: 278
objectClass: organization
objectClass: top
dn: o=279,dc=test,dc=com
o: 279
objectClass: organization
objectClass: top
dn: o=280,dc=test,dc=com
o: 280
objectClass: organization
objectClass: top
dn: o=281,dc=test,dc=com
o: 281
objectClass: organization
objectClass: top
dn: o=285,dc=test,dc=com
o: 285
objectClass: organization
objectClass: top
dn: o=287,dc=test,dc=com
o: 287
objectClass: organization
objectClass: top
dn: o=299,dc=test,dc=com
o: 299
objectClass: organization
objectClass: top
dn: o=301,dc=test,dc=com
o: 301
objectClass: organization
objectClass: top
dn: o=302,dc=test,dc=com
o: 302
objectClass: organization
objectClass: top
dn: o=303,dc=test,dc=com
o: 303
objectClass: organization
objectClass: top
dn: o=308,dc=test,dc=com
o: 308
objectClass: organization
objectClass: top
dn: o=314,dc=test,dc=com
o: 314
objectClass: organization
objectClass: top
dn: o=315,dc=test,dc=com
o: 315
objectClass: organization
objectClass: top
dn: o=316,dc=test,dc=com
o: 316
objectClass: organization
objectClass: top
dn: o=317,dc=test,dc=com
o: 317
objectClass: organization
objectClass: top
dn: o=282,dc=test,dc=com
o: 282
objectClass: organization
objectClass: top
dn: o=319,dc=test,dc=com
o: 319
objectClass: organization
objectClass: top
dn: o=320,dc=test,dc=com
o: 320
objectClass: organization
objectClass: top
dn: o=321,dc=test,dc=com
o: 321
objectClass: organization
objectClass: top
dn: o=207,dc=test,dc=com
o: 207
objectClass: organization
objectClass: top
dn: o=322,dc=test,dc=com
o: 322
objectClass: organization
objectClass: top
dn: o=325,dc=test,dc=com
o: 325
objectClass: organization
objectClass: top
dn: o=331,dc=test,dc=com
o: 331
objectClass: organization
objectClass: top
dn: o=333,dc=test,dc=com
o: 333
objectClass: organization
objectClass: top
dn: o=334,dc=test,dc=com
o: 334
objectClass: organization
objectClass: top
dn: o=335,dc=test,dc=com
o: 335
objectClass: organization
objectClass: top
dn: o=337,dc=test,dc=com
o: 337
objectClass: organization
objectClass: top
dn: o=339,dc=test,dc=com
o: 339
objectClass: organization
objectClass: top
dn: o=341,dc=test,dc=com
o: 341
objectClass: organization
objectClass: top
dn: o=342,dc=test,dc=com
o: 342
objectClass: organization
objectClass: top
dn: o=343,dc=test,dc=com
o: 343
objectClass: organization
objectClass: top
dn: o=346,dc=test,dc=com
o: 346
objectClass: organization
objectClass: top
dn: o=351,dc=test,dc=com
o: 351
objectClass: organization
objectClass: top
dn: o=352,dc=test,dc=com
o: 352
objectClass: organization
objectClass: top
dn: o=353,dc=test,dc=com
o: 353
objectClass: organization
objectClass: top
dn: o=356,dc=test,dc=com
o: 356
objectClass: organization
objectClass: top
dn: o=358,dc=test,dc=com
o: 358
objectClass: organization
objectClass: top
dn: o=360,dc=test,dc=com
o: 360
objectClass: organization
objectClass: top
dn: o=366,dc=test,dc=com
o: 366
objectClass: organization
objectClass: top
dn: o=372,dc=test,dc=com
o: 372
objectClass: organization
objectClass: top
dn: o=373,dc=test,dc=com
o: 373
objectClass: organization
objectClass: top
dn: o=374,dc=test,dc=com
o: 374
objectClass: organization
objectClass: top
dn: o=375,dc=test,dc=com
o: 375
objectClass: organization
objectClass: top
dn: o=377,dc=test,dc=com
o: 377
objectClass: organization
objectClass: top
dn: o=379,dc=test,dc=com
o: 379
objectClass: organization
objectClass: top
dn: o=380,dc=test,dc=com
o: 380
objectClass: organization
objectClass: top
dn: o=381,dc=test,dc=com
o: 381
objectClass: organization
objectClass: top
dn: o=383,dc=test,dc=com
o: 383
objectClass: organization
objectClass: top
dn: o=385,dc=test,dc=com
o: 385
objectClass: organization
objectClass: top
dn: o=386,dc=test,dc=com
o: 386
objectClass: organization
objectClass: top
dn: o=389,dc=test,dc=com
o: 389
objectClass: organization
objectClass: top
dn: o=390,dc=test,dc=com
o: 390
objectClass: organization
objectClass: top
dn: o=392,dc=test,dc=com
o: 392
objectClass: organization
objectClass: top
dn: o=396,dc=test,dc=com
o: 396
objectClass: organization
objectClass: top
dn: o=397,dc=test,dc=com
o: 397
objectClass: organization
objectClass: top
dn: o=398,dc=test,dc=com
o: 398
objectClass: organization
objectClass: top
dn: o=399,dc=test,dc=com
o: 399
objectClass: organization
objectClass: top
dn: o=401,dc=test,dc=com
o: 401
objectClass: organization
objectClass: top
dn: o=402,dc=test,dc=com
o: 402
objectClass: organization
objectClass: top
dn: o=388,dc=test,dc=com
o: 388
objectClass: organization
objectClass: top
dn: o=406,dc=test,dc=com
o: 406
objectClass: organization
objectClass: top
dn: o=405,dc=test,dc=com
o: 405
objectClass: organization
objectClass: top
dn: o=408,dc=test,dc=com
o: 408
objectClass: organization
objectClass: top
dn: o=409,dc=test,dc=com
o: 409
objectClass: organization
objectClass: top
dn: o=413,dc=test,dc=com
o: 413
objectClass: organization
objectClass: top
dn: o=414,dc=test,dc=com
o: 414
objectClass: organization
objectClass: top
dn: o=415,dc=test,dc=com
o: 415
objectClass: organization
objectClass: top
dn: o=416,dc=test,dc=com
o: 416
objectClass: organization
objectClass: top
dn: o=418,dc=test,dc=com
o: 418
objectClass: organization
objectClass: top
dn: o=419,dc=test,dc=com
o: 419
objectClass: organization
objectClass: top
dn: o=424,dc=test,dc=com
o: 424
objectClass: organization
objectClass: top
dn: o=425,dc=test,dc=com
o: 425
objectClass: organization
objectClass: top
dn: o=429,dc=test,dc=com
o: 429
objectClass: organization
objectClass: top
dn: o=430,dc=test,dc=com
o: 430
objectClass: organization
objectClass: top
dn: o=433,dc=test,dc=com
o: 433
objectClass: organization
objectClass: top
dn: o=434,dc=test,dc=com
o: 434
objectClass: organization
objectClass: top
dn: o=435,dc=test,dc=com
o: 435
objectClass: organization
objectClass: top
dn: o=437,dc=test,dc=com
o: 437
objectClass: organization
objectClass: top
dn: o=440,dc=test,dc=com
o: 440
objectClass: organization
objectClass: top
dn: o=420,dc=test,dc=com
o: 420
objectClass: organization
objectClass: top
dn: o=445,dc=test,dc=com
o: 445
objectClass: organization
objectClass: top
dn: o=446,dc=test,dc=com
o: 446
objectClass: organization
objectClass: top
dn: o=447,dc=test,dc=com
o: 447
objectClass: organization
objectClass: top
dn: o=448,dc=test,dc=com
o: 448
objectClass: organization
objectClass: top
dn: o=449,dc=test,dc=com
o: 449
objectClass: organization
objectClass: top
dn: o=450,dc=test,dc=com
o: 450
objectClass: organization
objectClass: top
dn: o=452,dc=test,dc=com
o: 452
objectClass: organization
objectClass: top
dn: o=453,dc=test,dc=com
o: 453
objectClass: organization
objectClass: top
dn: o=454,dc=test,dc=com
o: 454
objectClass: organization
objectClass: top
dn: o=458,dc=test,dc=com
o: 458
objectClass: organization
objectClass: top
dn: o=459,dc=test,dc=com
o: 459
objectClass: organization
objectClass: top
dn:ou=1,o=2,dc=test,dc=com
ou: 1
objectClass: organizationalUnit
objectClass: top
dn:ou=4,o=5,dc=test,dc=com
ou: 4
objectClass: organizationalUnit
objectClass: top
dn:ou=5,o=6,dc=test,dc=com
ou: 5
objectClass: organizationalUnit
objectClass: top
dn:ou=6,o=6,dc=test,dc=com
ou: 6
objectClass: organizationalUnit
objectClass: top
dn:ou=7,o=5,dc=test,dc=com
ou: 7
objectClass: organizationalUnit
objectClass: top
dn:ou=9,o=9,dc=test,dc=com
ou: 9
objectClass: organizationalUnit
objectClass: top
dn:ou=10,o=6,dc=test,dc=com
ou: 10
objectClass: organizationalUnit
objectClass: top
dn:ou=11,o=6,dc=test,dc=com
ou: 11
objectClass: organizationalUnit
objectClass: top
dn:ou=12,o=6,dc=test,dc=com
ou: 12
objectClass: organizationalUnit
objectClass: top
dn:ou=13,o=6,dc=test,dc=com
ou: 13
objectClass: organizationalUnit
objectClass: top
dn:ou=14,o=9,dc=test,dc=com
ou: 14
objectClass: organizationalUnit
objectClass: top
dn:ou=15,o=6,dc=test,dc=com
ou: 15
objectClass: organizationalUnit
objectClass: top
dn:ou=16,o=6,dc=test,dc=com
ou: 16
objectClass: organizationalUnit
objectClass: top
dn:ou=17,o=6,dc=test,dc=com
ou: 17
objectClass: organizationalUnit
objectClass: top
dn:ou=20,o=10,dc=test,dc=com
ou: 20
objectClass: organizationalUnit
objectClass: top
dn:ou=27,o=11,dc=test,dc=com
ou: 27
objectClass: organizationalUnit
objectClass: top
dn:ou=28,o=9,dc=test,dc=com
ou: 28
objectClass: organizationalUnit
objectClass: top
dn:ou=29,o=9,dc=test,dc=com
ou: 29
objectClass: organizationalUnit
objectClass: top
dn:ou=30,o=13,dc=test,dc=com
ou: 30
objectClass: organizationalUnit
objectClass: top
dn:ou=31,o=14,dc=test,dc=com
ou: 31
objectClass: organizationalUnit
objectClass: top
dn:ou=32,o=15,dc=test,dc=com
ou: 32
objectClass: organizationalUnit
objectClass: top
dn:ou=33,o=16,dc=test,dc=com
ou: 33
objectClass: organizationalUnit
objectClass: top
dn:ou=34,o=17,dc=test,dc=com
ou: 34
objectClass: organizationalUnit
objectClass: top
dn:ou=35,o=15,dc=test,dc=com
ou: 35
objectClass: organizationalUnit
objectClass: top
dn:ou=36,o=18,dc=test,dc=com
ou: 36
objectClass: organizationalUnit
objectClass: top
dn:ou=37,o=19,dc=test,dc=com
ou: 37
objectClass: organizationalUnit
objectClass: top
dn:ou=38,o=20,dc=test,dc=com
ou: 38
objectClass: organizationalUnit
objectClass: top
dn:ou=39,o=21,dc=test,dc=com
ou: 39
objectClass: organizationalUnit
objectClass: top
dn:ou=40,o=22,dc=test,dc=com
ou: 40
objectClass: organizationalUnit
objectClass: top
dn:ou=41,o=23,dc=test,dc=com
ou: 41
objectClass: organizationalUnit
objectClass: top
dn:ou=42,o=24,dc=test,dc=com
ou: 42
objectClass: organizationalUnit
objectClass: top
dn:ou=43,o=25,dc=test,dc=com
ou: 43
objectClass: organizationalUnit
objectClass: top
dn:ou=44,o=26,dc=test,dc=com
ou: 44
objectClass: organizationalUnit
objectClass: top
dn:ou=45,o=27,dc=test,dc=com
ou: 45
objectClass: organizationalUnit
objectClass: top
dn:ou=46,o=27,dc=test,dc=com
ou: 46
objectClass: organizationalUnit
objectClass: top
dn:ou=47,o=27,dc=test,dc=com
ou: 47
objectClass: organizationalUnit
objectClass: top
dn:ou=48,o=28,dc=test,dc=com
ou: 48
objectClass: organizationalUnit
objectClass: top
dn:ou=49,o=29,dc=test,dc=com
ou: 49
objectClass: organizationalUnit
objectClass: top
dn:ou=50,o=30,dc=test,dc=com
ou: 50
objectClass: organizationalUnit
objectClass: top
dn:ou=51,o=32,dc=test,dc=com
ou: 51
objectClass: organizationalUnit
objectClass: top
dn:ou=52,o=33,dc=test,dc=com
ou: 52
objectClass: organizationalUnit
objectClass: top
dn:ou=53,o=36,dc=test,dc=com
ou: 53
objectClass: organizationalUnit
objectClass: top
dn:ou=54,o=37,dc=test,dc=com
ou: 54
objectClass: organizationalUnit
objectClass: top
dn:ou=55,o=37,dc=test,dc=com
ou: 55
objectClass: organizationalUnit
objectClass: top
dn:ou=56,o=41,dc=test,dc=com
ou: 56
objectClass: organizationalUnit
objectClass: top
dn:ou=57,o=40,dc=test,dc=com
ou: 57
objectClass: organizationalUnit
objectClass: top
dn:ou=58,o=42,dc=test,dc=com
ou: 58
objectClass: organizationalUnit
objectClass: top
dn:ou=61,o=45,dc=test,dc=com
ou: 61
objectClass: organizationalUnit
objectClass: top
dn:ou=62,o=33,dc=test,dc=com
ou: 62
objectClass: organizationalUnit
objectClass: top
dn:ou=63,o=46,dc=test,dc=com
ou: 63
objectClass: organizationalUnit
objectClass: top
dn:ou=64,o=31,dc=test,dc=com
ou: 64
objectClass: organizationalUnit
objectClass: top
dn:ou=65,o=48,dc=test,dc=com
ou: 65
objectClass: organizationalUnit
objectClass: top
dn:ou=67,o=50,dc=test,dc=com
ou: 67
objectClass: organizationalUnit
objectClass: top
dn:ou=68,o=51,dc=test,dc=com
ou: 68
objectClass: organizationalUnit
objectClass: top
dn:ou=69,o=50,dc=test,dc=com
ou: 69
objectClass: organizationalUnit
objectClass: top
dn:ou=71,o=53,dc=test,dc=com
ou: 71
objectClass: organizationalUnit
objectClass: top
dn:ou=72,o=55,dc=test,dc=com
ou: 72
objectClass: organizationalUnit
objectClass: top
dn:ou=75,o=9,dc=test,dc=com
ou: 75
objectClass: organizationalUnit
objectClass: top
dn:ou=76,o=9,dc=test,dc=com
ou: 76
objectClass: organizationalUnit
objectClass: top
dn:ou=80,o=59,dc=test,dc=com
ou: 80
objectClass: organizationalUnit
objectClass: top
dn:ou=82,o=61,dc=test,dc=com
ou: 82
objectClass: organizationalUnit
objectClass: top
dn:ou=83,o=61,dc=test,dc=com
ou: 83
objectClass: organizationalUnit
objectClass: top
dn:ou=84,o=61,dc=test,dc=com
ou: 84
objectClass: organizationalUnit
objectClass: top
dn:ou=85,o=62,dc=test,dc=com
ou: 85
objectClass: organizationalUnit
objectClass: top
dn:ou=86,o=30,dc=test,dc=com
ou: 86
objectClass: organizationalUnit
objectClass: top
dn:ou=88,o=65,dc=test,dc=com
ou: 88
objectClass: organizationalUnit
objectClass: top
dn:ou=89,o=65,dc=test,dc=com
ou: 89
objectClass: organizationalUnit
objectClass: top
dn:ou=90,o=66,dc=test,dc=com
ou: 90
objectClass: organizationalUnit
objectClass: top
dn:ou=91,o=67,dc=test,dc=com
ou: 91
objectClass: organizationalUnit
objectClass: top
dn:ou=92,o=68,dc=test,dc=com
ou: 92
objectClass: organizationalUnit
objectClass: top
dn:ou=93,o=69,dc=test,dc=com
ou: 93
objectClass: organizationalUnit
objectClass: top
dn:ou=94,o=70,dc=test,dc=com
ou: 94
objectClass: organizationalUnit
objectClass: top
dn:ou=95,o=67,dc=test,dc=com
ou: 95
objectClass: organizationalUnit
objectClass: top
dn:ou=96,o=72,dc=test,dc=com
ou: 96
objectClass: organizationalUnit
objectClass: top
dn:ou=97,o=25,dc=test,dc=com
ou: 97
objectClass: organizationalUnit
objectClass: top
dn:ou=101,o=76,dc=test,dc=com
ou: 101
objectClass: organizationalUnit
objectClass: top
dn:ou=102,o=77,dc=test,dc=com
ou: 102
objectClass: organizationalUnit
objectClass: top
dn:ou=103,o=78,dc=test,dc=com
ou: 103
objectClass: organizationalUnit
objectClass: top
dn:ou=105,o=80,dc=test,dc=com
ou: 105
objectClass: organizationalUnit
objectClass: top
dn:ou=106,o=81,dc=test,dc=com
ou: 106
objectClass: organizationalUnit
objectClass: top
dn:ou=107,o=82,dc=test,dc=com
ou: 107
objectClass: organizationalUnit
objectClass: top
dn:ou=109,o=84,dc=test,dc=com
ou: 109
objectClass: organizationalUnit
objectClass: top
dn:ou=110,o=85,dc=test,dc=com
ou: 110
objectClass: organizationalUnit
objectClass: top
dn:ou=111,o=85,dc=test,dc=com
ou: 111
objectClass: organizationalUnit
objectClass: top
dn:ou=112,o=86,dc=test,dc=com
ou: 112
objectClass: organizationalUnit
objectClass: top
dn:ou=113,o=87,dc=test,dc=com
ou: 113
objectClass: organizationalUnit
objectClass: top
dn:ou=114,o=88,dc=test,dc=com
ou: 114
objectClass: organizationalUnit
objectClass: top
dn:ou=115,o=90,dc=test,dc=com
ou: 115
objectClass: organizationalUnit
objectClass: top
dn:ou=116,o=91,dc=test,dc=com
ou: 116
objectClass: organizationalUnit
objectClass: top
dn:ou=117,o=92,dc=test,dc=com
ou: 117
objectClass: organizationalUnit
objectClass: top
dn:ou=118,o=92,dc=test,dc=com
ou: 118
objectClass: organizationalUnit
objectClass: top
dn:ou=119,o=93,dc=test,dc=com
ou: 119
objectClass: organizationalUnit
objectClass: top
dn:ou=120,o=94,dc=test,dc=com
ou: 120
objectClass: organizationalUnit
objectClass: top
dn:ou=121,o=94,dc=test,dc=com
ou: 121
objectClass: organizationalUnit
objectClass: top
dn:ou=122,o=95,dc=test,dc=com
ou: 122
objectClass: organizationalUnit
objectClass: top
dn:ou=123,o=96,dc=test,dc=com
ou: 123
objectClass: organizationalUnit
objectClass: top
dn:ou=124,o=97,dc=test,dc=com
ou: 124
objectClass: organizationalUnit
objectClass: top
dn:ou=126,o=99,dc=test,dc=com
ou: 126
objectClass: organizationalUnit
objectClass: top
dn:ou=127,o=100,dc=test,dc=com
ou: 127
objectClass: organizationalUnit
objectClass: top
dn:ou=128,o=9,dc=test,dc=com
ou: 128
objectClass: organizationalUnit
objectClass: top
dn:ou=129,o=105,dc=test,dc=com
ou: 129
objectClass: organizationalUnit
objectClass: top
dn:ou=130,o=9,dc=test,dc=com
ou: 130
objectClass: organizationalUnit
objectClass: top
dn:ou=131,o=99,dc=test,dc=com
ou: 131
objectClass: organizationalUnit
objectClass: top
dn:ou=134,o=108,dc=test,dc=com
ou: 134
objectClass: organizationalUnit
objectClass: top
dn:ou=137,o=111,dc=test,dc=com
ou: 137
objectClass: organizationalUnit
objectClass: top
dn:ou=145,o=119,dc=test,dc=com
ou: 145
objectClass: organizationalUnit
objectClass: top
dn:ou=148,o=121,dc=test,dc=com
ou: 148
objectClass: organizationalUnit
objectClass: top
dn:ou=152,o=119,dc=test,dc=com
ou: 152
objectClass: organizationalUnit
objectClass: top
dn:ou=153,o=37,dc=test,dc=com
ou: 153
objectClass: organizationalUnit
objectClass: top
dn:ou=155,o=126,dc=test,dc=com
ou: 155
objectClass: organizationalUnit
objectClass: top
dn:ou=158,o=129,dc=test,dc=com
ou: 158
objectClass: organizationalUnit
objectClass: top
dn:ou=159,o=129,dc=test,dc=com
ou: 159
objectClass: organizationalUnit
objectClass: top
dn:ou=161,o=131,dc=test,dc=com
ou: 161
objectClass: organizationalUnit
objectClass: top
dn:ou=163,o=133,dc=test,dc=com
ou: 163
objectClass: organizationalUnit
objectClass: top
dn:ou=167,o=77,dc=test,dc=com
ou: 167
objectClass: organizationalUnit
objectClass: top
dn:ou=169,o=138,dc=test,dc=com
ou: 169
objectClass: organizationalUnit
objectClass: top
dn:ou=172,o=142,dc=test,dc=com
ou: 172
objectClass: organizationalUnit
objectClass: top
dn:ou=173,o=143,dc=test,dc=com
ou: 173
objectClass: organizationalUnit
objectClass: top
dn:ou=175,o=144,dc=test,dc=com
ou: 175
objectClass: organizationalUnit
objectClass: top
dn:ou=179,o=146,dc=test,dc=com
ou: 179
objectClass: organizationalUnit
objectClass: top
dn:ou=183,o=149,dc=test,dc=com
ou: 183
objectClass: organizationalUnit
objectClass: top
dn:ou=186,o=152,dc=test,dc=com
ou: 186
objectClass: organizationalUnit
objectClass: top
dn:ou=189,o=154,dc=test,dc=com
ou: 189
objectClass: organizationalUnit
objectClass: top
dn:ou=190,o=155,dc=test,dc=com
ou: 190
objectClass: organizationalUnit
objectClass: top
dn:ou=193,o=158,dc=test,dc=com
ou: 193
objectClass: organizationalUnit
objectClass: top
dn:ou=196,o=160,dc=test,dc=com
ou: 196
objectClass: organizationalUnit
objectClass: top
dn:ou=197,o=161,dc=test,dc=com
ou: 197
objectClass: organizationalUnit
objectClass: top
dn:ou=202,o=164,dc=test,dc=com
ou: 202
objectClass: organizationalUnit
objectClass: top
dn:ou=203,o=165,dc=test,dc=com
ou: 203
objectClass: organizationalUnit
objectClass: top
dn:ou=204,o=166,dc=test,dc=com
ou: 204
objectClass: organizationalUnit
objectClass: top
dn:ou=205,o=30,dc=test,dc=com
ou: 205
objectClass: organizationalUnit
objectClass: top
dn:ou=206,o=167,dc=test,dc=com
ou: 206
objectClass: organizationalUnit
objectClass: top
dn:ou=207,o=168,dc=test,dc=com
ou: 207
objectClass: organizationalUnit
objectClass: top
dn:ou=208,o=169,dc=test,dc=com
ou: 208
objectClass: organizationalUnit
objectClass: top
dn:ou=209,o=170,dc=test,dc=com
ou: 209
objectClass: organizationalUnit
objectClass: top
dn:ou=210,o=171,dc=test,dc=com
ou: 210
objectClass: organizationalUnit
objectClass: top
dn:ou=211,o=171,dc=test,dc=com
ou: 211
objectClass: organizationalUnit
objectClass: top
dn:ou=212,o=171,dc=test,dc=com
ou: 212
objectClass: organizationalUnit
objectClass: top
dn:ou=213,o=171,dc=test,dc=com
ou: 213
objectClass: organizationalUnit
objectClass: top
dn:ou=216,o=174,dc=test,dc=com
ou: 216
objectClass: organizationalUnit
objectClass: top
dn:ou=217,o=171,dc=test,dc=com
ou: 217
objectClass: organizationalUnit
objectClass: top
dn:ou=218,o=97,dc=test,dc=com
ou: 218
objectClass: organizationalUnit
objectClass: top
dn:ou=219,o=175,dc=test,dc=com
ou: 219
objectClass: organizationalUnit
objectClass: top
dn:ou=220,o=176,dc=test,dc=com
ou: 220
objectClass: organizationalUnit
objectClass: top
dn:ou=221,o=177,dc=test,dc=com
ou: 221
objectClass: organizationalUnit
objectClass: top
dn:ou=223,o=179,dc=test,dc=com
ou: 223
objectClass: organizationalUnit
objectClass: top
dn:ou=225,o=180,dc=test,dc=com
ou: 225
objectClass: organizationalUnit
objectClass: top
dn:ou=226,o=181,dc=test,dc=com
ou: 226
objectClass: organizationalUnit
objectClass: top
dn:ou=227,o=182,dc=test,dc=com
ou: 227
objectClass: organizationalUnit
objectClass: top
dn:ou=228,o=184,dc=test,dc=com
ou: 228
objectClass: organizationalUnit
objectClass: top
dn:ou=229,o=185,dc=test,dc=com
ou: 229
objectClass: organizationalUnit
objectClass: top
dn:ou=230,o=180,dc=test,dc=com
ou: 230
objectClass: organizationalUnit
objectClass: top
dn:ou=235,o=76,dc=test,dc=com
ou: 235
objectClass: organizationalUnit
objectClass: top
dn:ou=236,o=76,dc=test,dc=com
ou: 236
objectClass: organizationalUnit
objectClass: top
dn:ou=238,o=191,dc=test,dc=com
ou: 238
objectClass: organizationalUnit
objectClass: top
dn:ou=241,o=171,dc=test,dc=com
ou: 241
objectClass: organizationalUnit
objectClass: top
dn:ou=242,o=194,dc=test,dc=com
ou: 242
objectClass: organizationalUnit
objectClass: top
dn:ou=243,o=195,dc=test,dc=com
ou: 243
objectClass: organizationalUnit
objectClass: top
dn:ou=244,o=196,dc=test,dc=com
ou: 244
objectClass: organizationalUnit
objectClass: top
dn:ou=245,o=184,dc=test,dc=com
ou: 245
objectClass: organizationalUnit
objectClass: top
dn:ou=246,o=184,dc=test,dc=com
ou: 246
objectClass: organizationalUnit
objectClass: top
dn:ou=247,o=183,dc=test,dc=com
ou: 247
objectClass: organizationalUnit
objectClass: top
dn:ou=254,o=201,dc=test,dc=com
ou: 254
objectClass: organizationalUnit
objectClass: top
dn:ou=256,o=120,dc=test,dc=com
ou: 256
objectClass: organizationalUnit
objectClass: top
dn:ou=259,o=27,dc=test,dc=com
ou: 259
objectClass: organizationalUnit
objectClass: top
dn:ou=260,o=205,dc=test,dc=com
ou: 260
objectClass: organizationalUnit
objectClass: top
dn:ou=277,o=217,dc=test,dc=com
ou: 277
objectClass: organizationalUnit
objectClass: top
dn:ou=283,o=76,dc=test,dc=com
ou: 283
objectClass: organizationalUnit
objectClass: top
dn:ou=287,o=76,dc=test,dc=com
ou: 287
objectClass: organizationalUnit
objectClass: top
dn:ou=290,o=76,dc=test,dc=com
ou: 290
objectClass: organizationalUnit
objectClass: top
dn:ou=291,o=222,dc=test,dc=com
ou: 291
objectClass: organizationalUnit
objectClass: top
dn:ou=292,o=223,dc=test,dc=com
ou: 292
objectClass: organizationalUnit
objectClass: top
dn:ou=295,o=226,dc=test,dc=com
ou: 295
objectClass: organizationalUnit
objectClass: top
dn:ou=296,o=227,dc=test,dc=com
ou: 296
objectClass: organizationalUnit
objectClass: top
dn:ou=299,o=230,dc=test,dc=com
ou: 299
objectClass: organizationalUnit
objectClass: top
dn:ou=300,o=171,dc=test,dc=com
ou: 300
objectClass: organizationalUnit
objectClass: top
dn:ou=302,o=165,dc=test,dc=com
ou: 302
objectClass: organizationalUnit
objectClass: top
dn:ou=303,o=231,dc=test,dc=com
ou: 303
objectClass: organizationalUnit
objectClass: top
dn:ou=304,o=232,dc=test,dc=com
ou: 304
objectClass: organizationalUnit
objectClass: top
dn:ou=305,o=233,dc=test,dc=com
ou: 305
objectClass: organizationalUnit
objectClass: top
dn:ou=306,o=234,dc=test,dc=com
ou: 306
objectClass: organizationalUnit
objectClass: top
dn:ou=307,o=235,dc=test,dc=com
ou: 307
objectClass: organizationalUnit
objectClass: top
dn:ou=310,o=119,dc=test,dc=com
ou: 310
objectClass: organizationalUnit
objectClass: top
dn:ou=312,o=91,dc=test,dc=com
ou: 312
objectClass: organizationalUnit
objectClass: top
dn:ou=313,o=91,dc=test,dc=com
ou: 313
objectClass: organizationalUnit
objectClass: top
dn:ou=314,o=238,dc=test,dc=com
ou: 314
objectClass: organizationalUnit
objectClass: top
dn:ou=325,o=245,dc=test,dc=com
ou: 325
objectClass: organizationalUnit
objectClass: top
dn:ou=326,o=245,dc=test,dc=com
ou: 326
objectClass: organizationalUnit
objectClass: top
dn:ou=328,o=246,dc=test,dc=com
ou: 328
objectClass: organizationalUnit
objectClass: top
dn:ou=332,o=27,dc=test,dc=com
ou: 332
objectClass: organizationalUnit
objectClass: top
dn:ou=333,o=248,dc=test,dc=com
ou: 333
objectClass: organizationalUnit
objectClass: top
dn:ou=334,o=248,dc=test,dc=com
ou: 334
objectClass: organizationalUnit
objectClass: top
dn:ou=337,o=76,dc=test,dc=com
ou: 337
objectClass: organizationalUnit
objectClass: top
dn:ou=343,o=254,dc=test,dc=com
ou: 343
objectClass: organizationalUnit
objectClass: top
dn:ou=346,o=255,dc=test,dc=com
ou: 346
objectClass: organizationalUnit
objectClass: top
dn:ou=347,o=256,dc=test,dc=com
ou: 347
objectClass: organizationalUnit
objectClass: top
dn:ou=348,o=42,dc=test,dc=com
ou: 348
objectClass: organizationalUnit
objectClass: top
dn:ou=349,o=42,dc=test,dc=com
ou: 349
objectClass: organizationalUnit
objectClass: top
dn:ou=350,o=257,dc=test,dc=com
ou: 350
objectClass: organizationalUnit
objectClass: top
dn:ou=353,o=260,dc=test,dc=com
ou: 353
objectClass: organizationalUnit
objectClass: top
dn:ou=357,o=263,dc=test,dc=com
ou: 357
objectClass: organizationalUnit
objectClass: top
dn:ou=362,o=171,dc=test,dc=com
ou: 362
objectClass: organizationalUnit
objectClass: top
dn:ou=365,o=270,dc=test,dc=com
ou: 365
objectClass: organizationalUnit
objectClass: top
dn:ou=366,o=271,dc=test,dc=com
ou: 366
objectClass: organizationalUnit
objectClass: top
dn:ou=367,o=272,dc=test,dc=com
ou: 367
objectClass: organizationalUnit
objectClass: top
dn:ou=368,o=273,dc=test,dc=com
ou: 368
objectClass: organizationalUnit
objectClass: top
dn:ou=370,o=27,dc=test,dc=com
ou: 370
objectClass: organizationalUnit
objectClass: top
dn:ou=372,o=275,dc=test,dc=com
ou: 372
objectClass: organizationalUnit
objectClass: top
dn:ou=373,o=275,dc=test,dc=com
ou: 373
objectClass: organizationalUnit
objectClass: top
dn:ou=374,o=275,dc=test,dc=com
ou: 374
objectClass: organizationalUnit
objectClass: top
dn:ou=375,o=276,dc=test,dc=com
ou: 375
objectClass: organizationalUnit
objectClass: top
dn:ou=377,o=146,dc=test,dc=com
ou: 377
objectClass: organizationalUnit
objectClass: top
dn:ou=378,o=278,dc=test,dc=com
ou: 378
objectClass: organizationalUnit
objectClass: top
dn:ou=379,o=279,dc=test,dc=com
ou: 379
objectClass: organizationalUnit
objectClass: top
dn:ou=380,o=280,dc=test,dc=com
ou: 380
objectClass: organizationalUnit
objectClass: top
dn:ou=381,o=76,dc=test,dc=com
ou: 381
objectClass: organizationalUnit
objectClass: top
dn:ou=382,o=281,dc=test,dc=com
ou: 382
objectClass: organizationalUnit
objectClass: top
dn:ou=385,o=285,dc=test,dc=com
ou: 385
objectClass: organizationalUnit
objectClass: top
dn:ou=387,o=287,dc=test,dc=com
ou: 387
objectClass: organizationalUnit
objectClass: top
dn:ou=388,o=120,dc=test,dc=com
ou: 388
objectClass: organizationalUnit
objectClass: top
dn:ou=389,o=120,dc=test,dc=com
ou: 389
objectClass: organizationalUnit
objectClass: top
dn:ou=390,o=299,dc=test,dc=com
ou: 390
objectClass: organizationalUnit
objectClass: top
dn:ou=395,o=301,dc=test,dc=com
ou: 395
objectClass: organizationalUnit
objectClass: top
dn:ou=396,o=302,dc=test,dc=com
ou: 396
objectClass: organizationalUnit
objectClass: top
dn:ou=397,o=303,dc=test,dc=com
ou: 397
objectClass: organizationalUnit
objectClass: top
dn:ou=403,o=308,dc=test,dc=com
ou: 403
objectClass: organizationalUnit
objectClass: top
dn:ou=407,o=9,dc=test,dc=com
ou: 407
objectClass: organizationalUnit
objectClass: top
dn:ou=408,o=171,dc=test,dc=com
ou: 408
objectClass: organizationalUnit
objectClass: top
dn:ou=414,o=314,dc=test,dc=com
ou: 414
objectClass: organizationalUnit
objectClass: top
dn:ou=415,o=315,dc=test,dc=com
ou: 415
objectClass: organizationalUnit
objectClass: top
dn:ou=417,o=9,dc=test,dc=com
ou: 417
objectClass: organizationalUnit
objectClass: top
dn:ou=418,o=9,dc=test,dc=com
ou: 418
objectClass: organizationalUnit
objectClass: top
dn:ou=419,o=316,dc=test,dc=com
ou: 419
objectClass: organizationalUnit
objectClass: top
dn:ou=420,o=317,dc=test,dc=com
ou: 420
objectClass: organizationalUnit
objectClass: top
dn:ou=422,o=282,dc=test,dc=com
ou: 422
objectClass: organizationalUnit
objectClass: top
dn:ou=423,o=319,dc=test,dc=com
ou: 423
objectClass: organizationalUnit
objectClass: top
dn:ou=424,o=320,dc=test,dc=com
ou: 424
objectClass: organizationalUnit
objectClass: top
dn:ou=425,o=321,dc=test,dc=com
ou: 425
objectClass: organizationalUnit
objectClass: top
dn:ou=426,o=207,dc=test,dc=com
ou: 426
objectClass: organizationalUnit
objectClass: top
dn:ou=427,o=322,dc=test,dc=com
ou: 427
objectClass: organizationalUnit
objectClass: top
dn:ou=430,o=88,dc=test,dc=com
ou: 430
objectClass: organizationalUnit
objectClass: top
dn:ou=434,o=325,dc=test,dc=com
ou: 434
objectClass: organizationalUnit
objectClass: top
dn:ou=435,o=325,dc=test,dc=com
ou: 435
objectClass: organizationalUnit
objectClass: top
dn:ou=436,o=325,dc=test,dc=com
ou: 436
objectClass: organizationalUnit
objectClass: top
dn:ou=437,o=325,dc=test,dc=com
ou: 437
objectClass: organizationalUnit
objectClass: top
dn:ou=438,o=325,dc=test,dc=com
ou: 438
objectClass: organizationalUnit
objectClass: top
dn:ou=439,o=325,dc=test,dc=com
ou: 439
objectClass: organizationalUnit
objectClass: top
dn:ou=441,o=325,dc=test,dc=com
ou: 441
objectClass: organizationalUnit
objectClass: top
dn:ou=442,o=325,dc=test,dc=com
ou: 442
objectClass: organizationalUnit
objectClass: top
dn:ou=443,o=325,dc=test,dc=com
ou: 443
objectClass: organizationalUnit
objectClass: top
dn:ou=444,o=325,dc=test,dc=com
ou: 444
objectClass: organizationalUnit
objectClass: top
dn:ou=445,o=325,dc=test,dc=com
ou: 445
objectClass: organizationalUnit
objectClass: top
dn:ou=448,o=120,dc=test,dc=com
ou: 448
objectClass: organizationalUnit
objectClass: top
dn:ou=450,o=331,dc=test,dc=com
ou: 450
objectClass: organizationalUnit
objectClass: top
dn:ou=452,o=24,dc=test,dc=com
ou: 452
objectClass: organizationalUnit
objectClass: top
dn:ou=453,o=333,dc=test,dc=com
ou: 453
objectClass: organizationalUnit
objectClass: top
dn:ou=454,o=275,dc=test,dc=com
ou: 454
objectClass: organizationalUnit
objectClass: top
dn:ou=455,o=275,dc=test,dc=com
ou: 455
objectClass: organizationalUnit
objectClass: top
dn:ou=456,o=334,dc=test,dc=com
ou: 456
objectClass: organizationalUnit
objectClass: top
dn:ou=457,o=76,dc=test,dc=com
ou: 457
objectClass: organizationalUnit
objectClass: top
dn:ou=458,o=335,dc=test,dc=com
ou: 458
objectClass: organizationalUnit
objectClass: top
dn:ou=459,o=335,dc=test,dc=com
ou: 459
objectClass: organizationalUnit
objectClass: top
dn:ou=460,o=180,dc=test,dc=com
ou: 460
objectClass: organizationalUnit
objectClass: top
dn:ou=461,o=180,dc=test,dc=com
ou: 461
objectClass: organizationalUnit
objectClass: top
dn:ou=464,o=337,dc=test,dc=com
ou: 464
objectClass: organizationalUnit
objectClass: top
dn:ou=467,o=335,dc=test,dc=com
ou: 467
objectClass: organizationalUnit
objectClass: top
dn:ou=468,o=339,dc=test,dc=com
ou: 468
objectClass: organizationalUnit
objectClass: top
dn:ou=471,o=335,dc=test,dc=com
ou: 471
objectClass: organizationalUnit
objectClass: top
dn:ou=472,o=335,dc=test,dc=com
ou: 472
objectClass: organizationalUnit
objectClass: top
dn:ou=473,o=341,dc=test,dc=com
ou: 473
objectClass: organizationalUnit
objectClass: top
dn:ou=475,o=33,dc=test,dc=com
ou: 475
objectClass: organizationalUnit
objectClass: top
dn:ou=476,o=342,dc=test,dc=com
ou: 476
objectClass: organizationalUnit
objectClass: top
dn:ou=477,o=343,dc=test,dc=com
ou: 477
objectClass: organizationalUnit
objectClass: top
dn:ou=480,o=346,dc=test,dc=com
ou: 480
objectClass: organizationalUnit
objectClass: top
dn:ou=482,o=180,dc=test,dc=com
ou: 482
objectClass: organizationalUnit
objectClass: top
dn:ou=483,o=217,dc=test,dc=com
ou: 483
objectClass: organizationalUnit
objectClass: top
dn:ou=484,o=217,dc=test,dc=com
ou: 484
objectClass: organizationalUnit
objectClass: top
dn:ou=485,o=316,dc=test,dc=com
ou: 485
objectClass: organizationalUnit
objectClass: top
dn:ou=486,o=257,dc=test,dc=com
ou: 486
objectClass: organizationalUnit
objectClass: top
dn:ou=487,o=270,dc=test,dc=com
ou: 487
objectClass: organizationalUnit
objectClass: top
dn:ou=488,o=50,dc=test,dc=com
ou: 488
objectClass: organizationalUnit
objectClass: top
dn:ou=491,o=65,dc=test,dc=com
ou: 491
objectClass: organizationalUnit
objectClass: top
dn:ou=496,o=37,dc=test,dc=com
ou: 496
objectClass: organizationalUnit
objectClass: top
dn:ou=497,o=351,dc=test,dc=com
ou: 497
objectClass: organizationalUnit
objectClass: top
dn:ou=498,o=9,dc=test,dc=com
ou: 498
objectClass: organizationalUnit
objectClass: top
dn:ou=499,o=352,dc=test,dc=com
ou: 499
objectClass: organizationalUnit
objectClass: top
dn:ou=500,o=91,dc=test,dc=com
ou: 500
objectClass: organizationalUnit
objectClass: top
dn:ou=501,o=91,dc=test,dc=com
ou: 501
objectClass: organizationalUnit
objectClass: top
dn:ou=502,o=91,dc=test,dc=com
ou: 502
objectClass: organizationalUnit
objectClass: top
dn:ou=503,o=316,dc=test,dc=com
ou: 503
objectClass: organizationalUnit
objectClass: top
dn:ou=504,o=353,dc=test,dc=com
ou: 504
objectClass: organizationalUnit
objectClass: top
dn:ou=505,o=66,dc=test,dc=com
ou: 505
objectClass: organizationalUnit
objectClass: top
dn:ou=507,o=77,dc=test,dc=com
ou: 507
objectClass: organizationalUnit
objectClass: top
dn:ou=509,o=260,dc=test,dc=com
ou: 509
objectClass: organizationalUnit
objectClass: top
dn:ou=510,o=356,dc=test,dc=com
ou: 510
objectClass: organizationalUnit
objectClass: top
dn:ou=511,o=245,dc=test,dc=com
ou: 511
objectClass: organizationalUnit
objectClass: top
dn:ou=513,o=301,dc=test,dc=com
ou: 513
objectClass: organizationalUnit
objectClass: top
dn:ou=515,o=316,dc=test,dc=com
ou: 515
objectClass: organizationalUnit
objectClass: top
dn:ou=516,o=358,dc=test,dc=com
ou: 516
objectClass: organizationalUnit
objectClass: top
dn:ou=519,o=360,dc=test,dc=com
ou: 519
objectClass: organizationalUnit
objectClass: top
dn:ou=527,o=366,dc=test,dc=com
ou: 527
objectClass: organizationalUnit
objectClass: top
dn:ou=528,o=316,dc=test,dc=com
ou: 528
objectClass: organizationalUnit
objectClass: top
dn:ou=535,o=372,dc=test,dc=com
ou: 535
objectClass: organizationalUnit
objectClass: top
dn:ou=536,o=373,dc=test,dc=com
ou: 536
objectClass: organizationalUnit
objectClass: top
dn:ou=537,o=374,dc=test,dc=com
ou: 537
objectClass: organizationalUnit
objectClass: top
dn:ou=539,o=375,dc=test,dc=com
ou: 539
objectClass: organizationalUnit
objectClass: top
dn:ou=540,o=377,dc=test,dc=com
ou: 540
objectClass: organizationalUnit
objectClass: top
dn:ou=542,o=379,dc=test,dc=com
ou: 542
objectClass: organizationalUnit
objectClass: top
dn:ou=543,o=380,dc=test,dc=com
ou: 543
objectClass: organizationalUnit
objectClass: top
dn:ou=544,o=335,dc=test,dc=com
ou: 544
objectClass: organizationalUnit
objectClass: top
dn:ou=545,o=381,dc=test,dc=com
ou: 545
objectClass: organizationalUnit
objectClass: top
dn:ou=548,o=383,dc=test,dc=com
ou: 548
objectClass: organizationalUnit
objectClass: top
dn:ou=550,o=385,dc=test,dc=com
ou: 550
objectClass: organizationalUnit
objectClass: top
dn:ou=551,o=9,dc=test,dc=com
ou: 551
objectClass: organizationalUnit
objectClass: top
dn:ou=552,o=386,dc=test,dc=com
ou: 552
objectClass: organizationalUnit
objectClass: top
dn:ou=554,o=389,dc=test,dc=com
ou: 554
objectClass: organizationalUnit
objectClass: top
dn:ou=555,o=390,dc=test,dc=com
ou: 555
objectClass: organizationalUnit
objectClass: top
dn:ou=556,o=390,dc=test,dc=com
ou: 556
objectClass: organizationalUnit
objectClass: top
dn:ou=557,o=85,dc=test,dc=com
ou: 557
objectClass: organizationalUnit
objectClass: top
dn:ou=560,o=120,dc=test,dc=com
ou: 560
objectClass: organizationalUnit
objectClass: top
dn:ou=561,o=392,dc=test,dc=com
ou: 561
objectClass: organizationalUnit
objectClass: top
dn:ou=564,o=396,dc=test,dc=com
ou: 564
objectClass: organizationalUnit
objectClass: top
dn:ou=565,o=397,dc=test,dc=com
ou: 565
objectClass: organizationalUnit
objectClass: top
dn:ou=566,o=398,dc=test,dc=com
ou: 566
objectClass: organizationalUnit
objectClass: top
dn:ou=567,o=398,dc=test,dc=com
ou: 567
objectClass: organizationalUnit
objectClass: top
dn:ou=568,o=399,dc=test,dc=com
ou: 568
objectClass: organizationalUnit
objectClass: top
dn:ou=570,o=76,dc=test,dc=com
ou: 570
objectClass: organizationalUnit
objectClass: top
dn:ou=571,o=401,dc=test,dc=com
ou: 571
objectClass: organizationalUnit
objectClass: top
dn:ou=572,o=401,dc=test,dc=com
ou: 572
objectClass: organizationalUnit
objectClass: top
dn:ou=573,o=85,dc=test,dc=com
ou: 573
objectClass: organizationalUnit
objectClass: top
dn:ou=575,o=402,dc=test,dc=com
ou: 575
objectClass: organizationalUnit
objectClass: top
dn:ou=577,o=392,dc=test,dc=com
ou: 577
objectClass: organizationalUnit
objectClass: top
dn:ou=578,o=392,dc=test,dc=com
ou: 578
objectClass: organizationalUnit
objectClass: top
dn:ou=580,o=377,dc=test,dc=com
ou: 580
objectClass: organizationalUnit
objectClass: top
dn:ou=582,o=388,dc=test,dc=com
ou: 582
objectClass: organizationalUnit
objectClass: top
dn:ou=583,o=406,dc=test,dc=com
ou: 583
objectClass: organizationalUnit
objectClass: top
dn:ou=585,o=405,dc=test,dc=com
ou: 585
objectClass: organizationalUnit
objectClass: top
dn:ou=586,o=408,dc=test,dc=com
ou: 586
objectClass: organizationalUnit
objectClass: top
dn:ou=587,o=146,dc=test,dc=com
ou: 587
objectClass: organizationalUnit
objectClass: top
dn:ou=588,o=65,dc=test,dc=com
ou: 588
objectClass: organizationalUnit
objectClass: top
dn:ou=589,o=65,dc=test,dc=com
ou: 589
objectClass: organizationalUnit
objectClass: top
dn:ou=590,o=65,dc=test,dc=com
ou: 590
objectClass: organizationalUnit
objectClass: top
dn:ou=591,o=36,dc=test,dc=com
ou: 591
objectClass: organizationalUnit
objectClass: top
dn:ou=592,o=409,dc=test,dc=com
ou: 592
objectClass: organizationalUnit
objectClass: top
dn:ou=594,o=33,dc=test,dc=com
ou: 594
objectClass: organizationalUnit
objectClass: top
dn:ou=600,o=335,dc=test,dc=com
ou: 600
objectClass: organizationalUnit
objectClass: top
dn:ou=601,o=17,dc=test,dc=com
ou: 601
objectClass: organizationalUnit
objectClass: top
dn:ou=603,o=316,dc=test,dc=com
ou: 603
objectClass: organizationalUnit
objectClass: top
dn:ou=604,o=180,dc=test,dc=com
ou: 604
objectClass: organizationalUnit
objectClass: top
dn:ou=605,o=180,dc=test,dc=com
ou: 605
objectClass: organizationalUnit
objectClass: top
dn:ou=606,o=180,dc=test,dc=com
ou: 606
objectClass: organizationalUnit
objectClass: top
dn:ou=607,o=413,dc=test,dc=com
ou: 607
objectClass: organizationalUnit
objectClass: top
dn:ou=608,o=42,dc=test,dc=com
ou: 608
objectClass: organizationalUnit
objectClass: top
dn:ou=609,o=316,dc=test,dc=com
ou: 609
objectClass: organizationalUnit
objectClass: top
dn:ou=610,o=37,dc=test,dc=com
ou: 610
objectClass: organizationalUnit
objectClass: top
dn:ou=611,o=37,dc=test,dc=com
ou: 611
objectClass: organizationalUnit
objectClass: top
dn:ou=612,o=414,dc=test,dc=com
ou: 612
objectClass: organizationalUnit
objectClass: top
dn:ou=613,o=398,dc=test,dc=com
ou: 613
objectClass: organizationalUnit
objectClass: top
dn:ou=614,o=415,dc=test,dc=com
ou: 614
objectClass: organizationalUnit
objectClass: top
dn:ou=615,o=37,dc=test,dc=com
ou: 615
objectClass: organizationalUnit
objectClass: top
dn:ou=616,o=37,dc=test,dc=com
ou: 616
objectClass: organizationalUnit
objectClass: top
dn:ou=617,o=416,dc=test,dc=com
ou: 617
objectClass: organizationalUnit
objectClass: top
dn:ou=618,o=37,dc=test,dc=com
ou: 618
objectClass: organizationalUnit
objectClass: top
dn:ou=619,o=37,dc=test,dc=com
ou: 619
objectClass: organizationalUnit
objectClass: top
dn:ou=623,o=335,dc=test,dc=com
ou: 623
objectClass: organizationalUnit
objectClass: top
dn:ou=624,o=335,dc=test,dc=com
ou: 624
objectClass: organizationalUnit
objectClass: top
dn:ou=625,o=93,dc=test,dc=com
ou: 625
objectClass: organizationalUnit
objectClass: top
dn:ou=626,o=37,dc=test,dc=com
ou: 626
objectClass: organizationalUnit
objectClass: top
dn:ou=627,o=37,dc=test,dc=com
ou: 627
objectClass: organizationalUnit
objectClass: top
dn:ou=628,o=418,dc=test,dc=com
ou: 628
objectClass: organizationalUnit
objectClass: top
dn:ou=629,o=392,dc=test,dc=com
ou: 629
objectClass: organizationalUnit
objectClass: top
dn:ou=630,o=419,dc=test,dc=com
ou: 630
objectClass: organizationalUnit
objectClass: top
dn:ou=631,o=76,dc=test,dc=com
ou: 631
objectClass: organizationalUnit
objectClass: top
dn:ou=634,o=76,dc=test,dc=com
ou: 634
objectClass: organizationalUnit
objectClass: top
dn:ou=636,o=424,dc=test,dc=com
ou: 636
objectClass: organizationalUnit
objectClass: top
dn:ou=637,o=424,dc=test,dc=com
ou: 637
objectClass: organizationalUnit
objectClass: top
dn:ou=638,o=33,dc=test,dc=com
ou: 638
objectClass: organizationalUnit
objectClass: top
dn:ou=643,o=425,dc=test,dc=com
ou: 643
objectClass: organizationalUnit
objectClass: top
dn:ou=644,o=425,dc=test,dc=com
ou: 644
objectClass: organizationalUnit
objectClass: top
dn:ou=652,o=429,dc=test,dc=com
ou: 652
objectClass: organizationalUnit
objectClass: top
dn:ou=654,o=430,dc=test,dc=com
ou: 654
objectClass: organizationalUnit
objectClass: top
dn:ou=655,o=93,dc=test,dc=com
ou: 655
objectClass: organizationalUnit
objectClass: top
dn:ou=656,o=93,dc=test,dc=com
ou: 656
objectClass: organizationalUnit
objectClass: top
dn:ou=657,o=257,dc=test,dc=com
ou: 657
objectClass: organizationalUnit
objectClass: top
dn:ou=658,o=257,dc=test,dc=com
ou: 658
objectClass: organizationalUnit
objectClass: top
dn:ou=659,o=257,dc=test,dc=com
ou: 659
objectClass: organizationalUnit
objectClass: top
dn:ou=662,o=397,dc=test,dc=com
ou: 662
objectClass: organizationalUnit
objectClass: top
dn:ou=663,o=33,dc=test,dc=com
ou: 663
objectClass: organizationalUnit
objectClass: top
dn:ou=664,o=433,dc=test,dc=com
ou: 664
objectClass: organizationalUnit
objectClass: top
dn:ou=665,o=434,dc=test,dc=com
ou: 665
objectClass: organizationalUnit
objectClass: top
dn:ou=667,o=435,dc=test,dc=com
ou: 667
objectClass: organizationalUnit
objectClass: top
dn:ou=668,o=335,dc=test,dc=com
ou: 668
objectClass: organizationalUnit
objectClass: top
dn:ou=669,o=33,dc=test,dc=com
ou: 669
objectClass: organizationalUnit
objectClass: top
dn:ou=670,o=33,dc=test,dc=com
ou: 670
objectClass: organizationalUnit
objectClass: top
dn:ou=674,o=437,dc=test,dc=com
ou: 674
objectClass: organizationalUnit
objectClass: top
dn:ou=677,o=33,dc=test,dc=com
ou: 677
objectClass: organizationalUnit
objectClass: top
dn:ou=678,o=33,dc=test,dc=com
ou: 678
objectClass: organizationalUnit
objectClass: top
dn:ou=679,o=33,dc=test,dc=com
ou: 679
objectClass: organizationalUnit
objectClass: top
dn:ou=680,o=77,dc=test,dc=com
ou: 680
objectClass: organizationalUnit
objectClass: top
dn:ou=681,o=358,dc=test,dc=com
ou: 681
objectClass: organizationalUnit
objectClass: top
dn:ou=684,o=440,dc=test,dc=com
ou: 684
objectClass: organizationalUnit
objectClass: top
dn:ou=690,o=405,dc=test,dc=com
ou: 690
objectClass: organizationalUnit
objectClass: top
dn:ou=691,o=76,dc=test,dc=com
ou: 691
objectClass: organizationalUnit
objectClass: top
dn:ou=697,o=420,dc=test,dc=com
ou: 697
objectClass: organizationalUnit
objectClass: top
dn:ou=698,o=420,dc=test,dc=com
ou: 698
objectClass: organizationalUnit
objectClass: top
dn:ou=699,o=445,dc=test,dc=com
ou: 699
objectClass: organizationalUnit
objectClass: top
dn:ou=700,o=446,dc=test,dc=com
ou: 700
objectClass: organizationalUnit
objectClass: top
dn:ou=701,o=446,dc=test,dc=com
ou: 701
objectClass: organizationalUnit
objectClass: top
dn:ou=702,o=447,dc=test,dc=com
ou: 702
objectClass: organizationalUnit
objectClass: top
dn:ou=703,o=448,dc=test,dc=com
ou: 703
objectClass: organizationalUnit
objectClass: top
dn:ou=704,o=449,dc=test,dc=com
ou: 704
objectClass: organizationalUnit
objectClass: top
dn:ou=705,o=449,dc=test,dc=com
ou: 705
objectClass: organizationalUnit
objectClass: top
dn:ou=706,o=449,dc=test,dc=com
ou: 706
objectClass: organizationalUnit
objectClass: top
dn:ou=709,o=450,dc=test,dc=com
ou: 709
objectClass: organizationalUnit
objectClass: top
dn:ou=710,o=452,dc=test,dc=com
ou: 710
objectClass: organizationalUnit
objectClass: top
dn:ou=711,o=452,dc=test,dc=com
ou: 711
objectClass: organizationalUnit
objectClass: top
dn:ou=712,o=452,dc=test,dc=com
ou: 712
objectClass: organizationalUnit
objectClass: top
dn:ou=713,o=452,dc=test,dc=com
ou: 713
objectClass: organizationalUnit
objectClass: top
dn:ou=714,o=453,dc=test,dc=com
ou: 714
objectClass: organizationalUnit
objectClass: top
dn:ou=717,o=454,dc=test,dc=com
ou: 717
objectClass: organizationalUnit
objectClass: top
dn:ou=718,o=454,dc=test,dc=com
ou: 718
objectClass: organizationalUnit
objectClass: top
dn:ou=719,o=452,dc=test,dc=com
ou: 719
objectClass: organizationalUnit
objectClass: top
dn:ou=725,o=458,dc=test,dc=com
ou: 725
objectClass: organizationalUnit
objectClass: top
dn:ou=726,o=458,dc=test,dc=com
ou: 726
objectClass: organizationalUnit
objectClass: top
dn:ou=727,o=459,dc=test,dc=com
ou: 727
objectClass: organizationalUnit
objectClass: top
dn:ou=728,o=459,dc=test,dc=com
ou: 728
objectClass: organizationalUnit
objectClass: top
# 0
dn: uid=4ddcae52-f65f-501f-9f8b-f3d79e4d0bba,ou=28,o=9,dc=test,dc=com
cn: Andy K
sn: NA
exampleIdentifier: 6387424151464334
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
objectClass: examplePerson
o: 9
ou: 28
uid: 4ddcae52-f65f-501f-9f8b-f3d79e4d0bba
# 1
dn: uid=892fd1bf-4338-5c67-9096-56736fd395f1,ou=417,o=9,dc=test,dc=com
cn: Mo Fl
sn: NA
exampleIdentifier: 4944391708466170
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
objectClass: examplePerson
o: 9
ou: 417
uid: 892fd1bf-4338-5c67-9096-56736fd395f1
# 2
dn: uid=d4596112-e5ea-5bdb-9844-db864fe8a928,ou=372,o=275,dc=test,dc=com
cn: DI N
sn: NA
exampleIdentifier: 2528010044631957
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
objectClass: examplePerson
o: 275
ou: 372
uid: d4596112-e5ea-5bdb-9844-db864fe8a928
# 3
dn: uid=725873b2-ed1f-5ca7-ae51-57fc8500386a,ou=219,o=175,dc=test,dc=com
cn: HE R
sn: NA
exampleIdentifier: 8805679313756611
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
objectClass: examplePerson
o: 175
ou: 219
uid: 725873b2-ed1f-5ca7-ae51-57fc8500386a
# 4
dn: uid=80e04e16-613f-5c5a-9b87-2eb534a42391,ou=225,o=180,dc=test,dc=com
cn: MU I
sn: NA
exampleIdentifier: 3613132687772569
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
objectClass: examplePerson
o: 180
ou: 225
uid: 80e04e16-613f-5c5a-9b87-2eb534a42391
# 5
dn: uid=d6b23d01-f158-5120-8134-3ce3bd7db9a3,ou=97,o=25,dc=test,dc=com
cn: SE M
sn: NA
exampleIdentifier: 3261848230337957
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
objectClass: examplePerson
o: 25
ou: 97
uid: d6b23d01-f158-5120-8134-3ce3bd7db9a3
# 6
dn: uid=4d63576b-63b5-54f5-b96d-a611a3165ce7,ou=97,o=25,dc=test,dc=com
cn: HA
sn: NA
exampleIdentifier: 2197009364317645
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
objectClass: examplePerson
o: 77
ou: 783
uid: 4d63576b-63b5-54f5-b96d-a611a3165ce7
# 7
dn: uid=8c06c8bf-c797-5b7a-b06c-d3410c5ff758,ou=548,o=383,dc=test,dc=com
cn: RI
sn: NA
exampleIdentifier: 9595441818794545
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
objectClass: examplePerson
o: 383
ou: 548
uid: 8c06c8bf-c797-5b7a-b06c-d3410c5ff758
opendj-server-msad-plugin/pom.xml
@@ -5,7 +5,7 @@
    <parent>
        <groupId>org.openidentityplatform.opendj</groupId>
        <artifactId>opendj-parent</artifactId>
        <version>4.8.3-SNAPSHOT</version>
        <version>4.9.5-SNAPSHOT</version>
    </parent>
    <artifactId>opendj-server-msad-plugin</artifactId>
opendj-server/pom.xml
@@ -19,7 +19,7 @@
  <parent>
    <groupId>org.openidentityplatform.opendj</groupId>
    <artifactId>opendj-parent</artifactId>
    <version>4.8.3-SNAPSHOT</version>
    <version>4.9.5-SNAPSHOT</version>
  </parent>
  <artifactId>opendj-server</artifactId>
  <name>OpenDJ Server NG</name>
pom.xml
@@ -19,7 +19,7 @@
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.openidentityplatform.opendj</groupId>
    <artifactId>opendj-parent</artifactId>
    <version>4.8.3-SNAPSHOT</version>
    <version>4.9.5-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>OpenDJ Directory Services Project</name>
@@ -35,12 +35,12 @@
        <product.locales>ca_ES,es,de,fr,ja,ko,pl,zh_CN,zh_TW</product.locales>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <localized.jars.classifier>i18n</localized.jars.classifier>
        <commons.version>2.2.4-SNAPSHOT</commons.version>
        <commons.version>2.2.4</commons.version>
        <freemarker.version>2.3.31</freemarker.version>
        <grizzly-framework.version>2.3.35</grizzly-framework.version>
        <metrics-core.version>3.1.2</metrics-core.version>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <maven.compiler.source>8</maven.compiler.source>
        <!-- OSGi bundles properties -->
        <opendj.osgi.import.additional />
        <!--
@@ -286,22 +286,6 @@
        <finalName>${project.groupId}.${project.artifactId}</finalName>
        <plugins>
             <plugin>
                <groupId>org.openidentityplatform.maven.plugins</groupId>
                <artifactId>javadoc-updater-maven-plugin</artifactId>
                <version>1.0.0</version>
                <executions>
                    <execution>
                        <phase>site</phase>
                        <goals>
                            <goal>fixjavadoc</goal>
                        </goals>
                        <configuration>
                            <directory>${project.reporting.outputDirectory}</directory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <executions>
@@ -327,6 +311,7 @@
              </executions>
              <configuration>
                <doclint>none</doclint>
                <notimestamp>true</notimestamp>
              </configuration>
            </plugin>
            <plugin>
@@ -368,10 +353,6 @@
                        <fork>true</fork>
                        <compilerArgs>
                            <arg>-XDignore.symbol.file</arg>
                            <arg>--add-exports</arg>
                            <arg>java.base/sun.security.x509=ALL-UNNAMED</arg>
                            <arg>--add-exports</arg>
                            <arg>java.base/sun.security.tools.keytool=ALL-UNNAMED</arg>
                        </compilerArgs>
                    </configuration>
                </plugin>
@@ -479,7 +460,7 @@
                <plugin>
                    <groupId>org.apache.felix</groupId>
                    <artifactId>maven-bundle-plugin</artifactId>
                    <version>5.1.9</version>
                    <version>2.3.7</version>
                    <extensions>true</extensions>
                    <configuration>
                        <instructions>
@@ -721,6 +702,15 @@
            </modules>
        </profile>
        <profile>
            <id>set-compiler-release</id>
            <activation>
                <jdk>[9,)</jdk>
            </activation>
            <properties>
                <maven.compiler.release>8</maven.compiler.release>
            </properties>
        </profile>
        <profile>
          <id>jdk16.options</id>
          <activation>
            <jdk>[16,)</jdk>