From ff93f3bf42f4e2ed6e3cd90bb7983e4754e25bae Mon Sep 17 00:00:00 2001
From: Valera V Harseko <vharseko@3a-systems.ru>
Date: Mon, 22 Jun 2026 10:55:39 +0000
Subject: [PATCH] Refine LDAP benchmark: READD, SSHA-256 hashing, grouped charts

---
 .github/workflows/benchmark.yml |   57 +++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 47 insertions(+), 10 deletions(-)

diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index c8b7838..5dff071 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -78,7 +78,7 @@
       - uses: actions/checkout@v6
 
       - name: Cache JMeter
-        uses: actions/cache@v4
+        uses: actions/cache@v5
         with:
           path: ~/jmeter
           key: jmeter-${{ env.JMETER }}
@@ -103,15 +103,32 @@
             -e LDAP_TLS=false \
             "$OPENLDAP_IMAGE"
 
-      - name: Wait for OpenLDAP + seed ou=People
+      - name: Configure OpenLDAP (SSHA-256 hash-on-write, seed)
         run: |
-          for i in $(seq 1 90); do
-            if ldapsearch -x -H ldap://localhost:2389 -D "cn=admin,$BASEDN" -w password \
-                 -b "$BASEDN" -s base dn >/dev/null 2>&1; then
-              echo "OpenLDAP is up"; break
-            fi
-            sleep 2
-          done
+          wait_ldap() {
+            for i in $(seq 1 90); do
+              ldapsearch -x -H ldap://localhost:2389 -D "cn=admin,$BASEDN" -w password \
+                -b "$BASEDN" -s base dn >/dev/null 2>&1 && { echo "OpenLDAP is up"; return 0; }
+              sleep 2
+            done
+          }
+          le() { docker exec -i openldap "$@" -Y EXTERNAL -H ldapi:/// >/dev/null 2>&1 || true; }
+          wait_ldap
+          # Load pw-sha2 (provides {SSHA256}) and ppolicy (overlay) modules; osixia ships both
+          # in /usr/lib/ldap. Create the module list entry or append the values, then restart so
+          # the modules are active in the running slapd.
+          printf 'dn: cn=module{0},cn=config\nobjectClass: olcModuleList\nolcModuleLoad: pw-sha2\nolcModuleLoad: ppolicy\n' | le ldapadd
+          printf 'dn: cn=module{0},cn=config\nchangetype: modify\nadd: olcModuleLoad\nolcModuleLoad: pw-sha2\n' | le ldapmodify
+          printf 'dn: cn=module{0},cn=config\nchangetype: modify\nadd: olcModuleLoad\nolcModuleLoad: ppolicy\n' | le ldapmodify
+          docker restart openldap
+          wait_ldap
+          # Make slapd hash cleartext userPassword with {SSHA256} on a plain modify: set the global
+          # password-hash and enable the ppolicy overlay's hash_cleartext on the mdb database.
+          printf 'dn: olcDatabase={-1}frontend,cn=config\nchangetype: modify\nreplace: olcPasswordHash\nolcPasswordHash: {SSHA256}\n' | le ldapmodify
+          DBDN="$(docker exec openldap ldapsearch -Y EXTERNAL -H ldapi:/// -LLL -b cn=config '(olcDatabase=*mdb)' dn 2>/dev/null | sed -n 's/^dn: //p' | head -1)"
+          [ -n "$DBDN" ] || DBDN="olcDatabase={1}mdb,cn=config"
+          printf 'dn: olcOverlay=ppolicy,%s\nobjectClass: olcOverlayConfig\nobjectClass: olcPPolicyConfig\nolcOverlay: ppolicy\nolcPPolicyHashCleartext: TRUE\n' "$DBDN" | le ldapadd
+          # Seed ou=People (after the restart so it survives any re-init).
           ldapadd -x -H ldap://localhost:2389 -D "cn=admin,$BASEDN" -w password \
             -f .github/benchmark/people.ldif || true
 
@@ -141,6 +158,11 @@
             -Jjmeter.reportgenerator.sample_filter="$SAMPLE_FILTER" \
             -l openldap.jtl -e -o openldap
 
+      - name: Stop OpenLDAP
+        run: |
+          docker logs openldap 2>&1 | tail -n 100 || true
+          docker rm -f openldap || true
+
       - name: Start OpenDJ
         run: |
           docker run -d --name opendj -p 1389:1389 \
@@ -161,6 +183,16 @@
           ldapadd -x -H ldap://localhost:1389 -D "cn=Directory Manager" -w password \
             -f .github/benchmark/people.ldif || true
 
+      - name: Configure OpenDJ password policy (SSHA-256 hash-on-write)
+        run: |
+          # Hash cleartext userPassword with Salted SHA-256 on write, matching OpenLDAP.
+          docker exec opendj /opt/opendj/bin/dsconfig set-password-policy-prop \
+            --policy-name "Default Password Policy" \
+            --set default-password-storage-scheme:"Salted SHA-256" \
+            --hostname localhost --port 4444 \
+            --bindDN "cn=Directory Manager" --bindPassword password \
+            --trustAll --no-prompt
+
       - name: Capture OpenDJ version
         run: |
           # `|| true` guards the bind so a transient ldapsearch failure can't trip pipefail;
@@ -187,6 +219,11 @@
             -Jjmeter.reportgenerator.sample_filter="$SAMPLE_FILTER" \
             -l opendj.jtl -e -o opendj
 
+      - name: Stop OpenDJ
+        run: |
+          docker logs opendj 2>&1 | tail -n 100 || true
+          docker rm -f opendj || true
+
       # ---------------------------------------------------------------- Report
       - name: Build job summary
         run: |
@@ -197,7 +234,7 @@
 
       - name: Upload JMeter reports
         if: always()
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v7
         with:
           name: jmeter-reports
           path: |

--
Gitblit v1.10.0