opf/openproject · error · LdapAuthSource::Error

LDAP-Error: %{error_message}

Error message

LDAP-Error: %{error_message}

What it means

This variant of the LDAP test error comes from the rescue Net::LDAP::Error branch in LdapAuthSource#test_connection: the raised LdapAuthSource::Error interpolates the underlying exception into ldap_error ('%{error_message}'). Unlike the auth-failed variant, the failure happened while establishing the connection or during TLS — before any bind credential mattered.

Source

Thrown at app/models/ldap_auth_source.rb:188

    attrs
  rescue Net::LDAP::Error => e
    raise LdapAuthSource::Error, "LdapError: #{e.message}"
  end

  # Open and return a system connection
  def with_connection
    yield initialize_ldap_con(account, account_password)
  end

  # test the connection to the LDAP
  def test_connection
    unless authenticate_dn(account, account_password)
      raise LdapAuthSource::Error,
            I18n.t("ldap_auth_sources.ldap_error", error_message: I18n.t("ldap_auth_sources.ldap_auth_failed"))
    end
  rescue Net::LDAP::Error => e
    raise LdapAuthSource::Error,
          I18n.t("ldap_auth_sources.ldap_error", error_message: e.to_s)
  end

  def get_user_attributes_from_ldap_entry(entry)
    base_attributes = {
      dn: entry.dn,
      ldap_auth_source_id: id
    }

    base_attributes.merge mapped_attributes(entry)
  end

  def mapped_attributes(entry)
    %i[login firstname lastname mail admin].each_with_object({}) do |key, hash|
      ldap_attribute = send(:"attr_#{key}")
      next if ldap_attribute.blank?

      val = LdapAuthSource.get_attr(entry, ldap_attribute)

View on GitHub (pinned to d9742c43f3)

Solutions

  1. Read the interpolated error message — Net::LDAP names the concrete cause (connection refused, timeout, certificate verify failed).
  2. Fix connectivity: verify host/port with nc -zv host 636 and confirm the LDAPS toggle matches the port.
  3. For TLS/certificate errors, trust the LDAP server's CA on the application host (or point net-ldap at the CA bundle), then retest.

Example fix

# before
LdapAuthSource.new(host: 'ldap.example.com', port: 636, ldaps: false)

# after
LdapAuthSource.new(host: 'ldap.example.com', port: 636, ldaps: true)
Defensive patterns

Strategy: try-catch

Validate before calling

require 'resolv'
Resolv::DNS.open { |dns| dns.getaddress(host) } # fail fast on DNS
require 'socket'
Socket.tcp(host, port, connect_timeout: 5)     # fail fast on reachability

Try / catch

begin
  ldap_auth_source.test_connection
rescue LdapAuthSource::Error => e
  retry_once_after_network_change if e.message =~ /connection refused|timeout|certificate/
  raise
end

Prevention

When it happens

Trigger: Testing an LDAP source with an unreachable host, DNS failure, wrong port (e.g. 636 without LDAPS enabled, or 389 against a TLS-only server), firewall drop, or a failing certificate handshake (untrusted/self-signed CA).

Common situations: Host/port typos in the auth source; LDAPS/StartTLS mismatch; self-signed certificates without a trusted CA on the OpenProject host; firewall or VPN blocking the app server but not an admin's laptop.

Related errors


AI-assisted analysis of opf/openproject@d9742c43f3 (2026-08-21). Data as JSON: /api/errors/dcc2db38a4cde918. Report an issue: GitHub.