Skip to content

Fix LDAP TLS client certificate options must be set before ldap_connect() for Google Secure LDAP#945

Open
mikelog wants to merge 1 commit into
Combodo:developfrom
mikelog:fix/ldap-tls-options-before-connect
Open

Fix LDAP TLS client certificate options must be set before ldap_connect() for Google Secure LDAP#945
mikelog wants to merge 1 commit into
Combodo:developfrom
mikelog:fix/ldap-tls-options-before-connect

Conversation

@mikelog

@mikelog mikelog commented Jun 23, 2026

Copy link
Copy Markdown

Base information

Question Answer
Related to a SourceForge thread / Another PR / A GitHub Issue / Combodo ticket? N/A
Type of change? Bug fix

Symptom (bug)

When using Google Secure LDAP (ldaps://ldap.google.com:636) with client
certificates, the first authentication attempt on each new PHP-FPM worker
always fails with:

ldap_authentication: can not bind to the LDAP server 'ldaps://ldap.google.com'
(port: 636). Error: 'Can't contact LDAP server'

Subsequent attempts from the same worker succeed. Users need 2-5 login attempts
before being granted access.

Reproduction procedure (bug)

  1. Configure iTop with Google Workspace Secure LDAP (ldaps://ldap.google.com:636)
  2. Set LDAP_OPT_X_TLS_CACERTFILE, LDAP_OPT_X_TLS_CERTFILE,
    LDAP_OPT_X_TLS_KEYFILE in the options array in config-itop.php
  3. Use nginx + PHP-FPM with pm = ondemand or pm = dynamic
  4. Restart PHP-FPM to get a fresh worker
  5. Attempt to log in — first attempt fails, second succeeds

Cause (bug)

In CheckCredentials(), TLS options (LDAP_OPT_X_TLS_CACERTFILE,
LDAP_OPT_X_TLS_CERTFILE, LDAP_OPT_X_TLS_KEYFILE) are set via
ldap_set_option($hDS, ...) after ldap_connect().

However, OpenLDAP requires these options to be set globally via
ldap_set_option(null, ...) before ldap_connect() so that the TLS
context includes the client certificate during the SSL handshake.

Current broken order:

  1. ldap_connect() ← TLS handshake starts here, no client cert loaded yet
  2. foreach $aOptions with ldap_set_option($hDS, ...) ← too late for TLS
  3. ldap_bind() ← fails on first worker attempt

Proposed solution (bug)

Set TLS options globally via ldap_set_option(null, ...) before ldap_connect(),
then reinitialize the TLS context with LDAP_OPT_X_TLS_NEWCTX:

// Set TLS options globally BEFORE ldap_connect() (required for ldaps:// with client certificates)
foreach ($aOptions as $name => $value) {
    ldap_set_option(null, $name, $value);
}
// Reinitialize TLS context so new options take effect
ldap_set_option(null, LDAP_OPT_X_TLS_NEWCTX, 0);

$hDS = @ldap_connect($sLDAPHost, $iLDAPPort);

Checklist before requesting a review

  • I have performed a self-review of my code
  • I have tested all changes on an iTop instance
  • I have added a unit test, otherwise I have explained why I couldn't
    • Manual testing confirmed fix: 100% login success rate after change vs
      ~20-50% before (first attempt always failed on fresh workers)
  • Is the PR clear and detailed enough so anyone can understand without
    digging in the code?

Environment tested

  • iTop: 2.7.3 (same code present in 3.2.3)
  • LDAP server: Google Workspace Secure LDAP (ldap.google.com:636)
  • PHP: 7.4.33, nginx + PHP-FPM (pm = ondemand)
  • OpenSSL: 3.0.13, Ubuntu

Additional notes

Please consider backporting to support/3.2 as this affects the current stable release (3.2.3).
Confirmed and tested on iTop 2.7.3 with the same code path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant