feat(authentik): recovery email links to embedded reset-password UI
Custom email template rendered via AUTH_APP_URL, mounted in Authentik, and gitignored rendered HTML to avoid localhost hardcoding in prod.
This commit is contained in:
parent
8bbc539d77
commit
f7ef89fa82
@ -292,7 +292,9 @@ MAIL_MICROSOFT_OAUTH_CLIENT_SECRET=
|
||||
MAIL_MICROSOFT_OAUTH_TENANT=common
|
||||
MAIL_OAUTH_REDIRECT_URL=
|
||||
MAIL_APP_URL=http{{SECURE}}://{{PUBLIC_HOST}}/mail
|
||||
# Cible nginx → suite frontend unifié mail+drive (dev: Next sur l'hôte :3004 ; prod: suite-frontend:3000)
|
||||
# Origine app pour pages auth (/login, /reset-password) — template e-mail recovery Authentik.
|
||||
# Dev local Next.js : AUTH_APP_URL=http://localhost:3004
|
||||
AUTH_APP_URL=http{{SECURE}}://{{PUBLIC_HOST}}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Stalwart hosted mail (optional — enable for @ultisuite.fr / custom domains)
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -32,5 +32,8 @@ Thumbs.db
|
||||
# Docker data (local volumes)
|
||||
docker-data/
|
||||
|
||||
# Rendered Authentik email templates (generated by deploy/authentik/render-blueprints.sh)
|
||||
deploy/authentik/templates/**/*.html
|
||||
|
||||
# Node.js
|
||||
node_modules/
|
||||
|
||||
@ -8,7 +8,7 @@ Blueprints in `blueprints/` are mounted into Authentik at `/blueprints/custom` a
|
||||
| `02-ulti-brand.yaml` | Branding UltiSuite + lien « Créer un compte » sur login |
|
||||
| `03-ulti-suite-groups.yaml` | Claim OIDC `groups` (RBAC contacts/calendar/drive/photos) |
|
||||
| `04-ulti-post-migration-security.yaml` | Flow WebAuthn/TOTP post-migration (`ulti-post-migration-security`) |
|
||||
| `05-ulti-recovery.yaml` | Mot de passe oublié (`ulti-recovery`) |
|
||||
| `05-ulti-recovery.yaml` | Mot de passe oublié (`ulti-recovery`) + e-mail → `/reset-password` |
|
||||
| `ulti-oidc.yaml` | App OIDC Ultimail |
|
||||
| `nextcloud-oidc.yaml` | App OIDC Nextcloud |
|
||||
| `onlyoffice-oidc.yaml` | App OIDC OnlyOffice |
|
||||
@ -36,6 +36,22 @@ cd ../ulti-backend
|
||||
docker exec deploy-authentik-server-1 ak apply_blueprint /blueprints/custom/02-ulti-brand.yaml
|
||||
```
|
||||
|
||||
### Mot de passe oublié (recovery embedded)
|
||||
|
||||
1. L'utilisateur saisit son e-mail sur `/forgot-password` (UI Ulti).
|
||||
2. Authentik envoie un e-mail avec lien vers `{AUTH_APP_URL}/reset-password?flow_token=…` (template `email/ulti_password_reset.html`).
|
||||
3. `/reset-password` reprend le flow `ulti-recovery` via le BFF (`is_restored` → étapes mot de passe embedded).
|
||||
|
||||
Variable `.env` : `AUTH_APP_URL` (défaut dev `http://localhost:3004`). Régénérée dans le template e-mail par `./deploy/authentik/render-blueprints.sh`.
|
||||
|
||||
Appliquer après changement recovery :
|
||||
|
||||
```bash
|
||||
./deploy/authentik/render-blueprints.sh # depuis ulti-backend avec .env.resolved sourcé
|
||||
docker exec deploy-authentik-server-1 ak apply_blueprint /blueprints/custom/05-ulti-recovery.yaml
|
||||
./deploy/compose-up.sh restart authentik-worker
|
||||
```
|
||||
|
||||
## Inscription utilisateur
|
||||
|
||||
Flow public : `http://localhost/auth/if/flow/ulti-enrollment/`
|
||||
|
||||
@ -31,7 +31,7 @@ entries:
|
||||
use_global_settings: true
|
||||
token_expiry: 1800
|
||||
subject: UltiSuite — Réinitialisation du mot de passe
|
||||
template: email/password_reset.html
|
||||
template: email/ulti_password_reset.html
|
||||
activate_user_on_success: true
|
||||
recovery_max_attempts: 5
|
||||
recovery_cache_timeout: 300
|
||||
|
||||
@ -1,15 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# Render Authentik blueprint templates using PUBLIC_HOST / SECURE / SUITE_ORIGIN from .env.resolved.
|
||||
# Render Authentik blueprint + email templates using .env.resolved variables.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
BP_DIR="$ROOT/deploy/authentik/blueprints"
|
||||
TPL_DIR="$ROOT/deploy/authentik/templates"
|
||||
|
||||
if [[ -z "${SUITE_ORIGIN:-}" || -z "${PUBLIC_HOST:-}" ]]; then
|
||||
echo "render-blueprints: SUITE_ORIGIN and PUBLIC_HOST must be set (source .env.resolved first)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Frontend origin for auth pages (/login, /reset-password). Falls back to SUITE_ORIGIN.
|
||||
AUTH_APP_URL="${AUTH_APP_URL:-${NEXT_PUBLIC_APP_URL:-${SUITE_ORIGIN}}}"
|
||||
if [[ "$AUTH_APP_URL" == */mail ]]; then
|
||||
AUTH_APP_URL="${AUTH_APP_URL%/mail}"
|
||||
fi
|
||||
|
||||
render_one() {
|
||||
local tpl="$1"
|
||||
local out="${tpl%.template}"
|
||||
@ -17,6 +24,7 @@ render_one() {
|
||||
-e "s|{{SUITE_ORIGIN}}|${SUITE_ORIGIN}|g" \
|
||||
-e "s|{{PUBLIC_HOST}}|${PUBLIC_HOST}|g" \
|
||||
-e "s|{{SECURE}}|${SECURE:-}|g" \
|
||||
-e "s|{{AUTH_APP_URL}}|${AUTH_APP_URL}|g" \
|
||||
"$tpl" > "$out"
|
||||
echo "render-blueprints: ${out##*/}"
|
||||
}
|
||||
@ -25,3 +33,8 @@ shopt -s nullglob
|
||||
for tpl in "$BP_DIR"/*.yaml.template; do
|
||||
render_one "$tpl"
|
||||
done
|
||||
|
||||
for tpl in "$TPL_DIR"/**/*.template "$TPL_DIR"/*/*.template; do
|
||||
[[ -f "$tpl" ]] || continue
|
||||
render_one "$tpl"
|
||||
done
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
{% extends "email/base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load humanize %}
|
||||
|
||||
{% block content %}
|
||||
<tr>
|
||||
<td align="center">
|
||||
<h1>{% trans "Réinitialiser votre mot de passe UltiSuite" %}</h1>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td align="center" style="max-width: 320px; padding: 20px 0; color: #212124;">
|
||||
{% blocktrans with username=user.username %}
|
||||
Bonjour {{ username }}, utilisez le bouton ci-dessous pour choisir un nouveau mot de passe UltiSpace.
|
||||
{% endblocktrans %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" class="btn btn-primary">
|
||||
<a id="confirm" href="{{AUTH_APP_URL}}/reset-password?flow_token={{ token }}" rel="noopener noreferrer" target="_blank">
|
||||
{% trans "Réinitialiser le mot de passe" %}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
{% endblock %}
|
||||
|
||||
{% block sub_content %}
|
||||
<tr>
|
||||
<td style="padding: 20px; font-size: 12px; color: #212124;" align="center">
|
||||
{% blocktrans with expires=expires|naturaltime %}
|
||||
Si vous n'êtes pas à l'origine de cette demande, ignorez cet e-mail. Le lien est valide {{ expires }}.
|
||||
{% endblocktrans %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endblock %}
|
||||
@ -110,6 +110,7 @@ services:
|
||||
env_file: ../.env.resolved
|
||||
volumes:
|
||||
- ./authentik/blueprints:/blueprints/custom:ro
|
||||
- ./authentik/templates:/templates:ro
|
||||
- ./authentik/branding/ultisuite-logo-light.png:/web/dist/assets/branding/ultisuite-logo-light.png:ro
|
||||
- ./authentik/branding/ultisuite-logo-dark.png:/web/dist/assets/branding/ultisuite-logo-dark.png:ro
|
||||
- ./authentik/branding/ultisuite-favicon.png:/web/dist/assets/branding/ultisuite-favicon.png:ro
|
||||
@ -145,6 +146,7 @@ services:
|
||||
env_file: ../.env.resolved
|
||||
volumes:
|
||||
- ./authentik/blueprints:/blueprints/custom:ro
|
||||
- ./authentik/templates:/templates:ro
|
||||
- ./authentik/branding/ultisuite-logo-light.png:/web/dist/assets/branding/ultisuite-logo-light.png:ro
|
||||
- ./authentik/branding/ultisuite-logo-dark.png:/web/dist/assets/branding/ultisuite-logo-dark.png:ro
|
||||
- ./authentik/branding/ultisuite-favicon.png:/web/dist/assets/branding/ultisuite-favicon.png:ro
|
||||
|
||||
Loading…
Reference in New Issue
Block a user