Working after iterations
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -86,9 +86,13 @@ logs/
|
||||
*.bak
|
||||
*.tmp
|
||||
|
||||
# Environment files with secrets
|
||||
# Environment files
|
||||
# Note: .env is tracked and contains non-secret configuration (ports, etc.)
|
||||
# Add secrets only to .env.local which is ignored
|
||||
.env.local
|
||||
.env.*.local
|
||||
.env.production
|
||||
.env.development
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
|
||||
94
CHANGELOG.md
Normal file
94
CHANGELOG.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.1.0] - 2025-01-XX
|
||||
|
||||
### Added
|
||||
- Initial release of LDAP Docker development tool
|
||||
- OpenLDAP 1.5.0 container with SSL/TLS support
|
||||
- phpLDAPadmin web interface for easy administration
|
||||
- Pre-configured test users and groups for testing.local domain
|
||||
- SSL certificate generation script using Python cryptography
|
||||
- Comprehensive CLI tool for managing LDAP server (`ldap-docker` command)
|
||||
- Makefile with convenient shortcuts for common operations
|
||||
- Interactive quickstart script (`quickstart.sh`) for guided setup
|
||||
- Example Python authentication script demonstrating LDAP integration
|
||||
- Support for custom dev-ca certificates
|
||||
- Persistent Docker volumes for data and configuration
|
||||
- Test suite for certificate generation
|
||||
- Comprehensive documentation:
|
||||
- README.md - Full project documentation
|
||||
- GETTING_STARTED.md - Beginner-friendly guide
|
||||
- QUICKREF.md - Quick command reference
|
||||
- certs/README.md - Certificate management guide
|
||||
- examples/README.md - Integration patterns and examples
|
||||
|
||||
### Test Data
|
||||
- 4 pre-configured test users (admin, jdoe, jsmith, testuser)
|
||||
- 3 test groups (admins, developers, users)
|
||||
- All test users use password: `password123`
|
||||
- Admin credentials: `cn=admin,dc=testing,dc=local` / `admin_password`
|
||||
|
||||
### Infrastructure
|
||||
- Docker Compose configuration for easy deployment
|
||||
- UV package manager integration for Python dependencies
|
||||
- Cross-platform support (MacOS, Linux, Windows)
|
||||
- Rancher Desktop and Docker Desktop compatibility
|
||||
|
||||
### Fixed
|
||||
- Updated `pyproject.toml` to use `dependency-groups.dev` instead of deprecated `tool.uv.dev-dependencies`
|
||||
- Added `tool.hatch.build.targets.wheel.packages` configuration to fix build errors
|
||||
- Removed obsolete `version` field from `docker-compose.yml` (Docker Compose v2+ compatibility)
|
||||
- Fixed LDAP user password hashes to use proper SSHA format generated by `slappasswd`
|
||||
- Fixed attribute type conversion in example scripts for uidNumber and gidNumber
|
||||
|
||||
### Technical Details
|
||||
- Base DN: `dc=testing,dc=local`
|
||||
- LDAP Port: 389 (standard)
|
||||
- LDAPS Port: 636 (SSL/TLS)
|
||||
- Web Admin Port: 8080
|
||||
- Python 3.9+ required
|
||||
- Docker/Rancher Desktop required
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Planned Features
|
||||
- Additional integration examples (Node.js, Go, Ruby, etc.)
|
||||
- Health check endpoints
|
||||
- Automated backup scripts
|
||||
- Docker image with pre-built configuration
|
||||
- Kubernetes/Helm deployment examples
|
||||
- LDAP replication setup guide
|
||||
- Performance tuning guide
|
||||
- Security hardening options
|
||||
|
||||
---
|
||||
|
||||
## Release Notes
|
||||
|
||||
### Version 0.1.0
|
||||
This is the initial release providing a complete LDAP development environment suitable for:
|
||||
- Testing LDAP authentication in applications
|
||||
- Development and integration testing
|
||||
- Learning LDAP concepts
|
||||
- Prototyping LDAP-based systems
|
||||
|
||||
**Important Security Notes:**
|
||||
- This tool is for **DEVELOPMENT USE ONLY**
|
||||
- Default passwords are well-known and insecure
|
||||
- Self-signed certificates are not suitable for production
|
||||
- Never use this with real user data or in production environments
|
||||
|
||||
### Upgrade Instructions
|
||||
Not applicable for initial release.
|
||||
|
||||
### Breaking Changes
|
||||
Not applicable for initial release.
|
||||
|
||||
---
|
||||
|
||||
For support, issues, or feature requests, please refer to the project documentation or open an issue on the project repository.
|
||||
22
Makefile
22
Makefile
@@ -1,5 +1,11 @@
|
||||
.PHONY: help install init start stop restart down logs status certs-generate certs-check test-connection test-auth test-users clean clean-all
|
||||
|
||||
# Load environment variables from .env file if it exists
|
||||
ifneq (,$(wildcard ./.env))
|
||||
include .env
|
||||
export
|
||||
endif
|
||||
|
||||
# Default target
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
@@ -55,9 +61,9 @@ start: ## Start the LDAP server
|
||||
@echo "✅ LDAP server started"
|
||||
@echo ""
|
||||
@echo "Services available at:"
|
||||
@echo " - LDAP: ldap://localhost:389"
|
||||
@echo " - LDAPS: ldaps://localhost:636"
|
||||
@echo " - Admin: http://localhost:8080"
|
||||
@echo " - LDAP: ldap://localhost:$${LDAP_PORT:-389}"
|
||||
@echo " - LDAPS: ldaps://localhost:$${LDAPS_PORT:-636}"
|
||||
@echo " - Admin: http://localhost:$${PHPLDAPADMIN_PORT:-8080}"
|
||||
@echo ""
|
||||
@echo "Admin credentials:"
|
||||
@echo " DN: cn=admin,dc=testing,dc=local"
|
||||
@@ -105,19 +111,19 @@ status: ## Show container status
|
||||
|
||||
test-connection: ## Test connection to LDAP server
|
||||
@echo "Testing LDAP connection..."
|
||||
uv run python -c "from ldap3 import Server, Connection, ALL; s = Server('ldap://localhost:389', get_info=ALL); c = Connection(s, auto_bind=True); print('✅ Connection successful'); c.unbind()"
|
||||
@export LDAP_PORT=$${LDAP_PORT:-389}; uv run python -c "import os; from ldap3 import Server, Connection, ALL; s = Server(f\"ldap://localhost:{os.environ.get('LDAP_PORT', '389')}\", get_info=ALL); c = Connection(s, auto_bind=True); print('✅ Connection successful'); c.unbind()"
|
||||
|
||||
test-auth: ## Test authentication with admin user
|
||||
@echo "Testing LDAP authentication..."
|
||||
uv run python -c "from ldap3 import Server, Connection; s = Server('ldap://localhost:389'); c = Connection(s, 'cn=admin,dc=testing,dc=local', 'admin_password', auto_bind=True); print('✅ Authentication successful'); c.unbind()"
|
||||
@export LDAP_PORT=$${LDAP_PORT:-389}; uv run python -c "import os; from ldap3 import Server, Connection; s = Server(f\"ldap://localhost:{os.environ.get('LDAP_PORT', '389')}\"); c = Connection(s, 'cn=admin,dc=testing,dc=local', 'admin_password', auto_bind=True); print('✅ Authentication successful'); c.unbind()"
|
||||
|
||||
test-users: ## List all users in LDAP
|
||||
@echo "Listing LDAP users..."
|
||||
@uv run python -c "from ldap3 import Server, Connection; s = Server('ldap://localhost:389'); c = Connection(s, 'cn=admin,dc=testing,dc=local', 'admin_password', auto_bind=True); c.search('dc=testing,dc=local', '(objectClass=inetOrgPerson)', attributes=['uid', 'cn', 'mail']); [print(f' - {e.cn}: {e.uid} ({e.mail})') for e in c.entries]; c.unbind()"
|
||||
@export LDAP_PORT=$${LDAP_PORT:-389}; uv run python -c "import os; from ldap3 import Server, Connection; s = Server(f\"ldap://localhost:{os.environ.get('LDAP_PORT', '389')}\"); c = Connection(s, 'cn=admin,dc=testing,dc=local', 'admin_password', auto_bind=True); c.search('dc=testing,dc=local', '(objectClass=inetOrgPerson)', attributes=['uid', 'cn', 'mail']); [print(f' - {e.cn}: {e.uid} ({e.mail})') for e in c.entries]; c.unbind()"
|
||||
|
||||
test-ssl: ## Test SSL/TLS connection
|
||||
@echo "Testing LDAPS connection..."
|
||||
openssl s_client -connect localhost:636 -CAfile certs/ca.crt </dev/null
|
||||
openssl s_client -connect localhost:$${LDAPS_PORT:-636} -CAfile certs/ca.crt </dev/null
|
||||
|
||||
test-all: test-connection test-auth test-users ## Run all tests
|
||||
|
||||
@@ -126,7 +132,7 @@ shell: ## Open a shell in the LDAP container
|
||||
|
||||
ldapsearch: ## Run ldapsearch command (example query)
|
||||
@echo "Running ldapsearch..."
|
||||
ldapsearch -H ldap://localhost:389 -x -b "dc=testing,dc=local" -D "cn=admin,dc=testing,dc=local" -w admin_password
|
||||
ldapsearch -H ldap://localhost:$${LDAP_PORT:-389} -x -b "dc=testing,dc=local" -D "cn=admin,dc=testing,dc=local" -w admin_password
|
||||
|
||||
clean: ## Clean Python build artifacts
|
||||
@echo "Cleaning build artifacts..."
|
||||
|
||||
436
PORT_CONFIGURATION.md
Normal file
436
PORT_CONFIGURATION.md
Normal file
@@ -0,0 +1,436 @@
|
||||
# Port Configuration Guide
|
||||
|
||||
This guide explains how to configure custom ports for your LDAP Docker environment to avoid conflicts with other services.
|
||||
|
||||
## Quick Start
|
||||
|
||||
**To change ports, simply edit the `.env` file:**
|
||||
|
||||
```bash
|
||||
# Edit .env file
|
||||
LDAP_PORT=20389
|
||||
LDAPS_PORT=20636
|
||||
PHPLDAPADMIN_PORT=8080
|
||||
```
|
||||
|
||||
Then restart:
|
||||
```bash
|
||||
make down && make start
|
||||
```
|
||||
|
||||
That's it! All scripts and tools will automatically use your custom ports.
|
||||
|
||||
---
|
||||
|
||||
## Why Custom Ports?
|
||||
|
||||
You might want to use custom ports if:
|
||||
- You have another LDAP server running on standard ports (389/636)
|
||||
- Port 389 requires root/admin privileges
|
||||
- You're running multiple LDAP environments simultaneously
|
||||
- Your organization has specific port requirements
|
||||
|
||||
## Files Involved
|
||||
|
||||
The port configuration system uses these files:
|
||||
|
||||
### 1. `.env` - Your Configuration (Edit This!)
|
||||
```bash
|
||||
LDAP_PORT=20389 # Your custom LDAP port
|
||||
LDAPS_PORT=20636 # Your custom LDAPS port
|
||||
PHPLDAPADMIN_PORT=8080 # Web admin interface port
|
||||
```
|
||||
|
||||
### 2. `docker-compose.yml` - Uses Environment Variables
|
||||
```yaml
|
||||
ports:
|
||||
- "${LDAP_PORT:-389}:389" # Host:Container mapping
|
||||
- "${LDAPS_PORT:-636}:636"
|
||||
```
|
||||
|
||||
The `${LDAP_PORT:-389}` syntax means:
|
||||
- Use `$LDAP_PORT` if set in `.env`
|
||||
- Otherwise use default `389`
|
||||
|
||||
### 3. Scripts - Auto-detect Ports
|
||||
All Python scripts and Makefile commands read from `.env` automatically:
|
||||
- `scripts/cli.py`
|
||||
- `scripts/ldapsearch_helper.sh`
|
||||
- `examples/simple_auth.py`
|
||||
- `Makefile`
|
||||
|
||||
## How to Change Ports
|
||||
|
||||
### Method 1: Edit .env File (Recommended)
|
||||
|
||||
1. **Edit `.env`:**
|
||||
```bash
|
||||
vim .env # or your favorite editor
|
||||
```
|
||||
|
||||
2. **Change the port values:**
|
||||
```bash
|
||||
LDAP_PORT=20389
|
||||
LDAPS_PORT=20636
|
||||
```
|
||||
|
||||
3. **Restart the containers:**
|
||||
```bash
|
||||
make down && make start
|
||||
```
|
||||
|
||||
4. **Verify:**
|
||||
```bash
|
||||
docker-compose ps
|
||||
# Should show 0.0.0.0:20389->389/tcp
|
||||
```
|
||||
|
||||
### Method 2: Environment Variables (Temporary)
|
||||
|
||||
For one-time use without modifying `.env`:
|
||||
|
||||
```bash
|
||||
LDAP_PORT=30389 LDAPS_PORT=30636 docker-compose up -d
|
||||
```
|
||||
|
||||
### Method 3: Create .env.local (Advanced)
|
||||
|
||||
For personal overrides without modifying the main `.env`:
|
||||
|
||||
```bash
|
||||
# Create .env.local (git-ignored)
|
||||
echo "LDAP_PORT=12389" > .env.local
|
||||
echo "LDAPS_PORT=12636" >> .env.local
|
||||
|
||||
# Docker Compose will merge both files
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Testing with Custom Ports
|
||||
|
||||
### Automatic - Use Our Tools
|
||||
|
||||
All our tools automatically detect your ports from `.env`:
|
||||
|
||||
```bash
|
||||
# These all work automatically with your custom ports
|
||||
make test-users
|
||||
make test-connection
|
||||
uv run python examples/simple_auth.py
|
||||
```
|
||||
|
||||
### Generate ldapsearch Commands
|
||||
|
||||
Use our helper script to generate commands with your ports:
|
||||
|
||||
```bash
|
||||
./scripts/ldapsearch_helper.sh
|
||||
```
|
||||
|
||||
Output includes commands like:
|
||||
```bash
|
||||
# List all users
|
||||
ldapsearch -H ldap://localhost:20389 \
|
||||
-D "cn=admin,dc=testing,dc=local" \
|
||||
-w admin_password \
|
||||
-b "ou=people,dc=testing,dc=local" \
|
||||
"(objectClass=inetOrgPerson)" \
|
||||
uid cn mail
|
||||
```
|
||||
|
||||
### Manual ldapsearch Commands
|
||||
|
||||
Replace `389` with your `LDAP_PORT` and `636` with your `LDAPS_PORT`:
|
||||
|
||||
```bash
|
||||
# Standard LDAP (unencrypted)
|
||||
ldapsearch -H ldap://localhost:20389 \
|
||||
-D "cn=admin,dc=testing,dc=local" \
|
||||
-w admin_password \
|
||||
-b "dc=testing,dc=local"
|
||||
|
||||
# LDAPS (SSL/TLS)
|
||||
ldapsearch -H ldaps://localhost:20636 \
|
||||
-D "cn=admin,dc=testing,dc=local" \
|
||||
-w admin_password \
|
||||
-b "dc=testing,dc=local"
|
||||
|
||||
# Search for specific user
|
||||
ldapsearch -H ldap://localhost:20389 \
|
||||
-D "cn=admin,dc=testing,dc=local" \
|
||||
-w admin_password \
|
||||
-b "dc=testing,dc=local" \
|
||||
"(uid=jdoe)"
|
||||
|
||||
# Test user authentication
|
||||
ldapsearch -H ldap://localhost:20389 \
|
||||
-D "uid=jdoe,ou=people,dc=testing,dc=local" \
|
||||
-w password123 \
|
||||
-b "dc=testing,dc=local" \
|
||||
"(uid=jdoe)"
|
||||
```
|
||||
|
||||
### Using Python
|
||||
|
||||
```python
|
||||
import os
|
||||
from ldap3 import Server, Connection
|
||||
|
||||
# Automatically uses LDAP_PORT from environment
|
||||
port = os.environ.get('LDAP_PORT', '389')
|
||||
server = Server(f'ldap://localhost:{port}')
|
||||
conn = Connection(server,
|
||||
user='cn=admin,dc=testing,dc=local',
|
||||
password='admin_password',
|
||||
auto_bind=True)
|
||||
|
||||
conn.search('dc=testing,dc=local', '(objectClass=*)')
|
||||
print(f"Connected on port {port}")
|
||||
conn.unbind()
|
||||
```
|
||||
|
||||
## Common Port Configurations
|
||||
|
||||
### Development (Unprivileged Ports)
|
||||
```bash
|
||||
LDAP_PORT=20389
|
||||
LDAPS_PORT=20636
|
||||
PHPLDAPADMIN_PORT=8080
|
||||
```
|
||||
|
||||
### Testing (High Ports)
|
||||
```bash
|
||||
LDAP_PORT=30389
|
||||
LDAPS_PORT=30636
|
||||
PHPLDAPADMIN_PORT=8090
|
||||
```
|
||||
|
||||
### Multiple Environments
|
||||
```bash
|
||||
# Environment 1 (.env)
|
||||
LDAP_PORT=20389
|
||||
LDAPS_PORT=20636
|
||||
|
||||
# Environment 2 (separate directory or .env.local)
|
||||
LDAP_PORT=21389
|
||||
LDAPS_PORT=21636
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Port Already in Use
|
||||
|
||||
**Error:** `Bind for 0.0.0.0:20389 failed: port is already allocated`
|
||||
|
||||
**Check what's using the port:**
|
||||
```bash
|
||||
lsof -i :20389
|
||||
# or
|
||||
netstat -an | grep 20389
|
||||
```
|
||||
|
||||
**Solutions:**
|
||||
1. Stop the conflicting service
|
||||
2. Choose a different port in `.env`
|
||||
3. Use `make down` to stop this LDAP server first
|
||||
|
||||
### Scripts Not Using Custom Ports
|
||||
|
||||
**Problem:** Scripts still connect to port 389
|
||||
|
||||
**Solution:** Ensure `.env` is loaded:
|
||||
|
||||
1. **Check .env exists:**
|
||||
```bash
|
||||
ls -la .env
|
||||
```
|
||||
|
||||
2. **Verify ports are set:**
|
||||
```bash
|
||||
grep LDAP_PORT .env
|
||||
```
|
||||
|
||||
3. **Reload environment:**
|
||||
```bash
|
||||
source .env # For bash scripts
|
||||
make down && make start # Restart containers
|
||||
```
|
||||
|
||||
### Docker Compose Not Reading .env
|
||||
|
||||
**Problem:** Containers still on default ports
|
||||
|
||||
**Check:**
|
||||
```bash
|
||||
# View what Docker Compose sees
|
||||
docker-compose config | grep -A2 ports
|
||||
```
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Ensure .env is in project root
|
||||
pwd # Should be ldap_docker/
|
||||
ls .env # Should exist
|
||||
|
||||
# Force reload
|
||||
docker-compose down
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Can't Connect After Port Change
|
||||
|
||||
**Verify containers are running on correct ports:**
|
||||
```bash
|
||||
docker-compose ps
|
||||
# Should show: 0.0.0.0:20389->389/tcp
|
||||
```
|
||||
|
||||
**Test connectivity:**
|
||||
```bash
|
||||
# Test if port is listening
|
||||
nc -zv localhost 20389
|
||||
|
||||
# Test LDAP response
|
||||
ldapsearch -H ldap://localhost:20389 -x -b "" -s base
|
||||
```
|
||||
|
||||
**Check logs:**
|
||||
```bash
|
||||
make logs
|
||||
# Look for: "slapd starting"
|
||||
```
|
||||
|
||||
## Port Reference Table
|
||||
|
||||
| Service | Default Port | Docker Internal Port | Configurable Via |
|
||||
|---------|--------------|---------------------|------------------|
|
||||
| LDAP | 389 | 389 | `LDAP_PORT` in .env |
|
||||
| LDAPS | 636 | 636 | `LDAPS_PORT` in .env |
|
||||
| phpLDAPadmin | 8080 | 80 | `PHPLDAPADMIN_PORT` in .env |
|
||||
|
||||
**Note:** The "Docker Internal Port" (right side of mapping) never changes. Only the host port (left side) is configurable.
|
||||
|
||||
## Advanced: Port Mapping Explained
|
||||
|
||||
Docker port mapping format: `HOST:CONTAINER`
|
||||
|
||||
```yaml
|
||||
ports:
|
||||
- "20389:389"
|
||||
```
|
||||
|
||||
This means:
|
||||
- **20389** = Port on your Mac (accessible via `localhost:20389`)
|
||||
- **389** = Port inside the Docker container (LDAP's standard port)
|
||||
|
||||
The container always listens on 389 internally. We just map it to 20389 externally.
|
||||
|
||||
## Testing Multiple Configurations
|
||||
|
||||
Run multiple LDAP servers simultaneously:
|
||||
|
||||
```bash
|
||||
# Terminal 1: First instance
|
||||
cd ldap_docker_1
|
||||
echo "LDAP_PORT=20389" > .env
|
||||
echo "LDAPS_PORT=20636" >> .env
|
||||
make start
|
||||
|
||||
# Terminal 2: Second instance
|
||||
cd ldap_docker_2
|
||||
echo "LDAP_PORT=21389" > .env
|
||||
echo "LDAPS_PORT=21636" >> .env
|
||||
make start
|
||||
|
||||
# Now you have two LDAP servers running!
|
||||
ldapsearch -H ldap://localhost:20389 ... # Server 1
|
||||
ldapsearch -H ldap://localhost:21389 ... # Server 2
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use .env for configuration** - Don't hardcode ports in scripts
|
||||
2. **Document your ports** - Add comments in .env explaining your choices
|
||||
3. **Use unprivileged ports** - Ports above 1024 don't require root
|
||||
4. **Avoid common ports** - Skip 8080, 3000, 5000 (often used by other tools)
|
||||
5. **Be consistent** - If LDAP is 20389, make LDAPS 20636 (same prefix)
|
||||
|
||||
## Integration Examples
|
||||
|
||||
### Configure Your Application
|
||||
|
||||
After changing ports, update your application's LDAP configuration:
|
||||
|
||||
```python
|
||||
# Django settings.py
|
||||
AUTH_LDAP_SERVER_URI = "ldap://localhost:20389"
|
||||
|
||||
# Flask
|
||||
LDAP_HOST = "localhost"
|
||||
LDAP_PORT = 20389
|
||||
|
||||
# Environment variable
|
||||
export LDAP_URL="ldap://localhost:20389"
|
||||
```
|
||||
|
||||
### Using with Docker Networks
|
||||
|
||||
If your application is also in Docker:
|
||||
|
||||
```yaml
|
||||
# Your app's docker-compose.yml
|
||||
services:
|
||||
your-app:
|
||||
environment:
|
||||
LDAP_URL: "ldap://ldap-server:389" # Use container name and internal port
|
||||
networks:
|
||||
- ldap_docker_ldap-network # Connect to LDAP network
|
||||
|
||||
networks:
|
||||
ldap_docker_ldap-network:
|
||||
external: true
|
||||
```
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```bash
|
||||
# View current configuration
|
||||
cat .env | grep PORT
|
||||
|
||||
# Generate ldapsearch commands
|
||||
./scripts/ldapsearch_helper.sh
|
||||
|
||||
# Test connection on custom port
|
||||
make test-connection
|
||||
|
||||
# Check what ports containers are using
|
||||
docker-compose ps
|
||||
|
||||
# Change ports (example)
|
||||
echo "LDAP_PORT=12389" > .env
|
||||
echo "LDAPS_PORT=12636" >> .env
|
||||
make down && make start
|
||||
|
||||
# Verify new ports work
|
||||
make test-users
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
**To use custom ports:**
|
||||
1. Edit `LDAP_PORT` and `LDAPS_PORT` in `.env`
|
||||
2. Run `make down && make start`
|
||||
3. All tools automatically use your new ports!
|
||||
|
||||
**Need ldapsearch commands?**
|
||||
- Run `./scripts/ldapsearch_helper.sh`
|
||||
- Or manually replace 389 → your LDAP_PORT, 636 → your LDAPS_PORT
|
||||
|
||||
That's it! The port configuration system is designed to be simple and automatic.
|
||||
|
||||
---
|
||||
|
||||
**See Also:**
|
||||
- [README.md](README.md) - Full documentation
|
||||
- [GETTING_STARTED.md](GETTING_STARTED.md) - Setup guide
|
||||
- [QUICKREF.md](QUICKREF.md) - Command reference
|
||||
@@ -1,35 +1,33 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
openldap:
|
||||
image: osixia/openldap:1.5.0
|
||||
container_name: ldap-server
|
||||
hostname: ldap.testing.local
|
||||
container_name: ${LDAP_CONTAINER_NAME:-ldap-server}
|
||||
hostname: ${LDAP_HOSTNAME:-ldap.testing.local}
|
||||
environment:
|
||||
# Base domain configuration
|
||||
LDAP_ORGANISATION: "Testing Organization"
|
||||
LDAP_DOMAIN: "testing.local"
|
||||
LDAP_BASE_DN: "dc=testing,dc=local"
|
||||
LDAP_ORGANISATION: ${LDAP_ORGANISATION:-Testing Organization}
|
||||
LDAP_DOMAIN: ${LDAP_DOMAIN:-testing.local}
|
||||
LDAP_BASE_DN: ${LDAP_BASE_DN:-dc=testing,dc=local}
|
||||
|
||||
# Admin credentials (change these for production)
|
||||
LDAP_ADMIN_PASSWORD: "admin_password"
|
||||
LDAP_CONFIG_PASSWORD: "config_password"
|
||||
LDAP_ADMIN_PASSWORD: ${LDAP_ADMIN_PASSWORD:-admin_password}
|
||||
LDAP_CONFIG_PASSWORD: ${LDAP_CONFIG_PASSWORD:-config_password}
|
||||
|
||||
# SSL/TLS Configuration
|
||||
LDAP_TLS: "true"
|
||||
LDAP_TLS_CRT_FILENAME: "server.crt"
|
||||
LDAP_TLS_KEY_FILENAME: "server.key"
|
||||
LDAP_TLS_CA_CRT_FILENAME: "ca.crt"
|
||||
LDAP_TLS_VERIFY_CLIENT: "try"
|
||||
LDAP_TLS: ${LDAP_TLS:-true}
|
||||
LDAP_TLS_CRT_FILENAME: ${LDAP_TLS_CRT_FILENAME:-server.crt}
|
||||
LDAP_TLS_KEY_FILENAME: ${LDAP_TLS_KEY_FILENAME:-server.key}
|
||||
LDAP_TLS_CA_CRT_FILENAME: ${LDAP_TLS_CA_CRT_FILENAME:-ca.crt}
|
||||
LDAP_TLS_VERIFY_CLIENT: ${LDAP_TLS_VERIFY_CLIENT:-try}
|
||||
|
||||
# Logging
|
||||
LDAP_LOG_LEVEL: "256"
|
||||
LDAP_LOG_LEVEL: ${LDAP_LOG_LEVEL:-256}
|
||||
|
||||
ports:
|
||||
# Standard LDAP port
|
||||
- "389:389"
|
||||
- "${LDAP_PORT:-389}:389"
|
||||
# LDAPS (SSL) port
|
||||
- "636:636"
|
||||
- "${LDAPS_PORT:-636}:636"
|
||||
|
||||
volumes:
|
||||
# Custom certificates - place your dev-ca certs here
|
||||
@@ -52,12 +50,12 @@ services:
|
||||
# Optional: phpLDAPadmin for web-based management
|
||||
phpldapadmin:
|
||||
image: osixia/phpldapadmin:0.9.0
|
||||
container_name: ldap-admin
|
||||
container_name: ${PHPLDAPADMIN_CONTAINER_NAME:-ldap-admin}
|
||||
environment:
|
||||
PHPLDAPADMIN_LDAP_HOSTS: "openldap"
|
||||
PHPLDAPADMIN_HTTPS: "false"
|
||||
ports:
|
||||
- "8080:80"
|
||||
- "${PHPLDAPADMIN_PORT:-8080}:80"
|
||||
depends_on:
|
||||
- openldap
|
||||
networks:
|
||||
|
||||
@@ -11,6 +11,7 @@ Usage:
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
@@ -24,7 +25,8 @@ except ImportError:
|
||||
|
||||
|
||||
# Configuration
|
||||
LDAP_SERVER = "ldap://localhost:389"
|
||||
LDAP_PORT = os.environ.get("LDAP_PORT", "389")
|
||||
LDAP_SERVER = f"ldap://localhost:{LDAP_PORT}"
|
||||
LDAP_BASE_DN = "dc=testing,dc=local"
|
||||
LDAP_PEOPLE_OU = "ou=people,dc=testing,dc=local"
|
||||
LDAP_GROUPS_OU = "ou=groups,dc=testing,dc=local"
|
||||
@@ -104,8 +106,8 @@ class LDAPAuthenticator:
|
||||
"first_name": str(entry.givenName) if entry.givenName else "",
|
||||
"last_name": str(entry.sn),
|
||||
"email": str(entry.mail),
|
||||
"uid_number": int(entry.uidNumber) if entry.uidNumber else None,
|
||||
"gid_number": int(entry.gidNumber) if entry.gidNumber else None,
|
||||
"uid_number": int(str(entry.uidNumber)) if entry.uidNumber else None,
|
||||
"gid_number": int(str(entry.gidNumber)) if entry.gidNumber else None,
|
||||
"dn": entry.entry_dn,
|
||||
}
|
||||
conn.unbind()
|
||||
|
||||
@@ -25,7 +25,7 @@ cn: John Doe
|
||||
sn: Doe
|
||||
givenName: John
|
||||
mail: jdoe@testing.local
|
||||
userPassword: {SSHA}5en6G6MezRroT3XKqkdPOmY/BFQ= # password: password123
|
||||
userPassword: {SSHA}Vj/QLoVDZbjklfhV/e6JdTo8MUNRy9dN
|
||||
uidNumber: 10001
|
||||
gidNumber: 10001
|
||||
homeDirectory: /home/jdoe
|
||||
@@ -42,7 +42,7 @@ cn: Jane Smith
|
||||
sn: Smith
|
||||
givenName: Jane
|
||||
mail: jsmith@testing.local
|
||||
userPassword: {SSHA}5en6G6MezRroT3XKqkdPOmY/BFQ= # password: password123
|
||||
userPassword: {SSHA}Vj/QLoVDZbjklfhV/e6JdTo8MUNRy9dN
|
||||
uidNumber: 10002
|
||||
gidNumber: 10002
|
||||
homeDirectory: /home/jsmith
|
||||
@@ -59,7 +59,7 @@ cn: Admin User
|
||||
sn: User
|
||||
givenName: Admin
|
||||
mail: admin@testing.local
|
||||
userPassword: {SSHA}5en6G6MezRroT3XKqkdPOmY/BFQ= # password: password123
|
||||
userPassword: {SSHA}Vj/QLoVDZbjklfhV/e6JdTo8MUNRy9dN
|
||||
uidNumber: 10000
|
||||
gidNumber: 10000
|
||||
homeDirectory: /home/admin
|
||||
@@ -76,7 +76,7 @@ cn: Test User
|
||||
sn: User
|
||||
givenName: Test
|
||||
mail: testuser@testing.local
|
||||
userPassword: {SSHA}5en6G6MezRroT3XKqkdPOmY/BFQ= # password: password123
|
||||
userPassword: {SSHA}Vj/QLoVDZbjklfhV/e6JdTo8MUNRy9dN
|
||||
uidNumber: 10003
|
||||
gidNumber: 10003
|
||||
homeDirectory: /home/testuser
|
||||
|
||||
@@ -33,8 +33,11 @@ ldap-docker = "scripts.cli:main"
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.uv]
|
||||
dev-dependencies = [
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["scripts", "tests"]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"pytest>=7.4.0",
|
||||
"pytest-cov>=4.1.0",
|
||||
"black>=23.0.0",
|
||||
|
||||
@@ -6,6 +6,7 @@ This tool provides convenient commands for starting, stopping, and testing
|
||||
the LDAP server, as well as managing test users and certificates.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
@@ -27,8 +28,8 @@ PROJECT_ROOT = Path(__file__).parent.parent
|
||||
CERTS_DIR = PROJECT_ROOT / "certs"
|
||||
LDIF_DIR = PROJECT_ROOT / "ldif"
|
||||
DEFAULT_HOST = "localhost"
|
||||
DEFAULT_PORT = 389
|
||||
DEFAULT_LDAPS_PORT = 636
|
||||
DEFAULT_PORT = int(os.environ.get("LDAP_PORT", "389"))
|
||||
DEFAULT_LDAPS_PORT = int(os.environ.get("LDAPS_PORT", "636"))
|
||||
DEFAULT_BASE_DN = "dc=testing,dc=local"
|
||||
DEFAULT_ADMIN_DN = "cn=admin,dc=testing,dc=local"
|
||||
DEFAULT_ADMIN_PASSWORD = "admin_password"
|
||||
|
||||
195
scripts/ldapsearch_helper.sh
Executable file
195
scripts/ldapsearch_helper.sh
Executable file
@@ -0,0 +1,195 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# LDAP Search Helper
|
||||
# Generates ldapsearch commands configured for your environment
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Get the directory where this script is located
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# Load environment variables from .env if it exists
|
||||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||||
source "$PROJECT_ROOT/.env"
|
||||
fi
|
||||
|
||||
# Set defaults if not in environment
|
||||
LDAP_PORT=${LDAP_PORT:-389}
|
||||
LDAPS_PORT=${LDAPS_PORT:-636}
|
||||
LDAP_BASE_DN=${LDAP_BASE_DN:-dc=testing,dc=local}
|
||||
LDAP_ADMIN_PASSWORD=${LDAP_ADMIN_PASSWORD:-admin_password}
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}LDAP Search Command Generator${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
echo "Configuration:"
|
||||
echo " LDAP Port: $LDAP_PORT"
|
||||
echo " LDAPS Port: $LDAPS_PORT"
|
||||
echo " Base DN: $LDAP_BASE_DN"
|
||||
echo ""
|
||||
|
||||
# Function to print a command example
|
||||
print_cmd() {
|
||||
local description="$1"
|
||||
local command="$2"
|
||||
|
||||
echo -e "${GREEN}# $description${NC}"
|
||||
echo -e "${YELLOW}$command${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}Basic Connection Tests${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
|
||||
print_cmd "Test server is responding (anonymous bind)" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -x -b \"\" -s base"
|
||||
|
||||
print_cmd "Test with admin credentials" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"$LDAP_BASE_DN\""
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}Search Users${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
|
||||
print_cmd "List all users" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"ou=people,$LDAP_BASE_DN\" \"(objectClass=inetOrgPerson)\" uid cn mail"
|
||||
|
||||
print_cmd "Search for specific user (jdoe)" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"$LDAP_BASE_DN\" \"(uid=jdoe)\""
|
||||
|
||||
print_cmd "Test user authentication (as jdoe)" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"uid=jdoe,ou=people,$LDAP_BASE_DN\" -w password123 -b \"$LDAP_BASE_DN\" \"(uid=jdoe)\""
|
||||
|
||||
print_cmd "Get all user attributes for jdoe" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"ou=people,$LDAP_BASE_DN\" \"(uid=jdoe)\" '*' '+'"
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}Search Groups${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
|
||||
print_cmd "List all groups" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"ou=groups,$LDAP_BASE_DN\" \"(objectClass=groupOfNames)\" cn member"
|
||||
|
||||
print_cmd "Find groups for user jdoe" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"ou=groups,$LDAP_BASE_DN\" \"(member=uid=jdoe,ou=people,$LDAP_BASE_DN)\" cn"
|
||||
|
||||
print_cmd "Get members of developers group" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"ou=groups,$LDAP_BASE_DN\" \"(cn=developers)\" member"
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}LDAPS (SSL/TLS) Commands${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
|
||||
print_cmd "Test LDAPS connection" \
|
||||
"ldapsearch -H ldaps://localhost:$LDAPS_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"$LDAP_BASE_DN\""
|
||||
|
||||
print_cmd "LDAPS with CA certificate verification" \
|
||||
"LDAPTLS_CACERT=$PROJECT_ROOT/certs/ca.crt ldapsearch -H ldaps://localhost:$LDAPS_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"$LDAP_BASE_DN\""
|
||||
|
||||
print_cmd "Check SSL certificate" \
|
||||
"openssl s_client -connect localhost:$LDAPS_PORT -CAfile $PROJECT_ROOT/certs/ca.crt -showcerts"
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}Secure Commands (Password Prompt)${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
|
||||
print_cmd "Admin search with password prompt (more secure)" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"cn=admin,$LDAP_BASE_DN\" -W -b \"$LDAP_BASE_DN\""
|
||||
|
||||
print_cmd "User authentication with password prompt" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"uid=jdoe,ou=people,$LDAP_BASE_DN\" -W -b \"$LDAP_BASE_DN\" \"(uid=jdoe)\""
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}Advanced Queries${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
|
||||
print_cmd "Search with wildcard (all users starting with 'j')" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"ou=people,$LDAP_BASE_DN\" \"(uid=j*)\" uid cn"
|
||||
|
||||
print_cmd "Search by email domain" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"ou=people,$LDAP_BASE_DN\" \"(mail=*@testing.local)\" uid mail"
|
||||
|
||||
print_cmd "Count total users" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"ou=people,$LDAP_BASE_DN\" \"(objectClass=inetOrgPerson)\" dn | grep -c '^dn:'"
|
||||
|
||||
print_cmd "Export entire directory to LDIF file" \
|
||||
"ldapsearch -H ldap://localhost:$LDAP_PORT -D \"cn=admin,$LDAP_BASE_DN\" -w $LDAP_ADMIN_PASSWORD -b \"$LDAP_BASE_DN\" -LLL > ldap_backup.ldif"
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE}Quick Reference${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
echo "Common flags:"
|
||||
echo " -H : LDAP URI (ldap:// or ldaps://)"
|
||||
echo " -D : Bind DN (user to authenticate as)"
|
||||
echo " -w : Password (visible in process list)"
|
||||
echo " -W : Prompt for password (more secure)"
|
||||
echo " -x : Use simple authentication"
|
||||
echo " -b : Base DN to search from"
|
||||
echo " -s : Scope (base, one, sub)"
|
||||
echo " -LLL: LDIF output without comments"
|
||||
echo ""
|
||||
echo "Test credentials:"
|
||||
echo " Admin: cn=admin,$LDAP_BASE_DN / $LDAP_ADMIN_PASSWORD"
|
||||
echo " Test user: uid=jdoe,ou=people,$LDAP_BASE_DN / password123"
|
||||
echo ""
|
||||
echo -e "${GREEN}Tip:${NC} Copy any command above and run it in your terminal!"
|
||||
echo ""
|
||||
|
||||
# Option to run a command interactively
|
||||
if [ "$1" = "--interactive" ] || [ "$1" = "-i" ]; then
|
||||
echo ""
|
||||
echo "Select a command to run:"
|
||||
echo " 1) List all users"
|
||||
echo " 2) Search for user jdoe"
|
||||
echo " 3) Test user authentication"
|
||||
echo " 4) List all groups"
|
||||
echo " 5) Test LDAPS connection"
|
||||
echo " 6) Custom command"
|
||||
echo ""
|
||||
read -p "Choice (1-6): " choice
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
ldapsearch -H ldap://localhost:$LDAP_PORT -D "cn=admin,$LDAP_BASE_DN" -w $LDAP_ADMIN_PASSWORD -b "ou=people,$LDAP_BASE_DN" "(objectClass=inetOrgPerson)" uid cn mail
|
||||
;;
|
||||
2)
|
||||
ldapsearch -H ldap://localhost:$LDAP_PORT -D "cn=admin,$LDAP_BASE_DN" -w $LDAP_ADMIN_PASSWORD -b "$LDAP_BASE_DN" "(uid=jdoe)"
|
||||
;;
|
||||
3)
|
||||
read -p "Enter password for jdoe: " -s user_pass
|
||||
echo ""
|
||||
ldapsearch -H ldap://localhost:$LDAP_PORT -D "uid=jdoe,ou=people,$LDAP_BASE_DN" -w "$user_pass" -b "$LDAP_BASE_DN" "(uid=jdoe)"
|
||||
;;
|
||||
4)
|
||||
ldapsearch -H ldap://localhost:$LDAP_PORT -D "cn=admin,$LDAP_BASE_DN" -w $LDAP_ADMIN_PASSWORD -b "ou=groups,$LDAP_BASE_DN" "(objectClass=groupOfNames)" cn member
|
||||
;;
|
||||
5)
|
||||
LDAPTLS_CACERT=$PROJECT_ROOT/certs/ca.crt ldapsearch -H ldaps://localhost:$LDAPS_PORT -D "cn=admin,$LDAP_BASE_DN" -w $LDAP_ADMIN_PASSWORD -b "$LDAP_BASE_DN"
|
||||
;;
|
||||
6)
|
||||
read -p "Enter custom filter: " filter
|
||||
ldapsearch -H ldap://localhost:$LDAP_PORT -D "cn=admin,$LDAP_BASE_DN" -w $LDAP_ADMIN_PASSWORD -b "$LDAP_BASE_DN" "$filter"
|
||||
;;
|
||||
*)
|
||||
echo "Invalid choice"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
Reference in New Issue
Block a user