Skip to content

Commit a7cef48

Browse files
committed
Bump flask-appbuilder to 5.2.1 and mirror new auth event hooks
Upstream FAB 5.2.1 was released to PyPI on 2026-04-09 (no GitHub release was cut, only a master commit `5dae8164` titled "release: 5.2.1"). It adds three vendored-relevant items on top of 5.2.0: - PR #2450 (commit 63e7708e) — three new no-op hook methods on BaseSecurityManager: on_user_login, on_user_login_failed, on_user_logout. update_user_auth_stat now calls on_user_login or on_user_login_failed at the end. AuthView.logout / SAML SLO call on_user_logout. Hook defaults are no-ops; subclasses can override for audit logging. - PR #2451 — _is_user_detached / _get_safe_user helpers + a rewrite of has_access to handle DetachedInstanceError on g.user (LocalProxy or detached ORM instance after some session boundary). Inherited automatically; not vendored in override.py so no mirror needed. - PR #2440 — security log redactions: OAuth tokens / responses no longer logged at debug level. Inherited; the redacted code paths are not vendored in override.py. Mirror the auth-event-hook pieces into FabAirflowSecurityManagerOverride since update_user_auth_stat is vendored. Without this mirror, the new hooks would not fire in Airflow because override.py shadows the upstream implementation. Specifically: - Add no-op on_user_login / on_user_login_failed / on_user_logout methods on FabAirflowSecurityManagerOverride mirroring the FAB defaults. - Append the on_user_login / on_user_login_failed dispatch at the end of FabAirflowSecurityManagerOverride.update_user_auth_stat, matching the upstream order (called after update_user, so the counters / last_login are already persisted before the hook runs). Bump EXPECTED_FAB_VERSION in test_fab_alignment.py to 5.2.1; all 7 alignment tests + 39 security_manager unit tests pass locally with flask-appbuilder==5.2.1 installed. The pyjwt floor pin from the parent commit on this branch is unchanged; the lock-file bump for it is included here because uv re-resolved the graph for the FAB version bump.
1 parent d711e88 commit a7cef48

5 files changed

Lines changed: 44 additions & 7 deletions

File tree

providers/fab/docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ PIP package Version required
111111
``apache-airflow-providers-common-compat`` ``>=1.12.0``
112112
``blinker`` ``>=1.6.2``
113113
``flask`` ``>=2.2.1``
114-
``flask-appbuilder`` ``==5.2.0``
114+
``flask-appbuilder`` ``==5.2.1``
115115
``pyjwt`` ``>=2.11.0``
116116
``flask-login`` ``>=0.6.2; python_version < "3.14"``
117117
``flask-login`` ``>=0.6.3; python_version >= "3.14"``

providers/fab/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ dependencies = [
7777
# Every time we update FAB version here, please make sure that you review the classes and models in
7878
# `airflow/providers/fab/auth_manager/security_manager/override.py` with their upstream counterparts.
7979
# In particular, make sure any breaking changes, for example any new methods, are accounted for.
80-
"flask-appbuilder==5.2.0", # Whenever updating the version, run test_fab_alignment.py to verify.
80+
"flask-appbuilder==5.2.1", # Whenever updating the version, run test_fab_alignment.py to verify.
8181
# Transitive via flask-appbuilder -> flask-jwt-extended; pinned here so the FAB
8282
# provider keeps installing cleanly when paired with older airflow-core releases
8383
# (the compat-3.0.6 matrix job) whose own pyjwt floor predates `jwt.types.Options`

providers/fab/src/airflow/providers/fab/auth_manager/security_manager/override.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,6 +1544,36 @@ def del_register_user(self, register_user) -> bool:
15441544
def get_all_users(self) -> list[User]:
15451545
return self.session.scalars(select(self.user_model)).all()
15461546

1547+
def on_user_login(self, user) -> None:
1548+
"""
1549+
Run after a successful user login.
1550+
1551+
Override to add custom logic (e.g. audit logging). Mirrors
1552+
``BaseSecurityManager.on_user_login`` from FAB 5.2.1+.
1553+
1554+
:param user: The authenticated user model.
1555+
"""
1556+
1557+
def on_user_login_failed(self, user) -> None:
1558+
"""
1559+
Run after a failed user login attempt.
1560+
1561+
Override to add custom logic (e.g. audit logging). Mirrors
1562+
``BaseSecurityManager.on_user_login_failed`` from FAB 5.2.1+.
1563+
1564+
:param user: The identified (but not authenticated) user model.
1565+
"""
1566+
1567+
def on_user_logout(self, user) -> None:
1568+
"""
1569+
Run when a user logs out.
1570+
1571+
Override to add custom logic (e.g. audit logging). Mirrors
1572+
``BaseSecurityManager.on_user_logout`` from FAB 5.2.1+.
1573+
1574+
:param user: The user model that is logging out.
1575+
"""
1576+
15471577
def update_user_auth_stat(self, user, success=True) -> None:
15481578
"""
15491579
Update user authentication stats.
@@ -1569,6 +1599,13 @@ def update_user_auth_stat(self, user, success=True) -> None:
15691599
else:
15701600
user.fail_login_count += 1
15711601
self.update_user(user)
1602+
# Fire the auth event hooks added in FAB 5.2.1 (PR #2450) so subclasses
1603+
# can plug in audit logging / custom side effects without having to
1604+
# override update_user_auth_stat itself.
1605+
if success:
1606+
self.on_user_login(user)
1607+
else:
1608+
self.on_user_login_failed(user)
15721609

15731610
"""
15741611
-------------

providers/fab/tests/unit/fab/auth_manager/security_manager/test_fab_alignment.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
from airflow.providers.fab.auth_manager.security_manager.override import FabAirflowSecurityManagerOverride
4141

4242
# The FAB version that override.py was last aligned with.
43-
EXPECTED_FAB_VERSION = "5.2.0"
43+
EXPECTED_FAB_VERSION = "5.2.1"
4444

4545
# FAB public methods that override.py intentionally does NOT implement.
4646
# Every entry must have a comment explaining why it's excluded.

uv.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)