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

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new ebdf48b3a94 urlencode next url during redirects (#62707)
ebdf48b3a94 is described below

commit ebdf48b3a94f7e88a1e5ed611bdba8a3537bd620
Author: Daniel Wolf <[email protected]>
AuthorDate: Tue Mar 3 20:29:59 2026 +0100

    urlencode next url during redirects (#62707)
---
 .../api_fastapi/core_api/routes/public/auth.py       |  4 +++-
 .../api_fastapi/core_api/routes/public/test_auth.py  | 20 +++++++++++++++++++-
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/auth.py 
b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/auth.py
index a20bb21720a..17f5edd1347 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/routes/public/auth.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/routes/public/auth.py
@@ -16,6 +16,8 @@
 # under the License.
 from __future__ import annotations
 
+from urllib.parse import urlencode
+
 import structlog
 from fastapi import HTTPException, Request, status
 from fastapi.responses import RedirectResponse
@@ -44,7 +46,7 @@ def login(request: Request, auth_manager: AuthManagerDep, 
next: None | str = Non
         raise HTTPException(status_code=400, detail="Invalid or unsafe next 
URL")
 
     if next:
-        login_url += f"?next={next}"
+        login_url += f"?{urlencode({'next': next})}"
 
     return RedirectResponse(login_url)
 
diff --git 
a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_auth.py 
b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_auth.py
index 07b6876fa3b..c860c847501 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_auth.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/public/test_auth.py
@@ -18,6 +18,7 @@ from __future__ import annotations
 
 import time
 from unittest.mock import MagicMock, patch
+from urllib.parse import parse_qs, urlencode
 
 import jwt
 import pytest
@@ -60,11 +61,28 @@ class TestGetLogin(TestAuthEndpoint):
 
         assert response.status_code == 307
         assert (
-            response.headers["location"] == 
f"{AUTH_MANAGER_LOGIN_URL}?next={params.get('next')}"
+            response.headers["location"]
+            == f"{AUTH_MANAGER_LOGIN_URL}?{urlencode({'next': 
params.get('next')})}"
             if params.get("next")
             else AUTH_MANAGER_LOGIN_URL
         )
 
+    @patch("airflow.api_fastapi.core_api.routes.public.auth.is_safe_url", 
return_value=True)
+    def test_next_url_correctly_encoded(self, mock_is_safe_url, test_client):
+        """Test that special characters in the next URL are correctly url 
encoded."""
+        next_url = 
"http://localhost:8080/dags/my_dag/runs/manual__2026-03-02T12:45:13.113989+00:00/tasks/t";
+        response = test_client.get("/auth/login", follow_redirects=False, 
params={"next": next_url})
+
+        assert response.status_code == 307
+        location = response.headers["location"]
+        query_string = location.split("?", 1)[1]
+        # Literals that have special meaning in query strings must be url 
encoded.
+        assert "+" not in query_string
+        assert ":" not in query_string
+        assert "/" not in query_string
+        # Decoding the query string must recover the original URL unchanged.
+        assert parse_qs(query_string)["next"][0] == next_url
+
     @pytest.mark.parametrize(
         "params",
         [

Reply via email to