How Doom Handles Self-Signed Certificates During LDAPS Connections

Doom disables certificate validation entirely by configuring an ldap3.Tls object with validate=ssl.CERT_NONE and relaxed cipher policies, then applies this custom TLS context to LDAPS connections on port 636.

When connecting to enterprise Active Directory environments, Doom must often handle LDAPS connections where servers present self-signed certificates or certificates from internal certificate authorities. According to the 000pp/doom source code, the application implements a deliberate trust-any-certificate strategy to ensure connectivity in these scenarios.

Understanding the LDAPS Connection Flow in Doom

Doom establishes directory service connections using the ldap3 library. The connection logic prioritizes security through LDAPS (LDAP over TLS) on port 636, but implements fallback mechanisms for environments where TLS connections fail. The critical component for handling untrusted certificates resides in the custom TLS configuration object that overrides Python's default SSL verification behavior.

Disabling Certificate Validation in src/doom/protocols/ldap.py

The core implementation resides in src/doom/protocols/ldap.py, specifically within the TLS object instantiation on lines 15-18. Here, Doom explicitly constructs a TLS context that bypasses certificate chain verification.

Configuring the TLS Object (Lines 15-18)

import ssl
import ldap3

tls = ldap3.Tls(
    validate=ssl.CERT_NONE,
    version=ssl.PROTOCOL_TLSv1_2,
    ciphers="ALL:@SECLEVEL=0",
)

This configuration performs three critical functions:

  • validate=ssl.CERT_NONE — Instructs the underlying OpenSSL implementation to ignore certificate validation errors, allowing connections to proceed regardless of whether the certificate is self-signed, expired, or issued by an unknown CA.

  • version=ssl.PROTOCOL_TLSv1_2 — Enforces TLS 1.2 as the minimum protocol version, balancing compatibility with security requirements.

  • ciphers="ALL:@SECLEVEL=0" — Relaxes OpenSSL's security level to zero, permitting legacy cipher suites that older Active Directory deployments might require.

Applying Custom TLS Settings to the LDAPS Server

After creating the permissive TLS object, Doom applies it to the server definition on lines 19-21 of the same file.

Server Definition (Lines 19-21)

ldaps_server = ldap3.Server(
    f"ldaps://{host}",
    port=636,
    use_ssl=True,
    get_info=ldap3.ALL,
    tls=tls,
)

The tls=tls parameter injects the custom SSL context into the connection establishment process. When use_ssl=True and port 636 are specified, ldap3 uses this context to wrap the TCP connection in TLS.

If the LDAPS bind operation fails due to authentication errors rather than TLS handshake issues, Doom implements a fallback mechanism that attempts a plain LDAP connection on port 389. However, the self-signed certificate handling applies exclusively to the LDAPS code path described above.

Complete Implementation Example

The following snippet demonstrates the complete connection flow as implemented in Doom, showing how the TLS configuration integrates with NTLM authentication:

import ssl
import ldap3

def create_ldaps_connection(host: str, user: str, password: str):
    # Configure TLS to accept self-signed certificates

    tls = ldap3.Tls(
        validate=ssl.CERT_NONE,
        version=ssl.PROTOCOL_TLSv1_2,
        ciphers="ALL:@SECLEVEL=0",
    )
    
    # Define LDAPS server with custom TLS context

    server = ldap3.Server(
        f"ldaps://{host}",
        port=636,
        use_ssl=True,
        get_info=ldap3.ALL,
        tls=tls,
    )
    
    # Establish connection with NTLM authentication

    conn = ldap3.Connection(
        server,
        user=user,
        password=password,
        authentication=ldap3.NTLM,
        auto_bind=True,
        auto_referrals=False,
        raise_exceptions=True,
    )
    return conn

Security Considerations

Doom's approach intentionally prioritizes connectivity over certificate validation, which aligns with common enterprise Active Directory deployment patterns where internal CAs or self-signed certificates are standard. The implementation in src/doom/protocols/ldap.py acknowledges that certificate provisioning in these environments is often managed internally rather than through public PKI infrastructure.

However, this configuration disables protection against man-in-the-middle attacks. The code mitigates this risk partially by enforcing TLS 1.2 and requiring encrypted connections rather than falling back to unencrypted LDAP when LDAPS is available.

Summary

  • Doom handles self-signed certificates by creating a custom ldap3.Tls object with validate=ssl.CERT_NONE in src/doom/protocols/ldap.py (lines 15-18).
  • The TLS configuration relaxes cipher requirements with "ALL:@SECLEVEL=0" to support legacy Active Directory servers while maintaining TLS 1.2 protocol enforcement.
  • This custom TLS context is applied to LDAPS connections on port 636, allowing authentication to proceed regardless of certificate trust status.
  • If LDAPS authentication fails, Doom implements a fallback to plain LDAP on port 389, though this bypasses the certificate handling logic entirely.

Frequently Asked Questions

Does Doom verify the certificate chain when connecting to LDAPS servers?

No, Doom explicitly disables certificate chain verification by setting validate=ssl.CERT_NONE in the TLS configuration object. This allows connections to succeed even when the LDAP server presents a self-signed certificate or a certificate issued by an internal CA not trusted by the system's default certificate store.

What TLS version does Doom require for LDAPS connections?

Doom enforces TLS 1.2 as the minimum protocol version by specifying version=ssl.PROTOCOL_TLSv1_2 in the ldap3.Tls constructor. This provides a balance between security and compatibility with enterprise Active Directory environments that may not support TLS 1.3.

Where is the LDAPS certificate handling implemented in the Doom codebase?

The certificate handling logic is implemented in src/doom/protocols/ldap.py, specifically between lines 15-21. Lines 15-18 create the custom TLS object with disabled validation, while lines 19-21 apply this TLS context to the LDAPS server definition using the tls parameter.

What happens if the LDAPS connection fails in Doom?

If the LDAPS bind operation fails due to authentication errors, Doom falls back to attempting a plain LDAP connection on port 389. However, this fallback only occurs for authentication failures, not TLS handshake errors. The self-signed certificate handling specifically applies only to the LDAPS code path on port 636.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →