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

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

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

    Add "MENU" permission in auth manager (#37881)
    
    (cherry picked from commit 89e7f3e7bdf2126bbbcd959dc10d65ef92773cca)
---
 airflow/auth/managers/base_auth_manager.py       |  2 +-
 airflow/auth/managers/fab/fab_auth_manager.py    | 15 ++++-----------
 airflow/auth/managers/utils/fab.py               |  2 +-
 airflow/www/security_manager.py                  |  4 +---
 tests/auth/managers/fab/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 f64c803e6a..0b60969768 100644
--- a/airflow/auth/managers/base_auth_manager.py
+++ b/airflow/auth/managers/base_auth_manager.py
@@ -55,7 +55,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/fab/fab_auth_manager.py 
b/airflow/auth/managers/fab/fab_auth_manager.py
index 2e4014af2e..80624ef4a5 100644
--- a/airflow/auth/managers/fab/fab_auth_manager.py
+++ b/airflow/auth/managers/fab/fab_auth_manager.py
@@ -53,8 +53,6 @@ from airflow.exceptions import AirflowException
 from airflow.models import DagModel
 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,
@@ -266,8 +264,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(
@@ -472,18 +472,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/auth/managers/utils/fab.py 
b/airflow/auth/managers/utils/fab.py
index 316e5ecff1..5065f930fe 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():
     """Returns 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/www/security_manager.py b/airflow/www/security_manager.py
index 13342ff7f7..772e672ff6 100644
--- a/airflow/www/security_manager.py
+++ b/airflow/www/security_manager.py
@@ -40,8 +40,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,
@@ -335,7 +333,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/auth/managers/fab/test_fab_auth_manager.py 
b/tests/auth/managers/fab/test_fab_auth_manager.py
index bb9d507cbd..0d249a8603 100644
--- a/tests/auth/managers/fab/test_fab_auth_manager.py
+++ b/tests/auth/managers/fab/test_fab_auth_manager.py
@@ -40,6 +40,7 @@ from airflow.security.permissions import (
     RESOURCE_DAG,
     RESOURCE_DAG_RUN,
     RESOURCE_DATASET,
+    RESOURCE_DOCS,
     RESOURCE_JOB,
     RESOURCE_PLUGIN,
     RESOURCE_PROVIDER,
@@ -143,10 +144,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,
                     ),
@@ -349,6 +350,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