Library / SDK
cannatag/ldap3 avatar
cannatag/ldap3

ldap3 and the case for an abstraction layer over raw LDAP operations

a strictly RFC 4510 conforming LDAP V3 pure Python client. The same codebase works with Python 2. Python 3, PyPy and PyPy3

936 stars289 forksPythonNOASSERTION

At a glance

What is it?
ldap3 is a pure Python LDAP v3 client that claims strict RFC 4510 conformance and wraps the protocol in a higher level interface. The abstraction is convenient but the project also carries a Python 2 era promise that its own packaging no longer keeps.
Who is it for?
Adopt ldap3 when your application talks to an LDAP directory from Python and you want searches, binds and directory operations without hand rolling ASN.1, and treat the abstraction layer as single threaded per connection. Do not adopt it if your deployment depends on Python 2 or PyPy2 support, because the packaging metadata now declares requires-python as 3.4 and up, and do not assume the missing GitHub releases mean an abandoned project.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 4, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • cannatag/ldap3936 ★ · +0
Star history
Repository2026-10-212026-11-04
cannatag/ldap3936936

0 Stars in the last 14 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Why LDAP feels clumsy and what the abstraction layer changes

The project gives a diagnosis in its own documentation. LDAP operations look clumsy and hard to use because they reflect an old idea that time consuming operations should be performed client side, so the server is not bogged down with heavy elaborations. That historical design produced an API where a simple search requires assembling a filter, a scope and a set of attributes and then reading raw responses.

ldap3 answers this with what it calls a fully functional Abstraction Layer. The claim is specific: with the abstraction you do not need to issue any LDAP operation directly. The layer turns a directory into something that behaves like an object store with attributes and entries, while the underlying connection still speaks the wire protocol of an LDAP v3 server.

That framing also tells you who the library is for. It is for Python developers who need to authenticate against a directory, read groups, or manage entries from an application, and who would rather not deal with the mechanics of LDAP message encoding. It is a client library only: the description calls it an LDAP V3 pure Python client library, and there is no server component here.

The conformance claim is narrow and checkable. The library describes itself as strictly RFC 4510 conforming, which is the protocol definition for LDAP v3. The name itself is a clue about scope. An RFC 4510 library is one that follows the base protocol rules closely, and the trade-off in that choice tends to be fidelity to the specification over convenience for exotic server extensions.

One library across Python 2, Python 3, PyPy and PyPy3

The documentation makes a bold portability claim in its opening line: the same codebase runs in Python 2, Python 3, PyPy and PyPy3. A single implementation serving four runtimes removes the usual duplication where a library keeps a Python 2 branch and a Python 3 branch that drift apart in behaviour.

The current packaging metadata tells a different story, and it is worth reading carefully before you plan an upgrade. The project metadata declares requires-python as 3.4 and up, and the classifier list includes only Programming Language:: Python:: 3, alongside Operating System:: OS Independent and Development Status:: 5 - Production/Stable. The version field reads 2.10.2rc4, so the release candidate suffix is present in the source tree as well.

So there is a gap between the claim on the front page and the packaging in front of you. The historical multi-interpreter support is a fact about the codebase, but the current distribution metadata narrows what pip will install and where. Nothing in the documentation explains when Python 2 support was dropped or whether the code paths remain in the source tree.

Two other structural details are visible in the repository. The default branch is dev, and the project asks for pull requests on that branch rather than on a release branch. There are no GitHub releases, so version history for a user of the library lives in the PyPI package rather than in the GitHub release list.

SAFE_SYNC, SAFE_RESTARTABLE and ASYNC all return four elements

Thread safety in ldap3 is not an option you toggle loosely. The documentation states that in multithreaded programs you must use one of three strategies, and it names them precisely.

SAFE_SYNC is the synchronous connection strategy, SAFE_RESTARTABLE is the restartable synchronous connection strategy, and ASYNC is the asynchronous one. With SAFE_SYNC or SAFE_RESTARTABLE, every LDAP operation returns a tuple of four elements, and the documentation names each one. The status states whether the operation was successful. The result is the LDAP result of the operation. The response is the response of an LDAP search operation. The request is the original request of the operation.

That four element return is the interface contract, and it is easy to get wrong. A caller who assumes the return value is a bare boolean, or who unpacks two items instead of four, will fail. The documentation even includes a comment noting that you usually do not need the original request, which is the fourth element, so discarding that last element is the intended pattern.

With ASYNC the contract changes shape. You do not get the response as part of the return value; you request it afterwards with the get_response() method. That is the difference between a strategy that blocks until the server answers and one that returns control to the caller first, and it is the decision that determines how you structure the calling code.

Installing the package and running a first search

Installation is a single pip command, given in the documentation as install with pip install ldap3. Package downloads live on PyPI, and the project is also installable from source, since the latest source can be downloaded from the GitHub repository.

bash
pip install ldap3

The build system in the source tree is straightforward. The pyproject.toml file names setuptools as the build requirement, with setuptools at 77.0.3 or later, and selects the setuptools.build_meta backend.

toml
[build-system]
requires = ["setuptools >= 77.0.3"]
build-backend = "setuptools.build_meta"

Two runtime dependencies come with it, and both are mandatory in the dependency list rather than optional.

toml
dependencies = [
    "pyasn1>=0.4.6",
    "pycryptodomex",
]

pyasn1 handles the ASN.1 encoding that LDAP messages require, and the project credits Ilya Etingof, the author of pyasn1, in its thanks section. pycryptodomex provides the cryptographic primitives.

Your first real use is a search against a server. The documentation gives this shape with SAFE_SYNC, binding automatically on connection.

python
from ldap3 import Server, Connection, SAFE_SYNC
server = Server('my_server')
conn = Connection(server, 'my_user', 'my_password', client_strategy=SAFE_SYNC, auto_bind=True)
status, result, response, _ = conn.search('o=test', '(objectclass=*)')  # usually you don't need the original request (4th element of the returned tuple)

Read the result as four values. A successful operation is reflected in the status element, the LDAP result carries the server side outcome, and the response holds what the search returned. The final placeholder is deliberate, discarding the original request.

The abstraction layer is not thread safe

The limitation is stated without hedging in the documentation, and it sits directly beside the feature that makes the library pleasant to use. The SafeSync strategy can be used with the abstraction layer, but the abstraction layer itself is currently NOT thread safe.

That is a sharper warning than the general advice about connection strategies. SAFE_SYNC makes an individual operation safe to call from a multithreaded program; it does not make a shared abstraction layer object safe to use from several threads at once. The two statements sit side by side in the same section, and reading only the strategy list would miss it.

The practical consequence is that the safe pattern is one connection and one abstraction layer per thread, rather than a shared instance guarded by a lock. If your application pools LDAP connections behind a single object and hands them to worker threads, the abstraction layer is the component that will misbehave, not the strategy setting.

Other boundaries are simply undocumented rather than prohibited. The documentation does not describe behaviour for a server that returns referral or continuation responses, nor does it set out how the abstraction maps every RFC 4510 element, such as the controls described in the protocol. The reference documentation at ldap3.readthedocs.io covers much of this, but the front page of the project does not, and the deployment decisions that follow from it have to be taken by reading the docs rather than the README.

Kerberos support is an optional extra, not the default

Authentication against a directory is where a client library either stays simple or grows options, and ldap3 keeps the advanced cases in optional extras. The optional dependency groups in the packaging metadata are named winkerberos and gssapi.

toml
[project.optional-dependencies]
winkerberos = ["winkerberos"]
gssapi = ["gssapi"]

The requirements file for development shows how the extras map onto platforms. The winkerberos package is required only where the platform system is Windows, and the gssapi package is required everywhere the platform system is not Windows. That split is the practical shape of Kerberos support, since the two mechanisms are not interchangeable on the same host.

This matters when you choose an ldap3 install. A plain pip install ldap3 gives you simple bind and whatever the base protocol offers, plus the two runtime dependencies. Enterprise directory environments, which often authenticate with SPNEGO or GSSAPI rather than a password, need the extras installed explicitly, and on Linux that means the gssapi group.

The project also ships example scripts in the repository root, with tut1.py through tut4.py, and its thanks section credits the FreeIPA team for letting the author use their demo LDAP server in the tutorial. That is a useful pointer for anyone trying the library: the tutorial is built around a real directory server rather than a mock, so the behaviour you observe during evaluation comes from an implementation outside the library.

LGPL v3, a README-rendered licence, and no tagged releases

The licence is LGPL v3, stated in the project documentation with a copyright line covering 2013 through 2025, and the packaging metadata records it as LGPL-3.0-or-later with the licence files listed as LICENSE.txt, COPYING.txt and COPYING.LESSER.txt. The three files are the usual LGPL arrangement, where the library carries its own terms while the accompanying terms cover what it links against.

There is a mismatch worth knowing about before you reason about terms. The repository metadata classifies the licence as a custom type that GitHub cannot categorise, yet the source files themselves name LGPL v3. For anyone running a licence scanner, the automated classification and the actual licence text may disagree, and a scanner that trusts the GitHub field will report the wrong thing.

On the practical side of LGPL use, the obligation that tends to surface is about modifications: if you change the library itself rather than calling it, the modified version carries conditions. How that applies to a specific deployment is a question for your own counsel rather than for this review.

Maintenance information is thin, so read it carefully. The repository is not archived, and the last push was on 2026-04-18. There are no GitHub releases, so the version trail comes from PyPI and from the changelog, which is published at ldap3.readthedocs.io/changelog.html, with the repository also carrying CHANGES.txt and _changelog.txt alongside the generated _version.json.

Because the last push is more than six months old, treat this as a library you evaluate on its own merits rather than one with a visible commit cadence. The documentation itself points to a Continuous integration setup for testing, a SECURITY.md file in the repository root, and a support ticket tracker, all of which exist as of that 2026-04-18 push.

Editorial conclusion

Adopt ldap3 when your application talks to an LDAP directory from Python and you want searches, binds and directory operations without hand rolling ASN.1, and treat the abstraction layer as single threaded per connection. Do not adopt it if your deployment depends on Python 2 or PyPy2 support, because the packaging metadata now declares requires-python as 3.4 and up, and do not assume the missing GitHub releases mean an abandoned project. Before committing, read the version field in pyproject.toml, which currently reads 2.10.2rc4, and confirm on a staging directory that the connection strategy you intend to use returns the four element tuple your code expects.

Frequently asked questions

How do I install ldap3?

The documentation gives the install command as pip install ldap3. Package downloads are on PyPI at pypi.python.org/pypi/ldap3, and the source can be downloaded from the GitHub repository.

Is the ldap3 abstraction layer safe to use from multiple threads?

No. The documentation says the SafeSync strategy can be used with the abstraction layer, but the abstraction layer itself is currently NOT thread safe. In multithreaded programs you must use SAFE_SYNC, SAFE_RESTARTABLE or ASYNC.

What does an ldap3 search return?

With SAFE_SYNC or SAFE_RESTARTABLE it returns a tuple of four elements: status, result, response and the original request. With ASYNC you request the response separately using the get_response() method.

Does ldap3 support Kerberos authentication?

It supports it through optional dependency groups named winkerberos and gssapi. The requirements file ties winkerberos to Windows and gssapi to non Windows platforms.

Which Python versions does ldap3 support?

The project documentation says the same codebase runs in Python 2, Python 3, PyPy and PyPy3. The current packaging metadata declares requires-python as 3.4 or later and classifies the project for Python 3 only.

Official sources

  1. cannatag/ldap3 on GitHub
  2. Issues
  3. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/cannatag-ldap3.svg)](https://hysenlabs.com/projects/cannatag-ldap3)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/cannatag-ldap3.svg)](https://hysenlabs.com/projects/cannatag-ldap3)

Was this useful?