Changed app for proxy and https++

This commit is contained in:
2026-01-23 09:48:57 +01:00
parent b737826d11
commit afab617c5c

175
app.py
View File

@@ -8,6 +8,7 @@ import argparse
import sys import sys
import secrets import secrets
import logging import logging
import json
# Configure logging # Configure logging
logging.basicConfig( logging.basicConfig(
@@ -46,15 +47,48 @@ app.config.update(
PREFERRED_URL_SCHEME='https' PREFERRED_URL_SCHEME='https'
) )
# Set this to True to use the special cookie fix for Zoraxy
ZORAXY_COOKIE_FIX = True
def fix_cookie_for_zoraxy(response):
"""Special handler for Zoraxy cookie issues with SameSite=None"""
if not ZORAXY_COOKIE_FIX:
return response
# Get all cookies from the response
cookies = response.headers.getlist('Set-Cookie')
if not cookies:
return response
# Clear existing cookies
del response.headers['Set-Cookie']
# Fix each cookie and add it back
for cookie in cookies:
if 'malias_session' in cookie and 'SameSite' not in cookie:
# Add SameSite=None and Secure attributes
if 'HttpOnly' in cookie:
cookie = cookie.replace('HttpOnly', 'HttpOnly; SameSite=None; Secure')
else:
cookie += '; SameSite=None; Secure'
response.headers.add('Set-Cookie', cookie)
return response
@app.after_request @app.after_request
def add_security_headers(response): def after_request(response):
"""Add security headers to every response""" """Process the response before it's sent"""
# Add SameSite=None explicitly for all cookies if Auth proxy is detected # Apply special cookie fix for Zoraxy
if request.headers.get('Remote-User') or request.headers.get('X-Remote-User'): response = fix_cookie_for_zoraxy(response)
cookie_header = response.headers.get('Set-Cookie', '')
if cookie_header and 'SameSite=' not in cookie_header: # Set CORS headers to allow Zoraxy and Authelia to work together
cookie_header = cookie_header.replace('HttpOnly', 'HttpOnly; SameSite=None; Secure') response.headers['Access-Control-Allow-Origin'] = request.headers.get('Origin', '*')
response.headers['Set-Cookie'] = cookie_header response.headers['Access-Control-Allow-Credentials'] = 'true'
# Cache control
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
response.headers['Pragma'] = 'no-cache'
response.headers['Expires'] = '0'
return response return response
@@ -66,7 +100,10 @@ def get_authelia_user():
'X-Remote-User', 'X-Remote-User',
'X-Authelia-Username', 'X-Authelia-Username',
'X-Forwarded-User', 'X-Forwarded-User',
'REMOTE_USER' 'REMOTE_USER',
'Http-Remote-User',
'Http-X-Remote-User',
'X-Authenticated-User'
] ]
for header in auth_headers: for header in auth_headers:
@@ -75,6 +112,19 @@ def get_authelia_user():
logger.info(f"Authelia user detected via {header}: {user}") logger.info(f"Authelia user detected via {header}: {user}")
return user return user
# Check Zoraxy forwarded headers (sometimes encoded differently)
if 'X-Forwarded-Headers' in request.headers:
try:
# Some reverse proxies encode headers as JSON
fwd_headers = json.loads(request.headers.get('X-Forwarded-Headers'))
for header in auth_headers:
if header in fwd_headers:
user = fwd_headers[header]
logger.info(f"Authelia user detected via forwarded headers - {header}: {user}")
return user
except:
pass
return None return None
def login_required(f): def login_required(f):
@@ -105,7 +155,9 @@ def login_required(f):
# Regular session check # Regular session check
if not session.get('logged_in'): if not session.get('logged_in'):
logger.warning("Access denied: User not authenticated") logger.warning("Access denied: User not authenticated")
if request.is_json:
return jsonify({'status': 'error', 'message': 'Not authenticated', 'redirect': '/login'}), 401 return jsonify({'status': 'error', 'message': 'Not authenticated', 'redirect': '/login'}), 401
return redirect(url_for('login'))
return f(*args, **kwargs) return f(*args, **kwargs)
return decorated_function return decorated_function
@@ -130,7 +182,20 @@ def login():
session['user_token'] = secrets.token_urlsafe(32) session['user_token'] = secrets.token_urlsafe(32)
session['auth_method'] = 'authelia' session['auth_method'] = 'authelia'
session.modified = True session.modified = True
return redirect(url_for('index'))
# 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=request.cookies.get(app.config['SESSION_COOKIE_NAME']),
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
# Handle form submission for local authentication # Handle form submission for local authentication
if request.method == 'POST': if request.method == 'POST':
@@ -146,7 +211,24 @@ def login():
session['auth_method'] = 'local' session['auth_method'] = 'local'
session.modified = True session.modified = True
# Return JSON response
response = jsonify({'status': 'success', 'message': 'Login successful'}) response = jsonify({'status': 'success', 'message': 'Login successful'})
# Manually set cookie with correct parameters for Zoraxy
if ZORAXY_COOKIE_FIX:
max_age = int(app.config['PERMANENT_SESSION_LIFETIME'].total_seconds())
cookie_value = request.cookies.get(app.config['SESSION_COOKIE_NAME']) or session.sid
response.set_cookie(
app.config['SESSION_COOKIE_NAME'],
cookie_value,
max_age=max_age,
secure=app.config['SESSION_COOKIE_SECURE'],
httponly=app.config['SESSION_COOKIE_HTTPONLY'],
samesite='None',
path=app.config['SESSION_COOKIE_PATH']
)
logger.info(f"Set fixed cookie for Zoraxy: {app.config['SESSION_COOKIE_NAME']}")
return response return response
else: else:
logger.warning("Login failed: Invalid password") logger.warning("Login failed: Invalid password")
@@ -156,6 +238,12 @@ def login():
if session.get('logged_in'): if session.get('logged_in'):
return redirect(url_for('index')) return redirect(url_for('index'))
# Check cookies and client IP for troubleshooting
if app.debug:
logger.info(f"Cookies: {request.cookies}")
logger.info(f"Client IP: {request.remote_addr}")
logger.info(f"X-Forwarded-For: {request.headers.get('X-Forwarded-For')}")
# Show login form # Show login form
return render_template('login.html') return render_template('login.html')
@@ -195,7 +283,12 @@ def logout():
return redirect(common_authelia_urls[0]) return redirect(common_authelia_urls[0])
# Default case: redirect to login page # Default case: redirect to login page
return redirect(url_for('login')) response = redirect(url_for('login'))
# Clear cookie by setting expired date
response.set_cookie(app.config['SESSION_COOKIE_NAME'], '', expires=0)
return response
@app.route('/') @app.route('/')
def index(): def index():
@@ -214,10 +307,33 @@ def index():
session['auth_method'] = 'authelia' session['auth_method'] = 'authelia'
session.modified = True session.modified = True
# Set cookie manually with correct parameters
response = make_response(render_template('index.html'))
if ZORAXY_COOKIE_FIX:
max_age = int(app.config['PERMANENT_SESSION_LIFETIME'].total_seconds())
cookie_value = request.cookies.get(app.config['SESSION_COOKIE_NAME']) or session.sid
response.set_cookie(
app.config['SESSION_COOKIE_NAME'],
cookie_value,
max_age=max_age,
secure=app.config['SESSION_COOKIE_SECURE'],
httponly=app.config['SESSION_COOKIE_HTTPONLY'],
samesite='None',
path=app.config['SESSION_COOKIE_PATH']
)
logger.info(f"Set fixed cookie for Zoraxy on index: {app.config['SESSION_COOKIE_NAME']}")
return response
# Check if logged in # Check if logged in
if not session.get('logged_in'): if not session.get('logged_in'):
return redirect(url_for('login')) return redirect(url_for('login'))
# Debug logging
if app.debug and session.get('logged_in'):
logger.info(f"User authenticated with method: {session.get('auth_method', 'unknown')}")
# Show main page # Show main page
return render_template('index.html') return render_template('index.html')
@@ -453,7 +569,10 @@ def health_check():
'authenticated': session.get('logged_in', False), 'authenticated': session.get('logged_in', False),
'authelia_user': session.get('authelia_user', None), 'authelia_user': session.get('authelia_user', None),
'auth_method': session.get('auth_method'), 'auth_method': session.get('auth_method'),
'version': '1.0.1' 'version': '1.0.2',
'cookies': {k: '***' for k in request.cookies.keys()}, # Only show cookie names
'authelia_headers_present': get_authelia_user() is not None,
'zoraxy_headers_present': 'X-Forwarded-Server' in request.headers
}) })
# Add a debugging endpoint # Add a debugging endpoint
@@ -489,6 +608,7 @@ def debug_info():
'app_config': { 'app_config': {
'DEBUG': app.debug, 'DEBUG': app.debug,
'PREFERRED_URL_SCHEME': app.config['PREFERRED_URL_SCHEME'], 'PREFERRED_URL_SCHEME': app.config['PREFERRED_URL_SCHEME'],
'ZORAXY_COOKIE_FIX': ZORAXY_COOKIE_FIX
} }
} }
@@ -508,6 +628,37 @@ def show_headers():
'authelia_user': get_authelia_user() 'authelia_user': get_authelia_user()
}) })
# Self-test endpoint for cookies
@app.route('/cookie-test')
def cookie_test():
"""Test cookie handling"""
# Clear any existing cookie
resp = make_response(jsonify({'status': 'ok', 'message': 'Cookie set test'}))
# Set a test cookie with the same attributes as session
resp.set_cookie(
'malias_test_cookie',
'test-value',
max_age=3600,
secure=app.config['SESSION_COOKIE_SECURE'],
httponly=app.config['SESSION_COOKIE_HTTPONLY'],
samesite='None',
path=app.config['SESSION_COOKIE_PATH']
)
return resp
# Endpoint to check if test cookie is set
@app.route('/cookie-check')
def cookie_check():
"""Check if test cookie was properly set"""
test_cookie = request.cookies.get('malias_test_cookie')
return jsonify({
'test_cookie_present': test_cookie is not None,
'test_cookie_value': test_cookie if test_cookie else None,
'all_cookies': {k: '***' for k in request.cookies.keys()}
})
if __name__ == '__main__': if __name__ == '__main__':
# Parse command-line arguments # Parse command-line arguments
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(