|
@@ -72,7 +72,7 @@ In the Entra app registration, configure:
|
|
|
Leave Entra fields blank if you only intend to use the local-admin
|
|
Leave Entra fields blank if you only intend to use the local-admin
|
|
|
fallback. The OIDC sign-in button still appears, but clicking it will fail
|
|
fallback. The OIDC sign-in button still appears, but clicking it will fail
|
|
|
until the variables are populated — keep `LOCAL_ADMIN_EMAIL` /
|
|
until the variables are populated — keep `LOCAL_ADMIN_EMAIL` /
|
|
|
-`LOCAL_ADMIN_PASSWORD` filled if you skip Entra entirely.
|
|
|
|
|
|
|
+`LOCAL_ADMIN_PASSWORD_HASH` filled if you skip Entra entirely.
|
|
|
|
|
|
|
|
### 3.2 Application URL
|
|
### 3.2 Application URL
|
|
|
|
|
|
|
@@ -111,17 +111,46 @@ turns them on — useful when troubleshooting in a non-public install.
|
|
|
|
|
|
|
|
```
|
|
```
|
|
|
LOCAL_ADMIN_EMAIL=admin@example.com
|
|
LOCAL_ADMIN_EMAIL=admin@example.com
|
|
|
-LOCAL_ADMIN_PASSWORD=<a long passphrase>
|
|
|
|
|
|
|
+LOCAL_ADMIN_PASSWORD_HASH='$2y$10$...' # output of password_hash()
|
|
|
LOCAL_ADMIN_NAME=Local Admin
|
|
LOCAL_ADMIN_NAME=Local Admin
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-If both `LOCAL_ADMIN_EMAIL` and `LOCAL_ADMIN_PASSWORD` are set, a second
|
|
|
|
|
-sign-in form appears at `/auth/local`. The password is **compared in
|
|
|
|
|
-plain text** against the env value — so:
|
|
|
|
|
|
|
+If both `LOCAL_ADMIN_EMAIL` and `LOCAL_ADMIN_PASSWORD_HASH` are set, a
|
|
|
|
|
+second sign-in form appears at `/auth/local`. The submitted password is
|
|
|
|
|
+verified with PHP's `password_verify()` against the stored bcrypt hash —
|
|
|
|
|
+the plaintext password is never written to disk.
|
|
|
|
|
+
|
|
|
|
|
+**Generating the hash.** Pick whichever one-liner matches what you have
|
|
|
|
|
+installed; both prompt interactively so the password isn't kept in shell
|
|
|
|
|
+history:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# Host PHP 8 (any minor):
|
|
|
|
|
+php -r 'echo password_hash(readline("Password: "), PASSWORD_DEFAULT), PHP_EOL;'
|
|
|
|
|
+
|
|
|
|
|
+# No host PHP — borrow the runtime image:
|
|
|
|
|
+docker run --rm -it php:8.3-cli php -r \
|
|
|
|
|
+ 'echo password_hash(readline("Password: "), PASSWORD_DEFAULT), PHP_EOL;'
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Each invocation prints a different `$2y$10$...` string for the same
|
|
|
|
|
+input — that's the per-hash random salt. Either one verifies.
|
|
|
|
|
+
|
|
|
|
|
+Paste the result into `.env` between **single quotes** so the shell that
|
|
|
|
|
+launches `docker compose` doesn't try to expand the `$` segments inside
|
|
|
|
|
+the hash:
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+LOCAL_ADMIN_PASSWORD_HASH='$2y$10$abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnop'
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Then:
|
|
|
|
|
|
|
|
- Pick a long, unique passphrase you do not reuse anywhere else.
|
|
- Pick a long, unique passphrase you do not reuse anywhere else.
|
|
|
- Make sure `.env` is `chmod 600` and owned by a single trusted user.
|
|
- Make sure `.env` is `chmod 600` and owned by a single trusted user.
|
|
|
-- Rotate the passphrase by editing `.env` and restarting the container.
|
|
|
|
|
|
|
+- Rotate the passphrase by regenerating the hash, replacing the line in
|
|
|
|
|
+ `.env`, and restarting the container — active sessions stay valid
|
|
|
|
|
+ until they expire (the hash is only consulted at sign-in time).
|
|
|
|
|
|
|
|
The local-admin user is recorded in the database as
|
|
The local-admin user is recorded in the database as
|
|
|
`entra_oid = "local:<email>"` with `is_admin = 1`. If the `users` table
|
|
`entra_oid = "local:<email>"` with `is_admin = 1`. If the `users` table
|
|
@@ -304,7 +333,7 @@ before pulling.
|
|
|
| Symptom | Likely cause | Fix |
|
|
| Symptom | Likely cause | Fix |
|
|
|
|---|---|---|
|
|
|---|---|---|
|
|
|
| `/auth/login` returns "redirect URI mismatch" | The redirect URI registered in Entra does not equal `{APP_BASE_URL}/auth/callback`. | Update either `APP_BASE_URL` in `.env` or the Entra app registration. |
|
|
| `/auth/login` returns "redirect URI mismatch" | The redirect URI registered in Entra does not equal `{APP_BASE_URL}/auth/callback`. | Update either `APP_BASE_URL` in `.env` or the Entra app registration. |
|
|
|
-| `/auth/local` returns 404 | `LOCAL_ADMIN_EMAIL` or `LOCAL_ADMIN_PASSWORD` is blank. | Set both, then `docker compose restart`. |
|
|
|
|
|
|
|
+| `/auth/local` returns 404 | `LOCAL_ADMIN_EMAIL` or `LOCAL_ADMIN_PASSWORD_HASH` is blank. | Set both (see §3.5 for the hash recipe), then `docker compose restart`. |
|
|
|
| Sign-in succeeds but every page shows "not authorised" | The user has no `is_admin` flag and is trying to access an admin-only page. | Promote them via Users (logged in as another admin). |
|
|
| Sign-in succeeds but every page shows "not authorised" | The user has no `is_admin` flag and is trying to access an admin-only page. | Promote them via Users (logged in as another admin). |
|
|
|
| Container restarts in a loop | Most often a malformed `.env` line or a permission problem on `./data`. | `docker compose logs` will show the PHP fatal. Check that `./data` is writable by the `www-data` user inside the container (uid 33 on the Apache image). |
|
|
| Container restarts in a loop | Most often a malformed `.env` line or a permission problem on `./data`. | `docker compose logs` will show the PHP fatal. Check that `./data` is writable by the `www-data` user inside the container (uid 33 on the Apache image). |
|
|
|
| CSS looks broken / unstyled | The Node build stage was skipped or used a stale layer. | `docker compose build --no-cache` and restart. |
|
|
| CSS looks broken / unstyled | The Node build stage was skipped or used a stale layer. | `docker compose build --no-cache` and restart. |
|