diff --git a/engine/apps/auth_token/auth.py b/engine/apps/auth_token/auth.py index d86ad6eed..dc6ccf7ae 100644 --- a/engine/apps/auth_token/auth.py +++ b/engine/apps/auth_token/auth.py @@ -9,7 +9,7 @@ from rest_framework.authentication import BaseAuthentication, get_authorization_header from rest_framework.request import Request -from apps.api.permissions import GrafanaAPIPermissions, LegacyAccessControlRole, RBACPermission, user_is_authorized +from apps.api.permissions import GrafanaAPIPermissions, LegacyAccessControlRole from apps.grafana_plugin.helpers.gcom import check_token from apps.grafana_plugin.sync_data import SyncPermission, SyncUser from apps.user_management.exceptions import OrganizationDeletedException, OrganizationMovedException @@ -52,10 +52,8 @@ def authenticate(self, request): auth = get_authorization_header(request).decode("utf-8") user, auth_token = self.authenticate_credentials(auth) - if not user.is_active or not user_is_authorized(user, [RBACPermission.Permissions.API_KEYS_WRITE]): - raise exceptions.AuthenticationFailed( - "Only users with Admin permissions are allowed to perform this action." - ) + if not user.is_active: + raise exceptions.AuthenticationFailed("Only active users are allowed to perform this action.") return user, auth_token diff --git a/engine/apps/public_api/tests/test_rbac_permissions.py b/engine/apps/public_api/tests/test_rbac_permissions.py new file mode 100644 index 000000000..9829550d8 --- /dev/null +++ b/engine/apps/public_api/tests/test_rbac_permissions.py @@ -0,0 +1,98 @@ +from unittest.mock import patch + +import pytest +from django.urls import reverse +from rest_framework import status +from rest_framework.response import Response +from rest_framework.test import APIClient + +from apps.api.permissions import GrafanaAPIPermission, LegacyAccessControlRole, get_most_authorized_role +from apps.public_api.urls import router + + +@pytest.mark.parametrize( + "rbac_enabled,role,give_perm", + [ + # rbac disabled: we will check the role is enough based on get_most_authorized_role for the perm + (False, "admin", None), + (False, "editor", None), + (False, "viewer", None), + (False, None, None), + # rbac enabled: having role None, check the perm is required + (True, None, False), + (True, None, True), + ], +) +@pytest.mark.django_db +def test_rbac_permissions( + make_organization_and_user_with_token, + rbac_enabled, + role, + give_perm, +): + # APIView default actions + # (name, http method, detail-based) + default_actions = { + "create": ("post", False), + "list": ("get", False), + "retrieve": ("get", True), + "update": ("put", True), + "partial_update": ("patch", True), + "destroy": ("delete", True), + } + + organization, user, token = make_organization_and_user_with_token() + if organization.is_rbac_permissions_enabled != rbac_enabled: + # skip if the organization's rbac_enabled is not the expected by the test + return + + client = APIClient() + # check all actions for all public API viewsets + for _, viewset, _basename in router.registry: + if viewset.__name__ == "ActionView": + # old actions (webhooks) are deprecated, no RBAC support + continue + for viewset_method_name, required_perms in viewset.rbac_permissions.items(): + # setup user's role and permissions + if rbac_enabled: + # set the user's role to None and assign the permission or not based on the flag + user.role = LegacyAccessControlRole.NONE + user.permissions = [] + expected = status.HTTP_403_FORBIDDEN + if give_perm: + # if permissions are given, expect a 200 response + user.permissions = [GrafanaAPIPermission(action=perm.value) for perm in required_perms] + expected = status.HTTP_200_OK + user.save() + else: + # set the user's role to the given role + user.role = LegacyAccessControlRole[role.upper()] if role else LegacyAccessControlRole.NONE + user.save() + # check what the minimum required role for the perms is + required_role = get_most_authorized_role(required_perms) + # set expected depending on the user's role + expected = status.HTTP_200_OK if user.role <= required_role else status.HTTP_403_FORBIDDEN + + # iterate over all viewset actions, making an API request for each, + # using the user's token and confirming the response status code + if viewset_method_name in default_actions: + http_method, detail = default_actions[viewset_method_name] + else: + action_method = getattr(viewset, viewset_method_name) + http_method = list(action_method.mapping.keys())[0] + detail = action_method.detail + + method_path = f"{viewset.__module__}.{viewset.__name__}.{viewset_method_name}" + success = Response(status=status.HTTP_200_OK) + kwargs = {"pk": "NONEXISTENT"} if detail else None + if viewset_method_name in default_actions and detail: + url = reverse(f"api-public:{_basename}-detail", kwargs=kwargs) + elif viewset_method_name in default_actions and not detail: + url = reverse(f"api-public:{_basename}-list", kwargs=kwargs) + else: + name = viewset_method_name.replace("_", "-") + url = reverse(f"api-public:{_basename}-{name}", kwargs=kwargs) + + with patch(method_path, return_value=success): + response = client.generic(path=url, method=http_method, HTTP_AUTHORIZATION=token) + assert response.status_code == expected diff --git a/engine/apps/public_api/views/alert_groups.py b/engine/apps/public_api/views/alert_groups.py index 738219d42..d4f4a302f 100644 --- a/engine/apps/public_api/views/alert_groups.py +++ b/engine/apps/public_api/views/alert_groups.py @@ -11,6 +11,7 @@ from apps.alerts.models import AlertGroup, AlertReceiveChannel from apps.alerts.tasks import delete_alert_group, wipe from apps.api.label_filtering import parse_label_query +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.constants import VALID_DATE_FOR_DELETE_INCIDENT from apps.public_api.helpers import is_valid_group_creation_date, team_has_slack_token_for_deleting @@ -57,7 +58,19 @@ class AlertGroupView( GenericViewSet, ): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.ALERT_GROUPS_READ], + "retrieve": [RBACPermission.Permissions.ALERT_GROUPS_READ], + "destroy": [RBACPermission.Permissions.ALERT_GROUPS_WRITE], + "acknowledge": [RBACPermission.Permissions.ALERT_GROUPS_WRITE], + "unacknowledge": [RBACPermission.Permissions.ALERT_GROUPS_WRITE], + "resolve": [RBACPermission.Permissions.ALERT_GROUPS_WRITE], + "unresolve": [RBACPermission.Permissions.ALERT_GROUPS_WRITE], + "silence": [RBACPermission.Permissions.ALERT_GROUPS_WRITE], + "unsilence": [RBACPermission.Permissions.ALERT_GROUPS_WRITE], + } throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/alerts.py b/engine/apps/public_api/views/alerts.py index 6674ed1bb..b96d51c50 100644 --- a/engine/apps/public_api/views/alerts.py +++ b/engine/apps/public_api/views/alerts.py @@ -6,6 +6,7 @@ from rest_framework.viewsets import GenericViewSet from apps.alerts.models import Alert +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.serializers.alerts import AlertSerializer from apps.public_api.throttlers.user_throttle import UserThrottle @@ -19,7 +20,11 @@ class AlertFilter(filters.FilterSet): class AlertView(RateLimitHeadersMixin, mixins.ListModelMixin, GenericViewSet): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.ALERT_GROUPS_READ], + } throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/escalation.py b/engine/apps/public_api/views/escalation.py index ae3b5717d..be5459264 100644 --- a/engine/apps/public_api/views/escalation.py +++ b/engine/apps/public_api/views/escalation.py @@ -4,6 +4,7 @@ from rest_framework.views import APIView from apps.alerts.paging import DirectPagingAlertGroupResolvedError, DirectPagingUserTeamValidationError, direct_paging +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.serializers import AlertGroupSerializer, EscalationSerializer from apps.public_api.throttlers import UserThrottle @@ -16,7 +17,11 @@ class EscalationView(APIView): """ authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "post": [RBACPermission.Permissions.ALERT_GROUPS_DIRECT_PAGING], + } throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/escalation_chains.py b/engine/apps/public_api/views/escalation_chains.py index d8f935137..84bb71628 100644 --- a/engine/apps/public_api/views/escalation_chains.py +++ b/engine/apps/public_api/views/escalation_chains.py @@ -4,6 +4,7 @@ from rest_framework.viewsets import ModelViewSet from apps.alerts.models import EscalationChain +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.serializers import EscalationChainSerializer from apps.public_api.throttlers.user_throttle import UserThrottle @@ -15,7 +16,16 @@ class EscalationChainView(RateLimitHeadersMixin, ModelViewSet): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.ESCALATION_CHAINS_READ], + "retrieve": [RBACPermission.Permissions.ESCALATION_CHAINS_READ], + "create": [RBACPermission.Permissions.ESCALATION_CHAINS_WRITE], + "update": [RBACPermission.Permissions.ESCALATION_CHAINS_WRITE], + "partial_update": [RBACPermission.Permissions.ESCALATION_CHAINS_WRITE], + "destroy": [RBACPermission.Permissions.ESCALATION_CHAINS_WRITE], + } throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/escalation_policies.py b/engine/apps/public_api/views/escalation_policies.py index f6dbe4bc0..ddbaeae80 100644 --- a/engine/apps/public_api/views/escalation_policies.py +++ b/engine/apps/public_api/views/escalation_policies.py @@ -4,6 +4,7 @@ from rest_framework.viewsets import ModelViewSet from apps.alerts.models import EscalationPolicy +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.serializers import EscalationPolicySerializer, EscalationPolicyUpdateSerializer from apps.public_api.throttlers.user_throttle import UserThrottle @@ -14,7 +15,16 @@ class EscalationPolicyView(RateLimitHeadersMixin, UpdateSerializerMixin, ModelViewSet): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.ESCALATION_CHAINS_READ], + "retrieve": [RBACPermission.Permissions.ESCALATION_CHAINS_READ], + "create": [RBACPermission.Permissions.ESCALATION_CHAINS_WRITE], + "update": [RBACPermission.Permissions.ESCALATION_CHAINS_WRITE], + "partial_update": [RBACPermission.Permissions.ESCALATION_CHAINS_WRITE], + "destroy": [RBACPermission.Permissions.ESCALATION_CHAINS_WRITE], + } throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/info.py b/engine/apps/public_api/views/info.py index f9cc13ca5..e5925d632 100644 --- a/engine/apps/public_api/views/info.py +++ b/engine/apps/public_api/views/info.py @@ -2,13 +2,18 @@ from rest_framework.response import Response from rest_framework.views import APIView +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.throttlers import InfoThrottler class InfoView(APIView): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "get": [RBACPermission.Permissions.OTHER_SETTINGS_READ], + } throttle_classes = [InfoThrottler] diff --git a/engine/apps/public_api/views/integrations.py b/engine/apps/public_api/views/integrations.py index ed17f9aac..26c55224f 100644 --- a/engine/apps/public_api/views/integrations.py +++ b/engine/apps/public_api/views/integrations.py @@ -4,6 +4,7 @@ from rest_framework.viewsets import ModelViewSet from apps.alerts.models import AlertReceiveChannel +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.serializers import IntegrationSerializer, IntegrationUpdateSerializer from apps.public_api.throttlers.user_throttle import UserThrottle @@ -24,7 +25,18 @@ class IntegrationView( ModelViewSet, ): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.INTEGRATIONS_READ], + "retrieve": [RBACPermission.Permissions.INTEGRATIONS_READ], + "create": [RBACPermission.Permissions.INTEGRATIONS_WRITE], + "update": [RBACPermission.Permissions.INTEGRATIONS_WRITE], + "partial_update": [RBACPermission.Permissions.INTEGRATIONS_WRITE], + "destroy": [RBACPermission.Permissions.INTEGRATIONS_WRITE], + "maintenance_start": [RBACPermission.Permissions.INTEGRATIONS_WRITE], + "maintenance_stop": [RBACPermission.Permissions.INTEGRATIONS_WRITE], + } throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/on_call_shifts.py b/engine/apps/public_api/views/on_call_shifts.py index af944b005..e825ea353 100644 --- a/engine/apps/public_api/views/on_call_shifts.py +++ b/engine/apps/public_api/views/on_call_shifts.py @@ -4,6 +4,7 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.viewsets import ModelViewSet +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.serializers import CustomOnCallShiftSerializer, CustomOnCallShiftUpdateSerializer from apps.public_api.throttlers.user_throttle import UserThrottle @@ -16,7 +17,16 @@ class CustomOnCallShiftView(RateLimitHeadersMixin, UpdateSerializerMixin, ModelViewSet): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.SCHEDULES_READ], + "retrieve": [RBACPermission.Permissions.SCHEDULES_READ], + "create": [RBACPermission.Permissions.SCHEDULES_WRITE], + "update": [RBACPermission.Permissions.SCHEDULES_WRITE], + "partial_update": [RBACPermission.Permissions.SCHEDULES_WRITE], + "destroy": [RBACPermission.Permissions.SCHEDULES_WRITE], + } throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/organizations.py b/engine/apps/public_api/views/organizations.py index f4fd1352a..1df2f63a5 100644 --- a/engine/apps/public_api/views/organizations.py +++ b/engine/apps/public_api/views/organizations.py @@ -2,6 +2,7 @@ from rest_framework.settings import api_settings from rest_framework.viewsets import ReadOnlyModelViewSet +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.serializers import OrganizationSerializer from apps.public_api.throttlers.user_throttle import UserThrottle @@ -15,7 +16,11 @@ class OrganizationView( ReadOnlyModelViewSet, ): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "retrieve": [RBACPermission.Permissions.OTHER_SETTINGS_READ], + } throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/personal_notifications.py b/engine/apps/public_api/views/personal_notifications.py index 44b251a38..acd3ff5c4 100644 --- a/engine/apps/public_api/views/personal_notifications.py +++ b/engine/apps/public_api/views/personal_notifications.py @@ -4,6 +4,7 @@ from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.base.models import UserNotificationPolicy from apps.public_api.serializers import PersonalNotificationRuleSerializer, PersonalNotificationRuleUpdateSerializer @@ -17,7 +18,16 @@ class PersonalNotificationView(RateLimitHeadersMixin, UpdateSerializerMixin, ModelViewSet): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.USER_SETTINGS_READ], + "retrieve": [RBACPermission.Permissions.USER_SETTINGS_READ], + "create": [RBACPermission.Permissions.USER_SETTINGS_WRITE], + "update": [RBACPermission.Permissions.USER_SETTINGS_WRITE], + "partial_update": [RBACPermission.Permissions.USER_SETTINGS_WRITE], + "destroy": [RBACPermission.Permissions.USER_SETTINGS_WRITE], + } throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/resolution_notes.py b/engine/apps/public_api/views/resolution_notes.py index 586c5aca7..3df56e5fb 100644 --- a/engine/apps/public_api/views/resolution_notes.py +++ b/engine/apps/public_api/views/resolution_notes.py @@ -18,7 +18,6 @@ class ResolutionNoteView(RateLimitHeadersMixin, UpdateSerializerMixin, ModelView permission_classes = (IsAuthenticated, RBACPermission) rbac_permissions = { - "metadata": [RBACPermission.Permissions.ALERT_GROUPS_READ], "list": [RBACPermission.Permissions.ALERT_GROUPS_READ], "retrieve": [RBACPermission.Permissions.ALERT_GROUPS_READ], "create": [RBACPermission.Permissions.ALERT_GROUPS_WRITE], diff --git a/engine/apps/public_api/views/routes.py b/engine/apps/public_api/views/routes.py index 895e016ea..794615271 100644 --- a/engine/apps/public_api/views/routes.py +++ b/engine/apps/public_api/views/routes.py @@ -6,6 +6,7 @@ from rest_framework.viewsets import ModelViewSet from apps.alerts.models import ChannelFilter +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.serializers import ChannelFilterSerializer, ChannelFilterUpdateSerializer from apps.public_api.throttlers.user_throttle import UserThrottle @@ -17,7 +18,16 @@ class ChannelFilterView(RateLimitHeadersMixin, UpdateSerializerMixin, ModelViewSet): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.INTEGRATIONS_READ], + "retrieve": [RBACPermission.Permissions.INTEGRATIONS_READ], + "create": [RBACPermission.Permissions.INTEGRATIONS_WRITE], + "update": [RBACPermission.Permissions.INTEGRATIONS_WRITE], + "partial_update": [RBACPermission.Permissions.INTEGRATIONS_WRITE], + "destroy": [RBACPermission.Permissions.INTEGRATIONS_WRITE], + } throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/schedules.py b/engine/apps/public_api/views/schedules.py index e1b83cf5a..6dcca6fd0 100644 --- a/engine/apps/public_api/views/schedules.py +++ b/engine/apps/public_api/views/schedules.py @@ -8,6 +8,7 @@ from rest_framework.views import Response from rest_framework.viewsets import ModelViewSet +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication, ScheduleExportAuthentication from apps.public_api.custom_renderers import CalendarRenderer from apps.public_api.serializers import PolymorphicScheduleSerializer, PolymorphicScheduleUpdateSerializer @@ -28,7 +29,17 @@ class OnCallScheduleChannelView(RateLimitHeadersMixin, UpdateSerializerMixin, ModelViewSet): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.SCHEDULES_READ], + "retrieve": [RBACPermission.Permissions.SCHEDULES_READ], + "create": [RBACPermission.Permissions.SCHEDULES_WRITE], + "update": [RBACPermission.Permissions.SCHEDULES_WRITE], + "partial_update": [RBACPermission.Permissions.SCHEDULES_WRITE], + "destroy": [RBACPermission.Permissions.SCHEDULES_WRITE], + "final_shifts": [RBACPermission.Permissions.SCHEDULES_READ], + } throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/shift_swap.py b/engine/apps/public_api/views/shift_swap.py index 29d5fcbe6..07f978e5c 100644 --- a/engine/apps/public_api/views/shift_swap.py +++ b/engine/apps/public_api/views/shift_swap.py @@ -8,7 +8,7 @@ from rest_framework.response import Response from rest_framework.serializers import BaseSerializer -from apps.api.permissions import AuthenticatedRequest +from apps.api.permissions import AuthenticatedRequest, RBACPermission from apps.api.views.shift_swap import BaseShiftSwapViewSet from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.throttlers.user_throttle import UserThrottle @@ -24,7 +24,17 @@ class ShiftSwapViewSet(RateLimitHeadersMixin, BaseShiftSwapViewSet): # set authentication and permission classes authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.SCHEDULES_READ], + "retrieve": [RBACPermission.Permissions.SCHEDULES_READ], + "create": [RBACPermission.Permissions.SCHEDULES_WRITE], + "update": [RBACPermission.Permissions.SCHEDULES_WRITE], + "partial_update": [RBACPermission.Permissions.SCHEDULES_WRITE], + "destroy": [RBACPermission.Permissions.SCHEDULES_WRITE], + "take": [RBACPermission.Permissions.SCHEDULES_WRITE], + } # public API customizations throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/slack_channels.py b/engine/apps/public_api/views/slack_channels.py index 1f363596f..77581f3dd 100644 --- a/engine/apps/public_api/views/slack_channels.py +++ b/engine/apps/public_api/views/slack_channels.py @@ -2,6 +2,7 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.viewsets import GenericViewSet +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.serializers.slack_channel import SlackChannelSerializer from apps.public_api.throttlers.user_throttle import UserThrottle @@ -12,7 +13,12 @@ class SlackChannelView(RateLimitHeadersMixin, mixins.ListModelMixin, GenericViewSet): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.CHATOPS_READ], + } + pagination_class = FiftyPageSizePaginator throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/teams.py b/engine/apps/public_api/views/teams.py index 96cea48da..490e74efb 100644 --- a/engine/apps/public_api/views/teams.py +++ b/engine/apps/public_api/views/teams.py @@ -2,6 +2,7 @@ from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.permissions import IsAuthenticated +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.serializers.teams import TeamSerializer from apps.public_api.tf_sync import is_request_from_terraform, sync_teams_on_tf_request @@ -14,7 +15,12 @@ class TeamView(PublicPrimaryKeyMixin, RetrieveModelMixin, ListModelMixin, viewsets.GenericViewSet): serializer_class = TeamSerializer authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.USER_SETTINGS_READ], + "retrieve": [RBACPermission.Permissions.USER_SETTINGS_READ], + } model = Team pagination_class = FiftyPageSizePaginator diff --git a/engine/apps/public_api/views/user_groups.py b/engine/apps/public_api/views/user_groups.py index 3db869545..ced7f626b 100644 --- a/engine/apps/public_api/views/user_groups.py +++ b/engine/apps/public_api/views/user_groups.py @@ -2,6 +2,7 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.viewsets import GenericViewSet +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.serializers.user_groups import UserGroupSerializer from apps.public_api.throttlers.user_throttle import UserThrottle @@ -12,7 +13,12 @@ class UserGroupView(RateLimitHeadersMixin, mixins.ListModelMixin, GenericViewSet): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.CHATOPS_READ], + } + pagination_class = FiftyPageSizePaginator throttle_classes = [UserThrottle] diff --git a/engine/apps/public_api/views/users.py b/engine/apps/public_api/views/users.py index 524b5ee00..97315fe20 100644 --- a/engine/apps/public_api/views/users.py +++ b/engine/apps/public_api/views/users.py @@ -5,7 +5,7 @@ from rest_framework.views import Response from rest_framework.viewsets import ReadOnlyModelViewSet -from apps.api.permissions import LegacyAccessControlRole +from apps.api.permissions import LegacyAccessControlRole, RBACPermission from apps.auth_token.auth import ApiTokenAuthentication, UserScheduleExportAuthentication from apps.public_api.custom_renderers import CalendarRenderer from apps.public_api.serializers import FastUserSerializer, UserSerializer @@ -36,7 +36,12 @@ class Meta: class UserView(RateLimitHeadersMixin, ShortSerializerMixin, ReadOnlyModelViewSet): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.USER_SETTINGS_READ], + "retrieve": [RBACPermission.Permissions.USER_SETTINGS_READ], + } model = User pagination_class = HundredPageSizePaginator diff --git a/engine/apps/public_api/views/webhooks.py b/engine/apps/public_api/views/webhooks.py index 4773e2c38..8f75148b7 100644 --- a/engine/apps/public_api/views/webhooks.py +++ b/engine/apps/public_api/views/webhooks.py @@ -5,6 +5,7 @@ from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet +from apps.api.permissions import RBACPermission from apps.auth_token.auth import ApiTokenAuthentication from apps.public_api.serializers.webhooks import ( WebhookCreateSerializer, @@ -21,7 +22,18 @@ class WebhooksView(RateLimitHeadersMixin, UpdateSerializerMixin, ModelViewSet): authentication_classes = (ApiTokenAuthentication,) - permission_classes = (IsAuthenticated,) + permission_classes = (IsAuthenticated, RBACPermission) + + rbac_permissions = { + "list": [RBACPermission.Permissions.OUTGOING_WEBHOOKS_READ], + "retrieve": [RBACPermission.Permissions.OUTGOING_WEBHOOKS_READ], + "create": [RBACPermission.Permissions.OUTGOING_WEBHOOKS_WRITE], + "update": [RBACPermission.Permissions.OUTGOING_WEBHOOKS_WRITE], + "partial_update": [RBACPermission.Permissions.OUTGOING_WEBHOOKS_WRITE], + "destroy": [RBACPermission.Permissions.OUTGOING_WEBHOOKS_WRITE], + "responses": [RBACPermission.Permissions.OUTGOING_WEBHOOKS_READ], + } + pagination_class = FiftyPageSizePaginator throttle_classes = [UserThrottle]