A modular LDAP gateway server that bridges LDAP authentication to various backends (MySQL/MongoDB/Proxmox). Built with Node.js and ldapjs, it separates directory lookups (user/group info) from authentication (password validation) for flexible integration with modern and legacy systems.
The project is structured as a modular monorepo with distinct responsibilities:
graph TB
subgraph "📦 @ldap-gateway/core (npm package)"
A[LdapEngine] --> B[AuthProvider Interface]
A --> C[DirectoryProvider Interface]
A --> D[Utilities & Error Handling]
end
subgraph "🚀 ldap-gateway-server (standalone)"
E[Server Implementation] --> F[Provider Factory]
E --> G[Configuration Loader]
F --> H[DB Backend]
F --> I[LDAP Backend]
F --> J[Proxmox Backend]
end
subgraph "📋 Distribution"
K[Binary Executable]
L[.deb/.rpm packages]
M[Homebrew Formula]
N[Docker Images]
end
A -.-> E
E --> K
E --> L
E --> M
E --> N
classDef coreStyle fill:#e1f5fe
classDef serverStyle fill:#f3e5f5
classDef distStyle fill:#e8f5e8
class A,B,C,D coreStyle
class E,F,G,H,I,J serverStyle
class K,L,M,N distStyle
sequenceDiagram
participant User as 👤 User
participant Client as 🖥️ SSH Client
participant SSSD as 🔐 SSSD
participant Gateway as 🌉 LDAP Gateway
participant Directory as 📁 Directory Backend
participant Auth as 🔑 Auth Backend
User->>Client: SSH login attempt
Client->>SSSD: Authenticate user
SSSD->>Gateway: LDAP bind request
Gateway->>Directory: Fetch user info
Directory-->>Gateway: User details + groups
Gateway->>Auth: Validate credentials
Auth-->>Gateway: Auth result
Gateway-->>SSSD: LDAP response
SSSD-->>Client: Access granted/denied
Client-->>User: Login success/failure
# Download latest release
curl -LO https://github.com/mieweb/LDAPServer/releases/latest/download/ldap-gateway-linux.tar.gz
tar -xzf ldap-gateway-linux.tar.gz
cd ldap-gateway-*
sudo ./install.shUbuntu/Debian:
curl -LO https://github.com/mieweb/LDAPServer/releases/latest/download/ldap-gateway_amd64.deb
sudo dpkg -i ldap-gateway_amd64.debRHEL/CentOS/Fedora:
curl -LO https://github.com/mieweb/LDAPServer/releases/latest/download/ldap-gateway.rpm
sudo rpm -i ldap-gateway.rpmmacOS (Homebrew):
brew tap mieweb/homebrew-tap
brew install ldap-gatewaygit clone https://github.com/mieweb/LDAPServer.git
cd LDAPServer
npm install
cp server/.env.example server/.env
# Edit .env with your configuration
./launch.shCreate or edit /etc/ldap-gateway/.env:
# Directory backend: where to find user/group information
DIRECTORY_BACKEND=sql # sql | mongodb | proxmox
# Authentication backends: how to validate passwords (comma-separated for multiple)
AUTH_BACKENDS=ldap # sql | mongodb | ldap | proxmox | notification | sql,ldap | ldap,notification
# LDAP Server Configuration
LDAP_BASE_DN=dc=company,dc=com
# SQL configuration (for any SQL-based system)
SQL_URL=mysql://ldap_user:secure_password@localhost:3306/your_database
SQL_QUERY_ONE_USER='SELECT * FROM users WHERE username = ?'
SQL_QUERY_GROUPS_BY_MEMBER='SELECT * FROM groups g WHERE JSON_CONTAINS(g.member_uids, JSON_QUOTE(?))'
SQL_QUERY_ALL_USERS='SELECT * FROM users'
SQL_QUERY_ALL_GROUPS='SELECT
g.gid_number,
g.name,
g.gid_number AS id,
GROUP_CONCAT(u.username) AS member_uids
FROM groups g
LEFT JOIN user_groups ug ON g.gid_number = ug.group_id
LEFT JOIN users u ON ug.user_id = u.id
GROUP BY g.gid_number, g.name
ORDER BY g.name'
# Security: Require authentication for search operations
# Default: true (authentication required for security)
# Set to false only for development/testing if you need anonymous access
REQUIRE_AUTH_FOR_SEARCH=true
# MongoDB configuration (for mongodb backends)
MONGO_URI=mongodb://localhost:27017/ldap_user_db
MONGO_DATABASE=ldap_user_db
# External LDAP/AD authentication
LDAP_BIND_DN=CN=ldap-service,OU=Service Accounts,DC=company,DC=com
LDAP_BIND_PASSWORD=ldap_service_password
AD_DOMAIN=company.comBy default, authentication is required before allowing LDAP search operations:
# Authentication required by default (recommended for security)
REQUIRE_AUTH_FOR_SEARCH=true # This is the default
# Only disable for development/testing if needed
# REQUIRE_AUTH_FOR_SEARCH=falseBehavior:
true(default): Clients must authenticate with valid credentials before searchingfalse: Allows anonymous searches - only use for development/testing
Example:
# Without authentication (fails when REQUIRE_AUTH_FOR_SEARCH=true)
ldapsearch -H ldaps://localhost:636 -x -b "dc=company,dc=com" "(uid=john)"
# Result: Insufficient access (error 50)
# With authentication (succeeds)
ldapsearch -H ldaps://localhost:636 -x -D "uid=john,dc=company,dc=com" -w password -b "dc=company,dc=com" "(uid=john)"
# Result: Returns user informationRecommendation: Set to true for all production environments to prevent unauthorized directory enumeration.
For LDAPS connections, you can configure which TLS versions and ciphers are allowed:
# Minimum TLS version (default: uses Node.js default, typically TLSv1.2)
# Options: TLSv1.2, TLSv1.3
TLS_MIN_VERSION=TLSv1.2
# Maximum TLS version (default: uses Node.js default, typically TLSv1.3)
# Options: TLSv1.2, TLSv1.3
TLS_MAX_VERSION=TLSv1.3
# Allowed ciphers (OpenSSL cipher list format)
# Leave empty/unset to use Node.js defaults
TLS_CIPHERS=TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-RSA-AES256-GCM-SHA384Recommended Settings for High Security:
# Enforce TLS 1.3 only (most secure, but may not work with older clients)
TLS_MIN_VERSION=TLSv1.3
TLS_MAX_VERSION=TLSv1.3Recommended Settings for Compatibility:
# Allow TLS 1.2 and 1.3 (good balance of security and compatibility)
TLS_MIN_VERSION=TLSv1.2
TLS_MAX_VERSION=TLSv1.3Testing TLS Configuration:
# Check which TLS versions are supported
openssl s_client -connect localhost:636 -tls1_2 </dev/null 2>&1 | grep "Protocol"
openssl s_client -connect localhost:636 -tls1_3 </dev/null 2>&1 | grep "Protocol"
# Check available ciphers
openssl s_client -connect localhost:636 -cipher 'HIGH' </dev/null 2>&1 | grep "Cipher"Notes:
- TLS 1.0 and 1.1 are not supported (deprecated and insecure)
- When both
TLS_MIN_VERSIONandTLS_MAX_VERSIONare unset, Node.js defaults apply - Invalid version combinations (min > max) will be rejected with a warning and defaults will be used
- Cipher validation: Invalid cipher strings are validated at startup and rejected with a warning
- If an invalid cipher string is provided, Node.js defaults will be used instead
- This prevents runtime connection failures from misconfigured ciphers
- Common cipher string formats:
- Single cipher:
TLS_AES_256_GCM_SHA384 - Multiple ciphers:
TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES256-GCM-SHA384 - Cipher expressions:
HIGH:!aNULL:!MD5(excludes weak ciphers)
- Single cipher:
# Using systemd (installed packages)
sudo systemctl enable ldap-gateway
sudo systemctl start ldap-gateway
# Or run directly
ldap-gateway
# Development mode
npm run devThe LDAP gateway separates directory lookups from authentication, allowing flexible mixing:
| Backend | Description | Use Case |
|---|---|---|
sql |
MySQL/MariaDB/SQLite3/PostgreSQL databases | Any SQL-based system (WebChart, custom schemas) |
mongodb |
MongoDB collections | Modern web applications |
proxmox |
Proxmox user.cfg/shadow.cfg files | Virtualization environments |
Multiple backends supported - Use comma-separated values (e.g., AUTH_BACKENDS=sql,ldap) to try authentication providers in order.
| Backend | Description | Use Case |
|---|---|---|
sql |
MySQL/MariaDB/SQLite3/PostgreSQL password hashes | Self-contained auth with SQL databases |
mongodb |
MongoDB password hashes | Self-contained auth with MongoDB collections |
ldap |
External LDAP/Active Directory | Enterprise SSO integration |
proxmox |
Proxmox shadow file | Proxmox container authentication |
notification |
MFA push notifications via mobile app | Two-factor authentication, enhanced security |
DIRECTORY_BACKEND=sql # User info from MySQL
AUTH_BACKENDS=ldap # Passwords via AD
AD_DOMAIN=your-domain.com
LDAP_BIND_DN=CN=service,DC=your-domain,DC=com
SQL_URL=mysql://ldap_user:secure_password@localhost:3306/your_database
SQL_QUERY_ONE_USER='SELECT * FROM users WHERE username = ?'
SQL_QUERY_GROUPS_BY_MEMBER='SELECT * FROM groups g WHERE JSON_CONTAINS(g.member_uids, JSON_QUOTE(?))'
SQL_QUERY_ALL_USERS='SELECT * FROM users'
SQL_QUERY_ALL_GROUPS='SELECT
g.gid_number,
g.name,
g.gid_number AS id,
GROUP_CONCAT(u.username) AS member_uids
FROM groups g
LEFT JOIN user_groups ug ON g.gid_number = ug.group_id
LEFT JOIN users u ON ug.user_id = u.id
GROUP BY g.gid_number, g.name
ORDER BY g.name'DIRECTORY_BACKEND=mysql # User info from MySQL
AUTH_BACKENDS=mysql # Passwords in MySQL
SQL_URL=mysql://ldap_user:secure_password@localhost:3306/your_database
SQL_QUERY_ONE_USER='SELECT * FROM users WHERE username = ?'
SQL_QUERY_GROUPS_BY_MEMBER='SELECT * FROM groups g WHERE JSON_CONTAINS(g.member_uids, JSON_QUOTE(?))'
SQL_QUERY_ALL_USERS='SELECT * FROM users'
SQL_QUERY_ALL_GROUPS='SELECT
g.gid_number,
g.name,
g.gid_number AS id,
GROUP_CONCAT(u.username) AS member_uids
FROM groups g
LEFT JOIN user_groups ug ON g.gid_number = ug.group_id
LEFT JOIN users u ON ug.user_id = u.id
GROUP BY g.gid_number, g.name
ORDER BY g.name'DIRECTORY_BACKEND=mongodb # User info from MongoDB
AUTH_BACKENDS=mongodb # Passwords in MongoDB
MONGO_URI=mongodb://localhost:27017/users
MONGO_DATABASE=usersDIRECTORY_BACKEND=proxmox # Users from Proxmox config
AUTH_BACKENDS=proxmox # Passwords from Proxmox
PROXMOX_USER_CFG=/etc/pve/user.cfg
PROXMOX_SHADOW_CFG=/etc/pve/shadow.cfg🎥 Multiple Backends Demo - See how to configure multiple authentication backends
DIRECTORY_BACKEND=sql # User info from SQL
AUTH_BACKENDS=sql,ldap # Try SQL auth first, fallback to LDAP
SQL_URL=mysql://ldap_user:secure_password@localhost:3306/your_database
SQL_QUERY_ONE_USER='SELECT * FROM users WHERE username = ?'
SQL_QUERY_GROUPS_BY_MEMBER='SELECT * FROM groups g WHERE JSON_CONTAINS(g.member_uids, JSON_QUOTE(?))'
SQL_QUERY_ALL_USERS='SELECT * FROM users'
SQL_QUERY_ALL_GROUPS='SELECT
g.gid_number,
g.name,
g.gid_number AS id,
GROUP_CONCAT(u.username) AS member_uids
FROM groups g
LEFT JOIN user_groups ug ON g.gid_number = ug.group_id
LEFT JOIN users u ON ug.user_id = u.id
GROUP BY g.gid_number, g.name
ORDER BY g.name'
AD_DOMAIN=your-domain.com
LDAP_BIND_DN=CN=service,DC=your-domain,DC=comDIRECTORY_BACKEND=sql # User info from MySQL
AUTH_BACKENDS=ldap,notification # LDAP auth + MFA push notifications
AD_DOMAIN=your-domain.com
LDAP_BIND_DN=CN=service,DC=your-domain,DC=com
SQL_URL=mysql://ldap_user:secure_password@localhost:3306/your_database
SQL_QUERY_ONE_USER='SELECT * FROM users WHERE username = ?'
SQL_QUERY_GROUPS_BY_MEMBER='SELECT * FROM groups g WHERE JSON_CONTAINS(g.member_uids, JSON_QUOTE(?))'
SQL_QUERY_ALL_USERS='SELECT * FROM users'
SQL_QUERY_ALL_GROUPS='SELECT
g.gid_number,
g.name,
g.gid_number AS id,
GROUP_CONCAT(u.username) AS member_uids
FROM groups g
LEFT JOIN user_groups ug ON g.gid_number = ug.group_id
LEFT JOIN users u ON ug.user_id = u.id
GROUP BY g.gid_number, g.name
ORDER BY g.name'
# MFA Configuration (requires MIE Authenticator app)
ENABLE_NOTIFICATION=true
NOTIFICATION_URL=https://your-notification-service.comNEW: Create your own backends without rebuilding! Place JavaScript files in server/backends/ to add custom authentication or directory providers.
- Create a custom auth backend (
server/backends/my-auth.js):
const { AuthProvider } = require('@ldap-gateway/core');
class MyAuthBackend extends AuthProvider {
async authenticate(username, password) {
// Your custom authentication logic
return await myApiCall(username, password);
}
}
module.exports = {
name: 'my-auth',
type: 'auth',
provider: MyAuthBackend
};- Configure to use it:
AUTH_BACKENDS=my-auth- Restart the server - your backend loads automatically!
- ✅ No rebuild required - just add JS files
- ✅ Hot reload support - change files without restarting
- ✅ Full access to core interfaces - use AuthProvider and DirectoryProvider
- ✅ Template included -
server/backends/template.jsto get started - ✅ Examples provided - See
server/backends/*.example.js
🎥 Quick Demo - See custom backend creation in action
📚 Full documentation: See server/backends/README.md for complete guide with examples.
# Search for users
ldapsearch -x -H ldaps://localhost:636 -b "dc=company,dc=com" "(uid=john)"
# List all users
ldapsearch -x -H ldaps://localhost:636 -b "dc=company,dc=com" "(objectClass=posixAccount)"
# List groups
ldapsearch -x -H ldaps://localhost:636 -b "dc=company,dc=com" "(objectClass=posixGroup)"# Test SSH authentication through SSSD
ssh john@ldap-client-host
# Test with specific port
ssh john@localhost -p 2222# Check service status
systemctl status ldap-gateway
# View logs
journalctl -u ldap-gateway -f
# Test configuration
ldap-gateway --config-testThe LDAP Gateway integrates with WebChart EHR systems using the SQL backend:
DIRECTORY_BACKEND=sql # WebChart uses MySQL
AUTH_BACKENDS=sql
SQL_URL=mysql://ldap_user:secure_password@localhost:3306/your_database
# TODO: implement queries matching the webchart schemaWebChart users are mapped to standard LDAP objects with healthcare-specific attributes and group memberships based on WebChart realms.
Direct integration with Proxmox virtualization environments:
- Container Authentication → Centralized LDAP for all containers/VMs
- Configuration Syncing → Reads directly from Proxmox user/shadow files
- MFA Support → Optional push notifications via MIE Authenticator
- Automated Setup → Use pown.sh for container LDAP client configuration
# Install in Proxmox container
pct create 100 --template debian-12 --hostname ldap-gateway
pct set 100 --mp0 /etc/pve,mp=/etc/pve:ro # Mount Proxmox config
pct start 100
pct enter 100
# Install LDAP Gateway
curl -L https://github.com/mieweb/LDAPServer/releases/latest/download/ldap-gateway_amd64.deb
dpkg -i ldap-gateway_amd64.deb
# Configure for Proxmox
cat > /etc/ldap-gateway/.env << EOF
DIRECTORY_BACKEND=proxmox
AUTH_BACKENDS=proxmox
PROXMOX_USER_CFG=/etc/pve/user.cfg
PROXMOX_SHADOW_CFG=/etc/pve/shadow.cfg
EOF
systemctl enable --now ldap-gatewayLDAPServer/
├── npm/ # @ldap-gateway/core package
│ ├── src/ # Core interfaces and utilities
│ ├── dist/ # Built package
│ └── package.json # Core package definition
├── server/ # ldap-gateway-server package
│ ├── src/ # Server implementation
│ ├── dist/ # Built server
│ └── package.json # Server package definition
├── .github/workflows/ # CI/CD automation
├── nfpm/ # Package configuration
├── docker/ # Development containers
└── terraform/ # AWS deployment
# Install dependencies
npm install
# Build core package
npm run build:core
# Build server package
npm run build:server
# Create binary
npm run build:binary
# Build packages (.deb/.rpm)
nfpm package --packager deb# Run all tests
npm test
# Test specific package
npm run test:core
npm run test:server
# Integration testing with Docker
./launch.sh # Starts MySQL + test client
./shutdown.sh # Cleanup- Fork and clone the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes with tests
- Run the test suite:
npm test - Submit a pull request
- 🎬 Quick Demo - Complete walkthrough shorts
- 📖 API Documentation - Core package usage
- 🔧 Server Configuration - Server setup guide
- 🏥 WebChart Integration - Healthcare deployment
- 📱 MIE Authenticator - MFA mobile app
- 🛠️ pown.sh - Container automation
sequenceDiagram
participant User as ann (User)
participant Client as Client (SSHD)
participant SSSD as SSSD
participant CustomLDAP as Custom LDAPServer (ldapjs)
participant DB as Database (MySQL/MongoDB)
participant AuthSys as Authentication System (AD/LDAP)
User->>Client: SSH login request (ann)
Client->>SSSD: Authenticate user (ann)
%% User information lookup
SSSD->>CustomLDAP: Fetch user info (id, groups)
CustomLDAP->>DB: Check if user exists
DB-->>CustomLDAP: User exists
CustomLDAP-->>SSSD: Return user info + group memberships
%% Password verification via your custom LDAP server connecting to auth system
SSSD->>CustomLDAP: Verify user credentials
CustomLDAP->>AuthSys: Forward authentication request
AuthSys-->>CustomLDAP: Authentication result
CustomLDAP-->>SSSD: Forward authentication result
%% Group membership and final authorization
SSSD-->>Client: Authentication success/failure
Client-->>User: Login allowed/denied
sequenceDiagram
participant User as ann (User)
participant Client as Client (SSHD)
participant SSSD as SSSD
participant CustomLDAP as Custom LDAPServer (ldapjs)
participant DB as Database (MySQL/MongoDB)
participant AuthSys as Authentication System (AD/LDAP)
participant NotifSvc as Notification Service
User->>Client: SSH login request (ann)
Client->>SSSD: Authenticate user (ann)
SSSD->>CustomLDAP: Check user authentication
CustomLDAP->>DB: Check if user exists
DB-->>CustomLDAP: User exists
CustomLDAP->>AuthSys: Authenticate user credentials
AuthSys-->>CustomLDAP: Authentication successful
CustomLDAP-->>SSSD: Authentication successful
SSSD-->>Client: Authentication successful
CustomLDAP->>NotifSvc: Send notification for approval
NotifSvc-->>User: Push notification to phone
User-->>NotifSvc: Approve SSH request
NotifSvc-->>CustomLDAP: Send approval response
CustomLDAP-->>Client: Allow SSH login
MIT License - see LICENSE file for details.
Built with ❤️ by MIEWeb for healthcare and enterprise environments.