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 89e7f3e7bd Add "MENU" permission in auth manager (#37881)
89e7f3e7bd is described below

commit 89e7f3e7bdf2126bbbcd959dc10d65ef92773cca
Author: Vincent <[email protected]>
AuthorDate: Tue Mar 5 13:56:44 2024 -0500

    Add "MENU" permission in auth manager (#37881)
---
 airflow/auth/managers/base_auth_manager.py              |  2 +-
 airflow/auth/managers/utils/fab.py                      |  2 +-
 airflow/providers/fab/auth_manager/fab_auth_manager.py  | 15 ++++-----------
 airflow/www/security_manager.py                         |  4 +---
 .../providers/fab/auth_manager/test_fab_auth_manager.py | 17 +++++++++++++++--
 5 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/airflow/auth/managers/base_auth_manager.py 
b/airflow/auth/managers/base_auth_manager.py
index 88164b644e..a0176fc833 100644
--- a/airflow/auth/managers/base_auth_manager.py
+++ b/airflow/auth/managers/base_auth_manager.py
@@ -57,7 +57,7 @@ if TYPE_CHECKING:
     from airflow.www.extensions.init_appbuilder import AirflowAppBuilder
     from airflow.www.security_manager import AirflowSecurityManagerV2
 
-ResourceMethod = Literal["GET", "POST", "PUT", "DELETE"]
+ResourceMethod = Literal["GET", "POST", "PUT", "DELETE", "MENU"]
 
 
 class BaseAuthManager(LoggingMixin):
diff --git a/airflow/auth/managers/utils/fab.py 
b/airflow/auth/managers/utils/fab.py
index 22b572e07f..0f2bc7c46e 100644
--- a/airflow/auth/managers/utils/fab.py
+++ b/airflow/auth/managers/utils/fab.py
@@ -36,6 +36,7 @@ _MAP_METHOD_NAME_TO_FAB_ACTION_NAME: dict[ResourceMethod, 
str] = {
     "GET": ACTION_CAN_READ,
     "PUT": ACTION_CAN_EDIT,
     "DELETE": ACTION_CAN_DELETE,
+    "MENU": ACTION_CAN_ACCESS_MENU,
 }
 
 
@@ -48,5 +49,4 @@ def get_method_from_fab_action_map():
     """Return the map associating a FAB action to a method."""
     return {
         **{v: k for k, v in _MAP_METHOD_NAME_TO_FAB_ACTION_NAME.items()},
-        ACTION_CAN_ACCESS_MENU: "GET",
     }
diff --git a/airflow/providers/fab/auth_manager/fab_auth_manager.py 
b/airflow/providers/fab/auth_manager/fab_auth_manager.py
index 90109950b3..1d3506c3df 100644
--- a/airflow/providers/fab/auth_manager/fab_auth_manager.py
+++ b/airflow/providers/fab/auth_manager/fab_auth_manager.py
@@ -54,8 +54,6 @@ from 
airflow.providers.fab.auth_manager.cli_commands.definition import (
 from airflow.providers.fab.auth_manager.models import Permission, Role, User
 from airflow.security import permissions
 from airflow.security.permissions import (
-    ACTION_CAN_ACCESS_MENU,
-    ACTION_CAN_READ,
     RESOURCE_AUDIT_LOG,
     RESOURCE_CLUSTER_ACTIVITY,
     RESOURCE_CONFIG,
@@ -263,8 +261,10 @@ class FabAuthManager(BaseAuthManager):
         return self._is_authorized(method=method, 
resource_type=RESOURCE_VARIABLE, user=user)
 
     def is_authorized_view(self, *, access_view: AccessView, user: BaseUser | 
None = None) -> bool:
+        # "Docs" are only links in the menu, there is no page associated
+        method: ResourceMethod = "MENU" if access_view == AccessView.DOCS else 
"GET"
         return self._is_authorized(
-            method="GET", 
resource_type=_MAP_ACCESS_VIEW_TO_FAB_RESOURCE_TYPE[access_view], user=user
+            method=method, 
resource_type=_MAP_ACCESS_VIEW_TO_FAB_RESOURCE_TYPE[access_view], user=user
         )
 
     def is_authorized_custom_view(
@@ -463,18 +463,11 @@ class FabAuthManager(BaseAuthManager):
         """
         Return the user permissions.
 
-        ACTION_CAN_READ and ACTION_CAN_ACCESS_MENU are merged into because 
they are very similar.
-        We can assume that if a user has permissions to read variables, they 
also have permissions to access
-        the menu "Variables".
-
         :param user: the user to get permissions for
 
         :meta private:
         """
-        perms = getattr(user, "perms") or []
-        return [
-            (ACTION_CAN_READ if perm[0] == ACTION_CAN_ACCESS_MENU else 
perm[0], perm[1]) for perm in perms
-        ]
+        return getattr(user, "perms") or []
 
     def _get_root_dag_id(self, dag_id: str) -> str:
         """
diff --git a/airflow/www/security_manager.py b/airflow/www/security_manager.py
index 5cd9c15923..bd31535983 100644
--- a/airflow/www/security_manager.py
+++ b/airflow/www/security_manager.py
@@ -39,8 +39,6 @@ from airflow.auth.managers.utils.fab import (
 from airflow.exceptions import AirflowException
 from airflow.models import Connection, DagRun, Pool, TaskInstance, Variable
 from airflow.security.permissions import (
-    ACTION_CAN_ACCESS_MENU,
-    ACTION_CAN_READ,
     RESOURCE_ADMIN_MENU,
     RESOURCE_AUDIT_LOG,
     RESOURCE_BROWSE_MENU,
@@ -340,7 +338,7 @@ class AirflowSecurityManagerV2(LoggingMixin):
             # This means the page the user is trying to access is specific to 
the auth manager used
             # Example: the user list view in FabAuthManager
             return lambda action, resource_pk, user: 
get_auth_manager().is_authorized_custom_view(
-                fab_action_name=ACTION_CAN_READ if action == 
ACTION_CAN_ACCESS_MENU else action,
+                fab_action_name=action,
                 fab_resource_name=fab_resource_name,
                 user=user,
             )
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 65a6fb8f56..89c6352543 100644
--- a/tests/providers/fab/auth_manager/test_fab_auth_manager.py
+++ b/tests/providers/fab/auth_manager/test_fab_auth_manager.py
@@ -39,6 +39,7 @@ from airflow.security.permissions import (
     RESOURCE_DAG,
     RESOURCE_DAG_RUN,
     RESOURCE_DATASET,
+    RESOURCE_DOCS,
     RESOURCE_JOB,
     RESOURCE_PLUGIN,
     RESOURCE_PROVIDER,
@@ -140,10 +141,10 @@ class TestFabAuthManager:
                         [(ACTION_CAN_DELETE, resource_type), 
(ACTION_CAN_CREATE, "resource_test")],
                         True,
                     ),
-                    # With permission (testing that ACTION_CAN_ACCESS_MENU 
gives GET permissions)
+                    # With permission
                     (
                         api_name,
-                        "GET",
+                        "MENU",
                         [(ACTION_CAN_ACCESS_MENU, resource_type)],
                         True,
                     ),
@@ -346,6 +347,18 @@ class TestFabAuthManager:
                 [(ACTION_CAN_READ, RESOURCE_TRIGGER)],
                 False,
             ),
+            # Docs (positive)
+            (
+                AccessView.DOCS,
+                [(ACTION_CAN_ACCESS_MENU, RESOURCE_DOCS)],
+                True,
+            ),
+            # Without permission
+            (
+                AccessView.DOCS,
+                [(ACTION_CAN_READ, RESOURCE_DOCS)],
+                False,
+            ),
         ],
     )
     def test_is_authorized_view(self, access_view, user_permissions, 
expected_result, auth_manager):

Reply via email to