From f90d319eeb008c9ee0f4fa81bb7448a828da35dd Mon Sep 17 00:00:00 2001 From: William Mantly Date: Mon, 27 Jul 2026 20:10:58 -0400 Subject: [PATCH] Fix jump-host SSH login: point it at ldaps://, not ldap:// MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jump-secrets.js's ldap.url was 'ldap://sso-manager:389' with tlsOptions set. ldapts treats a non-empty tlsOptions as "use implicit TLS" regardless of URL scheme, so every LDAP connection from jump-host opened a raw TLS handshake against sso-manager's plaintext-LDAP port — slapd dropped the connection before any LDAP message parsed (visible in slapd.log as "connection lost" right after ACCEPT, no BIND ever logged). Every SSH login failed with a generic "Permission denied" for any account, any password — indistinguishable from a wrong credential. Root-caused by building a local theta-env stack, restarting jump-host with edited config, and calling userLdap.getUser/checkPassword directly inside the container: got "Client network socket disconnected before secure TLS connection was established" instead of a vague auth failure. Switching to ldaps://sso-manager:636 (already exposed by the same container, already what tlsOptions was meant for) fixes it — verified getUser/checkPassword succeed and a real SSH login authenticates. Companion defensive fix: simpleworkjs/ldap#1 (rejects this exact ldap://+tlsOptions combination going forward, for proxy/sso too). Existing deployments must edit their own ./config/jump-secrets.js (this template only affects fresh bootstraps) — see the PR description. Co-Authored-By: Claude Sonnet 5 --- bootstrap/bootstrap.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bootstrap/bootstrap.js b/bootstrap/bootstrap.js index ebdfe77..b5ef51b 100644 --- a/bootstrap/bootstrap.js +++ b/bootstrap/bootstrap.js @@ -527,7 +527,16 @@ function writeJumpSecrets(apiToken, oidc, localAdminPass) { module.exports = { \tname: ${JSON.stringify(sso.name || 'SSO Manager')}, \tldap: { -\t\turl: 'ldap://sso-manager:389', +\t\t// ldaps:// (636), not ldap:// (389): @simpleworkjs/ldap's client always +\t\t// sets tlsOptions (see jump-host's models/user_ldap.js), and ldapts +\t\t// treats a non-empty tlsOptions as "use implicit TLS" regardless of the +\t\t// URL scheme -- pointed at the plain port, that means it opens a raw TLS +\t\t// handshake against a server expecting plaintext LDAP, which slapd just +\t\t// drops (logged as "connection lost", no BIND ever attempted). This bit +\t\t// jump-host silently: every SSH login failed with the generic +\t\t// "Permission denied" for any password, because getUser()/checkPassword() +\t\t// never even reached slapd. +\t\turl: 'ldaps://sso-manager:636', \t\tbindDN: ${JSON.stringify(BIND_DN)}, \t\tbindPassword: ${JSON.stringify(ADMIN_PASS)}, \t\tuserBase: ${JSON.stringify(`ou=people,${BASE_DN}`)},