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

jedcunningham pushed a commit to branch v2-9-test
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit 092ceaed55fff2d09c5a975b255d33d3d29106b9
Author: Vincent <97131062+vincb...@users.noreply.github.com>
AuthorDate: Mon Apr 22 12:36:26 2024 -0400

    Update `is_authorized_custom_view` from auth manager to handle custom 
actions (#39167)
    
    (cherry picked from commit f7a2f6032544defa8a00d1f7fa90e91d27eb3a8e)
---
 airflow/auth/managers/base_auth_manager.py                  |  7 +++++--
 airflow/providers/amazon/aws/auth_manager/avp/entities.py   |  2 +-
 airflow/providers/amazon/aws/auth_manager/avp/facade.py     |  7 +++++--
 .../providers/amazon/aws/auth_manager/aws_auth_manager.py   |  2 +-
 airflow/providers/fab/auth_manager/fab_auth_manager.py      |  7 +++++--
 tests/auth/managers/test_base_auth_manager.py               |  2 +-
 tests/providers/fab/auth_manager/test_fab_auth_manager.py   | 13 ++++++++++++-
 7 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/airflow/auth/managers/base_auth_manager.py 
b/airflow/auth/managers/base_auth_manager.py
index 4d5c249235..7bb4e92889 100644
--- a/airflow/auth/managers/base_auth_manager.py
+++ b/airflow/auth/managers/base_auth_manager.py
@@ -237,7 +237,7 @@ class BaseAuthManager(LoggingMixin):
 
     @abstractmethod
     def is_authorized_custom_view(
-        self, *, method: ResourceMethod, resource_name: str, user: BaseUser | 
None = None
+        self, *, method: ResourceMethod | str, resource_name: str, user: 
BaseUser | None = None
     ):
         """
         Return whether the user is authorized to perform a given action on a 
custom view.
@@ -246,7 +246,10 @@ class BaseAuthManager(LoggingMixin):
         the auth manager is used as part of the environment. It can also be a 
view defined as part of a
         plugin defined by a user.
 
-        :param method: the method to perform
+        :param method: the method to perform.
+            The method can also be a string if the action has been defined in 
a plugin.
+            In that case, the action can be anything (e.g. can_do).
+            See https://github.com/apache/airflow/issues/39144
         :param resource_name: the name of the resource
         :param user: the user to perform the action on. If not provided (or 
None), it uses the current user
         """
diff --git a/airflow/providers/amazon/aws/auth_manager/avp/entities.py 
b/airflow/providers/amazon/aws/auth_manager/avp/entities.py
index f2c6376729..8c2e8855b8 100644
--- a/airflow/providers/amazon/aws/auth_manager/avp/entities.py
+++ b/airflow/providers/amazon/aws/auth_manager/avp/entities.py
@@ -55,7 +55,7 @@ def get_entity_type(resource_type: AvpEntities) -> str:
     return AVP_PREFIX_ENTITIES + resource_type.value
 
 
-def get_action_id(resource_type: AvpEntities, method: ResourceMethod):
+def get_action_id(resource_type: AvpEntities, method: ResourceMethod | str):
     """
     Return action id.
 
diff --git a/airflow/providers/amazon/aws/auth_manager/avp/facade.py 
b/airflow/providers/amazon/aws/auth_manager/avp/facade.py
index 010531155e..4bb9515004 100644
--- a/airflow/providers/amazon/aws/auth_manager/avp/facade.py
+++ b/airflow/providers/amazon/aws/auth_manager/avp/facade.py
@@ -75,7 +75,7 @@ class 
AwsAuthManagerAmazonVerifiedPermissionsFacade(LoggingMixin):
     def is_authorized(
         self,
         *,
-        method: ResourceMethod,
+        method: ResourceMethod | str,
         entity_type: AvpEntities,
         user: AwsAuthManagerUser | None,
         entity_id: str | None = None,
@@ -86,7 +86,10 @@ class 
AwsAuthManagerAmazonVerifiedPermissionsFacade(LoggingMixin):
 
         Check whether the user has permissions to access given resource.
 
-        :param method: the method to perform
+        :param method: the method to perform.
+            The method can also be a string if the action has been defined in 
a plugin.
+            In that case, the action can be anything (e.g. can_do).
+            See https://github.com/apache/airflow/issues/39144
         :param entity_type: the entity type the user accesses
         :param user: the user
         :param entity_id: the entity ID the user accesses. If not provided, 
all entities of the type will be
diff --git a/airflow/providers/amazon/aws/auth_manager/aws_auth_manager.py 
b/airflow/providers/amazon/aws/auth_manager/aws_auth_manager.py
index eb202acfca..1d2bcf1b19 100644
--- a/airflow/providers/amazon/aws/auth_manager/aws_auth_manager.py
+++ b/airflow/providers/amazon/aws/auth_manager/aws_auth_manager.py
@@ -207,7 +207,7 @@ class AwsAuthManager(BaseAuthManager):
         )
 
     def is_authorized_custom_view(
-        self, *, method: ResourceMethod, resource_name: str, user: BaseUser | 
None = None
+        self, *, method: ResourceMethod | str, resource_name: str, user: 
BaseUser | None = None
     ):
         return self.avp_facade.is_authorized(
             method=method,
diff --git a/airflow/providers/fab/auth_manager/fab_auth_manager.py 
b/airflow/providers/fab/auth_manager/fab_auth_manager.py
index 7533a214aa..ea5ec403ac 100644
--- a/airflow/providers/fab/auth_manager/fab_auth_manager.py
+++ b/airflow/providers/fab/auth_manager/fab_auth_manager.py
@@ -268,11 +268,14 @@ class FabAuthManager(BaseAuthManager):
         )
 
     def is_authorized_custom_view(
-        self, *, method: ResourceMethod, resource_name: str, user: BaseUser | 
None = None
+        self, *, method: ResourceMethod | str, resource_name: str, user: 
BaseUser | None = None
     ):
         if not user:
             user = self.get_user()
-        fab_action_name = get_fab_action_from_method_map()[method]
+        if method in get_fab_action_from_method_map():
+            fab_action_name = get_fab_action_from_method_map()[method]
+        else:
+            fab_action_name = method
         return (fab_action_name, resource_name) in 
self._get_user_permissions(user)
 
     @provide_session
diff --git a/tests/auth/managers/test_base_auth_manager.py 
b/tests/auth/managers/test_base_auth_manager.py
index 04191c4838..64d33f6065 100644
--- a/tests/auth/managers/test_base_auth_manager.py
+++ b/tests/auth/managers/test_base_auth_manager.py
@@ -95,7 +95,7 @@ class EmptyAuthManager(BaseAuthManager):
         raise NotImplementedError()
 
     def is_authorized_custom_view(
-        self, *, method: ResourceMethod, resource_name: str, user: BaseUser | 
None = None
+        self, *, method: ResourceMethod | str, resource_name: str, user: 
BaseUser | None = None
     ):
         raise NotImplementedError()
 
diff --git a/tests/providers/fab/auth_manager/test_fab_auth_manager.py 
b/tests/providers/fab/auth_manager/test_fab_auth_manager.py
index 773651fafe..b5f654e382 100644
--- a/tests/providers/fab/auth_manager/test_fab_auth_manager.py
+++ b/tests/providers/fab/auth_manager/test_fab_auth_manager.py
@@ -392,10 +392,21 @@ class TestFabAuthManager:
                 [(ACTION_CAN_READ, "custom_resource2")],
                 False,
             ),
+            (
+                "DUMMY",
+                "custom_resource",
+                [("DUMMY", "custom_resource")],
+                True,
+            ),
         ],
     )
     def test_is_authorized_custom_view(
-        self, method: ResourceMethod, resource_name: str, user_permissions, 
expected_result, auth_manager
+        self,
+        method: ResourceMethod | str,
+        resource_name: str,
+        user_permissions,
+        expected_result,
+        auth_manager,
     ):
         user = Mock()
         user.perms = user_permissions

Reply via email to