Fixed login with only ip:port access
This commit is contained in:
145
app.py
145
app.py
@@ -21,71 +21,78 @@ logger = logging.getLogger('mailcow-alias-manager')
|
||||
app = Flask(__name__)
|
||||
app.secret_key = os.getenv('SECRET_KEY', 'malias-default-secret-key-please-change') # Consistent secret key
|
||||
|
||||
# Configure for reverse proxy - modified to handle multiple proxy layers including Authelia
|
||||
# Increasing the number of proxies to handle Zoraxy->Authelia->App chain
|
||||
app.wsgi_app = ProxyFix(
|
||||
app.wsgi_app,
|
||||
x_for=2, # Trust X-Forwarded-For with 2 proxies (Zoraxy + Authelia)
|
||||
x_proto=2, # Trust X-Forwarded-Proto (http/https)
|
||||
x_host=2, # Trust X-Forwarded-Host
|
||||
x_prefix=2 # Trust X-Forwarded-Prefix
|
||||
)
|
||||
# Configure proxy mode based on environment variable
|
||||
# ENABLE_PROXY=true: Behind reverse proxy (Authelia/Zoraxy/Nginx/etc.)
|
||||
# ENABLE_PROXY=false: Direct IP:port access (default)
|
||||
ENABLE_PROXY = os.getenv('ENABLE_PROXY', 'false').lower() in ('true', '1', 'yes')
|
||||
|
||||
if ENABLE_PROXY:
|
||||
# Mode: Behind reverse proxy (Authelia/Zoraxy/Nginx/etc.)
|
||||
logger.info("=" * 60)
|
||||
logger.info(" ACCESS MODE: Reverse Proxy (ENABLE_PROXY=true)")
|
||||
logger.info("=" * 60)
|
||||
logger.info(" Configuration:")
|
||||
logger.info(" - ProxyFix middleware: ACTIVE")
|
||||
logger.info(" - Trusted proxies: 2 (e.g., Zoraxy + Authelia)")
|
||||
logger.info(" - Cookie security: HTTPS only (Secure=True)")
|
||||
logger.info(" - SameSite policy: None (cross-origin auth)")
|
||||
logger.info(" - URL scheme: https://")
|
||||
logger.info("=" * 60)
|
||||
|
||||
app.wsgi_app = ProxyFix(
|
||||
app.wsgi_app,
|
||||
x_for=2, # Trust X-Forwarded-For with 2 proxies
|
||||
x_proto=2, # Trust X-Forwarded-Proto (http/https)
|
||||
x_host=2, # Trust X-Forwarded-Host
|
||||
x_prefix=2 # Trust X-Forwarded-Prefix
|
||||
)
|
||||
|
||||
cookie_secure = True
|
||||
cookie_samesite = 'None'
|
||||
preferred_scheme = 'https'
|
||||
else:
|
||||
# Mode: Direct IP:port access (no proxy)
|
||||
logger.info("=" * 60)
|
||||
logger.info(" ACCESS MODE: Direct IP:Port (ENABLE_PROXY=false)")
|
||||
logger.info("=" * 60)
|
||||
logger.info(" Configuration:")
|
||||
logger.info(" - ProxyFix middleware: DISABLED")
|
||||
logger.info(" - Cookie security: HTTP allowed (Secure=False)")
|
||||
logger.info(" - SameSite policy: Lax (standard mode)")
|
||||
logger.info(" - URL scheme: http://")
|
||||
logger.info(" - Access via: http://your-ip:5172")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# Don't apply ProxyFix for direct access
|
||||
cookie_secure = False
|
||||
cookie_samesite = 'Lax'
|
||||
preferred_scheme = 'http'
|
||||
|
||||
# Initialize database on startup
|
||||
malias_w.init_database()
|
||||
|
||||
# Session configuration optimized for reverse proxy with Authelia
|
||||
# Session configuration - dynamic based on proxy mode
|
||||
app.config.update(
|
||||
PERMANENT_SESSION_LIFETIME=timedelta(hours=24),
|
||||
SESSION_COOKIE_NAME='malias_session', # Unique name to avoid conflicts with Authelia
|
||||
SESSION_COOKIE_SECURE=True, # Always use secure cookies with Authelia
|
||||
SESSION_COOKIE_NAME='malias_session',
|
||||
SESSION_COOKIE_SECURE=cookie_secure,
|
||||
SESSION_COOKIE_HTTPONLY=True,
|
||||
SESSION_COOKIE_SAMESITE='None', # Required for authentication proxies
|
||||
SESSION_COOKIE_SAMESITE=cookie_samesite,
|
||||
SESSION_COOKIE_PATH='/',
|
||||
SESSION_COOKIE_DOMAIN=None, # Let browser auto-set domain
|
||||
SESSION_REFRESH_EACH_REQUEST=True, # Keep session alive
|
||||
PREFERRED_URL_SCHEME='https'
|
||||
SESSION_COOKIE_DOMAIN=None,
|
||||
SESSION_REFRESH_EACH_REQUEST=True,
|
||||
PREFERRED_URL_SCHEME=preferred_scheme
|
||||
)
|
||||
|
||||
# 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
|
||||
def after_request(response):
|
||||
"""Process the response before it's sent"""
|
||||
# Apply special cookie fix for Zoraxy
|
||||
response = fix_cookie_for_zoraxy(response)
|
||||
if ENABLE_PROXY:
|
||||
# Set CORS headers for proxy mode (needed for Authelia/Zoraxy)
|
||||
response.headers['Access-Control-Allow-Origin'] = request.headers.get('Origin', '*')
|
||||
response.headers['Access-Control-Allow-Credentials'] = 'true'
|
||||
|
||||
# Set CORS headers to allow Zoraxy and Authelia to work together
|
||||
response.headers['Access-Control-Allow-Origin'] = request.headers.get('Origin', '*')
|
||||
response.headers['Access-Control-Allow-Credentials'] = 'true'
|
||||
|
||||
# Cache control
|
||||
# Cache control (applies to both modes)
|
||||
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
|
||||
response.headers['Pragma'] = 'no-cache'
|
||||
response.headers['Expires'] = '0'
|
||||
@@ -213,21 +220,6 @@ def login():
|
||||
|
||||
# Return JSON response
|
||||
response = jsonify({'status': 'success', 'message': 'Login successful'})
|
||||
|
||||
# Manually set cookie with correct parameters for Zoraxy
|
||||
if ZORAXY_COOKIE_FIX:
|
||||
session_token = secrets.token_urlsafe(32) # Generate a new token
|
||||
response.set_cookie(
|
||||
app.config['SESSION_COOKIE_NAME'],
|
||||
session_token,
|
||||
max_age=int(app.config['PERMANENT_SESSION_LIFETIME'].total_seconds()),
|
||||
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
|
||||
else:
|
||||
logger.warning("Login failed: Invalid password")
|
||||
@@ -307,24 +299,7 @@ def index():
|
||||
session['user_token'] = secrets.token_urlsafe(32)
|
||||
session['auth_method'] = 'authelia'
|
||||
session.modified = True
|
||||
|
||||
# Set cookie manually with correct parameters
|
||||
response = make_response(render_template('index.html'))
|
||||
|
||||
if ZORAXY_COOKIE_FIX:
|
||||
session_token = secrets.token_urlsafe(32) # Generate a new token
|
||||
response.set_cookie(
|
||||
app.config['SESSION_COOKIE_NAME'],
|
||||
session_token,
|
||||
max_age=int(app.config['PERMANENT_SESSION_LIFETIME'].total_seconds()),
|
||||
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
|
||||
return render_template('index.html')
|
||||
|
||||
# Check if logged in
|
||||
if not session.get('logged_in'):
|
||||
@@ -608,7 +583,7 @@ def debug_info():
|
||||
'app_config': {
|
||||
'DEBUG': app.debug,
|
||||
'PREFERRED_URL_SCHEME': app.config['PREFERRED_URL_SCHEME'],
|
||||
'ZORAXY_COOKIE_FIX': ZORAXY_COOKIE_FIX
|
||||
'ENABLE_PROXY': ENABLE_PROXY
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user