{"id":2242,"library":"python-ldap","title":"python-ldap","description":"python-ldap provides a low-level API for implementing LDAP clients, wrapping the OpenLDAP C library. It supports LDAPv3 and offers comprehensive features for interacting with LDAP directories. The current version is 3.4.5, with minor releases for bug fixes and security updates, and major versions typically bringing Python version compatibility and API changes.","status":"active","version":"3.4.5","language":"en","source_language":"en","source_url":"https://github.com/python-ldap/python-ldap","tags":["ldap","authentication","directory_service","networking","openldap"],"install":[{"cmd":"pip install python-ldap","lang":"bash","label":"Install latest version"},{"cmd":"sudo apt-get install libldap2-dev libsasl2-dev # Debian/Ubuntu\nsudo dnf install openldap-devel cyrus-sasl-devel # Fedora\nbrew install openldap # macOS\npip install python-ldap","lang":"bash","label":"Install with system dependencies (recommended)"}],"dependencies":[{"reason":"Required for ASN.1 encoding/decoding, introduced in 3.0.0.","package":"pyasn1"},{"reason":"Required for ASN.1 encoding/decoding, introduced in 3.0.0.","package":"pyasn1_modules"}],"imports":[{"symbol":"ldap","correct":"import ldap"},{"note":"modlist is commonly used for creating/comparing LDAP modification lists.","wrong":"import ldap.modlist # Access via ldap.modlist is okay, but from ldap import modlist is more direct for common use.","symbol":"modlist","correct":"from ldap import modlist"},{"note":"Used for DN manipulation and escaping.","symbol":"ldap.dn","correct":"import ldap.dn"},{"note":"Used for filter manipulation and escaping.","symbol":"ldap.filter","correct":"import ldap.filter"}],"quickstart":{"code":"import ldap\nimport os\n\n# Configure LDAP server details\nLDAP_SERVER_URI = os.environ.get('LDAP_SERVER_URI', 'ldap://localhost:389')\nLDAP_BIND_DN = os.environ.get('LDAP_BIND_DN', 'cn=admin,dc=example,dc=org')\nLDAP_BIND_PASSWORD = os.environ.get('LDAP_BIND_PASSWORD', 'adminpassword')\nLDAP_SEARCH_BASE = os.environ.get('LDAP_SEARCH_BASE', 'dc=example,dc=org')\nLDAP_SEARCH_FILTER = os.environ.get('LDAP_SEARCH_FILTER', '(objectClass=person)')\nLDAP_SEARCH_ATTRIBUTES = ['cn', 'mail']\n\ntry:\n    # Initialize LDAP connection\n    l = ldap.initialize(LDAP_SERVER_URI)\n    l.set_option(ldap.OPT_REFERRALS, 0)\n    l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)\n\n    # Bind to the directory\n    l.simple_bind_s(LDAP_BIND_DN.encode('utf-8'), LDAP_BIND_PASSWORD.encode('utf-8'))\n    print(f\"Successfully bound to {LDAP_SERVER_URI}\")\n\n    # Search the directory\n    result_id = l.search(\n        LDAP_SEARCH_BASE.encode('utf-8'),\n        ldap.SCOPE_SUBTREE,\n        LDAP_SEARCH_FILTER.encode('utf-8'),\n        LDAP_SEARCH_ATTRIBUTES\n    )\n\n    results = []\n    while True:\n        result_type, result_data = l.result(result_id, 0)\n        if not result_data:\n            break\n        if result_type == ldap.RES_SEARCH_ENTRY:\n            for dn, entry in result_data:\n                results.append((dn.decode('utf-8'), {k.decode('utf-8'): [v.decode('utf-8') for v in val] for k, val in entry.items()}))\n    \n    print(f\"Found {len(results)} entries:\")\n    for dn, entry in results:\n        print(f\"DN: {dn}\")\n        print(f\"  CN: {entry.get('cn')}\")\n        print(f\"  Mail: {entry.get('mail')}\")\n\nexcept ldap.SERVER_DOWN as e:\n    print(f\"LDAP server down or connection failed: {e}\")\nexcept ldap.LDAPError as e:\n    print(f\"LDAP Error: {e}\")\nfinally:\n    # Unbind from the directory\n    if 'l' in locals() and l:\n        try:\n            l.unbind_s()\n            print(\"Unbound from LDAP server.\")\n        except ldap.LDAPError as e:\n            print(f\"Error during unbind: {e}\")\n","lang":"python","description":"This quickstart demonstrates how to establish a connection to an LDAP server, perform a simple bind, search for entries, and process the results. It highlights the use of `ldap.initialize`, `simple_bind_s`, and `search` with error handling. Note the explicit encoding of strings to bytes, which is crucial for python-ldap 3.x."},"warnings":[{"fix":"Ensure your project is running on Python 3.6+ (3.4.0+ requires 3.6+). For Python 2 compatibility, you must use python-ldap 2.x, which is no longer maintained.","message":"python-ldap 3.x is Python 3 ONLY. Version 3.0.0 dropped support for Python 2.x entirely. Attempts to use python-ldap 3.x in a Python 2 environment will fail.","severity":"breaking","affected_versions":"3.0.0 and newer"},{"fix":"Explicitly encode Python strings to bytes (e.g., `my_string.encode('utf-8')`) when passing them to python-ldap functions. Decode byte results back to strings (e.g., `my_bytes.decode('utf-8')`) when consuming them.","message":"All string data in python-ldap 3.x is handled as bytes. Inputs for DNs, filters, attribute names/values, and outputs from search operations are bytes. This is a fundamental change from python-ldap 2.x and is a common source of `TypeError` or unexpected behavior.","severity":"breaking","affected_versions":"3.0.0 and newer"},{"fix":"Always use `ldap.initialize()` to create an LDAPObject instance.","message":"The `ldap.open()` and `ldap.init()` functions were deprecated and completely removed in version 3.1.0.","severity":"deprecated","affected_versions":"3.1.0 and newer"},{"fix":"Migrate to `OPT_X_TLS_CACERTFILE`, `OPT_X_TLS_CERTFILE`, `OPT_X_TLS_KEYFILE`, etc., for specific TLS configuration. Consult OpenLDAP documentation for recommended TLS options.","message":"The `OPT_X_TLS` option was removed in 3.4.2, brought back as deprecated in 3.4.3, and is slated for final removal in version 3.5.0. Relying on this option may cause future breaking changes.","severity":"deprecated","affected_versions":"3.4.2, 3.4.3, 3.4.4, 3.4.5 (and future 3.5.0+)"},{"fix":"Update logic to expect and handle boolean `True`/`False` values instead of integers for comparison results.","message":"The return type of `LDAPObject.compare_s()` and `LDAPObject.compare_ext_s()` changed from an integer (0 or 1) to a boolean (`False` or `True`) in version 3.1.0. Code expecting an integer return value may behave incorrectly.","severity":"gotcha","affected_versions":"3.1.0 and newer"},{"fix":"Upgrade to python-ldap 3.4.5 or newer. When using `escape_filter_chars`, ensure `str` input when `escape_mode=1`. For DNs, verify NUL character handling. Always validate and sanitize user inputs meticulously.","message":"Versions prior to 3.4.5 had security vulnerabilities (CVE-2025-61911, CVE-2025-61912) related to improper escaping of input in `ldap.filter.escape_filter_chars` and `ldap.dn.escape_dn_chars`.","severity":"gotcha","affected_versions":"3.x up to 3.4.4"}],"env_vars":null,"last_verified":"2026-04-09T00:00:00.000Z","next_check":"2026-07-08T00:00:00.000Z"}