{"id":1295,"library":"ldap3","title":"ldap3 - LDAP Client Library","description":"ldap3 is a strictly RFC 4510 conforming LDAP V3 pure Python client library. The same codebase runs in Python 2, Python 3, PyPy and PyPy3. It offers a more pythonic way to interact with LDAP servers, including an Abstraction Layer for simplified operations.","status":"active","version":"2.9.1","language":"en","source_language":"en","source_url":"https://github.com/cannatag/ldap3","tags":["ldap","authentication","directory","networking","security","client"],"install":[{"cmd":"pip install ldap3","lang":"bash","label":"Install stable version"},{"cmd":"pip install ldap3[gssapi]","lang":"bash","label":"Install with Kerberos (GSSAPI) support"},{"cmd":"pip install ldap3[winkerberos]","lang":"bash","label":"Install with Kerberos (winkerberos) support for Windows"}],"dependencies":[{"reason":"Required for ASN.1 encoding/decoding, used for network communication.","package":"pyasn1"},{"reason":"Required for cryptographic operations, often used with SASL authentication.","package":"pycryptodomex"},{"reason":"Optional, required for Kerberos SASL authentication.","package":"gssapi","optional":true},{"reason":"Optional, required for Kerberos SASL authentication on Windows clients.","package":"winkerberos","optional":true}],"imports":[{"symbol":"Server","correct":"from ldap3 import Server"},{"symbol":"Connection","correct":"from ldap3 import Connection"},{"symbol":"Tls","correct":"from ldap3 import Tls"},{"note":"Constants like ANONYMOUS, SIMPLE, SASL are directly in the ldap3 namespace, not under an 'AUTH_' prefix.","wrong":"from ldap3 import AUTH_ANONYMOUS","symbol":"ANONYMOUS","correct":"from ldap3 import ANONYMOUS"},{"note":"Connection strategies are typically imported directly by their short names (e.g., SYNC, ASYNC, RESTARTABLE).","wrong":"from ldap3 import STRATEGY_SYNC","symbol":"STRATEGY_SYNC","correct":"from ldap3 import SYNC"}],"quickstart":{"code":"import os\nfrom ldap3 import Server, Connection, SYNC, ANONYMOUS, SUBTREE\n\n# Configuration from environment variables for security and flexibility\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=com')\nLDAP_BIND_PASSWORD = os.environ.get('LDAP_BIND_PASSWORD', 'adminpassword')\nLDAP_SEARCH_BASE = os.environ.get('LDAP_SEARCH_BASE', 'dc=example,dc=com')\nLDAP_SEARCH_FILTER = os.environ.get('LDAP_SEARCH_FILTER', '(objectClass=person)')\nLDAP_SEARCH_ATTRIBUTES = os.environ.get('LDAP_SEARCH_ATTRIBUTES', 'cn,mail').split(',')\n\ndef ldap_connect_and_search():\n    try:\n        # Define the LDAP server\n        s = Server(LDAP_SERVER_URI)\n\n        # Establish a connection. auto_bind=True performs the bind operation immediately.\n        # authentication=ANONYMOUS can be used if no credentials are required.\n        # For authenticated bind:\n        # c = Connection(s, user=LDAP_BIND_DN, password=LDAP_BIND_PASSWORD, client_strategy=SYNC, auto_bind=True)\n        c = Connection(s, user=LDAP_BIND_DN, password=LDAP_BIND_PASSWORD, client_strategy=SYNC, auto_bind=True, raise_exceptions=True)\n\n        print(f\"Connection status: {c.bound}\")\n\n        # Perform a search operation\n        # search_base: The base DN for the search\n        # search_filter: The LDAP filter string\n        # search_scope: The scope of the search (e.g., SUBTREE, BASE, LEVEL)\n        # attributes: List of attributes to retrieve, or ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES\n        c.search(LDAP_SEARCH_BASE, LDAP_SEARCH_FILTER, search_scope=SUBTREE, attributes=LDAP_SEARCH_ATTRIBUTES)\n\n        # Process the search results\n        print(f\"Found {len(c.entries)} entries:\")\n        for entry in c.entries:\n            print(f\"  DN: {entry.entry_dn}\")\n            for attr in LDAP_SEARCH_ATTRIBUTES:\n                if hasattr(entry, attr):\n                    print(f\"    {attr}: {getattr(entry, attr).value}\")\n\n    except Exception as e:\n        print(f\"An LDAP error occurred: {e}\")\n    finally:\n        if 'c' in locals() and c.bound:\n            c.unbind()\n            print(\"Connection unbound.\")\n\nif __name__ == '__main__':\n    ldap_connect_and_search()","lang":"python","description":"This example demonstrates how to establish a connection to an LDAP server, perform a simple bind with credentials (or anonymously), and execute a search operation. It uses environment variables for sensitive configuration details. The `raise_exceptions=True` parameter is added to the `Connection` to ensure LDAP operation failures are surfaced as Python exceptions."},"warnings":[{"fix":"Ensure you are installing and importing the `ldap3` package. If you have `python-ldap` installed, be mindful of potential conflicts due to similar names but different APIs.","message":"The library was formerly known as `python3-ldap` and was renamed to `ldap3` to avoid confusion with the `python-ldap` library. Users migrating from `python3-ldap` or older `python-ldap` installations should be aware.","severity":"gotcha","affected_versions":"< 1.0"},{"fix":"Be explicit about string encoding when necessary. Use `set_config_parameter('DEFAULT_ENCODING', 'my_encoding')` if your input encoding is not UTF-8 and differs from your system default. Ensure data retrieved is handled as UTF-8.","message":"LDAP protocol strictly uses UTF-8 for string values. While `ldap3` attempts to handle encoding, mismatches between your environment's default encoding and required UTF-8 can lead to issues. Explicit encoding/decoding may be necessary.","severity":"gotcha","affected_versions":"All"},{"fix":"Always check the documentation for the specific connection strategy you are using to understand its return values. For `ASYNC`, you typically need to call `get_response()` separately to retrieve the operation result. For multi-threaded programs, use `SAFE_SYNC` or `SAFE_RESTARTABLE`.","message":"Different connection strategies (e.g., `SYNC`, `ASYNC`, `RESTARTABLE`, `REUSABLE`, `SAFE_SYNC`, `SAFE_RESTARTABLE`) have different return value semantics. Synchronous strategies (e.g., `SYNC`) typically return booleans for success/failure, while asynchronous strategies (e.g., `ASYNC`) return a `message_id`. Incorrectly handling these return types is a common pitfall.","severity":"gotcha","affected_versions":"All"},{"fix":"Always escape user inputs before using them in LDAP filters or DNs. `ldap3` provides utility functions for this (e.g., `ldap3.utils.conv.escape_filter_chars`, `ldap3.utils.conv.escape_rdn_chars`). Never directly concatenate unescaped user input into LDAP queries.","message":"Special characters in user-provided input for LDAP queries (e.g., `*`, `(`, `)`, `\\`, NUL) must be properly escaped to prevent syntax errors and security vulnerabilities (like LDAP injection).","severity":"gotcha","affected_versions":"All"},{"fix":"Check for `ldap3` updates that include the fix for `pyasn1` compatibility. If warning persists and is disruptive, you may need to filter the warning or consider pinning `pyasn1 < 0.6.0` if feasible for your project, though this is not generally recommended for security/maintenance reasons.","message":"When using `ldap3` with `pyasn1` versions greater than `0.6.0`, a `DeprecationWarning` regarding `typeMap` vs. `TYPE_MAP` may be triggered. While typically harmless, it can clutter logs. This issue has been addressed in PR #983.","severity":"gotcha","affected_versions":"All `ldap3` versions with `pyasn1 > 0.6.0` (until `ldap3` officially incorporates the fix in a release, or you use a `bleeding-edge` version)."}],"env_vars":null,"last_verified":"2026-04-08T00:00:00.000Z","next_check":"2026-07-07T00:00:00.000Z"}