From c81f6f1ab8c63280cd0da2ada37df248a5ed6ac5 Mon Sep 17 00:00:00 2001 From: Rune Olsen Date: Fri, 23 Jan 2026 12:10:52 +0100 Subject: [PATCH] Fixed login with only ip:port access --- app.py | 136 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 111 insertions(+), 25 deletions(-) diff --git a/app.py b/app.py index 1210e5b..9daea0c 100644 --- a/app.py +++ b/app.py @@ -49,12 +49,39 @@ app.config.update( # Set this to True to use the special cookie fix for Zoraxy ZORAXY_COOKIE_FIX = True +# Set this to True to enable direct IP access (without secure cookies) +ALLOW_IP_ACCESS = True + +def is_direct_ip_access(): + """Check if the request is coming from a direct IP access (not through reverse proxy)""" + # Check for Zoraxy/proxy headers + zoraxy_headers = [ + 'X-Forwarded-For', + 'X-Forwarded-Host', + 'X-Forwarded-Proto', + 'X-Forwarded-Server' + ] + + # If any of these headers exist, it's likely coming through Zoraxy + for header in zoraxy_headers: + if header in request.headers: + return False + + # If host starts with an IP address, it's direct access + host = request.headers.get('Host', '') + if host.startswith('127.0.0.1') or host.startswith('192.168.') or host.startswith('10.'): + return True + + return 'localhost' in host.lower() def fix_cookie_for_zoraxy(response): """Special handler for Zoraxy cookie issues with SameSite=None""" if not ZORAXY_COOKIE_FIX: return response + # Check if this is direct IP access + direct_ip = is_direct_ip_access() + # Get all cookies from the response cookies = response.headers.getlist('Set-Cookie') if not cookies: @@ -66,11 +93,21 @@ def fix_cookie_for_zoraxy(response): # 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') + if direct_ip: + # For direct IP access, use different cookie settings + if 'HttpOnly' in cookie: + cookie = cookie.replace('HttpOnly', 'HttpOnly; SameSite=Lax') + else: + cookie += '; SameSite=Lax' + # Remove Secure flag for HTTP + cookie = cookie.replace('; Secure', '') else: - cookie += '; SameSite=None; Secure' + # For proxy access, use secure settings + 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 @@ -185,15 +222,17 @@ def login(): # Set a cookie manually to ensure it's properly formatted for Zoraxy response = redirect(url_for('index')) + # Check if direct IP access + direct_ip = is_direct_ip_access() # 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'], + secure=not direct_ip and app.config['SESSION_COOKIE_SECURE'], # Only secure for proxy httponly=app.config['SESSION_COOKIE_HTTPONLY'], - samesite='None' + samesite='Lax' if direct_ip else 'None' # Lax for IP access, None for proxy ) return response @@ -214,19 +253,22 @@ def login(): # Return JSON response response = jsonify({'status': 'success', 'message': 'Login successful'}) - # Manually set cookie with correct parameters for Zoraxy - if ZORAXY_COOKIE_FIX: + # Check if direct IP access + direct_ip = is_direct_ip_access() + + # Manually set cookie with correct parameters + if ZORAXY_COOKIE_FIX or ALLOW_IP_ACCESS: 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'], + secure=not direct_ip and app.config['SESSION_COOKIE_SECURE'], # Only secure for proxy httponly=app.config['SESSION_COOKIE_HTTPONLY'], - samesite='None', + samesite='Lax' if direct_ip else 'None', # Lax for IP access, None for proxy path=app.config['SESSION_COOKIE_PATH'] ) - logger.info(f"Set fixed cookie for Zoraxy: {app.config['SESSION_COOKIE_NAME']}") + logger.info(f"Set fixed cookie for {'direct IP' if direct_ip else 'Zoraxy'}: {app.config['SESSION_COOKIE_NAME']}") return response else: @@ -244,6 +286,7 @@ def login(): logger.info(f"X-Forwarded-For: {request.headers.get('X-Forwarded-For')}") # Log all headers to see what's coming from Authelia logger.info(f"All headers: {dict(request.headers)}") + logger.info(f"Direct IP access: {is_direct_ip_access()}") # Show login form return render_template('login.html') @@ -286,8 +329,17 @@ def logout(): # Default case: redirect to login page response = redirect(url_for('login')) - # Clear cookie by setting expired date - response.set_cookie(app.config['SESSION_COOKIE_NAME'], '', expires=0) + # Check if direct IP access + direct_ip = is_direct_ip_access() + + # Clear cookie by setting expired date, with appropriate settings for the access method + response.set_cookie( + app.config['SESSION_COOKIE_NAME'], + '', expires=0, + secure=not direct_ip and app.config['SESSION_COOKIE_SECURE'], + samesite='Lax' if direct_ip else 'None', + path='/' + ) return response @@ -311,18 +363,21 @@ def index(): # Set cookie manually with correct parameters response = make_response(render_template('index.html')) - if ZORAXY_COOKIE_FIX: + # Check if direct IP access + direct_ip = is_direct_ip_access() + + if ZORAXY_COOKIE_FIX or ALLOW_IP_ACCESS: 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'], + secure=not direct_ip and app.config['SESSION_COOKIE_SECURE'], # Only secure for proxy httponly=app.config['SESSION_COOKIE_HTTPONLY'], - samesite='None', + samesite='Lax' if direct_ip else 'None', # Lax for IP access, None for proxy path=app.config['SESSION_COOKIE_PATH'] ) - logger.info(f"Set fixed cookie for Zoraxy on index: {app.config['SESSION_COOKIE_NAME']}") + logger.info(f"Set fixed cookie for {'direct IP' if direct_ip else 'Zoraxy'}: {app.config['SESSION_COOKIE_NAME']}") return response @@ -569,10 +624,11 @@ def health_check(): 'authenticated': session.get('logged_in', False), 'authelia_user': session.get('authelia_user', None), 'auth_method': session.get('auth_method'), - 'version': '1.0.2', + 'version': '1.0.3', '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 + 'zoraxy_detected': 'X-Forwarded-Server' in request.headers, + 'direct_ip_access': is_direct_ip_access() }) # Add a debugging endpoint @@ -594,6 +650,7 @@ def debug_info(): 'x_forwarded_host': request.headers.get('X-Forwarded-Host'), 'x_forwarded_prefix': request.headers.get('X-Forwarded-Prefix'), 'remote_user': get_authelia_user(), + 'direct_ip_access': is_direct_ip_access() } # Additional server information @@ -608,7 +665,8 @@ def debug_info(): 'app_config': { 'DEBUG': app.debug, 'PREFERRED_URL_SCHEME': app.config['PREFERRED_URL_SCHEME'], - 'ZORAXY_COOKIE_FIX': ZORAXY_COOKIE_FIX + 'ZORAXY_COOKIE_FIX': ZORAXY_COOKIE_FIX, + 'ALLOW_IP_ACCESS': ALLOW_IP_ACCESS } } @@ -627,24 +685,32 @@ def show_headers(): return jsonify({ 'headers': dict(request.headers), 'remote_addr': request.remote_addr, - 'authelia_user': get_authelia_user() + 'authelia_user': get_authelia_user(), + 'direct_ip_access': is_direct_ip_access() }) # Self-test endpoint for cookies @app.route('/cookie-test') def cookie_test(): """Test cookie handling""" + # Check if direct IP access + direct_ip = is_direct_ip_access() + # Clear any existing cookie - resp = make_response(jsonify({'status': 'ok', 'message': 'Cookie set test'})) + resp = make_response(jsonify({ + 'status': 'ok', + 'message': 'Cookie set test', + 'direct_ip_access': direct_ip + })) # 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'], + secure=not direct_ip and app.config['SESSION_COOKIE_SECURE'], # Only secure for proxy httponly=app.config['SESSION_COOKIE_HTTPONLY'], - samesite='None', + samesite='Lax' if direct_ip else 'None', # Lax for IP access, None for proxy path=app.config['SESSION_COOKIE_PATH'] ) @@ -655,10 +721,13 @@ def cookie_test(): def cookie_check(): """Check if test cookie was properly set""" test_cookie = request.cookies.get('malias_test_cookie') + direct_ip = is_direct_ip_access() + 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()} + 'all_cookies': {k: '***' for k in request.cookies.keys()}, + 'direct_ip_access': direct_ip }) # New endpoint to test Zoraxy auth configuration @@ -697,6 +766,23 @@ def authelia_test(): 'zoraxy_detected': any('zoraxy' in h.lower() for h in all_headers.keys()) or 'X-Forwarded-Server' in all_headers, 'host_header': request.headers.get('Host'), 'referer': request.headers.get('Referer'), + 'direct_ip_access': is_direct_ip_access() + }) + +# New endpoint to test direct IP access detection +@app.route('/ip-test') +def ip_test(): + """Test if the request is coming from direct IP access""" + return jsonify({ + 'direct_ip_access': is_direct_ip_access(), + 'host': request.headers.get('Host', ''), + 'remote_addr': request.remote_addr, + 'proxy_headers': { + 'x_forwarded_for': request.headers.get('X-Forwarded-For'), + 'x_forwarded_host': request.headers.get('X-Forwarded-Host'), + 'x_forwarded_proto': request.headers.get('X-Forwarded-Proto'), + 'x_forwarded_server': request.headers.get('X-Forwarded-Server') + } }) if __name__ == '__main__':