Fixed login with only ip:port access
This commit is contained in:
130
app.py
130
app.py
@@ -49,12 +49,39 @@ app.config.update(
|
|||||||
|
|
||||||
# Set this to True to use the special cookie fix for Zoraxy
|
# Set this to True to use the special cookie fix for Zoraxy
|
||||||
ZORAXY_COOKIE_FIX = True
|
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):
|
def fix_cookie_for_zoraxy(response):
|
||||||
"""Special handler for Zoraxy cookie issues with SameSite=None"""
|
"""Special handler for Zoraxy cookie issues with SameSite=None"""
|
||||||
if not ZORAXY_COOKIE_FIX:
|
if not ZORAXY_COOKIE_FIX:
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
# Check if this is direct IP access
|
||||||
|
direct_ip = is_direct_ip_access()
|
||||||
|
|
||||||
# Get all cookies from the response
|
# Get all cookies from the response
|
||||||
cookies = response.headers.getlist('Set-Cookie')
|
cookies = response.headers.getlist('Set-Cookie')
|
||||||
if not cookies:
|
if not cookies:
|
||||||
@@ -66,11 +93,21 @@ def fix_cookie_for_zoraxy(response):
|
|||||||
# Fix each cookie and add it back
|
# Fix each cookie and add it back
|
||||||
for cookie in cookies:
|
for cookie in cookies:
|
||||||
if 'malias_session' in cookie and 'SameSite' not in cookie:
|
if 'malias_session' in cookie and 'SameSite' not in cookie:
|
||||||
# Add SameSite=None and Secure attributes
|
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:
|
||||||
|
# For proxy access, use secure settings
|
||||||
if 'HttpOnly' in cookie:
|
if 'HttpOnly' in cookie:
|
||||||
cookie = cookie.replace('HttpOnly', 'HttpOnly; SameSite=None; Secure')
|
cookie = cookie.replace('HttpOnly', 'HttpOnly; SameSite=None; Secure')
|
||||||
else:
|
else:
|
||||||
cookie += '; SameSite=None; Secure'
|
cookie += '; SameSite=None; Secure'
|
||||||
|
|
||||||
response.headers.add('Set-Cookie', cookie)
|
response.headers.add('Set-Cookie', cookie)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
@@ -185,15 +222,17 @@ def login():
|
|||||||
|
|
||||||
# Set a cookie manually to ensure it's properly formatted for Zoraxy
|
# Set a cookie manually to ensure it's properly formatted for Zoraxy
|
||||||
response = redirect(url_for('index'))
|
response = redirect(url_for('index'))
|
||||||
|
# Check if direct IP access
|
||||||
|
direct_ip = is_direct_ip_access()
|
||||||
# Set cookie parameters to work with Zoraxy/Authelia
|
# Set cookie parameters to work with Zoraxy/Authelia
|
||||||
response.set_cookie(
|
response.set_cookie(
|
||||||
key=app.config['SESSION_COOKIE_NAME'],
|
key=app.config['SESSION_COOKIE_NAME'],
|
||||||
value=secrets.token_urlsafe(32), # Generate a new token instead of using session.sid
|
value=secrets.token_urlsafe(32), # Generate a new token instead of using session.sid
|
||||||
max_age=int(app.config['PERMANENT_SESSION_LIFETIME'].total_seconds()),
|
max_age=int(app.config['PERMANENT_SESSION_LIFETIME'].total_seconds()),
|
||||||
path=app.config['SESSION_COOKIE_PATH'],
|
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'],
|
httponly=app.config['SESSION_COOKIE_HTTPONLY'],
|
||||||
samesite='None'
|
samesite='Lax' if direct_ip else 'None' # Lax for IP access, None for proxy
|
||||||
)
|
)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@@ -214,19 +253,22 @@ def login():
|
|||||||
# Return JSON response
|
# 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
|
# Check if direct IP access
|
||||||
if ZORAXY_COOKIE_FIX:
|
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
|
session_token = secrets.token_urlsafe(32) # Generate a new token
|
||||||
response.set_cookie(
|
response.set_cookie(
|
||||||
app.config['SESSION_COOKIE_NAME'],
|
app.config['SESSION_COOKIE_NAME'],
|
||||||
session_token,
|
session_token,
|
||||||
max_age=int(app.config['PERMANENT_SESSION_LIFETIME'].total_seconds()),
|
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'],
|
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']
|
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
|
return response
|
||||||
else:
|
else:
|
||||||
@@ -244,6 +286,7 @@ def login():
|
|||||||
logger.info(f"X-Forwarded-For: {request.headers.get('X-Forwarded-For')}")
|
logger.info(f"X-Forwarded-For: {request.headers.get('X-Forwarded-For')}")
|
||||||
# Log all headers to see what's coming from Authelia
|
# Log all headers to see what's coming from Authelia
|
||||||
logger.info(f"All headers: {dict(request.headers)}")
|
logger.info(f"All headers: {dict(request.headers)}")
|
||||||
|
logger.info(f"Direct IP access: {is_direct_ip_access()}")
|
||||||
|
|
||||||
# Show login form
|
# Show login form
|
||||||
return render_template('login.html')
|
return render_template('login.html')
|
||||||
@@ -286,8 +329,17 @@ def logout():
|
|||||||
# Default case: redirect to login page
|
# Default case: redirect to login page
|
||||||
response = redirect(url_for('login'))
|
response = redirect(url_for('login'))
|
||||||
|
|
||||||
# Clear cookie by setting expired date
|
# Check if direct IP access
|
||||||
response.set_cookie(app.config['SESSION_COOKIE_NAME'], '', expires=0)
|
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
|
return response
|
||||||
|
|
||||||
@@ -311,18 +363,21 @@ def index():
|
|||||||
# Set cookie manually with correct parameters
|
# Set cookie manually with correct parameters
|
||||||
response = make_response(render_template('index.html'))
|
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
|
session_token = secrets.token_urlsafe(32) # Generate a new token
|
||||||
response.set_cookie(
|
response.set_cookie(
|
||||||
app.config['SESSION_COOKIE_NAME'],
|
app.config['SESSION_COOKIE_NAME'],
|
||||||
session_token,
|
session_token,
|
||||||
max_age=int(app.config['PERMANENT_SESSION_LIFETIME'].total_seconds()),
|
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'],
|
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']
|
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
|
return response
|
||||||
|
|
||||||
@@ -569,10 +624,11 @@ 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.2',
|
'version': '1.0.3',
|
||||||
'cookies': {k: '***' for k in request.cookies.keys()}, # Only show cookie names
|
'cookies': {k: '***' for k in request.cookies.keys()}, # Only show cookie names
|
||||||
'authelia_headers_present': get_authelia_user() is not None,
|
'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
|
# Add a debugging endpoint
|
||||||
@@ -594,6 +650,7 @@ def debug_info():
|
|||||||
'x_forwarded_host': request.headers.get('X-Forwarded-Host'),
|
'x_forwarded_host': request.headers.get('X-Forwarded-Host'),
|
||||||
'x_forwarded_prefix': request.headers.get('X-Forwarded-Prefix'),
|
'x_forwarded_prefix': request.headers.get('X-Forwarded-Prefix'),
|
||||||
'remote_user': get_authelia_user(),
|
'remote_user': get_authelia_user(),
|
||||||
|
'direct_ip_access': is_direct_ip_access()
|
||||||
}
|
}
|
||||||
|
|
||||||
# Additional server information
|
# Additional server information
|
||||||
@@ -608,7 +665,8 @@ 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
|
'ZORAXY_COOKIE_FIX': ZORAXY_COOKIE_FIX,
|
||||||
|
'ALLOW_IP_ACCESS': ALLOW_IP_ACCESS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -627,24 +685,32 @@ def show_headers():
|
|||||||
return jsonify({
|
return jsonify({
|
||||||
'headers': dict(request.headers),
|
'headers': dict(request.headers),
|
||||||
'remote_addr': request.remote_addr,
|
'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
|
# Self-test endpoint for cookies
|
||||||
@app.route('/cookie-test')
|
@app.route('/cookie-test')
|
||||||
def cookie_test():
|
def cookie_test():
|
||||||
"""Test cookie handling"""
|
"""Test cookie handling"""
|
||||||
|
# Check if direct IP access
|
||||||
|
direct_ip = is_direct_ip_access()
|
||||||
|
|
||||||
# Clear any existing cookie
|
# 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
|
# Set a test cookie with the same attributes as session
|
||||||
resp.set_cookie(
|
resp.set_cookie(
|
||||||
'malias_test_cookie',
|
'malias_test_cookie',
|
||||||
'test-value',
|
'test-value',
|
||||||
max_age=3600,
|
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'],
|
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']
|
path=app.config['SESSION_COOKIE_PATH']
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -655,10 +721,13 @@ def cookie_test():
|
|||||||
def cookie_check():
|
def cookie_check():
|
||||||
"""Check if test cookie was properly set"""
|
"""Check if test cookie was properly set"""
|
||||||
test_cookie = request.cookies.get('malias_test_cookie')
|
test_cookie = request.cookies.get('malias_test_cookie')
|
||||||
|
direct_ip = is_direct_ip_access()
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'test_cookie_present': test_cookie is not None,
|
'test_cookie_present': test_cookie is not None,
|
||||||
'test_cookie_value': test_cookie if test_cookie else 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
|
# 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,
|
'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'),
|
'host_header': request.headers.get('Host'),
|
||||||
'referer': request.headers.get('Referer'),
|
'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__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
Reference in New Issue
Block a user