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

vincbeck 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 c902fea1145 Fix FabAuthManager.get_url_login() dropping next_url 
(#73134)
c902fea1145 is described below

commit c902fea1145290e6e47c3a5c8b2901e945ae5219
Author: TheoLauw <[email protected]>
AuthorDate: Mon Sep 14 18:05:05 2026 +0200

    Fix FabAuthManager.get_url_login() dropping next_url (#73134)
    
    FabAuthManager.get_url_login() accepted **kwargs but never read
    next_url from it, so callers redirecting an unauthenticated or
    expired-session request to the login page (via
    providers/fab/src/airflow/providers/fab/www/auth.py, which already
    passes next_url=request.url) always lost the originally requested
    URL. After completing login, the user landed on the homepage instead
    of the deep link they opened, and had to open the same link a second
    time to reach it.
    
    This mirrors the fix already applied to SimpleAuthManager in #67965,
    which was scoped to SimpleAuthManager only and left FabAuthManager
    with the identical bug.
    
    The rest of the redirect chain (flask_appbuilder's AuthOAuthView/
    AuthDBView reading `next` from the query string into the OAuth state,
    and the redirect/get_safe_redirect monkey-patch in
    providers/fab/www/extensions/init_appbuilder.py that sets the JWT
    cookie and forwards to that URL) already works correctly, so
    propagating next_url into the login URL is the only change needed.
---
 .../airflow/providers/fab/auth_manager/fab_auth_manager.py   |  8 ++++++--
 .../fab/tests/unit/fab/auth_manager/test_fab_auth_manager.py | 12 ++++++++++++
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git 
a/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py 
b/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
index 7e7241e48f0..629b974a2c1 100644
--- a/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
+++ b/providers/fab/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
@@ -23,7 +23,7 @@ import warnings
 from contextlib import suppress
 from functools import cached_property
 from typing import TYPE_CHECKING, Any
-from urllib.parse import urljoin
+from urllib.parse import urlencode, urljoin
 
 from cachetools import TTLCache, cachedmethod
 from fastapi import FastAPI
@@ -706,7 +706,11 @@ class FabAuthManager(BaseAuthManager[User]):
 
     def get_url_login(self, **kwargs) -> str:
         """Return the login page url."""
-        return urljoin(self.apiserver_endpoint, 
f"{AUTH_MANAGER_FASTAPI_APP_PREFIX}/login/")
+        login_url = urljoin(self.apiserver_endpoint, 
f"{AUTH_MANAGER_FASTAPI_APP_PREFIX}/login/")
+        next_url = kwargs.get("next_url")
+        if next_url:
+            return f"{login_url}?{urlencode({'next': next_url})}"
+        return login_url
 
     def get_url_logout(self) -> str | None:
         """Return the logout page url."""
diff --git a/providers/fab/tests/unit/fab/auth_manager/test_fab_auth_manager.py 
b/providers/fab/tests/unit/fab/auth_manager/test_fab_auth_manager.py
index 5ddad4a1ae8..8f5d537039f 100644
--- a/providers/fab/tests/unit/fab/auth_manager/test_fab_auth_manager.py
+++ b/providers/fab/tests/unit/fab/auth_manager/test_fab_auth_manager.py
@@ -22,6 +22,7 @@ from itertools import chain
 from typing import TYPE_CHECKING
 from unittest import mock
 from unittest.mock import MagicMock, Mock
+from urllib.parse import urlencode
 
 import pytest
 from flask import g
@@ -1053,6 +1054,17 @@ class TestFabAuthManager:
         result = auth_manager.get_url_login()
         assert result == f"{AUTH_MANAGER_FASTAPI_APP_PREFIX}/login/"
 
+    def test_get_url_login_with_next_url(self, auth_manager):
+        next_url = 
"http://localhost:8080/dags/example_dag/runs/manual__2026-05-20/tasks/example_task";
+        result = auth_manager.get_url_login(next_url=next_url)
+        assert result == 
f"{AUTH_MANAGER_FASTAPI_APP_PREFIX}/login/?{urlencode({'next': next_url})}"
+
+    def test_get_url_login_without_next_url_kwarg(self, auth_manager):
+        # Callers that don't pass next_url (or pass an empty one) must keep 
getting the
+        # bare login url, matching the pre-existing behavior relied on 
elsewhere.
+        result = auth_manager.get_url_login(next_url=None)
+        assert result == f"{AUTH_MANAGER_FASTAPI_APP_PREFIX}/login/"
+
     def test_get_url_logout(self, auth_manager):
         result = auth_manager.get_url_logout()
         assert result == f"{AUTH_MANAGER_FASTAPI_APP_PREFIX}/logout"

Reply via email to