This is an automated email from the ASF dual-hosted git repository.

vincbeck pushed a commit to branch v3-2-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-2-test by this push:
     new aa4592bafd8 Fix SimpleAuthManager redirect to next URL after login 
(#67483) (#67784)
aa4592bafd8 is described below

commit aa4592bafd859e3e92334f4582831baf485e468d
Author: GayathriSrividya <[email protected]>
AuthorDate: Mon Jun 1 22:30:36 2026 +0530

    Fix SimpleAuthManager redirect to next URL after login (#67483) (#67784)
---
 .../auth/managers/simple/routes/login.py           |  6 +++++-
 .../auth/managers/simple/routes/test_login.py      | 22 ++++++++++++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git 
a/airflow-core/src/airflow/api_fastapi/auth/managers/simple/routes/login.py 
b/airflow-core/src/airflow/api_fastapi/auth/managers/simple/routes/login.py
index f65aa71f223..d7076865e7a 100644
--- a/airflow-core/src/airflow/api_fastapi/auth/managers/simple/routes/login.py
+++ b/airflow-core/src/airflow/api_fastapi/auth/managers/simple/routes/login.py
@@ -28,6 +28,7 @@ from airflow.api_fastapi.auth.managers.simple.utils import 
parse_login_body
 from airflow.api_fastapi.common.router import AirflowRouter
 from airflow.api_fastapi.common.types import Mimetype
 from airflow.api_fastapi.core_api.openapi.exceptions import 
create_openapi_http_exception_doc
+from airflow.api_fastapi.core_api.security import is_safe_url
 from airflow.configuration import conf
 
 login_router = AirflowRouter(tags=["SimpleAuthManagerLogin"])
@@ -85,7 +86,10 @@ def create_token_all_admins() -> LoginResponse:
 )
 def login_all_admins(request: Request) -> RedirectResponse:
     """Login the user with no credentials."""
-    response = RedirectResponse(url=conf.get("api", "base_url", fallback="/"))
+    fallback_url = conf.get("api", "base_url", fallback="/")
+    next_url = request.query_params.get("next")
+    redirect_url = next_url if next_url and is_safe_url(next_url, 
request=request) else fallback_url
+    response = RedirectResponse(url=redirect_url)
 
     # The default config has this as an empty string, so we can't use 
`has_option`.
     # And look at the request info (needs `--proxy-headers` flag to api-server)
diff --git 
a/airflow-core/tests/unit/api_fastapi/auth/managers/simple/routes/test_login.py 
b/airflow-core/tests/unit/api_fastapi/auth/managers/simple/routes/test_login.py
index 8729b483b4a..14e946bdc7f 100644
--- 
a/airflow-core/tests/unit/api_fastapi/auth/managers/simple/routes/test_login.py
+++ 
b/airflow-core/tests/unit/api_fastapi/auth/managers/simple/routes/test_login.py
@@ -86,6 +86,28 @@ class TestLogin:
             assert "location" in response.headers
             assert response.cookies.get("_token") is not None
 
+    def test_login_all_admins_redirects_to_next_url(self, test_client):
+        with conf_vars({("core", "simple_auth_manager_all_admins"): "true", 
("api", "ssl_cert"): "false"}):
+            response = test_client.get(
+                
"/auth/token/login?next=/dags/example_dag/runs/manual__2026-05-20/tasks/example_task",
+                follow_redirects=False,
+            )
+            assert response.status_code == 307
+            assert (
+                response.headers["location"] == 
"/dags/example_dag/runs/manual__2026-05-20/tasks/example_task"
+            )
+            assert response.cookies.get("_token") is not None
+
+    def test_login_all_admins_ignores_unsafe_next_url(self, test_client):
+        with conf_vars({("core", "simple_auth_manager_all_admins"): "true", 
("api", "ssl_cert"): "false"}):
+            response = test_client.get(
+                "/auth/token/login?next=https://example.com/malicious";,
+                follow_redirects=False,
+            )
+            assert response.status_code == 307
+            assert response.headers["location"] == "/"
+            assert response.cookies.get("_token") is not None
+
     def test_login_all_admins_config_disabled(self, test_client):
         response = test_client.get("/auth/token/login", follow_redirects=False)
         assert response.status_code == 403

Reply via email to