# ldap-manager

# Tests:
[![CI](https://github.com/israelhen153/ldap-manager/actions/workflows/makefile.yml/badge.svg)](https://github.com/israelhen153/ldap-manager/actions/workflows/makefile.yml)

## Demo

[![asciicast](https://asciinema.org/a/cl9HR8vuYwlNrCe8.svg)](https://asciinema.org/a/cl9HR8vuYwlNrCe8)

**CLI power tools for sysadmins who run OpenLDAP and refuse to touch a web UI.**

Manage users, groups, backups, SSH keys, password policies, and server operations — all from one command. Replace your pile of bash scripts and raw `ldapmodify` commands with something that actually has `--dry-run`.

```bash
pip install ldap-manager
ldap-manager user list --enabled --json
```

---

## Why?

If you manage OpenLDAP, your options are:

| Tool | Problem |
|------|---------|
| `ldapmodify` / `ldapsearch` | LDIF by hand for every operation |
| phpLDAPadmin | Abandoned, PHP, browser-only |
| LDAP Account Manager | Java, $$$, overkill for CLI admins |
| Your 15 bash scripts | Fragile, no error handling, no dry-run |

**ldap-manager** is the missing CLI. One tool, tab completion, JSON output, dry-run on destructive operations, and actual tests.

---

## Features

| Category | What you get |
|----------|-------------|
| **Users** | Create, update, delete, enable/disable, search with filters, dump as JSON |
| **Groups** | Create, delete, add/remove members, list, supports posixGroup and groupOfNames |
| **Backup & Restore** | Full `slapcat`/`slapadd` dumps with gzip, metadata, and config backup |
| **Batch Operations** | Bulk create/update/delete from JSON/CSV/TSV with `--dry-run` |
| **Password Reset** | Reset all users at once, CSV output with new passwords |
| **SSH Keys** | Add, remove, list `ldapPublicKey` attributes per user |
| **Server Ops** | Status, start/stop/restart, reindex with `--auto` |
| **Password Policy** | View policy config, check user expiry/lockout status |
| **LDIF Export/Import** | Standards-compliant RFC 2849 export and import with dry-run |
| **Tree Management** | List/create/delete OUs, visualize your DIT |
| **Audit Logging** | JSON-lines audit trail of all operations |
| **JSON Output** | `--json` flag on 12+ commands for scripting and pipelines |

---

## Quickstart

### Install

```bash
# Rocky/RHEL 8+
dnf install epel-release -y
dnf install python3-ldap python3-pyyaml python3-click python3-passlib \
            openldap-clients openldap-servers -y

pip install ldap-manager
```

### Configure

```bash
cp config.example.yaml /etc/ldap-manager/config.yaml
vim /etc/ldap-manager/config.yaml
```

Or use environment variables:

```bash
export LDAP_URI="ldap://localhost:389"
export LDAP_BIND_DN="cn=admin,dc=example,dc=com"
export LDAP_BIND_PASSWORD="secret"
export LDAP_BASE_DN="dc=example,dc=com"
```

### Go

```bash
ldap-manager user list
```

---

## Usage

### Users

```bash
ldap-manager user list --enabled --json
ldap-manager user get jdoe
ldap-manager user create jdoe --cn "John Doe" --mail john@example.com
ldap-manager user update jdoe --set mail=new@example.com --set loginShell=/bin/zsh
ldap-manager user delete jdoe --yes
ldap-manager user disable jdoe
ldap-manager user enable jdoe
ldap-manager user passwd jdoe

# Search with filters
ldap-manager user search --uid "j*"
ldap-manager user search --mail "*@engineering.com" --enabled
ldap-manager user search --filter "(description=contractor*)" --json
```

### Groups

```bash
ldap-manager group list
ldap-manager group create devops --gid 5000
ldap-manager group add-member devops jdoe
ldap-manager group remove-member devops jdoe
ldap-manager group members devops --json
ldap-manager group delete old_team --yes
```

### Backup & Restore

```bash
ldap-manager backup dump --tag pre-migration
ldap-manager backup list
ldap-manager backup restore /var/backups/ldap/ldap_backup_20240101_120000
ldap-manager backup restore /path/to/backup --with-config --yes
```

### Batch Operations

```bash
# Bulk create from CSV/JSON
ldap-manager batch create users.csv --dry-run
ldap-manager batch create users.json --yes

# Bulk delete
ldap-manager batch delete terminations.csv --dry-run
```

### Bulk Password Reset

```bash
ldap-manager passwd-all --dry-run
ldap-manager passwd-all --output /secure/passwords.csv --length 24
```

### SSH Keys

```bash
ldap-manager user ssh-key-list jdoe
ldap-manager user ssh-key-add jdoe ~/.ssh/id_ed25519.pub
ldap-manager user ssh-key-remove jdoe 1
```

### Server Operations

```bash
ldap-manager server status
ldap-manager server start
ldap-manager server stop
ldap-manager server restart
ldap-manager server reindex --auto    # stops slapd, reindexes, restarts
```

### Password Policy

```bash
ldap-manager ppolicy status jdoe      # expiry, lockout, grace logins
ldap-manager ppolicy policy           # view current policy config
ldap-manager ppolicy check-all        # find expired/locked accounts
```

### LDIF Export & Import

```bash
ldap-manager user export --format ldif --scope all -o backup.ldif
ldap-manager user export --format json --enabled -o active_users.json
ldap-manager import users.ldif --dry-run
```

### Tree Management

```bash
ldap-manager tree show                # visualize DIT
ldap-manager tree list-ous
ldap-manager tree create-ou "ou=Contractors,dc=example,dc=com"
ldap-manager tree delete-ou "ou=OldDept,dc=example,dc=com" --recursive
```

### Audit Log

```bash
ldap-manager audit log --since 2024-01-01
ldap-manager audit log --action create --target jdoe
ldap-manager audit status
```

### Global Options

```bash
ldap-manager -c /path/to/config.yaml user list    # custom config
ldap-manager -v user list                          # verbose logging
```

---

## Configuration

Config is loaded from (in order, later overrides earlier):

1. `/etc/ldap-manager/config.yaml` (system)
2. `~/.ldap-manager.yaml` (user)
3. `--config` flag (explicit)
4. Environment variables (highest priority)

See `config.example.yaml` for all options.

---

## Development

```bash
git clone https://github.com/YOURUSERNAME/ldap-manager.git
cd ldap-manager
make install    # creates venv, installs deps
make ci         # lint + typecheck + security + tests
```

Tests use mocked LDAP connections — no live server needed.

```
make lint         # ruff check + format
make typecheck    # mypy
make security     # bandit
make test         # pytest with coverage
make ci           # all of the above
```

---

## Project Structure

```
ldap_manager/
├── __init__.py       # Package metadata
├── cli.py            # Click CLI — 40+ commands
├── config.py         # YAML + env config loading
├── connection.py     # LDAP connection context manager
├── users.py          # User CRUD, enable/disable, search
├── groups.py         # Group management (posixGroup + groupOfNames)
├── passwords.py      # Bulk password generation + reset
├── backup.py         # slapcat/slapadd dump + restore
├── batch.py          # Bulk operations from CSV/JSON/TSV
├── server.py         # Server status, start/stop, reindex
├── sshkeys.py        # SSH public key management
├── ppolicy.py        # Password policy status + checks
├── ldif_ops.py       # RFC 2849 LDIF export/import
├── tree.py           # OU/DIT management + visualization
└── audit.py          # JSON-lines audit logging
```

---

## Design Decisions

- **`slapcat`/`slapadd` for backup** — protocol-level export (`ldapsearch`) is lossy. It misses `cn=config`, overlays, ACLs, and operational attributes. `slapcat` captures everything.
- **`loginShell` for enable/disable** — simpler and more portable than `shadowExpire` or `nsAccountLock`. No overlay needed.
- **SSHA passwords** — most universally supported LDAP hash. Change `hash_scheme` in config if your server has `pw-argon2`.
- **Dry-run on destructive ops** — batch, import, delete, and password reset all support `--dry-run`.
- **JSON output everywhere** — `--json` on 12+ commands for piping to `jq`, scripts, and monitoring.

---

## Requirements

- Python 3.10+
- OpenLDAP client libraries (`libldap2-dev` / `openldap-devel`)
- OpenLDAP server tools on the LDAP host (for backup/restore and server ops)

## License

MIT
