This is an automated email from the ASF dual-hosted git repository. vavila pushed a commit to branch fix/consider-app_root-on-login-url in repository https://gitbox.apache.org/repos/asf/superset.git
commit 595907803185f71cbd3b48c5ed1f2667096beac8 Author: Vitor Avila <[email protected]> AuthorDate: Thu Feb 12 17:35:54 2026 -0300 fix: Include app_root in next param --- superset/views/utils.py | 4 +- .../test_subdirectory_deployments.py | 63 ++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/superset/views/utils.py b/superset/views/utils.py index 1ec9e2a54ac..56f0a567cf9 100644 --- a/superset/views/utils.py +++ b/superset/views/utils.py @@ -78,9 +78,9 @@ def redirect_to_login(next_target: str | None = None) -> FlaskResponse: target = next_target if target is None and has_request_context(): if request.query_string: - target = request.full_path.rstrip("?") + target = request.script_root + request.full_path.rstrip("?") else: - target = request.path + target = request.script_root + request.path if target: query["next"] = [target] diff --git a/tests/integration_tests/test_subdirectory_deployments.py b/tests/integration_tests/test_subdirectory_deployments.py index c7676288538..b12f36efe07 100644 --- a/tests/integration_tests/test_subdirectory_deployments.py +++ b/tests/integration_tests/test_subdirectory_deployments.py @@ -17,10 +17,12 @@ """Tests for subdirectory deployment features.""" from unittest.mock import MagicMock +from urllib.parse import parse_qs, urlparse from werkzeug.test import EnvironBuilder from superset.app import AppRootMiddleware +from superset.views.utils import redirect_to_login from tests.integration_tests.base_tests import SupersetTestCase @@ -99,3 +101,64 @@ class TestSubdirectoryDeployments(SupersetTestCase): assert called_environ["PATH_INFO"] == "" # SCRIPT_NAME should be set to the prefix assert called_environ["SCRIPT_NAME"] == "/superset" + + def test_redirect_to_login_with_app_root(self): + """Test that redirect_to_login includes app root in next parameter.""" + with self.app.test_request_context( + "/superset/welcome/", + environ_base={ + "SCRIPT_NAME": "/analytics", + "PATH_INFO": "/superset/welcome/", + }, + ): + response = redirect_to_login() + parsed_url = urlparse(response.location) + query_params = parse_qs(parsed_url.query) + + # The next parameter should include the app root prefix + assert "next" in query_params + assert query_params["next"][0] == "/analytics/superset/welcome/" + + def test_redirect_to_login_with_query_string_and_app_root(self): + """Test that redirect_to_login preserves query string with app root.""" + with self.app.test_request_context( + "/superset/welcome/?foo=bar", + environ_base={ + "SCRIPT_NAME": "/analytics", + "PATH_INFO": "/superset/welcome/", + "QUERY_STRING": "foo=bar", + }, + ): + response = redirect_to_login() + parsed_url = urlparse(response.location) + query_params = parse_qs(parsed_url.query) + + # The next parameter should include both app root and query string + assert "next" in query_params + assert query_params["next"][0] == "/analytics/superset/welcome/?foo=bar" + + def test_redirect_to_login_without_app_root(self): + """Test that redirect_to_login works without app root (no regression).""" + with self.app.test_request_context("/superset/welcome/"): + response = redirect_to_login() + parsed_url = urlparse(response.location) + query_params = parse_qs(parsed_url.query) + + # The next parameter should be the path without any prefix + assert "next" in query_params + assert query_params["next"][0] == "/superset/welcome/" + + def test_redirect_to_login_with_custom_target_and_app_root(self): + """Test that redirect_to_login respects custom target parameter.""" + with self.app.test_request_context( + "/some/other/path", + environ_base={"SCRIPT_NAME": "/analytics", "PATH_INFO": "/some/other/path"}, + ): + # When next_target is explicitly provided, it should be used as-is + custom_target = "/custom/target" + response = redirect_to_login(next_target=custom_target) + parsed_url = urlparse(response.location) + query_params = parse_qs(parsed_url.query) + + assert "next" in query_params + assert query_params["next"][0] == custom_target
