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

eladkal 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 f663060f405 Fix AUTH_ROLE_PUBLIC returning 401 in FastAPI API server 
(#69773)
f663060f405 is described below

commit f663060f405c14445cf5098aa95e47a684ad1173
Author: John Doe <[email protected]>
AuthorDate: Tue Jul 14 00:17:27 2026 +0900

    Fix AUTH_ROLE_PUBLIC returning 401 in FastAPI API server (#69773)
    
    * Fix AUTH_ROLE_PUBLIC returning 401 in FastAPI API server
    
    FabAuthRolePublicMiddleware only sets request.state.user for
    anonymous requests. Core's get_user() dependency also checks
    request.state.user_authenticated_via for the trusted-middleware
    sentinel before skipping JWT validation, so every anonymous request
    falls through to JWT validation, has no token, and is rejected with
    401 regardless of AUTH_ROLE_PUBLIC (or [fab] auth_role_public) being
    configured correctly.
    
    Set the same trust marker JWTRefreshMiddleware already sets when it
    pre-authenticates a request, so both middlewares honor the same
    contract.
    
    * Fix FAB middleware compatibility with Airflow<3.3
    
    The FAB provider supports Airflow 3.0.2 and later, while
    USER_INJECTED_BY_TRUSTED_MIDDLEWARE is only available in newer core
    releases. Importing it unconditionally prevents the provider from loading
    and causes test collection to fail against supported versions such as
    Airflow 3.0.6.
    
    Preserve trusted middleware authentication on newer core versions without
    requiring older supported versions to expose the marker.
    r Airflow versions
    
    * fix: reflect modifications based on comments
    
    * fix: reflect modifications based on comments
    
    * Update providers/fab/src/airflow/providers/fab/auth_manager/middleware.py
    
    ---------
    
    Co-authored-by: Elad Kalif <[email protected]>
---
 .../src/airflow/providers/fab/auth_manager/middleware.py    | 11 +++++++++++
 .../fab/tests/unit/fab/auth_manager/test_middleware.py      | 13 +++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/providers/fab/src/airflow/providers/fab/auth_manager/middleware.py 
b/providers/fab/src/airflow/providers/fab/auth_manager/middleware.py
index 3bf2cea833c..e16b1af85bb 100644
--- a/providers/fab/src/airflow/providers/fab/auth_manager/middleware.py
+++ b/providers/fab/src/airflow/providers/fab/auth_manager/middleware.py
@@ -23,6 +23,7 @@ from starlette.middleware.base import BaseHTTPMiddleware
 
 from airflow.api_fastapi.app import get_auth_manager
 from airflow.api_fastapi.auth.managers.base_auth_manager import 
COOKIE_NAME_JWT_TOKEN
+from airflow.api_fastapi.core_api import security as core_api_security
 
 if TYPE_CHECKING:
     from fastapi import Request
@@ -44,9 +45,19 @@ class FabAuthRolePublicMiddleware(BaseHTTPMiddleware):
     async def dispatch(self, request: Request, call_next):
         if not self._has_auth_token(request):
             auth_manager = cast("FabAuthManager", get_auth_manager())
+
             public_user = auth_manager.build_public_user()
             if public_user is not None:
                 request.state.user = public_user
+
+                user_injected = getattr(
+                    core_api_security,
+                    "USER_INJECTED_BY_TRUSTED_MIDDLEWARE",
+                    None,
+                )
+                if user_injected is not None:
+                    request.state.user_authenticated_via = user_injected
+
         return await call_next(request)
 
     @staticmethod
diff --git a/providers/fab/tests/unit/fab/auth_manager/test_middleware.py 
b/providers/fab/tests/unit/fab/auth_manager/test_middleware.py
index e4117a0fe91..b6dc2665531 100644
--- a/providers/fab/tests/unit/fab/auth_manager/test_middleware.py
+++ b/providers/fab/tests/unit/fab/auth_manager/test_middleware.py
@@ -21,6 +21,7 @@ from unittest.mock import AsyncMock, Mock, patch
 import pytest
 
 from airflow.api_fastapi.auth.managers.base_auth_manager import 
COOKIE_NAME_JWT_TOKEN
+from airflow.api_fastapi.core_api import security as core_api_security
 from airflow.providers.fab.auth_manager.middleware import 
FabAuthRolePublicMiddleware
 
 
@@ -47,6 +48,18 @@ class TestFabAuthRolePublicMiddleware:
         await middleware.dispatch(request, call_next)
 
         assert request.state.user is public_user
+
+        trusted_marker = getattr(
+            core_api_security,
+            "USER_INJECTED_BY_TRUSTED_MIDDLEWARE",
+            None,
+        )
+
+        if trusted_marker is not None:
+            assert request.state.user_authenticated_via is trusted_marker
+        else:
+            assert not hasattr(request.state, "user_authenticated_via")
+
         auth_manager.build_public_user.assert_called_once_with()
         call_next.assert_awaited_once_with(request)
 

Reply via email to