# yamldap
<div align="center">
<img src="https://raw.githubusercontent.com/rvben/yamldap/main/assets/logo.png" alt="yamldap logo" width="400">
**A lightweight LDAP server that serves directory data from YAML files**
[](https://crates.io/crates/yamldap)
[](https://docs.rs/yamldap)
[](https://github.com/rvben/yamldap#license)
[](https://github.com/rvben/yamldap/actions)
</div>
---
A lightweight LDAP server that serves directory data from YAML files, designed for local development and testing.
## Features
- 🚀 **Quick Setup** - Define your LDAP directory in a simple YAML file
- 🔐 **Authentication** - Support for multiple password formats (plain, SHA, SSHA, bcrypt)
- 🔍 **LDAP Operations** - Bind, search, and compare operations
- 🛠️ **Development Friendly** - Perfect for testing LDAP integrations locally
- 🐳 **Docker Support** - Run in containers with provided Dockerfile
- ⚡ **Lightweight** - Minimal resource usage, fast startup
## Installation
### From Crates.io
```bash
cargo install yamldap
```
### From Binary Releases
Download pre-built binaries from the [GitHub Releases](https://github.com/rvben/yamldap/releases) page for:
- Linux (x86_64, aarch64)
- macOS (x86_64, aarch64)
- Windows (x86_64)
### From Source
```bash
git clone https://github.com/rvben/yamldap
cd yamldap
cargo install --path .
```
### Using Docker
Pull from GitHub Container Registry:
```bash
# Pull the latest version (multi-platform: linux/amd64, linux/arm64)
docker pull ghcr.io/rvben/yamldap:latest
# Or pull a specific version
docker pull ghcr.io/rvben/yamldap:0.0.1
# Run with your YAML directory file
docker run -p 389:389 -v $(pwd)/directory.yaml:/data/directory.yaml ghcr.io/rvben/yamldap:latest -f /data/directory.yaml
```
Or build locally:
```bash
docker build -t yamldap .
docker run -p 389:389 -v $(pwd)/examples/sample_directory.yaml:/data/directory.yaml yamldap:latest -f /data/directory.yaml
```
### Using Docker Compose
Using pre-built images from registry:
```bash
docker compose -f compose.registry.yml up
```
Or build and run locally:
```bash
docker compose up
```
## Quick Start
1. Create a YAML file defining your directory:
```yaml
directory:
base_dn: "dc=example,dc=com"
entries:
- dn: "dc=example,dc=com"
objectClass: ["top", "domain"]
dc: "example"
- dn: "ou=users,dc=example,dc=com"
objectClass: ["top", "organizationalUnit"]
ou: "users"
- dn: "uid=john,ou=users,dc=example,dc=com"
objectClass: ["top", "person", "inetOrgPerson"]
uid: "john"
cn: "John Doe"
sn: "Doe"
mail: "john@example.com"
userPassword: "secret123"
```
2. Start the server:
```bash
yamldap -f directory.yaml --port 3389
docker run -p 389:389 -v $(pwd)/directory.yaml:/data/directory.yaml ghcr.io/rvben/yamldap:latest -f /data/directory.yaml
docker run -p 389:389 -v $(pwd)/directory.yaml:/data/directory.yaml ghcr.io/rvben/yamldap:latest -f /data/directory.yaml --allow-anonymous
```
3. Test with LDAP tools:
```bash
ldapsearch -x -H ldap://localhost:3389 -b "dc=example,dc=com" "(objectClass=*)"
ldapsearch -x -H ldap://localhost:3389 \
-D "uid=john,ou=users,dc=example,dc=com" \
-w secret123 \
-b "dc=example,dc=com" "(uid=john)"
```
## Command Line Options
```
yamldap [OPTIONS]
Options:
-f, --file <FILE> Path to YAML directory file
-p, --port <PORT> Port to listen on [default: 389]
--bind-address <ADDR> Address to bind to [default: 0.0.0.0]
--allow-anonymous Allow anonymous bind operations
-v, --verbose Enable verbose logging
--log-level <LEVEL> Set log level: debug, info, warn, error [default: info]
-h, --help Print help
```
## YAML Directory Format
### Basic Structure
```yaml
directory:
base_dn: "dc=example,dc=com" # Required: Base DN for the directory
entries: # List of directory entries
- dn: "..." # Distinguished Name
objectClass: [...] # Object classes
attribute: value # Attributes and values
```
### Password Formats
```yaml
# Plain text (for testing only!)
userPassword: "plaintext"
# SHA hash
userPassword: "{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g="
# Salted SHA
userPassword: "{SSHA}DkMTwBl+a/3DfY+MTDTrcd5kMT8dpDkE"
# Bcrypt
userPassword: "$2b$10$..."
```
### Complete Example
See [examples/sample_directory.yaml](examples/sample_directory.yaml) for a full example with users, groups, and organizational units.
## Testing Scripts
### Python Test Script
```bash
./test_ldap.py
```
### Shell Test Script
```bash
./test_basic.sh
```
## Integration Examples
### Python
```python
import ldap
conn = ldap.initialize("ldap://localhost:389")
conn.simple_bind_s("uid=john,ou=users,dc=example,dc=com", "password")
results = conn.search_s("dc=example,dc=com", ldap.SCOPE_SUBTREE, "(uid=john)")
```
### Node.js
```javascript
const ldap = require('ldapjs');
const client = ldap.createClient({ url: 'ldap://localhost:389' });
client.bind('uid=john,ou=users,dc=example,dc=com', 'password', (err) => {
// Authenticated
});
```
### Java/Spring
```java
@Bean
public LdapContextSource contextSource() {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl("ldap://localhost:389");
contextSource.setBase("dc=example,dc=com");
contextSource.setUserDn("uid=john,ou=users,dc=example,dc=com");
contextSource.setPassword("password");
return contextSource;
}
```
## Development
### Running Tests
```bash
# Run all tests
cargo test
# Run with coverage report
make coverage
# Check test coverage percentage
make coverage-check
# Run benchmarks
make bench
```
### Building
```bash
# Build release version
cargo build --release
# Build Docker image (3.99MB scratch image)
make docker-build
```
### Code Quality
```bash
# Format code
cargo fmt
# Run linter
cargo clippy
# Run all CI checks
make ci
```
### Testing & Coverage
The project includes comprehensive unit tests with ~63% code coverage:
- 148 unit tests covering all major components
- Integration tests for LDAP operations
- Performance benchmarks with Criterion
- Test coverage reporting via cargo-tarpaulin
Run `make help` to see all available Make targets.
## Limitations
- Read-only operations (no add/modify/delete support yet)
- Basic LDAP v3 protocol support
- Limited search filter syntax
- No referral or alias support
- No TLS/SSL support yet
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
This project is dual-licensed under MIT OR Apache-2.0