feat: add directory adapter
LDAPS directory adapter with certificate verification, allow-listed reads and writes, escaped filters, password verification and change, password policy and account state, plus an in-memory fake. Adds the LDAP_* configuration, python-ldap with its image libraries, the CA file mount and an opt-in live test for the test OU. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3t4WL7bd9bdHHNjEsxzqC
This commit is contained in:
@@ -14,6 +14,13 @@ All configuration comes from environment variables, validated at startup. If any
|
||||
| `DEBUG` | no | `false` | `true` or `false` |
|
||||
| `TRUSTED_PROXIES` | no | empty | Comma-separated IP addresses or networks. Reserved for the client-IP rule in a later entry; currently has no effect |
|
||||
| `LOG_LEVEL` | no | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` |
|
||||
| `LDAP_SERVER` | yes | | Directory server host name (optionally `:port`); LDAPS on 636 is always used and the name must be in the server's certificate |
|
||||
| `LDAP_USER_OU_DN` | yes | | Distinguished name of the OU whose users the portal may read and change |
|
||||
| `LDAP_BIND_DN` | yes | | Service account, as distinguished name or user principal name |
|
||||
| `LDAP_BIND_PASSWORD` | yes | | Password of the service account |
|
||||
| `LDAP_CA_FILE` | yes | | Path inside the container of the PEM file with the CA chain; certificate verification is never disabled |
|
||||
| `LDAP_PUBLISHER_GROUP_DN` | yes | | Group whose direct members are Publishers |
|
||||
| `LDAP_ADMIN_GROUP_DN` | yes | | Group whose direct members are Admins |
|
||||
| `DEFAULT_TIMEZONE` | no | `Europe/Berlin` | IANA zone used for display; storage is UTC |
|
||||
|
||||
## Run in a container
|
||||
@@ -21,7 +28,7 @@ All configuration comes from environment variables, validated at startup. If any
|
||||
The image is built and run on a Linux host from a checkout of this repository.
|
||||
|
||||
```sh
|
||||
cp .env.example .env # then set SECRET_KEY and ALLOWED_HOSTS
|
||||
cp .env.example .env # then set SECRET_KEY, ALLOWED_HOSTS, the LDAP_* values and CA_FILE_HOST
|
||||
docker compose up --build
|
||||
curl -H "Host: <first ALLOWED_HOSTS entry>" http://localhost:8000/healthz # {"status":"ok"}
|
||||
```
|
||||
@@ -41,3 +48,13 @@ uv run ruff check .
|
||||
```
|
||||
|
||||
`pytest` sets its own test environment (see `pyproject.toml`).
|
||||
|
||||
### Directory adapter against the test OU
|
||||
|
||||
`uv sync` builds `python-ldap`, which needs the OpenLDAP and SASL development libraries (the Docker image installs them). The automated tests use an in-memory fake and a stand-in for the `ldap` module, so they run anywhere. To check the real adapter against the test OU, run this on a Linux host with the libraries installed (never against the production OU):
|
||||
|
||||
```sh
|
||||
PORTAL_LIVE_LDAP=1 LIVE_LDAP_SERVER=... LIVE_LDAP_USER_OU_DN=... LIVE_LDAP_BIND_DN=... LIVE_LDAP_BIND_PASSWORD=... LIVE_LDAP_CA_FILE=... LIVE_LDAP_PUBLISHER_GROUP_DN=... LIVE_LDAP_ADMIN_GROUP_DN=... LIVE_LDAP_TEST_PASSWORD=<current password of ptest-user1> uv run pytest portal/tests/test_directory_live.py -v
|
||||
```
|
||||
|
||||
It restores what it writes and does not change any password.
|
||||
|
||||
Reference in New Issue
Block a user