Release v0.1.0
- Initial release of LDAP Docker development tool - Full .env configuration support with comprehensive documentation - Pre-configured test users and SSL/TLS support - Consolidated documentation in README
This commit is contained in:
@@ -5,9 +5,7 @@ This package contains management and utility scripts for the LDAP Docker
|
||||
development environment.
|
||||
|
||||
Modules:
|
||||
- cli: Command-line interface for managing LDAP server
|
||||
- generate_certs: SSL/TLS certificate generation utility
|
||||
"""
|
||||
|
||||
__version__ = "0.1.0"
|
||||
__all__ = ["cli", "generate_certs"]
|
||||
|
||||
464
scripts/cli.py
464
scripts/cli.py
@@ -1,464 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
CLI tool for managing the LDAP Docker development environment.
|
||||
|
||||
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
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
import click
|
||||
|
||||
try:
|
||||
import ldap3
|
||||
from ldap3 import ALL, Connection, Server
|
||||
from ldap3.core.exceptions import LDAPException
|
||||
except ImportError:
|
||||
ldap3 = None
|
||||
|
||||
|
||||
# Constants
|
||||
PROJECT_ROOT = Path(__file__).parent.parent
|
||||
CERTS_DIR = PROJECT_ROOT / "certs"
|
||||
LDIF_DIR = PROJECT_ROOT / "ldif"
|
||||
DEFAULT_HOST = "localhost"
|
||||
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"
|
||||
|
||||
|
||||
def run_command(cmd: list[str], cwd: Optional[Path] = None, check: bool = True) -> subprocess.CompletedProcess:
|
||||
"""Run a shell command and return the result."""
|
||||
if cwd is None:
|
||||
cwd = PROJECT_ROOT
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=check,
|
||||
)
|
||||
return result
|
||||
except subprocess.CalledProcessError as e:
|
||||
click.echo(f"Error running command: {' '.join(cmd)}", err=True)
|
||||
click.echo(f"Exit code: {e.returncode}", err=True)
|
||||
if e.stdout:
|
||||
click.echo(f"stdout: {e.stdout}", err=True)
|
||||
if e.stderr:
|
||||
click.echo(f"stderr: {e.stderr}", err=True)
|
||||
raise
|
||||
|
||||
|
||||
def check_docker():
|
||||
"""Check if Docker is available."""
|
||||
try:
|
||||
result = run_command(["docker", "version"], check=False)
|
||||
if result.returncode != 0:
|
||||
click.echo("Error: Docker is not running or not installed.", err=True)
|
||||
click.echo("Please ensure Docker (or Rancher Desktop) is running.", err=True)
|
||||
sys.exit(1)
|
||||
except FileNotFoundError:
|
||||
click.echo("Error: Docker command not found.", err=True)
|
||||
click.echo("Please install Docker or Rancher Desktop.", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def check_certificates():
|
||||
"""Check if SSL certificates exist."""
|
||||
required_files = ["ca.crt", "server.crt", "server.key"]
|
||||
missing = [f for f in required_files if not (CERTS_DIR / f).exists()]
|
||||
|
||||
if missing:
|
||||
click.echo("⚠️ Warning: Missing SSL certificate files:", err=True)
|
||||
for f in missing:
|
||||
click.echo(f" - {CERTS_DIR / f}", err=True)
|
||||
click.echo("\nYou can:", err=True)
|
||||
click.echo(" 1. Copy your dev-ca certificates to the certs/ directory", err=True)
|
||||
click.echo(" 2. Generate self-signed certificates: ldap-docker certs generate", err=True)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@click.group()
|
||||
@click.version_option(version="0.1.0")
|
||||
def cli():
|
||||
"""LDAP Docker Development Tool - Manage your OpenLDAP development environment."""
|
||||
pass
|
||||
|
||||
|
||||
@cli.group()
|
||||
def server():
|
||||
"""Manage the LDAP server container."""
|
||||
pass
|
||||
|
||||
|
||||
@server.command("start")
|
||||
@click.option("--detach", "-d", is_flag=True, default=True, help="Run in detached mode")
|
||||
@click.option("--build", is_flag=True, help="Build images before starting")
|
||||
def server_start(detach: bool, build: bool):
|
||||
"""Start the LDAP server and optional phpLDAPadmin."""
|
||||
check_docker()
|
||||
check_certificates()
|
||||
|
||||
cmd = ["docker-compose", "up"]
|
||||
if detach:
|
||||
cmd.append("-d")
|
||||
if build:
|
||||
cmd.append("--build")
|
||||
|
||||
click.echo("Starting LDAP server...")
|
||||
result = run_command(cmd)
|
||||
|
||||
if result.returncode == 0:
|
||||
click.echo("✅ LDAP server started successfully!")
|
||||
click.echo(f"\nLDAP server is available at:")
|
||||
click.echo(f" - LDAP: ldap://localhost:389")
|
||||
click.echo(f" - LDAPS: ldaps://localhost:636")
|
||||
click.echo(f" - Admin: http://localhost:8080 (phpLDAPadmin)")
|
||||
click.echo(f"\nAdmin credentials:")
|
||||
click.echo(f" - DN: {DEFAULT_ADMIN_DN}")
|
||||
click.echo(f" - Password: {DEFAULT_ADMIN_PASSWORD}")
|
||||
|
||||
if detach:
|
||||
click.echo("\nWaiting for server to be ready...")
|
||||
time.sleep(5)
|
||||
# Try to check if server is responding
|
||||
result = run_command(
|
||||
["docker-compose", "ps", "--filter", "status=running"],
|
||||
check=False
|
||||
)
|
||||
if "ldap-server" in result.stdout:
|
||||
click.echo("✅ Server is running")
|
||||
|
||||
|
||||
@server.command("stop")
|
||||
def server_stop():
|
||||
"""Stop the LDAP server."""
|
||||
check_docker()
|
||||
|
||||
click.echo("Stopping LDAP server...")
|
||||
run_command(["docker-compose", "stop"])
|
||||
click.echo("✅ LDAP server stopped")
|
||||
|
||||
|
||||
@server.command("restart")
|
||||
def server_restart():
|
||||
"""Restart the LDAP server."""
|
||||
check_docker()
|
||||
|
||||
click.echo("Restarting LDAP server...")
|
||||
run_command(["docker-compose", "restart"])
|
||||
click.echo("✅ LDAP server restarted")
|
||||
|
||||
click.echo("\nWaiting for server to be ready...")
|
||||
time.sleep(5)
|
||||
|
||||
|
||||
@server.command("down")
|
||||
@click.option("--volumes", "-v", is_flag=True, help="Remove volumes (deletes all data)")
|
||||
def server_down(volumes: bool):
|
||||
"""Stop and remove the LDAP server containers."""
|
||||
check_docker()
|
||||
|
||||
cmd = ["docker-compose", "down"]
|
||||
if volumes:
|
||||
if not click.confirm("⚠️ This will delete all LDAP data. Continue?"):
|
||||
click.echo("Aborted.")
|
||||
return
|
||||
cmd.append("-v")
|
||||
|
||||
click.echo("Removing LDAP server containers...")
|
||||
run_command(cmd)
|
||||
click.echo("✅ Containers removed")
|
||||
|
||||
|
||||
@server.command("logs")
|
||||
@click.option("--follow", "-f", is_flag=True, help="Follow log output")
|
||||
@click.option("--tail", "-n", default=100, help="Number of lines to show from the end")
|
||||
@click.option("--service", default="openldap", help="Service to show logs for")
|
||||
def server_logs(follow: bool, tail: int, service: str):
|
||||
"""View LDAP server logs."""
|
||||
check_docker()
|
||||
|
||||
cmd = ["docker-compose", "logs", f"--tail={tail}"]
|
||||
if follow:
|
||||
cmd.append("-f")
|
||||
cmd.append(service)
|
||||
|
||||
# For follow mode, we want to pass through to the terminal
|
||||
try:
|
||||
subprocess.run(cmd, cwd=PROJECT_ROOT)
|
||||
except KeyboardInterrupt:
|
||||
click.echo("\n")
|
||||
|
||||
|
||||
@server.command("status")
|
||||
def server_status():
|
||||
"""Check LDAP server status."""
|
||||
check_docker()
|
||||
|
||||
result = run_command(["docker-compose", "ps"], check=False)
|
||||
click.echo(result.stdout)
|
||||
|
||||
|
||||
@cli.group()
|
||||
def certs():
|
||||
"""Manage SSL/TLS certificates."""
|
||||
pass
|
||||
|
||||
|
||||
@certs.command("generate")
|
||||
@click.option("--force", is_flag=True, help="Overwrite existing certificates")
|
||||
@click.option("--hostname", default="ldap.testing.local", help="Server hostname")
|
||||
def certs_generate(force: bool, hostname: str):
|
||||
"""Generate self-signed SSL certificates for development."""
|
||||
script_path = PROJECT_ROOT / "scripts" / "generate_certs.py"
|
||||
|
||||
if not script_path.exists():
|
||||
click.echo(f"Error: Certificate generation script not found: {script_path}", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
cmd = [sys.executable, str(script_path), "--hostname", hostname]
|
||||
if force:
|
||||
cmd.append("--force")
|
||||
|
||||
try:
|
||||
subprocess.run(cmd, check=True)
|
||||
except subprocess.CalledProcessError:
|
||||
click.echo("Failed to generate certificates", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@certs.command("check")
|
||||
def certs_check():
|
||||
"""Verify SSL certificates."""
|
||||
required_files = {
|
||||
"ca.crt": "CA Certificate",
|
||||
"server.crt": "Server Certificate",
|
||||
"server.key": "Server Private Key",
|
||||
}
|
||||
|
||||
click.echo("Checking SSL certificates...\n")
|
||||
|
||||
all_exist = True
|
||||
for filename, description in required_files.items():
|
||||
filepath = CERTS_DIR / filename
|
||||
if filepath.exists():
|
||||
size = filepath.stat().st_size
|
||||
click.echo(f"✅ {description}: {filepath} ({size} bytes)")
|
||||
else:
|
||||
click.echo(f"❌ {description}: {filepath} (missing)")
|
||||
all_exist = False
|
||||
|
||||
if all_exist:
|
||||
click.echo("\n✅ All required certificates are present")
|
||||
|
||||
# Try to verify the certificate chain
|
||||
try:
|
||||
result = run_command([
|
||||
"openssl", "verify", "-CAfile",
|
||||
str(CERTS_DIR / "ca.crt"),
|
||||
str(CERTS_DIR / "server.crt")
|
||||
], check=False)
|
||||
|
||||
if result.returncode == 0:
|
||||
click.echo("✅ Certificate chain is valid")
|
||||
else:
|
||||
click.echo("⚠️ Certificate chain verification failed")
|
||||
click.echo(result.stderr)
|
||||
except FileNotFoundError:
|
||||
click.echo("ℹ️ OpenSSL not found, skipping certificate verification")
|
||||
else:
|
||||
click.echo("\n❌ Some certificates are missing")
|
||||
click.echo("Run 'ldap-docker certs generate' to create them")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@cli.group()
|
||||
def test():
|
||||
"""Test LDAP server connectivity and queries."""
|
||||
pass
|
||||
|
||||
|
||||
@test.command("connection")
|
||||
@click.option("--host", default=DEFAULT_HOST, help="LDAP server host")
|
||||
@click.option("--port", default=DEFAULT_PORT, help="LDAP server port")
|
||||
@click.option("--use-ssl", is_flag=True, help="Use LDAPS instead of LDAP")
|
||||
def test_connection(host: str, port: int, use_ssl: bool):
|
||||
"""Test basic connection to LDAP server."""
|
||||
if ldap3 is None:
|
||||
click.echo("Error: ldap3 library not installed", err=True)
|
||||
click.echo("Install it with: uv pip install ldap3", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
if use_ssl:
|
||||
port = DEFAULT_LDAPS_PORT
|
||||
url = f"ldaps://{host}:{port}"
|
||||
else:
|
||||
url = f"ldap://{host}:{port}"
|
||||
|
||||
click.echo(f"Testing connection to {url}...")
|
||||
|
||||
try:
|
||||
server = Server(url, get_info=ALL, use_ssl=use_ssl)
|
||||
conn = Connection(server, auto_bind=True)
|
||||
|
||||
click.echo("✅ Successfully connected to LDAP server")
|
||||
click.echo(f"\nServer info:")
|
||||
click.echo(f" Vendor: {server.info.vendor_name if server.info else 'Unknown'}")
|
||||
click.echo(f" Version: {server.info.vendor_version if server.info else 'Unknown'}")
|
||||
|
||||
conn.unbind()
|
||||
|
||||
except LDAPException as e:
|
||||
click.echo(f"❌ Connection failed: {e}", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@test.command("auth")
|
||||
@click.option("--host", default=DEFAULT_HOST, help="LDAP server host")
|
||||
@click.option("--port", default=DEFAULT_PORT, help="LDAP server port")
|
||||
@click.option("--use-ssl", is_flag=True, help="Use LDAPS")
|
||||
@click.option("--user", default=DEFAULT_ADMIN_DN, help="User DN")
|
||||
@click.option("--password", default=DEFAULT_ADMIN_PASSWORD, help="Password")
|
||||
def test_auth(host: str, port: int, use_ssl: bool, user: str, password: str):
|
||||
"""Test authentication with LDAP server."""
|
||||
if ldap3 is None:
|
||||
click.echo("Error: ldap3 library not installed", err=True)
|
||||
click.echo("Install it with: uv pip install ldap3", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
if use_ssl:
|
||||
port = DEFAULT_LDAPS_PORT
|
||||
url = f"ldaps://{host}:{port}"
|
||||
else:
|
||||
url = f"ldap://{host}:{port}"
|
||||
|
||||
click.echo(f"Testing authentication to {url}...")
|
||||
click.echo(f"User: {user}")
|
||||
|
||||
try:
|
||||
server = Server(url, get_info=ALL, use_ssl=use_ssl)
|
||||
conn = Connection(server, user=user, password=password, auto_bind=True)
|
||||
|
||||
click.echo("✅ Authentication successful")
|
||||
|
||||
# Try to perform a simple search
|
||||
conn.search(DEFAULT_BASE_DN, "(objectClass=*)", search_scope="BASE")
|
||||
if conn.entries:
|
||||
click.echo(f"✅ Base DN accessible: {DEFAULT_BASE_DN}")
|
||||
|
||||
conn.unbind()
|
||||
|
||||
except LDAPException as e:
|
||||
click.echo(f"❌ Authentication failed: {e}", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@test.command("users")
|
||||
@click.option("--host", default=DEFAULT_HOST, help="LDAP server host")
|
||||
@click.option("--port", default=DEFAULT_PORT, help="LDAP server port")
|
||||
@click.option("--use-ssl", is_flag=True, help="Use LDAPS")
|
||||
def test_users(host: str, port: int, use_ssl: bool):
|
||||
"""List all users in the LDAP directory."""
|
||||
if ldap3 is None:
|
||||
click.echo("Error: ldap3 library not installed", err=True)
|
||||
click.echo("Install it with: uv pip install ldap3", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
if use_ssl:
|
||||
port = DEFAULT_LDAPS_PORT
|
||||
url = f"ldaps://{host}:{port}"
|
||||
else:
|
||||
url = f"ldap://{host}:{port}"
|
||||
|
||||
try:
|
||||
server = Server(url, get_info=ALL, use_ssl=use_ssl)
|
||||
conn = Connection(
|
||||
server,
|
||||
user=DEFAULT_ADMIN_DN,
|
||||
password=DEFAULT_ADMIN_PASSWORD,
|
||||
auto_bind=True
|
||||
)
|
||||
|
||||
# Search for all users
|
||||
conn.search(
|
||||
DEFAULT_BASE_DN,
|
||||
"(objectClass=inetOrgPerson)",
|
||||
attributes=["uid", "cn", "mail", "uidNumber"]
|
||||
)
|
||||
|
||||
if conn.entries:
|
||||
click.echo(f"Found {len(conn.entries)} user(s):\n")
|
||||
for entry in conn.entries:
|
||||
click.echo(f" - {entry.cn}: {entry.uid} ({entry.mail})")
|
||||
else:
|
||||
click.echo("No users found")
|
||||
|
||||
conn.unbind()
|
||||
|
||||
except LDAPException as e:
|
||||
click.echo(f"❌ Query failed: {e}", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@cli.command("init")
|
||||
def init():
|
||||
"""Initialize the LDAP Docker environment."""
|
||||
click.echo("Initializing LDAP Docker environment...\n")
|
||||
|
||||
# Check Docker
|
||||
click.echo("1. Checking Docker...")
|
||||
check_docker()
|
||||
click.echo(" ✅ Docker is available\n")
|
||||
|
||||
# Check certificates
|
||||
click.echo("2. Checking SSL certificates...")
|
||||
if not check_certificates():
|
||||
if click.confirm("\nGenerate self-signed certificates now?", default=True):
|
||||
certs_generate.callback(force=False, hostname="ldap.testing.local")
|
||||
else:
|
||||
click.echo("\nℹ️ You can generate certificates later with: ldap-docker certs generate")
|
||||
click.echo(" Or copy your dev-ca certificates to the certs/ directory")
|
||||
else:
|
||||
click.echo(" ✅ Certificates are present\n")
|
||||
|
||||
# Start server
|
||||
click.echo("\n3. Starting LDAP server...")
|
||||
if click.confirm("Start the LDAP server now?", default=True):
|
||||
server_start.callback(detach=True, build=False)
|
||||
else:
|
||||
click.echo("\nℹ️ You can start the server later with: ldap-docker server start")
|
||||
|
||||
click.echo("\n✅ Initialization complete!")
|
||||
click.echo("\nUseful commands:")
|
||||
click.echo(" - View logs: ldap-docker server logs -f")
|
||||
click.echo(" - Test connection: ldap-docker test connection")
|
||||
click.echo(" - List users: ldap-docker test users")
|
||||
click.echo(" - Stop server: ldap-docker server stop")
|
||||
|
||||
|
||||
def main():
|
||||
"""Entry point for the CLI."""
|
||||
try:
|
||||
cli()
|
||||
except KeyboardInterrupt:
|
||||
click.echo("\n\nInterrupted by user")
|
||||
sys.exit(130)
|
||||
except Exception as e:
|
||||
click.echo(f"Error: {e}", err=True)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -9,7 +9,7 @@ For production, use proper certificates from your dev-ca or a trusted CA.
|
||||
import argparse
|
||||
import ipaddress
|
||||
import sys
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
@@ -17,7 +17,7 @@ try:
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography.x509.oid import ExtensionOID, NameOID
|
||||
from cryptography.x509.oid import ExtendedKeyUsageOID, NameOID
|
||||
except ImportError:
|
||||
print("Error: cryptography library not found.")
|
||||
print("Install it with: uv pip install cryptography")
|
||||
@@ -55,8 +55,8 @@ def generate_ca_certificate(
|
||||
.issuer_name(issuer)
|
||||
.public_key(private_key.public_key())
|
||||
.serial_number(x509.random_serial_number())
|
||||
.not_valid_before(datetime.utcnow())
|
||||
.not_valid_after(datetime.utcnow() + timedelta(days=days_valid))
|
||||
.not_valid_before(datetime.now(timezone.utc))
|
||||
.not_valid_after(datetime.now(timezone.utc) + timedelta(days=days_valid))
|
||||
.add_extension(
|
||||
x509.BasicConstraints(ca=True, path_length=None),
|
||||
critical=True,
|
||||
@@ -90,7 +90,7 @@ def generate_server_certificate(
|
||||
ca_cert: x509.Certificate,
|
||||
ca_key: rsa.RSAPrivateKey,
|
||||
hostname: str = "ldap.testing.local",
|
||||
san_list: list[str] = None,
|
||||
san_list: list[str] | None = None,
|
||||
days_valid: int = 365,
|
||||
) -> x509.Certificate:
|
||||
"""Generate a server certificate signed by the CA."""
|
||||
@@ -123,8 +123,8 @@ def generate_server_certificate(
|
||||
.issuer_name(ca_cert.subject)
|
||||
.public_key(private_key.public_key())
|
||||
.serial_number(x509.random_serial_number())
|
||||
.not_valid_before(datetime.utcnow())
|
||||
.not_valid_after(datetime.utcnow() + timedelta(days=days_valid))
|
||||
.not_valid_before(datetime.now(timezone.utc))
|
||||
.not_valid_after(datetime.now(timezone.utc) + timedelta(days=days_valid))
|
||||
.add_extension(
|
||||
x509.SubjectAlternativeName(san_entries),
|
||||
critical=False,
|
||||
@@ -148,7 +148,7 @@ def generate_server_certificate(
|
||||
critical=True,
|
||||
)
|
||||
.add_extension(
|
||||
x509.ExtendedKeyUsage([x509.ExtendedKeyUsageOID.SERVER_AUTH]),
|
||||
x509.ExtendedKeyUsage([ExtendedKeyUsageOID.SERVER_AUTH]),
|
||||
critical=False,
|
||||
)
|
||||
.add_extension(
|
||||
@@ -236,9 +236,7 @@ def main():
|
||||
|
||||
# Check if certificates already exist
|
||||
if not args.force:
|
||||
existing = [
|
||||
p for p in [ca_cert_path, server_cert_path, server_key_path] if p.exists()
|
||||
]
|
||||
existing = [p for p in [ca_cert_path, server_cert_path, server_key_path] if p.exists()]
|
||||
if existing:
|
||||
print("Error: The following certificate files already exist:")
|
||||
for p in existing:
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
#!/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