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 d536ec4bd1 fab_auth_manager: allow get_user method to return the user
authenticated via Kerberos (#43662)
d536ec4bd1 is described below
commit d536ec4bd1da958d2f2e5822a6fec647baa12ba9
Author: Balthazar Rouberol <[email protected]>
AuthorDate: Tue Nov 5 17:07:02 2024 +0100
fab_auth_manager: allow get_user method to return the user authenticated
via Kerberos (#43662)
---
.../providers/fab/auth_manager/fab_auth_manager.py | 15 +++++++++++--
.../fab/auth_manager/test_fab_auth_manager.py | 26 +++++++++++++++++++---
2 files changed, 36 insertions(+), 5 deletions(-)
diff --git
a/providers/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
b/providers/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
index 8a8fad6788..e93e440f5d 100644
--- a/providers/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
+++ b/providers/src/airflow/providers/fab/auth_manager/fab_auth_manager.py
@@ -25,7 +25,7 @@ from typing import TYPE_CHECKING, Container
import packaging.version
from connexion import FlaskApi
-from flask import Blueprint, url_for
+from flask import Blueprint, g, url_for
from packaging.version import Version
from sqlalchemy import select
from sqlalchemy.orm import Session, joinedload
@@ -183,9 +183,20 @@ class FabAuthManager(BaseAuthManager):
return f"{first_name} {last_name}".strip()
def get_user(self) -> User:
- """Return the user associated to the user in session."""
+ """
+ Return the user associated to the user in session.
+
+ Attempt to find the current user in g.user, as defined by the kerberos
authentication backend.
+ If no such user is found, return the `current_user` local proxy
object, linked to the user session.
+
+ """
from flask_login import current_user
+ # If a user has gone through the Kerberos dance, the kerberos
authentication manager
+ # has linked it with a User model, stored in g.user, and not the
session.
+ if current_user.is_anonymous and getattr(g, "user", None) is not None
and not g.user.is_anonymous:
+ return g.user
+
return current_user
def init(self) -> None:
diff --git a/providers/tests/fab/auth_manager/test_fab_auth_manager.py
b/providers/tests/fab/auth_manager/test_fab_auth_manager.py
index 91efb8428c..d298f7667e 100644
--- a/providers/tests/fab/auth_manager/test_fab_auth_manager.py
+++ b/providers/tests/fab/auth_manager/test_fab_auth_manager.py
@@ -16,13 +16,14 @@
# under the License.
from __future__ import annotations
+from contextlib import contextmanager
from itertools import chain
from typing import TYPE_CHECKING
from unittest import mock
from unittest.mock import Mock
import pytest
-from flask import Flask
+from flask import Flask, g
from airflow.exceptions import AirflowConfigException, AirflowException
@@ -72,6 +73,13 @@ IS_AUTHORIZED_METHODS_SIMPLE = {
}
+@contextmanager
+def user_set(app, user):
+ g.user = user
+ yield
+ g.user = None
+
+
@pytest.fixture
def auth_manager():
return FabAuthManager(None)
@@ -114,12 +122,24 @@ class TestFabAuthManager:
assert auth_manager.get_user_display_name() == expected
@mock.patch("flask_login.utils._get_user")
- def test_get_user(self, mock_current_user, auth_manager):
+ def test_get_user(self, mock_current_user, minimal_app_for_auth_api,
auth_manager):
user = Mock()
user.is_anonymous.return_value = True
mock_current_user.return_value = user
+ with minimal_app_for_auth_api.app_context():
+ assert auth_manager.get_user() == user
- assert auth_manager.get_user() == user
+ @mock.patch("flask_login.utils._get_user")
+ def test_get_user_from_flask_g(self, mock_current_user,
minimal_app_for_auth_api, auth_manager):
+ session_user = Mock()
+ session_user.is_anonymous = True
+ mock_current_user.return_value = session_user
+
+ flask_g_user = Mock()
+ flask_g_user.is_anonymous = False
+ with minimal_app_for_auth_api.app_context():
+ with user_set(minimal_app_for_auth_api, flask_g_user):
+ assert auth_manager.get_user() == flask_g_user
@pytest.mark.db_test
@mock.patch.object(FabAuthManager, "get_user")