Skip to content
DinithKumudikaPublic

About

A lightweight and fast LDAP built using Rust

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

23 Commits

Folders and files

Repository files navigation

FastLDAP

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.

Features

  • Asynchronous I/O: Fully built on tokio for 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 redb for durable, disk-based persistent storage across restarts.
  • Configuration-Driven Bootstrapping: Easily seed users and groups on startup using the config.yaml file.
  • 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.

Project Structure

  • 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.

System Architecture

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)")]
Loading

Component Interaction

  • Network & Connection Layer: Handles incoming TCP connections and TLS wrapper streams inside server.rs and delegates them to connection.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 using nom for zero-copy parsing. Additionally, it now contains high-level parsers to translate the decoded primitives into structured LdapMessage requests (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 concurrent DashMapto 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.

Prerequisites

  • 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.

Configuration

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"

Building and Running Locally

  1. Clone and Build:

    git clone <repository-url>
    cd fastldap
    cargo build --release
  2. 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 port 389 to accept LDAP connections.

Docker Deployment

You can easily containerize and run FastLDAP using Docker.

  1. Build the Docker Image:

    docker build -t fastldap .
  2. 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.yaml file and the data directory (if using redb storage) so your configurations and database persist across container restarts.

Using Docker Compose

If you prefer Docker Compose, you can simply run:

docker-compose up -d

This will automatically build the image and start the server with the necessary ports and volume mounts configured.

Usage & Testing

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).

1. Test Authentication and Search

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=*)"

2. Adding Users Over the Network (Recommended)

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.)

3. Configuring Initial Seed Data (For Memory Backend)

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!

Keycloak Integration

FastLDAP is specifically designed to seamlessly integrate with Keycloak's User Federation.

To connect Keycloak to FastLDAP:

  1. Navigate to your Keycloak Admin Console -> User Federation -> Add LDAP providers.
  2. Set Vendor to Other.
  3. Set Connection URL to ldap://127.0.0.1:389.
  4. Set Users DN to dc=example,dc=com (matching the seed data).
  5. Set Bind Type to simple.
  6. Configure the Bind DN (uid=testuser,dc=example,dc=com) and password (password123) to match your administrative account.
  7. Click Test connection and Test authentication to verify.

Contributing

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:

Code Standards & Workflow

  • Formatting & Linting: We use standard Rust tooling. Ensure you run cargo fmt and cargo clippy --all-targets --all-features before submitting a PR.
  • Testing: Run cargo test to 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 graphify for code navigation and architecture documentation. You can view the current architecture in graphify-out/GRAPH_REPORT.md or run /graphify query "<your question>" to ask questions about the project's codebase.

Adding a New LDAP Operation

If you're tackling items on the roadmap like new operations (Add, Delete, Modify), follow this established pattern:

  1. Protocol Layer: Define the BER structs and response types in src/protocol/.
  2. Parser: Add BER parsing logic in src/ber/message_parser.rs.
  3. Handler: Implement the business logic in src/operations/<op>.rs, mapping the request to the backend.
  4. Integration: Wire the new handler into the main Connection matching logic in src/connection.rs.

Future Roadmap

  • 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.

License

This project is licensed under the MIT License.

About

A lightweight and fast LDAP built using Rust

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages