You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by mi...@apache.org on 2026/09/21 21:14:39 UTC
(superset) branch master updated: fix(security): skip session checks for health probes (#43786)
This is an automated email from the ASF dual-hosted git repository.
aminghadersohi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 782b7ae924c fix(security): skip session checks for health probes (#43786)
782b7ae924c is described below
commit 782b7ae924cb6508d0ba04a3098ad0725ae6a119
Author: Amin Ghadersohi <am...@gmail.com>
AuthorDate: Tue Sep 22 07:14:31 2026 +1000
fix(security): skip session checks for health probes (#43786)
---
superset/security/session_invalidation.py | 16 +++++++++++++++-
tests/unit_tests/security/test_session_invalidation.py | 18 ++++++++++++++++++
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/superset/security/session_invalidation.py b/superset/security/session_invalidation.py
index a15a8b9b14d..670aed3bae9 100644
--- a/superset/security/session_invalidation.py
+++ b/superset/security/session_invalidation.py
@@ -38,7 +38,7 @@ import math
from datetime import datetime, timezone
from typing import Any, Optional
-from flask import flash, session
+from flask import flash, has_request_context, request, session
from flask_babel import gettext as __
from flask_login import current_user, logout_user
from sqlalchemy import event, inspect, or_
@@ -50,6 +50,12 @@ logger = logging.getLogger(__name__)
#: Session key holding the epoch-seconds timestamp of when the session logged in.
SESSION_LOGIN_AT_KEY = "_login_at"
+# Health checks are deliberately independent of authentication and the metadata
+# database, so they must not resolve ``current_user`` or perform session checks.
+# Every probe rule registered by ``health()`` in ``superset/views/health.py``
+# resolves to this single endpoint.
+_HEALTH_CHECK_ENDPOINT = "health.health"
+
def _utcnow() -> datetime:
return datetime.now(timezone.utc)
@@ -108,6 +114,14 @@ def enforce_session_validity() -> Optional[Response]:
Fails open — any error here logs a warning and allows the request rather
than risk locking everyone out on a bug in the check.
"""
+ # Do this before touching current_user: it is a LocalProxy whose resolution
+ # may query the metadata DB. Probes do not need session invalidation
+ # enforcement. Flask matches the URL in ``RequestContext.push()``, before
+ # ``preprocess_request()`` runs the ``before_request`` funcs, so
+ # ``request.endpoint`` is already resolved here.
+ if has_request_context() and request.endpoint == _HEALTH_CHECK_ENDPOINT:
+ return None
+
try:
user = current_user
if not user or not getattr(user, "is_authenticated", False):
diff --git a/tests/unit_tests/security/test_session_invalidation.py b/tests/unit_tests/security/test_session_invalidation.py
index 85f5e1c70fc..9c5574d6dfc 100644
--- a/tests/unit_tests/security/test_session_invalidation.py
+++ b/tests/unit_tests/security/test_session_invalidation.py
@@ -17,6 +17,7 @@
from datetime import datetime, timedelta, timezone
from types import SimpleNamespace
+from typing import Any
from unittest.mock import MagicMock, patch
from sqlalchemy.exc import IntegrityError
@@ -95,6 +96,23 @@ def test_enforce_skips_unauthenticated_user() -> None:
logout.assert_not_called()
+def test_enforce_skips_health_check_before_resolving_user(app: Any) -> None:
+ """Health probes must not resolve current_user or touch metadata."""
+ rules = [str(r) for r in app.url_map.iter_rules() if r.endpoint == "health.health"]
+ assert rules, "no health probe routes registered"
+ for rule in rules:
+ with app.test_request_context(rule):
+ with (
+ patch(f"{MODULE}.current_user") as current,
+ patch(f"{MODULE}.logger.warning") as warning,
+ patch(f"{MODULE}.logout_user") as logout,
+ ):
+ assert enforce_session_validity() is None
+ current.__bool__.assert_not_called()
+ warning.assert_not_called()
+ logout.assert_not_called()
+
+
def test_enforce_skips_guest_user() -> None:
"""Guest (embedded) users have their own revocation path and are skipped."""
with (