- Go 50.1%
- CSS 26.9%
- HTML 22.4%
- Dockerfile 0.6%
|
All checks were successful
continuous-integration/drone/push Build is passing
Distinguish between "not found" and "multiple entries found" instead of the generic "User does not exist or too many entries returned", making it easier to diagnose issues in logs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| dextpl | ||
| static | ||
| .drone.yml | ||
| .gitignore | ||
| addy.go | ||
| altcha.go | ||
| change.go | ||
| csrf.go | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| ldap.go | ||
| login.go | ||
| lost.go | ||
| main.go | ||
| ratelimit.go | ||
| README.md | ||
| renovate.json | ||
| reset.go | ||
| static.go | ||
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
mailAliasin LDAP, exposed via an addy.io-compatible API - HTTP Basic Auth endpoint (
/auth) — validates credentials against LDAP, forwardsX-Remote-Userheader; suitable for use with nginxauth_request - Docker registry anonymous read — optionally allows unauthenticated
GET/HEADon registry image paths viaX-Special-Authheader - 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
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:
{
"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:
# 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 to keep a consistent look across the SSO stack.
Docker
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