FastLDAP is an asynchronous, high-performance, in-memory LDAP (Lightweight Directory Access Protocol) server built with Rust and tokio async runtime for managing TCP and TLS connections, the nom parser-combinator library for decoding Basic Encoding Rules (BER), and a lock-free concurrent hash map combined with fine-grained locking to implement an in-memory directory store. Designed for speed, safety, and RFC 4511 compliance, this solution serves as a highly scalable identity provider. It is a good candidate for Keycloak federation.
- Asynchronous I/O: Fully built on
tokiofor maximum concurrency, capable of handling thousands of simultaneous connections. - Dual Storage Backends:
- In-Memory Store: Uses a lock-free concurrent hash map (
DashMap) for blazingly fast, ephemeral directories. - Persistent Store: Uses
redbfor durable, disk-based persistent storage across restarts.
- In-Memory Store: Uses a lock-free concurrent hash map (
- Configuration-Driven Bootstrapping: Easily seed users and groups on startup using the
config.yamlfile. - LDAP Operations: Supports core LDAP operations over the network, including Bind, Search, Add, Delete, Modify, and ModifyDN.
- Search Capabilities: Supports complex RFC 4515 LDAP search filters for group and user enumeration.
- Security Ready: Built-in support for LDAPS (TLS over port 636) using
tokio-rustls.
src/ber/: Zero-copy BER streaming decoder, encoder, and LDAP message parsers.src/protocol/: LDAP message structures and response codes.src/store/:DashMap-backed in-memory store and LDIF loader.src/operations/: Request handlers for Bind, Search, etc.src/filter/: RFC 4515 compliant filter parser and evaluator.src/utils/: Common utilities and standardized error types.src/server.rs&src/connection.rs: Tokio TCP/TLS connection management.src/main.rs,src/lib.rs,src/config.rs: Crate entry points and configuration.
graph TD
Client["LDAP Client / Keycloak"] <-->|"TCP / TLS (LDAPS)"| Listener["TcpListener in server.rs"]
Listener -->|"Spawns Tokio Task"| Conn["Connection in connection.rs"]
Conn <-->|"Raw Bytes"| BER["BER Decoder & Encoder in ber/"]
Conn <-->|"LdapMessage"| Handler["Operation Handlers in operations/"]
Handler <-->|"Backend Trait Interface"| Store["Storage Layer in store/"]
Store <-->|"MemoryBackend"| MemDB[("DashMap (In-Memory)")]
Store <-->|"RedbBackend"| DiskDB[("Redb (Persistent Disk)")]
-
Network & Connection Layer: Handles incoming TCP connections and TLS wrapper streams inside
server.rsand delegates them toconnection.rs. This spawns a dedicated Tokio task per client connection. Connection streams manage read/write buffers, continuously decoding incoming byte streams into messages, routing them to the appropriate operation handler, and encoding the generated responses back to the client. -
ASN.1 BER Encoding & Message Parsing: Managed by the
ber/module. It decodes ASN.1 primitive types (integers, booleans, strings) and tags/lengths usingnomfor zero-copy parsing. Additionally, it now contains high-level parsers to translate the decoded primitives into structuredLdapMessagerequests (Bind, Search, etc.) and encoders to serialize outgoing responses. -
Protocol Layer:
protocol/defines the LDAP message structures and response codes for each operation (Bind, Search, Add, Delete, Modify, ModifyDN) and result codes defined in RFC 4511. -
Database Backend: Under
store/, models the database layer, directory entries, storage backend interfaces, and LDIF data seeding utility. It uses a concurrentDashMapto manage entries thread-safely with high read throughput. -
Operation Controllers: The
operations/module coordinates request payloads with backend storage mutations and generates response structures. Translates LDAP requests to store calls (e.g. matching passwords for Binds, evaluating entries for Searches). -
Search Filters: The
filter/module parses LDAP RFC 4515 filter string expressions into a structured Abstract Syntax Tree (AST) and evaluates them against directory entries. Supports complex filter operations including logical logic (&,|,!,*, etc), attribute existence checks ((cn=*)), and substring matching.
- Rust Toolchain: 1.75 or higher.
- C++ Build Tools: Required for compiling dependencies on Windows. Ensure you have the Visual Studio Build Tools with C++ extensions installed.
FastLDAP uses a config.yaml file to configure its behavior. By default, it expects this file in the current working directory. You can also pass the APP_ENV environment variable to configure the application's environment context (e.g., production, development).
Example config.yaml:
server:
bind_address: "0.0.0.0:389"
storage:
# Choose either 'memory' or 'redb'
type_: "redb"
file: "/app/data/fastldap.redb"
# Optional: Seed data loaded on startup (currently loaded when using the memory backend)
seed_data:
- dn: "dc=example,dc=com"
attributes:
objectclass:
- "top"
- "domain"
- dn: "uid=testuser,dc=example,dc=com"
attributes:
objectclass:
- "inetOrgPerson"
- "person"
userpassword:
- "password123"
sn:
- "User"
cn:
- "Test User"-
Clone and Build:
git clone <repository-url> cd fastldap cargo build --release
-
Run the server:
cargo run --release
By default, the server loads seed data from the internal LDIF configuration (e.g.,
dc=example,dc=com) and binds to port389to accept LDAP connections.
You can easily containerize and run FastLDAP using Docker.
-
Build the Docker Image:
docker build -t fastldap . -
Run the Docker Container:
docker run -d \ -p 389:389 \ -e APP_ENV=production \ -v $(pwd)/config.yaml:/app/config.yaml \ -v $(pwd)/data:/app/data \ --name fastldap-server \ fastldap
Note: Be sure to map the
config.yamlfile and thedatadirectory (if usingredbstorage) so your configurations and database persist across container restarts.
If you prefer Docker Compose, you can simply run:
docker-compose up -dThis will automatically build the image and start the server with the necessary ports and volume mounts configured.
You can interact with the server immediately after starting it. FastLDAP loads a default set of seeded users on startup (e.g., uid=testuser,dc=example,dc=com with password password123).
You can use ldapsearch to query the directory using the default admin account:
ldapsearch -H ldap://localhost:389 -D "uid=testuser,dc=example,dc=com" -w password123 -b "dc=example,dc=com" "(objectClass=*)"FastLDAP supports the LDAP Add operation natively. You can add users dynamically via ldapadd.
First, create an LDIF file (e.g., new_user.ldif):
dn: uid=newuser,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: person
userPassword: newpassword456
sn: User
cn: New User
Then run the ldapadd command to authenticate and push the entry:
ldapadd -H ldap://localhost:389 -D "uid=testuser,dc=example,dc=com" -w password123 -f new_user.ldif(If using the redb backend, this user will persist on disk across restarts.)
If you are using the memory backend, FastLDAP can automatically load seed users on startup directly from your configuration.
To seed your own test users, open config.yaml and append them to the seed_data section. They will be available immediately upon running the server!
FastLDAP is specifically designed to seamlessly integrate with Keycloak's User Federation.
To connect Keycloak to FastLDAP:
- Navigate to your Keycloak Admin Console -> User Federation -> Add LDAP providers.
- Set Vendor to
Other. - Set Connection URL to
ldap://127.0.0.1:389. - Set Users DN to
dc=example,dc=com(matching the seed data). - Set Bind Type to
simple. - Configure the Bind DN (
uid=testuser,dc=example,dc=com) and password (password123) to match your administrative account. - Click Test connection and Test authentication to verify.
We welcome contributions!
Note
AI-Assisted Codebase: Please be aware that this codebase was primarily written by AI under human supervision. While the code is functional and tested, you might occasionally encounter unconventional patterns. Refactoring and structural cleanups are always welcome!
Since you likely already have experience building applications, here's a quick guide to navigating and extending the codebase:
- Formatting & Linting: We use standard Rust tooling. Ensure you run
cargo fmtandcargo clippy --all-targets --all-featuresbefore submitting a PR. - Testing: Run
cargo testto execute unit tests. If you're adding a new LDAP operation, please add corresponding tests in the relevant module (e.g.,src/operations/). - Graphify Knowledge Graph: This project uses
graphifyfor code navigation and architecture documentation. You can view the current architecture ingraphify-out/GRAPH_REPORT.mdor run/graphify query "<your question>"to ask questions about the project's codebase.
If you're tackling items on the roadmap like new operations (Add, Delete, Modify), follow this established pattern:
- Protocol Layer: Define the BER structs and response types in
src/protocol/. - Parser: Add BER parsing logic in
src/ber/message_parser.rs. - Handler: Implement the business logic in
src/operations/<op>.rs, mapping the request to the backend. - Integration: Wire the new handler into the main
Connectionmatching logic insrc/connection.rs.
- Support for LDAP Add, Delete, Modify, and ModifyDN operations over the network connection.
- Persistent storage backends (implemented via
redb). - Advanced SASL authentication (GSSAPI, SCRAM).
- Strict LDAP schema validation.
This project is licensed under the MIT License.