Adding LDAP support
This commit is contained in:
1 parent
d60ad42f0c
commit
f2b99089ea
17 files changed
+541
-23
No files matched your search
@@ -4,19 +4,19 @@ A production-shaped starting point for a web app that serves both **HTML (HTMX)*
|
||||
|
||||
## Stack
|
||||
|
||||
| Concern | Choice |
|
||||
|----------------|--------|
|
||||
| Web framework | FastAPI |
|
||||
| HTML / interactivity | Jinja2 + HTMX |
|
||||
| ORM | SQLAlchemy 2.0 (async) |
|
||||
| Migrations | Alembic |
|
||||
| Database | SQLite (default) or Postgres — one `DATABASE_URL` |
|
||||
| Auth | JWT access + refresh tokens, rotation, DB-backed revocation |
|
||||
| Authorization | RBAC: users → roles → permissions |
|
||||
| Admin UI | Custom HTMX dashboard (user & role CRUD) |
|
||||
| Config | env vars **or** `.env` (pydantic-settings) |
|
||||
| Tooling | uv, pytest, ruff |
|
||||
| Packaging | Dockerfile + docker-compose |
|
||||
| Concern | Choice |
|
||||
| -------------------- | ----------------------------------------------------------- |
|
||||
| Web framework | FastAPI |
|
||||
| HTML / interactivity | Jinja2 + HTMX |
|
||||
| ORM | SQLAlchemy 2.0 (async) |
|
||||
| Migrations | Alembic |
|
||||
| Database | SQLite (default) or Postgres — one `DATABASE_URL` |
|
||||
| Auth | JWT access + refresh tokens, rotation, DB-backed revocation |
|
||||
| Authorization | RBAC: users → roles → permissions |
|
||||
| Admin UI | Custom HTMX dashboard (user & role CRUD) |
|
||||
| Config | env vars **or** `.env` (pydantic-settings) |
|
||||
| Tooling | uv, pytest, ruff |
|
||||
| Packaging | Dockerfile + docker-compose |
|
||||
|
||||
## Layout
|
||||
|
||||
@@ -154,6 +154,7 @@ Every setting is read from an environment variable first, then `.env`
|
||||
| `AUTO_CREATE_TABLES` | `true` | create tables on startup (dev); use Alembic in prod |
|
||||
| `COOKIE_SECURE` | `false` | set `true` behind HTTPS |
|
||||
| `FIRST_SUPERUSER_EMAIL` / `_PASSWORD` | admin@example.com / changethis | used by seed |
|
||||
| `LDAP_ENABLED` | `false` | validate logins against LDAP/AD (see below) |
|
||||
|
||||
## Auth model
|
||||
|
||||
@@ -168,6 +169,28 @@ stores the access token in an httpOnly cookie so pages work without client JS.
|
||||
Refresh tokens are stored server-side as a SHA-256 hash + `jti` with a `revoked`
|
||||
flag, so logout and rotation genuinely invalidate them.
|
||||
|
||||
### LDAP / Active Directory (optional)
|
||||
|
||||
Set `LDAP_ENABLED=true` to validate logins against a directory. On a successful
|
||||
bind, a local user is **provisioned on first login** (with an unusable local
|
||||
password and the roles in `LDAP_DEFAULT_ROLES`) so RBAC, tokens, and the admin
|
||||
UI work unchanged. Existing accounts still authenticate against the local
|
||||
database as a fallback, so the seeded superuser keeps working.
|
||||
|
||||
Two lookup modes (configured in `.env`, see `.env.example`):
|
||||
|
||||
- **Direct bind** — set `LDAP_BIND_DN_TEMPLATE`, e.g.
|
||||
`uid={username},ou=people,dc=example,dc=com`; the login name is substituted
|
||||
and used to bind directly.
|
||||
- **Search + bind** — leave the template empty and set `LDAP_BIND_DN` /
|
||||
`LDAP_BIND_PASSWORD` (a service account) plus `LDAP_USER_SEARCH_BASE` /
|
||||
`LDAP_USER_SEARCH_FILTER`; the user is located, then re-bound to verify the
|
||||
password.
|
||||
|
||||
The local user's email/name come from the `LDAP_ATTR_EMAIL` / `LDAP_ATTR_FULL_NAME`
|
||||
attributes. Use `ldaps://` (`LDAP_USE_SSL=true`) or `LDAP_START_TLS=true` in
|
||||
production so credentials aren't sent in cleartext.
|
||||
|
||||
## RBAC
|
||||
|
||||
`users → roles → permissions`. Permissions follow `resource:action`
|
||||
|
||||
Reference in new issue
Block a user