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",
[