ldap3

A pure-Rust LDAP client built on Tokio, with matching sync and async APIs, TLS, and SASL GSSAPI/NTLM auth.

Library
Cargo
v0.12.1
260stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
38/100Needs Attention
Development Activity0
Maintenance0
Community72
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
71/100Good
Architecture82
Code Quality68
Innovation72
Learning Curve60

ldap3 is a client-only library for talking to LDAPv3 directory servers from Rust, built on the Tokio async runtime. It exposes both a synchronous interface (LdapConn) and an asynchronous one (LdapConnAsync/Ldap) with essentially the same call shape, so code can start synchronous and move to async without relearning the API.

Beyond basic bind/search/add/modify/compare/delete operations, the crate implements a wide range of LDAPv3 controls (paged results, content sync, manage DSA IT, proxy authorization, matched values, assertion, relax rules, and transactions) and extended operations (StartTLS, WhoAmI, password modify, and transactions), plus SASL EXTERNAL, GSSAPI (via Kerberos, gated behind FFI to system Kerberos libraries), and NTLM authentication. TLS is supported through either native-tls or Rustls, with the crypto provider chosen explicitly at compile time.

The wire protocol itself — BER/ASN.1 encoding and decoding of LDAP PDUs — lives in a companion workspace member, lber, which the main crate depends on directly by path. This separation keeps protocol-level structure encoding isolated from the connection and operation logic.

What You Get

  • Synchronous (LdapConn) and asynchronous (LdapConnAsync/Ldap) clients sharing the same call interface
  • Full LDAPv3 operation set: bind, search, add, modify, modify DN, compare, delete, unbind, abandon
  • Built-in support for common controls (paged results, content sync, proxy auth, matched values, assertion, relax rules, transactions) and extended operations (StartTLS, WhoAmI, password modify)
  • TLS via native-tls or Rustls, selectable at compile time through Cargo features
  • SASL EXTERNAL, GSSAPI/Kerberos, and NTLM authentication mechanisms
  • A companion lber crate implementing the underlying BER/ASN.1 encoding used by the LDAP wire protocol

Common Use Cases

  • Authenticating application users against an existing Active Directory or OpenLDAP directory
  • Searching and reading directory entries (users, groups, org units) from a Rust backend service
  • Provisioning or updating directory entries as part of an identity-management tool
  • Building LDAP-aware infrastructure tooling (sync agents, audit scripts, migration utilities) that needs paged search and transactional semantics
  • Implementing StartTLS or SASL-based secure binds where the calling application controls the TLS/crypto stack directly

Under The Hood

Architecture The crate is organized in clear layers around a codec-driven connection: protocol.rs defines LdapCodec, a Tokio Decoder/Encoder that frames raw LDAP PDUs over the wire using the lber BER implementation; conn.rs owns the actual socket (TCP, Unix domain socket, or TLS-wrapped stream) and drives it through a Framed codec, dispatching parsed responses to per-request channels (oneshot for single results, mpsc for search result streams) via an internal LdapOp enum; ldap.rs exposes the async Ldap handle with one method per LDAP operation, building request Tag structures and awaiting the corresponding channel; sync.rs wraps the async API in a blocking Tokio runtime to provide LdapConn. Controls and extended operations are implemented as sibling modules (controls_impl/*, exop_impl/*) that each encode/decode one control or exop and are cheap to extend when a new LDAPv3 control is needed. Cargo feature flags (tls, tls-rustls, gssapi, ntlm, sync) gate entire code paths at compile time via #[cfg(feature = ...)], so a consumer only pays for the transports and auth mechanisms it actually enables — swapping the core BER encoding in lber would ripple through every operation, since all requests and responses pass through it.

Tech Stack Built on Tokio 1.x (macros, io-util, sync, time, net features) with tokio-util for the Framed/codec machinery and tokio-stream for search result streaming. Async trait methods use async-trait. TLS is pluggable: native-tls/tokio-native-tls for the platform TLS backend, or rustls/tokio-rustls/rustls-native-certs/x509-parser with an explicit crypto provider (ring or aws-lc-rs). GSSAPI support pulls in cross-krb5 (FFI to system Kerberos) and NTLM pulls in sspi. Errors use thiserror; filter string parsing uses nom; the workspace’s lber member has no external dependencies beyond bytes, keeping the BER layer self-contained. The crate targets edition 2024 and is split as a two-member Cargo workspace (ldap3 + lber).

Code Quality The crate carries inline unit tests only in a couple of modules (util.rs, filter.rs, mainly for filter-string parsing edge cases); broader behavioral coverage instead lives in the examples/ directory, which is designed to run against a bundled example LDAP server under data/ — a pragmatic but less automatable approach than a conventional tests/ integration suite. Error handling is explicit and typed throughout via thiserror-derived LdapError and a crate-wide Result alias rather than panics or silent fallbacks. Naming is consistent with LDAP protocol terminology (Scope, SearchEntry, Mod, Tag), and heavy use of #[cfg(feature = ...)] keeps optional subsystems (TLS backends, GSSAPI, NTLM) cleanly separated without runtime branching.

What Makes It Unique Unlike LDAP bindings that FFI into OpenLDAP’s libldap (paying a C dependency and platform-specific build burden), ldap3 implements the wire protocol and BER encoding natively in Rust via its own lber crate, while still supporting the harder authentication paths — GSSAPI and NTLM — that pure-protocol reimplementations often skip. Presenting sync and async APIs with matching method signatures over the same underlying async core is also a deliberate design choice that lets consumers change execution models without a rewrite.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search