From 3d11470f818f546f14e41236c8c98b262d160834 Mon Sep 17 00:00:00 2001 From: Rune Olsen Date: Fri, 23 Jan 2026 13:41:39 +0100 Subject: [PATCH] Auto login with Authelia --- PROXY_SETUP.md | 3 ++ README.md | 2 ++ app.py | 93 ++++++++++++++++++++++++++------------------------ 3 files changed, 53 insertions(+), 45 deletions(-) diff --git a/PROXY_SETUP.md b/PROXY_SETUP.md index dbe9fc8..f331142 100644 --- a/PROXY_SETUP.md +++ b/PROXY_SETUP.md @@ -61,6 +61,9 @@ environment: - SSL/TLS termination at proxy - Production deployments with HTTPS +**Special Feature - Authelia Auto-Login:** +When `ENABLE_PROXY=true` and you're using Authelia, the app automatically logs you in using Authelia's authentication headers. **No app password needed!** Simply authenticate through Authelia, and you'll be logged into the Mailcow Alias Manager automatically. + --- ### **Switching Between Modes** diff --git a/README.md b/README.md index a4a6848..6f544a1 100644 --- a/README.md +++ b/README.md @@ -76,12 +76,14 @@ The application supports two access modes: - Set `ENABLE_PROXY=false` in `docker-compose.yml` (default) - Access at: `http://your-server-ip:5172` - Works over HTTP (no HTTPS required) +- **Login:** Enter app password - Perfect for internal/LAN access **Proxy Access** - Access via reverse proxy (Authelia, Nginx, Traefik, etc.) - Set `ENABLE_PROXY=true` in `docker-compose.yml` - Access at: `https://alias.yourdomain.com` (through your proxy) - Requires HTTPS +- **Login:** Automatic when using Authelia (no password needed!) - See [PROXY_SETUP.md](PROXY_SETUP.md) for detailed configuration **To switch modes:** diff --git a/app.py b/app.py index 3b93f00..4a9ce6d 100644 --- a/app.py +++ b/app.py @@ -171,40 +171,35 @@ def login_required(f): @app.route('/login', methods=['GET', 'POST']) def login(): - """Login page""" - # First, try Authelia authentication - authelia_user = get_authelia_user() + """Login page or JSON login endpoint""" - # Debug logging for all requests - if app.debug: - logger.info(f"Login route: method={request.method}, headers={dict(request.headers)}") - - # If Authelia authenticated, login and redirect to index - if authelia_user: - logger.info(f"Login via Authelia for user: {authelia_user}") - session.clear() - session.permanent = True - session['logged_in'] = True - session['authelia_user'] = authelia_user - session['user_token'] = secrets.token_urlsafe(32) - session['auth_method'] = 'authelia' - session.modified = True + # Auto-login when ENABLE_PROXY=true and Authelia headers are present + if ENABLE_PROXY: + authelia_user = get_authelia_user() - # Set a cookie manually to ensure it's properly formatted for Zoraxy - response = redirect(url_for('index')) - # Set cookie parameters to work with Zoraxy/Authelia - response.set_cookie( - key=app.config['SESSION_COOKIE_NAME'], - value=secrets.token_urlsafe(32), # Generate a new token instead of using session.sid - max_age=int(app.config['PERMANENT_SESSION_LIFETIME'].total_seconds()), - path=app.config['SESSION_COOKIE_PATH'], - secure=app.config['SESSION_COOKIE_SECURE'], - httponly=app.config['SESSION_COOKIE_HTTPONLY'], - samesite='None' - ) - return response + if authelia_user: + # User authenticated by Authelia - auto-login + if not session.get('logged_in'): + logger.info(f"🔐 Auto-login: User '{authelia_user}' authenticated by Authelia") + session.clear() + session.permanent = True + session['logged_in'] = True + session['user_token'] = secrets.token_urlsafe(32) + session['auth_method'] = 'authelia' + session['authelia_user'] = authelia_user + session.modified = True + + # Get additional Authelia info if available + session['remote_email'] = request.headers.get('Remote-Email', '') + session['remote_name'] = request.headers.get('Remote-Name', '') + session['remote_groups'] = request.headers.get('Remote-Groups', '') + + logger.info(f"✅ Auto-login successful: {authelia_user} ({session.get('remote_email', 'no email')})") + + # Already logged in via Authelia - redirect to main page + return redirect(url_for('index')) - # Handle form submission for local authentication + # Handle form submission for local authentication (only when ENABLE_PROXY=false) if request.method == 'POST': password = request.json.get('password', '') logger.info("Login attempt with password (redacted)") @@ -286,20 +281,28 @@ def logout(): @app.route('/') def index(): """Main page - requires login""" - # Try to auto-login with Authelia - authelia_user = get_authelia_user() - - if authelia_user and not session.get('logged_in'): - # Auto-login for users authenticated by Authelia - logger.info(f"Auto-login via Authelia for user: {authelia_user}") - session.clear() - session.permanent = True - session['logged_in'] = True - session['authelia_user'] = authelia_user - session['user_token'] = secrets.token_urlsafe(32) - session['auth_method'] = 'authelia' - session.modified = True - return render_template('index.html') + # Auto-login with Authelia (only when ENABLE_PROXY=true) + if ENABLE_PROXY: + authelia_user = get_authelia_user() + + if authelia_user and not session.get('logged_in'): + # Auto-login for users authenticated by Authelia + logger.info(f"🔐 Auto-login via Authelia for user: {authelia_user}") + session.clear() + session.permanent = True + session['logged_in'] = True + session['authelia_user'] = authelia_user + session['user_token'] = secrets.token_urlsafe(32) + session['auth_method'] = 'authelia' + session.modified = True + + # Store additional Authelia info + session['remote_email'] = request.headers.get('Remote-Email', '') + session['remote_name'] = request.headers.get('Remote-Name', '') + session['remote_groups'] = request.headers.get('Remote-Groups', '') + + logger.info(f"✅ Auto-login successful: {authelia_user} ({session.get('remote_email', 'no email')})") + return render_template('index.html') # Check if logged in if not session.get('logged_in'):