This is an automated email from the ASF dual-hosted git repository.
ferruzzi 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 2b0d88e450 Handle logout by auth manager (#32819)
2b0d88e450 is described below
commit 2b0d88e450f11af8e447864ca258142a6756126d
Author: Vincent <[email protected]>
AuthorDate: Mon Jul 31 15:20:38 2023 -0400
Handle logout by auth manager (#32819)
* Handle logout by auth manager
---
airflow/auth/managers/base_auth_manager.py | 10 ++++------
airflow/auth/managers/fab/fab_auth_manager.py | 6 ++++++
airflow/www/auth.py | 2 +-
airflow/www/extensions/init_appbuilder.py | 4 ----
airflow/www/extensions/init_security.py | 4 +---
airflow/www/templates/appbuilder/navbar_right.html | 2 +-
tests/auth/managers/fab/test_fab_auth_manager.py | 11 +++++++++++
tests/www/views/test_session.py | 8 +-------
8 files changed, 25 insertions(+), 22 deletions(-)
diff --git a/airflow/auth/managers/base_auth_manager.py
b/airflow/auth/managers/base_auth_manager.py
index a234efcaca..cb40ee9c87 100644
--- a/airflow/auth/managers/base_auth_manager.py
+++ b/airflow/auth/managers/base_auth_manager.py
@@ -41,32 +41,30 @@ class BaseAuthManager(LoggingMixin):
@abstractmethod
def get_user_name(self) -> str:
"""Return the username associated to the user in session."""
- ...
@abstractmethod
def get_user(self) -> BaseUser:
"""Return the user associated to the user in session."""
- ...
@abstractmethod
def get_user_id(self) -> str:
"""Return the user ID associated to the user in session."""
- ...
@abstractmethod
def is_logged_in(self) -> bool:
"""Return whether the user is logged in."""
- ...
@abstractmethod
def get_url_login(self, **kwargs) -> str:
"""Return the login page url."""
- ...
+
+ @abstractmethod
+ def get_url_logout(self) -> str:
+ """Return the logout page url."""
@abstractmethod
def get_url_user_profile(self) -> str | None:
"""Return the url to a page displaying info about the current user."""
- ...
def get_security_manager_override_class(self) -> type:
"""
diff --git a/airflow/auth/managers/fab/fab_auth_manager.py
b/airflow/auth/managers/fab/fab_auth_manager.py
index 085b6e997b..7a23953b35 100644
--- a/airflow/auth/managers/fab/fab_auth_manager.py
+++ b/airflow/auth/managers/fab/fab_auth_manager.py
@@ -70,6 +70,12 @@ class FabAuthManager(BaseAuthManager):
else:
return url_for(f"{self.security_manager.auth_view.endpoint}.login")
+ def get_url_logout(self):
+ """Return the logout page url."""
+ if not self.security_manager.auth_view:
+ raise AirflowException("`auth_view` not defined in the security
manager.")
+ return url_for(f"{self.security_manager.auth_view.endpoint}.logout")
+
def get_url_user_profile(self) -> str | None:
"""Return the url to a page displaying info about the current user."""
if not self.security_manager.user_view:
diff --git a/airflow/www/auth.py b/airflow/www/auth.py
index 46b645f197..9afe995054 100644
--- a/airflow/www/auth.py
+++ b/airflow/www/auth.py
@@ -54,7 +54,7 @@ def has_access(permissions: Sequence[tuple[str, str]] | None
= None) -> Callable
hostname=get_hostname()
if conf.getboolean("webserver", "EXPOSE_HOSTNAME")
else "redact",
- logout_url=appbuilder.get_url_for_logout,
+ logout_url=get_auth_manager().get_url_logout(),
),
403,
)
diff --git a/airflow/www/extensions/init_appbuilder.py
b/airflow/www/extensions/init_appbuilder.py
index 2537ea8bc7..11c358abb6 100644
--- a/airflow/www/extensions/init_appbuilder.py
+++ b/airflow/www/extensions/init_appbuilder.py
@@ -588,10 +588,6 @@ class AirflowAppBuilder:
def get_url_for_login_with(self, next_url: str | None = None) -> str:
return get_auth_manager().get_url_login(next_url=next_url)
- @property
- def get_url_for_logout(self):
- return url_for(f"{self.sm.auth_view.endpoint}.logout")
-
@property
def get_url_for_index(self):
return
url_for(f"{self.indexview.endpoint}.{self.indexview.default_view}")
diff --git a/airflow/www/extensions/init_security.py
b/airflow/www/extensions/init_security.py
index cdd4ec8862..ea3c2211c9 100644
--- a/airflow/www/extensions/init_security.py
+++ b/airflow/www/extensions/init_security.py
@@ -20,7 +20,6 @@ import logging
from importlib import import_module
from flask import g, redirect
-from flask_login import logout_user
from airflow.configuration import conf
from airflow.exceptions import AirflowConfigException, AirflowException
@@ -70,5 +69,4 @@ def init_check_user_active(app):
@app.before_request
def check_user_active():
if get_auth_manager().is_logged_in() and not g.user.is_active:
- logout_user()
- return redirect(get_auth_manager().get_url_login())
+ return redirect(get_auth_manager().get_url_logout())
diff --git a/airflow/www/templates/appbuilder/navbar_right.html
b/airflow/www/templates/appbuilder/navbar_right.html
index 2c16e09d96..8eec9f9fcf 100644
--- a/airflow/www/templates/appbuilder/navbar_right.html
+++ b/airflow/www/templates/appbuilder/navbar_right.html
@@ -78,7 +78,7 @@
<li><a href="{{user_profile_url}}"><span
class="material-icons">account_circle</span>{{_("Your Profile")}}</a></li>
<li role="separator" class="divider"></li>
{% endif %}
- <li><a href="{{appbuilder.get_url_for_logout}}"><span
class="material-icons">exit_to_app</span>{{_("Log Out")}}</a></li>
+ <li><a href="{{auth_manager.get_url_logout()}}"><span
class="material-icons">exit_to_app</span>{{_("Log Out")}}</a></li>
</ul>
</li>
{% else %}
diff --git a/tests/auth/managers/fab/test_fab_auth_manager.py
b/tests/auth/managers/fab/test_fab_auth_manager.py
index 96ddbc7f3e..c36ef8686d 100644
--- a/tests/auth/managers/fab/test_fab_auth_manager.py
+++ b/tests/auth/managers/fab/test_fab_auth_manager.py
@@ -99,6 +99,17 @@ class TestFabAuthManager:
auth_manager.get_url_login(next_url="next_url")
mock_url_for.assert_called_once_with("test_endpoint.login",
next="next_url")
+ def test_get_url_logout_when_auth_view_not_defined(self, auth_manager):
+ with pytest.raises(AirflowException, match="`auth_view` not defined in
the security manager."):
+ auth_manager.get_url_logout()
+
+ @mock.patch("airflow.auth.managers.fab.fab_auth_manager.url_for")
+ def test_get_url_logout(self, mock_url_for, auth_manager):
+ auth_manager.security_manager.auth_view = Mock()
+ auth_manager.security_manager.auth_view.endpoint = "test_endpoint"
+ auth_manager.get_url_logout()
+ mock_url_for.assert_called_once_with("test_endpoint.logout")
+
def test_get_url_user_profile_when_auth_view_not_defined(self,
auth_manager):
assert auth_manager.get_url_user_profile() is None
diff --git a/tests/www/views/test_session.py b/tests/www/views/test_session.py
index d8987a0178..822cf967fd 100644
--- a/tests/www/views/test_session.py
+++ b/tests/www/views/test_session.py
@@ -95,10 +95,4 @@ def test_check_active_user(app, user_client):
user.active = False
resp = user_client.get("/home")
assert resp.status_code == 302
- assert "/login" in resp.headers.get("Location")
-
- # And they were logged out
- user.active = True
- resp = user_client.get("/home")
- assert resp.status_code == 302
- assert "/login" in resp.headers.get("Location")
+ assert "/logout" in resp.headers.get("Location")