A transparent socket-based LDAP proxy that intelligently routes authentication requests to the correct Domain Controller based on the user's UPN (User Principal Name) domain.
Scenario: You're migrating from Domain A to Domain B. Users are split across two domains, but your legacy application only accepts ONE LDAP endpoint. Users who moved to Domain B can't authenticate anymore because their UPNs don't exist in Domain A.
Solution: A proxy that presents a single endpoint but intelligently routes authentication requests to the correct domain controller based on the user's UPN (user@domain.com).
Legacy App → LDAP Proxy (single endpoint) → Routes to correct DC
↓
john@domainA.com → DC-A (10.1.1.5)
jane@domainB.com → DC-B (10.2.2.5)
The proxy:
- Listens on a single port (389 or 3389)
- Accepts authentication requests
- Extracts the domain from the username (user@domain.com)
- Routes to the appropriate Domain Controller
- Returns the authentication result
- Transparent routing - Legacy apps don't need changes
- Multi-domain support - Route to different DCs based on UPN domain
- Configuration-driven - Add domains via JSON, no code changes
- Concurrent connections - Threading for multiple simultaneous authentications
- SSL/TLS support - Use LDAPS (port 636) for secure connections
- Comprehensive logging - Track all authentication attempts (passwords never logged)
- Production-ready - Includes systemd service, deployment guide
- Real-time monitoring - Live activity feed with WebSocket updates
- Statistics & charts - Visual insights with Chart.js (trends, success rates, domain breakdown)
- Configuration editor - Manage domains and settings via web interface
- Alert management - Create custom alerts for failed auth patterns
- Easy deployment - Modern web UI built with Flask and Bootstrap
- Python 3.8 or higher
- Network connectivity to Domain Controllers
- Domain Controllers with LDAP enabled (port 389 or 636)
pip install ldap3Edit ldap_proxy_config.json:
{
"listen_host": "0.0.0.0",
"listen_port": 3389,
"default_domain": "domainA.com",
"domain_routes": {
"domainA.com": {
"dc_host": "10.1.1.5",
"dc_port": 389,
"use_ssl": false
},
"domainB.com": {
"dc_host": "10.2.2.5",
"dc_port": 389,
"use_ssl": false
}
}
}python3 ldap_proxy.py# In another terminal
python3 test_client.py -u john@domainA.com -p password123The LDAP proxy includes a modern web dashboard for monitoring and configuration!
# Install web dependencies
pip install flask flask-socketio python-socketio
# Start the web dashboard (in addition to the proxy)
cd web_ui
python3 app.py
# Open in browser
# http://localhost:5000- Dashboard: Real-time authentication feed, statistics, domain breakdown
- Statistics: Interactive charts, trends, top users, domain stats
- Configuration: Visual editor for domain routes and settings
- Alerts: Create alerts for failed auth patterns, view trigger history
See WEB_UI_GUIDE.md for complete documentation!
{
"listen_host": "0.0.0.0",
"listen_port": 3389,
"connection_timeout": 30,
"default_domain": "domainA.com",
"domain_routes": {
"domainA.com": {
"dc_host": "dc1.domainA.com",
"dc_port": 389,
"use_ssl": false
},
"domainB.com": {
"dc_host": "dc1.domainB.com",
"dc_port": 636,
"use_ssl": true
}
}
}| Option | Description | Default |
|---|---|---|
listen_host |
Interface to bind to (0.0.0.0 = all) | 0.0.0.0 |
listen_port |
Port to listen on | 3389 |
connection_timeout |
Timeout for DC connections (seconds) | 30 |
default_domain |
Domain to use when username has no @domain | - |
domain_routes |
Map of domains to DC configurations | {} |
| Option | Description | Default |
|---|---|---|
dc_host |
Domain Controller hostname or IP | Required |
dc_port |
LDAP port (389 or 636 for SSL) | 389 |
use_ssl |
Use LDAPS (SSL/TLS) | false |
- Port 3389: Non-privileged port, good for testing (no root required)
- Port 389: Standard LDAP port (requires root or port forwarding)
For production on port 389, use iptables forwarding or setcap (see DEPLOYMENT_GUIDE.md).
Interactive mode:
python3 test_client.pySingle test:
python3 test_client.py -u john@domainA.com -p password123Different host/port:
python3 test_client.py -H 192.168.1.100 -P 389 -u john@domainA.com -p passVerify routing works for multiple domains:
python3 test_client.py -u user1@domainA.com -p password1
python3 test_client.py -u user2@domainB.com -p password2- Client connects to proxy (port 3389)
- Client sends username and password
- Proxy extracts domain from username (e.g.,
john@domainA.com→domainA.com) - Proxy looks up DC configuration for that domain
- Proxy connects to the correct DC (e.g., 10.1.1.5:389)
- Proxy attempts LDAP BIND with user credentials
- DC responds with success or failure
- Proxy returns result to client
All authentication attempts are logged:
2025-11-19 10:05:23 - INFO - New connection from ('192.168.1.100', 54321)
2025-11-19 10:05:23 - INFO - Attempting authentication for 'john@domainA.com' via DC: 10.1.1.5:389
2025-11-19 10:05:23 - INFO - ✓ Authentication SUCCESSFUL for 'john@domainA.com' via 10.1.1.5
2025-11-19 10:05:23 - INFO - Connection closed from ('192.168.1.100', 54321)
Important: Passwords are NEVER logged.
See DEPLOYMENT_GUIDE.md for complete deployment instructions including:
- Installing as a systemd service
- Port forwarding for port 389
- Security hardening
- Monitoring and logging
- Troubleshooting
# Copy files to production location
sudo cp ldap_proxy.py /opt/ldap-proxy/
sudo cp ldap_proxy_config.json /opt/ldap-proxy/
# Install dependencies
sudo pip3 install ldap3
# Create systemd service
sudo nano /etc/systemd/system/ldap-proxy.service
# Enable and start
sudo systemctl enable ldap-proxy
sudo systemctl start ldap-proxy
# Check status
sudo systemctl status ldap-proxyldap-proxy-project/
├── ldap_proxy.py # Main proxy server
├── ldap_proxy_config.json # Configuration (your settings)
├── ldap_proxy_config.example.json # Example configuration
├── test_client.py # Test client tool
├── DEPLOYMENT_GUIDE.md # Production deployment guide
├── README.md # This file
└── requirements.txt # Python dependencies
Simply edit the configuration file - no code changes needed:
{
"domain_routes": {
"domainA.com": {"dc_host": "10.1.1.5", "dc_port": 389},
"domainB.com": {"dc_host": "10.2.2.5", "dc_port": 389},
"domainC.com": {"dc_host": "10.3.3.5", "dc_port": 636, "use_ssl": true}
}
}Restart the proxy:
sudo systemctl restart ldap-proxy# Check configuration syntax
python3 -c "import json; json.load(open('ldap_proxy_config.json'))"
# Check port is not in use
sudo netstat -tlnp | grep 3389
# Check logs
sudo journalctl -u ldap-proxy -n 50# Test DC connectivity from proxy server
ldapsearch -x -H ldap://dc1.domainA.com:389 -b "" -s base
# Check proxy logs for routing
sudo journalctl -u ldap-proxy | grep "Attempting authentication"
# Verify username is in UPN format (user@domain.com)# Check firewall
sudo ufw status
sudo firewall-cmd --list-all
# Test connection
telnet localhost 3389
nc -zv localhost 3389- Use LDAPS (SSL/TLS) with Domain Controllers in production
- Firewall: Only allow traffic from application servers
- Use private network/VPN between proxy and DCs
- Run as non-privileged user
- Restrict config file permissions (
chmod 600) - Regular security updates
- Monitor authentication logs
- Alert on service failures
- Monitor failed authentication attempts
- Regular log review
- Track authentication patterns
The proxy uses threading to handle multiple concurrent authentications:
- Each connection gets its own thread
- Multiple users can authenticate simultaneously
- Lightweight - minimal resource usage
- Tested with hundreds of concurrent connections
Current version handles:
- ✓ LDAP BIND (authentication)
- ✓ Multiple domains
- ✓ SSL/TLS support
- ✓ Concurrent connections
Not implemented (yet):
- ✗ Full LDAP protocol (searches, adds, modifies)
- ✗ Connection pooling
- ✗ Health checks / automatic failover
- ✗ Load balancing across multiple DCs
For full LDAP proxy functionality, additional protocol operations would need to be implemented.
This proxy is perfect for:
- Domain migrations - Users split across multiple domains
- Legacy applications - Can only handle one LDAP endpoint
- Multi-tenant environments - Different customers on different domains
- Testing environments - Route test users to different DCs
- Gradual migrations - Transparent routing as users migrate
MIT
Contributions welcome! Areas for improvement:
- Connection pooling
- Health checks and failover
- Full LDAP protocol support
- Metrics/monitoring endpoints
- Load balancing
- Check logs:
sudo journalctl -u ldap-proxy - Test DC connectivity:
ldapsearch -x -H ldap://dc:389 - Verify configuration:
python3 -c "import json; json.load(open('config.json'))" - See DEPLOYMENT_GUIDE.md for detailed troubleshooting
- DEPLOYMENT_GUIDE.md - Complete production deployment guide
- ldap_proxy_config.example.json - Configuration examples
- test_client.py - Testing tool
The Bottom Line:
This proxy solves a real enterprise problem with simple, elegant code. It's transparent to users, configuration-driven, and production-ready. Perfect for domain migrations and legacy application support.