148 lines
5.8 KiB
Markdown
148 lines
5.8 KiB
Markdown
# chldapasswd
|
|
|
|
A self-hosted web portal for LDAP account management. Users can log in, view their profile, change their password, recover a lost password, and manage mail aliases — all without requiring direct LDAP access.
|
|
|
|
## Features
|
|
|
|
- **Password change** — authenticated users can update their LDAP password (SHA-512 crypt, minimum 12 chars, requires upper/lower/digit)
|
|
- **Lost password recovery** — sends a one-time reset link via email (token expires in 1 hour)
|
|
- **Profile view** — displays LDAP attributes after login
|
|
- **Mail alias management** — create/delete auto-generated email aliases stored as `mailAlias` in LDAP, exposed via an addy.io-compatible API
|
|
- **HTTP Basic Auth endpoint** (`/auth`) — validates credentials against LDAP, forwards `X-Remote-User` header; suitable for use with nginx `auth_request`
|
|
- **Docker registry anonymous read** — optionally allows unauthenticated `GET`/`HEAD` on registry image paths via `X-Special-Auth` header
|
|
- **Altcha PoW CAPTCHA** — proof-of-work challenge on sensitive forms, no third-party service required
|
|
- **CSRF protection** — token-based on state-changing forms
|
|
- **Rate limiting** — per-IP on login, password change, lost password, and alias API endpoints
|
|
- **Security headers** — CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy
|
|
|
|
## Building
|
|
|
|
```sh
|
|
go build -ldflags="-s -w" -o chldapasswd
|
|
```
|
|
|
|
Requires Go 1.23+. A Drone CI pipeline builds and pushes `nemunaire/chldapasswd:latest` on each push to `master`.
|
|
|
|
## Usage
|
|
|
|
```
|
|
chldapasswd [flags] [serve]
|
|
chldapasswd [flags] generate-lost-password-link <uid>
|
|
```
|
|
|
|
### Flags
|
|
|
|
| Flag | Default | Description |
|
|
|------|---------|-------------|
|
|
| `-bind` | `127.0.0.1:8080` | Listen address |
|
|
| `-baseurl` | `/` | URL prefix (for reverse-proxy subpath deployment) |
|
|
| `-config` | _(none)_ | Path to a JSON config file for LDAP settings |
|
|
| `-public-url` | _(none)_ | Base URL used in password reset emails |
|
|
| `-brand-name` | `chldapasswd` | Brand name shown in the UI |
|
|
| `-brand-logo` | _(none)_ | URL of a logo image shown in the UI |
|
|
| `-addy-api-secret` | _(none)_ | HMAC secret for the alias API |
|
|
| `-dev` | `false` | Development mode: disables HSTS and cookie `Secure` flag |
|
|
|
|
### Environment variables
|
|
|
|
All LDAP and SMTP settings can be provided via environment variables (they override CLI flags and config file values):
|
|
|
|
| Variable | Description |
|
|
|----------|-------------|
|
|
| `LDAP_HOST` | LDAP server hostname |
|
|
| `LDAP_PORT` | LDAP server port |
|
|
| `LDAP_STARTTLS` | Enable STARTTLS (`1`/`on`/`true`) |
|
|
| `LDAP_SSL` | Use LDAPS (`1`/`on`/`true`) |
|
|
| `LDAP_BASEDN` | Base DN for searches |
|
|
| `LDAP_SERVICEDN` | DN of the service account |
|
|
| `LDAP_SERVICE_PASSWORD` | Password of the service account |
|
|
| `LDAP_SERVICE_PASSWORD_FILE` | Path to a file containing the service password |
|
|
| `SMTP_HOST` | SMTP server (leave empty to use local `sendmail`) |
|
|
| `SMTP_PORT` | SMTP port |
|
|
| `SMTP_USER` | SMTP username |
|
|
| `SMTP_PASSWORD` | SMTP password |
|
|
| `SMTP_PASSWORD_FILE` | Path to a file containing the SMTP password |
|
|
| `SMTP_FROM` | Sender address for recovery emails |
|
|
| `PUBLIC_URL` | Public base URL (overrides `-public-url`) |
|
|
| `BRAND_NAME` | Brand name (overrides `-brand-name`) |
|
|
| `BRAND_LOGO` | Brand logo URL (overrides `-brand-logo`) |
|
|
| `ADDY_API_SECRET` | HMAC secret for the alias API |
|
|
| `ALIAS_ALLOWED_DOMAINS` | Comma-separated list of domains users may create aliases under |
|
|
| `DOCKER_REGISTRY_SECRET` | Shared secret for anonymous Docker registry read access |
|
|
|
|
### JSON config file
|
|
|
|
The `-config` flag accepts a JSON file whose fields map directly to the `LDAP` struct:
|
|
|
|
```json
|
|
{
|
|
"Host": "auth.example.com",
|
|
"Port": 636,
|
|
"Ssl": true,
|
|
"BaseDN": "dc=example,dc=com",
|
|
"ServiceDN": "cn=svc,ou=services,dc=example,dc=com",
|
|
"ServicePassword": "secret",
|
|
"MailHost": "smtp.example.com",
|
|
"MailPort": 587,
|
|
"MailUser": "mailer",
|
|
"MailPassword": "secret",
|
|
"MailFrom": "noreply@example.com"
|
|
}
|
|
```
|
|
|
|
## HTTP endpoints
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| `GET/POST` | `/` or `/change` | Password change form |
|
|
| `GET/POST` | `/login` | Login form — shows user profile on success |
|
|
| `GET/POST` | `/lost` | Lost password form |
|
|
| `GET/POST` | `/reset` | Password reset via token (from email link) |
|
|
| `GET/POST` | `/auth` | HTTP Basic Auth validation for reverse-proxy use |
|
|
| `POST` | `/api/v1/aliases` | Create a mail alias (addy.io-compatible) |
|
|
| `DELETE` | `/api/v1/aliases/{alias}` | Delete a mail alias |
|
|
| `GET` | `/altcha-challenge` | Fetch a PoW challenge for the Altcha widget |
|
|
|
|
## Mail alias API
|
|
|
|
The alias API is compatible with the addy.io API format. Tokens are HMAC-SHA224 signed and encoded in Base32:
|
|
|
|
```sh
|
|
# Create alias
|
|
curl -X POST https://auth.example.com/api/v1/aliases \
|
|
-H "Authorization: Bearer <token>" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"domain": "example.com"}'
|
|
|
|
# Delete alias
|
|
curl -X DELETE https://auth.example.com/api/v1/aliases/abc123%40example.com \
|
|
-H "Authorization: Bearer <token>"
|
|
```
|
|
|
|
The token for a given `uid` is: `base32(uid + ":" + HMAC-SHA224(apiSecret, uid))`.
|
|
|
|
Alias creation is disabled unless `ALIAS_ALLOWED_DOMAINS` is set.
|
|
|
|
## Templates
|
|
|
|
HTML templates are embedded from the `static/` directory at build time. To customise the UI, edit the files in `static/` before building.
|
|
|
|
The `dextpl/` directory contains a matching theme for [Dex](https://dexidp.io/) to keep a consistent look across the SSO stack.
|
|
|
|
## Docker
|
|
|
|
```sh
|
|
docker run -d \
|
|
-e LDAP_HOST=auth.example.com \
|
|
-e LDAP_PORT=636 \
|
|
-e LDAP_SSL=true \
|
|
-e LDAP_BASEDN=dc=example,dc=com \
|
|
-e LDAP_SERVICEDN=cn=svc,ou=services,dc=example,dc=com \
|
|
-e LDAP_SERVICE_PASSWORD=secret \
|
|
-e SMTP_HOST=smtp.example.com \
|
|
-e SMTP_PORT=587 \
|
|
-e SMTP_FROM=noreply@example.com \
|
|
-e PUBLIC_URL=https://auth.example.com \
|
|
-p 8080:8080 \
|
|
nemunaire/chldapasswd
|
|
```
|