Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 35 additions & 32 deletions airflow/auth/managers/base_auth_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,12 @@ def __init__(self, appbuilder: AirflowAppBuilder) -> None:
super().__init__()
self.appbuilder = appbuilder

@staticmethod
def get_cli_commands() -> list[CLICommand]:
def init(self) -> None:
"""
Vends CLI commands to be included in Airflow CLI.
Run operations when Airflow is initializing.

Override this method to expose commands via Airflow CLI to manage this auth manager.
By default, do nothing.
"""
return []

def get_api_endpoints(self) -> None | Blueprint:
"""Return API endpoint(s) definition for the auth manager."""
return None

def get_user_name(self) -> str:
"""Return the username associated to the user in session."""
Expand Down Expand Up @@ -112,17 +106,26 @@ def get_user_id(self) -> str | None:
return str(user_id)
return None

def init(self) -> None:
"""
Run operations when Airflow is initializing.

By default, do nothing.
"""

@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."""

def get_url_user_profile(self) -> str | None:
"""
Return the url to a page displaying info about the current user.

By default, return None.
"""
return None

@abstractmethod
def is_authorized_configuration(
self,
Expand Down Expand Up @@ -413,22 +416,6 @@ def filter_permitted_menu_items(self, menu_items: list[MenuItem]) -> list[MenuIt
accessible_items.append(menu_item_copy)
return accessible_items

@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."""

def get_url_user_profile(self) -> str | None:
"""
Return the url to a page displaying info about the current user.

By default, return None.
"""
return None

@cached_property
def security_manager(self) -> AirflowSecurityManagerV2:
"""
Expand All @@ -443,3 +430,19 @@ def security_manager(self) -> AirflowSecurityManagerV2:
from airflow.www.security_manager import AirflowSecurityManagerV2

return AirflowSecurityManagerV2(self.appbuilder)

@staticmethod
def get_cli_commands() -> list[CLICommand]:
"""
Vends CLI commands to be included in Airflow CLI.

Override this method to expose commands via Airflow CLI to manage this auth manager.
"""
return []

def get_api_endpoints(self) -> None | Blueprint:
"""Return API endpoint(s) definition for the auth manager."""
return None

def register_views(self) -> None:
Comment thread
vincbeck marked this conversation as resolved.
"""Register views specific to the auth manager."""
4 changes: 4 additions & 0 deletions airflow/providers/amazon/aws/auth_manager/aws_auth_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from airflow.providers.amazon.aws.auth_manager.security_manager.aws_security_manager_override import (
AwsSecurityManagerOverride,
)
from airflow.providers.amazon.aws.auth_manager.views.auth import AwsAuthManagerAuthenticationViews

try:
from airflow.auth.managers.base_auth_manager import BaseAuthManager, ResourceMethod
Expand Down Expand Up @@ -423,6 +424,9 @@ def get_cli_commands() -> list[CLICommand]:
),
]

def register_views(self) -> None:
self.appbuilder.add_view_no_menu(AwsAuthManagerAuthenticationViews())

@staticmethod
def _get_menu_item_request(resource_name: str) -> IsAuthorizedRequest:
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@


class AwsSecurityManagerOverride(AirflowSecurityManagerV2):
"""The security manager override specific to AWS auth manager."""
"""
The security manager override specific to AWS auth manager.

This class is only used in Airflow 2. This can be safely be removed when min Airflow version >= 3
"""

def register_views(self):
"""Register views specific to AWS auth manager."""
Expand Down
3 changes: 3 additions & 0 deletions airflow/providers/fab/auth_manager/fab_auth_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,9 @@ def get_url_user_profile(self) -> str | None:
return None
return url_for(f"{self.security_manager.user_view.endpoint}.userinfo")

def register_views(self) -> None:
self.security_manager.register_views()

def _is_authorized(
self,
*,
Expand Down
7 changes: 6 additions & 1 deletion airflow/www/extensions/init_appbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,12 @@ def _add_admin_views(self):
self.add_view_no_menu(self.indexview)
self.add_view_no_menu(UtilView())
self.bm.register_views()
self.sm.register_views()

try:
get_auth_manager().register_views()
except AttributeError:
# TODO: remove when min airflow version >= 3
self.sm.register_views()

def _add_addon_views(self):
"""Register declared addons."""
Expand Down
26 changes: 21 additions & 5 deletions tests/providers/amazon/aws/auth_manager/test_aws_auth_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
from flask import Flask, session
from flask_appbuilder.menu import MenuItem

from airflow.providers.amazon.aws.auth_manager.security_manager.aws_security_manager_override import (
AwsSecurityManagerOverride,
)
from tests.test_utils.compat import AIRFLOW_V_2_8_PLUS, AIRFLOW_V_2_9_PLUS

try:
Expand All @@ -39,17 +42,14 @@
except ImportError:
if not AIRFLOW_V_2_8_PLUS:
pytest.skip(
"Skipping tests that require AwsSecurityManagerOverride for Airflow < 2.8.0",
"Skipping tests that require airflow.auth.managers.models.resource_details for Airflow < 2.8.0",
allow_module_level=True,
)
else:
raise
from airflow.providers.amazon.aws.auth_manager.avp.entities import AvpEntities
from airflow.providers.amazon.aws.auth_manager.avp.facade import AwsAuthManagerAmazonVerifiedPermissionsFacade
from airflow.providers.amazon.aws.auth_manager.aws_auth_manager import AwsAuthManager
from airflow.providers.amazon.aws.auth_manager.security_manager.aws_security_manager_override import (
AwsSecurityManagerOverride,
)
from airflow.providers.amazon.aws.auth_manager.user import AwsAuthManagerUser
from airflow.security.permissions import (
RESOURCE_AUDIT_LOG,
Expand Down Expand Up @@ -785,7 +785,23 @@ def test_security_manager_return_default_security_manager(self, auth_manager_wit
def test_get_cli_commands_return_cli_commands(self, auth_manager):
assert len(auth_manager.get_cli_commands()) > 0

@pytest.importorskip("python3-saml")
@pytest.mark.db_test
@patch(
"airflow.providers.amazon.aws.auth_manager.views.auth.conf.get_mandatory_value", return_value="test"
)
def test_register_views(self, mock_get_mandatory_value, auth_manager_with_appbuilder):
pytest.importorskip("onelogin")
from airflow.providers.amazon.aws.auth_manager.views.auth import AwsAuthManagerAuthenticationViews

with patch.object(AwsAuthManagerAuthenticationViews, "idp_data"):
auth_manager_with_appbuilder.appbuilder.add_view_no_menu = Mock()
auth_manager_with_appbuilder.register_views()
auth_manager_with_appbuilder.appbuilder.add_view_no_menu.assert_called_once()
assert isinstance(
auth_manager_with_appbuilder.appbuilder.add_view_no_menu.call_args.args[0],
AwsAuthManagerAuthenticationViews,
)

@pytest.mark.db_test
@patch.object(AwsAuthManagerAmazonVerifiedPermissionsFacade, "get_batch_is_authorized_single_result")
@patch.object(AwsAuthManagerAmazonVerifiedPermissionsFacade, "get_batch_is_authorized_results")
Expand Down