Repository: arenadata/adcm (language: python)

Issue:
Fixed expand child for Role object

ADCM-992 on load new bundle search license hash in all bundles, despite the name



Discussion / hints:

Fix patch:
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 874acf69f0..ac990d6df4 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,5 +1,5 @@
 * @arenadata/python
-/tests/functional/ @arenadata/python-qa
-/tests/ui_tests/ @arenadata/python-qa
-/tests/api/ @arenadata/python-qa
+/tests/functional/ @arenadata/python-web-qa
+/tests/ui_tests/ @arenadata/python-web-qa
+/tests/api/ @arenadata/python-web-qa
 /web/ @arenadata/angular
diff --git a/python/api/action/serializers.py b/python/api/action/serializers.py
index 511f7b7da6..8b73aef058 100644
--- a/python/api/action/serializers.py
+++ b/python/api/action/serializers.py
@@ -19,7 +19,7 @@
 import cm.adcm_config
 from cm.models import PrototypeConfig, SubAction
 
-from api.api_views import get_api_url_kwargs
+from api.utils import get_api_url_kwargs
 from api.config.serializers import ConfigSerializerUI
 
 
diff --git a/python/api/action/views.py b/python/api/action/views.py
index 0cddca6ed5..efcdacce76 100644
--- a/python/api/action/views.py
+++ b/python/api/action/views.py
@@ -10,22 +10,23 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from itertools import compress
+
+from django.contrib.contenttypes.models import ContentType
+from guardian.mixins import PermissionListMixin
 from rest_framework import permissions
 from rest_framework.response import Response
 
-from api.api_views import (
-    ListView,
-    DetailViewRO,
-    GenericAPIPermView,
+from api.base_view import GenericUIView
+from api.job.serializers import RunTaskSerializer
+from api.utils import (
     ActionFilter,
+    AdcmFilterBackend,
     create,
-    check_obj,
     filter_actions,
     permission_denied,
+    get_object_for_user,
 )
-from api.job.serializers import RunTaskSerializer
-
-from cm.job import get_host_object
 from cm.models import (
     Host,
     Action,
@@ -33,6 +34,7 @@
     HostComponent,
     get_model_by_type,
 )
+from rbac.viewsets import DjangoOnlyObjectPermissions
 from . import serializers
 
 
@@ -50,12 +52,14 @@ def get_obj(**kwargs):
     return obj, action_id
 
 
-class ActionList(ListView):
+class ActionList(PermissionListMixin, GenericUIView):
     queryset = Action.objects.all()
     serializer_class = serializers.ActionSerializer
     serializer_class_ui = serializers.ActionUISerializer
     filterset_class = ActionFilter
     filterset_fields = ('name', 'button', 'button_is_null')
+    filter_backends = (AdcmFilterBackend,)
+    permission_required = ['cm.view_action']
 
     def get(self, request, *args, **kwargs):  # pylint: disable=too-many-locals
         """
@@ -76,13 +80,13 @@ def get(self, request, *args, **kwargs):  # pylint: disable=too-many-locals
                     cluster, _ = get_obj(object_type='cluster', cluster_id=hc.cluster_id)
                     service, _ = get_obj(object_type='service', service_id=hc.service_id)
                     component, _ = get_obj(object_type='component', component_id=hc.component_id)
-                    for obj in [cluster, service, component]:
+                    for connect_obj in [cluster, service, component]:
                         actions.update(
                             filter_actions(
-                                obj,
+                                connect_obj,
                                 self.filter_queryset(
                                     self.get_queryset().filter(
-                                        prototype=obj.prototype, host_action=True
+                                        prototype=connect_obj.prototype, host_action=True
                                     )
                                 ),
                             )
@@ -108,36 +112,46 @@ def get(self, request, *args, **kwargs):  # pylint: disable=too-many-locals
                 ),
             )
             objects = {obj.prototype.type: obj}
-        serializer_class = self.select_serializer(request)
-        serializer = serializer_class(
+        # added filter actions by custom perm for run actions
+        perms = [f'cm.run_action_{a.display_name}' for a in actions]
+        mask = [request.user.has_perm(perm, obj) for perm in perms]
+        actions = list(compress(actions, mask))
+        serializer = self.get_serializer(
             actions, many=True, context={'request': request, 'objects': objects, 'obj': obj}
         )
         return Response(serializer.data)
 
 
-class ActionDetail(DetailViewRO):
+class ActionDetail(PermissionListMixin, GenericUIView):
     queryset = Action.objects.all()
     serializer_class = serializers.ActionDetailSerializer
     serializer_class_ui = serializers.ActionUISerializer
+    permission_classes = (DjangoOnlyObjectPermissions,)
+    permission_required = ['cm.view_action']
 
     def get(self, request, *args, **kwargs):
         """
         Show specified action
         """
-        obj, action_id = get_obj(**kwargs)
-        action = check_obj(Action, {'id': action_id}, 'ACTION_NOT_FOUND')
+        object_type, object_id, action_id = get_object_type_id(**kwargs)
+        model = get_model_by_type(object_type)
+        ct = ContentType.objects.get_for_model(model)
+        obj = get_object_for_user(
+            request.user, f'{ct.app_label}.view_{ct.model}', model, id=object_id
+        )
+        # TODO: we can access not only the actions of this object
+        action = get_object_for_user(request.user, 'cm.view_action', Action, id=action_id)
         if isinstance(obj, Host) and action.host_action:
             objects = {'host': obj}
         else:
             objects = {action.prototype.type: obj}
-        serializer_class = self.select_serializer(request)
-        serializer = serializer_class(
+        serializer = self.get_serializer(
             action, context={'request': request, 'objects': objects, 'obj': obj}
         )
         return Response(serializer.data)
 
 
-class RunTask(GenericAPIPermView):
+class RunTask(GenericUIView):
     queryset = TaskLog.objects.all()
     serializer_class = RunTaskSerializer
     permission_classes = (permissions.IsAuthenticated,)
@@ -148,9 +162,6 @@ def has_action_perm(self, action, obj):
         if user.has_perm('cm.add_task'):
             return True
 
-        if action.host_action:
-            obj = get_host_object(action, obj.cluster)
-
         return user.has_perm(f'cm.run_action_{action.display_name}', obj)
 
     def check_action_perm(self, action, obj):
@@ -161,8 +172,13 @@ def post(self, request, *args, **kwargs):
         """
         Ran specified action
         """
-        obj, action_id = get_obj(**kwargs)
-        action = check_obj(Action, {'id': action_id}, 'ACTION_NOT_FOUND')
+        object_type, object_id, action_id = get_object_type_id(**kwargs)
+        model = get_model_by_type(object_type)
+        ct = ContentType.objects.get_for_model(model)
+        obj = get_object_for_user(
+            request.user, f'{ct.app_label}.view_{ct.model}', model, id=object_id
+        )
+        action = get_object_for_user(request.user, 'cm.view_action', Action, id=action_id)
         self.check_action_perm(action, obj)
-        serializer = self.serializer_class(data=request.data, context={'request': request})
+        serializer = self.get_serializer(data=request.data)
         return create(serializer, action=action, task_object=obj)
diff --git a/python/api/adcm/serializers.py b/python/api/adcm/serializers.py
index c665eeb29e..822cc02557 100644
--- a/python/api/adcm/serializers.py
+++ b/python/api/adcm/serializers.py
@@ -12,7 +12,7 @@
 
 from rest_framework import serializers
 
-from api.api_views import hlink, CommonAPIURL
+from api.utils import hlink, CommonAPIURL
 from api.concern.serializers import ConcernItemSerializer
 from api.serializers import StringListSerializer
 from cm.adcm_config import get_main_info
diff --git a/python/api/adcm/views.py b/python/api/adcm/views.py
index 6ccef27f20..d68e5fb0f0 100644
--- a/python/api/adcm/views.py
+++ b/python/api/adcm/views.py
@@ -10,12 +10,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from rest_framework import permissions
+from rest_framework.response import Response
+
 from cm.models import ADCM
-from api.api_views import DetailViewRO, ListView
+from api.base_view import GenericUIView, DetailView
 from . import serializers
 
 
-class AdcmList(ListView):
+class AdcmList(GenericUIView):
     """
     get:
     List adcm object
@@ -24,9 +27,15 @@ class AdcmList(ListView):
     queryset = ADCM.objects.all()
     serializer_class = serializers.AdcmSerializer
     serializer_class_ui = serializers.AdcmDetailUISerializer
+    permission_classes = (permissions.IsAuthenticated,)
+
+    def get(self, request, *args, **kwargs):
+        obj = self.get_queryset()
+        serializer = self.get_serializer(obj, many=True)
+        return Response(serializer.data)
 
 
-class AdcmDetail(DetailViewRO):
+class AdcmDetail(DetailView):
     """
     get:
     Show adcm object
@@ -35,6 +44,7 @@ class AdcmDetail(DetailViewRO):
     queryset = ADCM.objects.all()
     serializer_class = serializers.AdcmDetailSerializer
     serializer_class_ui = serializers.AdcmDetailUISerializer
+    permission_classes = (permissions.IsAuthenticated,)
     lookup_field = 'id'
     lookup_url_kwarg = 'adcm_id'
     error_code = 'ADCM_NOT_FOUND'
diff --git a/python/api/base_view.py b/python/api/base_view.py
new file mode 100644
index 0000000000..4116a712e6
--- /dev/null
+++ b/python/api/base_view.py
@@ -0,0 +1,170 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# pylint: disable=not-callable, unused-import, too-many-locals
+
+import rest_framework.pagination
+from django.core.exceptions import ObjectDoesNotExist, FieldError
+from rest_framework import serializers
+from rest_framework.generics import GenericAPIView
+from rest_framework.permissions import SAFE_METHODS, DjangoModelPermissions, DjangoObjectPermissions
+from rest_framework.response import Response
+from rest_framework.utils.urls import replace_query_param
+from rest_framework.viewsets import ViewSetMixin
+
+from adcm.settings import REST_FRAMEWORK
+from api.utils import AdcmFilterBackend, AdcmOrderingFilter, getlist_from_querydict
+from cm.errors import AdcmEx
+
+
+class ModelPermOrReadOnlyForAuth(DjangoModelPermissions):
+    def has_permission(self, request, view):
+        if request.user and request.user.is_authenticated:
+            if request.method in SAFE_METHODS:
+                return True
+            else:
+                queryset = self._queryset(view)
+                perms = self.get_required_permissions(request.method, queryset.model)
+                return request.user.has_perms(perms)
+        return False
+
+
+class GenericUIView(GenericAPIView):
+    """
+    GenericAPIView with extended selection for serializer class
+    (switched by query parameter view=interface)
+    """
+
+    permission_classes = (DjangoObjectPermissions,)
+    serializer_class_post: serializers.Serializer = None
+    serializer_class_ui: serializers.Serializer = None
+    serializer_class: serializers.Serializer = None
+
+    def _is_for_ui(self) -> bool:
+        view = self.request.query_params.get('view', None)
+        return view == 'interface'
+
+    def get_serializer_class(self):
+        if self.request is not None:
+            if self.request.method == 'POST':
+                if self.serializer_class_post:
+                    return self.serializer_class_post
+            elif self._is_for_ui():
+                if self.serializer_class_ui:
+                    return self.serializer_class_ui
+        return super().get_serializer_class()
+
+
+class GenericUIViewSet(ViewSetMixin, GenericUIView):
+    """GenericUIView with expanded for ViewSet"""
+
+
+class PaginatedView(GenericUIView):
+    """
+    GenericAPIView with pagination
+    extended with selection of serializer class
+    """
+
+    filter_backends = (AdcmFilterBackend, AdcmOrderingFilter)
+    pagination_class = rest_framework.pagination.LimitOffsetPagination
+
+    def get_ordering(self, request, queryset, view):
+        Order = AdcmOrderingFilter()
+        return Order.get_ordering(request, queryset, view)
+
+    def is_paged(self, request):
+        limit = self.request.query_params.get('limit', False)
+        offset = self.request.query_params.get('offset', False)
+        return bool(limit or offset)
+
+    def get_paged_link(self):
+        page = self.paginator
+        url = self.request.build_absolute_uri()
+        url = replace_query_param(url, page.limit_query_param, page.limit)
+        url = replace_query_param(url, page.offset_query_param, 0)
+        return url
+
+    def get_page(self, obj, request, context=None):
+        if not context:
+            context = {}
+        context['request'] = request
+        count = obj.count()
+        serializer_class = self.get_serializer_class()
+
+        if 'fields' in request.query_params or 'distinct' in request.query_params:
+            serializer_class = None
+            try:
+                fields = getlist_from_querydict(request.query_params, 'fields')
+                distinct = int(request.query_params.get('distinct', 0))
+
+                if fields and distinct:
+                    obj = obj.values(*fields).distinct()
+                elif fields:
+                    obj = obj.values(*fields)
+
+            except (FieldError, ValueError):
+                qp = ','.join(
+                    [
+                        f'{k}={v}'
+                        for k, v in request.query_params.items()
+                        if k in ['fields', 'distinct']
+                    ]
+                )
+                msg = f'Bad query params: {qp}'
+                raise AdcmEx('BAD_QUERY_PARAMS', msg=msg) from None
+
+        page = self.paginate_queryset(obj)
+        if self.is_paged(request):
+            if serializer_class is not None:
+                serializer = serializer_class(page, many=True, context=context)
+                page = serializer.data
+            return self.get_paginated_response(page)
+
+        if count <= REST_FRAMEWORK['PAGE_SIZE']:
+            if serializer_class is not None:
+                serializer = serializer_class(obj, many=True, context=context)
+                obj = serializer.data
+            return Response(obj)
+
+        msg = 'Response is too long, use paginated request'
+        raise AdcmEx('TOO_LONG', msg=msg, args=self.get_paged_link())
+
+    def get(self, request, *args, **kwargs):
+        obj = self.filter_queryset(self.get_queryset())
+        return self.get_page(obj, request)
+
+
+class DetailView(GenericUIView):
+    """
+    GenericAPIView for single object
+    extended with selection of serializer class
+    """
+
+    error_code = 'OBJECT_NOT_FOUND'
+
+    def check_obj(self, kw_req):
+        try:
+            return self.get_queryset().get(**kw_req)
+        except ObjectDoesNotExist:
+            raise AdcmEx(self.error_code) from None
+
+    def get_object(self):
+        lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
+        kw_req = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
+        obj = self.check_obj(kw_req)
+        self.check_object_permissions(self.request, obj)
+        return obj
+
+    def get(self, request, *args, **kwargs):
+        obj = self.get_object()
+        serializer = self.get_serializer(obj)
+        return Response(serializer.data)
diff --git a/python/api/cluster/serializers.py b/python/api/cluster/serializers.py
index 8399652b8f..352ee9c919 100644
--- a/python/api/cluster/serializers.py
+++ b/python/api/cluster/serializers.py
@@ -17,7 +17,7 @@
 import cm.job
 import cm.status_api
 from api.action.serializers import ActionShort
-from api.api_views import (
+from api.utils import (
     CommonAPIURL,
     ObjectURL,
     UrlField,
diff --git a/python/api/cluster/views.py b/python/api/cluster/views.py
index 34373ac83e..855cada6c4 100644
--- a/python/api/cluster/views.py
+++ b/python/api/cluster/views.py
@@ -12,29 +12,29 @@
 
 from itertools import chain
 
+from guardian.mixins import PermissionListMixin
 from rest_framework import status, permissions
-from rest_framework.generics import GenericAPIView
 from rest_framework.response import Response
 
 import api.serializers
 import cm.api
 import cm.bundle
 import cm.job
-import cm.status_api
-from api.api_views import (
-    DetailViewRO,
-    GenericAPIPermView,
-    InterfaceView,
-    ListView,
-    PageView,
-    PageViewAdd,
+from api.base_view import GenericUIView, DetailView, PaginatedView
+from api.stack.serializers import ImportSerializer, ServiceSerializer, BundleServiceUISerializer
+from api.utils import (
+    AdcmOrderingFilter,
     check_custom_perm,
     check_obj,
     create,
     update,
+    get_object_for_user,
 )
 from cm.errors import AdcmEx
 from cm.models import Cluster, HostComponent, Prototype, ClusterObject, Upgrade, ClusterBind
+from cm.status_api import make_ui_cluster_status
+from cm.upgrade import get_upgrade
+from rbac.viewsets import DjangoOnlyObjectPermissions
 from . import serializers
 
 
@@ -52,7 +52,7 @@ def get_obj_conf(cluster_id, service_id):
     return obj
 
 
-class ClusterList(PageViewAdd):
+class ClusterList(PermissionListMixin, PaginatedView):
     """
     get:
     List of all existing clusters
@@ -67,15 +67,22 @@ class ClusterList(PageViewAdd):
     serializer_class_post = serializers.ClusterDetailSerializer
     filterset_fields = ('name', 'prototype_id')
     ordering_fields = ('name', 'state', 'prototype__display_name', 'prototype__version_order')
+    permission_required = ['cm.view_cluster']
 
+    def post(self, request, *args, **kwargs):
+        serializer = self.get_serializer(data=request.data)
+        return create(serializer)
 
-class ClusterDetail(DetailViewRO):
+
+class ClusterDetail(PermissionListMixin, DetailView):
     """
     get:
     Show cluster
     """
 
     queryset = Cluster.objects.all()
+    permission_classes = (DjangoOnlyObjectPermissions,)
+    permission_required = ['cm.view_cluster']
     serializer_class = serializers.ClusterDetailSerializer
     serializer_class_ui = serializers.ClusterUISerializer
     lookup_field = 'id'
@@ -87,9 +94,7 @@ def patch(self, request, *args, **kwargs):
         Edit cluster
         """
         obj = self.get_object()
-        serializer = self.serializer_class(
-            obj, data=request.data, partial=True, context={'request': request}
-        )
+        serializer = self.get_serializer(obj, data=request.data, partial=True)
         return update(serializer)
 
     def delete(self, request, *args, **kwargs):
@@ -101,48 +106,53 @@ def delete(self, request, *args, **kwargs):
         return Response(status=status.HTTP_204_NO_CONTENT)
 
 
-class ClusterBundle(ListView):
+class ClusterBundle(GenericUIView):
     queryset = Prototype.objects.filter(type='service')
-    serializer_class = api.stack.serializers.ServiceSerializer
-    serializer_class_ui = api.stack.serializers.BundleServiceUISerializer
+    serializer_class = ServiceSerializer
+    serializer_class_ui = BundleServiceUISerializer
 
-    def get(self, request, cluster_id):  # pylint: disable=arguments-differ
+    def get(self, request, *args, **kwargs):
         """
         List all services of specified cluster of bundle
         """
-        cluster = check_obj(Cluster, cluster_id)
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
+        check_custom_perm(request.user, 'add_service_to', 'cluster', cluster)
         bundle = self.get_queryset().filter(bundle=cluster.prototype.bundle)
         shared = self.get_queryset().filter(shared=True).exclude(bundle=cluster.prototype.bundle)
-        serializer_class = self.select_serializer(request)
-        serializer = serializer_class(
+        serializer = self.get_serializer(
             list(chain(bundle, shared)), many=True, context={'request': request, 'cluster': cluster}
         )
         return Response(serializer.data)
 
 
-class ClusterImport(ListView):
+class ClusterImport(GenericUIView):
     queryset = Prototype.objects.all()
-    serializer_class = api.stack.serializers.ImportSerializer
-    post_serializer = serializers.PostImportSerializer
-    check_import_perm = check_custom_perm
+    serializer_class = ImportSerializer
+    serializer_class_post = serializers.PostImportSerializer
     permission_classes = (permissions.IsAuthenticated,)
 
-    def get(self, request, cluster_id):  # pylint: disable=arguments-differ
+    def get(self, request, *args, **kwargs):
         """
         List all imports avaliable for specified cluster
         """
-        cluster = check_obj(Cluster, cluster_id)
-        self.check_import_perm('view_import_of', 'cluster', cluster, 'view_clusterbind')
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
+        check_custom_perm(request.user, 'view_import_of', 'cluster', cluster, 'view_clusterbind')
         res = cm.api.get_import(cluster)
         return Response(res)
 
-    def post(self, request, cluster_id):  # pylint: disable=arguments-differ
+    def post(self, request, *args, **kwargs):
         """
         Update bind for cluster
         """
-        cluster = check_obj(Cluster, cluster_id)
-        self.check_import_perm('change_import_of', 'cluster', cluster)
-        serializer = self.post_serializer(
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
+        check_custom_perm(request.user, 'change_import_of', 'cluster', cluster)
+        serializer = self.get_serializer(
             data=request.data, context={'request': request, 'cluster': cluster}
         )
         if serializer.is_valid():
@@ -151,177 +161,186 @@ def post(self, request, cluster_id):  # pylint: disable=arguments-differ
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
 
-class ClusterBindList(ListView):
+class ClusterBindList(GenericUIView):
     queryset = ClusterBind.objects.all()
     serializer_class = serializers.ClusterBindSerializer
-    check_import_perm = check_custom_perm
+    serializer_class_post = serializers.DoBindSerializer
     permission_classes = (permissions.IsAuthenticated,)
 
-    def get_serializer_class(self):
-        if self.request and self.request.method == 'POST':
-            return serializers.DoBindSerializer
-        else:
-            return serializers.ClusterBindSerializer
-
-    def get(self, request, cluster_id):  # pylint: disable=arguments-differ
+    def get(self, request, *args, **kwargs):
         """
         List all binds of specified cluster
         """
-        cluster = check_obj(Cluster, cluster_id)
-        self.check_import_perm('view_import_of', 'cluster', cluster, 'view_clusterbind')
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
+        check_custom_perm(request.user, 'view_import_of', 'cluster', cluster, 'view_clusterbind')
         obj = self.get_queryset().filter(cluster=cluster, service=None)
-        serializer = self.get_serializer_class()(obj, many=True, context={'request': request})
+        serializer = self.get_serializer(obj, many=True)
         return Response(serializer.data)
 
-    def post(self, request, cluster_id):
+    def post(self, request, *args, **kwargs):
         """
         Bind two clusters
         """
-        cluster = check_obj(Cluster, cluster_id)
-        self.check_import_perm('change_import_of', 'cluster', cluster)
-        serializer = self.get_serializer_class()(data=request.data, context={'request': request})
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
+        check_custom_perm(request.user, 'change_import_of', 'cluster', cluster)
+        serializer = self.get_serializer(data=request.data)
         return create(serializer, cluster=cluster)
 
 
-class ClusterBindDetail(DetailViewRO):
+class ClusterBindDetail(GenericUIView):
     queryset = ClusterBind.objects.all()
     serializer_class = serializers.BindSerializer
-    check_import_perm = check_custom_perm
     permission_classes = (permissions.IsAuthenticated,)
 
-    def get_obj(self, cluster_id, bind_id):
-        cluster = check_obj(Cluster, cluster_id)
-        return cluster, check_obj(ClusterBind, {'cluster': cluster, 'id': bind_id})
-
-    def get(self, request, cluster_id, bind_id):  # pylint: disable=arguments-differ
+    def get(self, request, *args, **kwargs):
         """
         Show specified bind of specified cluster
         """
-        cluster, obj = self.get_obj(cluster_id, bind_id)
-        self.check_import_perm('view_import_of', 'cluster', cluster, 'view_clusterbind')
-        serializer = self.serializer_class(obj, context={'request': request})
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
+        bind = check_obj(ClusterBind, {'cluster': cluster, 'id': kwargs['bind_id']})
+        check_custom_perm(request.user, 'view_import_of', 'cluster', cluster, 'view_clusterbind')
+        serializer = self.get_serializer(bind)
         return Response(serializer.data)
 
-    def delete(self, request, cluster_id, bind_id):  # pylint: disable=arguments-differ
+    def delete(self, request, *args, **kwargs):
         """
         Unbind specified bind of specified cluster
         """
-        cluster, bind = self.get_obj(cluster_id, bind_id)
-        self.check_import_perm('change_import_of', 'cluster', cluster)
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
+        bind = check_obj(ClusterBind, {'cluster': cluster, 'id': kwargs['bind_id']})
+        check_custom_perm(request.user, 'change_import_of', 'cluster', cluster)
         cm.api.unbind(bind)
         return Response(status=status.HTTP_204_NO_CONTENT)
 
 
-class ClusterUpgrade(PageView):
+class ClusterUpgrade(GenericUIView):
     queryset = Upgrade.objects.all()
     serializer_class = api.serializers.UpgradeLinkSerializer
-    check_upgrade_perm = check_custom_perm
     permission_classes = (permissions.IsAuthenticated,)
 
-    def get(self, request, cluster_id):  # pylint: disable=arguments-differ
+    def get_ordering(self):
+        Order = AdcmOrderingFilter()
+        return Order.get_ordering(self.request, self.get_queryset(), self)
+
+    def get(self, request, *args, **kwargs):
         """
         List all avaliable upgrades for specified cluster
         """
-        cluster = check_obj(Cluster, cluster_id)
-        self.check_upgrade_perm('view_upgrade_of', 'cluster', cluster)
-        obj = cm.upgrade.get_upgrade(cluster, self.get_ordering(request, self.queryset, self))
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
+        check_custom_perm(request.user, 'view_upgrade_of', 'cluster', cluster)
+        obj = get_upgrade(cluster, self.get_ordering())
         serializer = self.serializer_class(
             obj, many=True, context={'cluster_id': cluster.id, 'request': request}
         )
         return Response(serializer.data)
 
 
-class ClusterUpgradeDetail(ListView):
+class ClusterUpgradeDetail(GenericUIView):
     queryset = Upgrade.objects.all()
     serializer_class = api.serializers.UpgradeLinkSerializer
-    check_upgrade_perm = check_custom_perm
     permission_classes = (permissions.IsAuthenticated,)
 
-    def get(self, request, cluster_id, upgrade_id):  # pylint: disable=arguments-differ
+    def get(self, request, *args, **kwargs):
         """
         List all avaliable upgrades for specified cluster
         """
-        cluster = check_obj(Cluster, cluster_id)
-        self.check_upgrade_perm('view_upgrade_of', 'cluster', cluster)
-        obj = self.get_queryset().get(id=upgrade_id)
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
+        check_custom_perm(request.user, 'view_upgrade_of', 'cluster', cluster)
+        obj = check_obj(
+            Upgrade, {'id': kwargs['upgrade_id'], 'bundle__name': cluster.prototype.bundle.name}
+        )
         serializer = self.serializer_class(
             obj, context={'cluster_id': cluster.id, 'request': request}
         )
         return Response(serializer.data)
 
 
-class DoClusterUpgrade(GenericAPIPermView):
+class DoClusterUpgrade(GenericUIView):
     queryset = Upgrade.objects.all()
     serializer_class = api.serializers.DoUpgradeSerializer
-    check_upgrade_perm = check_custom_perm
     permission_classes = (permissions.IsAuthenticated,)
 
-    def post(self, request, cluster_id, upgrade_id):
+    def post(self, request, *args, **kwargs):
         """
         Do upgrade specified cluster
         """
-        cluster = check_obj(Cluster, cluster_id)
-        self.check_upgrade_perm('do_upgrade_of', 'cluster', cluster)
-        serializer = self.serializer_class(data=request.data, context={'request': request})
-        return create(serializer, upgrade_id=int(upgrade_id), obj=cluster)
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
+        check_custom_perm(request.user, 'do_upgrade_of', 'cluster', cluster)
+        serializer = self.get_serializer(data=request.data)
+        return create(serializer, upgrade_id=int(kwargs['upgrade_id']), obj=cluster)
 
 
-class StatusList(GenericAPIView, InterfaceView):
+class StatusList(GenericUIView):
+    permission_classes = (permissions.IsAuthenticated,)
     queryset = HostComponent.objects.all()
-    model_name = Cluster
     serializer_class = serializers.StatusSerializer
 
-    def get(self, request, cluster_id):
+    def get(self, request, *args, **kwargs):
         """
         Show all hosts and components in a specified cluster
         """
-        cluster = check_obj(Cluster, cluster_id)
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
         host_components = self.get_queryset().filter(cluster=cluster)
-        if self.for_ui(request):
-            return Response(cm.status_api.make_ui_cluster_status(cluster, host_components))
+        if self._is_for_ui():
+            return Response(make_ui_cluster_status(cluster, host_components))
         else:
-            serializer = self.serializer_class(
-                host_components, many=True, context={'request': request}
-            )
+            serializer = self.get_serializer(host_components, many=True)
             return Response(serializer.data)
 
 
-class HostComponentList(GenericAPIPermView, InterfaceView):
+class HostComponentList(GenericUIView):
     queryset = HostComponent.objects.all()
     serializer_class = serializers.HostComponentSerializer
     serializer_class_ui = serializers.HostComponentUISerializer
-    check_hc_perm = check_custom_perm
+    serializer_class_post = serializers.HostComponentSaveSerializer
     permission_classes = (permissions.IsAuthenticated,)
 
-    def get_serializer_class(self):
-        if self.request and self.request.method == 'POST':
-            return serializers.HostComponentSaveSerializer
-        return self.serializer_class
-
-    def get(self, request, cluster_id):
+    def get(self, request, *args, **kwargs):
         """
         Show host <-> component map in a specified cluster
         """
-        cluster = check_obj(Cluster, cluster_id)
-        self.check_hc_perm('view_host_components_of', 'cluster', cluster, 'view_hostcomponent')
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
+        check_custom_perm(
+            request.user, 'view_host_components_of', 'cluster', cluster, 'view_hostcomponent'
+        )
         hc = self.get_queryset().filter(cluster=cluster)
-        serializer_class = self.select_serializer(request)
-        if self.for_ui(request):
+        if self._is_for_ui():
             ui_hc = HostComponent()
             ui_hc.hc = hc
-            serializer = serializer_class(ui_hc, context={'request': request, 'cluster': cluster})
+            serializer = self.get_serializer(
+                ui_hc, context={'request': request, 'cluster': cluster}
+            )
         else:
-            serializer = serializer_class(hc, many=True, context={'request': request})
+            serializer = self.get_serializer(hc, many=True)
         return Response(serializer.data)
 
-    def post(self, request, cluster_id):
+    def post(self, request, *args, **kwargs):
         """
         Create new mapping service:component <-> host in a specified cluster.
         """
-        cluster = check_obj(Cluster, cluster_id)
-        self.check_hc_perm('edit_host_components_of', 'cluster', cluster)
-        save_serializer = self.get_serializer_class()
-        serializer = save_serializer(
+        cluster = get_object_for_user(
+            request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+        )
+        check_custom_perm(request.user, 'edit_host_components_of', 'cluster', cluster)
+        serializer = self.get_serializer(
             data=request.data,
             context={
                 'request': request,
@@ -337,21 +356,22 @@ def post(self, request, cluster_id):
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
 
-class HostComponentDetail(GenericAPIPermView):
+class HostComponentDetail(GenericUIView):
     queryset = HostComponent.objects.all()
     serializer_class = serializers.HostComponentSerializer
-    check_hc_perm = check_custom_perm
     permission_classes = (permissions.IsAuthenticated,)
 
     def get_obj(self, cluster_id, hs_id):
-        cluster = check_obj(Cluster, cluster_id)
-        self.check_hc_perm('view_host_components_of', 'cluster', cluster, 'view_hostcomponent')
+        cluster = get_object_for_user(self.request.user, 'cm.view_cluster', Cluster, id=cluster_id)
+        check_custom_perm(
+            self.request.user, 'view_host_components_of', 'cluster', cluster, 'view_hostcomponent'
+        )
         return check_obj(HostComponent, {'id': hs_id, 'cluster': cluster}, 'HOSTSERVICE_NOT_FOUND')
 
-    def get(self, request, cluster_id, hs_id):
+    def get(self, request, *args, **kwargs):
         """
         Show host <-> component link in a specified cluster
         """
-        obj = self.get_obj(cluster_id, hs_id)
-        serializer = self.serializer_class(obj, context={'request': request})
+        obj = self.get_obj(kwargs['cluster_id'], kwargs['hs_id'])
+        serializer = self.get_serializer(obj)
         return Response(serializer.data)
diff --git a/python/api/component/serializers.py b/python/api/component/serializers.py
index d7e4e22a7b..7d0cf8248e 100644
--- a/python/api/component/serializers.py
+++ b/python/api/component/serializers.py
@@ -15,7 +15,7 @@
 from rest_framework import serializers
 
 from api.action.serializers import ActionShort
-from api.api_views import hlink, filter_actions, CommonAPIURL, ObjectURL
+from api.utils import hlink, filter_actions, CommonAPIURL, ObjectURL
 from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer
 from api.group_config.serializers import GroupConfigsHyperlinkedIdentityField
 from api.serializers import StringListSerializer
diff --git a/python/api/component/views.py b/python/api/component/views.py
index 0260d3dea4..9f2a32d612 100644
--- a/python/api/component/views.py
+++ b/python/api/component/views.py
@@ -10,69 +10,76 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from rest_framework.generics import GenericAPIView
+from guardian.mixins import PermissionListMixin
+from rest_framework import permissions
 from rest_framework.response import Response
 
-import cm.status_api
-from api.api_views import PageView, check_obj, DetailViewRO, InterfaceView
+from api.base_view import GenericUIView, PaginatedView, DetailView
+from api.utils import get_object_for_user
 from cm.models import ServiceComponent, ClusterObject, Cluster, HostComponent
+from cm.status_api import make_ui_component_status
+from rbac.viewsets import DjangoOnlyObjectPermissions
 from . import serializers
 
 
-class ComponentListView(PageView):
+def get_component_queryset(queryset, user, kwargs):
+    if 'cluster_id' in kwargs:
+        cluster = get_object_for_user(user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id'])
+        co = get_object_for_user(
+            user, 'cm.view_clusterobject', ClusterObject, cluster=cluster, id=kwargs['service_id']
+        )
+        queryset = queryset.filter(cluster=cluster, service=co)
+    elif 'service_id' in kwargs:
+        co = get_object_for_user(
+            user, 'cm.view_clusterobject', ClusterObject, id=kwargs['service_id']
+        )
+        queryset = queryset.filter(service=co)
+    return queryset
+
+
+class ComponentListView(PermissionListMixin, PaginatedView):
     queryset = ServiceComponent.objects.all()
     serializer_class = serializers.ComponentSerializer
     serializer_class_ui = serializers.ComponentUISerializer
     filterset_fields = ('cluster_id', 'service_id')
     ordering_fields = ('state', 'prototype__display_name', 'prototype__version_order')
+    permission_required = ['cm.view_servicecomponent']
 
-    def get(self, request, *args, **kwargs):
-        """
-        List all components
-        """
-        queryset = self.get_queryset()
-        if 'cluster_id' in kwargs:
-            cluster = check_obj(Cluster, kwargs['cluster_id'], 'CLUSTER_NOT_FOUND')
-            co = check_obj(
-                ClusterObject, {'cluster': cluster, 'id': kwargs['service_id']}, 'SERVICE_NOT_FOUND'
-            )
-            queryset = self.get_queryset().filter(cluster=cluster, service=co)
-        elif 'service_id' in kwargs:
-            co = check_obj(ClusterObject, {'id': kwargs['service_id']}, 'SERVICE_NOT_FOUND')
-            queryset = self.get_queryset().filter(service=co)
-        return self.get_page(self.filter_queryset(queryset), request)
+    def get_queryset(self):  # pylint: disable=arguments-differ
+        queryset = super().get_queryset()
+        return get_component_queryset(queryset, self.request.user, self.kwargs)
 
 
-class ComponentDetailView(DetailViewRO):
+class ComponentDetailView(PermissionListMixin, DetailView):
     queryset = ServiceComponent.objects.all()
     serializer_class = serializers.ComponentDetailSerializer
     serializer_class_ui = serializers.ComponentUISerializer
+    permission_classes = (DjangoOnlyObjectPermissions,)
+    permission_required = ['cm.view_servicecomponent']
+    lookup_url_kwarg = 'component_id'
+    error_code = ServiceComponent.__error_code__
 
-    def get(self, request, *args, **kwargs):
-        """
-        Show component
-        """
-        component = check_obj(
-            ServiceComponent, {'id': kwargs['component_id']}, 'COMPONENT_NOT_FOUND'
-        )
-        serial_class = self.select_serializer(request)
-        serializer = serial_class(component, context={'request': request})
-        return Response(serializer.data)
+    def get_queryset(self):  # pylint: disable=arguments-differ
+        queryset = super().get_queryset()
+        return get_component_queryset(queryset, self.request.user, self.kwargs)
 
 
-class StatusList(GenericAPIView, InterfaceView):
-    serializer_class = serializers.StatusSerializer
-    model_name = ServiceComponent
+class StatusList(GenericUIView):
     queryset = HostComponent.objects.all()
+    permission_classes = (permissions.IsAuthenticated,)
+    serializer_class = serializers.StatusSerializer
 
-    def get(self, request, component_id, cluster_id=None, service_id=None):
+    def get(self, request, *args, **kwargs):
         """
         Show all components in a specified host
         """
-        component = check_obj(ServiceComponent, component_id)
-        if self.for_ui(request):
+        queryset = get_component_queryset(ServiceComponent.objects.all(), request.user, kwargs)
+        component = get_object_for_user(
+            request.user, 'cm.view_servicecomponent', queryset, id=kwargs['component_id']
+        )
+        if self._is_for_ui():
             host_components = self.get_queryset().filter(component=component)
-            return Response(cm.status_api.make_ui_component_status(component, host_components))
+            return Response(make_ui_component_status(component, host_components))
         else:
-            serializer = self.serializer_class(component, context={'request': request})
+            serializer = self.get_serializer(component)
             return Response(serializer.data)
diff --git a/python/api/concern/serializers.py b/python/api/concern/serializers.py
index b3a173f576..a1b72a4639 100644
--- a/python/api/concern/serializers.py
+++ b/python/api/concern/serializers.py
@@ -13,7 +13,7 @@
 from rest_framework.reverse import reverse
 from rest_framework import serializers
 
-from api.api_views import hlink, get_api_url_kwargs
+from api.utils import hlink, get_api_url_kwargs
 
 
 class ConcernItemSerializer(serializers.Serializer):
diff --git a/python/api/concern/views.py b/python/api/concern/views.py
index 4f3aa96498..f8f74938b7 100644
--- a/python/api/concern/views.py
+++ b/python/api/concern/views.py
@@ -12,8 +12,9 @@
 
 from django.contrib.contenttypes.models import ContentType
 from django_filters import rest_framework as drf_filters
+from rest_framework.permissions import IsAuthenticated
 
-from api.api_views import PageView, DetailViewRO
+from api.base_view import DetailView, PaginatedView
 from cm import models
 from cm.errors import AdcmEx
 from . import serializers
@@ -77,7 +78,7 @@ def is_valid(self):
         return super().is_valid()
 
 
-class ConcernItemList(PageView):
+class ConcernItemList(PaginatedView):
     """
     get:
     List of all existing concern items
@@ -86,11 +87,12 @@ class ConcernItemList(PageView):
     queryset = models.ConcernItem.objects.all()
     serializer_class = serializers.ConcernItemSerializer
     serializer_class_ui = serializers.ConcernItemUISerializer
+    permission_classes = (IsAuthenticated,)
     filterset_class = ConcernFilter
     ordering_fields = ('name',)
 
 
-class ConcernItemDetail(DetailViewRO):
+class ConcernItemDetail(DetailView):
     """
     get:
     Show concern item
@@ -98,6 +100,7 @@ class ConcernItemDetail(DetailViewRO):
 
     queryset = models.ConcernItem.objects.all()
     serializer_class = serializers.ConcernItemDetailSerializer
+    permission_classes = (IsAuthenticated,)
     lookup_field = 'id'
     lookup_url_kwarg = 'concern_id'
     error_code = 'CONCERNITEM_NOT_FOUND'
diff --git a/python/api/config/serializers.py b/python/api/config/serializers.py
index 9018165ba3..b3ada1f203 100644
--- a/python/api/config/serializers.py
+++ b/python/api/config/serializers.py
@@ -19,7 +19,7 @@
 import cm.adcm_config
 from cm.adcm_config import ui_config, restore_cluster_config
 from cm.api import update_obj_config
-from api.api_views import get_api_url_kwargs, CommonAPIURL
+from api.utils import get_api_url_kwargs, CommonAPIURL
 
 
 class ConfigVersionURL(serializers.HyperlinkedIdentityField):
diff --git a/python/api/config/views.py b/python/api/config/views.py
index c2827d80c2..254e2f7281 100644
--- a/python/api/config/views.py
+++ b/python/api/config/views.py
@@ -10,26 +10,30 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from guardian.mixins import PermissionListMixin
 from rest_framework import permissions
 from rest_framework.response import Response
 
-from api.api_views import ListView, GenericAPIPermView
-from api.api_views import create, update, check_obj, permission_denied
-
+from api.base_view import GenericUIView
+from api.utils import create, update, check_obj, permission_denied
 from cm.adcm_config import ui_config
+from cm.errors import AdcmEx
 from cm.models import get_model_by_type, ConfigLog, ObjectConfig
-
+from rbac.viewsets import DjangoOnlyObjectPermissions
 from . import serializers
 
 
-def get_config_version(objconf, version):
+def get_config_version(queryset, objconf, version):
     if version == 'previous':
         ver = objconf.previous
     elif version == 'current':
         ver = objconf.current
     else:
         ver = version
-    cl = ConfigLog.obj.get(obj_ref=objconf, id=ver)
+    try:
+        cl = queryset.get(obj_ref=objconf, id=ver)
+    except ConfigLog.DoesNotExist:
+        raise AdcmEx('CONFIG_NOT_FOUND') from None
     return cl
 
 
@@ -47,8 +51,7 @@ def get_obj(object_type, object_id):
     model = get_model_by_type(object_type)
     obj = model.obj.get(id=object_id)
     oc = check_obj(ObjectConfig, {type_to_model(object_type): obj}, 'CONFIG_NOT_FOUND')
-    cl = ConfigLog.obj.get(obj_ref=oc, id=oc.current)
-    return obj, oc, cl
+    return obj, oc
 
 
 def get_object_type_id_version(**kwargs):
@@ -58,109 +61,111 @@ def get_object_type_id_version(**kwargs):
     return object_type, object_id, version
 
 
-def get_queryset(self):
-    return get_model_by_type(self.object_type).objects.all()
-
-
 def has_config_perm(user, action_type, object_type, obj):
     """
-    config_of_adcm checks permission to view/change config of any object
-    settings_of_adcm checks permission to view/change only ADCM settings
+    Checks permission to view/change config of any object
     """
     model = type_to_model(object_type)
     if user.has_perm(f'cm.{action_type}_config_of_{model}', obj):
         return True
-    if user.has_perm(f'cm.{action_type}_config_of_adcm'):
-        return True
-    if user.has_perm(f'cm.{action_type}_settings_of_adcm') and object_type == 'adcm':
+    if model == 'adcm' and user.has_perm(f'cm.{action_type}_settings_of_{model}'):
         return True
     return False
 
 
-def check_config_perm(self, action_type, object_type, obj):
-    if not has_config_perm(self.request.user, action_type, object_type, obj):
+def check_config_perm(user, action_type, object_type, obj):
+    if not has_config_perm(user, action_type, object_type, obj):
         permission_denied()
 
 
-class ConfigView(ListView):
+class ConfigView(GenericUIView):
+    queryset = ConfigLog.objects.all()
     serializer_class = serializers.HistoryCurrentPreviousConfigSerializer
     permission_classes = (permissions.IsAuthenticated,)
-    check_config_perm = check_config_perm
-    get_queryset = get_queryset
-    object_type = None
 
     def get(self, request, *args, **kwargs):
         object_type, object_id, _ = get_object_type_id_version(**kwargs)
-        self.object_type = object_type
-        obj, _, _ = get_obj(object_type, object_id)
-        self.check_config_perm('view', object_type, obj)
-        serializer = self.serializer_class(
-            self.get_queryset().get(id=obj.id), context={'request': request, 'object': obj}
-        )
+        model = get_model_by_type(object_type)
+        obj = model.obj.get(id=object_id)
+        serializer = self.get_serializer(obj)
         return Response(serializer.data)
 
 
-class ConfigHistoryView(ListView):
+class ConfigHistoryView(PermissionListMixin, GenericUIView):
+    queryset = ConfigLog.objects.all()
     serializer_class = serializers.ConfigHistorySerializer
-    update_serializer = serializers.ObjectConfigUpdateSerializer
-    permission_classes = (permissions.IsAuthenticated,)
-    check_config_perm = check_config_perm
-    get_queryset = get_queryset
-    object_type = None
+    serializer_class_post = serializers.ObjectConfigUpdateSerializer
+    permission_required = ['cm.view_configlog']
+
+    def get_queryset(self, *args, **kwargs):
+        if self.request.user.has_perm('cm.view_settings_of_adcm'):
+            return super().get_queryset(*args, **kwargs) | ConfigLog.objects.filter(
+                obj_ref__adcm__isnull=False
+            )
+        else:
+            return super().get_queryset(*args, **kwargs).filter(obj_ref__adcm__isnull=True)
 
     def get(self, request, *args, **kwargs):
         object_type, object_id, _ = get_object_type_id_version(**kwargs)
-        self.object_type = object_type
-        obj, _, _ = get_obj(object_type, object_id)
-        self.check_config_perm('view', object_type, obj)
-        cl = ConfigLog.objects.filter(obj_ref=obj.config).order_by('-id')
-        serializer = self.serializer_class(
-            cl, many=True, context={'request': request, 'object': obj}
-        )
+        obj, oc = get_obj(object_type, object_id)
+        cl = self.get_queryset().filter(obj_ref=oc).order_by('-id')
+        serializer = self.get_serializer(cl, many=True, context={'request': request, 'object': obj})
         return Response(serializer.data)
 
     def post(self, request, *args, **kwargs):
         object_type, object_id, _ = get_object_type_id_version(**kwargs)
-        self.object_type = object_type
-        obj, _, cl = get_obj(object_type, object_id)
-        self.check_config_perm('change', object_type, obj)
-        serializer = self.update_serializer(
-            cl, data=request.data, context={'request': request, 'object': obj}
-        )
-        return create(serializer, ui=bool(self.for_ui(request)), obj=obj)
-
-
-class ConfigVersionView(ListView):
+        obj, oc = get_obj(object_type, object_id)
+        check_config_perm(request.user, 'change', object_type, obj)
+        try:
+            cl = self.get_queryset().get(obj_ref=oc, id=oc.current)
+        except ConfigLog.DoesNotExist:
+            raise AdcmEx('CONFIG_NOT_FOUND') from None
+        serializer = self.get_serializer(cl, data=request.data)
+        return create(serializer, ui=self._is_for_ui(), obj=obj)
+
+
+class ConfigVersionView(PermissionListMixin, GenericUIView):
+    queryset = ConfigLog.objects.all()
+    permission_classes = (DjangoOnlyObjectPermissions,)
     serializer_class = serializers.ObjectConfigSerializer
-    permission_classes = (permissions.IsAuthenticated,)
-    check_config_perm = check_config_perm
-    get_queryset = get_queryset
-    object_type = None
+    permission_required = ['cm.view_configlog']
+
+    def get_queryset(self, *args, **kwargs):
+        if self.request.user.has_perm('cm.view_settings_of_adcm'):
+            return super().get_queryset(*args, **kwargs) | ConfigLog.objects.filter(
+                obj_ref__adcm__isnull=False
+            )
+        else:
+            return super().get_queryset(*args, **kwargs).filter(obj_ref__adcm__isnull=True)
 
     def get(self, request, *args, **kwargs):
         object_type, object_id, version = get_object_type_id_version(**kwargs)
-        self.object_type = object_type
-        obj, oc, _ = get_obj(object_type, object_id)
-        self.check_config_perm('view', object_type, obj)
-        cl = get_config_version(oc, version)
-        if self.for_ui(request):
+        obj, oc = get_obj(object_type, object_id)
+        cl = get_config_version(self.get_queryset(), oc, version)
+        if self._is_for_ui():
             cl.config = ui_config(obj, cl)
-        serializer = self.serializer_class(cl, context={'request': request})
+        serializer = self.get_serializer(cl)
         return Response(serializer.data)
 
 
-class ConfigHistoryRestoreView(GenericAPIPermView):
+class ConfigHistoryRestoreView(PermissionListMixin, GenericUIView):
+    queryset = ConfigLog.objects.all()
     serializer_class = serializers.ObjectConfigRestoreSerializer
-    permission_classes = (permissions.IsAuthenticated,)
-    check_config_perm = check_config_perm
-    get_queryset = get_queryset
-    object_type = None
+    permission_classes = (DjangoOnlyObjectPermissions,)
+    permission_required = ['cm.view_configlog']
+
+    def get_queryset(self, *args, **kwargs):
+        if self.request.user.has_perm('cm.view_settings_of_adcm'):
+            return super().get_queryset(*args, **kwargs) | ConfigLog.objects.filter(
+                obj_ref__adcm__isnull=False
+            )
+        else:
+            return super().get_queryset(*args, **kwargs).filter(obj_ref__adcm__isnull=True)
 
     def patch(self, request, *args, **kwargs):
         object_type, object_id, version = get_object_type_id_version(**kwargs)
-        self.object_type = object_type
-        obj, oc, _ = get_obj(object_type, object_id)
-        self.check_config_perm('change', object_type, obj)
-        cl = get_config_version(oc, version)
-        serializer = self.serializer_class(cl, data=request.data, context={'request': request})
+        obj, oc = get_obj(object_type, object_id)
+        check_config_perm(request.user, 'change', object_type, obj)
+        cl = get_config_version(self.get_queryset(), oc, version)
+        serializer = self.get_serializer(cl, data=request.data)
         return update(serializer)
diff --git a/python/api/config_log/views.py b/python/api/config_log/views.py
index a7213d98ca..58989e74e2 100644
--- a/python/api/config_log/views.py
+++ b/python/api/config_log/views.py
@@ -10,20 +10,47 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from django.contrib.contenttypes.models import ContentType
+from guardian.mixins import PermissionListMixin
+from rest_framework import status
 from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin
+from rest_framework.permissions import DjangoObjectPermissions
+from rest_framework.response import Response
 
-from api.views import ViewInterfaceGenericViewSet
+from api.base_view import GenericUIViewSet
+from api.config.views import check_config_perm
 from cm.models import ConfigLog
 from .serializers import ConfigLogSerializer, UIConfigLogSerializer
-from rbac.viewsets import DjangoObjectPerm
 
 
 class ConfigLogViewSet(  # pylint: disable=too-many-ancestors
-    CreateModelMixin, ListModelMixin, RetrieveModelMixin, ViewInterfaceGenericViewSet
+    PermissionListMixin, CreateModelMixin, ListModelMixin, RetrieveModelMixin, GenericUIViewSet
 ):
     queryset = ConfigLog.objects.all()
     serializer_class = ConfigLogSerializer
-    permission_classes = (DjangoObjectPerm,)
-    ui_serializer_class = UIConfigLogSerializer
+    permission_classes = (DjangoObjectPermissions,)
+    serializer_class_ui = UIConfigLogSerializer
+    permission_required = ['cm.view_configlog']
     filterset_fields = ('id', 'obj_ref')
     ordering_fields = ('id',)
+
+    def get_queryset(self, *args, **kwargs):
+        if self.request.user.has_perm('cm.view_settings_of_adcm'):
+            return super().get_queryset(*args, **kwargs) | ConfigLog.objects.filter(
+                obj_ref__adcm__isnull=False
+            )
+        else:
+            return super().get_queryset(*args, **kwargs).filter(obj_ref__adcm__isnull=True)
+
+    def create(self, request, *args, **kwargs):
+        serializer = self.get_serializer(data=request.data)
+        serializer.is_valid(raise_exception=True)
+
+        # check custom permissions
+        obj = serializer.validated_data['obj_ref'].object
+        object_type = ContentType.objects.get_for_model(obj).model
+        check_config_perm(request.user, 'change', object_type, obj)
+
+        self.perform_create(serializer)
+        headers = self.get_success_headers(serializer.data)
+        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
diff --git a/python/api/group_config/views.py b/python/api/group_config/views.py
index b89664b370..8262a3794b 100644
--- a/python/api/group_config/views.py
+++ b/python/api/group_config/views.py
@@ -13,9 +13,8 @@
 
 from django.contrib.contenttypes.models import ContentType
 from django_filters.rest_framework import FilterSet, CharFilter
-from rest_framework.permissions import IsAuthenticated
-from rest_framework import status
-from rest_framework import viewsets
+from guardian.mixins import PermissionListMixin
+from rest_framework import status, viewsets, permissions
 from rest_framework.mixins import (
     ListModelMixin,
     CreateModelMixin,
@@ -25,23 +24,21 @@
 from rest_framework.response import Response
 from rest_framework_extensions.mixins import NestedViewSetMixin
 
-from api.api_views import permission_denied
-from api.views import ViewInterfaceGenericViewSet
+from api.base_view import GenericUIViewSet
+from api.utils import permission_denied
 from cm.models import GroupConfig, Host, ObjectConfig, ConfigLog
 from . import serializers
 
 
 def has_config_perm(user, action_type, obj):
     model = type(obj).__name__.lower()
-    if user.has_perm(f'cm.{action_type}_configlog'):
-        return True
     if user.has_perm(f'cm.{action_type}_config_of_{model}', obj):
         return True
     return False
 
 
-def check_config_perm(self, action_type, obj):
-    if not has_config_perm(self.request.user, action_type, obj):
+def check_config_perm(user, action_type, obj):
+    if not has_config_perm(user, action_type, obj):
         permission_denied()
 
 
@@ -61,6 +58,7 @@ class Meta:
 
 
 class GroupConfigHostViewSet(
+    PermissionListMixin,
     NestedViewSetMixin,
     ListModelMixin,
     CreateModelMixin,
@@ -70,13 +68,12 @@ class GroupConfigHostViewSet(
 ):  # pylint: disable=too-many-ancestors
     queryset = Host.objects.all()
     serializer_class = serializers.GroupConfigHostSerializer
-    permission_classes = (IsAuthenticated,)
-    check_config_perm = check_config_perm
+    permission_classes = (permissions.DjangoObjectPermissions,)
+    permission_required = ['view_host']
     lookup_url_kwarg = 'host_id'
 
     def destroy(self, request, *args, **kwargs):
         group_config = GroupConfig.obj.get(id=self.kwargs.get('parent_lookup_group_config'))
-        self.check_config_perm('change', group_config.object)
         host = self.get_object()
         group_config.hosts.remove(host)
         return Response(status=status.HTTP_204_NO_CONTENT)
@@ -88,23 +85,22 @@ def get_serializer_context(self):
         group_config_id = self.kwargs.get('parent_lookup_group_config')
         if group_config_id is not None:
             group_config = GroupConfig.obj.get(id=group_config_id)
-            self.check_config_perm('view', group_config.object)
             context.update({'group_config': group_config})
         return context
 
 
 class GroupConfigHostCandidateViewSet(
-    NestedViewSetMixin, viewsets.ReadOnlyModelViewSet
+    PermissionListMixin, NestedViewSetMixin, viewsets.ReadOnlyModelViewSet
 ):  # pylint: disable=too-many-ancestors
     serializer_class = serializers.GroupConfigHostCandidateSerializer
-    permission_classes = (IsAuthenticated,)
-    check_config_perm = check_config_perm
+    permission_classes = (permissions.DjangoObjectPermissions,)
     lookup_url_kwarg = 'host_id'
+    permission_required = ['cm.view_host']
 
-    def get_queryset(self):
+    def get_queryset(self, *args, **kwargs):
         group_config_id = self.kwargs.get('parent_lookup_group_config')
         if group_config_id is None:
-            return None
+            return Host.objects.none()
         group_config = GroupConfig.obj.get(id=group_config_id)
         return group_config.host_candidate()
 
@@ -115,16 +111,17 @@ def get_serializer_context(self):
         group_config_id = self.kwargs.get('parent_lookup_group_config')
         if group_config_id is not None:
             group_config = GroupConfig.obj.get(id=group_config_id)
-            self.check_config_perm('view', group_config.object)
             context.update({'group_config': group_config})
         return context
 
 
-class GroupConfigConfigViewSet(NestedViewSetMixin, RetrieveModelMixin, viewsets.GenericViewSet):
+class GroupConfigConfigViewSet(
+    PermissionListMixin, NestedViewSetMixin, RetrieveModelMixin, viewsets.GenericViewSet
+):  # pylint: disable=too-many-ancestors
     queryset = ObjectConfig.objects.all()
     serializer_class = serializers.GroupConfigConfigSerializer
-    permission_classes = (IsAuthenticated,)
-    check_config_perm = check_config_perm
+    permission_classes = (permissions.DjangoObjectPermissions,)
+    permission_required = ['view_objectconfig']
 
     def get_serializer_context(self):
         context = super().get_serializer_context()
@@ -133,7 +130,6 @@ def get_serializer_context(self):
         group_config_id = self.kwargs.get('parent_lookup_group_config')
         if group_config_id is not None:
             group_config = GroupConfig.obj.get(id=group_config_id)
-            self.check_config_perm('view', group_config.object)
             context.update({'group_config': group_config})
             context.update({'obj_ref__group_config': group_config})
         obj_ref_id = self.kwargs.get('pk')
@@ -144,20 +140,21 @@ def get_serializer_context(self):
 
 
 class GroupConfigConfigLogViewSet(
+    PermissionListMixin,
     NestedViewSetMixin,
     RetrieveModelMixin,
     ListModelMixin,
     CreateModelMixin,
-    ViewInterfaceGenericViewSet,
+    GenericUIViewSet,
 ):  # pylint: disable=too-many-ancestors
     serializer_class = serializers.GroupConfigConfigLogSerializer
-    ui_serializer_class = serializers.UIGroupConfigConfigLogSerializer
-    permission_classes = (IsAuthenticated,)
-    check_config_perm = check_config_perm
+    serializer_class_ui = serializers.UIGroupConfigConfigLogSerializer
+    permission_classes = (permissions.DjangoObjectPermissions,)
+    permission_required = ['view_configlog']
     filterset_fields = ('id',)
     ordering_fields = ('id',)
 
-    def get_queryset(self):
+    def get_queryset(self, *args, **kwargs):
         kwargs = {
             'obj_ref__group_config': self.kwargs.get('parent_lookup_obj_ref__group_config'),
             'obj_ref': self.kwargs.get('parent_lookup_obj_ref'),
@@ -171,7 +168,6 @@ def get_serializer_context(self):
         group_config_id = self.kwargs.get('parent_lookup_obj_ref__group_config')
         if group_config_id is not None:
             group_config = GroupConfig.obj.get(id=group_config_id)
-            self.check_config_perm('view', group_config.object)
             context.update({'obj_ref__group_config': group_config})
         obj_ref_id = self.kwargs.get('parent_lookup_obj_ref')
         if obj_ref_id is not None:
@@ -181,19 +177,49 @@ def get_serializer_context(self):
 
 
 class GroupConfigViewSet(
-    NestedViewSetMixin, viewsets.ModelViewSet
+    PermissionListMixin, NestedViewSetMixin, viewsets.ModelViewSet
 ):  # pylint: disable=too-many-ancestors
     queryset = GroupConfig.objects.all()
     serializer_class = serializers.GroupConfigSerializer
     filterset_class = GroupConfigFilterSet
-    permission_classes = (IsAuthenticated,)
-    check_config_perm = check_config_perm
+    permission_classes = (permissions.DjangoObjectPermissions,)
+    permission_required = ['cm.view_groupconfig']
+
+    def create(self, request, *args, **kwargs):
+        serializer = self.get_serializer(data=request.data)
+        serializer.is_valid(raise_exception=True)
 
-    def perform_create(self, serializer):
         model = serializer.validated_data['object_type'].model_class()
         obj = model.obj.get(id=serializer.validated_data['object_id'])
-        self.check_config_perm('change', obj)
-        serializer.save()
+        check_config_perm(self.request.user, 'change', obj)
+
+        self.perform_create(serializer)
+        headers = self.get_success_headers(serializer.data)
+        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
+
+    def update(self, request, *args, **kwargs):
+        partial = kwargs.pop('partial', False)
+        instance = self.get_object()
+
+        check_config_perm(self.request.user, 'change', instance.object)
+
+        serializer = self.get_serializer(instance, data=request.data, partial=partial)
+        serializer.is_valid(raise_exception=True)
+        self.perform_update(serializer)
+
+        if getattr(instance, '_prefetched_objects_cache', None):
+            # If 'prefetch_related' has been applied to a queryset, we need to
+            # forcibly invalidate the prefetch cache on the instance.
+            # pylint: disable=protected-access
+            instance._prefetched_objects_cache = {}
+
+        return Response(serializer.data)
+
+    def destroy(self, request, *args, **kwargs):
+        instance = self.get_object()
+        check_config_perm(self.request.user, 'change', instance.object)
+        self.perform_destroy(instance)
+        return Response(status=status.HTTP_204_NO_CONTENT)
 
     def get_serializer_context(self):
         context = super().get_serializer_context()
@@ -201,6 +227,5 @@ def get_serializer_context(self):
             return context
         if self.kwargs:
             group_config = self.get_object()
-            self.check_config_perm('view', group_config.object)
             context.update({'group_config': group_config})
         return context
diff --git a/python/api/host/serializers.py b/python/api/host/serializers.py
index a4ba5baf29..8bd05c9098 100644
--- a/python/api/host/serializers.py
+++ b/python/api/host/serializers.py
@@ -13,14 +13,16 @@
 from django.db import IntegrityError
 from rest_framework import serializers
 
-import cm
 from api.action.serializers import ActionShort
-from api.api_views import hlink, check_obj, filter_actions, CommonAPIURL, ObjectURL
 from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer
 from api.serializers import StringListSerializer
+from api.utils import hlink, check_obj, filter_actions, CommonAPIURL, ObjectURL
 from cm.adcm_config import get_main_info
+from cm.api import add_host
 from cm.errors import AdcmEx
 from cm.models import HostProvider, Prototype, Action
+from cm.stack import validate_name
+from cm.status_api import get_host_status
 
 
 class HostSerializer(serializers.Serializer):
@@ -40,11 +42,11 @@ def validate_provider_id(self, provider_id):
         return check_obj(HostProvider, provider_id)
 
     def validate_fqdn(self, name):
-        return cm.stack.validate_name(name, 'Host name')
+        return validate_name(name, 'Host name')
 
     def create(self, validated_data):
         try:
-            return cm.api.add_host(
+            return add_host(
                 validated_data.get('prototype_id'),
                 validated_data.get('provider_id'),
                 validated_data.get('fqdn'),
@@ -65,7 +67,7 @@ class HostDetailSerializer(HostSerializer):
     locked = serializers.BooleanField(read_only=True)
 
     def get_status(self, obj):
-        return cm.status_api.get_host_status(obj)
+        return get_host_status(obj)
 
 
 class ClusterHostSerializer(HostSerializer):
@@ -83,7 +85,7 @@ def create(self, validated_data):
         provider = check_obj(HostProvider, self.context.get('provider_id'))
         proto = Prototype.obj.get(bundle=provider.prototype.bundle, type='host')
         try:
-            return cm.api.add_host(
+            return add_host(
                 proto, provider, validated_data.get('fqdn'), validated_data.get('description', '')
             )
         except IntegrityError:
@@ -96,7 +98,7 @@ class StatusSerializer(serializers.Serializer):
     status = serializers.SerializerMethodField()
 
     def get_status(self, obj):
-        return cm.status_api.get_host_status(obj)
+        return get_host_status(obj)
 
 
 class HostUISerializer(HostDetailSerializer):
diff --git a/python/api/host/views.py b/python/api/host/views.py
index 055993e2a3..3de39af3cd 100644
--- a/python/api/host/views.py
+++ b/python/api/host/views.py
@@ -11,17 +11,15 @@
 # limitations under the License.
 
 from django_filters import rest_framework as drf_filters
-from rest_framework import status
-from rest_framework.generics import GenericAPIView
-from rest_framework.permissions import IsAuthenticated
+from guardian.mixins import PermissionListMixin
+from guardian.shortcuts import get_objects_for_user
+from rest_framework import status, permissions
 from rest_framework.response import Response
 
-from api.api_views import (
+from api.base_view import GenericUIView, PaginatedView, DetailView
+from api.utils import (
     create,
-    check_obj,
-    PageView,
-    DetailViewRO,
-    InterfaceView,
+    get_object_for_user,
     check_custom_perm,
 )
 from cm.api import remove_host_from_cluster, delete_host, add_host_to_cluster
@@ -36,6 +34,7 @@
     HostComponent,
 )
 from cm.status_api import make_ui_host_status
+from rbac.viewsets import DjangoOnlyObjectPermissions
 from . import serializers
 
 
@@ -82,7 +81,19 @@ class Meta:
         ]
 
 
-class HostList(PageView):
+def get_host_queryset(queryset, user, kwargs):
+    if 'cluster_id' in kwargs:
+        cluster = get_object_for_user(user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id'])
+        queryset = queryset.filter(cluster=cluster)
+    if 'provider_id' in kwargs:
+        provider = get_object_for_user(
+            user, 'cm.view_hostprovider', HostProvider, id=kwargs['provider_id']
+        )
+        queryset = queryset.filter(provider=provider)
+    return queryset
+
+
+class HostList(PermissionListMixin, PaginatedView):
     """
     get:
     List all hosts
@@ -94,8 +105,7 @@ class HostList(PageView):
     queryset = Host.objects.all()
     serializer_class = serializers.HostSerializer
     serializer_class_ui = serializers.HostUISerializer
-    permission_classes = (IsAuthenticated,)
-    check_host_perm = check_custom_perm
+    permission_required = ['cm.view_host']
     filterset_class = HostFilter
     filterset_fields = (
         'cluster_id',
@@ -118,18 +128,10 @@ class HostList(PageView):
         'prototype__version_order',
     )
 
-    def get(self, request, *args, **kwargs):
-        """
-        List all hosts
-        """
-        queryset = self.get_queryset()
-        if 'cluster_id' in kwargs:  # List cluster hosts
-            cluster = check_obj(Cluster, kwargs['cluster_id'])
-            queryset = self.get_queryset().filter(cluster=cluster)
-        if 'provider_id' in kwargs:  # List provider hosts
-            provider = check_obj(HostProvider, kwargs['provider_id'])
-            queryset = self.get_queryset().filter(provider=provider)
-        return self.get_page(self.filter_queryset(queryset), request)
+    def get_queryset(self, *args, **kwargs):
+        queryset = super().get_queryset(*args, **kwargs)
+        queryset = get_host_queryset(queryset, self.request.user, self.kwargs)
+        return get_objects_for_user(**self.get_get_objects_for_user_kwargs(queryset))
 
     def post(self, request, *args, **kwargs):
         """
@@ -145,12 +147,15 @@ def post(self, request, *args, **kwargs):
         )
         if serializer.is_valid():
             if 'provider_id' in kwargs:  # List provider hosts
-                provider = check_obj(HostProvider, kwargs['provider_id'])
+                provider = get_object_for_user(
+                    request.user, 'cm.view_hostprovider', HostProvider, id=kwargs['provider_id']
+                )
             else:
-                provider = serializer.validated_data.get(
-                    'provider_id',
+                provider = serializer.validated_data.get('provider_id')
+                provider = get_object_for_user(
+                    request.user, 'cm.view_hostprovider', HostProvider, id=provider.id
                 )
-            self.check_host_perm('add_host_to', 'hostprovider', provider)
+            check_custom_perm(request.user, 'add_host_to', 'hostprovider', provider)
             return create(serializer)
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
@@ -161,17 +166,19 @@ class HostListProvider(HostList):
 
 class HostListCluster(HostList):
     serializer_class = serializers.ClusterHostSerializer
-    permission_classes = (IsAuthenticated,)
-    check_host_perm = check_custom_perm
 
     def post(self, request, *args, **kwargs):
         serializer = self.get_serializer(data=request.data)
         if serializer.is_valid(raise_exception=True):
             validated_data = serializer.validated_data
             if 'cluster_id' in kwargs:
-                cluster = check_obj(Cluster, kwargs['cluster_id'])
-            host = check_obj(Host, validated_data.get('id'))
-            self.check_host_perm('map_host_to', 'cluster', cluster)
+                cluster = get_object_for_user(
+                    request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+                )
+            host = get_object_for_user(
+                request.user, 'cm.view_host', Host, id=validated_data.get('id')
+            )
+            check_custom_perm(request.user, 'map_host_to', 'cluster', cluster)
             add_host_to_cluster(cluster, host)
             return Response(self.get_serializer(host).data, status=status.HTTP_201_CREATED)
         else:
@@ -184,7 +191,7 @@ def check_host(host, cluster):
         raise AdcmEx('FOREIGN_HOST', msg)
 
 
-class HostDetail(DetailViewRO):
+class HostDetail(PermissionListMixin, DetailView):
     """
     get:
     Show host
@@ -193,52 +200,67 @@ class HostDetail(DetailViewRO):
     queryset = Host.objects.all()
     serializer_class = serializers.HostDetailSerializer
     serializer_class_ui = serializers.HostUISerializer
-    permission_classes = (IsAuthenticated,)
-    check_host_perm = check_custom_perm
+    permission_classes = (DjangoOnlyObjectPermissions,)
+    permission_required = ['cm.view_host']
     lookup_field = 'id'
     lookup_url_kwarg = 'host_id'
     error_code = 'HOST_NOT_FOUND'
 
-    def get(self, request, host_id, **kwargs):  # pylint: disable=arguments-differ)
-        host = check_obj(Host, host_id)
-        if 'cluster_id' in kwargs:
-            cluster = check_obj(Cluster, kwargs['cluster_id'])
-            check_host(host, cluster)
-        serial_class = self.select_serializer(request)
-        serializer = serial_class(host, context={'request': request})
-        return Response(serializer.data)
+    def get_queryset(self, *args, **kwargs):
+        queryset = super().get_queryset(*args, **kwargs)
+        queryset = get_host_queryset(queryset, self.request.user, self.kwargs)
+        return get_objects_for_user(**self.get_get_objects_for_user_kwargs(queryset))
 
-    def delete(self, request, host_id, **kwargs):  # pylint: disable=arguments-differ
+    def delete(self, request, *args, **kwargs):
         """
         Delete host
         """
-        host = check_obj(Host, host_id, 'HOST_NOT_FOUND')
+        host = self.get_object()
         if 'cluster_id' in kwargs:
             # Remove host from cluster
-            cluster = check_obj(Cluster, kwargs['cluster_id'])
+            cluster = get_object_for_user(
+                request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+            )
             check_host(host, cluster)
-            self.check_host_perm('unmap_host_from', 'cluster', cluster)
+            check_custom_perm(request.user, 'unmap_host_from', 'cluster', cluster)
             remove_host_from_cluster(host)
         else:
             # Delete host (and all corresponding host services:components)
-            self.check_host_perm('delete', 'host', host)
+            check_custom_perm(request.user, 'remove', 'host', host)
             delete_host(host)
         return Response(status=status.HTTP_204_NO_CONTENT)
 
 
-class StatusList(GenericAPIView, InterfaceView):
-    serializer_class = serializers.StatusSerializer
-    model_name = Host
+class StatusList(GenericUIView):
     queryset = HostComponent.objects.all()
+    permission_classes = (permissions.IsAuthenticated,)
+    serializer_class = serializers.StatusSerializer
 
-    def get(self, request, host_id, cluster_id=None):
+    def get(self, request, *args, **kwargs):
         """
         Show all components in a specified host
         """
-        host = check_obj(Host, host_id)
-        if self.for_ui(request):
+        cluster = None
+        host = get_object_for_user(request.user, 'cm.view_host', Host, id=kwargs['host_id'])
+        if 'cluster_id' in kwargs:
+            cluster = get_object_for_user(
+                request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+            )
+        if 'provider_id' in kwargs:
+            provider = get_object_for_user(
+                request.user, 'cm.view_hostprovider', HostProvider, id=kwargs['provider_id']
+            )
+            host = get_object_for_user(
+                request.user,
+                'cm.view_host',
+                Host.objects.filter(provider=provider),
+                id=kwargs['host_id'],
+            )
+        if self._is_for_ui():
             host_components = self.get_queryset().filter(host=host)
+            if cluster is not None:
+                host_components = self.get_queryset().filter(host=host, cluster=cluster)
             return Response(make_ui_host_status(host, host_components))
         else:
-            serializer = self.serializer_class(host, context={'request': request})
+            serializer = self.get_serializer(host)
             return Response(serializer.data)
diff --git a/python/api/job/serializers.py b/python/api/job/serializers.py
index 13cd2d68b9..b2626e86d9 100644
--- a/python/api/job/serializers.py
+++ b/python/api/job/serializers.py
@@ -23,7 +23,7 @@
 from cm.ansible_plugin import get_check_log
 from cm.errors import AdcmEx
 from cm.models import JobLog, Host, ClusterObject, ServiceComponent, get_object_cluster
-from api.api_views import hlink
+from api.utils import hlink
 from api.concern.serializers import ConcernItemSerializer
 
 
diff --git a/python/api/job/views.py b/python/api/job/views.py
index ce01c23510..66b5ba58b1 100644
--- a/python/api/job/views.py
+++ b/python/api/job/views.py
@@ -14,20 +14,22 @@
 import re
 
 from django.http import HttpResponse
-from rest_framework import status
-from rest_framework.generics import GenericAPIView
+from guardian.mixins import PermissionListMixin
+from rest_framework import status, permissions
 from rest_framework.response import Response
 from rest_framework.reverse import reverse
 
-from api.api_views import DetailViewRO, check_obj, PageView
+from api.base_view import GenericUIView, DetailView, PaginatedView
+from api.utils import get_object_for_user, check_custom_perm
 from cm import config
 from cm.errors import AdcmEx
 from cm.job import get_log, restart_task, cancel_task
 from cm.models import JobLog, TaskLog, LogStorage
+from rbac.viewsets import DjangoOnlyObjectPermissions
 from . import serializers
 
 
-class JobList(PageView):
+class JobList(PermissionListMixin, PaginatedView):
     """
     get:
     List all jobs
@@ -38,18 +40,22 @@ class JobList(PageView):
     serializer_class_ui = serializers.JobSerializer
     filterset_fields = ('action_id', 'task_id', 'pid', 'status', 'start_date', 'finish_date')
     ordering_fields = ('status', 'start_date', 'finish_date')
+    permission_classes = (permissions.DjangoModelPermissions,)
+    permission_required = ['cm.view_joblog']
 
 
-class JobDetail(GenericAPIView):
+class JobDetail(PermissionListMixin, GenericUIView):
     queryset = JobLog.objects.all()
+    permission_classes = (DjangoOnlyObjectPermissions,)
+    permission_required = ['cm.view_joblog']
     serializer_class = serializers.JobSerializer
 
-    def get(self, request, job_id):
+    def get(self, request, *args, **kwargs):
         """
         Show job
         """
-        job = check_obj(JobLog, job_id, 'JOB_NOT_FOUND')
-        job.log_dir = os.path.join(config.RUN_DIR, f'{job_id}')
+        job = get_object_for_user(request.user, 'cm.view_joblog', JobLog, id=kwargs['job_id'])
+        job.log_dir = os.path.join(config.RUN_DIR, f'{job.id}')
         logs = get_log(job)
         for lg in logs:
             log_id = lg['id']
@@ -61,33 +67,40 @@ def get(self, request, job_id):
             )
 
         job.log_files = logs
-        serializer = self.serializer_class(job, data=request.data, context={'request': request})
+        serializer = self.get_serializer(job, data=request.data)
         serializer.is_valid()
         return Response(serializer.data)
 
 
-class LogStorageListView(PageView):
+class LogStorageListView(PermissionListMixin, PaginatedView):
     queryset = LogStorage.objects.all()
+    permission_required = ['cm.view_logstorage']
     serializer_class = serializers.LogStorageListSerializer
     filterset_fields = ('name', 'type', 'format')
     ordering_fields = ('id', 'name')
 
-    def get(self, request, job_id):  # pylint: disable=arguments-differ
-        obj = self.filter_queryset(LogStorage.objects.filter(job_id=job_id))
-        return self.get_page(obj, request)
+    def get_queryset(self, *args, **kwargs):
+        queryset = super().get_queryset(*args, **kwargs)
+        if 'job_id' not in self.kwargs:
+            return queryset
+        return queryset.filter(job_id=self.kwargs['job_id'])
 
 
-class LogStorageView(GenericAPIView):
+class LogStorageView(PermissionListMixin, GenericUIView):
     queryset = LogStorage.objects.all()
+    permission_classes = (permissions.IsAuthenticated,)
+    permission_required = ['cm.view_logstorage']
     serializer_class = serializers.LogStorageSerializer
 
-    def get(self, request, job_id, log_id):
-        job = JobLog.obj.get(id=job_id)
+    def get(self, request, *args, **kwargs):
+        job = get_object_for_user(request.user, 'cm.view_joblog', JobLog, id=kwargs['job_id'])
         try:
-            log_storage = LogStorage.objects.get(id=log_id, job=job)
+            log_storage = self.get_queryset().get(id=kwargs['log_id'], job=job)
         except LogStorage.DoesNotExist:
-            raise AdcmEx('LOG_NOT_FOUND', f'log {log_id} not found for job {job_id}') from None
-        serializer = self.serializer_class(log_storage, context={'request': request})
+            raise AdcmEx(
+                'LOG_NOT_FOUND', f'log {kwargs["log_id"]} not found for job {kwargs["job_id"]}'
+            ) from None
+        serializer = self.get_serializer(log_storage)
         return Response(serializer.data)
 
 
@@ -120,7 +133,8 @@ def download_log_file(request, job_id, log_id):
     return response
 
 
-class LogFile(GenericAPIView):
+class LogFile(GenericUIView):
+    permission_classes = (permissions.IsAuthenticated,)
     queryset = LogStorage.objects.all()
     serializer_class = serializers.LogSerializer
 
@@ -135,51 +149,57 @@ def get(self, request, job_id, tag, level, log_type):
             tag = 'ansible'
 
         ls = LogStorage.obj.get(job_id=job_id, name=tag, type=_type, format=log_type)
-        serializer = self.serializer_class(ls, context={'request': request})
+        serializer = self.get_serializer(ls)
         return Response(serializer.data)
 
 
-class Task(PageView):
+class Task(PermissionListMixin, PaginatedView):
     """
     get:
     List all tasks
     """
 
     queryset = TaskLog.objects.order_by('-id')
+    permission_required = ['cm.view_tasklog']
     serializer_class = serializers.TaskListSerializer
     serializer_class_ui = serializers.TaskSerializer
     filterset_fields = ('action_id', 'pid', 'status', 'start_date', 'finish_date')
     ordering_fields = ('status', 'start_date', 'finish_date')
 
 
-class TaskDetail(DetailViewRO):
+class TaskDetail(PermissionListMixin, DetailView):
     """
     get:
     Show task
     """
 
     queryset = TaskLog.objects.all()
+    permission_required = ['cm.view_tasklog']
     serializer_class = serializers.TaskSerializer
     lookup_field = 'id'
     lookup_url_kwarg = 'task_id'
     error_code = 'TASK_NOT_FOUND'
 
 
-class TaskReStart(GenericAPIView):
+class TaskReStart(GenericUIView):
     queryset = TaskLog.objects.all()
+    permission_classes = (permissions.IsAuthenticated,)
     serializer_class = serializers.TaskSerializer
 
-    def put(self, request, task_id):
-        task = check_obj(TaskLog, task_id, 'TASK_NOT_FOUND')
+    def put(self, request, *args, **kwargs):
+        task = get_object_for_user(request.user, 'cm.view_tasklog', TaskLog, id=kwargs['task_id'])
+        check_custom_perm(request.user, 'change', TaskLog, task)
         restart_task(task)
         return Response(status=status.HTTP_200_OK)
 
 
-class TaskCancel(GenericAPIView):
+class TaskCancel(GenericUIView):
     queryset = TaskLog.objects.all()
+    permission_classes = (permissions.IsAuthenticated,)
     serializer_class = serializers.TaskSerializer
 
-    def put(self, request, task_id):
-        task = check_obj(TaskLog, task_id, 'TASK_NOT_FOUND')
+    def put(self, request, *args, **kwargs):
+        task = get_object_for_user(request.user, 'cm.view_tasklog', TaskLog, id=kwargs['task_id'])
+        check_custom_perm(request.user, 'change', TaskLog, task)
         cancel_task(task)
         return Response(status=status.HTTP_200_OK)
diff --git a/python/api/object_config/views.py b/python/api/object_config/views.py
index ad58097183..c09b37d1fe 100644
--- a/python/api/object_config/views.py
+++ b/python/api/object_config/views.py
@@ -10,15 +10,26 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from guardian.mixins import PermissionListMixin
+from rest_framework.permissions import DjangoObjectPermissions
 from rest_framework.viewsets import ReadOnlyModelViewSet
 
 from cm.models import ObjectConfig
 from .serializers import ObjectConfigSerializer
 
-from rbac.viewsets import DjangoObjectPerm
 
-
-class ObjectConfigViewSet(ReadOnlyModelViewSet):  # pylint: disable=too-many-ancestors
+class ObjectConfigViewSet(
+    PermissionListMixin, ReadOnlyModelViewSet
+):  # pylint: disable=too-many-ancestors
     queryset = ObjectConfig.objects.all()
     serializer_class = ObjectConfigSerializer
-    permission_classes = (DjangoObjectPerm,)
+    permission_classes = (DjangoObjectPermissions,)
+    permission_required = ['cm.view_objectconfig']
+
+    def get_queryset(self, *args, **kwargs):
+        if self.request.user.has_perm('cm.view_settings_of_adcm'):
+            return super().get_queryset(*args, **kwargs) | ObjectConfig.objects.filter(
+                adcm__isnull=False
+            )
+        else:
+            return super().get_queryset(*args, **kwargs).filter(adcm__isnull=True)
diff --git a/python/api/provider/serializers.py b/python/api/provider/serializers.py
index ee7c1df556..ddecb1dc40 100644
--- a/python/api/provider/serializers.py
+++ b/python/api/provider/serializers.py
@@ -15,7 +15,7 @@
 
 import cm
 from api.action.serializers import ActionShort
-from api.api_views import (
+from api.utils import (
     hlink,
     check_obj,
     filter_actions,
diff --git a/python/api/provider/views.py b/python/api/provider/views.py
index 21343f8c68..74b869817f 100644
--- a/python/api/provider/views.py
+++ b/python/api/provider/views.py
@@ -10,19 +10,28 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from guardian.mixins import PermissionListMixin
 from rest_framework import status, permissions
 from rest_framework.response import Response
 
-import cm
-from cm.models import HostProvider, Upgrade
-
-from api.api_views import create, check_obj, ListView, PageView, PageViewAdd, DetailViewRO
-from api.api_views import GenericAPIPermView, check_custom_perm
 import api.serializers
+from api.base_view import GenericUIView, DetailView, PaginatedView
+from api.utils import (
+    create,
+    check_obj,
+    check_custom_perm,
+    AdcmFilterBackend,
+    AdcmOrderingFilter,
+    get_object_for_user,
+)
+from cm.api import delete_host_provider
+from cm.models import HostProvider, Upgrade
+from cm.upgrade import get_upgrade
 from . import serializers
+from rbac.viewsets import DjangoOnlyObjectPermissions
 
 
-class ProviderList(PageViewAdd):
+class ProviderList(PermissionListMixin, PaginatedView):
     """
     get:
     List all host providers
@@ -37,9 +46,14 @@ class ProviderList(PageViewAdd):
     serializer_class_post = serializers.ProviderDetailSerializer
     filterset_fields = ('name', 'prototype_id')
     ordering_fields = ('name', 'state', 'prototype__display_name', 'prototype__version_order')
+    permission_required = ['cm.view_hostprovider']
 
+    def post(self, request, *args, **kwargs):
+        serializer = self.get_serializer(data=request.data)
+        return create(serializer)
 
-class ProviderDetail(DetailViewRO):
+
+class ProviderDetail(PermissionListMixin, DetailView):
     """
     get:
     Show host provider
@@ -48,68 +62,80 @@ class ProviderDetail(DetailViewRO):
     queryset = HostProvider.objects.all()
     serializer_class = serializers.ProviderDetailSerializer
     serializer_class_ui = serializers.ProviderUISerializer
+    permission_classes = (DjangoOnlyObjectPermissions,)
+    permission_required = ['cm.view_hostprovider']
     lookup_field = 'id'
     lookup_url_kwarg = 'provider_id'
     error_code = 'PROVIDER_NOT_FOUND'
 
-    def delete(self, request, provider_id):  # pylint: disable=arguments-differ
+    def delete(self, request, *args, **kwargs):
         """
         Remove host provider
         """
-        provider = check_obj(HostProvider, provider_id, 'PROVIDER_NOT_FOUND')
-        cm.api.delete_host_provider(provider)
+        provider = self.get_object()
+        delete_host_provider(provider)
         return Response(status=status.HTTP_204_NO_CONTENT)
 
 
-class ProviderUpgrade(PageView):
+class ProviderUpgrade(GenericUIView):
     queryset = Upgrade.objects.all()
     serializer_class = serializers.UpgradeProviderSerializer
-    check_upgrade_perm = check_custom_perm
     permission_classes = (permissions.IsAuthenticated,)
+    filter_backends = (AdcmFilterBackend, AdcmOrderingFilter)
+
+    def get_ordering(self):
+        order = AdcmOrderingFilter()
+        return order.get_ordering(self.request, self.get_queryset(), self)
 
-    def get(self, request, provider_id):  # pylint: disable=arguments-differ
+    def get(self, request, *args, **kwargs):
         """
         List all avaliable upgrades for specified host provider
         """
-        provider = check_obj(HostProvider, provider_id, 'PROVIDER_NOT_FOUND')
-        self.check_upgrade_perm('view_upgrade_of', 'hostprovider', provider)
-        obj = cm.upgrade.get_upgrade(provider, self.get_ordering(request, self.queryset, self))
+        provider = get_object_for_user(
+            request.user, 'cm.view_hostprovider', HostProvider, id=kwargs['provider_id']
+        )
+        check_custom_perm(request.user, 'view_upgrade_of', 'hostprovider', provider)
+        obj = get_upgrade(provider, self.get_ordering())
         serializer = self.serializer_class(
             obj, many=True, context={'provider_id': provider.id, 'request': request}
         )
         return Response(serializer.data)
 
 
-class ProviderUpgradeDetail(ListView):
+class ProviderUpgradeDetail(GenericUIView):
     queryset = Upgrade.objects.all()
     serializer_class = serializers.UpgradeProviderSerializer
-    check_upgrade_perm = check_custom_perm
     permission_classes = (permissions.IsAuthenticated,)
 
-    def get(self, request, provider_id, upgrade_id):  # pylint: disable=arguments-differ
+    def get(self, request, *args, **kwargs):
         """
         List all avaliable upgrades for specified host provider
         """
-        provider = check_obj(HostProvider, provider_id, 'PROVIDER_NOT_FOUND')
-        self.check_upgrade_perm('view_upgrade_of', 'hostprovider', provider)
-        obj = self.get_queryset().get(id=upgrade_id)
+        provider = get_object_for_user(
+            request.user, 'cm.view_hostprovider', HostProvider, id=kwargs['provider_id']
+        )
+        check_custom_perm(request.user, 'view_upgrade_of', 'hostprovider', provider)
+        obj = check_obj(
+            Upgrade, {'id': kwargs['upgrade_id'], 'bundle__name': provider.prototype.bundle.name}
+        )
         serializer = self.serializer_class(
             obj, context={'provider_id': provider.id, 'request': request}
         )
         return Response(serializer.data)
 
 
-class DoProviderUpgrade(GenericAPIPermView):
+class DoProviderUpgrade(GenericUIView):
     queryset = Upgrade.objects.all()
     serializer_class = api.serializers.DoUpgradeSerializer
-    check_upgrade_perm = check_custom_perm
     permission_classes = (permissions.IsAuthenticated,)
 
-    def post(self, request, provider_id, upgrade_id):
+    def post(self, request, *args, **kwargs):
         """
         Do upgrade specified host provider
         """
-        provider = check_obj(HostProvider, provider_id, 'PROVIDER_NOT_FOUND')
-        self.check_upgrade_perm('do_upgrade_of', 'hostprovider', provider)
-        serializer = self.serializer_class(data=request.data, context={'request': request})
-        return create(serializer, upgrade_id=int(upgrade_id), obj=provider)
+        provider = get_object_for_user(
+            request.user, 'cm.view_hostprovider', HostProvider, id=kwargs['provider_id']
+        )
+        check_custom_perm(request.user, 'do_upgrade_of', 'hostprovider', provider)
+        serializer = self.get_serializer(data=request.data)
+        return create(serializer, upgrade_id=int(kwargs['upgrade_id']), obj=provider)
diff --git a/python/api/serializers.py b/python/api/serializers.py
index ad852efabf..991c4bcfaa 100644
--- a/python/api/serializers.py
+++ b/python/api/serializers.py
@@ -14,17 +14,13 @@
 from rest_framework.reverse import reverse
 from rest_framework_extensions.settings import extensions_api_settings
 
-from api.api_views import check_obj, hlink, UrlField
+from api.utils import check_obj, hlink, UrlField
 from cm.adcm_config import ui_config
 from cm.errors import raise_AdcmEx
 from cm.models import Upgrade, GroupConfig
 from cm.upgrade import do_upgrade
 
 
-class EmptySerializer(serializers.Serializer):
-    id = serializers.IntegerField(read_only=True)
-
-
 class UpgradeSerializer(serializers.Serializer):
     id = serializers.IntegerField(read_only=True)
     name = serializers.CharField(required=False)
diff --git a/python/api/service/serializers.py b/python/api/service/serializers.py
index 5cbc6a509c..a45adb1755 100644
--- a/python/api/service/serializers.py
+++ b/python/api/service/serializers.py
@@ -17,7 +17,7 @@
 from rest_framework.reverse import reverse
 
 from api.action.serializers import ActionShort
-from api.api_views import check_obj, filter_actions, CommonAPIURL, ObjectURL
+from api.utils import check_obj, filter_actions, CommonAPIURL, ObjectURL
 from api.cluster.serializers import BindSerializer
 from api.component.serializers import ComponentUISerializer
 from api.concern.serializers import ConcernItemSerializer, ConcernItemUISerializer
diff --git a/python/api/service/views.py b/python/api/service/views.py
index 04ee91ff51..fc7b987247 100644
--- a/python/api/service/views.py
+++ b/python/api/service/views.py
@@ -10,40 +10,38 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from guardian.mixins import PermissionListMixin
 from rest_framework import status, permissions
-from rest_framework.generics import GenericAPIView
 from rest_framework.response import Response
 
 import cm.status_api
-from api.api_views import (
-    PageView,
+from api.base_view import GenericUIView, PaginatedView, DetailView
+from api.cluster.serializers import BindSerializer
+from api.stack.serializers import ImportSerializer
+from api.utils import (
     create,
     check_obj,
     check_custom_perm,
-    DetailViewRO,
-    ListView,
-    InterfaceView,
+    get_object_for_user,
 )
-from api.stack.serializers import ImportSerializer
-from api.cluster.serializers import BindSerializer
-
 from cm.api import delete_service, get_import, unbind
 from cm.models import Cluster, ClusterObject, Prototype, ClusterBind, HostComponent
-
+from rbac.viewsets import DjangoOnlyObjectPermissions
 from . import serializers
 
 
-def check_service(kwargs):
-    service = check_obj(ClusterObject, kwargs['service_id'])
+def check_service(user, kwargs):
+    service = get_object_for_user(
+        user, 'cm.view_clusterobject', ClusterObject, id=kwargs['service_id']
+    )
     if 'cluster_id' in kwargs:
-        check_obj(Cluster, kwargs['cluster_id'])
+        get_object_for_user(user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id'])
     return service
 
 
-class ServiceListView(PageView):
+class ServiceListView(PermissionListMixin, PaginatedView):
     queryset = ClusterObject.objects.all()
-    permission_classes = (permissions.IsAuthenticated,)
-    check_service_perm = check_custom_perm
+    permission_required = ['cm.view_clusterobject']
     serializer_class = serializers.ServiceSerializer
     serializer_class_ui = serializers.ServiceUISerializer
     serializer_class_cluster = serializers.ClusterServiceSerializer
@@ -56,8 +54,10 @@ def get(self, request, *args, **kwargs):
         """
         queryset = self.get_queryset()
         if 'cluster_id' in kwargs:
-            cluster = check_obj(Cluster, kwargs['cluster_id'])
-            queryset = self.get_queryset().filter(cluster=cluster)
+            cluster = get_object_for_user(
+                request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+            )
+            queryset = queryset.filter(cluster=cluster)
         return self.get_page(self.filter_queryset(queryset), request)
 
     def post(self, request, *args, **kwargs):
@@ -67,10 +67,14 @@ def post(self, request, *args, **kwargs):
         serializer_class = self.serializer_class
         if 'cluster_id' in kwargs:
             serializer_class = self.serializer_class_cluster
-            cluster = check_obj(Cluster, kwargs['cluster_id'])
+            cluster = get_object_for_user(
+                request.user, 'cm.view_cluster', Cluster, id=kwargs['cluster_id']
+            )
         else:
-            cluster = check_obj(Cluster, request.data['cluster_id'])
-        self.check_service_perm('add_service_to', 'cluster', cluster)
+            cluster = get_object_for_user(
+                request.user, 'cm.view_cluster', Cluster, id=request.data['cluster_id']
+            )
+        check_custom_perm(request.user, 'add_service_to', 'cluster', cluster)
         serializer = serializer_class(
             data=request.data,
             context={'request': request, 'cluster_id': kwargs.get('cluster_id', None)},
@@ -78,50 +82,55 @@ def post(self, request, *args, **kwargs):
         return create(serializer)
 
 
-class ServiceDetailView(DetailViewRO):
+class ServiceDetailView(PermissionListMixin, DetailView):
     queryset = ClusterObject.objects.all()
     serializer_class = serializers.ServiceDetailSerializer
     serializer_class_ui = serializers.ServiceUISerializer
-
-    def get(self, request, *args, **kwargs):
-        """
-        Show service
-        """
-        service = check_service(kwargs)
-        serial_class = self.select_serializer(request)
-        serializer = serial_class(service, context={'request': request})
-        return Response(serializer.data)
+    permission_classes = (DjangoOnlyObjectPermissions,)
+    lookup_url_kwarg = 'service_id'
+    permission_required = ['cm.view_clusterobject']
+    error_code = ClusterObject.__error_code__
+
+    def get_queryset(self, *args, **kwargs):
+        queryset = super().get_queryset(*args, **kwargs)
+        if 'cluster_id' in self.kwargs:
+            cluster = get_object_for_user(
+                self.request.user, 'cm.view_cluster', Cluster, id=self.kwargs['cluster_id']
+            )
+            queryset = queryset.filter(cluster=cluster)
+        return queryset
 
     def delete(self, request, *args, **kwargs):
         """
         Remove service from cluster
         """
-        service = check_service(kwargs)
-        delete_service(service)
+        instance = self.get_object()
+        delete_service(instance)
         return Response(status=status.HTTP_204_NO_CONTENT)
 
 
-class ServiceImportView(ListView):
+class ServiceImportView(GenericUIView):
     queryset = Prototype.objects.all()
     serializer_class = ImportSerializer
-    post_serializer_class = serializers.ImportPostSerializer
-    check_import_perm = check_custom_perm
+    serializer_class_post = serializers.ImportPostSerializer
     permission_classes = (permissions.IsAuthenticated,)
 
     def get(self, request, *args, **kwargs):
         """
         List all imports available for specified service
         """
-        service = check_service(kwargs)
-        self.check_import_perm('view_import_of', 'clusterobject', service, 'view_clusterbind')
+        service = check_service(request.user, kwargs)
+        check_custom_perm(
+            request.user, 'view_import_of', 'clusterobject', service, 'view_clusterbind'
+        )
         cluster = service.cluster
         return Response(get_import(cluster, service))
 
     def post(self, request, **kwargs):
-        service = check_service(kwargs)
-        self.check_import_perm('change_import_of', 'clusterobject', service)
+        service = check_service(request.user, kwargs)
+        check_custom_perm(request.user, 'change_import_of', 'clusterobject', service)
         cluster = service.cluster
-        serializer = self.post_serializer_class(
+        serializer = self.get_serializer(
             data=request.data, context={'request': request, 'cluster': cluster, 'service': service}
         )
         if serializer.is_valid():
@@ -129,47 +138,42 @@ def post(self, request, **kwargs):
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
 
-class ServiceBindView(ListView):
+class ServiceBindView(GenericUIView):
     queryset = ClusterBind.objects.all()
     serializer_class = serializers.ServiceBindSerializer
-    check_import_perm = check_custom_perm
+    serializer_class_post = serializers.ServiceBindPostSerializer
     permission_classes = (permissions.IsAuthenticated,)
 
-    def get_serializer_class(self):
-        if self.request and self.request.method == 'POST':
-            return serializers.ServiceBindPostSerializer
-        else:
-            return serializers.ServiceBindSerializer
-
     def get(self, request, *args, **kwargs):
         """
         List all binds of service
         """
-        service = check_service(kwargs)
-        self.check_import_perm('view_import_of', 'clusterobject', service, 'view_clusterbind')
+        service = check_service(request.user, kwargs)
+        check_custom_perm(
+            request.user, 'view_import_of', 'clusterobject', service, 'view_clusterbind'
+        )
         binds = self.get_queryset().filter(service=service)
-        serializer = self.get_serializer_class()(binds, many=True, context={'request': request})
+        serializer = self.get_serializer(binds, many=True)
         return Response(serializer.data)
 
     def post(self, request, **kwargs):
         """
         Bind two services
         """
-        service = check_service(kwargs)
-        self.check_import_perm('change_import_of', 'clusterobject', service)
+        service = check_service(request.user, kwargs)
+        check_custom_perm(request.user, 'change_import_of', 'clusterobject', service)
         cluster = service.cluster
-        serializer = self.get_serializer_class()(data=request.data, context={'request': request})
+        serializer = self.get_serializer(data=request.data)
         return create(serializer, cluster=cluster, service=service)
 
 
-class ServiceBindDetailView(DetailViewRO):
+class ServiceBindDetailView(GenericUIView):
     queryset = ClusterBind.objects.all()
     serializer_class = BindSerializer
-    check_import_perm = check_custom_perm
     permission_classes = (permissions.IsAuthenticated,)
 
     def get_obj(self, kwargs, bind_id):
-        service = check_service(kwargs)
+        service = check_service(self.request.user, kwargs)
         cluster = service.cluster
         return service, check_obj(ClusterBind, {'cluster': cluster, 'id': bind_id})
 
@@ -178,8 +182,10 @@ def get(self, request, *args, **kwargs):
         Show specified bind of service
         """
         service, bind = self.get_obj(kwargs, kwargs['bind_id'])
-        self.check_import_perm('view_import_of', 'clusterobject', service, 'view_clusterbind')
-        serializer = self.serializer_class(bind, context={'request': request})
+        check_custom_perm(
+            request.user, 'view_import_of', 'clusterobject', service, 'view_clusterbind'
+        )
+        serializer = self.get_serializer(bind)
         return Response(serializer.data)
 
     def delete(self, request, *args, **kwargs):
@@ -187,24 +193,24 @@ def delete(self, request, *args, **kwargs):
         Unbind specified bind of service
         """
         service, bind = self.get_obj(kwargs, kwargs['bind_id'])
-        self.check_import_perm('change_import_of', 'clusterobject', service)
+        check_custom_perm(request.user, 'change_import_of', 'clusterobject', service)
         unbind(bind)
         return Response(status=status.HTTP_204_NO_CONTENT)
 
 
-class StatusList(GenericAPIView, InterfaceView):
+class StatusList(GenericUIView):
+    permission_classes = (permissions.IsAuthenticated,)
     queryset = HostComponent.objects.all()
-    model_name = ClusterObject
     serializer_class = serializers.StatusSerializer
 
-    def get(self, request, service_id, cluster_id=None):
+    def get(self, request, *args, **kwargs):
         """
         Show all hosts and components in a specified cluster
         """
-        service = check_obj(ClusterObject, service_id)
-        if self.for_ui(request):
+        service = check_service(request.user, kwargs)
+        if self._is_for_ui():
             host_components = self.get_queryset().filter(service=service)
             return Response(cm.status_api.make_ui_service_status(service, host_components))
         else:
-            serializer = self.serializer_class(service, context={'request': request})
+            serializer = self.get_serializer(service)
             return Response(serializer.data)
diff --git a/python/api/stack/root.py b/python/api/stack/root.py
new file mode 100644
index 0000000000..f0b0d84417
--- /dev/null
+++ b/python/api/stack/root.py
@@ -0,0 +1,31 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Stack endpoint root view"""
+
+from rest_framework import permissions, routers
+
+
+class StackRoot(routers.APIRootView):
+    """Stack Root"""
+
+    permission_classes = (permissions.AllowAny,)
+    api_root_dict = {
+        'load': 'load-bundle',
+        'upload': 'upload-bundle',
+        'bundle': 'bundle',
+        'prototype': 'prototype',
+        'service': 'service-type',
+        'host': 'host-type',
+        'provider': 'provider-type',
+        'cluster': 'cluster-type',
+    }
diff --git a/python/api/stack/serializers.py b/python/api/stack/serializers.py
index 5e4ec4a1f7..4728c7fe36 100644
--- a/python/api/stack/serializers.py
+++ b/python/api/stack/serializers.py
@@ -12,26 +12,13 @@
 
 from rest_framework import serializers
 
-from cm.logger import log  # pylint: disable=unused-import
+from api.action.serializers import StackActionDetailSerializer
+from api.config.serializers import ConfigSerializer
+from api.serializers import UpgradeSerializer
+from api.utils import hlink
 from cm import config
 from cm.models import ClusterObject, Prototype, Bundle
 
-from api.api_views import hlink, UrlField
-from api.serializers import UpgradeSerializer
-from api.config.serializers import ConfigSerializer
-from api.action.serializers import StackActionDetailSerializer
-
-
-class Stack(serializers.Serializer):
-    load = UrlField(view_name='load-bundle')
-    upload = UrlField(view_name='upload-bundle')
-    bundle = UrlField(view_name='bundle')
-    prototype = UrlField(view_name='prototype')
-    service = UrlField(view_name='service-type')
-    host = UrlField(view_name='host-type')
-    provider = UrlField(view_name='provider-type')
-    cluster = UrlField(view_name='cluster-type')
-
 
 class LoadBundle(serializers.Serializer):
     bundle_file = serializers.CharField()
diff --git a/python/api/stack/urls.py b/python/api/stack/urls.py
index 93924bf880..1a42cb22fb 100644
--- a/python/api/stack/urls.py
+++ b/python/api/stack/urls.py
@@ -11,18 +11,20 @@
 # limitations under the License.
 
 from django.urls import path, include
-from . import views
 
+from . import views, root
 
 PROTOTYPE_ID = '<int:prototype_id>/'
 
 
 # fmt: off
 urlpatterns = [
-    path('', views.Stack.as_view(), name='stack'),
+    path('', root.StackRoot.as_view(), name='stack'),
     path('upload/', views.UploadBundle.as_view(), name='upload-bundle'),
-    path('load/', views.LoadBundle.as_view(), name='load-bundle'),
-    path('load/servicemap/', views.LoadServiceMap.as_view(), name='load-servicemap'),
+    path('load/', views.LoadBundle.as_view({'post': 'create'}), name='load-bundle'),
+    path(
+        'load/servicemap/', views.LoadBundle.as_view({'put': 'servicemap'}), name='load-servicemap'
+    ),
     path('bundle/', include([
         path('', views.BundleList.as_view(), name='bundle'),
         path('<int:bundle_id>/', include([
diff --git a/python/api/stack/views.py b/python/api/stack/views.py
index b750f03f9a..94764a5ccf 100644
--- a/python/api/stack/views.py
+++ b/python/api/stack/views.py
@@ -10,21 +10,29 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from rest_framework import decorators
 from rest_framework import status
-from rest_framework.reverse import reverse
-from rest_framework.response import Response
-from rest_framework.parsers import MultiPartParser
 from rest_framework.authentication import TokenAuthentication, SessionAuthentication
+from rest_framework.mixins import CreateModelMixin
+from rest_framework.parsers import MultiPartParser
+from rest_framework.permissions import IsAuthenticated
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
 
 import cm.api
 import cm.bundle
+from api.action.serializers import StackActionSerializer
+from api.base_view import (
+    GenericUIView,
+    DetailView,
+    PaginatedView,
+    GenericUIViewSet,
+    ModelPermOrReadOnlyForAuth,
+)
+from api.utils import check_obj
 from cm.models import Bundle, Prototype, Action
 from cm.models import PrototypeConfig, Upgrade, PrototypeExport
 from cm.models import PrototypeImport
-from cm.logger import log  # pylint: disable=unused-import
-
-from api.api_views import ListView, DetailViewRO, PageView, GenericAPIPermView, check_obj
-from api.action.serializers import StackActionSerializer
 from . import serializers
 
 
@@ -33,43 +41,35 @@ def enforce_csrf(self, request):
         return
 
 
-class Stack(GenericAPIPermView):
-    queryset = Prototype.objects.all()
-    serializer_class = serializers.Stack
-
-    def get(self, request):
-        """
-        Operations with stack of services
-        """
-        obj = Bundle()
-        serializer = self.serializer_class(obj, context={'request': request})
-        return Response(serializer.data)
-
-
-class UploadBundle(GenericAPIPermView):
+class UploadBundle(GenericUIView):
     queryset = Bundle.objects.all()
     serializer_class = serializers.UploadBundle
     authentication_classes = (CsrfOffSessionAuthentication, TokenAuthentication)
     parser_classes = (MultiPartParser,)
 
     def post(self, request):
-        serializer = self.serializer_class(data=request.data, context={'request': request})
+        serializer = self.get_serializer(data=request.data)
         if serializer.is_valid():
             serializer.save()
             return Response(status=status.HTTP_201_CREATED)
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
 
-class LoadBundle(GenericAPIPermView):
+class LoadBundle(CreateModelMixin, GenericUIViewSet):
     queryset = Prototype.objects.all()
     serializer_class = serializers.LoadBundle
 
-    def post(self, request):
+    @decorators.action(methods=['put'], detail=False)
+    def servicemap(self, request):
+        cm.api.load_service_map()
+        return Response(status=status.HTTP_200_OK)
+
+    def create(self, request, *args, **kwargs):
         """
         post:
         Load bundle
         """
-        serializer = self.serializer_class(data=request.data, context={'request': request})
+        serializer = self.get_serializer(data=request.data)
         if serializer.is_valid():
             bundle = cm.bundle.load_bundle(serializer.validated_data.get('bundle_file'))
             srl = serializers.BundleSerializer(bundle, context={'request': request})
@@ -78,7 +78,7 @@ def post(self, request):
             return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
 
-class BundleList(PageView):
+class BundleList(PaginatedView):
     """
     get:
     List all bundles
@@ -86,11 +86,12 @@ class BundleList(PageView):
 
     queryset = Bundle.objects.exclude(hash='adcm')
     serializer_class = serializers.BundleSerializer
+    permission_classes = (IsAuthenticated,)
     filterset_fields = ('name', 'version')
     ordering_fields = ('name', 'version_order')
 
 
-class BundleDetail(DetailViewRO):
+class BundleDetail(DetailView):
     """
     get:
     Show bundle
@@ -101,17 +102,18 @@ class BundleDetail(DetailViewRO):
 
     queryset = Bundle.objects.all()
     serializer_class = serializers.BundleSerializer
+    permission_classes = (ModelPermOrReadOnlyForAuth,)
     lookup_field = 'id'
     lookup_url_kwarg = 'bundle_id'
     error_code = 'BUNDLE_NOT_FOUND'
 
-    def delete(self, request, bundle_id):
-        bundle = check_obj(Bundle, bundle_id, 'BUNDLE_NOT_FOUND')
+    def delete(self, request, *args, **kwargs):
+        bundle = self.get_object()
         cm.bundle.delete_bundle(bundle)
         return Response(status=status.HTTP_204_NO_CONTENT)
 
 
-class BundleUpdate(GenericAPIPermView):
+class BundleUpdate(GenericUIView):
     queryset = Bundle.objects.all()
     serializer_class = serializers.BundleSerializer
 
@@ -121,14 +123,15 @@ def put(self, request, bundle_id):
         """
         bundle = check_obj(Bundle, bundle_id, 'BUNDLE_NOT_FOUND')
         cm.bundle.update_bundle(bundle)
-        serializer = self.serializer_class(bundle, context={'request': request})
+        serializer = self.get_serializer(bundle)
         return Response(serializer.data)
 
 
-class BundleLicense(GenericAPIPermView):
+class BundleLicense(GenericUIView):
     action = 'retrieve'
     queryset = Bundle.objects.all()
     serializer_class = serializers.LicenseSerializer
+    permission_classes = (IsAuthenticated,)
 
     def get(self, request, bundle_id):
         bundle = check_obj(Bundle, bundle_id, 'BUNDLE_NOT_FOUND')
@@ -137,7 +140,7 @@ def get(self, request, bundle_id):
         return Response({'license': bundle.license, 'accept': url, 'text': body})
 
 
-class AcceptLicense(GenericAPIPermView):
+class AcceptLicense(GenericUIView):
     queryset = Bundle.objects.all()
     serializer_class = serializers.LicenseSerializer
 
@@ -147,7 +150,7 @@ def put(self, request, bundle_id):
         return Response(status=status.HTTP_200_OK)
 
 
-class PrototypeList(PageView):
+class PrototypeList(PaginatedView):
     """
     get:
     List all stack prototypes
@@ -159,7 +162,7 @@ class PrototypeList(PageView):
     ordering_fields = ('display_name', 'version_order')
 
 
-class ServiceList(PageView):
+class ServiceList(PaginatedView):
     """
     get:
     List all stack services
@@ -171,7 +174,7 @@ class ServiceList(PageView):
     ordering_fields = ('display_name', 'version_order')
 
 
-class ServiceDetail(DetailViewRO):
+class ServiceDetail(DetailView):
     """
     get:
     Show stack service
@@ -195,7 +198,7 @@ def get_object(self):
         return service
 
 
-class ProtoActionDetail(GenericAPIPermView):
+class ProtoActionDetail(GenericUIView):
     queryset = Action.objects.all()
     serializer_class = StackActionSerializer
 
@@ -204,11 +207,11 @@ def get(self, request, action_id):
         Show action
         """
         obj = check_obj(Action, action_id, 'ACTION_NOT_FOUND')
-        serializer = self.serializer_class(obj, context={'request': request})
+        serializer = self.get_serializer(obj)
         return Response(serializer.data)
 
 
-class ServiceProtoActionList(GenericAPIPermView):
+class ServiceProtoActionList(GenericUIView):
     queryset = Action.objects.filter(prototype__type='service')
     serializer_class = StackActionSerializer
 
@@ -217,11 +220,11 @@ def get(self, request, prototype_id):
         List all actions of a specified service
         """
         obj = self.get_queryset().filter(prototype_id=prototype_id)
-        serializer = self.serializer_class(obj, many=True, context={'request': request})
+        serializer = self.get_serializer(obj, many=True)
         return Response(serializer.data)
 
 
-class ComponentList(PageView):
+class ComponentList(PaginatedView):
     """
     get:
     List all stack components
@@ -233,7 +236,7 @@ class ComponentList(PageView):
     ordering_fields = ('display_name', 'version_order')
 
 
-class HostTypeList(PageView):
+class HostTypeList(PaginatedView):
     """
     get:
     List all host types
@@ -245,7 +248,7 @@ class HostTypeList(PageView):
     ordering_fields = ('display_name', 'version_order')
 
 
-class ProviderTypeList(PageView):
+class ProviderTypeList(PaginatedView):
     """
     get:
     List all host providers types
@@ -255,9 +258,10 @@ class ProviderTypeList(PageView):
     serializer_class = serializers.ProviderTypeSerializer
     filterset_fields = ('name', 'bundle_id', 'display_name')
     ordering_fields = ('display_name', 'version_order')
+    permission_classes = (IsAuthenticated,)
 
 
-class ClusterTypeList(PageView):
+class ClusterTypeList(PaginatedView):
     """
     get:
     List all cluster types
@@ -269,7 +273,7 @@ class ClusterTypeList(PageView):
     ordering_fields = ('display_name', 'version_order')
 
 
-class AdcmTypeList(ListView):
+class AdcmTypeList(GenericUIView):
     """
     get:
     List adcm root object prototypes
@@ -279,15 +283,15 @@ class AdcmTypeList(ListView):
     serializer_class = serializers.AdcmTypeSerializer
     filterset_fields = ('bundle_id',)
 
+    def get(self, request, *args, **kwargs):
+        obj = self.get_queryset()
+        serializer = self.get_serializer(obj, many=True)
+        return Response(serializer.data)
+
 
-class PrototypeDetail(DetailViewRO):
-    """
-    get:
-    Show prototype
-    """
+class AbstractPrototypeDetail(DetailView):
+    """Common base class for *PrototypeDetail"""
 
-    queryset = Prototype.objects.all()
-    serializer_class = serializers.PrototypeDetailSerializer
     lookup_field = 'id'
     lookup_url_kwarg = 'prototype_id'
     error_code = 'PROTOTYPE_NOT_FOUND'
@@ -306,7 +310,17 @@ def get_object(self):
         return obj_type
 
 
-class AdcmTypeDetail(PrototypeDetail):
+class PrototypeDetail(AbstractPrototypeDetail):
+    """
+    get:
+    Show prototype
+    """
+
+    queryset = Prototype.objects.all()
+    serializer_class = serializers.PrototypeDetailSerializer
+
+
+class AdcmTypeDetail(AbstractPrototypeDetail):
     """
     get:
     Show adcm prototype
@@ -316,7 +330,7 @@ class AdcmTypeDetail(PrototypeDetail):
     serializer_class = serializers.AdcmTypeDetailSerializer
 
 
-class ClusterTypeDetail(PrototypeDetail):
+class ClusterTypeDetail(AbstractPrototypeDetail):
     """
     get:
     Show cluster prototype
@@ -326,7 +340,7 @@ class ClusterTypeDetail(PrototypeDetail):
     serializer_class = serializers.ClusterTypeDetailSerializer
 
 
-class ComponentTypeDetail(PrototypeDetail):
+class ComponentTypeDetail(AbstractPrototypeDetail):
     """
     get:
     Show component prototype
@@ -336,7 +350,7 @@ class ComponentTypeDetail(PrototypeDetail):
     serializer_class = serializers.ComponentTypeDetailSerializer
 
 
-class HostTypeDetail(PrototypeDetail):
+class HostTypeDetail(AbstractPrototypeDetail):
     """
     get:
     Show host prototype
@@ -346,7 +360,7 @@ class HostTypeDetail(PrototypeDetail):
     serializer_class = serializers.HostTypeDetailSerializer
 
 
-class ProviderTypeDetail(PrototypeDetail):
+class ProviderTypeDetail(AbstractPrototypeDetail):
     """
     get:
     Show host provider prototype
@@ -354,12 +368,3 @@ class ProviderTypeDetail(PrototypeDetail):
 
     queryset = Prototype.objects.filter(type='provider')
     serializer_class = serializers.ProviderTypeDetailSerializer
-
-
-class LoadServiceMap(GenericAPIPermView):
-    queryset = Prototype.objects.all()
-    serializer_class = serializers.Stack
-
-    def put(self, request):
-        cm.api.load_service_map()
-        return Response(status=status.HTTP_200_OK)
diff --git a/python/api/stats/root.py b/python/api/stats/root.py
new file mode 100644
index 0000000000..0eaff46d0b
--- /dev/null
+++ b/python/api/stats/root.py
@@ -0,0 +1,25 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Stats endpoint root view"""
+
+from rest_framework import permissions, routers
+
+
+class StatsRoot(routers.APIRootView):
+    """Stats Root"""
+
+    permission_classes = (permissions.AllowAny,)
+    api_root_dict = {
+        'task': 'task-stats',
+        'job': 'job-stats',
+    }
diff --git a/python/api/stats/urls.py b/python/api/stats/urls.py
index b75a84c266..22f8818ec9 100644
--- a/python/api/stats/urls.py
+++ b/python/api/stats/urls.py
@@ -10,13 +10,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
 from django.urls import path
-from . import views
 
+from . import views, root
 
 urlpatterns = [
-    path('', views.Stats.as_view(), name='stats'),
-    path('task/<int:task_id>/', views.TaskStats.as_view(), name='task-stats'),
-    path('job/<int:job_id>/', views.JobStats.as_view(), name='job-stats'),
+    path('', root.StatsRoot.as_view(), {'pk': 0}, name='stats'),
+    path('task/<int:pk>/', views.TaskStats.as_view(), name='task-stats'),
+    path('job/<int:pk>/', views.JobStats.as_view(), name='job-stats'),
 ]
diff --git a/python/api/stats/views.py b/python/api/stats/views.py
index 198d56942d..23934b1319 100644
--- a/python/api/stats/views.py
+++ b/python/api/stats/views.py
@@ -10,37 +10,25 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from guardian.mixins import PermissionListMixin
+from rest_framework import permissions
 from rest_framework.response import Response
 
+from api.base_view import GenericUIView
 from cm import config
 from cm.models import JobLog, TaskLog
-from api.serializers import EmptySerializer
-from api.api_views import GenericAPIPermView
-from . import serializers
 
 
-class Stats(GenericAPIPermView):
+class JobStats(PermissionListMixin, GenericUIView):
     queryset = JobLog.objects.all()
-    serializer_class = serializers.StatsSerializer
+    permission_classes = (permissions.IsAuthenticated,)
+    permission_required = ['cm.view_joblog']
 
-    def get(self, request):
-        """
-        Statistics
-        """
-        obj = JobLog(id=1)
-        serializer = self.serializer_class(obj, context={'request': request})
-        return Response(serializer.data)
-
-
-class JobStats(GenericAPIPermView):
-    queryset = JobLog.objects.all()
-    serializer_class = EmptySerializer
-
-    def get(self, request, job_id):
+    def get(self, request, pk):
         """
         Show jobs stats
         """
-        jobs = self.get_queryset().filter(id__gt=job_id)
+        jobs = self.get_queryset().filter(id__gt=pk)
         data = {
             config.Job.FAILED: jobs.filter(status=config.Job.FAILED).count(),
             config.Job.SUCCESS: jobs.filter(status=config.Job.SUCCESS).count(),
@@ -49,15 +37,16 @@ def get(self, request, job_id):
         return Response(data)
 
 
-class TaskStats(GenericAPIPermView):
+class TaskStats(PermissionListMixin, GenericUIView):
     queryset = TaskLog.objects.all()
-    serializer_class = EmptySerializer
+    permission_classes = (permissions.IsAuthenticated,)
+    permission_required = ['cm.view_tasklog']
 
-    def get(self, request, task_id):
+    def get(self, request, pk):
         """
         Show tasks stats
         """
-        tasks = self.get_queryset().filter(id__gt=task_id)
+        tasks = self.get_queryset().filter(id__gt=pk)
         data = {
             config.Job.FAILED: tasks.filter(status=config.Job.FAILED).count(),
             config.Job.SUCCESS: tasks.filter(status=config.Job.SUCCESS).count(),
diff --git a/python/api/api_views.py b/python/api/utils.py
similarity index 51%
rename from python/api/api_views.py
rename to python/api/utils.py
index 49b247834e..ed41336535 100644
--- a/python/api/api_views.py
+++ b/python/api/utils.py
@@ -10,31 +10,36 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# pylint: disable=not-callable, unused-import, too-many-locals
+# pylint: disable=not-callable, too-many-locals
 
 from typing import List
 
-from django.core.exceptions import ObjectDoesNotExist, FieldError
+from django.core.exceptions import ObjectDoesNotExist
 from django.http.request import QueryDict
 from django_filters import rest_framework as drf_filters
-
-import rest_framework.pagination
+from guardian.shortcuts import get_objects_for_user
 from rest_framework import status, serializers, exceptions
-from rest_framework.reverse import reverse
 from rest_framework.filters import OrderingFilter
 from rest_framework.response import Response
-from rest_framework.generics import GenericAPIView
-from rest_framework.utils.urls import replace_query_param
-from rest_framework.permissions import DjangoModelPermissions
-
-from adcm.settings import REST_FRAMEWORK
+from rest_framework.reverse import reverse
 
 import cm.upgrade
-from cm import config
 from cm.errors import AdcmEx
 from cm.models import Action, ADCMEntity, PrototypeConfig, ConcernType
 
-from rbac.viewsets import DjangoObjectPerm
+
+def get_object_for_user(user, perms, klass, **kwargs):
+    try:
+        queryset = get_objects_for_user(user, perms, klass)
+        return queryset.get(**kwargs)
+    except ObjectDoesNotExist:
+        model = klass
+        if not hasattr(klass, '_default_manager'):
+            model = klass.model
+        error_code = 'NO_MODEL_ERROR_CODE'
+        if hasattr(model, '__error_code__'):
+            error_code = model.__error_code__
+        raise AdcmEx(error_code) from None
 
 
 def check_obj(model, req, error=None):
@@ -65,8 +70,8 @@ def has_custom_permission(user, action_type, model, obj, second_perm):
     return False
 
 
-def check_custom_perm(self, action_type, model, obj, second_perm=None):
-    if not has_custom_permission(self.request.user, action_type, model, obj, second_perm):
+def check_custom_perm(user, action_type, model, obj, second_perm=None):
+    if not has_custom_permission(user, action_type, model, obj, second_perm):
         permission_denied()
 
 
@@ -148,47 +153,6 @@ def get_url(self, obj, view_name, request, format):  # pylint: disable=redefined
         return reverse(self.view_name, kwargs=kwargs, request=request, format=format)
 
 
-class DjangoModelPerm(DjangoModelPermissions):
-    """
-    Similar to `DjangoModelPermissions`, but adding 'view' permissions.
-    """
-
-    perms_map = {
-        'GET': ['%(app_label)s.view_%(model_name)s'],
-        'OPTIONS': ['%(app_label)s.view_%(model_name)s'],
-        'HEAD': ['%(app_label)s.view_%(model_name)s'],
-        'POST': ['%(app_label)s.add_%(model_name)s'],
-        'PUT': ['%(app_label)s.change_%(model_name)s'],
-        'PATCH': ['%(app_label)s.change_%(model_name)s'],
-        'DELETE': ['%(app_label)s.delete_%(model_name)s'],
-    }
-
-
-class GenericAPIPermView(GenericAPIView):
-    permission_classes = (DjangoObjectPerm,)
-
-
-class InterfaceView:
-    def for_ui(self, request):
-        view = self.request.query_params.get('view', None)
-        return bool(view == 'interface')
-
-    def select_serializer(self, request):
-        """
-        That is special function to handle api calls from UI.
-
-        UI send special GET parameter view=interface to switch between
-        regular and extended serializer
-        """
-        if request.method == 'POST':
-            if hasattr(self, 'serializer_class_post'):
-                return self.serializer_class_post
-        elif self.for_ui(request):
-            if hasattr(self, 'serializer_class_ui'):
-                return self.serializer_class_ui
-        return self.serializer_class
-
-
 def getlist_from_querydict(query_params, field_name):
     params = query_params.get(field_name)
     if params is None:
@@ -243,111 +207,3 @@ def get_filterset_kwargs(self, request, queryset, view):
             'queryset': queryset,
             'request': request,
         }
-
-
-class PageView(GenericAPIPermView, InterfaceView):
-    filter_backends = (AdcmFilterBackend, AdcmOrderingFilter)
-    pagination_class = rest_framework.pagination.LimitOffsetPagination
-
-    def get_ordering(self, request, queryset, view):
-        Order = AdcmOrderingFilter()
-        return Order.get_ordering(request, queryset, view)
-
-    def is_paged(self, request):
-        limit = self.request.query_params.get('limit', False)
-        offset = self.request.query_params.get('offset', False)
-        return bool(limit or offset)
-
-    def get_paged_link(self):
-        page = self.paginator
-        url = self.request.build_absolute_uri()
-        url = replace_query_param(url, page.limit_query_param, page.limit)
-        url = replace_query_param(url, page.offset_query_param, 0)
-        return url
-
-    def get_page(self, obj, request, context=None):
-        if not context:
-            context = {}
-        context['request'] = request
-        count = obj.count()
-        serializer_class = self.select_serializer(request)
-
-        if 'fields' in request.query_params or 'distinct' in request.query_params:
-            serializer_class = None
-            try:
-                fields = getlist_from_querydict(request.query_params, 'fields')
-                distinct = int(request.query_params.get('distinct', 0))
-
-                if fields and distinct:
-                    obj = obj.values(*fields).distinct()
-                elif fields:
-                    obj = obj.values(*fields)
-
-            except (FieldError, ValueError):
-                qp = ','.join(
-                    [
-                        f'{k}={v}'
-                        for k, v in request.query_params.items()
-                        if k in ['fields', 'distinct']
-                    ]
-                )
-                msg = f'Bad query params: {qp}'
-                raise AdcmEx('BAD_QUERY_PARAMS', msg=msg) from None
-
-        page = self.paginate_queryset(obj)
-        if self.is_paged(request):
-            if serializer_class is not None:
-                serializer = serializer_class(page, many=True, context=context)
-                page = serializer.data
-            return self.get_paginated_response(page)
-
-        if count <= REST_FRAMEWORK['PAGE_SIZE']:
-            if serializer_class is not None:
-                serializer = serializer_class(obj, many=True, context=context)
-                obj = serializer.data
-            return Response(obj)
-
-        msg = 'Response is too long, use paginated request'
-        raise AdcmEx('TOO_LONG', msg=msg, args=self.get_paged_link())
-
-    def get(self, request, *args, **kwargs):
-        obj = self.filter_queryset(self.get_queryset())
-        return self.get_page(obj, request)
-
-
-class PageViewAdd(PageView):
-    def post(self, request, *args, **kwargs):
-        serializer_class = self.select_serializer(request)
-        serializer = serializer_class(data=request.data, context={'request': request})
-        return create(serializer)
-
-
-class ListView(GenericAPIPermView, InterfaceView):
-    filter_backends = (AdcmFilterBackend,)
-
-    def get(self, request, *args, **kwargs):
-        obj = self.filter_queryset(self.get_queryset())
-        serializer_class = self.select_serializer(request)
-        serializer = serializer_class(obj, many=True, context={'request': request})
-        return Response(serializer.data)
-
-
-class DetailViewRO(GenericAPIPermView, InterfaceView):
-    def check_obj(self, kw_req):
-        try:
-            return self.get_queryset().get(**kw_req)
-        except ObjectDoesNotExist:
-            raise AdcmEx(self.error_code) from None
-
-    def get_object(self):
-        lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
-        kw_req = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
-        obj = self.check_obj(kw_req)
-        self.check_object_permissions(self.request, obj)
-        return obj
-
-    def get(self, request, *args, **kwargs):
-        obj = self.get_object()
-        serializer_class = self.select_serializer(request)
-        serializer = serializer_class(obj, context={'request': request})
-        return Response(serializer.data)
diff --git a/python/api/views.py b/python/api/views.py
index b41a17c6ec..cf94982219 100644
--- a/python/api/views.py
+++ b/python/api/views.py
@@ -20,7 +20,6 @@
 import cm.stack
 import cm.status_api
 from adcm.settings import ADCM_VERSION
-from rbac.viewsets import GenericPermViewSet
 
 
 class APIRoot(routers.APIRootView):
@@ -68,12 +67,3 @@ def get(self, request):
         General info about ADCM
         """
         return Response({'adcm_version': ADCM_VERSION, 'google_oauth': cm.api.has_google_oauth()})
-
-
-class ViewInterfaceGenericViewSet(GenericPermViewSet):
-    def get_serializer_class(self):
-        if self.request is not None:
-            view = self.request.query_params.get('view', None)
-            if view == 'interface':
-                return self.ui_serializer_class
-        return self.serializer_class
diff --git a/python/cm/api.py b/python/cm/api.py
index 1329e18260..80bb78f1a7 100644
--- a/python/cm/api.py
+++ b/python/cm/api.py
@@ -17,7 +17,6 @@
 from django.db import transaction
 from django.utils import timezone
 
-import rbac
 import cm.issue
 import cm.status_api
 from cm.adcm_config import (
@@ -52,6 +51,7 @@
     TaskLog,
 )
 from cm.upgrade import check_license, version_in
+from rbac.models import re_apply_object_policy
 
 
 def check_proto_type(proto, check_type):
@@ -131,7 +131,7 @@ def add_host(proto, provider, fqdn, desc=''):
         host.save()
         host.add_to_concerns(ctx.lock)
         cm.issue.update_hierarchy_issues(host)
-        rbac.models.re_apply_object_policy(provider)
+        re_apply_object_policy(provider)
     ctx.event.send_state()
     cm.status_api.post_event('create', 'host', host.id, 'provider', str(provider.id))
     load_service_map()
@@ -198,7 +198,7 @@ def add_host_to_cluster(cluster, host):
         host.save()
         host.add_to_concerns(ctx.lock)
         cm.issue.update_hierarchy_issues(host)
-        rbac.models.re_apply_object_policy(cluster)
+        re_apply_object_policy(cluster)
     cm.status_api.post_event('add', 'host', host.id, 'cluster', str(cluster.id))
     load_service_map()
     log.info('host #%s %s is added to cluster #%s %s', host.id, host.fqdn, cluster.id, cluster.name)
@@ -215,7 +215,7 @@ def get_cluster_and_host(cluster_id, fqdn, host_id):
         host = Host.obj.get(id=host_id)
     else:
         err('HOST_NOT_FOUND', 'fqdn or host_id is mandatory args')
-    return (cluster, host)
+    return cluster, host
 
 
 def add_host_to_cluster_by_id(cluster_id, fqdn, host_id):
@@ -321,7 +321,7 @@ def delete_service(service, cancel_tasks=True):
     cluster = service.cluster
     service.delete()
     cm.issue.update_hierarchy_issues(cluster)
-    rbac.models.re_apply_object_policy(cluster)
+    re_apply_object_policy(cluster)
     cm.status_api.post_event('delete', 'service', service_id)
     load_service_map()
     log.info(f'service #{service_id} is deleted')
@@ -349,7 +349,7 @@ def remove_host_from_cluster(host):
             cm.issue.update_hierarchy_issues(host)
         host.remove_from_concerns(ctx.lock)
         cm.issue.update_hierarchy_issues(cluster)
-        rbac.models.re_apply_object_policy(cluster)
+        re_apply_object_policy(cluster)
     ctx.event.send_state()
     cm.status_api.post_event('remove', 'host', host.id, 'cluster', str(cluster.id))
     load_service_map()
@@ -388,7 +388,7 @@ def add_service_to_cluster(cluster, proto):
         cs.save()
         add_components_to_service(cluster, cs)
         cm.issue.update_hierarchy_issues(cs)
-        rbac.models.re_apply_object_policy(cluster)
+        re_apply_object_policy(cluster)
     cm.status_api.post_event('add', 'service', cs.id, 'cluster', str(cluster.id))
     load_service_map()
     log.info(
@@ -449,6 +449,7 @@ def update_obj_config(obj_conf, conf, attr, desc=''):
     with transaction.atomic():
         cl = save_obj_config(obj_conf, new_conf, attr, desc)
         cm.issue.update_hierarchy_issues(obj)
+        re_apply_object_policy(obj)
     if hasattr(obj_conf, 'adcm'):
         prepare_social_auth(new_conf)
     if group is not None:
@@ -581,9 +582,9 @@ def save_hc(cluster, host_comp_list):  # pylint: disable=too-many-locals
     cm.issue.update_hierarchy_issues(cluster)
     load_service_map()
     for service in service_map:
-        rbac.models.re_apply_object_policy(service)
+        re_apply_object_policy(service)
     for hc in result:
-        rbac.models.re_apply_object_policy(hc.service)
+        re_apply_object_policy(hc.service)
     return result
 
 
diff --git a/python/cm/job.py b/python/cm/job.py
index b35fa41526..1550505b37 100644
--- a/python/cm/job.py
+++ b/python/cm/job.py
@@ -24,6 +24,7 @@
 from django.db import transaction
 from django.utils import timezone
 
+from rbac.roles import re_apply_policy_for_jobs
 from cm import api, inventory, adcm_config, variant, config
 from cm.adcm_config import process_file_type
 from cm.api_context import ctx
@@ -130,7 +131,7 @@ def prepare_task(
             process_file_type(task, spec, conf)
             task.config = new_conf
             task.save()
-
+    re_apply_policy_for_jobs(obj, task)
     return task
 
 
diff --git a/python/rbac/endpoints/group/views.py b/python/rbac/endpoints/group/views.py
index 548d8fd7af..34e52e0018 100644
--- a/python/rbac/endpoints/group/views.py
+++ b/python/rbac/endpoints/group/views.py
@@ -13,12 +13,14 @@
 """Group view sets"""
 
 from adwp_base.errors import AdwpEx
+from guardian.mixins import PermissionListMixin
 from rest_flex_fields.serializers import FlexFieldsSerializerMixin
 from rest_framework import serializers, status
+from rest_framework.permissions import DjangoModelPermissions
+from rest_framework.viewsets import ModelViewSet
 
 from rbac import models
 from rbac.services import group as group_services
-from rbac.viewsets import ModelPermViewSet
 
 
 class UserSerializer(serializers.Serializer):
@@ -87,11 +89,13 @@ def create(self, validated_data):
         return group_services.create(**validated_data)
 
 
-class GroupViewSet(ModelPermViewSet):  # pylint: disable=too-many-ancestors
+class GroupViewSet(PermissionListMixin, ModelViewSet):  # pylint: disable=too-many-ancestors
     """Group view set"""
 
     queryset = models.Group.objects.all()
     serializer_class = GroupSerializer
+    permission_classes = (DjangoModelPermissions,)
+    permission_required = ['rbac.view_group']
     filterset_fields = ('id', 'name')
     ordering_fields = ('id', 'name')
     search_fields = ('name', 'description')
diff --git a/python/rbac/endpoints/policy/views.py b/python/rbac/endpoints/policy/views.py
index a18cb2bb9b..be9d58d421 100644
--- a/python/rbac/endpoints/policy/views.py
+++ b/python/rbac/endpoints/policy/views.py
@@ -11,17 +11,19 @@
 # limitations under the License.
 
 import jsonschema
+from guardian.mixins import PermissionListMixin
 from rest_flex_fields.serializers import FlexFieldsSerializerMixin
 from rest_framework import serializers
 from rest_framework import status
+from rest_framework.permissions import DjangoModelPermissions
 from rest_framework.response import Response
 from rest_framework.validators import ValidationError
+from rest_framework.viewsets import ModelViewSet
 
 from cm.models import Cluster, ClusterObject, ServiceComponent, HostProvider, Host
 from rbac.models import Policy, User, Group, Role, RoleTypes
 from rbac.services.policy import policy_create, policy_update
 from rbac.utils import BaseRelatedSerializer
-from rbac.viewsets import ModelPermViewSet
 
 
 class ObjectField(serializers.JSONField):
@@ -128,9 +130,11 @@ def validate_role(self, role):
         return role
 
 
-class PolicyViewSet(ModelPermViewSet):  # pylint: disable=too-many-ancestors
+class PolicyViewSet(PermissionListMixin, ModelViewSet):  # pylint: disable=too-many-ancestors
     queryset = Policy.objects.all()
     serializer_class = PolicySerializer
+    permission_classes = (DjangoModelPermissions,)
+    permission_required = ['rbac.view_policy']
     filterset_fields = ('id', 'name', 'built_in', 'role', 'user', 'group')
     ordering_fields = ('id', 'name', 'built_in', 'role')
 
diff --git a/python/rbac/endpoints/role/views.py b/python/rbac/endpoints/role/views.py
index f849390d14..03913d1a57 100644
--- a/python/rbac/endpoints/role/views.py
+++ b/python/rbac/endpoints/role/views.py
@@ -10,19 +10,23 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from django.db.models import Q
+from django.db.models import Q, Prefetch
 from django_filters import rest_framework as filters
+from guardian.mixins import PermissionListMixin
+from guardian.shortcuts import get_objects_for_user
+from rest_flex_fields import is_expanded
 from rest_flex_fields.serializers import FlexFieldsSerializerMixin
 from rest_framework import serializers
 from rest_framework import status
-from rest_framework.response import Response
 from rest_framework.decorators import action
+from rest_framework.permissions import DjangoModelPermissions
+from rest_framework.response import Response
+from rest_framework.viewsets import ModelViewSet
 
 from cm.models import ProductCategory
-from rbac.models import Role
+from rbac.models import Role, RoleTypes
 from rbac.services.role import role_create, role_update
 from rbac.utils import BaseRelatedSerializer
-from rbac.viewsets import ModelPermViewSet
 
 
 class RoleChildSerializer(BaseRelatedSerializer):
@@ -86,14 +90,23 @@ class Meta:
         )
 
 
-class RoleView(ModelPermViewSet):  # pylint: disable=too-many-ancestors
+class RoleView(PermissionListMixin, ModelViewSet):  # pylint: disable=too-many-ancestors
 
-    queryset = Role.objects.all()
     serializer_class = RoleSerializer
+    permission_classes = (DjangoModelPermissions,)
+    permission_required = ['rbac.view_role']
     filterset_class = RoleFilter
     ordering_fields = ('id', 'name', 'display_name', 'built_in', 'type')
     search_fields = ('name', 'display_name')
 
+    def get_queryset(self, *args, **kwargs):
+        queryset = get_objects_for_user(**self.get_get_objects_for_user_kwargs(Role.objects.all()))
+        if is_expanded(self.request, 'child'):
+            return queryset.prefetch_related(
+                Prefetch('child', queryset=queryset.exclude(type=RoleTypes.hidden)),
+            )
+        return queryset
+
     def create(self, request, *args, **kwargs):
         serializer = self.get_serializer(data=request.data)
         if serializer.is_valid(raise_exception=True):
diff --git a/python/rbac/endpoints/user/views.py b/python/rbac/endpoints/user/views.py
index a430f144a4..f79f412c51 100644
--- a/python/rbac/endpoints/user/views.py
+++ b/python/rbac/endpoints/user/views.py
@@ -13,12 +13,14 @@
 """User view sets"""
 
 from adwp_base.errors import AdwpEx
+from guardian.mixins import PermissionListMixin
 from rest_flex_fields.serializers import FlexFieldsSerializerMixin
 from rest_framework import serializers, status
+from rest_framework.permissions import DjangoModelPermissions
+from rest_framework.viewsets import ModelViewSet
 
 from rbac import models
 from rbac.services import user as user_services
-from rbac.viewsets import ModelPermViewSet
 
 
 class PasswordField(serializers.CharField):
@@ -95,11 +97,13 @@ def create(self, validated_data):
         return user_services.create(**validated_data)
 
 
-class UserViewSet(ModelPermViewSet):  # pylint: disable=too-many-ancestors
+class UserViewSet(PermissionListMixin, ModelViewSet):  # pylint: disable=too-many-ancestors
     """User view set"""
 
     queryset = models.User.objects.all()
     serializer_class = UserSerializer
+    permission_classes = (DjangoModelPermissions,)
+    permission_required = ['rbac.view_user']
     filterset_fields = (
         'id',
         'username',
diff --git a/python/rbac/endpoints_ui/role/views.py b/python/rbac/endpoints_ui/role/views.py
index ae16698968..9769962a51 100644
--- a/python/rbac/endpoints_ui/role/views.py
+++ b/python/rbac/endpoints_ui/role/views.py
@@ -15,12 +15,12 @@
 from collections import defaultdict
 
 from rest_framework import serializers, mixins
-from rest_framework.response import Response
 from rest_framework.decorators import action
+from rest_framework.response import Response
 
+from api.base_view import GenericUIViewSet
 from cm import models as cm_models
 from rbac import models
-from rbac.viewsets import GenericPermViewSet
 
 
 class RoleSerializer(serializers.Serializer):
@@ -32,7 +32,7 @@ class RoleSerializer(serializers.Serializer):
     )
 
 
-class RoleViewSet(mixins.ListModelMixin, GenericPermViewSet):
+class RoleViewSet(mixins.ListModelMixin, GenericUIViewSet):
     queryset = models.Role.objects.all()
     serializer_class = RoleSerializer
 
diff --git a/python/rbac/migrations/0002_rm_default_policy.py b/python/rbac/migrations/0002_rm_default_policy.py
new file mode 100644
index 0000000000..e04c4d4915
--- /dev/null
+++ b/python/rbac/migrations/0002_rm_default_policy.py
@@ -0,0 +1,63 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Generated by Django 3.2 on 2022-02-14 09:29
+
+from django.db import migrations
+
+
+def remove_permissions(policy, policy_model):
+    for pp in policy.model_perm.all():
+        if (
+            policy_model.objects.filter(
+                user=pp.user, group=pp.group, model_perm__permission=pp.permission
+            ).count()
+            > 1
+        ):
+            continue
+        if pp.user:
+            pp.user.user_permissions.remove(pp.permission)
+        if pp.group:
+            pp.group.permissions.remove(pp.permission)
+        pp.delete()
+    for pp in policy.user_object_perm.all():
+        if policy_model.objects.filter(user=pp.user, user_object_perm=pp).count() > 1:
+            continue
+        pp.delete()
+    for pp in policy.group_object_perm.all():
+        if policy_model.objects.filter(group=pp.group, group_object_perm=pp).count() > 1:
+            continue
+        pp.delete()
+
+
+def remove_default_policy(apps, schema_editor):
+    Policy = apps.get_model('rbac', 'Policy')
+    policy = Policy.objects.filter(name='default', built_in=True).first()
+    if policy:
+        # Default django model delete() method is used here,
+        # so Policy.remove_permissions() was copied as-is
+        remove_permissions(policy, Policy)
+        policy.delete()
+
+    Role = apps.get_model('rbac', 'Role')
+    Role.objects.filter(name='Base role', type='hidden').delete()
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('rbac', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.RunPython(remove_default_policy),
+    ]
diff --git a/python/rbac/models.py b/python/rbac/models.py
index 735da0a803..5fea5d9648 100644
--- a/python/rbac/models.py
+++ b/python/rbac/models.py
@@ -23,7 +23,7 @@
 from guardian.models import UserObjectPermission, GroupObjectPermission
 from rest_framework.exceptions import ValidationError
 
-from cm.models import Bundle, ProductCategory
+from cm.models import Bundle, ProductCategory, HostComponent
 
 
 class ObjectType(models.TextChoices):
@@ -133,22 +133,22 @@ def apply(self, policy: 'Policy', user: User, group: Group, obj=None):
 
     def get_permissions(self, role: 'Role' = None):
         """Recursively get permissions of role and all her childs"""
-        role_list = []
-        perm_list = []
         if role is None:
             role = self
 
-        def get_perm(role, perm_list, role_list):
-            if role in role_list:
-                return
-            role_list.append(role)
-            for p in role.permissions.all():
-                if p not in perm_list:
-                    perm_list.append(p)
-            for child in role.child.all():
-                get_perm(child, perm_list, role_list)
-
-        get_perm(role, perm_list, role_list)
+        # the raw query was added to avoid many SQL queries
+        role_list = Role.objects.raw(
+            """
+                with recursive role_ids as (
+                    select id from rbac_role where id = %s
+                    union
+                    select role_child.to_role_id from role_ids as tmp
+                    inner join rbac_role_child as role_child on role_child.from_role_id = tmp.id
+                ) select id from role_ids;
+            """,
+            params=[role.id],
+        )
+        perm_list = list(Permission.objects.filter(role__in=role_list).distinct())
         return perm_list
 
 
@@ -198,26 +198,20 @@ class Policy(models.Model):
 
     def remove_permissions(self):
         for pp in self.model_perm.all():
-            if (
-                Policy.objects.filter(
-                    user=pp.user, group=pp.group, model_perm__permission=pp.permission
-                ).count()
-                > 1
-            ):
-                continue
-            if pp.user:
-                pp.user.user_permissions.remove(pp.permission)
-            if pp.group:
-                pp.group.permissions.remove(pp.permission)
-            pp.delete()
-        for pp in self.user_object_perm.all():
-            if Policy.objects.filter(user=pp.user, user_object_perm=pp).count() > 1:
-                continue
-            pp.delete()
-        for pp in self.group_object_perm.all():
-            if Policy.objects.filter(group=pp.group, group_object_perm=pp).count() > 1:
-                continue
-            pp.delete()
+            if pp.policy_set.count() <= 1:
+                if pp.user:
+                    pp.user.user_permissions.remove(pp.permission)
+                if pp.group:
+                    pp.group.permissions.remove(pp.permission)
+            pp.policy_set.remove(self)
+
+        for uop in self.user_object_perm.all():
+            if uop.policy_set.count() <= 1:
+                uop.delete()
+
+        for gop in self.group_object_perm.all():
+            if gop.policy_set.count() <= 1:
+                gop.delete()
 
     def add_object(self, obj):
         po = PolicyObject(object=obj)
@@ -239,6 +233,14 @@ def delete(self, using=None, keep_parents=False):
         self.remove_permissions()
         return super().delete(using, keep_parents)
 
+    @atomic
+    def apply_without_deletion(self):
+        """This function apply role over"""
+        for user in self.user.all():
+            self.role.apply(self, user, None)
+        for group in self.group.all():
+            self.role.apply(self, None, group=group)
+
     @atomic
     def apply(self):
         """This function apply role over"""
@@ -249,13 +251,36 @@ def apply(self):
             self.role.apply(self, None, group=group)
 
 
-def re_apply_object_policy(obj):
+def get_objects_for_policy(obj):
+    obj_type_map = {}
+    obj_type = obj.prototype.type
+    if obj_type == 'component':
+        object_list = [obj, obj.service, obj.cluster]
+    elif obj_type == 'service':
+        object_list = [obj, obj.cluster]
+    elif obj_type == 'host':
+        if obj.cluster:
+            object_list = [obj, obj.provider, obj.cluster]
+            for hc in HostComponent.objects.filter(cluster=obj.cluster, host=obj):
+                object_list.append(hc.service)
+                object_list.append(hc.component)
+        else:
+            object_list = [obj, obj.provider]
+    else:
+        object_list = [obj]
+    for policy_object in object_list:
+        obj_type_map[policy_object] = ContentType.objects.get_for_model(policy_object)
+    return obj_type_map
+
+
+def re_apply_object_policy(apply_object):
     """
     This function search for polices linked with specified object and re apply them
     """
-    content = ContentType.objects.get_for_model(obj)
-    for policy in Policy.objects.filter(object__object_id=obj.id, object__content_type=content):
-        policy.apply()
+    obj_type_map = get_objects_for_policy(apply_object)
+    for obj, ct in obj_type_map.items():
+        for policy in Policy.objects.filter(object__object_id=obj.id, object__content_type=ct):
+            policy.apply()
 
 
 def re_apply_all_polices():
diff --git a/python/rbac/roles.py b/python/rbac/roles.py
index a75d8be921..2565b08028 100644
--- a/python/rbac/roles.py
+++ b/python/rbac/roles.py
@@ -12,19 +12,27 @@
 
 """RBAC Role classes"""
 
+from adwp_base.errors import raise_AdwpEx as err
 from django.apps import apps
 from django.contrib.contenttypes.models import ContentType
+from django.db import transaction
+from django.utils import timezone
 from guardian.models import UserObjectPermission, GroupObjectPermission
-from adwp_base.errors import raise_AdwpEx as err
-from rbac.models import Policy, PolicyPermission, Role, User, Group, Permission
+
 from cm.models import (
     Action,
     ClusterObject,
     ServiceComponent,
     Host,
     HostComponent,
-    get_model_by_type,
+    GroupConfig,
+    TaskLog,
+    JobLog,
+    LogStorage,
+    DummyData,
 )
+from rbac.models import Policy, PolicyPermission, Role, User, Group, Permission
+from rbac.models import RoleTypes, get_objects_for_policy
 
 
 class AbstractRole:
@@ -57,16 +65,25 @@ def apply(self, policy: Policy, role: Role, user: User, group: Group, param_obj=
         for perm in role.get_permissions():
             if group is not None:
                 group.permissions.add(perm)
-                pp = PolicyPermission(policy=policy, group=group, permission=perm)
-                pp.save()
+                pp, _ = PolicyPermission.objects.get_or_create(group=group, permission=perm)
                 policy.model_perm.add(pp)
             if user is not None:
                 user.user_permissions.add(perm)
-                pp = PolicyPermission(policy=policy, user=user, permission=perm)
-                pp.save()
+                pp, _ = PolicyPermission.objects.get_or_create(user=user, permission=perm)
                 policy.model_perm.add(pp)
 
 
+def assign_user_or_group_perm(user, group, policy, perm, obj):
+    with transaction.atomic():
+        DummyData.objects.filter(id=1).update(date=timezone.now())
+        if user is not None:
+            uop = UserObjectPermission.objects.assign_perm(perm, user, obj)
+            policy.user_object_perm.add(uop)
+        if group is not None:
+            gop = GroupObjectPermission.objects.assign_perm(perm, group, obj)
+            policy.group_object_perm.add(gop)
+
+
 class ObjectRole(AbstractRole):
     """This Role apply django-guardian object level permissions"""
 
@@ -83,12 +100,26 @@ def apply(self, policy: Policy, role: Role, user: User, group: Group, param_obj=
         """Apply Role to User and/or Group"""
         for obj in policy.get_objects(param_obj):
             for perm in role.get_permissions():
-                if user is not None:
-                    uop = UserObjectPermission.objects.assign_perm(perm, user, obj)
-                    policy.user_object_perm.add(uop)
-                if group is not None:
-                    gop = GroupObjectPermission.objects.assign_perm(perm, group, obj)
-                    policy.group_object_perm.add(gop)
+                assign_user_or_group_perm(user, group, policy, perm, obj)
+
+
+def get_host_objects(obj):
+    object_type = obj.prototype.type
+    host_list = []
+    if object_type == 'cluster':
+        for host in Host.obj.filter(cluster=obj):
+            host_list.append(host)
+    elif object_type == 'service':
+        for hc in HostComponent.obj.filter(cluster=obj.cluster, service=obj):
+            host_list.append(hc.host)
+    elif object_type == 'component':
+        for hc in HostComponent.obj.filter(cluster=obj.cluster, service=obj.service, component=obj):
+            host_list.append(hc.host)
+    elif object_type == 'provider':
+        for host in Host.obj.filter(provider=obj):
+            host_list.append(host)
+
+    return host_list
 
 
 class ActionRole(AbstractRole):
@@ -106,18 +137,114 @@ def filter(self):
     def apply(self, policy: Policy, role: Role, user: User, group: Group = None, param_obj=None):
         """Apply Role to User and/or Group"""
         action = Action.obj.get(id=self.params['action_id'])
+        assign_user_or_group_perm(user, group, policy, get_perm_for_model(Action), action)
         for obj in policy.get_objects(param_obj):
-            model = get_model_by_type(obj.prototype.type)
-            ct = ContentType.objects.get_for_model(model)
-            run_action, _ = Permission.objects.get_or_create(
-                content_type=ct, codename=f'run_action_{action.display_name}'
-            )
-            if user is not None:
-                uop = UserObjectPermission.objects.assign_perm(run_action, user, obj)
-                policy.user_object_perm.add(uop)
-            if group is not None:
-                gop = GroupObjectPermission.objects.assign_perm(run_action, group, obj)
-                policy.group_object_perm.add(gop)
+            for perm in role.get_permissions():
+                if action.host_action and perm.content_type == ContentType.objects.get_for_model(
+                    Host
+                ):
+                    hosts = get_host_objects(obj)
+                    for host in hosts:
+                        assign_user_or_group_perm(user, group, policy, perm, host)
+                    continue
+                assign_user_or_group_perm(user, group, policy, perm, obj)
+
+
+class TaskRole(AbstractRole):
+    def apply(self, policy, role, user, group, param_obj=None):
+        task = TaskLog.obj.get(id=self.params['task_id'])
+        for obj in policy.get_objects(param_obj):
+            if obj == task.task_object:
+                apply_jobs(task, policy, user, group)
+
+
+def get_perm_for_model(model, action='view'):
+    ct = ContentType.objects.get_for_model(model)
+    codename = f'{action}_{model.__name__.lower()}'
+    perm, _ = Permission.objects.get_or_create(content_type=ct, codename=codename)
+    return perm
+
+
+def apply_jobs(task: TaskLog, policy: Policy, user: User, group: Group = None):
+    assign_user_or_group_perm(user, group, policy, get_perm_for_model(TaskLog), task)
+    assign_user_or_group_perm(user, group, policy, get_perm_for_model(TaskLog, 'change'), task)
+    for job in JobLog.objects.filter(task=task):
+        assign_user_or_group_perm(user, group, policy, get_perm_for_model(JobLog), job)
+        for log in LogStorage.objects.filter(job=job):
+            assign_user_or_group_perm(user, group, policy, get_perm_for_model(LogStorage), log)
+
+
+def re_apply_policy_for_jobs(action_object, task):
+    obj_type_map = get_objects_for_policy(action_object)
+    object_model = action_object.__class__.__name__.lower()
+    task_role, _ = Role.objects.get_or_create(
+        name=f'View role for task {task.id}',
+        display_name=f'View role for task {task.id}',
+        description='View tasklog object with following joblog and logstorage',
+        type=RoleTypes.hidden,
+        module_name='rbac.roles',
+        class_name='TaskRole',
+        init_params={
+            'task_id': task.id,
+        },
+        parametrized_by_type=[task.task_object.prototype.type],
+    )
+    for obj, ct in obj_type_map.items():
+        for policy in Policy.objects.filter(object__object_id=obj.id, object__content_type=ct):
+            for user in policy.user.all():
+                try:
+                    uop = UserObjectPermission.objects.get(
+                        user=user, permission__codename='view_action', object_pk=task.action.pk
+                    )
+                except UserObjectPermission.DoesNotExist:
+                    continue
+                if uop in policy.user_object_perm.all() and user.has_perm(
+                    f'view_{object_model}', action_object
+                ):
+                    policy.role.child.add(task_role)
+                    apply_jobs(task, policy, user, None)
+            for group in policy.group.all():
+                try:
+                    gop = GroupObjectPermission.objects.get(
+                        group=group, permission__codename='view_action', object_pk=task.action.pk
+                    )
+                except UserObjectPermission.DoesNotExist:
+                    continue
+                if gop in policy.group_object_perm.all() and group.has_perm(
+                    f'view_{object_model}', action_object
+                ):
+                    policy.role.child.add(task_role)
+                    apply_jobs(task, policy, None, group)
+
+
+class ConfigRole(AbstractRole):
+    """This Role apply permission to view and add config object"""
+
+    def apply(self, policy: Policy, role: Role, user: User, group: Group, param_obj=None):
+        for obj in policy.get_objects(param_obj):
+            if obj.config is None:
+                continue
+
+            object_type = ContentType.objects.get_for_model(obj)
+            config_groups = GroupConfig.objects.filter(object_type=object_type, object_id=obj.id)
+
+            for perm in role.get_permissions():
+
+                if perm.content_type.model == 'objectconfig':
+                    assign_user_or_group_perm(user, group, policy, perm, obj.config)
+                    for cg in config_groups:
+                        assign_user_or_group_perm(user, group, policy, perm, cg.config)
+
+                if perm.content_type.model == 'configlog':
+                    for config in obj.config.configlog_set.all():
+                        assign_user_or_group_perm(user, group, policy, perm, config)
+                    for cg in config_groups:
+                        for config in cg.config.configlog_set.all():
+                            assign_user_or_group_perm(user, group, policy, perm, config)
+
+                if perm.content_type.model == 'groupconfig':
+                    for cg in config_groups:
+                        assign_user_or_group_perm(user, group, policy, perm, cg)
 
 
 class ParentRole(AbstractRole):
@@ -125,43 +252,59 @@ class ParentRole(AbstractRole):
 
     def find_and_apply(self, obj, policy, role, user, group=None):
         """Find Role of appropriate type and apply it to specified object"""
-        for r in role.child.all():
-            if r.class_name not in ('ObjectRole', 'ActionRole'):
-                continue
+        for r in role.child.filter(
+            class_name__in=['ObjectRole', 'ActionRole', 'TaskRole', 'ConfigRole']
+        ):
             if obj.prototype.type in r.parametrized_by_type:
                 r.apply(policy, user, group, obj)
 
     def apply(
         self, policy: Policy, role: Role, user: User, group: Group = None, param_obj=None
-    ):  # pylint: disable=too-many-branches
+    ):  # pylint: disable=too-many-branches, too-many-nested-blocks
         """Apply Role to User and/or Group"""
+        for r in role.child.filter(class_name__in=['ModelRole', 'ParentRole']):
+            r.apply(policy, user, group, param_obj)
+
+        parametrized_by = set()
+        for r in role.child.all():
+            parametrized_by.update(set(r.parametrized_by_type))
+
         for obj in policy.get_objects(param_obj):
+            view_cluster_perm = Permission.objects.get(codename='view_cluster')
+            view_service_perm = Permission.objects.get(codename='view_clusterobject')
+
             self.find_and_apply(obj, policy, role, user, group)
 
             if obj.prototype.type == 'cluster':
-                for service in ClusterObject.obj.filter(cluster=obj):
-                    self.find_and_apply(service, policy, role, user, group)
-                    for comp in ServiceComponent.obj.filter(service=service):
-                        self.find_and_apply(comp, policy, role, user, group)
-                for host in Host.obj.filter(cluster=obj):
-                    self.find_and_apply(host, policy, role, user, group)
+                if 'service' in parametrized_by or 'component' in parametrized_by:
+                    for service in ClusterObject.obj.filter(cluster=obj):
+                        self.find_and_apply(service, policy, role, user, group)
+                        if 'component' in parametrized_by:
+                            for comp in ServiceComponent.obj.filter(service=service):
+                                self.find_and_apply(comp, policy, role, user, group)
+                if 'host' in parametrized_by:
+                    for host in Host.obj.filter(cluster=obj):
+                        self.find_and_apply(host, policy, role, user, group)
 
             elif obj.prototype.type == 'service':
-                for comp in ServiceComponent.obj.filter(service=obj):
-                    self.find_and_apply(comp, policy, role, user, group)
-                for hc in HostComponent.obj.filter(cluster=obj.cluster, service=obj):
-                    self.find_and_apply(hc.host, policy, role, user, group)
+                if 'component' in parametrized_by:
+                    for comp in ServiceComponent.obj.filter(service=obj):
+                        self.find_and_apply(comp, policy, role, user, group)
+                if 'host' in parametrized_by:
+                    for hc in HostComponent.obj.filter(cluster=obj.cluster, service=obj):
+                        self.find_and_apply(hc.host, policy, role, user, group)
+                assign_user_or_group_perm(user, group, policy, view_cluster_perm, obj.cluster)
 
             elif obj.prototype.type == 'component':
-                for hc in HostComponent.obj.filter(
-                    cluster=obj.cluster, service=obj.service, component=obj
-                ):
-                    self.find_and_apply(hc.host, policy, role, user, group)
+                if 'host' in parametrized_by:
+                    for hc in HostComponent.obj.filter(
+                        cluster=obj.cluster, service=obj.service, component=obj
+                    ):
+                        self.find_and_apply(hc.host, policy, role, user, group)
+                assign_user_or_group_perm(user, group, policy, view_cluster_perm, obj.cluster)
+                assign_user_or_group_perm(user, group, policy, view_service_perm, obj.service)
 
             elif obj.prototype.type == 'provider':
-                for host in Host.obj.filter(provider=obj):
-                    self.find_and_apply(host, policy, role, user, group)
-
-        for r in role.child.all():
-            if r.class_name in ('ModelRole', 'ParentRole'):
-                r.apply(policy, user, group, param_obj)
+                if 'host' in parametrized_by:
+                    for host in Host.obj.filter(provider=obj):
+                        self.find_and_apply(host, policy, role, user, group)
diff --git a/python/rbac/services/policy.py b/python/rbac/services/policy.py
index be70bf4647..3261e8c4d8 100644
--- a/python/rbac/services/policy.py
+++ b/python/rbac/services/policy.py
@@ -17,9 +17,10 @@
 from django.contrib.contenttypes.models import ContentType
 from django.db import IntegrityError
 from django.db.transaction import atomic
+from django.utils import timezone
 from rest_framework import status
 
-from cm.models import ADCMEntity
+from cm.models import ADCMEntity, DummyData
 from rbac.models import User, Policy, PolicyObject, Role, Group
 from rbac.utils import update_m2m_field
 
@@ -91,6 +92,7 @@ def policy_create(name: str, role: Role, built_in: bool = False, **kwargs):
     _check_subjects(users, groups)
 
     objects = kwargs.get('object', [])
+    DummyData.objects.filter(id=1).update(date=timezone.now())
     _check_objects(role, objects)
     description = kwargs.get('description', '')
     try:
@@ -124,6 +126,7 @@ def policy_update(policy: Policy, **kwargs) -> Policy:
 
     users = kwargs.get('user')
     groups = kwargs.get('group')
+    DummyData.objects.filter(id=1).update(date=timezone.now())
     _check_subjects(
         users if users is not None else policy.user.all(),
         groups if groups is not None else policy.group.all(),
@@ -133,7 +136,6 @@ def policy_update(policy: Policy, **kwargs) -> Policy:
     objects = kwargs.get('object')
     policy_old_objects = [po.object for po in policy.object.all()]
     _check_objects(role or policy.role, objects if objects is not None else policy_old_objects)
-
     if 'name' in kwargs:
         policy.name = kwargs['name']
     if 'description' in kwargs:
diff --git a/python/rbac/services/user.py b/python/rbac/services/user.py
index 9ba176c741..21be264536 100644
--- a/python/rbac/services/user.py
+++ b/python/rbac/services/user.py
@@ -75,12 +75,6 @@ def _regenerate_token(user: models.User) -> Token:
     return token
 
 
-def _update_default_policy(user: models.User) -> None:
-    policy = models.Policy.objects.get(name='default')
-    policy.user.add(user)
-    policy.apply()
-
-
 @transaction.atomic
 def update(
     user: models.User,
@@ -156,7 +150,6 @@ def create(
         )
     except IntegrityError as exc:
         raise AdwpEx('USER_CREATE_ERROR', msg=f'User creation failed with error {exc}') from exc
-    _update_default_policy(user)
     _update_groups(user, groups or [])
     _regenerate_token(user)
     return user
diff --git a/python/rbac/upgrade/role.py b/python/rbac/upgrade/role.py
index ff870e2fef..9a93af1aa0 100644
--- a/python/rbac/upgrade/role.py
+++ b/python/rbac/upgrade/role.py
@@ -20,9 +20,9 @@
 from django.utils import timezone
 
 import cm.checker
-from cm.models import ProductCategory, Bundle, Action, get_model_by_type, DummyData
+from cm.models import ProductCategory, Bundle, Action, get_model_by_type, DummyData, Host
 from rbac import log
-from rbac.models import Role, RoleMigration, Policy, Permission, re_apply_all_polices, RoleTypes
+from rbac.models import Role, RoleMigration, Permission, re_apply_all_polices, RoleTypes
 from rbac.settings import api_settings
 
 
@@ -34,14 +34,18 @@ def upgrade(data: dict):
 
     for role in data['roles']:
         role_obj = new_roles[role['name']]
+        task_roles = []
+        for child in role_obj.child.all():
+            if child.class_name == 'TaskRole':
+                task_roles.append(child)
         role_obj.child.clear()
         if 'child' not in role:
             continue
         for child in role['child']:
             child_role = new_roles[child]
             role_obj.child.add(child_role)
+        role_obj.child.add(*task_roles)
         role_obj.save()
-    re_apply_all_polices()
 
 
 def find_role(name: str, roles: list):
@@ -88,7 +92,7 @@ def upgrade_role(role: dict, data: dict) -> Role:
     """Upgrade single role"""
     perm_list = get_role_permissions(role, data['roles'])
     try:
-        new_role = Role.objects.get(name=role['name'])
+        new_role = Role.objects.get(name=role['name'], built_in=True)
         new_role.permissions.clear()
     except Role.DoesNotExist:
         new_role = Role(name=role['name'])
@@ -148,10 +152,24 @@ def get_role_spec(data: str, schema: str) -> dict:
     return data
 
 
+def get_perm(ct, codename, name=None):
+    if name:
+        perm, _ = Permission.objects.get_or_create(
+            content_type=ct,
+            codename=codename,
+            name=name,
+        )
+    else:
+        perm, _ = Permission.objects.get_or_create(
+            content_type=ct,
+            codename=codename,
+        )
+    return perm
+
+
 def prepare_hidden_roles(bundle: Bundle):
     """Prepares hidden roles"""
     hidden_roles = {}
-
     for act in Action.objects.filter(prototype__bundle=bundle):
         name_prefix = f'{act.prototype.type} action:'.title()
         name = f'{name_prefix} {act.display_name}'
@@ -164,7 +182,7 @@ def prepare_hidden_roles(bundle: Bundle):
             f'{bundle.name}_{bundle.version}_{bundle.edition}_{serv_name}'
             f'{act.prototype.type}_{act.prototype.display_name}_{act.name}'
         )
-        role = Role(
+        role, _ = Role.objects.get_or_create(
             name=role_name,
             display_name=role_name,
             description=(
@@ -190,15 +208,26 @@ def prepare_hidden_roles(bundle: Bundle):
         if bundle.category:
             role.category.add(bundle.category)
         ct = ContentType.objects.get_for_model(model)
-        perm, _ = Permission.objects.get_or_create(
-            content_type=ct,
-            codename=f'run_action_{act.display_name}',
-            name=f'Can run {act.display_name} actions',
-        )
-        role.permissions.add(perm)
+        model_name = model.__name__.lower()
+        role.permissions.add(get_perm(ct, f'view_{model_name}'))
         if name not in hidden_roles:
             hidden_roles[name] = {'parametrized_by_type': act.prototype.type, 'children': []}
         hidden_roles[name]['children'].append(role)
+        if act.host_action:
+            ct_host = ContentType.objects.get_for_model(Host)
+            role.permissions.add(get_perm(ct_host, 'view_host'))
+            role.permissions.add(
+                get_perm(
+                    ct_host, f'run_action_{act.display_name}', f'Can run {act.display_name} actions'
+                )
+            )
+        else:
+            role.permissions.add(
+                get_perm(
+                    ct, f'run_action_{act.display_name}', f'Can run {act.display_name} actions'
+                )
+            )
+
     return hidden_roles
 
 
@@ -232,7 +261,6 @@ def prepare_action_roles(bundle: Bundle):
         'Service Administrator': Role.objects.get(name='Service Administrator'),
     }
     hidden_roles = prepare_hidden_roles(bundle)
-
     for business_role_name, business_role_params in hidden_roles.items():
         if business_role_params['parametrized_by_type'] == 'component':
             parametrized_by_type = ['service', 'component']
@@ -256,15 +284,11 @@ def prepare_action_roles(bundle: Bundle):
         update_built_in_roles(bundle, business_role, parametrized_by_type, built_in_roles)
 
 
-def create_default_policy():
-    policy_name = 'default'
-    role = Role.objects.get(name='Base role')
-    try:
-        policy = Policy.objects.get(name=policy_name)
-        policy.role = role
-        policy.save()
-    except Policy.DoesNotExist:
-        Policy.objects.create(name=policy_name, role_id=role.id, built_in=True)
+def update_all_bundle_roles():
+    for bundle in Bundle.objects.exclude(name='ADCM'):
+        prepare_action_roles(bundle)
+        msg = f'Prepare roles for "{bundle.name}" bundle.'
+        log.info(msg)
 
 
 def init_roles():
@@ -280,19 +304,15 @@ def init_roles():
     if rm is None:
         rm = RoleMigration(version=0)
     if role_data['version'] > rm.version:
-        upgrade(role_data)
-        rm.version = role_data['version']
-        rm.save()
-        create_default_policy()
-        msg = f'Roles are upgraded to version {rm.version}'
-        log.info(msg)
+        with transaction.atomic():
+            upgrade(role_data)
+            rm.version = role_data['version']
+            rm.save()
+            update_all_bundle_roles()
+            re_apply_all_polices()
+            msg = f'Roles are upgraded to version {rm.version}'
+            log.info(msg)
     else:
         msg = f'Roles are already at version {rm.version}'
 
-    for bundle in Bundle.objects.exclude(name='ADCM'):
-        if not Role.objects.filter(bundle=bundle, type=RoleTypes.hidden).exists():
-            prepare_action_roles(bundle)
-            msg = f'Prepare roles for "{bundle.name}" bundle.'
-            log.info(msg)
-
     return msg
diff --git a/python/rbac/upgrade/role_schema.yaml b/python/rbac/upgrade/role_schema.yaml
index 536077ec31..b08f94921c 100644
--- a/python/rbac/upgrade/role_schema.yaml
+++ b/python/rbac/upgrade/role_schema.yaml
@@ -46,6 +46,7 @@ class_name:
     - ModelRole
     - ObjectRole
     - ParentRole
+    - ConfigRole
 
 type:
   match: set
diff --git a/python/rbac/upgrade/role_spec.yaml b/python/rbac/upgrade/role_spec.yaml
index 19778a7565..e32e871f72 100644
--- a/python/rbac/upgrade/role_spec.yaml
+++ b/python/rbac/upgrade/role_spec.yaml
@@ -1,11 +1,37 @@
 ---
 
-version: 1
+version: 4
 
 roles:
-    - name: Create host
+    - name: Add host
       description: The ability to add new host
-      type: business
+      type: hidden
+      module_name: rbac.roles
+      class_name: ModelRole
+      apps:
+        - label: cm
+          models:
+            - name: host
+              codenames:
+                - add
+
+    - name: Delete host
+      description: The ability to delete host
+      type: hidden
+      module_name: rbac.roles
+      class_name: ObjectRole
+      parametrized_by:
+        - host
+      apps:
+        - label: cm
+          models:
+            - name: host
+              codenames:
+                - delete
+
+    - name: Add host to provider
+      description: The ability to add host to provider
+      type: hidden
       module_name: rbac.roles
       class_name: ObjectRole
       parametrized_by:
@@ -13,14 +39,27 @@ roles:
       init_params:
         app_name: cm
         model: HostProvider
-      any_category: true
       apps:
         - label: cm
           models:
             - name: hostprovider
               codenames:
+                - view
                 - add_host_to
 
+    - name: Create host
+      description: The ability to add new host
+      type: business
+      module_name: rbac.roles
+      class_name: ParentRole
+      parametrized_by:
+        - provider
+      any_category: false
+      child:
+        - Add host
+        - Add host to provider
+        - Get host object
+
     - name: Create provider
       description: The ability to add new provider
       type: business
@@ -32,6 +71,7 @@ roles:
           models:
             - name: hostprovider
               codenames:
+                - view
                 - add
 
     - name: Create cluster
@@ -45,6 +85,7 @@ roles:
           models:
             - name: cluster
               codenames:
+                - view
                 - add
 
     - name: Accept license
@@ -93,16 +134,19 @@ roles:
       parametrized_by:
         - cluster
       module_name: rbac.roles
-      class_name: ObjectRole
-      init_params:
-        app_name: cm
-        model: Cluster
+      class_name: ConfigRole
       apps:
         - label: cm
           models:
-            - name: cluster
+            - name: objectconfig
+              codenames:
+                - view
+            - name: configlog
               codenames:
-                - view_config_of
+                - view
+            - name: groupconfig
+              codenames:
+                - view
 
     - name: View cluster configurations
       description: The ability to view the cluster configuration page
@@ -111,13 +155,13 @@ roles:
         - cluster
       module_name: rbac.roles
       class_name: ParentRole
+      any_category: true
       init_params:
         app_name: cm
         model: Cluster
       child:
+        - Get cluster object
         - View cluster config
-        - View config endpoints
-
 
     - name: View service config
       description: The ability to view the service configuration page
@@ -125,16 +169,19 @@ roles:
       parametrized_by:
         - service
       module_name: rbac.roles
-      class_name: ObjectRole
-      init_params:
-        app_name: cm
-        model: ClusterObject
+      class_name: ConfigRole
       apps:
         - label: cm
           models:
-            - name: clusterobject
+            - name: objectconfig
+              codenames:
+                - view
+            - name: configlog
               codenames:
-                - view_config_of
+                - view
+            - name: groupconfig
+              codenames:
+                - view
 
     - name: View service configurations
       description: The ability to view the service configuration page
@@ -143,12 +190,13 @@ roles:
         - service
       module_name: rbac.roles
       class_name: ParentRole
+      any_category: true
       init_params:
         app_name: cm
         model: ClusterObject
       child:
+        - Get service object
         - View service config
-        - View config endpoints
 
     - name: View component config
       description: The ability to view the component configuration page
@@ -156,16 +204,19 @@ roles:
       parametrized_by:
         - component
       module_name: rbac.roles
-      class_name: ObjectRole
-      init_params:
-        app_name: cm
-        model: ServiceComponent
+      class_name: ConfigRole
       apps:
         - label: cm
           models:
-            - name: servicecomponent
+            - name: objectconfig
               codenames:
-                - view_config_of
+                - view
+            - name: configlog
+              codenames:
+                - view
+            - name: groupconfig
+              codenames:
+                - view
 
     - name: View component configurations
       description: The ability to view the component configuration page
@@ -175,12 +226,14 @@ roles:
         - component
       module_name: rbac.roles
       class_name: ParentRole
+      any_category: true
       init_params:
         app_name: cm
         model: ServiceComponent
       child:
+        - Get service object
+        - Get component object
         - View component config
-        - View config endpoints
 
     - name: View provider config
       description: The ability to view the provider configuration page
@@ -188,16 +241,19 @@ roles:
       parametrized_by:
         - provider
       module_name: rbac.roles
-      class_name: ObjectRole
-      init_params:
-        app_name: cm
-        model: HostProvider
+      class_name: ConfigRole
       apps:
         - label: cm
           models:
-            - name: hostprovider
+            - name: objectconfig
+              codenames:
+                - view
+            - name: configlog
+              codenames:
+                - view
+            - name: groupconfig
               codenames:
-                - view_config_of
+                - view
 
     - name: View provider configurations
       description: The ability to view the provider configuration page
@@ -206,12 +262,13 @@ roles:
         - provider
       module_name: rbac.roles
       class_name: ParentRole
+      any_category: false
       init_params:
         app_name: cm
         model: HostProvider
       child:
+        - Get provider object
         - View provider config
-        - View config endpoints
 
     - name: View host config
       description: The ability to view the host configuration page
@@ -219,16 +276,19 @@ roles:
       parametrized_by:
         - host
       module_name: rbac.roles
-      class_name: ObjectRole
-      init_params:
-        app_name: cm
-        model: Host
+      class_name: ConfigRole
       apps:
         - label: cm
           models:
-            - name: host
+            - name: objectconfig
               codenames:
-                - view_config_of
+                - view
+            - name: configlog
+              codenames:
+                - view
+            - name: groupconfig
+              codenames:
+                - view
 
     - name: View host configurations
       description: The ability to view the host configuration page
@@ -237,42 +297,68 @@ roles:
         - host
       module_name: rbac.roles
       class_name: ParentRole
+      any_category: false
       init_params:
         app_name: cm
         model: Host
       child:
+        - Get host object
         - View host config
-        - View config endpoints
 
-    - name: View config endpoints
-      description: The ability to view list of all configs separatly
-      type: hidden
+    - name: View any object configuration
+      description: The ability to view config page of all objects except ADCM settings
+      type: business
       module_name: rbac.roles
       class_name: ModelRole
+      any_category: false
       apps:
-      - label: cm
-        models:
-          - name: objectconfig
-            codenames:
-              - view
-          - name: configlog
-            codenames:
-              - view
+        - label: cm
+          models:
+            - name: cluster
+              codenames:
+                - view
+            - name: clusterobject
+              codenames:
+                - view
+            - name: servicecomponent
+              codenames:
+                - view
+            - name: host
+              codenames:
+                - view
+            - name: hostprovider
+              codenames:
+                - view
+            - name: objectconfig
+              codenames:
+                - view
+            - name: configlog
+              codenames:
+                - view
+            - name: groupconfig
+              codenames:
+                - view
 
-    - name: View any object configuration
-      description: The ability to view config page of all objects except ADCM settings
-      type: business
+    - name: Edit config
+      description: The abiluty to change and add configuration
+      type: hidden
       module_name: rbac.roles
       class_name: ModelRole
-      any_category: true
-      child:
-        - View config endpoints
       apps:
         - label: cm
           models:
-            - name: adcm
+            - name: objectconfig
+              codenames:
+                - change
+            - name: configlog
+              codenames:
+                - add
+                - change
+            - name: groupconfig
               codenames:
-                - view_config_of
+                - add
+                - change
+                - delete
 
     - name: Edit cluster config
       description: The ability to change and add new cluster configuration
@@ -289,7 +375,6 @@ roles:
           models:
             - name: cluster
               codenames:
-                - view_config_of
                 - change_config_of
 
     - name: Edit cluster configurations
@@ -299,12 +384,15 @@ roles:
         - cluster
       module_name: rbac.roles
       class_name: ParentRole
+      any_category: true
       init_params:
         app_name: cm
         model: Cluster
       child:
+        - Get cluster object
+        - View cluster config
+        - Edit config
         - Edit cluster config
-        - Edit config endpoints
 
     - name: Edit service config
       description: The ability to change and add new service configuration
@@ -321,7 +409,6 @@ roles:
           models:
             - name: clusterobject
               codenames:
-                - view_config_of
                 - change_config_of
 
     - name: Edit service configurations
@@ -331,12 +418,15 @@ roles:
         - service
       module_name: rbac.roles
       class_name: ParentRole
+      any_category: true
       init_params:
         app_name: cm
         model: ClusterObject
       child:
+        - Get service object
+        - View service config
+        - Edit config
         - Edit service config
-        - Edit config endpoints
 
     - name: Edit component config
       description: The ability to change and add new component configuration
@@ -353,7 +443,6 @@ roles:
           models:
             - name: servicecomponent
               codenames:
-                - view_config_of
                 - change_config_of
 
     - name: Edit component configurations
@@ -364,12 +453,15 @@ roles:
         - component
       module_name: rbac.roles
       class_name: ParentRole
+      any_category: true
       init_params:
         app_name: cm
         model: ServiceComponent
       child:
+        - Get component object
+        - View component config
+        - Edit config
         - Edit component config
-        - Edit config endpoints
 
     - name: Edit provider config
       description: The ability to change and add new provider configuration
@@ -386,7 +478,6 @@ roles:
           models:
             - name: hostprovider
               codenames:
-                - view_config_of
                 - change_config_of
 
     - name: Edit provider configurations
@@ -396,12 +487,15 @@ roles:
         - provider
       module_name: rbac.roles
       class_name: ParentRole
+      any_category: false
       init_params:
         app_name: cm
         model: HostProvider
       child:
+        - Get provider object
+        - View provider config
+        - Edit config
         - Edit provider config
-        - Edit config endpoints
 
     - name: Edit host config
       description: The ability to change and add new host configuration
@@ -418,7 +512,6 @@ roles:
           models:
             - name: host
               codenames:
-                - view_config_of
                 - change_config_of
 
     - name: Edit host configurations
@@ -428,29 +521,15 @@ roles:
         - host
       module_name: rbac.roles
       class_name: ParentRole
+      any_category: false
       init_params:
         app_name: cm
         model: Host
       child:
+        - Get host object
+        - View host config
+        - Edit config
         - Edit host config
-        - Edit config endpoints
-
-    - name: Edit config endpoints
-      description: The ability to edit list of all configs separatly
-      type: hidden
-      module_name: rbac.roles
-      class_name: ModelRole
-      apps:
-        - label: cm
-          models:
-            - name: objectconfig
-              codenames:
-                - view
-                - change
-            - name: configlog
-              codenames:
-                - view
-                - change
 
     - name: View cluster imports
       description: The ability to view the cluster import page
@@ -496,6 +575,8 @@ roles:
       class_name: ParentRole
       any_category: true
       child:
+        - Get cluster object
+        - Get service object
         - View cluster imports
         - View service imports
 
@@ -504,13 +585,19 @@ roles:
       type: business
       module_name: rbac.roles
       class_name: ModelRole
-      any_category: true
+      any_category: false
       apps:
         - label: cm
           models:
             - name: clusterbind
               codenames:
                 - view
+            - name: cluster
+              codenames:
+                - view
+            - name: clusterobject
+              codenames:
+                - view
 
     - name: Manage cluster imports
       description: The ability to change cluster imports
@@ -558,12 +645,26 @@ roles:
         - cluster
         - service
       child:
+        - Get cluster object
+        - Get service object
         - Manage cluster imports
         - Manage service imports
 
-    - name: Add service
+    - name: Create service
+      description: The ability to add new service
+      type: hidden
+      module_name: rbac.roles
+      class_name: ModelRole
+      apps:
+        - label: cm
+          models:
+            - name: clusterobject
+              codenames:
+                - add
+
+    - name: Add service hidden
       description: The ability to add service to cluster
-      type: business
+      type: hidden
       parametrized_by:
         - cluster
       module_name: rbac.roles
@@ -571,13 +672,26 @@ roles:
       init_params:
         app_name: cm
         model: Cluster
-      any_category: true
       apps:
         - label: cm
           models:
             - name: cluster
               codenames:
                 - add_service_to
+                - view
+
+    - name: Add service
+      description: The ability to add service to cluster
+      type: business
+      parametrized_by:
+        - cluster
+      module_name: rbac.roles
+      class_name: ParentRole
+      any_category: true
+      child:
+        - Create service
+        - Add service hidden
+        - Get service object
 
     - name: Remove service
       description: The ability to remove service from cluster
@@ -595,30 +709,42 @@ roles:
           models:
             - name: clusterobject
               codenames:
+                - view
                 - delete
 
-    - name: Remove hosts
-      description: The ability to remove hosts
-      type: business
+    - name: Remove hosts hidden
+      display_name: Remove hosts hidden
+      description: The ability to remove host hidden
+      type: hidden
       parametrized_by:
         - host
       module_name: rbac.roles
       class_name: ObjectRole
-      init_params:
-        app_name: cm
-        model: Host
-      any_category: true
       apps:
         - label: cm
           models:
             - name: host
               codenames:
-                - delete
+                - remove
 
-    - name: Map hosts
-      display_name: Add hosts to the Cluster
-      description: The ability to map hosts to the Cluster
+    - name: Remove hosts
+      display_name: Remove host
+      description: The ability to remove host
       type: business
+      parametrized_by:
+        - host
+      module_name: rbac.roles
+      class_name: ParentRole
+      any_category: true
+      child:
+        - Get host object
+        - Delete host
+        - Remove hosts hidden
+
+    - name: Map hosts hidden
+      display_name: Add hosts to the Cluster hidden
+      description: The ability to map hosts to the Cluster
+      type: hidden
       parametrized_by:
         - cluster
       module_name: rbac.roles
@@ -626,83 +752,145 @@ roles:
       init_params:
         app_name: cm
         model: Cluster
-      any_category: true
       apps:
         - label: cm
           models:
             - name: cluster
               codenames:
+                - view
                 - map_host_to
 
-    - name: Unmap hosts
-      display_name: Remove hosts from the Cluster
-      description: The ability to unmap hosts to the Cluster
+    - name: Map hosts
+      display_name: Add hosts to the Cluster
+      description: The ability to map hosts to the Cluster
       type: business
       parametrized_by:
         - cluster
       module_name: rbac.roles
+      class_name: ParentRole
+      any_category: true
+      child:
+        - Add host
+        - Get host
+        - Map hosts hidden
+
+    - name: Unmap hosts hidden
+      display_name: Remove hosts from the Cluster hidden
+      description: The ability to unmap hosts from the Cluster
+      type: hidden
+      parametrized_by:
+        - cluster
+      module_name: rbac.roles
       class_name: ObjectRole
       init_params:
         app_name: cm
         model: Cluster
-      any_category: true
       apps:
         - label: cm
           models:
             - name: cluster
               codenames:
+                - view
                 - unmap_host_from
 
-    - name: View host-components
-      description: The ability to view exact cluster's host-component page
+    - name: Unmap hosts
+      display_name: Remove hosts from the Cluster
+      description: The ability to unmap hosts from the Cluster
       type: business
       parametrized_by:
         - cluster
       module_name: rbac.roles
-      class_name: ObjectRole
-      init_params:
-        app_name: cm
-        model: Cluster
+      class_name: ParentRole
       any_category: true
+      child:
+        - Get host object
+        - Delete host
+        - Unmap hosts hidden
+
+    - name: View host-components hidden
+      description: The ability to view exact cluster's host-component page
+      type: hidden
+      parametrized_by:
+        - cluster
+      module_name: rbac.roles
+      class_name: ObjectRole
       apps:
         - label: cm
           models:
             - name: cluster
               codenames:
+                - view
                 - view_host_components_of
 
+    - name: View host-components
+      description: The ability to view exact cluster's host-component page
+      type: business
+      parametrized_by:
+        - cluster
+      module_name: rbac.roles
+      class_name: ParentRole
+      any_category: true
+      child:
+        - Get service object
+        - Get component object
+        - Get host object
+        - View host-components hidden
+
     - name: View any object host-components
       description: The ability to view host-components page of all clusters
       type: business
       module_name: rbac.roles
       class_name: ModelRole
-      any_category: true
+      any_category: false
       apps:
         - label: cm
           models:
+            - name: cluster
+              codenames:
+                - view
+            - name: clusterobject
+              codenames:
+                - view
+            - name: servicecomponent
+              codenames:
+                - view
+            - name: host
+              codenames:
+                - view
             - name: hostcomponent
               codenames:
                 - view
 
-    - name: Edit host-components
+    - name: Edit host-components hidden
       description: The ability to edit exact cluster's host-component page
-      type: business
+      type: hidden
       parametrized_by:
         - cluster
       module_name: rbac.roles
       class_name: ObjectRole
-      init_params:
-        app_name: cm
-        model: Cluster
-      any_category: true
       apps:
         - label: cm
           models:
             - name: cluster
               codenames:
-                - view_host_components_of
                 - edit_host_components_of
 
+    - name: Edit host-components
+      description: The ability to edit exact cluster's host-component page
+      type: business
+      parametrized_by:
+        - cluster
+      module_name: rbac.roles
+      class_name: ParentRole
+      any_category: true
+      child:
+        - Get cluster object
+        - Get service object
+        - Get component object
+        - Get host object
+        - View host-components hidden
+        - Edit host-components hidden
+
     - name: Upgrade cluster bundle
       description: Update the cluster bundle
       type: business
@@ -710,6 +898,7 @@ roles:
         - cluster
       module_name: rbac.roles
       class_name: ObjectRole
+      any_category: true
       init_params:
         app_name: cm
         model: Cluster
@@ -718,6 +907,7 @@ roles:
           models:
             - name: cluster
               codenames:
+                - view
                 - view_upgrade_of
                 - do_upgrade_of
 
@@ -728,6 +918,7 @@ roles:
         - provider
       module_name: rbac.roles
       class_name: ObjectRole
+      any_category: false
       init_params:
         app_name: cm
         model: HostProvider
@@ -736,6 +927,7 @@ roles:
           models:
             - name: hostprovider
               codenames:
+                - view
                 - view_upgrade_of
                 - do_upgrade_of
 
@@ -755,6 +947,7 @@ roles:
           models:
             - name: cluster
               codenames:
+                - view
                 - delete
 
     - name: Remove provider
@@ -773,6 +966,7 @@ roles:
           models:
             - name: hostprovider
               codenames:
+                - view
                 - delete
 
     - name: Remove bundle
@@ -814,6 +1008,13 @@ roles:
               codenames:
                 - view_settings_of
                 - change_settings_of
+            - name: objectconfig
+              codenames:
+                - change
+            - name: configlog
+              codenames:
+                - add
+                - change
 
     - name: View users
       description: The ability to view Users page
@@ -834,13 +1035,12 @@ roles:
       module_name: rbac.roles
       class_name: ModelRole
       any_category: false
-      child:
-        - View users
       apps:
         - label: rbac
           models:
             - name: user
               codenames:
+                - view
                 - add
 
     - name: Edit user
@@ -849,13 +1049,12 @@ roles:
       module_name: rbac.roles
       class_name: ModelRole
       any_category: false
-      child:
-        - View users
       apps:
         - label: rbac
           models:
             - name: user
               codenames:
+                - view
                 - change
 
     - name: Remove user
@@ -864,13 +1063,12 @@ roles:
       module_name: rbac.roles
       class_name: ModelRole
       any_category: false
-      child:
-        - View users
       apps:
         - label: rbac
           models:
             - name: user
               codenames:
+                - view
                 - delete
 
     - name: View roles
@@ -892,13 +1090,12 @@ roles:
       module_name: rbac.roles
       class_name: ModelRole
       any_category: false
-      child:
-        - View roles
       apps:
         - label: rbac
           models:
             - name: role
               codenames:
+                - view
                 - add
 
     - name: Edit role
@@ -907,13 +1104,12 @@ roles:
       module_name: rbac.roles
       class_name: ModelRole
       any_category: false
-      child:
-        - View roles
       apps:
         - label: rbac
           models:
             - name: role
               codenames:
+                - view
                 - change
 
     - name: Remove roles
@@ -922,13 +1118,12 @@ roles:
       module_name: rbac.roles
       class_name: ModelRole
       any_category: false
-      child:
-        - View roles
       apps:
         - label: rbac
           models:
             - name: role
               codenames:
+                - view
                 - delete
 
     - name: View group
@@ -950,13 +1145,12 @@ roles:
       module_name: rbac.roles
       class_name: ModelRole
       any_category: false
-      child:
-        - View group
       apps:
         - label: rbac
           models:
             - name: group
               codenames:
+                - view
                 - add
 
     - name: Edit group
@@ -965,13 +1159,12 @@ roles:
       module_name: rbac.roles
       class_name: ModelRole
       any_category: false
-      child:
-        - View group
       apps:
         - label: rbac
           models:
             - name: group
               codenames:
+                - view
                 - change
 
     - name: Remove group
@@ -980,13 +1173,12 @@ roles:
       module_name: rbac.roles
       class_name: ModelRole
       any_category: false
-      child:
-        - View group
       apps:
         - label: rbac
           models:
             - name: group
               codenames:
+                - view
                 - delete
 
     - name: View policy
@@ -1008,13 +1200,12 @@ roles:
       module_name: rbac.roles
       class_name: ModelRole
       any_category: false
-      child:
-        - View policy
       apps:
         - label: rbac
           models:
             - name: policy
               codenames:
+                - view
                 - add
 
     - name: Edit policy
@@ -1023,13 +1214,12 @@ roles:
       module_name: rbac.roles
       class_name: ModelRole
       any_category: false
-      child:
-        - View policy
       apps:
         - label: rbac
           models:
             - name: policy
               codenames:
+                - view
                 - change
 
     - name: Remove policy
@@ -1038,48 +1228,37 @@ roles:
       module_name: rbac.roles
       class_name: ModelRole
       any_category: false
-      child:
-        - View policy
       apps:
         - label: rbac
           models:
             - name: policy
               codenames:
+                - view
                 - delete
 
-    - name: Base role
-      description: Default list of view permissions for all objects
-      type: hidden
-      module_name: rbac.roles
-      class_name: ParentRole
-      child:
-        - Get ADCM object
-        - Get provider
-        - Get cluster
-        - Get host
-        - Get service
-        - Get component
-        - Get task and jobs
-        - Get stack
-        - Get concerns
-
-    - name: Get ADCM object
-      description: Read access to ADCM
+    - name: Get provider
+      display_name: Get all providers
+      description: Read access to all Providers
       type: hidden
       module_name: rbac.roles
       class_name: ModelRole
       apps:
         - label: cm
           models:
-            - name: adcm
+            - name: hostprovider
               codenames:
                 - view
 
-    - name: Get provider
+    - name: Get provider object
       description: Read access to Provider
       type: hidden
       module_name: rbac.roles
-      class_name: ModelRole
+      class_name: ObjectRole
+      parametrized_by:
+        - provider
+      init_params:
+        app_name: cm
+        model: HostProvider
       apps:
         - label: cm
           models:
@@ -1088,7 +1267,8 @@ roles:
                 - view
 
     - name: Get cluster
-      description: Read access to Clusters
+      display_name: Get all clusters
+      description: Read access to all Clusters
       type: hidden
       module_name: rbac.roles
       class_name: ModelRole
@@ -1099,96 +1279,129 @@ roles:
               codenames:
                 - view
 
-    - name: Get host
-      description: Read access to Host
+    - name: Get cluster object
+      description: Read access to Cluster
       type: hidden
       module_name: rbac.roles
-      class_name: ModelRole
+      class_name: ObjectRole
+      parametrized_by:
+        - cluster
+      init_params:
+        app_name: cm
+        model: Cluster
       apps:
         - label: cm
           models:
-            - name: host
+            - name: cluster
               codenames:
                 - view
 
-    - name: Get service
-      description: Read access to Service
+    - name: Get host
+      display_name: Get all hosts
+      description: Read access to all Hosts
       type: hidden
       module_name: rbac.roles
       class_name: ModelRole
       apps:
         - label: cm
           models:
-            - name: clusterobject
+            - name: host
               codenames:
                 - view
 
-    - name: Get component
-      description: Read access to Component
+    - name: Get host object
+      description: Read access to Host
       type: hidden
       module_name: rbac.roles
-      class_name: ModelRole
+      class_name: ObjectRole
+      parametrized_by:
+        - host
+      init_params:
+        app_name: cm
+        model: Host
       apps:
         - label: cm
           models:
-            - name: servicecomponent
+            - name: host
               codenames:
                 - view
 
-    - name: Get task and jobs
-      description: Read access to job execution information
+    - name: Get service
+      display_name: Get all services
+      description: Read access to all Services
       type: hidden
       module_name: rbac.roles
       class_name: ModelRole
       apps:
         - label: cm
           models:
-            - name: tasklog
-              codenames:
-                - view
-            - name: joblog
+            - name: clusterobject
               codenames:
                 - view
-            - name: logstorage
+
+    - name: Get service object
+      description: Read access to Service
+      type: hidden
+      module_name: rbac.roles
+      class_name: ObjectRole
+      parametrized_by:
+        - service
+      init_params:
+        app_name: cm
+        model: ClusterObject
+      apps:
+        - label: cm
+          models:
+            - name: clusterobject
               codenames:
                 - view
 
-    - name: Get stack
-      description: Read access to all prototypes
+    - name: Get component
+      display_name: Get all components
+      description: Read access to all Components
       type: hidden
       module_name: rbac.roles
       class_name: ModelRole
       apps:
         - label: cm
           models:
-            - name: prototype
-              codenames:
-                - view
-            - name: bundle
-              codenames:
-                - view
-            - name: action
-              codenames:
-                - view
-            - name: prototypeconfig
-              codenames:
-                - view
-            - name: prototypeexport
+            - name: servicecomponent
               codenames:
                 - view
-            - name: prototypeimport
+
+    - name: Get component object
+      description: Read access to Component
+      type: hidden
+      module_name: rbac.roles
+      class_name: ObjectRole
+      parametrized_by:
+        - component
+      init_params:
+        app_name: cm
+        model: ServiceComponent
+      apps:
+        - label: cm
+          models:
+            - name: servicecomponent
               codenames:
                 - view
 
-    - name: Get concerns
-      description: Read access to all concerns
+    - name: Get task and jobs
+      display_name: Get all tasks and jobs
+      description: Read access to all job execution information
       type: hidden
       module_name: rbac.roles
       class_name: ModelRole
       apps:
         - label: cm
           models:
-            - name: concernitem
+            - name: tasklog
+              codenames:
+                - view
+            - name: joblog
+              codenames:
+                - view
+            - name: logstorage
               codenames:
                 - view
 
@@ -1197,6 +1410,12 @@ roles:
       module_name: rbac.roles
       class_name: ParentRole
       child:
+        - Get provider
+        - Get cluster
+        - Get host
+        - Get service
+        - Get component
+        - Get task and jobs
         - View any object host-components
         - View any object configuration
         - View any object import
@@ -1211,11 +1430,14 @@ roles:
       module_name: rbac.roles
       class_name: ParentRole
       child:
+        - Get service object
+        - Get component object
+        - Get host object
         - View host configurations
         - Edit service configurations
         - Edit component configurations
         - View host-components
-        - Manage imports
+        - Manage service imports
 
     - name: Cluster Administrator
       type: role
@@ -1231,6 +1453,7 @@ roles:
         - Edit cluster configurations
         - Edit host configurations
         - Edit host-components
+        - Manage cluster imports
         - Add service
         - Remove service
         - Remove hosts
@@ -1247,10 +1470,12 @@ roles:
         - provider
       init_params:
         app_name: cm
-        model: Cluster
+        model: HostProvider
       module_name: rbac.roles
       class_name: ParentRole
       child:
+        - Get provider object
+        - Get host object
         - Edit provider configurations
         - Edit host configurations
         - Upgrade provider bundle
diff --git a/python/rbac/viewsets.py b/python/rbac/viewsets.py
index 44516b6897..bd39e38672 100644
--- a/python/rbac/viewsets.py
+++ b/python/rbac/viewsets.py
@@ -12,69 +12,9 @@
 
 """RBAC Permissions classes"""
 
-from rest_framework import viewsets
-from rest_framework.permissions import DjangoModelPermissions, DjangoObjectPermissions
-from guardian.shortcuts import get_objects_for_user
+from rest_framework.permissions import DjangoObjectPermissions
 
 
-class DjangoModelPerm(DjangoModelPermissions):
-    """
-    Similar to `DjangoModelPermissions`, but adding 'view' permissions.
-    """
-
-    perms_map = {
-        'GET': ['%(app_label)s.view_%(model_name)s'],
-        'OPTIONS': ['%(app_label)s.view_%(model_name)s'],
-        'HEAD': ['%(app_label)s.view_%(model_name)s'],
-        'POST': ['%(app_label)s.add_%(model_name)s'],
-        'PUT': ['%(app_label)s.change_%(model_name)s'],
-        'PATCH': ['%(app_label)s.change_%(model_name)s'],
-        'DELETE': ['%(app_label)s.delete_%(model_name)s'],
-    }
-
-
-class DjangoObjectPerm(DjangoObjectPermissions):
-    """
-    Similar to `DjangoObjectPermissions`, but adding 'view' permissions.
-    """
-
-    perms_map = {
-        'GET': ['%(app_label)s.view_%(model_name)s'],
-        'OPTIONS': ['%(app_label)s.view_%(model_name)s'],
-        'HEAD': ['%(app_label)s.view_%(model_name)s'],
-        'POST': ['%(app_label)s.add_%(model_name)s'],
-        'PUT': ['%(app_label)s.change_%(model_name)s'],
-        'PATCH': ['%(app_label)s.change_%(model_name)s'],
-        'DELETE': ['%(app_label)s.delete_%(model_name)s'],
-    }
-
+class DjangoOnlyObjectPermissions(DjangoObjectPermissions):
     def has_permission(self, request, view):
-        model_cls = self._queryset(view).model
-        model_perms = self.get_required_permissions(request.method, model_cls)
-        objects = get_objects_for_user(request.user, model_perms)
-        if objects:
-            return True
-        return super().has_permission(request, view)
-
-    def has_object_permission(self, request, view, obj):
-        model_cls = self._queryset(view).model
-        user = request.user
-        model_perms = self.get_required_permissions(request.method, model_cls)
-        object_perms = self.get_required_object_permissions(request.method, model_cls)
-        if user.has_perms(object_perms, obj) or user.has_perms(model_perms):
-            return True
-        return False
-
-
-class ModelPermViewSet(viewsets.ModelViewSet):  # pylint: disable=too-many-ancestors
-    """Replace of DRF ModelViewSet with view permission"""
-
-    permission_classes = (DjangoObjectPerm,)
-
-
-class GenericPermViewSet(
-    viewsets.GenericViewSet,
-):
-    """Replace of DRF GenericViewSet with view permission"""
-
-    permission_classes = (DjangoObjectPerm,)
+        return True
diff --git a/web/src/app/core/http-interseptors/auth-interseptor.ts b/web/src/app/core/http-interseptors/auth-interseptor.ts
index 90c3a19715..4e4eaab6a3 100644
--- a/web/src/app/core/http-interseptors/auth-interseptor.ts
+++ b/web/src/app/core/http-interseptors/auth-interseptor.ts
@@ -55,6 +55,7 @@ export class AuthInterceptor implements HttpInterceptor {
         }
 
         /** redirect to previous page if it is present and method === GET */
+        /**
         if (res.status === 403 && request.method === 'GET') {
           const previous = this.routerHistory.previous();
 
@@ -64,6 +65,7 @@ export class AuthInterceptor implements HttpInterceptor {
             this.router.navigate(['/']);
           }
         }
+        */
 
         if (res.status === 500) this.router.navigate(['/500']);
 


Test patch:
diff --git a/pytest.sh b/pytest.sh
index c7b2fa5c00..3433d20616 100755
--- a/pytest.sh
+++ b/pytest.sh
@@ -18,7 +18,7 @@ pip3 install -r requirements-test.txt
 find . -name "*.pyc" -type f -delete
 find . -name "__pycache__" -type d -delete
 { # try
-    pytest tests/api tests/functional tests/ui_tests -s -v -n auto --maxfail 30 \
+    pytest tests/api tests/functional tests/ui_tests -s -v -n auto \
     --showlocals --alluredir ./allure-results/ --durations=20 -p allure_pytest \
     --reruns 2 --remote-executor-host "$SELENOID_HOST" --timeout=1080 "$@" &&
     chmod -R o+xw allure-results
diff --git a/python/rbac/tests/tests_api/test_policy.py b/python/rbac/tests/tests_api/test_policy.py
index 8c1863126c..068cc0a856 100644
--- a/python/rbac/tests/tests_api/test_policy.py
+++ b/python/rbac/tests/tests_api/test_policy.py
@@ -112,49 +112,49 @@ def test_create_policy(admin_api_client):
             },
         ),
         (
-            {"name": "test", "role": {"id": 1}},
+            {"name": "test", "role": {"id": 5}},
             {
                 "role": ["Role with type \"business\" could not be used in policy"],
                 "object": ["This field is required."],
             },
         ),
         (
-            {"name": "test", "role": {"id": 5}},
+            {"name": "test", "role": {"id": 1}},
             {
                 "role": ["Role with type \"hidden\" could not be used in policy"],
                 "object": ["This field is required."],
             },
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": None},
+            {"name": "test", "role": {"id": 90}, "user": None},
             {
                 "user": ["This field may not be null."],
                 "object": ["This field is required."],
             },
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": 1},
+            {"name": "test", "role": {"id": 90}, "user": 1},
             {
                 "user": {"non_field_errors": ["Expected a list of items but got type \"int\"."]},
                 "object": ["This field is required."],
             },
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": "string"},
+            {"name": "test", "role": {"id": 90}, "user": "string"},
             {
                 "user": {"non_field_errors": ["Expected a list of items but got type \"str\"."]},
                 "object": ["This field is required."],
             },
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": {}},
+            {"name": "test", "role": {"id": 90}, "user": {}},
             {
                 "user": {"non_field_errors": ["Expected a list of items but got type \"dict\"."]},
                 "object": ["This field is required."],
             },
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [1]},
+            {"name": "test", "role": {"id": 90}, "user": [1]},
             {
                 "user": [
                     {"non_field_errors": ["Invalid data. Expected a dictionary, but got int."]}
@@ -163,7 +163,7 @@ def test_create_policy(admin_api_client):
             },
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": ["string"]},
+            {"name": "test", "role": {"id": 90}, "user": ["string"]},
             {
                 "user": [
                     {"non_field_errors": ["Invalid data. Expected a dictionary, but got str."]}
@@ -172,63 +172,63 @@ def test_create_policy(admin_api_client):
             },
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [{}]},
+            {"name": "test", "role": {"id": 90}, "user": [{}]},
             {
                 "user": [{"id": ["This field is required."]}],
                 "object": ["This field is required."],
             },
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [{"id": None}]},
+            {"name": "test", "role": {"id": 90}, "user": [{"id": None}]},
             {
                 "user": [{"id": ["This field may not be null."]}],
                 "object": ["This field is required."],
             },
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [{"id": "string"}]},
+            {"name": "test", "role": {"id": 90}, "user": [{"id": "string"}]},
             {
                 "user": [{"id": ["Incorrect type. Expected pk value, received str."]}],
                 "object": ["This field is required."],
             },
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [{"id": 1000}]},
+            {"name": "test", "role": {"id": 90}, "user": [{"id": 1000}]},
             {
                 "user": [{"id": ["Invalid pk \"1000\" - object does not exist."]}],
                 "object": ["This field is required."],
             },
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [{"id": 2}], "object": None},
+            {"name": "test", "role": {"id": 90}, "user": [{"id": 2}], "object": None},
             {"object": ["This field may not be null."]},
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [{"id": 2}], "object": 1},
+            {"name": "test", "role": {"id": 90}, "user": [{"id": 2}], "object": 1},
             {"object": ["the field does not match the scheme"]},
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [{"id": 2}], "object": "string"},
+            {"name": "test", "role": {"id": 90}, "user": [{"id": 2}], "object": "string"},
             {"object": ["the field does not match the scheme"]},
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [{"id": 2}], "object": {}},
+            {"name": "test", "role": {"id": 90}, "user": [{"id": 2}], "object": {}},
             {"object": ["the field does not match the scheme"]},
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [{"id": 2}], "object": [1]},
+            {"name": "test", "role": {"id": 90}, "user": [{"id": 2}], "object": [1]},
             {"object": ["the field does not match the scheme"]},
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [{"id": 2}], "object": ["string"]},
+            {"name": "test", "role": {"id": 90}, "user": [{"id": 2}], "object": ["string"]},
             {"object": ["the field does not match the scheme"]},
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [{"id": 2}], "object": [{}]},
+            {"name": "test", "role": {"id": 90}, "user": [{"id": 2}], "object": [{}]},
             {"object": ["the field does not match the scheme"]},
         ),
         (
-            {"name": "test", "role": {"id": 78}, "user": [{"id": 2}], "object": [{"id": 1}]},
+            {"name": "test", "role": {"id": 90}, "user": [{"id": 2}], "object": [{"id": 1}]},
             {"object": ["the field does not match the scheme"]},
         ),
     ]
diff --git a/python/rbac/tests/tests_model/conftest.py b/python/rbac/tests/tests_model/conftest.py
new file mode 100644
index 0000000000..c357ddffaf
--- /dev/null
+++ b/python/rbac/tests/tests_model/conftest.py
@@ -0,0 +1,306 @@
+import pytest
+from django.contrib.auth.models import Permission
+from django.contrib.contenttypes.models import ContentType
+
+from cm.models import (
+    Bundle,
+    Prototype,
+    Cluster,
+    ClusterObject,
+    ServiceComponent,
+    HostProvider,
+    Host,
+)
+from rbac.models import Role, User, Group
+
+
+def cook_role(name, class_name, obj_type=None):
+    if obj_type is None:
+        obj_type = []
+    return Role.objects.create(
+        name=name,
+        display_name=name,
+        module_name='rbac.roles',
+        class_name=class_name,
+        parametrized_by_type=obj_type,
+    )
+
+
+def cook_user(name):
+    return User.objects.create(username=name, is_active=True, is_superuser=False)
+
+
+def cook_group(name):
+    return Group.objects.create(name=name)
+
+
+def cook_perm(app, codename, model):
+    content, _ = ContentType.objects.get_or_create(app_label=app, model=model)
+    perm, _ = Permission.objects.get_or_create(codename=f'{codename}_{model}', content_type=content)
+    return perm
+
+
+def get_bundle(number):
+    bundle, _ = Bundle.objects.get_or_create(name=f'bundle_{number}', version='1.0')
+    return bundle
+
+
+def get_cluster(bundle, number):
+    cp, _ = Prototype.objects.get_or_create(bundle=bundle, type='cluster', name=f'cluster_{number}')
+    cluster, _ = Cluster.objects.get_or_create(name=f'Cluster {number}', prototype=cp)
+    return cluster
+
+
+def get_service(cluster, bundle, number):
+    sp, _ = Prototype.objects.get_or_create(bundle=bundle, type='service', name=f'service_{number}')
+    service, _ = ClusterObject.objects.get_or_create(cluster=cluster, prototype=sp)
+    return service
+
+
+def get_component(cluster, service, bundle, number):
+    cp, _ = Prototype.objects.get_or_create(
+        bundle=bundle, type='component', name=f'component_{number}', parent=service.prototype
+    )
+    component, _ = ServiceComponent.objects.get_or_create(
+        cluster=cluster, service=service, prototype=cp
+    )
+    return component
+
+
+def get_provider():
+    bundle, _ = Bundle.objects.get_or_create(name='provider', version='1.0')
+    pp, _ = Prototype.objects.get_or_create(bundle=bundle, type='provider', name='provider')
+    p, _ = HostProvider.objects.get_or_create(name='provider', prototype=pp)
+    return p, bundle
+
+
+def get_host(b, p, number):
+    hp, _ = Prototype.objects.get_or_create(bundle=b, type='host', name='host')
+    host, _ = Host.objects.get_or_create(prototype=hp, provider=p, fqdn=f'host_{number}')
+    return host
+
+
+@pytest.fixture()
+def bundle1():
+    bundle = get_bundle(1)
+    return bundle
+
+
+@pytest.fixture()
+def cluster1():
+    bundle = get_bundle(1)
+    cluster = get_cluster(bundle, 1)
+    return cluster
+
+
+@pytest.fixture()
+def service1():
+    bundle = get_bundle(1)
+    cluster = get_cluster(bundle, 1)
+    service = get_service(cluster, bundle, 1)
+    return service
+
+
+@pytest.fixture()
+def service2():
+    bundle = get_bundle(1)
+    cluster = get_cluster(bundle, 1)
+    service = get_service(cluster, bundle, 2)
+    return service
+
+
+@pytest.fixture()
+def component11():
+    bundle = get_bundle(1)
+    cluster = get_cluster(bundle, 1)
+    service = get_service(cluster, bundle, 1)
+    component = get_component(cluster, service, bundle, 1)
+    return component
+
+
+@pytest.fixture()
+def component12():
+    bundle = get_bundle(1)
+    cluster = get_cluster(bundle, 1)
+    service = get_service(cluster, bundle, 1)
+    component = get_component(cluster, service, bundle, 2)
+    return component
+
+
+@pytest.fixture()
+def component21():
+    bundle = get_bundle(1)
+    cluster = get_cluster(bundle, 1)
+    service = get_service(cluster, bundle, 2)
+    component = get_component(cluster, service, bundle, 1)
+    return component
+
+
+@pytest.fixture()
+def cluster2():
+    bundle = get_bundle(2)
+    cluster = get_cluster(bundle, 2)
+    return cluster
+
+
+@pytest.fixture()
+def provider():
+    p, _ = get_provider()
+    return p
+
+
+@pytest.fixture()
+def host1():
+    p, bundle = get_provider()
+    host = get_host(bundle, p, 1)
+    return host
+
+
+@pytest.fixture()
+def host2():
+    p, bundle = get_provider()
+    host = get_host(bundle, p, 2)
+    return host
+
+
+@pytest.fixture()
+def host3():
+    p, bundle = get_provider()
+    host = get_host(bundle, p, 3)
+    return host
+
+
+@pytest.fixture
+def object_role():
+    return cook_role('object role', 'ObjectRole')
+
+
+@pytest.fixture()
+def model_role():
+    return cook_role('model role', 'ModelRole')
+
+
+@pytest.fixture()
+def user():
+    return cook_user('user')
+
+
+@pytest.fixture()
+def user1():
+    return cook_user('user1')
+
+
+@pytest.fixture()
+def group():
+    return cook_group('group')
+
+
+@pytest.fixture()
+def group1():
+    return cook_group('group1')
+
+
+@pytest.fixture()
+def add_host_perm():
+    return cook_perm('cm', 'add', 'host')
+
+
+@pytest.fixture()
+def view_cluster_perm():
+    return cook_perm('cm', 'view', 'cluster')
+
+
+@pytest.fixture()
+def object_role_view_perm_cluster():
+    cluster_role = cook_role('view_cluster', 'ObjectRole', ['cluster'])
+    cluster_role.permissions.add(cook_perm('cm', 'view', 'cluster'))
+    role = cook_role('view', 'ParentRole')
+    role.child.add(cluster_role)
+    return role
+
+
+@pytest.fixture()
+def object_role_custom_perm_cluster_service():
+    cluster_role = cook_role('cluster_change_config', 'ObjectRole', ['cluster'])
+    cluster_role.permissions.add(cook_perm('cm', 'change_config_of', 'cluster'))
+    service_role = cook_role('service_change_config', 'ObjectRole', ['service'])
+    service_role.permissions.add(cook_perm('cm', 'change_config_of', 'clusterobject'))
+    role = cook_role('change_config', 'ParentRole')
+    role.child.add(cluster_role, service_role)
+    return role
+
+
+@pytest.fixture()
+def object_role_custom_perm_cluster_service_component():
+    cluster_role = cook_role('cluster_change_config', 'ObjectRole', ['cluster'])
+    cluster_role.permissions.add(cook_perm('cm', 'change_config_of', 'cluster'))
+    service_role = cook_role('service_change_config', 'ObjectRole', ['service'])
+    service_role.permissions.add(cook_perm('cm', 'change_config_of', 'clusterobject'))
+    component_role = cook_role('component_change_config', 'ObjectRole', ['component'])
+    component_role.permissions.add(cook_perm('cm', 'change_config_of', 'servicecomponent'))
+    role = cook_role('change_config', 'ParentRole')
+    role.child.add(cluster_role, service_role, component_role)
+    return role
+
+
+@pytest.fixture()
+def object_role_custom_perm_service_component_host():
+    service_role = cook_role('service_change_config', 'ObjectRole', ['service'])
+    service_role.permissions.add(cook_perm('cm', 'change_config_of', 'clusterobject'))
+    component_role = cook_role('component_change_config', 'ObjectRole', ['component'])
+    component_role.permissions.add(cook_perm('cm', 'change_config_of', 'servicecomponent'))
+    host_role = cook_role('host_change_config', 'ObjectRole', ['host'])
+    host_role.permissions.add(cook_perm('cm', 'change_config_of', 'host'))
+    role = cook_role('change_config', 'ParentRole')
+    role.child.add(service_role, component_role, host_role)
+    return role
+
+
+@pytest.fixture()
+def object_role_custom_perm_cluster_host():
+    cluster_role = cook_role('cluster_change_config', 'ObjectRole', ['cluster'])
+    cluster_role.permissions.add(cook_perm('cm', 'change_config_of', 'cluster'))
+    host_role = cook_role('host_change_config', 'ObjectRole', ['host'])
+    host_role.permissions.add(cook_perm('cm', 'change_config_of', 'host'))
+    role = cook_role('change_config', 'ParentRole')
+    role.child.add(cluster_role, host_role)
+    return role
+
+
+@pytest.fixture()
+def object_role_custom_perm_cluster_service_component_host():
+    cluster_role = cook_role('cluster_change_config', 'ObjectRole', ['cluster'])
+    cluster_role.permissions.add(cook_perm('cm', 'change_config_of', 'cluster'))
+    service_role = cook_role('service_change_config', 'ObjectRole', ['service'])
+    service_role.permissions.add(cook_perm('cm', 'change_config_of', 'clusterobject'))
+    component_role = cook_role('component_change_config', 'ObjectRole', ['component'])
+    component_role.permissions.add(cook_perm('cm', 'change_config_of', 'servicecomponent'))
+    host_role = cook_role('host_change_config', 'ObjectRole', ['host'])
+    host_role.permissions.add(cook_perm('cm', 'change_config_of', 'host'))
+    role = cook_role('change_config', 'ParentRole')
+    role.child.add(cluster_role, service_role, component_role, host_role)
+    return role
+
+
+@pytest.fixture()
+def object_role_custom_perm_provider_host():
+    provider_role = cook_role('provider_change_config', 'ObjectRole', ['provider'])
+    provider_role.permissions.add(cook_perm('cm', 'change_config_of', 'hostprovider'))
+    host_role = cook_role('host_change_config', 'ObjectRole', ['host'])
+    host_role.permissions.add(cook_perm('cm', 'change_config_of', 'host'))
+    role = cook_role('change_config', 'ParentRole')
+    role.child.add(provider_role, host_role)
+    return role
+
+
+@pytest.fixture()
+def model_role_view_cluster_service_component_perm():
+    cluster_role = cook_role('view_cluster', 'ModelRole')
+    cluster_role.permissions.add(cook_perm('cm', 'view', 'cluster'))
+    service_role = cook_role('view_service', 'ModelRole')
+    service_role.permissions.add(cook_perm('cm', 'view', 'clusterobject'))
+    component_role = cook_role('view_component', 'ModelRole')
+    component_role.permissions.add(cook_perm('cm', 'view', 'servicecomponent'))
+    role = cook_role('view_objects', 'ParentRole')
+    role.child.add(cluster_role, service_role, component_role)
+    return role
diff --git a/python/rbac/tests/tests_model/test_policy.py b/python/rbac/tests/tests_model/test_policy.py
index 026727eb88..893f6120e7 100644
--- a/python/rbac/tests/tests_model/test_policy.py
+++ b/python/rbac/tests/tests_model/test_policy.py
@@ -11,15 +11,12 @@
 # limitations under the License.
 
 import pytest
-
-from django.contrib.contenttypes.models import ContentType
 from adwp_base.errors import AdwpEx
 
-from rbac.models import Role, Policy, User, Group, Permission
-from rbac.roles import ModelRole
-from cm.models import Bundle, Prototype, Action, Cluster, ClusterObject, ServiceComponent
-from cm.models import HostProvider, HostComponent
 from cm import api
+from cm.models import Bundle, Prototype, Action
+from rbac.models import Role, Policy
+from rbac.roles import ModelRole
 
 
 @pytest.mark.django_db
@@ -39,32 +36,6 @@ def test_role_class():
     assert isinstance(obj, ModelRole)
 
 
-def cook_user(name):
-    return User.objects.create(username=name, is_active=True, is_superuser=False)
-
-
-def cook_group(name):
-    return Group.objects.create(name=name)
-
-
-def cook_perm(app, codename, model):
-    content, _ = ContentType.objects.get_or_create(app_label=app, model=model)
-    perm, _ = Permission.objects.get_or_create(codename=f'{codename}_{model}', content_type=content)
-    return perm
-
-
-def cook_role(name, class_name, obj_type=None):
-    if obj_type is None:
-        obj_type = []
-    return Role.objects.create(
-        name=name,
-        display_name=name,
-        module_name='rbac.roles',
-        class_name=class_name,
-        parametrized_by_type=obj_type,
-    )
-
-
 def clear_perm_cache(user):
     if hasattr(user, '_perm_cache'):
         delattr(user, '_perm_cache')
@@ -75,544 +46,502 @@ def clear_perm_cache(user):
 
 
 @pytest.mark.django_db
-def test_model_policy():
-    user = cook_user('Joe')
-    r = cook_role('add', 'ModelRole')
-    perm = cook_perm('adcm', 'add', 'host')
-    r.permissions.add(perm)
+def test_model_policy(user, model_role, add_host_perm):
 
-    p = Policy.objects.create(name='MyPolicy', role=r)
+    model_role.permissions.add(add_host_perm)
+
+    p = Policy.objects.create(name='MyPolicy', role=model_role)
     p.user.add(user)
 
-    assert perm not in user.user_permissions.all()
-    assert not user.has_perm('adcm.add_host')
+    assert add_host_perm not in user.user_permissions.all()
+    assert not user.has_perm('cm.add_host')
     clear_perm_cache(user)
 
     p.apply()
-    assert perm in user.user_permissions.all()
-    assert user.has_perm('adcm.add_host')
+    assert add_host_perm in user.user_permissions.all()
+    assert user.has_perm('cm.add_host')
 
     clear_perm_cache(user)
     p.apply()
-    assert user.has_perm('adcm.add_host')
+    assert user.has_perm('cm.add_host')
 
 
 @pytest.mark.django_db
-def test_model_policy4group():
-    group = cook_group('Ops')
-    user = cook_user('Joe')
+def test_model_policy4group(user, group, model_role, add_host_perm):
     group.user_set.add(user)
+    model_role.permissions.add(add_host_perm)
 
-    r = cook_role('add', 'ModelRole')
-    perm = cook_perm('adcm', 'add', 'host')
-    r.permissions.add(perm)
-
-    p = Policy.objects.create(name='MyPolicy', role=r)
+    p = Policy.objects.create(name='MyPolicy', role=model_role)
     p.group.add(group)
 
-    assert perm not in group.permissions.all()
-    assert not user.has_perm('adcm.add_host')
+    assert add_host_perm not in group.permissions.all()
+    assert not user.has_perm('cm.add_host')
     clear_perm_cache(user)
 
     p.apply()
-    assert perm in group.permissions.all()
-    assert user.has_perm('adcm.add_host')
+    assert add_host_perm in group.permissions.all()
+    assert user.has_perm('cm.add_host')
 
     clear_perm_cache(user)
     p.apply()
-    assert user.has_perm('adcm.add_host')
+    assert user.has_perm('cm.add_host')
 
 
 @pytest.mark.django_db
-def test_object_policy():
-    user = cook_user('Joe')
-    r = cook_role('view', 'ObjectRole')
-    r.permissions.add(cook_perm('cm', 'view', 'bundle'))
+def test_object_policy(user, cluster1, cluster2, object_role_view_perm_cluster):
 
-    p = Policy.objects.create(name='MyPolicy', role=r)
+    p = Policy.objects.create(name='MyPolicy', role=object_role_view_perm_cluster)
     p.user.add(user)
 
-    b1 = Bundle.objects.create(name='ADH', version='1.0')
-    b2 = Bundle.objects.create(name='ADH', version='2.0')
-
-    p.add_object(b1)
-    assert not user.has_perm('cm.view_bundle', b1)
-
-    p.apply()
-
-    assert user.has_perm('cm.view_bundle', b1)
-    assert not user.has_perm('cm.view_bundle', b2)
+    assert not user.has_perm('cm.view_cluster', cluster1)
+    assert not user.has_perm('cm.view_cluster', cluster2)
 
+    p.add_object(cluster1)
     p.apply()
 
-    assert user.has_perm('cm.view_bundle', b1)
-    assert not user.has_perm('cm.view_bundle', b2)
+    assert user.has_perm('cm.view_cluster', cluster1)
+    assert not user.has_perm('cm.view_cluster', cluster2)
 
 
 @pytest.mark.django_db
-def test_object_policy_remove_user():
-    user = cook_user('Joe')
-    r = cook_role('view', 'ObjectRole')
-    r.permissions.add(cook_perm('cm', 'view', 'bundle'))
+def test_object_policy_remove_user(user, cluster1, cluster2, object_role, view_cluster_perm):
 
-    p = Policy.objects.create(name='MyPolicy', role=r)
-    p.user.add(user)
-
-    b1 = Bundle.objects.create(name='ADH', version='1.0')
-    b2 = Bundle.objects.create(name='ADH', version='2.0')
+    object_role.permissions.add(view_cluster_perm)
 
-    p.add_object(b1)
-    assert not user.has_perm('cm.view_bundle', b1)
+    p = Policy.objects.create(name='MyPolicy', role=object_role)
+    p.user.add(user)
+    p.add_object(cluster1)
+    assert not user.has_perm('cm.view_cluster', cluster1)
 
     p.apply()
 
-    assert user.has_perm('cm.view_bundle', b1)
-    assert not user.has_perm('cm.view_bundle', b2)
+    assert user.has_perm('cm.view_cluster', cluster1)
+    assert not user.has_perm('cm.view_cluster', cluster2)
 
     p.user.remove(user)
     p.apply()
 
-    assert not user.has_perm('cm.view_bundle', b1)
-    assert not user.has_perm('cm.view_bundle', b2)
+    assert not user.has_perm('cm.view_cluster', cluster1)
+    assert not user.has_perm('cm.view_cluster', cluster2)
 
 
 @pytest.mark.django_db
-def test_object_policy4group():
-    group = cook_group('Ops')
-    user = cook_user('Joe')
+def test_object_policy4group(user, group, cluster1, cluster2, object_role, view_cluster_perm):
     group.user_set.add(user)
 
-    r = cook_role('view', 'ObjectRole')
-    r.permissions.add(cook_perm('cm', 'view', 'bundle'))
+    object_role.permissions.add(view_cluster_perm)
 
-    p = Policy.objects.create(name='MyPolicy', role=r)
+    p = Policy.objects.create(name='MyPolicy', role=object_role)
     p.group.add(group)
 
-    b1 = Bundle.objects.create(name='ADH', version='1.0')
-    b2 = Bundle.objects.create(name='ADH', version='2.0')
-
-    p.add_object(b1)
-    assert not user.has_perm('cm.view_bundle', b1)
+    p.add_object(cluster1)
+    assert not user.has_perm('cm.view_cluster', cluster1)
 
     p.apply()
 
-    assert user.has_perm('cm.view_bundle', b1)
-    assert not user.has_perm('cm.view_bundle', b2)
-
-    p.apply()
-
-    assert user.has_perm('cm.view_bundle', b1)
-    assert not user.has_perm('cm.view_bundle', b2)
-
-
-def cook_conf_role():
-    r_cluster = cook_role('cluster_conf', 'ObjectRole', ['cluster'])
-    r_cluster.permissions.add(cook_perm('cm', 'edit_conf', 'cluster'))
-
-    r_service = cook_role('service_conf', 'ObjectRole', ['service'])
-    r_service.permissions.add(cook_perm('cm', 'edit_conf', 'clusterobject'))
-
-    r_comp = cook_role('component_conf', 'ObjectRole', ['component'])
-    r_comp.permissions.add(cook_perm('cm', 'edit_conf', 'servicecomponent'))
-
-    r_provider = cook_role('provider_conf', 'ObjectRole', ['provider'])
-    r_provider.permissions.add(cook_perm('cm', 'edit_conf', 'hostprovider'))
-
-    r_host = cook_role('host_conf', 'ObjectRole', ['host'])
-    r_host.permissions.add(cook_perm('cm', 'edit_conf', 'host'))
-
-    r = cook_role('all_conf', 'ParentRole')
-    r.child.add(r_cluster, r_service, r_comp, r_provider, r_host)
-
-    return r
-
-
-def cook_cluster1():
-    b = Bundle.obj.create(name='Adh', version='1.0')
-    cp = Prototype.obj.create(bundle=b, type='cluster', name='ADH')
-    cluster = Cluster.obj.create(name='Yukon', prototype=cp)
-
-    sp1 = Prototype.obj.create(bundle=b, type='service', name='Hadoop')
-    service1 = ClusterObject.obj.create(cluster=cluster, prototype=sp1)
-    cp11 = Prototype.obj.create(bundle=b, type='component', name='server')
-    comp11 = ServiceComponent.obj.create(cluster=cluster, service=service1, prototype=cp11)
-    cp12 = Prototype.obj.create(bundle=b, type='component', name='node')
-    comp12 = ServiceComponent.obj.create(cluster=cluster, service=service1, prototype=cp12)
-
-    sp2 = Prototype.obj.create(bundle=b, type='service', name='Kafka')
-    service2 = ClusterObject.obj.create(cluster=cluster, prototype=sp2)
-    cp21 = Prototype.obj.create(bundle=b, type='component', name='node2')
-    comp21 = ServiceComponent.obj.create(cluster=cluster, service=service2, prototype=cp21)
-
-    return (cluster, service1, service2, comp11, comp12, comp21, b)
-
-
-def cook_hosts():
-    b = Bundle.obj.create(name='ssh', version='1.0')
-    hpp = Prototype.obj.create(bundle=b, type='provider', name='Cloud')
-    provider = HostProvider.obj.create(name='Fort', prototype=hpp)
-    hp = Prototype.obj.create(bundle=b, type='host', name='Simple')
-
-    host1 = api.add_host(hp, provider, 'host1.net')
-    host2 = api.add_host(hp, provider, 'host2.net')
-    host3 = api.add_host(hp, provider, 'host3.net')
-
-    return (provider, host1, host2, host3)
+    assert user.has_perm('cm.view_cluster', cluster1)
+    assert not user.has_perm('cm.view_cluster', cluster2)
 
 
 @pytest.mark.django_db
-def test_parent_policy4cluster():
-    user = cook_user('Joe')
-    cluster, service1, service2, comp11, comp12, comp21, _ = cook_cluster1()
-
-    p = Policy.objects.create(role=cook_conf_role())
+def test_parent_policy4cluster(
+    user,
+    cluster1,
+    service1,
+    service2,
+    component11,
+    component21,
+    object_role_custom_perm_cluster_service_component,
+):
+
+    p = Policy.objects.create(role=object_role_custom_perm_cluster_service_component)
     p.user.add(user)
-    p.add_object(cluster)
+    p.add_object(cluster1)
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service2)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp11)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp12)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp21)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service2)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component21)
 
     p.apply()
 
-    assert user.has_perm('cm.edit_conf_cluster', cluster)
-    assert user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert user.has_perm('cm.edit_conf_clusterobject', service2)
-    assert user.has_perm('cm.edit_conf_servicecomponent', comp11)
-    assert user.has_perm('cm.edit_conf_servicecomponent', comp12)
-    assert user.has_perm('cm.edit_conf_servicecomponent', comp21)
+    assert user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert user.has_perm('cm.change_config_of_clusterobject', service2)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component21)
 
 
 @pytest.mark.django_db
-def test_parent_policy4service():
-    user = cook_user('Joe')
-    cluster, service1, service2, comp11, comp12, comp21, _ = cook_cluster1()
-    p = Policy.objects.create(role=cook_conf_role())
+def test_parent_policy4service(
+    user,
+    cluster1,
+    service1,
+    service2,
+    component11,
+    component21,
+    object_role_custom_perm_cluster_service_component,
+):
+    p = Policy.objects.create(role=object_role_custom_perm_cluster_service_component)
     p.user.add(user)
-
     p.add_object(service1)
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service2)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp11)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp12)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp21)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service2)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component21)
 
     p.apply()
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service2)
-    assert user.has_perm('cm.edit_conf_servicecomponent', comp11)
-    assert user.has_perm('cm.edit_conf_servicecomponent', comp12)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp21)
+    assert user.has_perm('cm.view_cluster', cluster1)
+
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service2)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component21)
 
 
 @pytest.mark.django_db
-def test_parent_policy4service2():
-    user = cook_user('Joe')
-    cluster, service1, service2, comp11, comp12, comp21, _ = cook_cluster1()
-    p = Policy.objects.create(role=cook_conf_role())
+def test_parent_policy4service2(
+    user,
+    cluster1,
+    service1,
+    service2,
+    component11,
+    component21,
+    object_role_custom_perm_cluster_service_component,
+):
+    p = Policy.objects.create(role=object_role_custom_perm_cluster_service_component)
     p.user.add(user)
-
     p.add_object(service2)
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service2)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp11)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp12)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp21)
+    assert not user.has_perm('cm.view_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service2)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component21)
 
     p.apply()
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert user.has_perm('cm.edit_conf_clusterobject', service2)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp11)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp12)
-    assert user.has_perm('cm.edit_conf_servicecomponent', comp21)
+    assert user.has_perm('cm.view_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert user.has_perm('cm.change_config_of_clusterobject', service2)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component21)
 
 
 @pytest.mark.django_db
-def test_parent_policy4component():
-    user = cook_user('Joe')
-    cluster, service1, service2, comp11, comp12, comp21, _ = cook_cluster1()
-    p = Policy.objects.create(role=cook_conf_role())
+def test_parent_policy4component(
+    user,
+    cluster1,
+    service1,
+    service2,
+    component11,
+    component21,
+    object_role_custom_perm_cluster_service_component,
+):
+    p = Policy.objects.create(role=object_role_custom_perm_cluster_service_component)
     p.user.add(user)
-
-    p.add_object(comp12)
-
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service2)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp11)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp12)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp21)
+    p.add_object(component11)
+    assert not user.has_perm('cm.view_cluster', cluster1)
+    assert not user.has_perm('cm.view_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service2)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component21)
 
     p.apply()
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service2)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp11)
-    assert user.has_perm('cm.edit_conf_servicecomponent', comp12)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp21)
+    assert user.has_perm('cm.view_cluster', cluster1)
+    assert user.has_perm('cm.view_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service2)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component21)
 
 
 @pytest.mark.django_db
-def test_parent_policy4host_in_cluster():
-    user = cook_user('Joe')
-    cluster, _, _, _, _, _, _ = cook_cluster1()
-    _, host1, host2, host3 = cook_hosts()
-    api.add_host_to_cluster(cluster, host1)
-    api.add_host_to_cluster(cluster, host2)
-
-    p = Policy.objects.create(role=cook_conf_role())
+def test_parent_policy4host_in_cluster(
+    user, cluster1, host1, host2, host3, object_role_custom_perm_cluster_host
+):
+    api.add_host_to_cluster(cluster1, host1)
+    api.add_host_to_cluster(cluster1, host2)
+    p = Policy.objects.create(role=object_role_custom_perm_cluster_host)
     p.user.add(user)
-    p.add_object(cluster)
+    p.add_object(cluster1)
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_host', host1)
-    assert not user.has_perm('cm.edit_conf_host', host2)
-    assert not user.has_perm('cm.edit_conf_host', host3)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_host', host1)
+    assert not user.has_perm('cm.change_config_of_host', host2)
+    assert not user.has_perm('cm.change_config_of_host', host3)
 
     p.apply()
 
-    assert user.has_perm('cm.edit_conf_cluster', cluster)
-    assert user.has_perm('cm.edit_conf_host', host1)
-    assert user.has_perm('cm.edit_conf_host', host2)
-    assert not user.has_perm('cm.edit_conf_host', host3)
+    assert user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert user.has_perm('cm.change_config_of_host', host1)
+    assert user.has_perm('cm.change_config_of_host', host2)
+    assert not user.has_perm('cm.change_config_of_host', host3)
 
 
 @pytest.mark.django_db
-def test_parent_policy4host_in_service():
-    user = cook_user('Joe')
-    cluster, service1, service2, comp11, comp12, comp21, _ = cook_cluster1()
-    _, host1, host2, host3 = cook_hosts()
-    api.add_host_to_cluster(cluster, host1)
-    api.add_host_to_cluster(cluster, host2)
-    api.add_host_to_cluster(cluster, host3)
+# pylint: disable=too-many-arguments
+def test_parent_policy4host_in_service(
+    user,
+    cluster1,
+    service1,
+    service2,
+    component11,
+    component21,
+    host1,
+    host2,
+    object_role_custom_perm_cluster_service_component_host,
+):
+    api.add_host_to_cluster(cluster1, host1)
+    api.add_host_to_cluster(cluster1, host2)
     api.add_hc(
-        cluster,
+        cluster1,
         [
-            {"service_id": service1.id, "component_id": comp11.id, "host_id": host1.id},
-            {"service_id": service1.id, "component_id": comp12.id, "host_id": host2.id},
-            {"service_id": service2.id, "component_id": comp21.id, "host_id": host3.id},
+            {"service_id": service1.id, "component_id": component11.id, "host_id": host1.id},
+            {"service_id": service2.id, "component_id": component21.id, "host_id": host2.id},
         ],
     )
-
-    p = Policy.objects.create(role=cook_conf_role())
+    p = Policy.objects.create(role=object_role_custom_perm_cluster_service_component_host)
     p.user.add(user)
     p.add_object(service1)
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert not user.has_perm('cm.edit_conf_host', host1)
-    assert not user.has_perm('cm.edit_conf_host', host2)
-    assert not user.has_perm('cm.edit_conf_host', host3)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service2)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component21)
+    assert not user.has_perm('cm.change_config_of_host', host1)
+    assert not user.has_perm('cm.change_config_of_host', host2)
 
     p.apply()
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert user.has_perm('cm.edit_conf_host', host1)
-    assert user.has_perm('cm.edit_conf_host', host2)
-    assert not user.has_perm('cm.edit_conf_host', host3)
+    assert not user.has_perm('cm.change_confing_of_cluster', cluster1)
+    assert user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service2)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component21)
+    assert user.has_perm('cm.change_config_of_host', host1)
+    assert not user.has_perm('cm.change_config_of_host', host2)
 
 
 @pytest.mark.django_db
-def test_parent_policy4host_in_component():
-    user = cook_user('Joe')
-    cluster, service1, service2, comp11, _, comp21, _ = cook_cluster1()
-    _, host1, host2, host3 = cook_hosts()
-    api.add_host_to_cluster(cluster, host1)
-    api.add_host_to_cluster(cluster, host2)
-    api.add_host_to_cluster(cluster, host3)
-    HostComponent.obj.create(cluster=cluster, service=service2, component=comp21, host=host1)
-    HostComponent.obj.create(cluster=cluster, service=service2, component=comp21, host=host2)
-    HostComponent.obj.create(cluster=cluster, service=service1, component=comp11, host=host3)
-
-    p = Policy.objects.create(role=cook_conf_role())
+# pylint: disable=too-many-arguments
+def test_parent_policy4host_in_component(
+    user,
+    cluster1,
+    service1,
+    service2,
+    component11,
+    component21,
+    host1,
+    host2,
+    host3,
+    object_role_custom_perm_cluster_service_component_host,
+):
+    api.add_host_to_cluster(cluster1, host1)
+    api.add_host_to_cluster(cluster1, host2)
+    api.add_host_to_cluster(cluster1, host3)
+    api.add_hc(
+        cluster1,
+        [
+            {'service_id': service2.id, 'component_id': component21.id, 'host_id': host1.id},
+            {'service_id': service2.id, 'component_id': component21.id, 'host_id': host2.id},
+            {'service_id': service1.id, 'component_id': component11.id, 'host_id': host3.id},
+        ],
+    )
+
+    p = Policy.objects.create(role=object_role_custom_perm_cluster_service_component_host)
     p.user.add(user)
-    p.add_object(comp21)
+    p.add_object(component21)
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert not user.has_perm('cm.edit_conf_servicecomponent', comp21)
-    assert not user.has_perm('cm.edit_conf_host', host1)
-    assert not user.has_perm('cm.edit_conf_host', host2)
-    assert not user.has_perm('cm.edit_conf_host', host3)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service2)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component21)
+    assert not user.has_perm('cm.change_config_of_host', host1)
+    assert not user.has_perm('cm.change_config_of_host', host2)
+    assert not user.has_perm('cm.change_config_of_host', host3)
 
     p.apply()
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert user.has_perm('cm.edit_conf_servicecomponent', comp21)
-    assert user.has_perm('cm.edit_conf_host', host1)
-    assert user.has_perm('cm.edit_conf_host', host2)
-    assert not user.has_perm('cm.edit_conf_host', host3)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service2)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component21)
+    assert user.has_perm('cm.change_config_of_host', host1)
+    assert user.has_perm('cm.change_config_of_host', host2)
+    assert not user.has_perm('cm.change_config_of_host', host3)
 
 
 @pytest.mark.django_db
-def test_parent_policy4provider():
-    user = cook_user('Joe')
-    provider, host1, host2, host3 = cook_hosts()
-
-    p = Policy.objects.create(role=cook_conf_role())
+def test_parent_policy4provider(
+    user, provider, host1, host2, host3, object_role_custom_perm_provider_host
+):
+    p = Policy.objects.create(role=object_role_custom_perm_provider_host)
     p.user.add(user)
     p.add_object(provider)
 
-    assert not user.has_perm('cm.edit_conf_hostprovider', provider)
-    assert not user.has_perm('cm.edit_conf_host', host1)
-    assert not user.has_perm('cm.edit_conf_host', host2)
-    assert not user.has_perm('cm.edit_conf_host', host3)
+    assert not user.has_perm('cm.change_config_of_hostprovider', provider)
+    assert not user.has_perm('cm.change_config_of_host', host1)
+    assert not user.has_perm('cm.change_config_of_host', host2)
+    assert not user.has_perm('cm.change_config_of_host', host3)
 
     p.apply()
 
-    assert user.has_perm('cm.edit_conf_hostprovider', provider)
-    assert user.has_perm('cm.edit_conf_host', host1)
-    assert user.has_perm('cm.edit_conf_host', host2)
-    assert user.has_perm('cm.edit_conf_host', host3)
+    assert user.has_perm('cm.change_config_of_hostprovider', provider)
+    assert user.has_perm('cm.change_config_of_host', host1)
+    assert user.has_perm('cm.change_config_of_host', host2)
+    assert user.has_perm('cm.change_config_of_host', host3)
 
 
 @pytest.mark.django_db
-def test_simple_parent_policy():
-    user = cook_user('Joe')
-
-    cluster = cook_role('change_cluster', 'ModelRole')
-    cluster.permissions.add(cook_perm('cm', 'change', 'cluster'))
-
-    service = cook_role('change_service', 'ModelRole')
-    service.permissions.add(cook_perm('cm', 'change', 'clusterobject'))
-
-    comp = cook_role('change_component', 'ModelRole')
-    comp.permissions.add(cook_perm('cm', 'change', 'servicecomponent'))
-
-    r = cook_role('all', 'ParentRole')
-    r.child.add(cluster, service, comp)
+def test_simple_parent_policy(user, model_role_view_cluster_service_component_perm):
 
-    p = Policy.objects.create(role=r)
+    p = Policy.objects.create(role=model_role_view_cluster_service_component_perm)
     p.user.add(user)
 
-    assert not user.has_perm('cm.change_cluster')
-    assert not user.has_perm('cm.change_clusterobject')
-    assert not user.has_perm('cm.change_servicecomponent')
+    assert not user.has_perm('cm.view_cluster')
+    assert not user.has_perm('cm.view_clusterobject')
+    assert not user.has_perm('cm.view_servicecomponent')
 
     clear_perm_cache(user)
     p.apply()
 
-    assert user.has_perm('cm.change_cluster')
-    assert user.has_perm('cm.change_clusterobject')
-    assert user.has_perm('cm.change_servicecomponent')
-
-
-@pytest.mark.django_db
-def test_empty_parent_policy():
-    user = cook_user('Joe')
-    _, _, service2, _, _, _, _ = cook_cluster1()
-
-    r = cook_role('all', 'ParentRole', ['service'])
-    p = Policy.objects.create(role=r)
-    p.user.add(user)
-    p.add_object(service2)
-
-    p.apply()
+    assert user.has_perm('cm.view_cluster')
+    assert user.has_perm('cm.view_clusterobject')
+    assert user.has_perm('cm.view_servicecomponent')
 
 
 @pytest.mark.django_db
-def test_add_service():
-    user = cook_user('Joe')
-    cluster, service1, service2, _, _, _, b = cook_cluster1()
-    sp3 = Prototype.obj.create(bundle=b, type='service', name='Hive')
+def test_add_service(
+    user, bundle1, cluster1, service1, service2, object_role_custom_perm_cluster_service
+):
+    sp3 = Prototype.obj.create(bundle=bundle1, type='service', name='service_3')
 
-    p = Policy.objects.create(role=cook_conf_role())
+    p = Policy.objects.create(role=object_role_custom_perm_cluster_service)
     p.user.add(user)
-    p.add_object(cluster)
+    p.add_object(cluster1)
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert not user.has_perm('cm.edit_conf_clusterobject', service2)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service2)
 
     p.apply()
 
-    assert user.has_perm('cm.edit_conf_cluster', cluster)
-    assert user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert user.has_perm('cm.edit_conf_clusterobject', service2)
+    assert user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert user.has_perm('cm.change_config_of_clusterobject', service2)
 
-    service3 = api.add_service_to_cluster(cluster, sp3)
-    assert user.has_perm('cm.edit_conf_clusterobject', service3)
+    service3 = api.add_service_to_cluster(cluster1, sp3)
+    assert user.has_perm('cm.change_config_of_clusterobject', service3)
 
 
 @pytest.mark.django_db
-def test_add_host():
-    user = cook_user('Joe')
-    cluster, service1, _, comp11, comp12, _, _ = cook_cluster1()
-    _, host1, host2, host3 = cook_hosts()
-    api.add_host_to_cluster(cluster, host1)
-    api.add_host_to_cluster(cluster, host2)
-    HostComponent.obj.create(cluster=cluster, service=service1, component=comp11, host=host1)
-    HostComponent.obj.create(cluster=cluster, service=service1, component=comp12, host=host2)
-
-    p = Policy.objects.create(role=cook_conf_role())
+def test_add_host(
+    user,
+    cluster1,
+    service1,
+    component11,
+    host1,
+    host2,
+    object_role_custom_perm_cluster_service_component_host,
+):
+    api.add_host_to_cluster(cluster1, host1)
+    api.add_hc(
+        cluster1, [{'service_id': service1.id, 'component_id': component11.id, 'host_id': host1.id}]
+    )
+
+    p = Policy.objects.create(role=object_role_custom_perm_cluster_service_component_host)
     p.user.add(user)
-    p.add_object(cluster)
+    p.add_object(cluster1)
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_host', host1)
-    assert not user.has_perm('cm.edit_conf_host', host2)
-    assert not user.has_perm('cm.edit_conf_host', host3)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert not user.has_perm('cm.change_config_of_host', host1)
+    assert not user.has_perm('cm.change_config_of_host', host2)
 
     p.apply()
 
-    assert user.has_perm('cm.edit_conf_cluster', cluster)
-    assert user.has_perm('cm.edit_conf_host', host1)
-    assert user.has_perm('cm.edit_conf_host', host2)
-    assert not user.has_perm('cm.edit_conf_host', host3)
+    assert user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert user.has_perm('cm.change_config_of_host', host1)
+    assert not user.has_perm('cm.change_config_of_host', host2)
 
-    api.add_host_to_cluster(cluster, host3)
+    api.add_host_to_cluster(cluster1, host2)
 
-    assert user.has_perm('cm.edit_conf_host', host3)
+    assert user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert user.has_perm('cm.change_config_of_host', host1)
+    assert user.has_perm('cm.change_config_of_host', host2)
 
 
 @pytest.mark.django_db
-def test_add_hc():
-    user = cook_user('Joe')
-    cluster, service1, _, comp11, comp12, _, _ = cook_cluster1()
-    _, host1, host2, host3 = cook_hosts()
-    api.add_host_to_cluster(cluster, host1)
-    HostComponent.obj.create(cluster=cluster, service=service1, component=comp11, host=host1)
-
-    p = Policy.objects.create(role=cook_conf_role())
+# pylint: disable=too-many-arguments
+def test_add_hc(
+    user,
+    cluster1,
+    service1,
+    component11,
+    component12,
+    host1,
+    host2,
+    object_role_custom_perm_service_component_host,
+):
+    api.add_host_to_cluster(cluster1, host1)
+    api.add_hc(
+        cluster1, [{'service_id': service1.id, 'component_id': component11.id, 'host_id': host1.id}]
+    )
+    p = Policy.objects.create(role=object_role_custom_perm_service_component_host)
     p.user.add(user)
     p.add_object(service1)
 
-    assert not user.has_perm('cm.edit_conf_cluster', cluster)
-    assert not user.has_perm('cm.edit_conf_host', host1)
-    assert not user.has_perm('cm.edit_conf_host', host2)
-    assert not user.has_perm('cm.edit_conf_host', host3)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert not user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert not user.has_perm('cm.change_config_of_servicecomponent', component12)
+    assert not user.has_perm('cm.change_config_of_host', host1)
+    assert not user.has_perm('cm.change_config_of_host', host2)
 
     p.apply()
 
-    assert user.has_perm('cm.edit_conf_clusterobject', service1)
-    assert user.has_perm('cm.edit_conf_host', host1)
-    assert not user.has_perm('cm.edit_conf_host', host2)
-    assert not user.has_perm('cm.edit_conf_host', host3)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component12)
+    assert user.has_perm('cm.change_config_of_host', host1)
+    assert not user.has_perm('cm.change_config_of_host', host2)
 
-    api.add_host_to_cluster(cluster, host2)
+    api.add_host_to_cluster(cluster1, host2)
     api.add_hc(
-        cluster,
+        cluster1,
         [
-            {"service_id": service1.id, "component_id": comp11.id, "host_id": host1.id},
-            {"service_id": service1.id, "component_id": comp12.id, "host_id": host2.id},
+            {'service_id': service1.id, 'component_id': component11.id, 'host_id': host1.id},
+            {"service_id": service1.id, "component_id": component12.id, "host_id": host2.id},
         ],
     )
 
-    assert user.has_perm('cm.edit_conf_host', host2)
+    assert not user.has_perm('cm.change_config_of_cluster', cluster1)
+    assert user.has_perm('cm.change_config_of_clusterobject', service1)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component11)
+    assert user.has_perm('cm.change_config_of_servicecomponent', component12)
+    assert user.has_perm('cm.change_config_of_host', host1)
+    assert user.has_perm('cm.change_config_of_host', host2)
 
 
 @pytest.mark.django_db
diff --git a/python/rbac/upgrade/test_spec.py b/python/rbac/upgrade/test_spec.py
index 72863cbfb6..6cf8f2bfbc 100644
--- a/python/rbac/upgrade/test_spec.py
+++ b/python/rbac/upgrade/test_spec.py
@@ -131,39 +131,3 @@ def is_exclude(name: str) -> bool:
         return EXCLUDE[name]
     except KeyError:
         return False
-
-
-def parametrized_by(role: dict) -> list:
-    if "parametrized_by" in role:
-        return role["parametrized_by"]
-    return []
-
-
-class ChildSumEx(AssertionError):
-    def __init__(self, name: str, role: list, child: list):
-        super().__init__(
-            (
-                f'For role "{name}" parametrize_by is not a sum of child parametrization:',
-                f'{set(role)} != {set(child)}',
-            )
-        )
-
-
-def tree_sum(role_map: dict, role: dict) -> list:
-    role_params = parametrized_by(role)
-    if "child" in role:
-        child_params = []
-        for c in role['child']:
-            child_params.extend(tree_sum(role_map, role_map[c]))
-        if not is_exclude(role["name"]):
-            if (not set(child_params) == set(role_params)) and 'component' not in child_params:
-                raise ChildSumEx(role["name"], role_params, child_params)
-    return role_params
-
-
-def test_parametrization_sum(roots: dict, role_map: dict):
-    """Check that most of the roles has parametrized_by equal to sum of child's parametrized_by.
-    But with some excludes.
-    """
-    for v in roots.values():
-        tree_sum(role_map, v)
diff --git a/requirements-test.txt b/requirements-test.txt
index d5a35e0c76..243b5c78db 100644
--- a/requirements-test.txt
+++ b/requirements-test.txt
@@ -1,5 +1,5 @@
 --extra-index-url https://ci.arenadata.io/artifactory/api/pypi/python-packages/simple
-adcm_client>=2022.1.27.13
+adcm_client>=2022.3.16.11
 adcm-pytest-plugin>=4.15.2, < 5.0
 attr
 allure-pytest
diff --git a/tests/api/utils/endpoints.py b/tests/api/utils/endpoints.py
index fb5f0e3f15..96f8f27876 100644
--- a/tests/api/utils/endpoints.py
+++ b/tests/api/utils/endpoints.py
@@ -338,11 +338,11 @@ def get_child_endpoint_by_fk_name(self, field_name: str) -> Optional["Endpoints"
         filter_predicate=is_not_built_in,
     )
 
-    # Test logic for "built_in"
     RbacBuiltInPolicy = Endpoint(
         path="rbac/policy",
         methods=[Methods.GET, Methods.LIST, Methods.POST],
         data_class=RbacBuiltInPolicyFields,
         spec_link="",
+        technical=True,
         filter_predicate=is_built_in,
     )
diff --git a/tests/functional/rbac/action_role_utils.py b/tests/functional/rbac/action_role_utils.py
index 7ade7ee51c..400d5d2fe4 100644
--- a/tests/functional/rbac/action_role_utils.py
+++ b/tests/functional/rbac/action_role_utils.py
@@ -1,19 +1,80 @@
 """Checks and utilities for action roles"""
 from operator import itemgetter
-from typing import Iterable, Tuple, Set, List, Iterator
+from typing import Iterable, Tuple, Set, List, Iterator, Optional, Union
 
 import allure
 from adcm_client.base import ObjectNotFound
-from adcm_client.objects import ADCMClient, Cluster, Prototype, Service, Role, Bundle
-from adcm_pytest_plugin.utils import catch_failed
+from adcm_client.objects import ADCMClient, Cluster, Prototype, Service, Role, Bundle, Host, Policy
+from adcm_pytest_plugin.utils import catch_failed, random_string
 
-from tests.functional.rbac.conftest import RbacRoles, extract_role_short_info, RoleShortInfo, RoleType
+from tests.functional.rbac.checkers import ForbiddenCallChecker
+from tests.functional.rbac.conftest import RbacRoles, extract_role_short_info, RoleShortInfo, RoleType, BusinessRole
+from tests.functional.tools import AnyADCMObject
 from tests.library.assertions import is_in_collection, is_not_in_collection, is_superset_of, does_not_intersect
+from tests.library.consts import HTTPMethod
+
+
+def action_business_role(
+    adcm_object: AnyADCMObject,
+    action_display_name: str,
+    *,
+    action_on_host: Optional[Host] = None,
+    no_deny_checker: bool = False,
+) -> BusinessRole:
+    """Construct BusinessRole that allows to run action"""
+    if no_deny_checker:
+        deny_checker = None
+    else:
+        action_owner = action_on_host if action_on_host else adcm_object
+        action_id = action_owner.action(display_name=action_display_name).id
+        deny_checker = ForbiddenCallChecker(action_owner.__class__, f'action/{action_id}/run', HTTPMethod.POST)
+
+    role_name = get_action_role_name(adcm_object, action_display_name)
+    return BusinessRole(
+        role_name,
+        lambda user_obj, *args, **kwargs: user_obj.action(display_name=action_display_name).run(**kwargs),
+        deny_checker,
+    )
+
+
+@allure.step("Create policy that allows to run action")
+def create_action_policy(
+    client: ADCMClient,
+    adcm_object: Union[AnyADCMObject, List[AnyADCMObject]],
+    *business_roles: BusinessRole,
+    user=None,
+    group=None,
+) -> Policy:
+    """Create policy based on business roles"""
+    if not (user or group):
+        raise ValueError("Either user or group should be provided to create policy")
+    user = user or []
+    group = group or []
+    child_roles = [{'id': client.role(name=role.role_name).id} for role in business_roles]
+    role_name = f"Test Action Role {random_string(6)}"
+    action_parent_role = client.role_create(name=role_name, display_name=role_name, child=child_roles)
+    return client.policy_create(
+        name=f"Test Action Policy {role_name[-6:]}",
+        role=action_parent_role,
+        objects=adcm_object if isinstance(adcm_object, list) else [adcm_object],
+        user=user if isinstance(user, list) else [user],
+        group=group if isinstance(group, list) else [group],
+    )
 
 
 # !===== Utils =====!
 
 
+def get_action_role_name(adcm_object: AnyADCMObject, action_display_name: str):
+    """Construct "umbrella" role name for an action with specified name"""
+    return f'{adcm_object.prototype().type.capitalize()} Action: {action_display_name}'
+
+
+def get_action_display_name_from_role_name(role_name: str):
+    """Get action display name from action role name"""
+    return role_name.rsplit('Action: ', maxsplit=1)[-1]
+
+
 def get_prototype_prefix_for_action_role(prototype: Prototype) -> str:
     """Get prototype based prefix for role name"""
     return f'{prototype.type}_{prototype.display_name}_'
diff --git a/tests/functional/rbac/actions/test_permissions_mixup.py b/tests/functional/rbac/actions/test_permissions_mixup.py
index 7113da9aaf..79f369d829 100644
--- a/tests/functional/rbac/actions/test_permissions_mixup.py
+++ b/tests/functional/rbac/actions/test_permissions_mixup.py
@@ -12,7 +12,7 @@
 
 """Test corner cases where permissions got messed up and allows more than they should be"""
 
-from typing import Iterable, Tuple
+from typing import Iterable, Tuple, Callable
 
 import allure
 import pytest
@@ -23,12 +23,11 @@
     RbacRoles,
     is_allowed,
     as_user_objects,
-    is_denied,
     BusinessRole,
 )
-from tests.functional.rbac.actions.utils import action_business_role, create_action_policy
+from tests.functional.rbac.action_role_utils import action_business_role, create_action_policy
 
-pytestmark = [pytest.mark.full]
+pytestmark = [pytest.mark.extra_rbac]
 
 SAME_DISPLAY_ACTION_NAME = "same_display"
 DO_NOTHING_ACTION_NAME = "Do nothing"
@@ -63,41 +62,52 @@ def clusters_with_services(self, actions_cluster_bundle, simple_cluster_bundle)
         return first_cluster, second_cluster
 
     @allure.issue("https://arenadata.atlassian.net/browse/ADCM-2557")
-    def test_cluster_admin(self, clients, user, clusters):
+    def test_cluster_admin(self, clients, user, clusters, is_denied_to_user):
         """
         Test that granting "Cluster Admin" to one cluster
         doesn't lead to unauthorized access to another cluster's actions
         """
+        (
+            first_cluster_admin,
+            second_cluster_admin,
+            first_another_bundle_cluster_admin,
+            second_another_bundle_cluster_admin,
+        ) = clusters
 
-        first_cluster, second_cluster, first_another_bundle_cluster, second_another_bundle_cluster = as_user_objects(
-            clients.user, *clusters
-        )
         # will create role for each cluster with same prototype
-        same_display_role = action_business_role(first_cluster, SAME_DISPLAY_ACTION_NAME)
-        do_nothing_role = action_business_role(second_cluster, DO_NOTHING_ACTION_NAME)
+        same_display_role = action_business_role(first_cluster_admin, SAME_DISPLAY_ACTION_NAME)
+        do_nothing_role = action_business_role(second_cluster_admin, DO_NOTHING_ACTION_NAME)
 
         clients.admin.policy_create(
             name="Cluster Admin for First Cluster",
             role=clients.admin.role(display_name=RbacRoles.ClusterAdministrator.value),
-            objects=[first_cluster],
+            objects=[first_cluster_admin],
             user=[user],
         )
 
+        first_cluster, *_ = as_user_objects(clients.user, first_cluster_admin)
+
         self.check_permissions(
             "Check that Cluster Admin grants permission only on one cluster",
             allowed=((first_cluster, same_display_role), (first_cluster, do_nothing_role)),
             denied=(
-                (second_cluster, same_display_role),
-                (second_cluster, do_nothing_role),
-                (first_another_bundle_cluster, do_nothing_role),
-                (second_another_bundle_cluster, do_nothing_role),
+                (second_cluster_admin, same_display_role),
+                (second_cluster_admin, do_nothing_role),
+                (first_another_bundle_cluster_admin, do_nothing_role),
+                (second_another_bundle_cluster_admin, do_nothing_role),
             ),
+            check_denied=is_denied_to_user,
         )
 
         create_action_policy(
-            clients.admin, second_cluster, action_business_role(first_cluster, SAME_DISPLAY_ACTION_NAME), user=user
+            clients.admin,
+            second_cluster_admin,
+            action_business_role(first_cluster, SAME_DISPLAY_ACTION_NAME),
+            user=user,
         )
 
+        second_cluster, *_ = as_user_objects(clients.user, second_cluster_admin)
+
         self.check_permissions(
             "Check that Cluster Admin and permission to run action works correctly",
             # we can reuse allowed and disallowed if init them as sets
@@ -108,19 +118,22 @@ def test_cluster_admin(self, clients, user, clusters):
                 (second_cluster, same_display_role),
             ),
             denied=(
-                (second_cluster, do_nothing_role),
-                (first_another_bundle_cluster, do_nothing_role),
-                (second_another_bundle_cluster, do_nothing_role),
+                (second_cluster_admin, do_nothing_role),
+                (first_another_bundle_cluster_admin, do_nothing_role),
+                (second_another_bundle_cluster_admin, do_nothing_role),
             ),
+            check_denied=is_denied_to_user,
         )
 
         create_action_policy(
             clients.admin,
-            first_another_bundle_cluster,
+            first_another_bundle_cluster_admin,
             action_business_role(first_cluster, DO_NOTHING_ACTION_NAME),
             user=user,
         )
 
+        first_another_bundle_cluster, *_ = as_user_objects(clients.user, first_another_bundle_cluster_admin)
+
         self.check_permissions(
             "Check that Cluster Admin does not grant access to another bundle's clusters actions",
             allowed=(
@@ -130,18 +143,20 @@ def test_cluster_admin(self, clients, user, clusters):
                 (first_another_bundle_cluster, do_nothing_role),
             ),
             denied=(
-                (second_cluster, do_nothing_role),
-                (first_another_bundle_cluster, same_display_role),
-                (second_another_bundle_cluster, do_nothing_role),
-                (second_another_bundle_cluster, same_display_role),
+                (second_cluster_admin, do_nothing_role),
+                (first_another_bundle_cluster_admin, same_display_role),
+                (second_another_bundle_cluster_admin, do_nothing_role),
+                (second_another_bundle_cluster_admin, same_display_role),
             ),
+            check_denied=is_denied_to_user,
         )
 
-    def test_service_admin(self, clients, clusters_with_services, user):
+    # pylint: disable-next=too-many-locals
+    def test_service_admin(self, clients, clusters_with_services, user, is_denied_to_user):
         """Test that granting "Service Admin" role doesn't interfere"""
         first_cluster, second_cluster = clusters_with_services
-        first_service, second_service = as_user_objects(clients.user, *first_cluster.service_list())
-        another_cluster_service, *_ = as_user_objects(clients.user, second_cluster.service())
+        first_service, second_service = first_cluster.service_list()
+        another_cluster_service = second_cluster.service()
         # will create role for each cluster with same prototype
         same_display_role = action_business_role(first_service, SAME_DISPLAY_ACTION_NAME)
         do_nothing_role = action_business_role(second_service, DO_NOTHING_ACTION_NAME)
@@ -153,10 +168,13 @@ def test_service_admin(self, clients, clusters_with_services, user):
             user=[user],
         )
 
+        user_first_service, *_ = as_user_objects(clients.user, first_service)
+
         self.check_permissions(
             "Check that Service Admin role allows actions only on one service in one cluster",
-            allowed=((first_service, do_nothing_role), (first_service, same_display_role)),
+            allowed=((user_first_service, do_nothing_role), (user_first_service, same_display_role)),
             denied=((second_service, do_nothing_role), (another_cluster_service, do_nothing_role)),
+            check_denied=is_denied_to_user,
         )
 
         create_action_policy(
@@ -166,15 +184,18 @@ def test_service_admin(self, clients, clusters_with_services, user):
             user=user,
         )
 
+        user_second_service, *_ = as_user_objects(clients.user, second_service)
+
         self.check_permissions(
             "Check that granting permission for a single action on another service in cluster "
             "doesn't allow full access to cluster's actions",
             allowed=(
-                (first_service, do_nothing_role),
-                (first_service, same_display_role),
-                (second_service, do_nothing_role),
+                (user_first_service, do_nothing_role),
+                (user_first_service, same_display_role),
+                (user_second_service, do_nothing_role),
             ),
             denied=((second_service, same_display_role), (another_cluster_service, do_nothing_role)),
+            check_denied=is_denied_to_user,
         )
 
         create_action_policy(
@@ -184,16 +205,19 @@ def test_service_admin(self, clients, clusters_with_services, user):
             user=user,
         )
 
+        user_another_cluster_service, *_ = as_user_objects(clients.user, another_cluster_service)
+
         self.check_permissions(
             "Check that granting permission to run a single action on another cluster's service "
             "doesn't grant extra permissions",
             allowed=(
-                (first_service, do_nothing_role),
-                (first_service, same_display_role),
-                (second_service, do_nothing_role),
-                (another_cluster_service, do_nothing_role),
+                (user_first_service, do_nothing_role),
+                (user_first_service, same_display_role),
+                (user_second_service, do_nothing_role),
+                (user_another_cluster_service, do_nothing_role),
             ),
             denied=((second_service, same_display_role), (another_cluster_service, same_display_role)),
+            check_denied=is_denied_to_user,
         )
 
     def check_permissions(
@@ -201,10 +225,11 @@ def check_permissions(
         message: str,
         allowed: Iterable[Tuple[AnyADCMObject, BusinessRole]],
         denied: Iterable[Tuple[Cluster, BusinessRole]],
+        check_denied: Callable,
     ):
         """Check that permissions on actions works as expected"""
         with allure.step(message):
             for adcm_object, role in allowed:
                 is_allowed(adcm_object, role).wait()
             for adcm_object, role in denied:
-                is_denied(adcm_object, role)
+                check_denied(adcm_object, role)
diff --git a/tests/functional/rbac/actions/test_role_composition.py b/tests/functional/rbac/actions/test_role_composition.py
index 8b635cf4f5..344e3c394c 100644
--- a/tests/functional/rbac/actions/test_role_composition.py
+++ b/tests/functional/rbac/actions/test_role_composition.py
@@ -25,7 +25,7 @@
     get_prototype_prefix_for_action_role,
 )
 
-pytestmark = [pytest.mark.full]
+pytestmark = [pytest.mark.extra_rbac]
 
 BAD_REQUEST = ADCMError('400 Bad Request', "")
 
diff --git a/tests/functional/rbac/actions/test_run_actions.py b/tests/functional/rbac/actions/test_run_actions.py
index 37aa5770e5..4f66981c42 100644
--- a/tests/functional/rbac/actions/test_run_actions.py
+++ b/tests/functional/rbac/actions/test_run_actions.py
@@ -16,9 +16,8 @@
 
 import itertools
 import os
-from collections import defaultdict
 from contextlib import contextmanager
-from typing import Type, Dict, Optional, List, Union, Callable, Tuple, Generator
+from typing import Optional, Union, Tuple
 
 import allure
 import pytest
@@ -27,7 +26,7 @@
 from tests.functional.rbac.actions.conftest import DATA_DIR
 from tests.functional.tools import AnyADCMObject, get_object_represent
 from tests.functional.rbac.conftest import BusinessRole, delete_policy, is_denied, is_allowed, as_user_objects
-from tests.functional.rbac.actions.utils import action_business_role, create_action_policy
+from tests.functional.rbac.action_role_utils import action_business_role, create_action_policy
 
 
 DO_NOTHING_ACTION = 'Do nothing'
@@ -81,52 +80,53 @@ def _test_basic_action_run_permissions(adcm_object, admin_sdk, user_sdk, user, a
     with allure.step(
         f'Check that granting policy allows to run action "{DO_NOTHING_ACTION}" on {get_object_represent(adcm_object)}'
     ):
-        (user_object,) = as_user_objects(user_sdk, adcm_object)
         business_role = action_business_role(adcm_object, DO_NOTHING_ACTION)
         policy = create_action_policy(admin_sdk, adcm_object, business_role, user=user)
 
         check_single_action_is_allowed_on_object(DO_NOTHING_ACTION, adcm_object, user_sdk, business_role)
 
     with allure.step(f"Check that granted permission doesn't allow running '{DO_NOTHING_ACTION}' on other objects"):
-        with user_objects_map(
-            user_sdk,
-            [adcm_object],
-            *all_objects,
-            exclude_predicate=_do_nothing_action_not_presented,
-        ) as objects_map:
-            check_action_is_not_allowed_on_objects(DO_NOTHING_ACTION, objects_map)
+        for obj in filter(
+            lambda x: not _is_the_same(x, adcm_object) and not _do_nothing_action_not_presented(x), all_objects
+        ):
+            is_denied(obj, action_business_role(obj, DO_NOTHING_ACTION), client=user_sdk)
 
     with allure.step('Check permission withdrawn'):
         delete_policy(policy)
-        is_denied(user_object, business_role)
+        is_denied(adcm_object, business_role, client=user_sdk)
 
 
-@pytest.mark.full()
+def _is_the_same(first_object, second_object) -> bool:
+    return first_object.__class__ == second_object.__class__ and first_object.id == second_object.id
+
+
+@pytest.mark.extra_rbac()
 def test_config_change_via_plugin(clients, user, actions_cluster, actions_provider):
     """
     Test that permission on action run is enough for changing configuration with plugins.
     Config change action has its own config.
     """
-    cluster, service, component = as_user_objects(
-        clients.user,
-        actions_cluster,
-        (serv := actions_cluster.service(name='config_changing_service')),
-        serv.component(name='config_changing_component'),
-    )
-    provider, host = as_user_objects(clients.user, actions_provider, actions_provider.host())
+    cluster = actions_cluster
+    service = actions_cluster.service(name='config_changing_service')
+    component = service.component(name='config_changing_component')
+
+    provider, host = actions_provider, actions_provider.host()
 
-    _test_config_change(cluster, (cluster,), user=user, admin_client=clients.admin)
-    _test_config_change(service, (cluster, service), user=user, admin_client=clients.admin)
-    _test_config_change(component, (cluster, service, component), user=user, admin_client=clients.admin)
+    _test_config_change(cluster, (cluster,), user=user, user_client=clients.user, admin_client=clients.admin)
+    _test_config_change(service, (cluster, service), user=user, user_client=clients.user, admin_client=clients.admin)
+    _test_config_change(
+        component, (cluster, service, component), user=user, user_client=clients.user, admin_client=clients.admin
+    )
 
-    _test_config_change(provider, (provider,), user=user, admin_client=clients.admin)
-    _test_config_change(host, (provider, host), user=user, admin_client=clients.admin)
+    _test_config_change(provider, (provider,), user=user, user_client=clients.user, admin_client=clients.admin)
+    _test_config_change(host, (provider, host), user=user, user_client=clients.user, admin_client=clients.admin)
 
 
 def _test_config_change(
     action_owner_object: AnyADCMObject,
     objects_to_change: Tuple[AnyADCMObject, ...],
     admin_client: ADCMClient,
+    user_client: ADCMClient,
     user: User,
 ) -> None:
     """
@@ -149,13 +149,13 @@ def _test_config_change(
         f'Apply policy on "{owner_object_represent}" and check config change is allowed without explicit permission'
     ):
         policy = create_action_policy(admin_client, action_owner_object, *business_roles, user=user)
+        user_object, *_ = as_user_objects(user_client, action_owner_object)
 
-        for adcm_object, business_role in object_role_map:
-            admin_object = as_user_objects(admin_client, adcm_object)[0]
+        for admin_object, business_role in object_role_map:
             config_field_value = admin_object.config()[CONFIG_FIELD_TO_CHANGE]
-            new_value = f'{config_field_value}_{adcm_object.__class__.__name__}'
+            new_value = f'{config_field_value}_{admin_object.__class__.__name__}'
             with allure.step(f'Try to change {get_object_represent(admin_object)} from {owner_object_represent}'):
-                task = is_allowed(action_owner_object, business_role, config={ACTION_CONFIG_ARGUMENT: new_value})
+                task = is_allowed(user_object, business_role, config={ACTION_CONFIG_ARGUMENT: new_value})
                 assert task.wait() == 'success', 'Action should succeeded'
                 assert (
                     admin_object.config()[CONFIG_FIELD_TO_CHANGE] == new_value
@@ -163,18 +163,22 @@ def _test_config_change(
 
     with allure.step('Delete policy and check actions are denied and config stays the same'):
         delete_policy(policy)
-        for adcm_object, business_role in object_role_map:
-            admin_object = as_user_objects(admin_client, adcm_object)[0]
+        for admin_object, business_role in object_role_map:
             with allure.step(f'Try to change {get_object_represent(admin_object)} from {owner_object_represent}'):
                 config_val_before = admin_object.config()[CONFIG_FIELD_TO_CHANGE]
-                is_denied(action_owner_object, business_role, config={ACTION_CONFIG_ARGUMENT: "This you seen't"})
+                is_denied(
+                    action_owner_object,
+                    business_role,
+                    config={ACTION_CONFIG_ARGUMENT: "This you seen't"},
+                    client=user_client,
+                )
                 config_val_after = admin_object.config()[CONFIG_FIELD_TO_CHANGE]
                 assert (
                     config_val_before == config_val_after
                 ), f'Config value should stay the same for object {get_object_represent(admin_object)}'
 
 
-@pytest.mark.full()
+@pytest.mark.extra_rbac()
 def test_host_actions(clients, actions_cluster, actions_cluster_bundle, actions_provider, user):
     """Test permissions on host actions"""
     host_action_template = '{object_type} ready for host'
@@ -195,15 +199,14 @@ def test_host_actions(clients, actions_cluster, actions_cluster_bundle, actions_
             component = service.component(name=component_name)
             cluster.hostcomponent_set((host, component))
 
-    host, second_host = as_user_objects(clients.user, first_host, second_host)
-    cluster, _, _ = user_cluster_objects = as_user_objects(
-        clients.user, actions_cluster, actions_service, single_component
-    )
+    cluster, *_ = cluster_objects = actions_cluster, actions_service, single_component
 
     with allure.step('Grant permission to run host actions on cluster, service and component'):
         business_roles = [
-            action_business_role(obj, host_action_template.format(object_type=obj.__class__.__name__))
-            for obj in user_cluster_objects
+            action_business_role(
+                obj, host_action_template.format(object_type=obj.__class__.__name__), action_on_host=first_host
+            )
+            for obj in cluster_objects
         ]
         policy = create_action_policy(
             clients.admin,
@@ -212,34 +215,40 @@ def test_host_actions(clients, actions_cluster, actions_cluster_bundle, actions_
             user=user,
         )
 
+        host, *_ = as_user_objects(clients.user, first_host)
+
     with allure.step('Run host actions from cluster, service and component on host in and out of cluster'):
         for role in business_roles:
             is_allowed(host, role).wait()
-            is_denied(second_host, role)
+            is_denied(second_host, role, client=clients.user)
 
     with allure.step('Check policy deletion leads to denial of host action execution'):
         delete_policy(policy)
         for role in business_roles:
-            is_denied(host, role)
-            is_denied(second_host, role)
+            is_denied(first_host, role, client=clients.user)
+            is_denied(second_host, role, client=clients.user)
 
 
-@pytest.mark.full()
+@pytest.mark.extra_rbac()
 def test_action_on_host_available_with_cluster_parametrization(clients, actions_cluster, actions_provider, user):
     """Test that host owned action is still available"""
     admin_host = actions_provider.host()
-    actions_cluster.host_add(admin_host)
-    user_cluster, user_host = as_user_objects(clients.user, actions_cluster, admin_host)
+    admin_cluster = actions_cluster
+    admin_cluster.host_add(admin_host)
+
     cluster_business_role, host_business_role = action_business_role(
-        user_cluster, DO_NOTHING_ACTION
-    ), action_business_role(user_host, DO_NOTHING_ACTION)
-    policy = create_action_policy(clients.admin, user_cluster, cluster_business_role, host_business_role, user=user)
+        admin_cluster, DO_NOTHING_ACTION
+    ), action_business_role(admin_host, DO_NOTHING_ACTION)
+    policy = create_action_policy(clients.admin, admin_cluster, cluster_business_role, host_business_role, user=user)
+
+    user_cluster, user_host = as_user_objects(clients.user, actions_cluster, admin_host)
+
     is_allowed(user_cluster, cluster_business_role).wait()
     is_allowed(user_host, host_business_role).wait()
 
     delete_policy(policy)
-    is_denied(user_cluster, cluster_business_role)
-    is_denied(user_host, host_business_role)
+    is_denied(admin_cluster, cluster_business_role, client=clients.user)
+    is_denied(admin_host, host_business_role, client=clients.user)
 
 
 class TestPluginsPermissions:
@@ -352,65 +361,17 @@ def check_single_action_is_allowed_on_object(
     business_role: Optional[BusinessRole] = None,
 ):
     """Check that only one action is allowed on object and the access to others is denied"""
-    (allowed_object,) = as_user_objects(user_sdk, adcm_object)
+    allowed_object, *_ = as_user_objects(user_sdk, adcm_object)
     business_role = business_role or action_business_role(allowed_object, action_display_name)
 
     is_allowed(allowed_object, business_role).wait()
     for action_name in (a.display_name for a in adcm_object.action_list() if a.display_name != action_display_name):
-        is_denied(allowed_object, action_business_role(allowed_object, action_name))
-
-
-@allure.step("Check actions aren't allowed on objects they don't suppose to")
-def check_action_is_not_allowed_on_objects(action_display_name: str, objects_to_deny: Dict[Type, Dict[int, object]]):
-    """Check that provided action (by display name) is not allowed to run on any of provided objects"""
-    for object_map in objects_to_deny.values():
-        for adcm_object in object_map.values():
-            is_denied(adcm_object, action_business_role(adcm_object, action_display_name))
+        is_denied(adcm_object, action_business_role(adcm_object, action_name), client=user_sdk)
 
 
 # !===== Utilities =====!
 
 
-@contextmanager
-def user_objects_map(
-    user_sdk,
-    exclude_objects: List[AnyADCMObject],
-    *objects: AnyADCMObject,
-    exclude_predicate: Callable[[AnyADCMObject], bool] = None,
-) -> Generator[Dict[Type, Dict[int, AnyADCMObject]], None, None]:
-    """
-    Get objects map in format:
-    {
-      classname: {
-        object_id: object (from user sdk)
-      }
-    }
-
-    Inside the context following objects are removed from map:
-    1. Ones that are listed in `exclude_objects`.
-    2. Ones that satisfies the exclude_predicate.
-    After the context is left all excluded objects are returned to the map.
-
-    P.S. You can improve this manager by adding `full_map` argument that will operate on existing map
-         (if you'll need to reuse map that was constructed during previous call).
-    """
-    full_map = defaultdict(dict)
-    user_objects = as_user_objects(user_sdk, *objects)
-
-    for obj in user_objects:
-        full_map[obj.__class__][obj.id] = obj
-
-    filtered = list(filter(exclude_predicate, user_objects)) if exclude_predicate else []
-
-    exclude_set = set((obj.__class__, obj.id) for obj in (exclude_objects + filtered))
-    excluded = tuple((full_map[cls].pop(object_id) for cls, object_id in exclude_set))
-
-    yield full_map
-
-    for obj in excluded:
-        full_map[obj.__class__][obj.id] = obj
-
-
 def get_all_cluster_tree_plain(cluster: Cluster) -> Tuple[Union[Cluster, Service, Component], ...]:
     """Get all cluster related elements (services and component) as a plain structure"""
     services = cluster.service_list()
diff --git a/tests/functional/rbac/actions/test_upgrade.py b/tests/functional/rbac/actions/test_upgrade.py
index ae00b04887..fbd13fa78b 100644
--- a/tests/functional/rbac/actions/test_upgrade.py
+++ b/tests/functional/rbac/actions/test_upgrade.py
@@ -18,15 +18,20 @@
 
 import allure
 import pytest
-from adcm_client.base import NoSuchEndpointOrAccessIsDenied
-from adcm_client.objects import Bundle, Cluster, Policy, Component, Service
+from adcm_client.base import NoSuchEndpointOrAccessIsDenied, ObjectNotFound
+from adcm_client.objects import Bundle, Cluster, Policy, Component, Service, ADCMClient
 from adcm_client.wrappers.api import AccessIsDenied
 
+from tests.library.consts import HTTPMethod
 from tests.functional.tools import ClusterRelatedObject
+from tests.functional.rbac.checkers import ForbiddenCallChecker
 from tests.functional.rbac.conftest import BusinessRole, is_allowed, is_denied, as_user_objects
+from tests.functional.rbac.action_role_utils import (
+    create_action_policy,
+    action_business_role,
+    get_action_display_name_from_role_name,
+)
 from tests.functional.rbac.actions.conftest import DATA_DIR
-from tests.functional.rbac.actions.utils import create_action_policy, action_business_role
-
 
 ClusterObjectClassName = Literal['Cluster', 'Service', 'Component']
 
@@ -77,7 +82,7 @@ def old_cluster_objects_map(self, old_cluster_objects) -> Dict[ClusterObjectClas
     def all_business_roles(self, old_cluster_objects):
         """Build roles for all actions on all objects both before and after the upgrade"""
         return [
-            action_business_role(adcm_object, action_display_name)
+            action_business_role(adcm_object, action_display_name, no_deny_checker=True)
             for adcm_object in old_cluster_objects
             for action_display_name in (
                 *(a.display_name for a in adcm_object.action_list()),
@@ -113,23 +118,24 @@ def test_upgrade(
         2. Display name change leads to denying of previously granted permission.
         3. Policy on new action can be created and will be allowed if granted.
         """
-        user_object_map = self._objects_map_as_user_objects(clients.user, old_cluster_objects_map)
-        self.check_permissions_before_upgrade(all_business_roles, user_object_map)
+        self.check_permissions_before_upgrade(clients.user, all_business_roles, old_cluster_objects_map)
         new_cluster = self.upgrade_cluster(old_cluster)
-        self.check_permissions_after_upgrade(all_business_roles, user_object_map)
-        self.check_action_with_changed_display_name_not_allowed_by_name(user_object_map)
+        self.check_permissions_after_upgrade(clients.user, all_business_roles, old_cluster_objects_map)
+        self.check_action_with_changed_display_name_not_allowed_by_name(clients.user, old_cluster_objects_map)
         self.check_new_action_can_be_launched(clients, user, new_cluster)
-        self.check_new_action_with_old_display_name(user_object_map)
+        self.check_new_action_with_old_display_name(clients.user, old_cluster_objects_map)
 
     @allure.step('Check permissions working as expected before upgrade')
-    def check_permissions_before_upgrade(self, all_business_roles, user_object_map):
+    def check_permissions_before_upgrade(self, user_client: ADCMClient, all_business_roles, object_map):
         """Check that correct permissions are allowed/denied before cluster upgrade"""
         self.check_roles_are_allowed(
-            user_object_map,
+            user_client,
+            object_map,
             tuple(self._get_roles_filter_exclude_by_action_name(all_business_roles, self.NOT_ALLOWED_ACTIONS)),
         )
         self.check_roles_are_denied(
-            user_object_map,
+            user_client,
+            object_map,
             tuple(self._get_roles_filter_select_by_action_name(all_business_roles, (NO_RIGHTS_ACTION,))),
         )
 
@@ -141,9 +147,10 @@ def upgrade_cluster(self, cluster):
         return cluster
 
     @allure.step('Check permissions working as expected after upgrade')
-    def check_permissions_after_upgrade(self, all_business_roles, user_object_map):
+    def check_permissions_after_upgrade(self, user_client: ADCMClient, all_business_roles, user_object_map):
         """Check that correct permissions are allowed/denied after cluster upgrade"""
         self.check_roles_are_allowed(
+            user_client,
             user_object_map,
             tuple(
                 self._get_roles_filter_exclude_by_action_name(
@@ -153,16 +160,18 @@ def check_permissions_after_upgrade(self, all_business_roles, user_object_map):
         )
 
         self.check_roles_are_denied(
+            user_client,
             user_object_map,
             tuple(self._get_roles_filter_select_by_action_name(all_business_roles, self.NOT_ALLOWED_ACTIONS)),
         )
 
     @allure.step("Check action with changed display name isn't available for user")
-    def check_action_with_changed_display_name_not_allowed_by_name(self, user_object_map):
+    def check_action_with_changed_display_name_not_allowed_by_name(self, user_client, object_map):
         """Check that action with changed display name can't be launched by its name"""
+        cluster, *_ = as_user_objects(user_client, object_map['Cluster'])
         try:
-            user_object_map['Cluster'].action(name='alternative_display_name').run()
-        except (AccessIsDenied, NoSuchEndpointOrAccessIsDenied):
+            cluster.action(name='alternative_display_name').run()
+        except (AccessIsDenied, NoSuchEndpointOrAccessIsDenied, ObjectNotFound):
             pass
         else:
             raise AssertionError("Action that changed display name shouldn't be allowed to run")
@@ -172,37 +181,47 @@ def check_new_action_can_be_launched(self, clients, user, upgraded_cluster: Clus
         """Check that policy can be created to run new action from cluster bundle and action actually can be launched"""
         service = upgraded_cluster.service()
         component = service.component()
-        for adcm_object in as_user_objects(clients.user, upgraded_cluster, service, component):
+        for adcm_object in upgraded_cluster, service, component:
             business_role = action_business_role(adcm_object, NEW_ACTION)
             create_action_policy(clients.admin, adcm_object, business_role, user=user)
-            is_allowed(adcm_object, business_role).wait()
+            is_allowed(as_user_objects(clients.user, adcm_object)[0], business_role).wait()
 
     @allure.step('Check display_name based role works on "mimic" action')
-    def check_new_action_with_old_display_name(self, user_object_map):
+    def check_new_action_with_old_display_name(self, user_client, user_object_map):
         """Check that new action that have display_name of another action from old version can be launched"""
         cluster = user_object_map['Cluster']
         business_role = action_business_role(cluster, MIMIC_NAME)
-        is_allowed(cluster, business_role)
+        is_allowed(as_user_objects(user_client, cluster)[0], business_role)
 
     def check_roles_are_allowed(
         self,
+        user_client: ADCMClient,
         cluster_object_map: Dict[ClusterObjectClassName, ClusterRelatedObject],
         business_roles: Iterable[BusinessRole],
     ):
         """Check that given roles are allowed to be launched"""
         for role in business_roles:
-            adcm_object = self._get_object_from_map_by_role_name(role.role_name, cluster_object_map)
+            adcm_object, *_ = as_user_objects(
+                user_client, self._get_object_from_map_by_role_name(role.role_name, cluster_object_map)
+            )
             is_allowed(adcm_object, role).wait()
 
     def check_roles_are_denied(
         self,
+        user_client: ADCMClient,
         cluster_object_map: Dict[ClusterObjectClassName, ClusterRelatedObject],
         business_roles: Iterable[BusinessRole],
     ):
         """Check that given roles aren't allowed to be launched"""
         for role in business_roles:
             adcm_object = self._get_object_from_map_by_role_name(role.role_name, cluster_object_map)
-            is_denied(adcm_object, role)
+            action_id = adcm_object.action(display_name=get_action_display_name_from_role_name(role.role_name)).id
+            rule_with_denied = BusinessRole(
+                role.role_name,
+                role.method_call,
+                ForbiddenCallChecker(adcm_object.__class__, f'action/{action_id}/run', HTTPMethod.POST),
+            )
+            is_denied(adcm_object, rule_with_denied, client=user_client)
 
     def _get_objects_map(self, objects):
         """Represent an object in form of an object map: { classname: object }"""
diff --git a/tests/functional/rbac/actions/utils.py b/tests/functional/rbac/actions/utils.py
deleted file mode 100644
index 714dca1cb0..0000000000
--- a/tests/functional/rbac/actions/utils.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Generic helpers for RBAC actions testing"""
-
-from typing import Union, List
-
-import allure
-from adcm_client.objects import ADCMClient, Policy
-from adcm_pytest_plugin.utils import random_string
-
-from tests.functional.rbac.conftest import BusinessRole
-from tests.functional.tools import AnyADCMObject
-
-
-def action_business_role(adcm_object: AnyADCMObject, action_display_name: str) -> BusinessRole:
-    """Construct BusinessRole that allows to run action"""
-    role_name = get_action_role_name(adcm_object, action_display_name)
-    return BusinessRole(
-        role_name, lambda user_obj, *args, **kwargs: user_obj.action(display_name=action_display_name).run(**kwargs)
-    )
-
-
-@allure.step("Create policy that allows to run action")
-def create_action_policy(
-    client: ADCMClient,
-    adcm_object: Union[AnyADCMObject, List[AnyADCMObject]],
-    *business_roles: BusinessRole,
-    user=None,
-    group=None,
-) -> Policy:
-    """Create policy based on business roles"""
-    if not (user or group):
-        raise ValueError("Either user or group should be provided to create policy")
-    user = user or []
-    group = group or []
-    child_roles = [{'id': client.role(name=role.role_name).id} for role in business_roles]
-    role_name = f"Test Action Role {random_string(6)}"
-    action_parent_role = client.role_create(name=role_name, display_name=role_name, child=child_roles)
-    return client.policy_create(
-        name=f"Test Action Policy {role_name[-6:]}",
-        role=action_parent_role,
-        objects=adcm_object if isinstance(adcm_object, list) else [adcm_object],
-        user=user if isinstance(user, list) else [user],
-        group=group if isinstance(group, list) else [group],
-    )
-
-
-def get_action_role_name(adcm_object: AnyADCMObject, action_display_name: str):
-    """Construct "umbrella" role name for an action with specified name"""
-    return f'{adcm_object.prototype().type.capitalize()} Action: {action_display_name}'
diff --git a/tests/functional/rbac/checkers.py b/tests/functional/rbac/checkers.py
new file mode 100644
index 0000000000..56eb8c101f
--- /dev/null
+++ b/tests/functional/rbac/checkers.py
@@ -0,0 +1,208 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Checker for checking if performing some actions is truly denied"""
+
+import json
+import re
+from functools import partial
+from typing import Type, Collection, Union, Callable, Optional
+from urllib import parse
+
+import allure
+import requests
+from adcm_client.base import ObjectNotFound
+from adcm_client.objects import (
+    ADCMClient,
+    Cluster,
+    Service,
+    Component,
+    Provider,
+    Host,
+    User,
+    Group,
+    Role,
+    Policy,
+    Bundle,
+    ADCM,
+)
+
+from tests.library.consts import HTTPMethod
+from tests.functional.tools import AnyADCMObject, AnyRBACObject
+
+RoleTargetObject = Union[AnyADCMObject, AnyRBACObject, Bundle, ADCM]
+RoleTargetType = Type[RoleTargetObject]
+
+
+class ForbiddenCallChecker:  # pylint: disable=too-few-public-methods
+    """
+    Helper class to build a checker that ensures that
+    interaction with an ADCM object is truly forbidden via direct calls to API
+    """
+
+    _API_ROOT = '/api/v1/'
+
+    # this regex should match word characters between { and } that ends in "id"
+    _format_id_arg_regexp = re.compile(r'{(\w*id)}')
+    _method_map = {
+        ADCM: 'adcm/{id}/',
+        Bundle: 'stack/bundle/{id}/',
+        Cluster: 'cluster/{id}/',
+        Service: 'cluster/{cluster_id}/service/{id}/',
+        Component: 'cluster/{cluster_id}/service/{service_id}/component/{id}/',
+        Provider: 'provider/{id}/',
+        Host: 'provider/{provider_id}/host/{id}/',
+        User: 'rbac/user/{id}/',
+        Group: 'rbac/group/{id}/',
+        Role: 'rbac/role/{id}/',
+        Policy: 'rbac/policy/{id}/',
+        # add new entries here (jobs, tasks)
+    }
+
+    # Here the function is stored that will form required URL part (before suffix)
+    # for the object that was passed to `__call__` function
+    # First argument is adcm_object, it's better to allow passing kwargs
+    _build_resource_path: Callable[..., str]
+    is_of_correct_type: Callable[[RoleTargetObject], bool]
+
+    def __init__(
+        self,
+        object_type: Union[RoleTargetType, Collection[RoleTargetType]],
+        endpoint_suffix: str,
+        method: HTTPMethod,
+        *,
+        special_case: Optional[str] = None,
+    ):
+        if special_case:
+            # rework to switch maybe if you have time
+            # and maybe add enum to list all possible cases not in string form
+            special_cases = {
+                'create-from-bundle': self._build_create_from_bundle_resource_path,
+                'host-on-cluster': self._build_resource_path_for_host_on_cluster,
+                'upgrade': self._build_resource_path_for_upgrade,
+            }
+            self._build_resource_path = special_cases[special_case]
+        else:
+            self._build_resource_path = self._build_default_resource_path
+        if isinstance(object_type, Collection):
+            self.is_of_correct_type = lambda obj: obj.__class__ in object_type
+        else:
+            self.is_of_correct_type = lambda obj: obj.__class__ == object_type
+        self.object_type = object_type
+        self.url_suffix = endpoint_suffix.lstrip('/')
+        self.method = method
+
+    def __call__(self, client: ADCMClient, adcm_object: AnyADCMObject, *args, **kwargs):
+        """
+        Try to access the resource / perform an action by:
+        1. Building URL for a given object
+        2. Requesting this URL with one of HTTP methods with authorization from `client` argument
+        3. Raise an AssertionError if response was 500
+        4. Raise an AssertionError if response wasn't 403 (because it's Forbidden checker)
+        """
+        resource_path = self._build_resource_path(adcm_object)
+        path_without_base_url = f'{self._API_ROOT}{resource_path}'.replace('//', '/')
+        url = parse.urljoin(client.url, path_without_base_url)
+        call_api_method = getattr(requests, self.method.value)
+        with allure.step(f'Send {self.method.name} request to {path_without_base_url}'):
+            response: requests.Response = call_api_method(
+                url,
+                headers={
+                    'Authorization': f'Token {client.api_token()}',
+                    'Content-Type': 'application/json',
+                },
+            )
+        if (status_code := response.status_code) >= 500:
+            raise AssertionError(f'Unhandled exception on {self.method.name} call to {url} check logs')
+        # if request is forbidden or object is present (404 with "correct" URL)
+        if status_code == 403 or (
+            status_code == 404
+            and not (response.headers['Content-Type'] == 'text/html' and 'Not Found' in response.text)
+        ):
+            return
+        try:
+            body = json.dumps(response.json(), indent=4)
+            attachment_type = allure.attachment_type.JSON
+        except requests.exceptions.JSONDecodeError:
+            body = response.text
+            attachment_type = allure.attachment_type.HTML
+        allure.attach(name=f'Response on call to {url}', body=body, attachment_type=attachment_type)
+        raise AssertionError(
+            f'Unexpected status code, call to {url} should be denied, but status code was {status_code}'
+        )
+
+    def _build_default_resource_path(self, adcm_object: RoleTargetObject, **_) -> str:
+        """Build resource path string for "basic" entities and actions"""
+        self._raise_on_incorrect_type(adcm_object)
+        infix_template = self._method_map[adcm_object.__class__]
+        template_format_arguments = {
+            format_arg: getattr(adcm_object, format_arg)
+            for format_arg in self._format_id_arg_regexp.findall(infix_template)
+        }
+        return f'{infix_template.format(**template_format_arguments)}{self.url_suffix}/'
+
+    def _build_resource_path_for_host_on_cluster(self, adcm_object: Host, **_):  # pylint: disable=no-self-use
+        """Build resource path string for host that belongs to a cluster"""
+        if not isinstance(adcm_object, Host) or not adcm_object.cluster_id:
+            raise ValueError(f'Object {adcm_object} should be of type Host and be bond to a cluster')
+        return f'cluster/{adcm_object.cluster_id}/host/{adcm_object.id}/'
+
+    def _build_resource_path_for_upgrade(self, adcm_object, **_):
+        """Build resource path for an upgrade action assuming there's available upgrade with id=1"""
+        self._raise_on_incorrect_type(adcm_object)
+        # upgrade only for cluster, provider, so nothing but id matters
+        object_suffix = self._method_map[adcm_object.__class__].format(id=adcm_object.id)
+        # we assume that it's always the first
+        return f'{object_suffix}upgrade/1/do/'
+
+    def _build_create_from_bundle_resource_path(self, adcm_object, **_):
+        """Build resource for creating entities from the bundle object"""
+        self._raise_on_incorrect_type(adcm_object)
+        try:
+            adcm_object.cluster_prototype()
+            return 'cluster/'
+        except ObjectNotFound:
+            return 'provider/'
+
+    def _raise_on_incorrect_type(self, adcm_object):
+        """
+        Raise ValueError if object type is incorrect, because it means that you've passed incorrect object to call
+        """
+        if not self.is_of_correct_type(adcm_object):
+            raise ValueError(f'Object {adcm_object} should be of type {self.object_type}')
+
+
+def _deny_endpoint_call(endpoint: str, method: HTTPMethod):
+    return partial(ForbiddenCallChecker, endpoint_suffix=endpoint, method=method)
+
+
+class Deny:  # pylint: disable=too-few-public-methods
+    """Description of possible "deny" checks"""
+
+    ViewConfigOf = _deny_endpoint_call('config/current', HTTPMethod.GET)
+    ChangeConfigOf = _deny_endpoint_call('config/history', HTTPMethod.POST)
+    AddServiceToCluster = ForbiddenCallChecker(Cluster, 'service', HTTPMethod.POST)
+    RemoveServiceFromCluster = ForbiddenCallChecker(Service, '', HTTPMethod.DELETE)
+    AddHostToCluster = ForbiddenCallChecker(Cluster, 'host', HTTPMethod.POST)
+    RemoveHostFromCluster = ForbiddenCallChecker(Host, '', HTTPMethod.DELETE, special_case='host-on-cluster')
+    Delete = _deny_endpoint_call('', HTTPMethod.DELETE)
+    ViewImportsOf = _deny_endpoint_call('import', HTTPMethod.GET)
+    ManageImportsOf = _deny_endpoint_call('bind', HTTPMethod.POST)
+    ViewHostComponentOf = _deny_endpoint_call('hostcomponent', HTTPMethod.GET)
+    EditHostComponentOf = _deny_endpoint_call('hostcomponent', HTTPMethod.POST)
+    # here we let special case to fully build suffix
+    CreateCluster = ForbiddenCallChecker(Bundle, '', HTTPMethod.POST, special_case='create-from-bundle')
+    CreateProvider = ForbiddenCallChecker(Bundle, '', HTTPMethod.POST, special_case='create-from-bundle')
+    CreateHost = ForbiddenCallChecker(Provider, 'host', HTTPMethod.POST)
+    UpgradeProvider = ForbiddenCallChecker(Provider, '', HTTPMethod.POST, special_case='upgrade')
+    UpgradeCluster = ForbiddenCallChecker(Cluster, '', HTTPMethod.POST, special_case='upgrade')
+    Change = _deny_endpoint_call('', HTTPMethod.PUT)  # change user, role, etc
diff --git a/tests/functional/rbac/conftest.py b/tests/functional/rbac/conftest.py
index 04a128c149..aebb9ad1c4 100644
--- a/tests/functional/rbac/conftest.py
+++ b/tests/functional/rbac/conftest.py
@@ -13,21 +13,38 @@
 import itertools
 import os
 from enum import Enum
+from functools import partial
 from operator import methodcaller
-from typing import Callable, NamedTuple, Union, List, Tuple, Collection
+from typing import Callable, NamedTuple, Union, List, Tuple, Collection, Optional
 
 import allure
 import pytest
-from adcm_client.base import NoSuchEndpointOrAccessIsDenied, BaseAPIObject
-from adcm_client.objects import ADCMClient, User, Group, Cluster, Service, Component, Provider, Host, Bundle, Role
-from adcm_client.wrappers.api import AccessIsDenied
+from adcm_client.base import NoSuchEndpointOrAccessIsDenied, BaseAPIObject, ObjectNotFound
+from adcm_client.objects import (
+    ADCMClient,
+    User,
+    Group,
+    Cluster,
+    Service,
+    Component,
+    Provider,
+    Host,
+    Bundle,
+    Role,
+    ADCM,
+    Policy,
+)
+from adcm_client.wrappers.api import AccessIsDenied, ADCMApiWrapper
 from adcm_pytest_plugin.utils import catch_failed, random_string
 
+from tests.functional.rbac.checkers import Deny
+from tests.functional.tools import get_object_represent, AnyADCMObject, ADCMObjects
+
+
 # pylint: disable=redefined-outer-name,unused-argument
 
 # Enum names doesn't conform to UPPER_CASE naming style
 # pylint: disable=invalid-name
-from tests.functional.tools import get_object_represent, AnyADCMObject
 
 
 def pytest_collection_modifyitems(session, config, items: list):
@@ -85,6 +102,7 @@ class BusinessRole(NamedTuple):
 
     role_name: str
     method_call: Callable
+    check_denied: Optional[Callable] = None
 
 
 class BusinessRoles(Enum):
@@ -92,65 +110,136 @@ class BusinessRoles(Enum):
 
     # pylint: disable=invalid-name
 
-    ViewAnyObjectConfiguration = BusinessRole("View any object configuration", methodcaller("config"))
-    ViewAnyObjectHostComponents = BusinessRole("View any object host-components", methodcaller("hostcomponent"))
-    ViewAnyObjectImport = BusinessRole("View any object import", methodcaller("imports"))
-
-    ViewClusterConfigurations = BusinessRole("View cluster configurations", methodcaller("config"))
-    ViewServiceConfigurations = BusinessRole("View service configurations", methodcaller("config"))
-    ViewComponentConfigurations = BusinessRole("View component configurations", methodcaller("config"))
-    ViewProviderConfigurations = BusinessRole("View provider configurations", methodcaller("config"))
-    ViewHostConfigurations = BusinessRole("View host configurations", methodcaller("config"))
-
-    EditClusterConfigurations = BusinessRole("Edit cluster configurations", methodcaller("config_set_diff", {}))
-    EditServiceConfigurations = BusinessRole("Edit service configurations", methodcaller("config_set_diff", {}))
-    EditComponentConfigurations = BusinessRole("Edit component configurations", methodcaller("config_set_diff", {}))
-    EditProviderConfigurations = BusinessRole("Edit provider configurations", methodcaller("config_set_diff", {}))
-    EditHostConfigurations = BusinessRole("Edit host configurations", methodcaller("config_set_diff", {}))
-
-    ViewImports = BusinessRole("View imports", methodcaller("imports"))
-    ManageImports = BusinessRole("Manage imports", lambda x, *args: x.bind(*args))
-    ViewHostComponents = BusinessRole("View host-components", methodcaller("hostcomponent"))
-    EditHostComponents = BusinessRole("Edit host-components", lambda x, *args: x.hostcomponent_set(*args))
-    AddService = BusinessRole("Add service", methodcaller("service_add", name="new_service"))
-    RemoveService = BusinessRole("Remove service", lambda x, *args: x.service_delete(*args))
-    RemoveHosts = BusinessRole("Remove hosts", methodcaller("delete"))
-    MapHosts = BusinessRole("Map hosts", lambda x, *args: x.host_add(*args))
-    UnmapHosts = BusinessRole("Unmap hosts", lambda x, *args: x.host_delete(*args))
-    UpgradeClusterBundle = BusinessRole("Upgrade cluster bundle", lambda x: x.upgrade().do())
-    UpgradeProviderBundle = BusinessRole("Upgrade provider bundle", lambda x: x.upgrade().do())
-    CreateHostProvider = BusinessRole(
-        "Create provider", lambda x: x.provider_create(name=f"new_provider {random_string(5)}")
-    )
-    CreateHost = BusinessRole("Create host", lambda x: x.host_create(fqdn=f"new_host_{random_string(5)}"))
-    RemoveHostProvider = BusinessRole("Remove provider", methodcaller("delete"))
-    CreateCluster = BusinessRole("Create cluster", lambda x: x.cluster_create(name=f"new_cluster {random_string(5)}"))
-    RemoveCluster = BusinessRole("Remove cluster", methodcaller("delete"))
+    # ADCM Client root roles
+
+    GetAllClusters = BusinessRole("Get cluster", lambda x, **kwargs: x.cluster(**kwargs))
+    GetAllServices = BusinessRole("Get service", lambda x, **kwargs: x.service(**kwargs))
+    GetAllComponents = BusinessRole("Get component", lambda x, **kwargs: x.component(**kwargs))
+    GetAllProviders = BusinessRole("Get provider", lambda x, **kwargs: x.provider(**kwargs))
+    GetAllHosts = BusinessRole("Get host", lambda x, **kwargs: x.host(**kwargs))
+    GetCluster = BusinessRole("Get cluster object", lambda x, **kwargs: x.cluster(**kwargs))
+    GetService = BusinessRole("Get service object", lambda x, **kwargs: x.service(**kwargs))
+    GetComponent = BusinessRole("Get component object", lambda x, **kwargs: x.component(**kwargs))
+    GetProvider = BusinessRole("Get provider object", lambda x, **kwargs: x.provider(**kwargs))
+    GetHost = BusinessRole("Get host object", lambda x, **kwargs: x.host(**kwargs))
+    GetTaskAndJob = BusinessRole("Get task and jobs", lambda x, **kwargs: x.task(**kwargs))
+
     UploadBundle = BusinessRole("Upload bundle", methodcaller("upload_from_fs", os.path.join(DATA_DIR, "dummy")))
-    RemoveBundle = BusinessRole("Remove bundle", methodcaller("delete"))
-    ViewADCMSettings = BusinessRole("View ADCM settings", methodcaller("config"))
-    EditADCMSettings = BusinessRole("Edit ADCM settings", methodcaller("config_set_diff", {}))
+
     ViewUsers = BusinessRole("View users", methodcaller("user_list"))
     CreateUser = BusinessRole("Create user", methodcaller("user_create", username="test", password="test"))
-    RemoveUser = BusinessRole("Remove user", methodcaller("delete"))
-    EditUser = BusinessRole("Edit user", lambda x: x.update(first_name=random_string(5)))
+    ViewGroups = BusinessRole("View group", methodcaller("group_list"))
+    CreateGroup = BusinessRole("Create group", methodcaller("group_create", name="test"))
     ViewRoles = BusinessRole("View roles", methodcaller("role_list"))
     CreateCustomRoles = BusinessRole(
         "Create custom role",
-        methodcaller("role_create", name="Custom role", display_name="Custom role", child=[{"id": 2}]),
+        lambda client: client.role_create(
+            name="Custom role",
+            display_name="Custom role",
+            child=[{"id": 5}],  # business role without parametrization
+        ),
     )
-    RemoveRoles = BusinessRole("Remove roles", methodcaller("delete"))
-    EditRoles = BusinessRole("Edit role", lambda x: x.update(display_name=random_string(5)))
-    ViewGroups = BusinessRole("View group", methodcaller("group_list"))
-    CreateGroup = BusinessRole("Create group", methodcaller("group_create", name="test"))
-    RemoveGroup = BusinessRole("Remove group", methodcaller("delete"))
-    EditGroup = BusinessRole("Edit group", lambda x: x.update(name=random_string(5)))
     ViewPolicies = BusinessRole("View policy", methodcaller("policy_list"))
     CreatePolicy = BusinessRole(
         "Create policy", lambda x, **kwargs: x.policy_create(name="Test policy", objects=[], **kwargs)
     )
-    RemovePolicy = BusinessRole("Remove policy", methodcaller("delete"))
-    EditPolicy = BusinessRole("Edit policy", lambda x: x.update(name=random_string(5)))
+
+    # ADCM client objects roles (should be checked directly by endpoint)
+
+    ViewAnyObjectConfiguration = BusinessRole(
+        "View any object configuration", methodcaller("config"), Deny.ViewConfigOf(ADCMObjects)
+    )
+    ViewAnyObjectHostComponents = BusinessRole(
+        "View any object host-components", methodcaller("hostcomponent"), Deny.ViewHostComponentOf((Cluster, Service))
+    )
+    ViewAnyObjectImport = BusinessRole(
+        "View any object import", methodcaller("imports"), Deny.ViewImportsOf((Cluster, Service))
+    )
+
+    ViewClusterConfigurations = BusinessRole(
+        "View cluster configurations", methodcaller("config"), Deny.ViewConfigOf(Cluster)
+    )
+    ViewServiceConfigurations = BusinessRole(
+        "View service configurations", methodcaller("config"), Deny.ViewConfigOf(Service)
+    )
+    ViewComponentConfigurations = BusinessRole(
+        "View component configurations", methodcaller("config"), Deny.ViewConfigOf(Component)
+    )
+    ViewProviderConfigurations = BusinessRole(
+        "View provider configurations", methodcaller("config"), Deny.ViewConfigOf(Provider)
+    )
+    ViewHostConfigurations = BusinessRole("View host configurations", methodcaller("config"), Deny.ViewConfigOf(Host))
+
+    CreateHostProvider = BusinessRole(
+        "Create provider", lambda x: x.provider_create(name=f"new_provider {random_string(5)}"), Deny.CreateProvider
+    )
+    CreateCluster = BusinessRole(
+        "Create cluster", lambda x: x.cluster_create(name=f"new_cluster {random_string(5)}"), Deny.CreateCluster
+    )
+    EditClusterConfigurations = BusinessRole(
+        "Edit cluster configurations", methodcaller("config_set_diff", {}), Deny.ChangeConfigOf(Cluster)
+    )
+    EditServiceConfigurations = BusinessRole(
+        "Edit service configurations", methodcaller("config_set_diff", {}), Deny.ChangeConfigOf(Service)
+    )
+    EditComponentConfigurations = BusinessRole(
+        "Edit component configurations", methodcaller("config_set_diff", {}), Deny.ChangeConfigOf(Component)
+    )
+    EditProviderConfigurations = BusinessRole(
+        "Edit provider configurations", methodcaller("config_set_diff", {}), Deny.ChangeConfigOf(Provider)
+    )
+    EditHostConfigurations = BusinessRole(
+        "Edit host configurations", methodcaller("config_set_diff", {}), Deny.ChangeConfigOf(Host)
+    )
+
+    ViewImports = BusinessRole("View imports", methodcaller("imports"), Deny.ViewImportsOf((Cluster, Service)))
+    ManageImports = BusinessRole(
+        "Manage imports", lambda x, *args: x.bind(*args), Deny.ManageImportsOf((Cluster, Service))
+    )
+    ManageClusterImports = BusinessRole(
+        "Manage cluster imports", lambda x, *args: x.bind(*args), Deny.ManageImportsOf(Cluster)
+    )
+    ManageServiceImports = BusinessRole(
+        "Manage service imports", lambda x, *args: x.bind(*args), Deny.ManageImportsOf(Service)
+    )
+
+    ViewHostComponents = BusinessRole(
+        "View host-components", methodcaller("hostcomponent"), Deny.ViewHostComponentOf(Cluster)
+    )
+    EditHostComponents = BusinessRole(
+        "Edit host-components", lambda x, *args: x.hostcomponent_set(*args), Deny.EditHostComponentOf(Cluster)
+    )
+
+    AddService = BusinessRole("Add service", methodcaller("service_add", name="new_service"), Deny.AddServiceToCluster)
+    RemoveService = BusinessRole(
+        "Remove service", lambda x, *args: x.service_delete(*args), Deny.RemoveServiceFromCluster
+    )
+    RemoveHosts = BusinessRole("Remove hosts", methodcaller("delete"), Deny.Delete(Host))
+    MapHosts = BusinessRole("Map hosts", lambda x, *args: x.host_add(*args), Deny.AddHostToCluster)
+    UnmapHosts = BusinessRole("Unmap hosts", lambda x, *args: x.host_delete(*args), Deny.RemoveHostFromCluster)
+
+    UpgradeClusterBundle = BusinessRole("Upgrade cluster bundle", lambda x: x.upgrade().do(), Deny.UpgradeCluster)
+    UpgradeProviderBundle = BusinessRole("Upgrade provider bundle", lambda x: x.upgrade().do(), Deny.UpgradeProvider)
+    CreateHost = BusinessRole(
+        "Create host", lambda x: x.host_create(fqdn=f"new_host_{random_string(5)}"), Deny.CreateHost
+    )
+    RemoveHostProvider = BusinessRole("Remove provider", methodcaller("delete"), Deny.Delete(Provider))
+    RemoveCluster = BusinessRole("Remove cluster", methodcaller("delete"), Deny.Delete(Cluster))
+    RemoveBundle = BusinessRole("Remove bundle", methodcaller("delete"), Deny.Delete(Bundle))
+
+    ViewADCMSettings = BusinessRole("View ADCM settings", methodcaller("config"), Deny.ViewConfigOf(ADCM))
+    EditADCMSettings = BusinessRole(
+        "Edit ADCM settings", methodcaller("config_set_diff", {}), Deny.ChangeConfigOf(ADCM)
+    )
+
+    RemoveUser = BusinessRole("Remove user", methodcaller("delete"), Deny.Delete(User))
+    EditUser = BusinessRole("Edit user", lambda x: x.update(first_name=random_string(5)), Deny.Change(User))
+    RemoveRoles = BusinessRole("Remove roles", methodcaller("delete"), Deny.Delete(Role))
+    EditRoles = BusinessRole("Edit role", lambda x: x.update(display_name=random_string(5)), Deny.Change(Role))
+    RemoveGroup = BusinessRole("Remove group", methodcaller("delete"), Deny.Delete(Group))
+    EditGroup = BusinessRole("Edit group", lambda x: x.update(name=random_string(5)), Deny.Change(Group))
+    RemovePolicy = BusinessRole("Remove policy", methodcaller("delete"), Deny.Delete(Policy))
+    EditPolicy = BusinessRole("Edit policy", lambda x: x.update(name=random_string(5)), Deny.Change(Policy))
 
     # aliases for view/edit_config_of funcs
     ViewADCMConfigurations = ViewADCMSettings
@@ -181,6 +270,26 @@ def edit_config_of(adcm_object) -> RbacRoles:
 PROVIDER_EDIT_CONFIG_ROLES = (BusinessRoles.EditProviderConfigurations, BusinessRoles.EditHostConfigurations)
 
 
+@pytest.fixture()
+@allure.title("Create test user")
+def user(sdk_client_fs) -> User:
+    """Create user for testing"""
+    return sdk_client_fs.user_create(*TEST_USER_CREDENTIALS)
+
+
+@pytest.fixture()
+def user_sdk(user, adcm_fs) -> ADCMClient:
+    """Returns ADCMClient object from adcm_client with testing user"""
+    username, password = TEST_USER_CREDENTIALS
+    return ADCMClient(url=adcm_fs.url, user=username, password=password)
+
+
+@pytest.fixture()
+def is_denied_to_user(user_sdk: ADCMClient) -> Callable:
+    """Return partially initialized `is_denied` function with `client` argument set to `user_sdk`"""
+    return partial(is_denied, client=user_sdk)
+
+
 @pytest.fixture()
 def clients(sdk_client_fs, user_sdk) -> SDKClients:
     """Get "container" with admin and user clients"""
@@ -188,12 +297,14 @@ def clients(sdk_client_fs, user_sdk) -> SDKClients:
 
 
 @pytest.fixture()
-def user_policy(request, user, sdk_client_fs, prepare_objects):
+def user_policy(request, user, sdk_client_fs, user_sdk, prepare_objects):
     """
     Create testing role and policy
     Parametrize this fixture with `use_role` decorator
     """
-    return create_policy(sdk_client_fs, request.param, objects=prepare_objects, users=[user], groups=[])
+    policy = create_policy(sdk_client_fs, request.param, objects=prepare_objects, users=[user], groups=[])
+    user_sdk.reread()
+    return policy
 
 
 def use_role(role: Union[BusinessRoles, Collection[BusinessRoles]]):
@@ -243,9 +354,19 @@ def second_objects(sdk_client_fs):
     return cluster, service, component, provider, host
 
 
+def get_as_client_object(api: ADCMApiWrapper, obj: AnyADCMObject, **kwargs):
+    """Get representation of an object from perspective of given user (client)"""
+    return obj.__class__(api, id=obj.id, **kwargs)
+
+
 def as_user_objects(user_sdk: ADCMClient, *objects: AnyADCMObject) -> Tuple[AnyADCMObject, ...]:
     """Get prepared objects via tested user sdk"""
-    return tuple((obj.__class__(user_sdk._api, id=obj.id) for obj in objects))  # pylint: disable=protected-access
+    api = user_sdk._api  # pylint: disable=protected-access
+    objects_repr = ", ".join(get_object_represent(obj) for obj in objects)
+    username = user_sdk.me().username
+    with allure.step(f'Get object from perspective of {username}: {objects_repr}'):
+        with catch_failed(ObjectNotFound, f"Failed to get one of following objects for {username}: {objects_repr}"):
+            return tuple((get_as_client_object(api, obj) for obj in objects))
 
 
 @allure.step("Delete policy")
@@ -272,16 +393,19 @@ def create_policy(
         "host": list(filter(lambda x: isinstance(x, Host), objects)),
     }
     child = []
-    for perm in [permission] if isinstance(permission, BusinessRoles) else permission:
-        role_name = perm.value.role_name
-        business_role = sdk_client.role(name=role_name)
-        child.append({"id": business_role.id})
     role_name = f"Testing {random_string(5)}"
-    role = sdk_client.role_create(
-        name=role_name,
-        display_name=role_name,
-        child=child,
-    )
+    if isinstance(permission, Role):
+        role = permission
+    else:
+        for perm in [permission] if isinstance(permission, BusinessRoles) else permission:
+            business_role_name = perm.value.role_name
+            business_role = sdk_client.role(name=business_role_name)
+            child.append({"id": business_role.id})
+        role = sdk_client.role_create(
+            name=role_name,
+            display_name=role_name,
+            child=child,
+        )
     if use_all_objects:
         suitable_objects = objects
     elif role.parametrized_by_type:
@@ -298,11 +422,27 @@ def create_policy(
 
 
 def is_allowed(
-    base_object: Union[BaseAPIObject, ADCMClient], business_role: Union[BusinessRole, BusinessRoles], *args, **kwargs
+    base_object: Union[BaseAPIObject, ADCMClient],
+    business_role: Union[BusinessRole, BusinessRoles],
+    *args,
+    raise_on_superuser: bool = True,
+    **kwargs,
 ):
     """
-    Assert that role is allowed on object
+    Assert that role is allowed on object.
     """
+    if raise_on_superuser:
+        if isinstance(base_object, ADCMClient):
+            is_superuser = base_object.me().is_superuser
+        else:
+            is_superuser = base_object._client.rbac.me.read()['is_superuser']  # pylint: disable=protected-access
+        if is_superuser:
+            raise ValueError(
+                "Object that is passed to `is_allowed` method should be an object representative "
+                "from a perspective of regular user, not a superuser.\n"
+                "If you want to check if the interaction is allowed to a superuser, "
+                "pass `False` to `raise_on_superuser` keyword argument."
+            )
     role: BusinessRole = business_role.value if isinstance(business_role, BusinessRoles) else business_role
     with allure.step(f"Assert that {role.role_name} on {get_object_represent(base_object)} is allowed"), catch_failed(
         (AccessIsDenied, NoSuchEndpointOrAccessIsDenied),
@@ -312,19 +452,55 @@ def is_allowed(
 
 
 def is_denied(
-    base_object: Union[BaseAPIObject, ADCMClient], business_role: Union[BusinessRole, BusinessRoles], *args, **kwargs
+    base_object: Union[BaseAPIObject, ADCMClient],
+    business_role: Union[BusinessRole, BusinessRoles],
+    *args,
+    client: Optional[ADCMClient] = None,
+    is_list: bool = False,
+    **kwargs,
 ):
     """
-    Assert that role is denied on object
+    Assert that role is denied on object.
+
+    You may find confusing how `is_allowed` and `is_denied` not mirroring themselves.
+    At first, they were: both were based purely on ADCM client and admin-user objects from it.
+    But now "getting" object is a part of permission system,
+      so we can't "get any object from user client and perform an action on it"
+      to check if action is truly denied, because we'll fail on receiving an object.
+    So we check the denial of "direct" action via API it this action is performed on another object,
+      rather than on ADCM client itself,
+      to be sure that we're not checking only the "not allowed via client" situation.
+
+    `is_list` marks if called resource is "list" to check if list is empty (equal to access is denied)
     """
     role: BusinessRole = business_role.value if isinstance(business_role, BusinessRoles) else business_role
-    with allure.step(f"Assert that {role.role_name} on {get_object_represent(base_object)} is denied"):
-        try:
-            role.method_call(base_object, *args, **kwargs)
-        except (AccessIsDenied, NoSuchEndpointOrAccessIsDenied):
-            pass
+    object_is_client = isinstance(base_object, ADCMClient)
+    # either `base_object` should be ADCMClient or both role.check_denied and client should be presented
+    # notice that priority is given to the first part
+    if not (object_is_client or (role.check_denied and client)):
+        raise ValueError(
+            "You shouldn't try to check if the role actions is denied on objects that are not of type ADCMClient "
+            "without providing denial checker.\n"
+            "When you pass `business_role` with denial checker, you must also provide `client` argument to check "
+            "against which ADCMClient to check denial.\n"
+            "To understand motivation behind this please check documentation of `is_denied` method."
+        )
+    object_represent = get_object_represent(base_object)
+    with allure.step(f"Assert that {role.role_name} on {object_represent} is denied"):
+        if object_is_client:
+            if is_list:
+                assert (
+                    len(role.method_call(base_object, *args, **kwargs)) == 0
+                ), f"{role.role_name} on {object_represent} should not be allowed: items were found in response body"
+            else:
+                try:
+                    role.method_call(base_object, *args, **kwargs)
+                except (AccessIsDenied, NoSuchEndpointOrAccessIsDenied):
+                    pass
+                else:
+                    raise AssertionError(f"{role.role_name} on {object_represent} should not be allowed")
         else:
-            raise AssertionError(f"{role.role_name} on {get_object_represent(base_object)} should not be allowed")
+            role.check_denied(client, base_object)
 
 
 def extract_role_short_info(role: Role) -> RoleShortInfo:
diff --git a/tests/functional/rbac/test_access_to_objects.py b/tests/functional/rbac/test_access_to_objects.py
new file mode 100644
index 0000000000..ab4f692685
--- /dev/null
+++ b/tests/functional/rbac/test_access_to_objects.py
@@ -0,0 +1,588 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Test that granting any permission on object allows user to:
+- see this object in the list of objects
+- get this object from ADCM client
+"""
+
+import os.path
+from contextlib import contextmanager
+from typing import Callable, Set, List, Iterable
+
+import allure
+import pytest
+from adcm_client.base import ObjectNotFound
+from adcm_client.objects import ADCMClient, Task, Cluster, Service, Component, Provider, User
+from adcm_pytest_plugin.utils import catch_failed
+
+from tests.library.utils import lower_class_name
+from tests.functional.tools import get_object_represent
+from tests.functional.rbac.conftest import (
+    DATA_DIR,
+    BusinessRoles as BR,
+    get_as_client_object,
+    delete_policy,
+    create_policy,
+    RbacRoles,
+    SDKClients,
+)
+from tests.functional.rbac.action_role_utils import create_action_policy, action_business_role
+
+# pylint: disable=no-self-use
+
+
+@contextmanager
+def granted_policy(client, business_role, adcm_object, user):
+    """Create policy based on business role and delete if afterwards"""
+    policy = create_policy(client, business_role, [adcm_object], [user], [])
+    yield policy
+    delete_policy(policy)
+
+
+class TestAccessToBasicObjects:
+    """
+    Test granting access to default objects:
+    cluster, service, component, provider, host
+    """
+
+    # pylint: disable-next=too-many-locals
+    def test_access_to_cluster_from_service_role(self, clients, user, prepare_objects, second_objects):
+        """
+        Test that granting permission on service grants permission to "view" service and cluster
+        """
+        all_objects = prepare_objects + second_objects
+        cluster, service, component, provider, host = prepare_objects
+        not_viewable_objects = (component, provider, host) + second_objects
+        cluster_and_service = (cluster, service)
+
+        for business_role in (BR.ViewServiceConfigurations, BR.EditServiceConfigurations, BR.ViewImports):
+            objects_to_check = ', '.join(map(lower_class_name, cluster_and_service))
+            with allure.step(
+                f'Check that granting "{business_role.value.role_name}" role to service '
+                f'gives view access to: {objects_to_check}'
+            ):
+                check_objects_are_not_viewable(clients.user, all_objects)
+                with granted_policy(clients.admin, business_role, service, user):
+                    check_objects_are_viewable(clients.user, cluster_and_service)
+                    check_objects_are_not_viewable(clients.user, not_viewable_objects)
+                check_objects_are_not_viewable(clients.user, all_objects)
+
+    def test_access_to_parents_from_component_role(self, clients, user, prepare_objects, second_objects):
+        """
+        Test that granting permission on component grants permission to "view" component, service and cluster
+        """
+        all_objects = prepare_objects + second_objects
+        cluster, service, component, *provider_objects = prepare_objects
+        cluster_objects = (cluster, service, component)
+
+        for business_role in (BR.ViewComponentConfigurations, BR.EditComponentConfigurations):
+            with allure.step(
+                f'Check that granting "{business_role.value.role_name}" role to component '
+                'gives access to "view" cluster'
+            ):
+                check_objects_are_not_viewable(clients.user, all_objects)
+                with granted_policy(clients.admin, business_role, component, user):
+                    check_objects_are_viewable(clients.user, cluster_objects)
+                    check_objects_are_not_viewable(clients.user, tuple(provider_objects) + second_objects)
+                check_objects_are_not_viewable(clients.user, all_objects)
+
+    @pytest.mark.extra_rbac()
+    def test_hierarchy_access_to_host(self, clients, user, cluster_bundle, provider_bundle):
+        """
+        Test that user can get host
+        when it is bonded to a cluster (user has permission to get this cluster),
+        when host is added to a cluster
+        when permission is granted before/after host is added
+        """
+        cluster = cluster_bundle.cluster_create(name='Test Cluster')
+        provider = provider_bundle.provider_create(name='Test Provider')
+        first_host, second_host = provider.host_create('host-1'), provider.host_create('host-2')
+
+        with allure.step('Add host to a cluster and check "view" permissions are granted'):
+            cluster.host_add(first_host)
+            check_objects_are_not_viewable(clients.user, [first_host, second_host])
+
+        with allure.step('Create policy on cluster and check "view" permission exists on added host'):
+            policy = create_policy(clients.admin, BR.ViewHostComponents, [cluster], [user], [])
+            check_objects_are_viewable(clients.user, [first_host])
+            check_objects_are_not_viewable(clients.user, [second_host])
+
+        with allure.step('Add second host and check "view" permission is granted on it'):
+            cluster.host_add(second_host)
+            check_objects_are_viewable(clients.user, [first_host, second_host])
+
+        with allure.step('Remove first host and check "view" permission is withdrawn'):
+            cluster.host_delete(first_host)
+            check_objects_are_viewable(clients.user, [second_host])
+            check_objects_are_not_viewable(clients.user, [first_host])
+
+        with allure.step('Remove policy and check "view" permissions were withdrawn'):
+            delete_policy(policy)
+            check_objects_are_not_viewable(clients.user, [first_host, second_host])
+
+    @pytest.mark.extra_rbac()
+    def test_hostcomponent_set(self, clients, user, prepare_objects, second_objects):
+        """
+        Test that hostcomponent can be set via ADCM client: user can get component and hosts on cluster
+        """
+        cluster, service, component, provider, host = prepare_objects
+        check_objects_are_not_viewable(clients.user, prepare_objects + second_objects)
+        with granted_policy(clients.admin, BR.EditHostComponents, cluster, user):
+            cluster.host_add(host)
+            check_objects_are_viewable(clients.user, [cluster, service, component, host])
+            check_objects_are_not_viewable(clients.user, [provider] + list(second_objects))
+        check_objects_are_not_viewable(clients.user, prepare_objects + second_objects)
+
+
+class TestActionBasedAccess:
+    """Test that granting permission to run action grants "view" permissions on an owner object"""
+
+    @pytest.fixture()
+    def cluster_with_host_action(self, sdk_client_fs):
+        """Create cluster with host action"""
+        bundle = sdk_client_fs.upload_from_fs(os.path.join(DATA_DIR, "cluster_with_host_action"))
+        return bundle.cluster_create(name='Cool Test Cluster')
+
+    @pytest.fixture()
+    def host(self, cluster_with_host_action, provider_bundle):
+        """Host object from "regular" provider that is added to cluster with host action"""
+        provider = provider_bundle.provider_create(name='Cool Test Provider')
+        return cluster_with_host_action.host_add(provider.host_create('see-mee-with-action'))
+
+    def test_action_permission_grants_access_to_owner_object(self, clients, user, prepare_objects, second_objects):
+        """
+        Test that permission on action of an object grants permission to "view" this object
+        """
+        objects = set(prepare_objects)
+        another_objects = set(second_objects)
+        all_objects = objects | another_objects
+
+        for adcm_object in objects:
+            with allure.step(
+                f'Add permission to run action on {adcm_object.__class__.__name__} and check if it became visible'
+            ):
+                check_objects_are_not_viewable(clients.user, all_objects)
+                policy = create_action_policy(
+                    clients.admin,
+                    adcm_object,
+                    action_business_role(adcm_object, 'No config action', no_deny_checker=True),
+                    user=user,
+                )
+                check_objects_are_viewable(clients.user, [adcm_object])
+                check_objects_are_not_viewable(
+                    clients.user, all_objects - self._get_object_and_parents_from_objects(adcm_object, all_objects)
+                )
+                delete_policy(policy)
+                check_objects_are_not_viewable(clients.user, all_objects)
+
+    def _get_object_and_parents_from_objects(self, adcm_object, objects) -> set:
+        """
+        Return set of object and its parents (if object is service or component) in set,
+        otherwise return just object itself in set
+        """
+        if isinstance(adcm_object, Service):
+            parent = next(obj for obj in objects if isinstance(obj, Cluster) and obj.id == adcm_object.cluster_id)
+            return {adcm_object, parent}
+        if isinstance(adcm_object, Component):
+            parents = set(
+                obj
+                for obj in objects
+                if (isinstance(obj, Service) and obj.id == adcm_object.service_id)
+                or (isinstance(obj, Cluster) and obj.id == adcm_object.cluster_id)
+            )
+            return parents | {adcm_object}
+        return {adcm_object}
+
+    @pytest.mark.extra_rbac()
+    def test_host_action_permission_grants_access_to_owner_object(self, clients, user, host, prepare_objects):
+        """
+        Test that permission on host actions grants permission to "view" host
+        """
+        cluster = host.cluster()
+        *other_objects, second_host = prepare_objects
+        check_objects_are_not_viewable(clients.user, (cluster, host) + prepare_objects)
+        policy = create_action_policy(
+            clients.admin,
+            cluster,
+            action_business_role(cluster, 'Host action', no_deny_checker=True),
+            user=user,
+        )
+        check_objects_are_viewable(clients.user, [cluster, host])
+        check_objects_are_not_viewable(clients.user, prepare_objects)
+        cluster.host_add(second_host)
+        check_objects_are_viewable(clients.user, [cluster, host, second_host])
+        check_objects_are_not_viewable(clients.user, other_objects)
+        with allure.step('Change host state and check nothing broke'):
+            host.action(name='host_action').run().wait()
+            check_objects_are_viewable(clients.user, [cluster, host])
+
+        delete_policy(policy)
+        check_objects_are_not_viewable(clients.user, [cluster, host])
+
+
+class TestAccessForJobsAndLogs:
+    """Test access for tasks, jobs, logs"""
+
+    REGULAR_ACTION = 'Regular action'
+    MULTIJOB_ACTION = 'Multijob'
+
+    SERVICE_NAME = 'test_service'
+
+    @allure.title('Cluster with service')
+    @pytest.fixture()
+    def cluster(self, sdk_client_fs) -> Cluster:
+        """Cluster with service"""
+        bundle = sdk_client_fs.upload_from_fs(os.path.join(DATA_DIR, 'jobs', 'cluster'))
+        cluster = bundle.cluster_create('Test Cluster')
+        cluster.service_add(name=self.SERVICE_NAME)
+        return cluster
+
+    @allure.title('Cluster without service')
+    @pytest.fixture()
+    def cluster_wo_service(self, cluster) -> Cluster:
+        """Cluster without service"""
+        cluster.service_delete(cluster.service())
+        return cluster
+
+    @allure.title('Cluster ready for upgrade')
+    @pytest.fixture()
+    def cluster_for_upgrade(self, sdk_client_fs) -> Cluster:
+        """Cluster ready for upgrade"""
+        path_to_upgrade_dir = os.path.join(os.path.dirname(__file__), 'actions', 'bundles', 'upgrade')
+        old = sdk_client_fs.upload_from_fs(os.path.join(path_to_upgrade_dir, 'old'))
+        sdk_client_fs.upload_from_fs(os.path.join(path_to_upgrade_dir, 'new'))
+        return old.cluster_create('Test Cluster for Upgrade')
+
+    @allure.title('Provider with host')
+    @pytest.fixture()
+    def provider(self, sdk_client_fs):
+        """Provider with host"""
+        bundle = sdk_client_fs.upload_from_fs(os.path.join(DATA_DIR, "jobs", "provider"))
+        provider = bundle.provider_create('Test Provider')
+        provider.host_create('test-host')
+        return provider
+
+    @pytest.fixture()
+    def finished_tasks(self, cluster, provider) -> List[Task]:
+        """Bunch of finished tasks"""
+        tasks = []
+        service = cluster.service()
+        for adcm_object in (cluster, service, service.component(), provider, provider.host()):
+            task = adcm_object.action(display_name=self.REGULAR_ACTION).run()
+            tasks.append(task)
+            task.wait()
+        return tasks
+
+    def test_access_to_tasks(
+        self, clients, user, cluster, provider, finished_tasks
+    ):  # pylint: disable=too-many-arguments
+        """
+        Test that user:
+        1. Have no access to task objects that were launched before user got permission to run action
+        2. Have access to task objects of allowed actions launched by all users after permission is granted
+        3. Have no access to task objects after policy deletion
+        """
+        service = cluster.service()
+        user_api = clients.user._api  # pylint: disable=protected-access
+        new_tasks = []
+
+        # add normal allure steps here
+        self.check_no_access_granted_for_tasks(clients.user, finished_tasks)
+        for adcm_object in (cluster, service, service.component(), provider, provider.host()):
+            with allure.step(
+                f'Create policy for running action "{self.MULTIJOB_ACTION}" on {adcm_object.__class__.__name__}'
+            ):
+                policy = create_action_policy(
+                    clients.admin,
+                    adcm_object,
+                    action_business_role(adcm_object, self.MULTIJOB_ACTION, no_deny_checker=True),
+                    user=user,
+                )
+                user_object = get_as_client_object(user_api, adcm_object)
+                user_task = user_object.action(display_name=self.MULTIJOB_ACTION).run()
+                user_task.wait()
+                admin_multijob = adcm_object.action(display_name=self.MULTIJOB_ACTION).run()
+                admin_multijob.wait()
+                admin_regular_task = adcm_object.action(display_name=self.REGULAR_ACTION).run()
+                admin_regular_task.wait()
+                new_tasks.extend((user_task, admin_multijob, admin_regular_task))
+                self.check_access_granted_for_tasks(clients.user, [user_task, admin_multijob])
+                self.check_no_access_granted_for_tasks(clients.user, finished_tasks + [admin_regular_task])
+                delete_policy(policy)
+                self.check_no_access_granted_for_tasks(clients.user, new_tasks + finished_tasks)
+
+    def test_access_to_tasks_on_service_add_remove(self, cluster_wo_service: Cluster, clients: SDKClients, user: User):
+        """
+        Test that service add/remove doesn't break permission to view task objects:
+        1. Add service
+        2. Create policy on action
+        3. Run action and check access to task objects is granted
+        4. Remove service and expect access remains
+        5. Add service again
+        6. Run action and check access to task objects of both tasks is granted
+        """
+        cluster = cluster_wo_service
+        service = cluster.service_add(name=self.SERVICE_NAME)
+        create_action_policy(
+            clients.admin,
+            service,
+            action_business_role(service, self.REGULAR_ACTION, no_deny_checker=True),
+            user=user,
+        )
+        with allure.step('Run action and check access to task objects'):
+            task = _run_and_wait(service, self.REGULAR_ACTION)
+            self.check_access_granted_for_tasks(clients.user, [task])
+        with allure.step('Delete service and check that access remains'):
+            cluster.service_delete(service)
+            self.check_access_granted_for_tasks(clients.user, [task])
+        with allure.step('Add service again'):
+            service = cluster.service_add(name=self.SERVICE_NAME)
+        with allure.step('Run action one more time and check access denied to both tasks'):
+            second_task = service.action(display_name=self.REGULAR_ACTION).run()
+            second_task.wait()
+            self.check_access_granted_for_tasks(clients.user, [task])
+            self.check_no_access_granted_for_tasks(clients.user, [second_task])
+
+    def test_access_to_tasks_on_cluster_host_add_remove(
+        self, cluster: Cluster, provider: Provider, clients: SDKClients, user: User
+    ):
+        """
+        Test that access to task objects is correct after host add/remove from cluster
+        """
+        host = provider.host()
+        create_action_policy(
+            clients.admin,
+            host,
+            action_business_role(host, self.REGULAR_ACTION, no_deny_checker=True),
+            user=user,
+        )
+        with allure.step('Run action and check that access is granted'):
+            task = _run_and_wait(host, self.REGULAR_ACTION)
+            self.check_access_granted_for_tasks(clients.user, [task])
+        with allure.step('Add host to cluster, run action and check access to tasks'):
+            cluster.host_add(host)
+            second_task = _run_and_wait(host, self.REGULAR_ACTION)
+            self.check_access_granted_for_tasks(clients.user, [task, second_task])
+        with allure.step('Remove host from cluster and check access to task objects'):
+            cluster.host_delete(host)
+            self.check_access_granted_for_tasks(clients.user, [task, second_task])
+
+    def test_access_to_tasks_on_hc_map_change(self, cluster, provider, clients, user):
+        """
+        Test that access for task objects is correct after HC map is changed
+        """
+        host = provider.host()
+        component = cluster.service().component()
+        with allure.step('Create permission to run action on host and component'):
+            for adcm_object in (host, component):
+                create_action_policy(
+                    clients.admin,
+                    adcm_object,
+                    action_business_role(adcm_object, self.REGULAR_ACTION, no_deny_checker=True),
+                    user=user,
+                )
+        with allure.step('Run actions and check access to them'):
+            host_task = _run_and_wait(host, self.REGULAR_ACTION)
+            component_task = _run_and_wait(component, self.REGULAR_ACTION)
+            self.check_access_granted_for_tasks(clients.user, [host_task, component_task])
+        with allure.step('Set HC map and check access to task objects'):
+            cluster.host_add(host)
+            cluster.hostcomponent_set((host, component))
+            second_host_task = _run_and_wait(host, self.REGULAR_ACTION)
+            second_component_task = _run_and_wait(component, self.REGULAR_ACTION)
+            self.check_access_granted_for_tasks(
+                clients.user, [host_task, component_task, second_host_task, second_component_task]
+            )
+        with allure.step('Change HC map and check access to task objects'):
+            second_host = provider.host_create('second-host')
+            cluster.host_add(second_host)
+            cluster.hostcomponent_set((second_host, component))
+            self.check_access_granted_for_tasks(
+                clients.user, [host_task, component_task, second_host_task, second_component_task]
+            )
+
+    @pytest.mark.extra_rbac()
+    def test_access_for_jobs_after_upgrade(self, cluster_for_upgrade, clients, user):
+        """
+        Test that access to task objects stays after the upgrade
+        """
+        cluster = cluster_for_upgrade
+        with granted_policy(
+            clients.admin, clients.admin.role(name=RbacRoles.ClusterAdministrator.value), cluster, user
+        ):
+            with allure.step('Run actions and check task objects are available'):
+                tasks = [_run_and_wait(cluster, action.display_name) for action in cluster.action_list()]
+                self.check_access_granted_for_tasks(clients.user, tasks)
+            with allure.step('Upgrade cluster and check task objects are still available'):
+                cluster.upgrade().do()
+                self.check_access_granted_for_tasks(clients.user, tasks)
+            with allure.step('Run actions after upgrade and check that all task objects are available'):
+                tasks.extend(_run_and_wait(cluster, action.display_name) for action in cluster.action_list())
+                self.check_access_granted_for_tasks(clients.user, tasks)
+
+    def test_roles_that_give_access_to_tasks(self, cluster, provider, clients, user):
+        """
+        Test that all roles that should give access to task objects truly grant it
+        """
+        service = cluster.service()
+        component = service.component()
+        host = provider.host()
+
+        with allure.step(
+            f'Check role {RbacRoles.ClusterAdministrator.value} grants access to task objects of '
+            'cluster, service, component and host'
+        ):
+            role = clients.admin.role(name=RbacRoles.ClusterAdministrator.value)
+            cluster.host_add(host)
+            with granted_policy(clients.admin, role, cluster, user):
+                tasks = [_run_and_wait(obj, self.REGULAR_ACTION) for obj in (cluster, service, component, host)]
+                self.check_access_granted_for_tasks(clients.user, tasks)
+            self.check_no_access_granted_for_tasks(clients.user, tasks)
+            cluster.host_delete(host)
+
+        with allure.step(
+            f'Check role {RbacRoles.ServiceAdministrator.value} grants access to task objects of service and component'
+        ):
+            role = clients.admin.role(name=RbacRoles.ServiceAdministrator.value)
+            with granted_policy(clients.admin, role, service, user):
+                tasks = [_run_and_wait(obj, self.REGULAR_ACTION) for obj in (service, component)]
+                self.check_access_granted_for_tasks(clients.user, tasks)
+            self.check_no_access_granted_for_tasks(clients.user, tasks)
+
+        with allure.step(
+            f'Check role {RbacRoles.ProviderAdministrator.value} grants access to task objects of provider and host'
+        ):
+            role = clients.admin.role(name=RbacRoles.ProviderAdministrator.value)
+            with granted_policy(clients.admin, role, provider, user):
+                tasks = [_run_and_wait(obj, self.REGULAR_ACTION) for obj in (provider, host)]
+                self.check_access_granted_for_tasks(clients.user, tasks)
+            self.check_no_access_granted_for_tasks(clients.user, tasks)
+
+    def test_access_after_one_of_two_action_permissions_is_removed(self, clients, user, cluster):
+        """
+        Test that when:
+        1. Permissions to run two actions are granted to user
+        2. User launched both actions
+        3. Permission on one of actions is withdrawn
+        User should be able to see logs of the permitted action
+        """
+        with allure.step('Grant user two policies on different actions on cluster'):
+            create_action_policy(
+                clients.admin,
+                cluster,
+                action_business_role(cluster, self.REGULAR_ACTION, no_deny_checker=True),
+                user=user,
+            )
+            multijob_policy = create_action_policy(
+                clients.admin,
+                cluster,
+                action_business_role(cluster, self.MULTIJOB_ACTION, no_deny_checker=True),
+                user=user,
+            )
+        with allure.step('Run both allowed actions'):
+            regular_task = _run_and_wait(cluster, self.REGULAR_ACTION)
+            multijob_task = _run_and_wait(cluster, self.MULTIJOB_ACTION)
+        with allure.step('Check that user have access for both tasks'):
+            self.check_access_granted_for_tasks(clients.user, [regular_task, multijob_task])
+        with allure.step(
+            'Delete policy on "multijob" and check that user now have access right only on "regular" task'
+        ):
+            delete_policy(multijob_policy)
+            self.check_access_granted_for_tasks(clients.user, [regular_task])
+            self.check_no_access_granted_for_tasks(clients.user, [multijob_task])
+
+    def check_access_granted_for_tasks(self, user_client: ADCMClient, tasks: Iterable[Task]):
+        """Check that access is granted to tasks, their jobs and logs"""
+        client_username = user_client.me().username
+        api = user_client._api  # pylint: disable=protected-access
+        with allure.step(f'Check that user "{client_username}" has no access for certain tasks, jobs and logs'):
+            for task in tasks:
+                with catch_failed(ObjectNotFound, 'Task object should be available directly via client'):
+                    get_as_client_object(api, task)
+                for job in task.job_list():
+                    with catch_failed(ObjectNotFound, 'Job and log objects should be available directly via client'):
+                        get_as_client_object(api, job)
+                        get_as_client_object(api, job.log(), path_args={'job_id': job.id})
+
+    def check_no_access_granted_for_tasks(self, user_client: ADCMClient, tasks: Iterable[Task]):
+        """Check there's no access to tasks, their jobs and logs"""
+        client_username = user_client.me().username
+        api = user_client._api  # pylint: disable=protected-access
+        with allure.step(f'Check that user "{client_username}" has no access for certain tasks, jobs and logs'):
+            for task in tasks:
+                _expect_not_found(api, task, 'Task object should not be available directly via client')
+                for job in task.job_list():
+                    _expect_not_found(api, job, 'Job object should be available directly via client')
+                    log = job.log()
+                    _expect_not_found(
+                        api, log, 'Log object should be available directly via client', path_args={'job_id': job.id}
+                    )
+
+
+def _get_objects_id(get_objects_list: Callable) -> Set[int]:
+    return {obj.id for obj in get_objects_list()}
+
+
+def _expect_not_found(api, obj, message, **kwargs):
+    try:
+        get_as_client_object(api, obj, **kwargs)
+    except ObjectNotFound:
+        pass
+    else:
+        raise AssertionError(message)
+
+
+def check_objects_are_viewable(user_client: ADCMClient, objects):
+    """Check that user can see objects in list and get them by id"""
+    client_username = user_client.me().username
+    api = user_client._api  # pylint: disable=protected-access
+    with allure.step(f'Check that certain objects are viewable to user "{client_username}"'):
+        for adcm_object in objects:
+            object_represent = get_object_represent(adcm_object)
+            with allure.step(f'Check that "{object_represent}" is available to user {client_username}'):
+                object_type_name = lower_class_name(adcm_object)
+                list_objects = getattr(user_client, f'{object_type_name}_list')
+                available_objects_ids = _get_objects_id(list_objects)
+                assert (
+                    adcm_object.id in available_objects_ids
+                ), f'Object "{object_represent}" should be listed in the list of {object_type_name}s'
+                with catch_failed(
+                    ObjectNotFound, f'Object "{object_represent}" should be available directly via client'
+                ):
+                    get_as_client_object(api, adcm_object)
+
+
+def check_objects_are_not_viewable(user_client: ADCMClient, objects):
+    """Check that user can't see objects in list and get them by id"""
+    client_username = user_client.me().username
+    api = user_client._api  # pylint: disable=protected-access
+    with allure.step(f'Check that certain objects are not viewable to user "{client_username}"'):
+        for adcm_object in objects:
+            object_represent = get_object_represent(adcm_object)
+            with allure.step(f'Check that "{object_represent}" is not available to user {client_username}'):
+                object_type_name = lower_class_name(adcm_object)
+                list_objects = getattr(user_client, f'{object_type_name}_list')
+                available_objects_ids = _get_objects_id(list_objects)
+                assert (
+                    adcm_object.id not in available_objects_ids
+                ), f'Object "{object_represent}" should not be listed in the list of {object_type_name}s'
+                _expect_not_found(
+                    api, adcm_object, f'Object "{object_represent}" should not be available directly via client'
+                )
+
+
+def _run_and_wait(adcm_object, action_display_name) -> Task:
+    task = adcm_object.action(display_name=action_display_name).run()
+    task.wait()
+    return task
diff --git a/tests/functional/rbac/test_adcm_related_permissions.py b/tests/functional/rbac/test_adcm_related_permissions.py
index 4ad33735cb..8efa14fb23 100644
--- a/tests/functional/rbac/test_adcm_related_permissions.py
+++ b/tests/functional/rbac/test_adcm_related_permissions.py
@@ -23,184 +23,184 @@
     is_denied,
     is_allowed,
     delete_policy,
-    as_user_objects,
 )
 
-pytestmark = [pytest.mark.full]
+pytestmark = [pytest.mark.extra_rbac]
 
 
 @use_role(BusinessRoles.ViewADCMSettings)
-def test_view_adcm_settings(user_policy, user_sdk: ADCMClient, prepare_objects):
+def test_view_adcm_settings(user_policy, user_sdk: ADCMClient, prepare_objects, is_denied_to_user):
     """Test that View ADCM Settings role is ok"""
-    (cluster,) = as_user_objects(user_sdk, prepare_objects[0])
+    cluster, *_ = prepare_objects
 
     is_allowed(user_sdk.adcm(), BusinessRoles.ViewADCMSettings)
-    is_denied(user_sdk.adcm(), BusinessRoles.EditADCMSettings)
-    is_denied(cluster, BusinessRoles.ViewClusterConfigurations)
+    is_denied_to_user(user_sdk.adcm(), BusinessRoles.EditADCMSettings)
+    is_denied_to_user(cluster, BusinessRoles.ViewClusterConfigurations)
 
     delete_policy(user_policy)
-    is_denied(user_sdk.adcm(), BusinessRoles.ViewADCMSettings)
+    is_denied_to_user(user_sdk.adcm(), BusinessRoles.ViewADCMSettings)
 
 
 @use_role(BusinessRoles.EditADCMSettings)
-def test_edit_adcm_settings(user_policy, user_sdk: ADCMClient, prepare_objects):
+def test_edit_adcm_settings(user_policy, user_sdk: ADCMClient, prepare_objects, is_denied_to_user):
     """Test that Edit ADCM Settings role is ok"""
-    (cluster,) = as_user_objects(user_sdk, prepare_objects[0])
+    cluster, *_ = prepare_objects
+    adcm = user_sdk.adcm()
 
-    is_allowed(user_sdk.adcm(), BusinessRoles.ViewADCMSettings)
-    is_allowed(user_sdk.adcm(), BusinessRoles.EditADCMSettings)
-    is_denied(cluster, BusinessRoles.ViewClusterConfigurations)
+    is_allowed(adcm, BusinessRoles.ViewADCMSettings)
+    is_allowed(adcm, BusinessRoles.EditADCMSettings)
+    is_denied_to_user(cluster, BusinessRoles.ViewClusterConfigurations)
 
     delete_policy(user_policy)
-    is_denied(user_sdk.adcm(), BusinessRoles.ViewADCMSettings)
-    is_denied(user_sdk.adcm(), BusinessRoles.EditADCMSettings)
+    is_denied_to_user(adcm, BusinessRoles.ViewADCMSettings, is_list=True)
+    is_denied_to_user(adcm, BusinessRoles.EditADCMSettings)
 
 
 @use_role(BusinessRoles.ViewUsers)
-def test_view_users(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient):
+def test_view_users(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient, is_denied_to_user):
     """Test that "View users" role is ok"""
 
     is_allowed(user_sdk, BusinessRoles.ViewUsers)
     is_denied(user_sdk, BusinessRoles.CreateUser)
-    simple_user = user_sdk.user(id=sdk_client_fs.user_create(username="test", password="test").id)
-    is_denied(simple_user, BusinessRoles.EditUser)
-    is_denied(simple_user, BusinessRoles.RemoveUser)
+    simple_user = sdk_client_fs.user_create(username="test", password="test")
+    is_denied_to_user(simple_user, BusinessRoles.EditUser)
+    is_denied_to_user(simple_user, BusinessRoles.RemoveUser)
 
     delete_policy(user_policy)
-    is_denied(user_sdk, BusinessRoles.ViewUsers)
+    is_denied(user_sdk, BusinessRoles.ViewUsers, is_list=True)
 
 
 @use_role(BusinessRoles.CreateUser)
-def test_create_users(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient):
+def test_create_users(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient, is_denied_to_user):
     """Test that "Create users" role is ok"""
 
     is_allowed(user_sdk, BusinessRoles.ViewUsers)
     is_allowed(user_sdk, BusinessRoles.CreateUser)
     simple_user = user_sdk.user(username="test")
-    is_denied(simple_user, BusinessRoles.EditUser)
-    is_denied(simple_user, BusinessRoles.RemoveUser)
+    is_denied_to_user(simple_user, BusinessRoles.EditUser)
+    is_denied_to_user(simple_user, BusinessRoles.RemoveUser)
 
     delete_policy(user_policy)
     sdk_client_fs.user(username="test").delete()
-    is_denied(user_sdk, BusinessRoles.ViewUsers)
+    is_denied(user_sdk, BusinessRoles.ViewUsers, is_list=True)
     is_denied(user_sdk, BusinessRoles.CreateUser)
 
 
 @use_role(BusinessRoles.EditUser)
-def test_edit_users(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient):
+def test_edit_users(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient, is_denied_to_user):
     """Test that "Edit users" role is ok"""
 
     is_allowed(user_sdk, BusinessRoles.ViewUsers)
     is_denied(user_sdk, BusinessRoles.CreateUser)
     simple_user = user_sdk.user(id=sdk_client_fs.user_create(username="test", password="test").id)
     is_allowed(simple_user, BusinessRoles.EditUser)
-    is_denied(simple_user, BusinessRoles.RemoveUser)
+    is_denied_to_user(simple_user, BusinessRoles.RemoveUser)
 
     delete_policy(user_policy)
-    is_denied(user_sdk, BusinessRoles.ViewUsers)
-    is_denied(simple_user, BusinessRoles.EditUser)
+    is_denied_to_user(user_sdk, BusinessRoles.ViewUsers, is_list=True)
+    is_denied_to_user(simple_user, BusinessRoles.EditUser)
 
 
 @use_role(BusinessRoles.RemoveUser)
-def test_remove_users(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient):
+def test_remove_users(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient, is_denied_to_user):
     """Test that "Remove users" role is ok"""
 
     is_allowed(user_sdk, BusinessRoles.ViewUsers)
     is_denied(user_sdk, BusinessRoles.CreateUser)
     simple_user = user_sdk.user(id=sdk_client_fs.user_create(username="test", password="test").id)
-    is_denied(simple_user, BusinessRoles.EditUser)
+    is_denied_to_user(simple_user, BusinessRoles.EditUser)
     is_allowed(simple_user, BusinessRoles.RemoveUser)
 
     delete_policy(user_policy)
-    is_denied(user_sdk, BusinessRoles.ViewUsers)
+    is_denied(user_sdk, BusinessRoles.ViewUsers, is_list=True)
 
 
 @use_role(BusinessRoles.ViewGroups)
-def test_view_groups(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient):
+def test_view_groups(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient, is_denied_to_user):
     """Test that "View groups" role is ok"""
 
     is_allowed(user_sdk, BusinessRoles.ViewGroups)
     is_denied(user_sdk, BusinessRoles.CreateGroup)
     simple_group = user_sdk.group(id=sdk_client_fs.group_create(name="test").id)
-    is_denied(simple_group, BusinessRoles.EditGroup)
-    is_denied(simple_group, BusinessRoles.RemoveGroup)
+    is_denied_to_user(simple_group, BusinessRoles.EditGroup)
+    is_denied_to_user(simple_group, BusinessRoles.RemoveGroup)
 
     delete_policy(user_policy)
-    is_denied(user_sdk, BusinessRoles.ViewGroups)
+    is_denied(user_sdk, BusinessRoles.ViewGroups, is_list=True)
 
 
 @use_role(BusinessRoles.CreateGroup)
-def test_create_groups(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient):
+def test_create_groups(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient, is_denied_to_user):
     """Test that "Create groups" role is ok"""
     is_allowed(user_sdk, BusinessRoles.ViewGroups)
     is_allowed(user_sdk, BusinessRoles.CreateGroup)
     simple_group = user_sdk.group(name="test")
-    is_denied(simple_group, BusinessRoles.EditGroup)
-    is_denied(simple_group, BusinessRoles.RemoveGroup)
+    is_denied_to_user(simple_group, BusinessRoles.EditGroup)
+    is_denied_to_user(simple_group, BusinessRoles.RemoveGroup)
 
     delete_policy(user_policy)
     sdk_client_fs.group(name="test").delete()
-    is_denied(user_sdk, BusinessRoles.ViewGroups)
+    is_denied(user_sdk, BusinessRoles.ViewGroups, is_list=True)
     is_denied(user_sdk, BusinessRoles.CreateGroup)
 
 
 @use_role(BusinessRoles.EditGroup)
-def test_edit_groups(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient):
+def test_edit_groups(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient, is_denied_to_user):
     """Test that "Edit groups" role is ok"""
 
     is_allowed(user_sdk, BusinessRoles.ViewGroups)
     is_denied(user_sdk, BusinessRoles.CreateGroup)
     simple_group = user_sdk.group(id=sdk_client_fs.group_create(name="test").id)
     is_allowed(simple_group, BusinessRoles.EditGroup)
-    is_denied(simple_group, BusinessRoles.RemoveGroup)
+    is_denied_to_user(simple_group, BusinessRoles.RemoveGroup)
 
     delete_policy(user_policy)
-    is_denied(user_sdk, BusinessRoles.ViewGroups)
-    is_denied(simple_group, BusinessRoles.EditGroup)
+    is_denied_to_user(user_sdk, BusinessRoles.ViewGroups, is_list=True)
+    is_denied_to_user(simple_group, BusinessRoles.EditGroup)
 
 
 @use_role(BusinessRoles.RemoveGroup)
-def test_remove_groups(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient):
+def test_remove_groups(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient, is_denied_to_user):
     """Test that "Remove groups" role is ok"""
 
     is_allowed(user_sdk, BusinessRoles.ViewGroups)
     is_denied(user_sdk, BusinessRoles.CreateGroup)
     simple_group = user_sdk.group(id=sdk_client_fs.group_create(name="test").id)
-    is_denied(simple_group, BusinessRoles.EditGroup)
+    is_denied_to_user(simple_group, BusinessRoles.EditGroup)
     is_allowed(simple_group, BusinessRoles.RemoveGroup)
 
     delete_policy(user_policy)
-    is_denied(user_sdk, BusinessRoles.ViewGroups)
+    is_denied_to_user(user_sdk, BusinessRoles.ViewGroups, is_list=True)
 
 
 @use_role(BusinessRoles.ViewRoles)
-def test_view_roles(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient):
+def test_view_roles(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient, is_denied_to_user):
     """Test that "View roles" role is ok"""
 
     is_allowed(user_sdk, BusinessRoles.ViewRoles)
-    is_denied(user_sdk, BusinessRoles.ViewUsers)
-    is_denied(user_sdk, BusinessRoles.ViewGroups)
-    is_denied(user_sdk, BusinessRoles.ViewPolicies)
+    is_denied(user_sdk, BusinessRoles.ViewUsers, is_list=True)
+    is_denied(user_sdk, BusinessRoles.ViewGroups, is_list=True)
+    is_denied(user_sdk, BusinessRoles.ViewPolicies, is_list=True)
     is_denied(user_sdk, BusinessRoles.CreateCustomRoles)
 
     BusinessRoles.CreateCustomRoles.value.method_call(sdk_client_fs)
     custom_role = user_sdk.role(name="Custom role")
-    is_denied(custom_role, BusinessRoles.EditRoles)
-    is_denied(custom_role, BusinessRoles.RemoveRoles)
+    is_denied_to_user(custom_role, BusinessRoles.EditRoles)
+    is_denied_to_user(custom_role, BusinessRoles.RemoveRoles)
 
     delete_policy(user_policy)
-    is_denied(user_sdk, BusinessRoles.ViewRoles)
+    is_denied(user_sdk, BusinessRoles.ViewRoles, is_list=True)
 
 
 @use_role(BusinessRoles.CreateCustomRoles)
-def test_create_custom_role(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient):
+def test_create_custom_role(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient, is_denied_to_user):
     """Test that "Create custom role" role is ok"""
 
     is_allowed(user_sdk, BusinessRoles.ViewRoles)
     is_allowed(user_sdk, BusinessRoles.CreateCustomRoles)
     custom_role = user_sdk.role(name="Custom role")
-    is_denied(custom_role, BusinessRoles.EditRoles)
-    is_denied(custom_role, BusinessRoles.RemoveRoles)
+    is_denied_to_user(custom_role, BusinessRoles.EditRoles)
+    is_denied_to_user(custom_role, BusinessRoles.RemoveRoles)
 
     delete_policy(user_policy)
     sdk_client_fs.role(id=custom_role.id).delete()
@@ -208,7 +208,7 @@ def test_create_custom_role(user_policy, user_sdk: ADCMClient, sdk_client_fs: AD
 
 
 @use_role(BusinessRoles.EditRoles)
-def test_edit_roles(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient):
+def test_edit_roles(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient, is_denied_to_user):
     """Test that "Edit role" role is ok"""
 
     is_allowed(user_sdk, BusinessRoles.ViewRoles)
@@ -217,10 +217,10 @@ def test_edit_roles(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClient
     BusinessRoles.CreateCustomRoles.value.method_call(sdk_client_fs)
     custom_role = user_sdk.role(name="Custom role")
     is_allowed(custom_role, BusinessRoles.EditRoles)
-    is_denied(custom_role, BusinessRoles.RemoveRoles)
+    is_denied_to_user(custom_role, BusinessRoles.RemoveRoles)
 
     delete_policy(user_policy)
-    is_denied(custom_role, BusinessRoles.EditRoles)
+    is_denied_to_user(custom_role, BusinessRoles.EditRoles)
 
 
 @use_role(BusinessRoles.RemoveRoles)
@@ -232,12 +232,12 @@ def test_remove_roles(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClie
 
     BusinessRoles.CreateCustomRoles.value.method_call(sdk_client_fs)
     custom_role = user_sdk.role(name="Custom role")
-    is_denied(custom_role, BusinessRoles.EditRoles)
+    is_denied(custom_role, BusinessRoles.EditRoles, client=user_sdk)
     is_allowed(custom_role, BusinessRoles.RemoveRoles)
 
     delete_policy(user_policy)
     BusinessRoles.CreateCustomRoles.value.method_call(sdk_client_fs)
-    is_denied(user_sdk, BusinessRoles.ViewRoles)
+    is_denied(user_sdk, BusinessRoles.ViewRoles, is_list=True)
 
 
 @use_role(BusinessRoles.ViewPolicies)
@@ -251,7 +251,7 @@ def test_view_policies(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMCli
     is_denied(user_sdk, BusinessRoles.CreatePolicy, role=custom_role, user=[user])
 
     delete_policy(user_policy)
-    is_denied(user_sdk, BusinessRoles.ViewPolicies)
+    is_denied(user_sdk, BusinessRoles.ViewPolicies, is_list=True)
 
 
 @use_role(BusinessRoles.CreatePolicy)
@@ -264,8 +264,8 @@ def test_create_policy(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMCli
     is_allowed(user_sdk, BusinessRoles.ViewPolicies)
     is_allowed(user_sdk, BusinessRoles.CreatePolicy, role=custom_role, user=[user])
     policy = user_sdk.policy(name="Test policy")
-    is_denied(policy, BusinessRoles.EditPolicy)
-    is_denied(policy, BusinessRoles.RemovePolicy)
+    is_denied(policy, BusinessRoles.EditPolicy, client=user_sdk)
+    is_denied(policy, BusinessRoles.RemovePolicy, client=user_sdk)
 
     delete_policy(user_policy)
     sdk_client_fs.policy(id=policy.id).delete()
@@ -285,11 +285,11 @@ def test_edit_policy(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMClien
         id=sdk_client_fs.policy_create(name="Test policy", objects=[], role=custom_role, user=[user]).id
     )
     is_allowed(custom_policy, BusinessRoles.EditPolicy)
-    is_denied(custom_policy, BusinessRoles.RemovePolicy)
+    is_denied(custom_policy, BusinessRoles.RemovePolicy, client=user_sdk)
 
     delete_policy(user_policy)
-    is_denied(user_sdk, BusinessRoles.ViewPolicies)
-    is_denied(custom_policy, BusinessRoles.EditPolicy)
+    is_denied(user_sdk, BusinessRoles.ViewPolicies, is_list=True)
+    is_denied(custom_policy, BusinessRoles.EditPolicy, client=user_sdk)
 
 
 @use_role(BusinessRoles.RemovePolicy)
@@ -304,9 +304,9 @@ def test_remove_policy(user_policy, user_sdk: ADCMClient, sdk_client_fs: ADCMCli
     custom_policy = user_sdk.policy(
         id=sdk_client_fs.policy_create(name="Test policy", objects=[], role=custom_role, user=[user]).id
     )
-    is_denied(custom_policy, BusinessRoles.EditPolicy)
+    is_denied(custom_policy, BusinessRoles.EditPolicy, client=user_sdk)
     is_allowed(custom_policy, BusinessRoles.RemovePolicy)
 
     delete_policy(user_policy)
     sdk_client_fs.policy_create(name="Test policy", objects=[], role=custom_role, user=[user])
-    is_denied(user_sdk, BusinessRoles.ViewPolicies)
+    is_denied(user_sdk, BusinessRoles.ViewPolicies, is_list=True)
diff --git a/tests/functional/rbac/test_built_in_roles_composition.py b/tests/functional/rbac/test_built_in_roles_composition.py
index 5f931d5cf3..20761d89ac 100644
--- a/tests/functional/rbac/test_built_in_roles_composition.py
+++ b/tests/functional/rbac/test_built_in_roles_composition.py
@@ -16,28 +16,41 @@
 
 import allure
 import pytest
-from adcm_client.objects import ADCMClient, Role, User
+from adcm_client.base import NoSuchEndpointOrAccessIsDenied
+from adcm_client.objects import ADCMClient, Role
+from adcm_client.wrappers.api import AccessIsDenied
+from adcm_pytest_plugin.utils import catch_failed
 
 from tests.library.assertions import is_superset_of
 from tests.functional.rbac.conftest import BusinessRoles
 
-pytestmark = [pytest.mark.full]
+pytestmark = [pytest.mark.extra_rbac]
 
 ADCM_USER_ROLES = {
     role.value.role_name
     for role in (
+        BusinessRoles.GetAllClusters,
+        BusinessRoles.GetAllServices,
+        BusinessRoles.GetAllComponents,
+        BusinessRoles.GetAllProviders,
+        BusinessRoles.GetAllHosts,
         BusinessRoles.ViewAnyObjectConfiguration,
         BusinessRoles.ViewAnyObjectImport,
         BusinessRoles.ViewAnyObjectHostComponents,
     )
 }
+
 SERVICE_ADMIN_ROLES = {
     role.value.role_name
     for role in (
+        BusinessRoles.GetService,
+        BusinessRoles.GetComponent,
+        BusinessRoles.GetHost,
         BusinessRoles.EditServiceConfigurations,
         BusinessRoles.EditComponentConfigurations,
         BusinessRoles.ViewHostConfigurations,
-        BusinessRoles.ManageImports,
+        BusinessRoles.ManageServiceImports,
+        BusinessRoles.ViewHostComponents,
     )
 }
 
@@ -45,6 +58,7 @@
     {
         role.value.role_name
         for role in (
+            BusinessRoles.ManageClusterImports,
             BusinessRoles.EditClusterConfigurations,
             BusinessRoles.EditHostConfigurations,
             BusinessRoles.MapHosts,
@@ -55,6 +69,8 @@
             BusinessRoles.UpgradeClusterBundle,
             BusinessRoles.UploadBundle,
             BusinessRoles.RemoveBundle,
+            BusinessRoles.CreateHost,
+            BusinessRoles.RemoveHosts,
         )
     }
 )
@@ -62,6 +78,8 @@
 PROVIDER_ADMIN_ROLES = {
     role.value.role_name
     for role in (
+        BusinessRoles.GetProvider,
+        BusinessRoles.GetHost,
         BusinessRoles.UpgradeProviderBundle,
         BusinessRoles.EditProviderConfigurations,
         BusinessRoles.EditHostConfigurations,
@@ -72,18 +90,6 @@
     )
 }
 
-BASE_ROLES = {
-    'Get ADCM object',
-    'Get provider',
-    'Get host',
-    'Get cluster',
-    'Get service',
-    'Get component',
-    'Get task and jobs',
-    'Get stack',
-    'Get concerns',
-}
-
 
 def get_children_business_roles(role: Role) -> List[str]:
     """
@@ -96,19 +102,21 @@ def get_children_business_roles(role: Role) -> List[str]:
     return result
 
 
-def test_default_role(user: User, sdk_client_fs: ADCMClient):
+@pytest.mark.usefixtures('prepare_objects')
+def test_default_role(clients):
     """
     Check that newly created user has role "ADCM User"
     """
-    policies = sdk_client_fs.policy_list()
-    user_policies = tuple(filter(lambda p: user.id in (u.id for u in p.user_list()), policies))
-    with allure.step('Check default user policy and roles'):
-        assert len(user_policies) == 1, 'User should have default policy after creation'
-        role_children = {r.name for r in user_policies[0].role().child_list()}
-        assert role_children == BASE_ROLES, (
-            f'Default roles should be {_set_to_string(BASE_ROLES)}.\n'
-            f'But the following were found: {_set_to_string(role_children)}.'
-        )
+    user_client = clients.user
+    assert user_client.bundle_list(), 'Default user should see bundles in bundle list'
+    with catch_failed(
+        (AccessIsDenied, NoSuchEndpointOrAccessIsDenied), 'Default user should be able to view ADCM objects'
+    ):
+        user_client.adcm()
+    for object_type in ('cluster', 'service', 'component', 'provider', 'host'):
+        assert (
+            len(getattr(user_client, f'{object_type}_list')()) == 0
+        ), f'List of {object_type} should be empty to default user'
 
 
 def test_composition(sdk_client_fs: ADCMClient):
diff --git a/tests/functional/rbac/test_bundle_deletion.py b/tests/functional/rbac/test_bundle_deletion.py
index 2f592a245b..1bbcf26134 100644
--- a/tests/functional/rbac/test_bundle_deletion.py
+++ b/tests/functional/rbac/test_bundle_deletion.py
@@ -23,7 +23,7 @@
 from tests.functional.rbac.conftest import RoleType, extract_role_short_info
 from tests.library.assertions import sets_are_equal
 
-pytestmark = [pytest.mark.full()]
+pytestmark = [pytest.mark.extra_rbac]
 
 BUNDLE_V1 = 'cluster'
 BUNDLE_V2 = 'cluster_v2'
diff --git a/tests/functional/rbac/test_business_permissions_data/cluster_with_host_action/config.yaml b/tests/functional/rbac/test_business_permissions_data/cluster_with_host_action/config.yaml
new file mode 100644
index 0000000000..d8c0abc9f9
--- /dev/null
+++ b/tests/functional/rbac/test_business_permissions_data/cluster_with_host_action/config.yaml
@@ -0,0 +1,38 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+- type: cluster
+  name: cluster_with_host_action
+  version: 3
+
+  actions:
+    just_action:
+      type: job
+      script_type: ansible
+      script: ./actions.yaml
+      display_name: "Just action"
+      states:
+        available: any
+
+    host_action:
+      type: job
+      script_type: ansible
+      script: ./actions.yaml
+      display_name: "Host action"
+      states:
+        available:
+          - created
+        on_success: initialized
+        on_fail: bad_state_very_bad
+      host_action: true
+
+
diff --git a/python/api/stats/serializers.py b/tests/functional/rbac/test_business_permissions_data/jobs/cluster/actions.yaml
similarity index 71%
rename from python/api/stats/serializers.py
rename to tests/functional/rbac/test_business_permissions_data/jobs/cluster/actions.yaml
index e132b1f09d..abe736f561 100644
--- a/python/api/stats/serializers.py
+++ b/tests/functional/rbac/test_business_permissions_data/jobs/cluster/actions.yaml
@@ -10,10 +10,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from rest_framework import serializers
-from api.api_views import hlink
-
-
-class StatsSerializer(serializers.Serializer):
-    task = hlink('task-stats', 'id', 'task_id')
-    job = hlink('job-stats', 'id', 'job_id')
+---
+- name: "SeeMeInAction"
+  hosts: localhost
+  tasks:
+    - name: "Success"
+      assert:
+        that:
+          - 1 == 1
+        msg: "Never gonna give you up"
diff --git a/tests/functional/rbac/test_business_permissions_data/jobs/cluster/config.yaml b/tests/functional/rbac/test_business_permissions_data/jobs/cluster/config.yaml
new file mode 100644
index 0000000000..5731ff2d00
--- /dev/null
+++ b/tests/functional/rbac/test_business_permissions_data/jobs/cluster/config.yaml
@@ -0,0 +1,51 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+- type: cluster
+  version: 4.9
+  name: test_cluster
+
+  actions: &actions
+    regular_action:
+      type: job
+      script_type: ansible
+      script: ./actions.yaml
+      display_name: "Regular action"
+      states:
+        available: any
+
+    multijob:
+      type: task
+      display_name: "Multijob"
+      scripts:
+        - &multijob
+          name: first_step
+          script_type: ansible
+          script: ./actions.yaml
+          params:
+            ansible_tags: success
+        - <<: *multijob
+          name: second_step
+        - <<: *multijob
+          name: third_step
+      states:
+        available: any
+
+- type: service
+  version: 3.4
+  name: test_service
+
+  actions: *actions
+
+  components:
+    test_component:
+      actions: *actions
diff --git a/tests/functional/rbac/test_business_permissions_data/jobs/provider/actions.yaml b/tests/functional/rbac/test_business_permissions_data/jobs/provider/actions.yaml
new file mode 100644
index 0000000000..abe736f561
--- /dev/null
+++ b/tests/functional/rbac/test_business_permissions_data/jobs/provider/actions.yaml
@@ -0,0 +1,21 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+- name: "SeeMeInAction"
+  hosts: localhost
+  tasks:
+    - name: "Success"
+      assert:
+        that:
+          - 1 == 1
+        msg: "Never gonna give you up"
diff --git a/tests/functional/rbac/test_business_permissions_data/jobs/provider/config.yaml b/tests/functional/rbac/test_business_permissions_data/jobs/provider/config.yaml
new file mode 100644
index 0000000000..02d76abb7b
--- /dev/null
+++ b/tests/functional/rbac/test_business_permissions_data/jobs/provider/config.yaml
@@ -0,0 +1,48 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+- type: provider
+  version: 6.5
+  name: test_provider
+
+  actions: &actions
+    regular_action:
+      type: job
+      script_type: ansible
+      script: ./actions.yaml
+      display_name: "Regular action"
+      states:
+        available: any
+
+    multijob:
+      type: task
+      display_name: "Multijob"
+      scripts:
+        - &multijob
+          name: first_step
+          script_type: ansible
+          script: ./actions.yaml
+          params:
+            ansible_tags: success
+        - <<: *multijob
+          name: second_step
+        - <<: *multijob
+          name: third_step
+      states:
+        available: any
+
+
+- type: host
+  version: 2.54
+  name: test_host
+
+  actions: *actions
diff --git a/tests/functional/rbac/test_cluster_related_permissions.py b/tests/functional/rbac/test_cluster_related_permissions.py
index e58114cee3..4042faa6fb 100644
--- a/tests/functional/rbac/test_cluster_related_permissions.py
+++ b/tests/functional/rbac/test_cluster_related_permissions.py
@@ -13,6 +13,7 @@
 """Test business permissions related to cluster objects"""
 
 # pylint: disable=too-many-arguments,unused-argument,too-many-locals
+import itertools
 
 import allure
 import pytest
@@ -33,35 +34,44 @@
     PROVIDER_EDIT_CONFIG_ROLES,
 )
 
-pytestmark = [pytest.mark.full]
+pytestmark = [pytest.mark.extra_rbac]
 
 
-def _build_view_edit_permission_check(allowed_or_denied, get_view_or_edit):
+def _build_view_edit_allow(get_view_or_edit):
     """Helper to build multiple objects check functions"""
 
     def check(*objects):
         for adcm_object in objects:
-            allowed_or_denied(adcm_object, get_view_or_edit(adcm_object))
+            is_allowed(adcm_object, get_view_or_edit(adcm_object))
 
     return check
 
 
-is_allowed_to_view = _build_view_edit_permission_check(is_allowed, BR.view_config_of)
-is_allowed_to_edit = _build_view_edit_permission_check(is_allowed, BR.edit_config_of)
-is_denied_to_view = _build_view_edit_permission_check(is_denied, BR.view_config_of)
-is_denied_to_edit = _build_view_edit_permission_check(is_denied, BR.edit_config_of)
+def _build_view_edit_deny(get_view_or_edit):
+    """Helper to build multiple objects deny check functions"""
+
+    def check(*objects, client=None):
+        for adcm_object in objects:
+            is_denied(adcm_object, get_view_or_edit(adcm_object), client=client)
+
+    return check
+
+
+is_allowed_to_view = _build_view_edit_allow(BR.view_config_of)
+is_allowed_to_edit = _build_view_edit_allow(BR.edit_config_of)
+is_denied_to_view = _build_view_edit_deny(BR.view_config_of)
+is_denied_to_edit = _build_view_edit_deny(BR.edit_config_of)
 
 
 @use_role(CLUSTER_VIEW_CONFIG_ROLES)
 def test_view_application_configurations(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects):
     """Test that View application configuration role is ok"""
-    cluster, service, component, provider, host = as_user_objects(user_sdk, *prepare_objects)
-    cluster_via_admin, *_ = prepare_objects
-    user_second_objects = as_user_objects(user_sdk, *second_objects)
-    second_service_on_first_cluster = user_sdk.service(id=cluster_via_admin.service_add(name="new_service").id)
+    cluster, service, component, provider, host = prepare_objects
+    second_service_on_first_cluster = cluster.service_add(name="new_service")
     second_component_on_first_cluster = second_service_on_first_cluster.component(name="test_component")
 
-    objects_affected_by_policy = (
+    objects_affected_by_policy = as_user_objects(
+        user_sdk,
         cluster,
         service,
         component,
@@ -70,349 +80,374 @@ def test_view_application_configurations(user_policy: Policy, user_sdk: ADCMClie
     )
 
     is_allowed_to_view(*objects_affected_by_policy)
-    is_denied_to_edit(*objects_affected_by_policy)
-    is_denied_to_view(provider, host, *user_second_objects)
+    is_denied_to_edit(*objects_affected_by_policy, client=user_sdk)
+    is_denied_to_view(provider, host, *second_objects, client=user_sdk)
     delete_policy(user_policy)
-    is_denied_to_view(*objects_affected_by_policy)
+    is_denied_to_view(*objects_affected_by_policy, client=user_sdk)
 
 
 @use_role(PROVIDER_VIEW_CONFIG_ROLES)
 def test_view_infrastructure_configurations(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects):
     """Test that View infrastructure configuration role is ok"""
-    cluster, service, component, provider, host = as_user_objects(user_sdk, *prepare_objects)
-    *_, provider_via_admin, _ = prepare_objects
-    user_second_objects = as_user_objects(user_sdk, *second_objects)
-    second_host_on_first_provider = user_sdk.host(id=provider_via_admin.host_create(fqdn="new_host").id)
+    cluster, service, component, provider, host = prepare_objects
+    second_host_on_first_provider = provider.host_create(fqdn="new_host")
 
     # second host on first provider will be allowed to view because of provider's permission
-    is_allowed_to_view(provider, host, second_host_on_first_provider)
-    is_denied_to_edit(provider, host, second_host_on_first_provider)
-    is_denied_to_view(cluster, service, component, *user_second_objects)
+    allowed_to_view_objects = as_user_objects(user_sdk, provider, host, second_host_on_first_provider)
+    is_allowed_to_view(*allowed_to_view_objects)
+    is_denied_to_edit(*allowed_to_view_objects, client=user_sdk)
+    is_denied_to_view(cluster, service, component, *second_objects, client=user_sdk)
     delete_policy(user_policy)
-    is_denied_to_view(provider, host)
+    is_denied_to_view(*allowed_to_view_objects, client=user_sdk)
 
 
 @use_role(CLUSTER_EDIT_CONFIG_ROLES)
 def test_edit_application_configurations(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects):
     """Test that Edit application configuration role is ok"""
-    cluster, service, component, provider, host = as_user_objects(user_sdk, *prepare_objects)
-    user_second_objects = as_user_objects(user_sdk, *second_objects)
+    cluster, service, component, provider, host = prepare_objects
 
-    is_allowed_to_view(cluster, service, component)
-    is_allowed_to_edit(cluster, service, component)
-    is_denied_to_edit(*user_second_objects, user_sdk.adcm(), provider, host)
+    allowed_user_objects = as_user_objects(user_sdk, cluster, service, component)
+    is_allowed_to_view(*allowed_user_objects)
+    is_allowed_to_edit(*allowed_user_objects)
+    is_denied_to_edit(*second_objects, user_sdk.adcm(), provider, host, client=user_sdk)
     delete_policy(user_policy)
-    is_denied_to_edit(cluster, service, component)
-    is_denied_to_view(cluster, service, component)
+    is_denied_to_edit(*allowed_user_objects, client=user_sdk)
+    is_denied_to_view(*allowed_user_objects, client=user_sdk)
 
 
 @use_role(PROVIDER_EDIT_CONFIG_ROLES)
 def test_edit_infrastructure_configurations(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects):
     """Test that Edit infrastructure configuration role is ok"""
-    cluster, service, component, provider, host = as_user_objects(user_sdk, *prepare_objects)
-    user_second_objects = as_user_objects(user_sdk, *second_objects)
+    cluster, service, component, provider, host = prepare_objects
 
-    is_allowed_to_view(provider, host)
-    is_allowed_to_edit(provider, host)
-    is_denied_to_edit(*user_second_objects, user_sdk.adcm(), cluster, service, component)
+    allowed_user_objects = as_user_objects(user_sdk, provider, host)
+    is_allowed_to_view(*allowed_user_objects)
+    is_allowed_to_edit(*allowed_user_objects)
+    is_denied_to_edit(*second_objects, user_sdk.adcm(), cluster, service, component, client=user_sdk)
     delete_policy(user_policy)
-    is_denied_to_edit(provider, host)
-    is_denied_to_view(provider, host)
+    is_denied_to_edit(*allowed_user_objects, client=user_sdk)
+    is_denied_to_view(*allowed_user_objects, client=user_sdk)
 
 
 @use_role(BR.ViewImports)
-def test_view_imports(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects):
+def test_view_imports(user_policy: Policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects):
     """Test that View imports role is ok"""
-    cluster, service, *_ = as_user_objects(user_sdk, *prepare_objects)
-    second_cluster, second_service, *_ = as_user_objects(user_sdk, *second_objects)
-    for base_object in [cluster, service]:
+    admin_cluster_second, admin_service_second, *_ = second_objects
+    cluster, service = as_user_objects(user_sdk, *prepare_objects[:2])
+    for base_object in (cluster, service):
         is_allowed(base_object, BR.ViewImports)
-        is_denied(base_object, BR.ManageImports, second_service)
-    for base_object in [second_cluster, second_service]:
-        is_denied(base_object, BR.ViewImports)
+        is_denied_to_user(base_object, BR.ManageImports)
+    for base_object in (admin_cluster_second, admin_service_second):
+        is_denied_to_user(base_object, BR.ViewImports)
     delete_policy(user_policy)
-    for base_object in [cluster, service]:
-        is_denied(base_object, BR.ViewImports)
+    for base_object in (cluster, service):
+        is_denied_to_user(base_object, BR.ViewImports)
 
 
 @use_role(BR.ManageImports)
-def test_manage_imports(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects):
+def test_manage_imports(user_policy: Policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects):
     """Test that Manage imports role is ok"""
-    cluster, service, *_ = as_user_objects(user_sdk, *prepare_objects)
-    cluster_via_admin, service_via_admin, *_ = prepare_objects
-    second_cluster, second_service, *_ = as_user_objects(user_sdk, *second_objects)
+    admin_cluster, admin_service, *_ = prepare_objects
+    cluster, service = as_user_objects(user_sdk, admin_cluster, admin_service)
+    admin_cluster_second, admin_service_second, *_ = second_objects
 
     for base_object in [cluster, service]:
         is_allowed(base_object, BR.ViewImports)
-        is_allowed(base_object, BR.ManageImports, second_service)
-    for base_object in [second_cluster, second_service]:
-        is_denied(base_object, BR.ViewImports)
+        is_allowed(base_object, BR.ManageImports, admin_service_second)
+    for base_object in [admin_cluster_second, admin_service_second]:
+        is_denied_to_user(base_object, BR.ViewImports)
     delete_policy(user_policy)
-    _ = (bind.delete() for bind in cluster_via_admin.bind_list())
-    _ = (bind.delete() for bind in service_via_admin.bind_list())
-    for base_object in [cluster, service]:
-        is_denied(base_object, BR.ViewImports)
-        is_denied(base_object, BR.ManageImports, second_service)
+    for bind in itertools.chain(admin_cluster.bind_list(), admin_service.bind_list()):
+        bind.delete()
+    for base_object in [admin_cluster, admin_service]:
+        is_denied_to_user(base_object, BR.ViewImports)
+        is_denied_to_user(base_object, BR.ManageImports, admin_service_second)
 
 
 @use_role(BR.ViewHostComponents)
-def test_view_hostcomponents(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects):
+def test_view_hostcomponents(
+    user_policy: Policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects
+):
     """Test that View host-components role is ok"""
-    cluster, _, component, _, host = as_user_objects(user_sdk, *prepare_objects)
     cluster_via_admin, *_, host_via_admin = prepare_objects
-    second_cluster, *_ = as_user_objects(user_sdk, *second_objects)
+    cluster, *_ = as_user_objects(user_sdk, cluster_via_admin)
+    second_cluster_via_admin, *_ = second_objects
     cluster_via_admin.host_add(host_via_admin)
 
     is_allowed(cluster, BR.ViewHostComponents)
-    is_denied(second_cluster, BR.ViewHostComponents)
-    is_denied(cluster, BR.EditHostComponents, (host, component))
+    is_denied_to_user(second_cluster_via_admin, BR.ViewHostComponents)
+    is_denied_to_user(cluster, BR.EditHostComponents)
     delete_policy(user_policy)
-    is_denied(cluster, BR.ViewHostComponents)
+    is_denied_to_user(cluster, BR.ViewHostComponents)
 
 
 @use_role(BR.EditHostComponents)
-def test_edit_hostcomponents(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects):
+def test_edit_hostcomponents(
+    user_policy: Policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects
+):
     """Test that Edit host-components role is ok"""
-    cluster, _, component, _, host = as_user_objects(user_sdk, *prepare_objects)
-    cluster_via_admin, *_, host_via_admin = prepare_objects
-    second_cluster, _, second_component, _, second_host = as_user_objects(user_sdk, *second_objects)
+
+    cluster_via_admin, _, component_via_admin, _, host_via_admin = prepare_objects
     second_cluster_via_admin, *_, second_host_via_admin = second_objects
+    cluster, *_ = as_user_objects(user_sdk, cluster_via_admin)
 
     cluster_via_admin.host_add(host_via_admin)
     second_cluster_via_admin.host_add(second_host_via_admin)
 
     is_allowed(cluster, BR.ViewHostComponents)
-    is_allowed(cluster, BR.EditHostComponents, (host, component))
-    is_denied(second_cluster, BR.ViewHostComponents)
-    is_denied(second_cluster, BR.EditHostComponents, (second_host, second_component))
+    is_allowed(cluster, BR.EditHostComponents, (host_via_admin, component_via_admin))
+    is_denied_to_user(second_cluster_via_admin, BR.ViewHostComponents)
+    is_denied_to_user(second_cluster_via_admin, BR.EditHostComponents)
     delete_policy(user_policy)
-    is_denied(cluster, BR.ViewHostComponents)
-    is_denied(cluster, BR.EditHostComponents)
+    is_denied_to_user(cluster, BR.ViewHostComponents)
+    is_denied_to_user(cluster, BR.EditHostComponents)
 
 
 @use_role(BR.AddService)
-def test_add_service(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects):
+def test_add_service(user_policy: Policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects):
     """Test that Add service role is ok"""
-    cluster, *_ = as_user_objects(user_sdk, *prepare_objects)
     cluster_via_admin, *_ = prepare_objects
-    second_cluster, *_ = as_user_objects(user_sdk, *second_objects)
+    cluster, *_ = as_user_objects(user_sdk, cluster_via_admin)
+    second_cluster_via_admin, *_ = second_objects
 
     is_allowed(cluster, BR.AddService)
     added_service = cluster.service(name="new_service")
-    is_denied(cluster, BR.RemoveService, added_service)
-    is_denied(second_cluster, BR.AddService)
+    is_denied_to_user(added_service, BR.RemoveService, added_service)
+    is_denied_to_user(second_cluster_via_admin, BR.AddService)
     cluster_via_admin.service(name="new_service").delete()
     delete_policy(user_policy)
-    is_denied(cluster, BR.AddService)
+    is_denied_to_user(cluster, BR.AddService)
 
 
 @use_role(BR.RemoveService)
-def test_remove_service(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects):
+def test_remove_service(user_policy: Policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects):
     """Test that Remove service role is ok"""
-    cluster, service, *_ = as_user_objects(user_sdk, *prepare_objects)
-    cluster_via_admin, *_ = prepare_objects
-    second_cluster, second_service, *_ = as_user_objects(user_sdk, *second_objects)
-    second_cluster_via_admin, *_ = second_objects
+    cluster_via_admin, service_via_admin, *_ = prepare_objects
+    cluster, *_ = as_user_objects(user_sdk, cluster_via_admin)
+    second_cluster_via_admin, second_service_via_admin, *_ = second_objects
 
-    is_denied(cluster, BR.AddService)
-    is_allowed(cluster, BR.RemoveService, service)
-    is_denied(second_cluster, BR.RemoveService, second_service)
+    is_denied_to_user(cluster_via_admin, BR.AddService)
+    is_allowed(cluster, BR.RemoveService, service_via_admin)
+    is_denied_to_user(service_via_admin, BR.RemoveService)
 
-    added_second_service = second_cluster_via_admin.service_add(name="new_service")
-    is_denied(cluster, BR.RemoveService, added_second_service)
+    second_cluster_via_admin.service_add(name="new_service")
+    is_denied_to_user(second_service_via_admin, BR.RemoveService)
 
     delete_policy(user_policy)
-    added_service = cluster_via_admin.service_add(name="test_service")
-    is_denied(cluster, BR.RemoveService, added_service)
+    cluster_via_admin.service_add(name="test_service")
+    is_denied_to_user(service_via_admin, BR.RemoveService)
 
 
 @use_role(BR.RemoveHosts)
-def test_remove_hosts(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects, sdk_client_fs, user):
+def test_remove_hosts(
+    user_policy: Policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects, sdk_client_fs, user
+):
     """Test that Remove hosts role is ok"""
-    *_, host = as_user_objects(user_sdk, *prepare_objects)
-    *_, second_host = as_user_objects(user_sdk, *second_objects)
+    *_, admin_host = prepare_objects
+    *_, admin_host_second = second_objects
+    *_, host = as_user_objects(user_sdk, admin_host)
 
     is_allowed(host, BR.RemoveHosts)
-    is_denied(second_host, BR.RemoveHosts)
+    is_denied_to_user(admin_host_second, BR.RemoveHosts)
     with allure.step("Assert that policy is valid after object removing"):
         user_policy.reread()
 
-    new_policy = create_policy(sdk_client_fs, BR.RemoveHosts, objects=[second_host], users=[user], groups=[])
+    new_policy = create_policy(sdk_client_fs, BR.RemoveHosts, objects=[admin_host_second], users=[user], groups=[])
     delete_policy(new_policy)
-    is_denied(second_host, BR.RemoveHosts)
+    is_denied_to_user(admin_host_second, BR.RemoveHosts)
 
 
 @use_role(BR.MapHosts)
-def test_map_hosts(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects):
+def test_map_hosts(user_policy: Policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects):
     """Test that Map hosts role is ok"""
-    cluster, *_, host = as_user_objects(user_sdk, *prepare_objects)
-    *_, provider_via_admin, _ = prepare_objects
-    second_cluster, *_, second_host = as_user_objects(user_sdk, *second_objects)
+    admin_cluster, *_, admin_host = prepare_objects
+    cluster, *_ = as_user_objects(user_sdk, admin_cluster)
+    admin_cluster_second, *_, admin_provider, _ = second_objects
 
-    new_host = provider_via_admin.host_create(fqdn="new_host")
-    is_allowed(cluster, BR.MapHosts, host)
-    is_denied(cluster, BR.UnmapHosts, host)
-    is_denied(second_cluster, BR.MapHosts, second_host)
+    admin_provider.host_create(fqdn="new_host")
+    is_allowed(cluster, BR.MapHosts, admin_host)
+    admin_host.reread()
+    is_denied_to_user(admin_host, BR.UnmapHosts)
+    is_denied_to_user(admin_cluster_second, BR.MapHosts)
 
     delete_policy(user_policy)
 
-    is_denied(cluster, BR.MapHosts, new_host)
+    is_denied_to_user(cluster, BR.MapHosts)
 
 
 @use_role(BR.UnmapHosts)
-def test_unmap_hosts(user_policy: Policy, user_sdk: ADCMClient, prepare_objects, second_objects):
+def test_unmap_hosts(user_policy: Policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects):
     """Test that Unmap hosts role is ok"""
-    cluster, *_, host = as_user_objects(user_sdk, *prepare_objects)
-    cluster_via_admin, *_, provider_via_admin, _ = prepare_objects
-    second_cluster, *_, second_host = as_user_objects(user_sdk, *second_objects)
-    second_cluster_via_admin, *_ = second_objects
+    cluster_via_admin, *_, provider_via_admin, host_via_admin = prepare_objects
+    cluster, *_ = as_user_objects(user_sdk, cluster_via_admin)
+    second_cluster_via_admin, *_, second_host_via_admin = second_objects
 
-    is_denied(cluster, BR.MapHosts, host)
-    is_denied(host, BR.RemoveHosts)
-    cluster_via_admin.host_add(host)
+    is_denied_to_user(cluster, BR.MapHosts)
+    is_denied_to_user(host_via_admin, BR.RemoveHosts)
+    cluster_via_admin.host_add(host_via_admin)
+    host, *_ = as_user_objects(user_sdk, host_via_admin)
     is_allowed(cluster, BR.UnmapHosts, host)
 
-    second_cluster_via_admin.host_add(second_host)
-    is_denied(second_cluster, BR.UnmapHosts, second_host)
+    second_cluster_via_admin.host_add(second_host_via_admin)
+    second_host_via_admin.reread()
+    is_denied_to_user(second_host_via_admin, BR.UnmapHosts)
 
     delete_policy(user_policy)
 
     new_host = provider_via_admin.host_create(fqdn="new_host")
     cluster_via_admin.host_add(new_host)
-    is_denied(cluster, BR.UnmapHosts, new_host)
+    new_host.reread()
+    is_denied_to_user(new_host, BR.UnmapHosts)
 
 
 @use_role(BR.UpgradeClusterBundle)
 @pytest.mark.usefixtures("second_objects")
-def test_upgrade_application_bundle(user_policy, user_sdk: ADCMClient, prepare_objects, sdk_client_fs, user):
+def test_upgrade_application_bundle(
+    user_policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, sdk_client_fs, user
+):
     """Test that Upgrade application bundle role is ok"""
-    cluster, *_, provider, _ = as_user_objects(user_sdk, *prepare_objects)
-    cluster_via_admin, *_ = prepare_objects
-    second_cluster = user_sdk.cluster(id=cluster_via_admin.bundle().cluster_create(name="Second cluster").id)
+    cluster_via_admin, *_, provider_via_admin, _ = prepare_objects
+    cluster, *_ = as_user_objects(user_sdk, cluster_via_admin)
+    second_cluster_via_admin = cluster_via_admin.bundle().cluster_create(name="Second cluster")
 
     is_allowed(cluster, BR.UpgradeClusterBundle)
-    is_denied(provider, BR.UpgradeClusterBundle)
-    is_denied(second_cluster, BR.UpgradeClusterBundle)
+    is_denied_to_user(provider_via_admin, BR.UpgradeProviderBundle)
+    is_denied_to_user(second_cluster_via_admin, BR.UpgradeClusterBundle)
 
     new_policy = create_policy(
-        sdk_client_fs, BR.UpgradeClusterBundle, objects=[second_cluster], users=[user], groups=[]
+        sdk_client_fs, BR.UpgradeClusterBundle, objects=[second_cluster_via_admin], users=[user], groups=[]
     )
     delete_policy(new_policy)
-    is_denied(second_cluster, BR.UpgradeClusterBundle)
+    is_denied_to_user(second_cluster_via_admin, BR.UpgradeClusterBundle)
 
 
 @use_role(BR.UpgradeProviderBundle)
 @pytest.mark.usefixtures("second_objects")
-def test_upgrade_infrastructure_bundle(user_policy, user_sdk: ADCMClient, prepare_objects, sdk_client_fs, user):
+def test_upgrade_infrastructure_bundle(
+    user_policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, sdk_client_fs, user
+):
     """Test that Upgrade infrastructure bundle role is ok"""
-    cluster, *_, provider, _ = as_user_objects(user_sdk, *prepare_objects)
-    *_, provider_via_admin, _ = prepare_objects
-    second_provider = user_sdk.provider(id=provider_via_admin.bundle().provider_create(name="Second provider").id)
+    cluster_via_admin, *_, provider_via_admin, _ = prepare_objects
+    provider, *_ = as_user_objects(user_sdk, provider_via_admin)
+    second_provider_via_admin = provider_via_admin.bundle().provider_create(name="Second provider")
 
     is_allowed(provider, BR.UpgradeProviderBundle)
-    is_denied(cluster, BR.UpgradeProviderBundle)
-    is_denied(second_provider, BR.UpgradeProviderBundle)
+    is_denied_to_user(cluster_via_admin, BR.UpgradeClusterBundle)
+    is_denied_to_user(second_provider_via_admin, BR.UpgradeProviderBundle)
 
     new_policy = create_policy(
-        sdk_client_fs, BR.UpgradeProviderBundle, objects=[second_provider], users=[user], groups=[]
+        sdk_client_fs, BR.UpgradeProviderBundle, objects=[second_provider_via_admin], users=[user], groups=[]
     )
     delete_policy(new_policy)
-    is_denied(second_provider, BR.UpgradeProviderBundle)
+    is_denied_to_user(second_provider_via_admin, BR.UpgradeProviderBundle)
 
 
 @use_role(BR.CreateHostProvider)
-def test_create_provider(user_policy, user_sdk: ADCMClient, prepare_objects, second_objects):
+def test_create_provider(user_policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects):
     """Test that Create provider role is ok"""
-    cluster, *_, provider, _ = as_user_objects(user_sdk, *prepare_objects)
-    *_, second_provider, _ = as_user_objects(user_sdk, *second_objects)
+    cluster, *_, provider, _ = prepare_objects
+    *_, second_provider, _ = second_objects
+    provider_bundle_first, provider_bundle_second = as_user_objects(
+        user_sdk, provider.bundle(), second_provider.bundle()
+    )
 
-    is_allowed(provider.bundle(), BR.CreateHostProvider)
-    is_allowed(second_provider.bundle(), BR.CreateHostProvider)
-    is_denied(provider, BR.CreateHost)
-    is_denied(user_sdk.provider_list()[-1], BR.CreateHost)
-    is_denied(cluster.bundle(), BR.CreateCluster)
+    is_allowed(provider_bundle_first, BR.CreateHostProvider)
+    is_allowed(provider_bundle_second, BR.CreateHostProvider)
+    is_denied_to_user(provider, BR.CreateHost)
+    is_denied_to_user(provider, BR.CreateHost)
+    is_denied_to_user(cluster.bundle(), BR.CreateCluster)
 
     delete_policy(user_policy)
-    is_denied(provider.bundle(), BR.CreateHostProvider)
+    is_denied_to_user(provider.bundle(), BR.CreateHostProvider)
 
 
 @use_role(BR.CreateHost)
-def test_create_host(user_policy, user_sdk: ADCMClient, prepare_objects, second_objects):
+def test_create_host(user_policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects):
     """Test that Create host role is ok"""
-    cluster, *_, provider, host = as_user_objects(user_sdk, *prepare_objects)
-    *_, second_provider, second_host = as_user_objects(user_sdk, *second_objects)
+    admin_cluster, *_, admin_provider, admin_host = prepare_objects
+    provider, *_ = as_user_objects(user_sdk, admin_provider)
+    *_, admin_second_provider, admin_second_host = second_objects
 
     is_allowed(provider, BR.CreateHost)
-    is_denied(host, BR.RemoveHosts)
-    is_denied(cluster, BR.MapHosts, host)
-    is_denied(second_provider, BR.CreateHost)
-    is_denied(second_host, BR.RemoveHosts)
+    is_denied_to_user(admin_host, BR.RemoveHosts)
+    is_denied_to_user(admin_cluster, BR.MapHosts, admin_host)
+    is_denied_to_user(admin_second_provider, BR.CreateHost)
+    is_denied_to_user(admin_second_host, BR.RemoveHosts)
 
     delete_policy(user_policy)
-    is_denied(provider, BR.CreateHost)
+    is_denied_to_user(admin_provider, BR.CreateHost)
 
 
 @use_role(BR.RemoveHostProvider)
-def test_remove_provider(user_policy, user_sdk: ADCMClient, prepare_objects, second_objects, sdk_client_fs, user):
+def test_remove_provider(
+    user_policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects, sdk_client_fs, user
+):
     """Test that Remove provider role is ok"""
-    *_, provider, host = as_user_objects(user_sdk, *prepare_objects)
-    *_, host_via_admin = prepare_objects
-    *_, second_provider, _ = as_user_objects(user_sdk, *second_objects)
-    *_, second_host_via_admin = second_objects
+    *_, provider_via_admin, host_via_admin = prepare_objects
+    provider, *_ = as_user_objects(user_sdk, provider_via_admin)
 
-    is_denied(host, BR.RemoveHosts)
+    *_, second_provider_via_admin, second_host_via_admin = second_objects
+
+    is_denied_to_user(host_via_admin, BR.RemoveHosts)
     host_via_admin.delete()
     second_host_via_admin.delete()
     is_allowed(provider, BR.RemoveHostProvider)
-    is_denied(second_provider, BR.RemoveHostProvider)
+    is_denied_to_user(second_provider_via_admin, BR.RemoveHostProvider)
 
-    new_policy = create_policy(sdk_client_fs, BR.RemoveHostProvider, objects=[second_provider], users=[user], groups=[])
+    new_policy = create_policy(
+        sdk_client_fs, BR.RemoveHostProvider, objects=[second_provider_via_admin], users=[user], groups=[]
+    )
+    user_sdk.reread()
     delete_policy(new_policy)
-    is_denied(second_provider, BR.RemoveHostProvider)
+    is_denied_to_user(second_provider_via_admin, BR.RemoveHostProvider)
 
 
 @use_role(BR.CreateCluster)
-def test_create_cluster(user_policy, user_sdk: ADCMClient, prepare_objects, second_objects):
+def test_create_cluster(user_policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects):
     """Test that Create cluster role is ok"""
-    cluster, *_, provider, _ = as_user_objects(user_sdk, *prepare_objects)
+    cluster, *_, provider, _ = prepare_objects
+    cluster_bundle, *_ = as_user_objects(user_sdk, cluster.bundle())
 
-    is_allowed(cluster.bundle(), BR.CreateCluster)
-    is_denied(provider.bundle(), BR.CreateHostProvider)
-    is_denied(cluster, BR.RemoveCluster)
+    is_allowed(cluster_bundle, BR.CreateCluster)
+    is_denied_to_user(provider.bundle(), BR.CreateHostProvider)
+    is_denied_to_user(cluster, BR.RemoveCluster)
 
     delete_policy(user_policy)
-    is_denied(cluster.bundle(), BR.CreateCluster)
+    is_denied_to_user(cluster_bundle, BR.CreateCluster)
 
 
 @use_role(BR.RemoveCluster)
-def test_remove_cluster(user_policy, user_sdk: ADCMClient, prepare_objects, second_objects, sdk_client_fs, user):
+def test_remove_cluster(
+    user_policy, user_sdk: ADCMClient, is_denied_to_user, prepare_objects, second_objects, sdk_client_fs, user
+):
     """Test that Remove cluster role is ok"""
-    cluster, *_ = as_user_objects(user_sdk, *prepare_objects)
-    second_cluster, *_ = as_user_objects(user_sdk, *second_objects)
+    admin_cluster, *_ = prepare_objects
+    admin_cluster_second, *_ = second_objects
+    cluster, *_ = as_user_objects(user_sdk, admin_cluster)
 
-    is_denied(cluster.bundle(), BR.CreateCluster)
+    is_denied_to_user(admin_cluster.bundle(), BR.CreateCluster)
     is_allowed(cluster, BR.RemoveCluster)
-    is_denied(second_cluster, BR.RemoveCluster)
+    is_denied_to_user(admin_cluster_second, BR.RemoveCluster)
 
-    new_policy = create_policy(sdk_client_fs, BR.RemoveCluster, objects=[second_cluster], users=[user], groups=[])
+    new_policy = create_policy(sdk_client_fs, BR.RemoveCluster, objects=[admin_cluster_second], users=[user], groups=[])
     delete_policy(new_policy)
-    is_denied(second_cluster, BR.RemoveCluster)
+    is_denied_to_user(admin_cluster_second, BR.RemoveCluster)
 
 
 @use_role(BR.UploadBundle)
-def test_upload_bundle(user_policy, user_sdk: ADCMClient, sdk_client_fs):
+def test_upload_bundle(clients, user_policy, is_denied_to_user):
     """Test that Upload bundle role is ok"""
 
-    is_allowed(user_sdk, BR.UploadBundle)
-    is_denied(user_sdk.bundle(), BR.RemoveBundle)
+    is_allowed(clients.user, BR.UploadBundle)
+    is_denied_to_user(clients.admin.bundle(), BR.RemoveBundle)
 
     delete_policy(user_policy)
-    sdk_client_fs.bundle_list()[-1].delete()
-    is_denied(user_sdk, BR.UploadBundle)
+    clients.admin.bundle_list()[-1].delete()
+    is_denied(clients.user, BR.UploadBundle)
 
 
 @use_role(BR.RemoveBundle)
-def test_remove_bundle(user_policy, user_sdk: ADCMClient, sdk_client_fs):
+def test_remove_bundle(user_policy, user_sdk: ADCMClient, sdk_client_fs, is_denied_to_user):
     """Test that Remove bundle role is ok"""
 
     is_denied(user_sdk, BR.UploadBundle)
@@ -421,82 +456,78 @@ def test_remove_bundle(user_policy, user_sdk: ADCMClient, sdk_client_fs):
 
     delete_policy(user_policy)
     BR.UploadBundle.value.method_call(sdk_client_fs)
-    is_denied(user_sdk.bundle_list()[-1], BR.RemoveBundle)
+    is_denied_to_user(user_sdk.bundle_list()[-1], BR.RemoveBundle)
 
 
 def test_service_administrator(user, user_sdk: ADCMClient, sdk_client_fs, prepare_objects, second_objects):
     """Test that service administrator role grants access to single service and its components"""
-    cluster, service, component, *provider_objects = as_user_objects(user_sdk, *prepare_objects)
-    cluster_via_admin, *_ = prepare_objects
-    second_service_on_first_cluster = user_sdk.service(id=cluster_via_admin.service_add(name="new_service").id)
-    second_cluster, second_service, second_component, *second_provider_objects = as_user_objects(
-        user_sdk, *second_objects
-    )
+    cluster, service, component, *provider_objects = prepare_objects
+    second_service_on_first_cluster = cluster.service_add(name="new_service")
 
     role = sdk_client_fs.role(name=RbacRoles.ServiceAdministrator.value)
     sdk_client_fs.policy_create(
         name=f"Policy with role {role.name}", role=role, objects=[service], user=[user], group=[]
     )
+    user_sdk.reread()
 
-    is_allowed_to_view(service, component)
-    is_allowed_to_edit(service, component)
-    is_denied_to_view(
-        cluster,
-        second_cluster,
-        second_service,
-        second_component,
-        second_service_on_first_cluster,
-        *provider_objects,
-        *second_provider_objects,
-    )
+    allowed_user_objects = as_user_objects(user_sdk, service, component)
+    is_allowed_to_view(*allowed_user_objects)
+    is_allowed_to_edit(*allowed_user_objects)
+    is_denied_to_view(cluster, second_service_on_first_cluster, *second_objects, *provider_objects, client=user_sdk)
 
 
 def test_cluster_administrator(user, user_sdk: ADCMClient, sdk_client_fs, prepare_objects, second_objects):
     """Test that cluster administrator role grants access to single cluster and related services and components"""
-    cluster, service, component, *provider_objects = as_user_objects(user_sdk, *prepare_objects)
-    second_cluster, second_service, second_component, *second_provider_objects = as_user_objects(
-        user_sdk, *second_objects
-    )
+    cluster, service, component, *provider_objects = prepare_objects
 
     role = sdk_client_fs.role(name=RbacRoles.ClusterAdministrator.value)
     sdk_client_fs.policy_create(
         name=f"Policy with role {role.name}", role=role, objects=[cluster], user=[user], group=[]
     )
+    user_sdk.reread()
 
-    is_allowed_to_view(cluster, service, component)
-    is_allowed_to_edit(cluster, service, component)
-    is_denied_to_view(second_cluster, second_service, second_component, *provider_objects, *second_provider_objects)
+    allowed_user_objects = as_user_objects(user_sdk, cluster, service, component)
+    is_allowed_to_view(*allowed_user_objects)
+    is_allowed_to_edit(*allowed_user_objects)
+    is_denied_to_view(*second_objects, *provider_objects, client=user_sdk)
 
 
 def test_provider_administrator(user, user_sdk: ADCMClient, sdk_client_fs, prepare_objects, second_objects):
     """Test that provider administrator role grants access to single provider and its hosts"""
-    cluster, service, component, hostprovider, host = as_user_objects(user_sdk, *prepare_objects)
-    second_cluster, second_service, second_component, *second_provider_objects = as_user_objects(
-        user_sdk, *second_objects
-    )
+    cluster, service, component, hostprovider, host = prepare_objects
+    second_cluster, second_service, second_component, *second_provider_objects = second_objects
 
     role = sdk_client_fs.role(name=RbacRoles.ProviderAdministrator.value)
     sdk_client_fs.policy_create(
         name=f"Policy with role {role.name}", role=role, objects=[hostprovider], user=[user], group=[]
     )
+    user_sdk.reread()
 
-    is_allowed_to_view(hostprovider, host)
-    is_allowed_to_edit(hostprovider, host)
+    user_hostprovider, user_host = as_user_objects(user_sdk, hostprovider, host)
+    is_allowed_to_view(user_hostprovider, user_host)
+    is_allowed_to_edit(user_hostprovider, user_host)
     is_denied_to_view(
-        cluster, service, component, second_cluster, second_service, second_component, *second_provider_objects
+        cluster,
+        service,
+        component,
+        second_cluster,
+        second_service,
+        second_component,
+        *second_provider_objects,
+        client=user_sdk,
     )
 
 
-def test_any_object_roles(clients, user, prepare_objects):
+def test_any_object_roles(clients, user, is_denied_to_user, prepare_objects):
     """Test that ViewAnyObject... default roles works as expected with ADCM User"""
-    cluster, *_ = user_objects = as_user_objects(clients.user, *prepare_objects)
+    admin_cluster, *_ = prepare_objects
 
     @allure.step("Check user has no access to any of objects")
     def check_has_no_rights():
-        is_denied(cluster, BR.ViewAnyObjectImport)
-        is_denied(cluster, BR.ViewAnyObjectHostComponents)
-        is_denied_to_view(*user_objects)
-        is_denied_to_edit(*user_objects)
+        is_denied_to_user(admin_cluster, BR.ViewAnyObjectImport, client=clients.user)
+        is_denied_to_user(admin_cluster, BR.ViewAnyObjectHostComponents, client=clients.user)
+        is_denied_to_view(*prepare_objects, client=clients.user)
+        is_denied_to_edit(*prepare_objects, client=clients.user)
 
     check_has_no_rights()
 
@@ -507,10 +538,12 @@ def check_has_no_rights():
         user=[user],
     )
 
+    cluster, *_ = as_user_objects(clients.user, admin_cluster)
+
     is_allowed(cluster, BR.ViewAnyObjectImport)
     is_allowed(cluster, BR.ViewAnyObjectHostComponents)
-    is_allowed_to_view(*user_objects)
-    is_denied_to_edit(*user_objects)
+    is_allowed_to_view(*as_user_objects(clients.user, *prepare_objects))
+    is_denied_to_edit(*prepare_objects, client=clients.user)
 
     delete_policy(policy)
 
diff --git a/tests/functional/rbac/test_complex_cases.py b/tests/functional/rbac/test_complex_cases.py
new file mode 100644
index 0000000000..12526c23af
--- /dev/null
+++ b/tests/functional/rbac/test_complex_cases.py
@@ -0,0 +1,198 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Test complex RBAC cases"""
+
+# pylint: disable=no-self-use, too-many-arguments
+
+from typing import Iterable
+
+import allure
+import pytest
+from adcm_client.objects import ADCMClient
+
+from tests.functional.rbac.conftest import create_policy, BusinessRoles as BR, as_user_objects, is_allowed, is_denied
+from tests.functional.tools import AnyADCMObject
+
+
+class TestTwoUsers:
+    """Test permissions when two non-superusers are in play"""
+
+    _SECOND_USER_CREDS = ("second_user", "password")
+
+    @pytest.fixture()
+    def first_user(self, user):
+        """Wrap first non-superuser"""
+        return user
+
+    @pytest.fixture()
+    def second_user(self, sdk_client_fs):
+        """Create second non-superuser"""
+        return sdk_client_fs.user_create(*self._SECOND_USER_CREDS)
+
+    @pytest.fixture()
+    def second_user_sdk(self, adcm_fs, second_user):  # pylint: disable=unused-argument
+        """ADCM Client for second non-superuser"""
+        username, password = self._SECOND_USER_CREDS
+        return ADCMClient(url=adcm_fs.url, user=username, password=password)
+
+    # pylint: disable=too-many-locals
+
+    def test_grant_role_to_users_withdraw_from_one(
+        self, sdk_client_fs, user_sdk, second_user_sdk, first_user, second_user, prepare_objects, second_objects
+    ):
+        """
+        Assign role to two users
+        Remove role from one of them
+        Check permissions are correct
+        """
+        cluster, service, component, provider, host = prepare_objects
+        objects_wo_service = [cluster, component, provider, host, *second_objects]
+        admin_client, first_client, second_client = sdk_client_fs, user_sdk, second_user_sdk
+
+        with allure.step('Create policy assigned to both users'):
+            policy = create_policy(admin_client, BR.EditServiceConfigurations, [service], [first_user, second_user], [])
+
+        with allure.step('Check that config of only one service can be edited by both users'):
+            self._edit_is_allowed_to(first_client, [service])
+            self._edit_is_allowed_to(second_client, [service])
+            self._edit_is_denied_to(first_client, objects_wo_service)
+            self._edit_is_denied_to(second_client, objects_wo_service)
+
+        with allure.step('Remove one of users from policy'):
+            policy.update(user=[{'id': second_user.id}])
+
+        with allure.step('Check that only one of users can edit config of one service'):
+            self._edit_is_allowed_to(second_client, [service])
+            self._edit_is_denied_to(second_client, objects_wo_service)
+            self._edit_is_denied_to(first_client, [*prepare_objects, *second_objects])
+
+    def test_change_users_in_groups(
+        self, sdk_client_fs, user_sdk, second_user_sdk, first_user, second_user, prepare_objects, second_objects
+    ):
+        """
+        Add two users to groups
+        Create policies assigned to groups
+        Change users in groups
+        """
+        cluster, service, component, provider, host = prepare_objects
+        objects_wo_service = [cluster, component, provider, host, *second_objects]
+        objects_wo_cluster = [service, component, provider, host, *second_objects]
+        admin_client, first_client, second_client = sdk_client_fs, user_sdk, second_user_sdk
+
+        with allure.step('Create two groups with one user in each'):
+            first_group = admin_client.group_create('First Group', user=[{'id': first_user.id}])
+            second_group = admin_client.group_create('Second Group', user=[{'id': second_user.id}])
+
+        with allure.step('Create two policies and assign separate group to each'):
+            create_policy(admin_client, BR.EditServiceConfigurations, [service], [], [first_group])
+            create_policy(admin_client, BR.EditClusterConfigurations, [cluster], [], [second_group])
+
+        with allure.step('Check that one user have access only to service config and another only to cluster config'):
+            self._edit_is_allowed_to(first_client, [service])
+            self._edit_is_allowed_to(second_client, [cluster])
+            self._edit_is_denied_to(first_client, objects_wo_service)
+            self._edit_is_denied_to(second_client, objects_wo_cluster)
+
+        with allure.step('Swap users in groups'):
+            first_group.update(user=[{'id': second_user.id}])
+            second_group.update(user=[{'id': first_user.id}])
+
+        with allure.step('Check that permissions were swapped'):
+            self._edit_is_allowed_to(first_client, [cluster])
+            self._edit_is_allowed_to(second_client, [service])
+            self._edit_is_denied_to(first_client, objects_wo_cluster)
+            self._edit_is_denied_to(second_client, objects_wo_service)
+
+    def test_grant_different_permissions_to_two_users(
+        self, sdk_client_fs, user_sdk, second_user_sdk, first_user, second_user, prepare_objects, second_objects
+    ):
+        """
+        Give one user one permission
+        Give another user second permission
+        Check they don't mix
+        """
+        cluster, service, component, provider, host = prepare_objects
+        objects_wo_service = [cluster, component, provider, host, *second_objects]
+        objects_wo_cluster = [service, component, provider, host, *second_objects]
+        admin_client, first_client, second_client = sdk_client_fs, user_sdk, second_user_sdk
+
+        with allure.step('Create two policies and assign separate group to each'):
+            first_policy = create_policy(admin_client, BR.EditServiceConfigurations, [service], [first_user], [])
+            second_policy = create_policy(admin_client, BR.EditClusterConfigurations, [cluster], [second_user], [])
+
+        with allure.step(
+            'Check that one user have access only to cluster config change, another user to service config change'
+        ):
+            self._edit_is_allowed_to(first_client, [service])
+            self._edit_is_allowed_to(second_client, [cluster])
+            self._edit_is_denied_to(first_client, objects_wo_service)
+            self._edit_is_denied_to(second_client, objects_wo_cluster)
+
+        with allure.step('Change users in policies'):
+            first_policy.update(user=[{'id': second_user.id}])
+            second_policy.update(user=[{'id': first_user.id}])
+
+        with allure.step('Check that permissions were swapped'):
+            self._edit_is_allowed_to(first_client, [cluster])
+            self._edit_is_allowed_to(second_client, [service])
+            self._edit_is_denied_to(first_client, objects_wo_cluster)
+            self._edit_is_denied_to(second_client, objects_wo_service)
+
+    def test_reassign_policies_between_two_users(
+        self, sdk_client_fs, user_sdk, second_user_sdk, first_user, second_user, prepare_objects, second_objects
+    ):
+        """
+        Grant policy to one user
+        Grant it to both
+        Grant it to another user
+        """
+        cluster, service, component, provider, host = prepare_objects
+        objects_wo_service = [cluster, component, provider, host, *second_objects]
+        admin_client, first_client, second_client = sdk_client_fs, user_sdk, second_user_sdk
+
+        with allure.step('Create policy assigned to one user'):
+            policy = create_policy(admin_client, BR.EditServiceConfigurations, [service], [first_user], [])
+
+        with allure.step('Check that user have access only to service config change'):
+            self._edit_is_allowed_to(first_client, [service])
+            self._edit_is_denied_to(first_client, objects_wo_service)
+            self._edit_is_denied_to(second_client, [*prepare_objects, *second_objects])
+
+        with allure.step('Grant access to both users to edit service config'):
+            policy.update(user=[{'id': first_user.id}, {'id': second_user.id}])
+
+        with allure.step('Check that both users have access only to service config change'):
+            self._edit_is_allowed_to(first_client, [service])
+            self._edit_is_allowed_to(second_client, [service])
+            self._edit_is_denied_to(first_client, objects_wo_service)
+            self._edit_is_denied_to(second_client, objects_wo_service)
+
+        with allure.step('Remove first user from policy'):
+            policy.update(user=[{'id': second_user.id}])
+
+        with allure.step('Check that another user now have access only to service config edit'):
+            self._edit_is_allowed_to(second_client, [service])
+            self._edit_is_denied_to(second_client, objects_wo_service)
+            self._edit_is_denied_to(first_client, [*prepare_objects, *second_objects])
+
+    # pylint: enable=too-many-locals
+
+    def _edit_is_allowed_to(self, user_client: ADCMClient, objects: Iterable[AnyADCMObject]):
+        user_client.reread()
+        for obj in as_user_objects(user_client, *objects):
+            is_allowed(obj, BR.edit_config_of(obj))
+
+    def _edit_is_denied_to(self, user_client: ADCMClient, objects: Iterable[AnyADCMObject]):
+        user_client.reread()
+        for obj in objects:
+            is_denied(obj, BR.edit_config_of(obj), client=user_client)
diff --git a/tests/functional/rbac/test_is_superuser.py b/tests/functional/rbac/test_is_superuser.py
index 671b79c8dd..72e597d9b0 100644
--- a/tests/functional/rbac/test_is_superuser.py
+++ b/tests/functional/rbac/test_is_superuser.py
@@ -13,6 +13,7 @@
 """Test user that has superuser rights"""
 
 # pylint: disable=redefined-outer-name
+from functools import partial
 
 import allure
 import pytest
@@ -27,6 +28,9 @@
 SUPERUSER_CREDENTIALS = {'username': 'supausa', 'password': 'youcantcrackme'}
 
 
+_is_allowed_to_superuser = partial(is_allowed, raise_on_superuser=False)
+
+
 @pytest.fixture()
 def superuser(sdk_client_fs: ADCMClient) -> User:
     """Creates user with superuser rights"""
@@ -59,28 +63,28 @@ def check_access_to_cluster_objects(objects, second_objects):
 
     with allure.step('Check access to basic config manipulations'):
         for obj in cluster, service, component:
-            is_allowed(obj, BusinessRoles.view_config_of(obj))
-            is_allowed(obj, BusinessRoles.edit_config_of(obj))
+            _is_allowed_to_superuser(obj, BusinessRoles.view_config_of(obj))
+            _is_allowed_to_superuser(obj, BusinessRoles.edit_config_of(obj))
 
     with allure.step('Check access to import manipulations'):
         for obj in cluster, service:
-            is_allowed(obj, BusinessRoles.ViewImports)
-        is_allowed(cluster, BusinessRoles.ManageImports, second_cluster)
-        is_allowed(service, BusinessRoles.ManageImports, second_service)
+            _is_allowed_to_superuser(obj, BusinessRoles.ViewImports)
+        _is_allowed_to_superuser(cluster, BusinessRoles.ManageImports, second_cluster)
+        _is_allowed_to_superuser(service, BusinessRoles.ManageImports, second_service)
 
     with allure.step('Check access to host-related cluster manipulations'):
-        is_allowed(cluster, BusinessRoles.ViewHostComponents)
-        is_allowed(cluster, BusinessRoles.MapHosts, host)
-        is_allowed(cluster, BusinessRoles.UnmapHosts, host)
+        _is_allowed_to_superuser(cluster, BusinessRoles.ViewHostComponents)
+        _is_allowed_to_superuser(cluster, BusinessRoles.MapHosts, host)
+        _is_allowed_to_superuser(cluster, BusinessRoles.UnmapHosts, host)
         cluster.host_add(host)
-        is_allowed(cluster, BusinessRoles.EditHostComponents, (host, component))
+        _is_allowed_to_superuser(cluster, BusinessRoles.EditHostComponents, (host, component))
 
     with allure.step('Check access to manipulations with services'):
-        new_service = is_allowed(cluster, BusinessRoles.AddService)
-        is_allowed(cluster, BusinessRoles.RemoveService, new_service)
+        new_service = _is_allowed_to_superuser(cluster, BusinessRoles.AddService)
+        _is_allowed_to_superuser(cluster, BusinessRoles.RemoveService, new_service)
 
     with allure.step('Check upgrade is available'):
-        is_allowed(cluster, BusinessRoles.UpgradeClusterBundle)
+        _is_allowed_to_superuser(cluster, BusinessRoles.UpgradeClusterBundle)
 
 
 @allure.step('Check that superuser has access to provider-related actions')
@@ -89,17 +93,17 @@ def check_access_to_provider_objects(objects):
     *_, provider, host = objects
 
     with allure.step('Check access to basic config manipulations'):
-        is_allowed(provider, BusinessRoles.view_config_of(provider))
-        is_allowed(provider, BusinessRoles.edit_config_of(provider))
-        is_allowed(host, BusinessRoles.view_config_of(host))
-        is_allowed(host, BusinessRoles.edit_config_of(host))
+        _is_allowed_to_superuser(provider, BusinessRoles.view_config_of(provider))
+        _is_allowed_to_superuser(provider, BusinessRoles.edit_config_of(provider))
+        _is_allowed_to_superuser(host, BusinessRoles.view_config_of(host))
+        _is_allowed_to_superuser(host, BusinessRoles.edit_config_of(host))
 
     with allure.step('Check access to manipulations with host'):
-        new_host = is_allowed(provider, BusinessRoles.CreateHost)
-        is_allowed(new_host, BusinessRoles.RemoveHosts)
+        new_host = _is_allowed_to_superuser(provider, BusinessRoles.CreateHost)
+        _is_allowed_to_superuser(new_host, BusinessRoles.RemoveHosts)
 
     with allure.step('Check upgrade is available'):
-        is_allowed(provider, BusinessRoles.UpgradeProviderBundle)
+        _is_allowed_to_superuser(provider, BusinessRoles.UpgradeProviderBundle)
 
 
 @allure.step('Check that superuser has access to general actions with RBAC and bundles')
@@ -115,33 +119,33 @@ def check_access_to_general_operations(client: ADCMClient, objects):  # pylint:
             BusinessRoles.ViewRoles,
             BusinessRoles.ViewPolicies,
         ):
-            is_allowed(client, view_role)
+            _is_allowed_to_superuser(client, view_role)
 
         for create, edit, remove in (
             (BusinessRoles.CreateUser, BusinessRoles.EditUser, BusinessRoles.RemoveUser),
             (BusinessRoles.CreateGroup, BusinessRoles.EditGroup, BusinessRoles.RemoveGroup),
             (BusinessRoles.CreateCustomRoles, BusinessRoles.EditRoles, BusinessRoles.RemoveRoles),
         ):
-            new_entity = is_allowed(client, create)
-            is_allowed(new_entity, edit)
-            is_allowed(new_entity, remove)
+            new_entity = _is_allowed_to_superuser(client, create)
+            _is_allowed_to_superuser(new_entity, edit)
+            _is_allowed_to_superuser(new_entity, remove)
 
-        new_policy = is_allowed(
+        new_policy = _is_allowed_to_superuser(
             client,
             BusinessRoles.CreatePolicy,
             user=[client.user()],
             role=BusinessRoles.CreateCustomRoles.value.method_call(client),
         )
-        is_allowed(new_policy, BusinessRoles.EditPolicy)
-        is_allowed(new_policy, BusinessRoles.RemovePolicy)
+        _is_allowed_to_superuser(new_policy, BusinessRoles.EditPolicy)
+        _is_allowed_to_superuser(new_policy, BusinessRoles.RemovePolicy)
 
     with allure.step('Check access to manipulations with cluster, provider and bundles'):
-        new_cluster = is_allowed(cluster_bundle, BusinessRoles.CreateCluster)
-        is_allowed(new_cluster, BusinessRoles.RemoveCluster)
-        new_hostprovider = is_allowed(provider_bundle, BusinessRoles.CreateHostProvider)
-        is_allowed(new_hostprovider, BusinessRoles.RemoveHostProvider)
-        new_bundle = is_allowed(client, BusinessRoles.UploadBundle)
-        is_allowed(new_bundle, BusinessRoles.RemoveBundle)
+        new_cluster = _is_allowed_to_superuser(cluster_bundle, BusinessRoles.CreateCluster)
+        _is_allowed_to_superuser(new_cluster, BusinessRoles.RemoveCluster)
+        new_hostprovider = _is_allowed_to_superuser(provider_bundle, BusinessRoles.CreateHostProvider)
+        _is_allowed_to_superuser(new_hostprovider, BusinessRoles.RemoveHostProvider)
+        new_bundle = _is_allowed_to_superuser(client, BusinessRoles.UploadBundle)
+        _is_allowed_to_superuser(new_bundle, BusinessRoles.RemoveBundle)
 
 
 @allure.step('Check that superuser is allowed to run actions')
diff --git a/tests/functional/rbac/test_object_parametrization.py b/tests/functional/rbac/test_object_parametrization.py
index 1c6e663e5b..7be1e8a617 100644
--- a/tests/functional/rbac/test_object_parametrization.py
+++ b/tests/functional/rbac/test_object_parametrization.py
@@ -31,35 +31,37 @@
 )
 
 
-def test_lower_cluster_hierarchy(user_sdk: ADCMClient, user, prepare_objects, sdk_client_fs):
+def test_lower_cluster_hierarchy(user_sdk: ADCMClient, user, is_denied_to_user, prepare_objects, sdk_client_fs):
     """
     Test that cluster role can be applied to lower cluster objects - services and components
     """
-    cluster, service, component, provider, host = as_user_objects(user_sdk, *prepare_objects)
+    cluster, service, component, provider, host = prepare_objects
     policy = create_policy(sdk_client_fs, CLUSTER_VIEW_CONFIG_ROLES, objects=[cluster], users=[user], groups=[])
-    is_allowed(cluster, BusinessRoles.ViewClusterConfigurations)
-    is_allowed(service, BusinessRoles.ViewServiceConfigurations)
-    is_allowed(component, BusinessRoles.ViewComponentConfigurations)
-    is_denied(provider, BusinessRoles.ViewProviderConfigurations)
-    is_denied(host, BusinessRoles.ViewHostConfigurations)
+    user_cluster, user_service, user_component = as_user_objects(user_sdk, cluster, service, component)
+    is_allowed(user_cluster, BusinessRoles.ViewClusterConfigurations)
+    is_allowed(user_service, BusinessRoles.ViewServiceConfigurations)
+    is_allowed(user_component, BusinessRoles.ViewComponentConfigurations)
+    is_denied_to_user(provider, BusinessRoles.ViewProviderConfigurations)
+    is_denied_to_user(host, BusinessRoles.ViewHostConfigurations)
     delete_policy(policy)
 
     policy = create_policy(sdk_client_fs, CLUSTER_VIEW_CONFIG_ROLES, objects=[service], users=[user], groups=[])
-    is_denied(cluster, BusinessRoles.ViewClusterConfigurations)
-    is_allowed(service, BusinessRoles.ViewServiceConfigurations)
-    is_allowed(component, BusinessRoles.ViewComponentConfigurations)
-    is_denied(provider, BusinessRoles.ViewProviderConfigurations)
-    is_denied(host, BusinessRoles.ViewHostConfigurations)
+    is_denied_to_user(cluster, BusinessRoles.ViewClusterConfigurations)
+    is_allowed(user_service, BusinessRoles.ViewServiceConfigurations)
+    is_allowed(user_component, BusinessRoles.ViewComponentConfigurations)
+    is_denied_to_user(provider, BusinessRoles.ViewProviderConfigurations)
+    is_denied_to_user(host, BusinessRoles.ViewHostConfigurations)
     delete_policy(policy)
 
     create_policy(sdk_client_fs, CLUSTER_VIEW_CONFIG_ROLES, objects=[component], users=[user], groups=[])
-    is_denied(cluster, BusinessRoles.ViewClusterConfigurations)
-    is_denied(service, BusinessRoles.ViewServiceConfigurations)
-    is_allowed(component, BusinessRoles.ViewComponentConfigurations)
-    is_denied(provider, BusinessRoles.ViewProviderConfigurations)
-    is_denied(host, BusinessRoles.ViewHostConfigurations)
+    is_denied_to_user(cluster, BusinessRoles.ViewClusterConfigurations)
+    is_denied_to_user(service, BusinessRoles.ViewServiceConfigurations)
+    is_allowed(user_component, BusinessRoles.ViewComponentConfigurations)
+    is_denied_to_user(provider, BusinessRoles.ViewProviderConfigurations)
+    is_denied_to_user(host, BusinessRoles.ViewHostConfigurations)
 
 
+# pylint: disable-next=too-many-locals
 def test_service_in_cluster_hierarchy(user, prepare_objects, sdk_client_fs, second_objects):
     """
     Test that service related role can be parametrized by cluster
@@ -78,38 +80,40 @@ def test_service_in_cluster_hierarchy(user, prepare_objects, sdk_client_fs, seco
 
     username, password = TEST_USER_CREDENTIALS
     user_sdk = ADCMClient(url=sdk_client_fs.url, user=username, password=password)
-    cluster, service, *_ = as_user_objects(user_sdk, *prepare_objects)
-    second_cluster, *_ = as_user_objects(user_sdk, *second_objects)
+    cluster, *_ = as_user_objects(user_sdk, cluster_via_admin)
+    second_cluster_via_admin, *_ = second_objects
 
     for service in cluster.service_list():
         is_allowed(cluster, BusinessRoles.RemoveService, service)
-    for service in second_cluster.service_list():
-        is_denied(second_cluster, BusinessRoles.RemoveService, service)
+    for service in second_cluster_via_admin.service_list():
+        is_denied(service, BusinessRoles.RemoveService, client=user_sdk)
 
 
-def test_provider_hierarchy(user_sdk: ADCMClient, user, prepare_objects, sdk_client_fs):
+def test_provider_hierarchy(user_sdk: ADCMClient, user, is_denied_to_user, prepare_objects, sdk_client_fs):
     """
     Parametrize role with provider related objects
     """
-    cluster, service, component, provider, host = as_user_objects(user_sdk, *prepare_objects)
+    cluster, service, component, provider, host = prepare_objects
 
     policy = create_policy(sdk_client_fs, PROVIDER_VIEW_CONFIG_ROLES, objects=[provider], users=[user], groups=[])
-    is_allowed(provider, BusinessRoles.ViewProviderConfigurations)
-    is_allowed(host, BusinessRoles.ViewHostConfigurations)
-    is_denied(cluster, BusinessRoles.ViewClusterConfigurations)
-    is_denied(service, BusinessRoles.ViewServiceConfigurations)
-    is_denied(component, BusinessRoles.ViewComponentConfigurations)
+
+    user_provider, user_host = as_user_objects(user_sdk, provider, host)
+    is_allowed(user_provider, BusinessRoles.ViewProviderConfigurations)
+    is_allowed(user_host, BusinessRoles.ViewHostConfigurations)
+    is_denied_to_user(cluster, BusinessRoles.ViewClusterConfigurations)
+    is_denied_to_user(service, BusinessRoles.ViewServiceConfigurations)
+    is_denied_to_user(component, BusinessRoles.ViewComponentConfigurations)
     delete_policy(policy)
 
     create_policy(sdk_client_fs, PROVIDER_VIEW_CONFIG_ROLES, objects=[host], users=[user], groups=[])
-    is_denied(provider, BusinessRoles.ViewProviderConfigurations)
-    is_allowed(host, BusinessRoles.ViewHostConfigurations)
-    is_denied(cluster, BusinessRoles.ViewClusterConfigurations)
-    is_denied(service, BusinessRoles.ViewServiceConfigurations)
-    is_denied(component, BusinessRoles.ViewComponentConfigurations)
+    is_denied_to_user(provider, BusinessRoles.ViewProviderConfigurations)
+    is_allowed(user_host, BusinessRoles.ViewHostConfigurations)
+    is_denied_to_user(cluster, BusinessRoles.ViewClusterConfigurations)
+    is_denied_to_user(service, BusinessRoles.ViewServiceConfigurations)
+    is_denied_to_user(component, BusinessRoles.ViewComponentConfigurations)
 
 
-@pytest.mark.full()
+@pytest.mark.extra_rbac()
 @pytest.mark.negative()
 def test_role_with_two_hierarchy_not_allowed(sdk_client_fs):
     """
@@ -145,7 +149,7 @@ def test_role_with_two_hierarchy_not_allowed(sdk_client_fs):
         )
 
 
-@pytest.mark.full()
+@pytest.mark.extra_rbac()
 def test_host_and_cluster_roles(sdk_client_fs):
     """
     Test that cluster and host roles is allowed to use together
diff --git a/tests/functional/rbac/test_permissions_deleting.py b/tests/functional/rbac/test_permissions_deleting.py
index 770b27af49..9ea26ec9ed 100644
--- a/tests/functional/rbac/test_permissions_deleting.py
+++ b/tests/functional/rbac/test_permissions_deleting.py
@@ -29,14 +29,14 @@ def test_remove_user_from_policy(user_sdk: ADCMClient, user, prepare_objects, sd
     Test that user loses access if user removed from policy user list
     """
     cluster_via_admin, *_ = prepare_objects
-    cluster = user_sdk.cluster(id=cluster_via_admin.id)
     policy = create_policy(
-        sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster], users=[user], groups=[]
+        sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster_via_admin], users=[user], groups=[]
     )
+    cluster = user_sdk.cluster(id=cluster_via_admin.id)
     is_allowed(cluster, BusinessRoles.ViewComponentConfigurations)
     with allure.step("Remove user from policy"):
         policy.update(user=[{"id": sdk_client_fs.user(username="admin").id}])
-    is_denied(cluster, BusinessRoles.ViewClusterConfigurations)
+    is_denied(cluster, BusinessRoles.ViewClusterConfigurations, client=user_sdk)
 
 
 def test_remove_group_from_policy(user_sdk: ADCMClient, user, prepare_objects, sdk_client_fs):
@@ -44,16 +44,16 @@ def test_remove_group_from_policy(user_sdk: ADCMClient, user, prepare_objects, s
     Test that user loses access if group with user removed from policy group list
     """
     cluster_via_admin, *_ = prepare_objects
-    cluster = user_sdk.cluster(id=cluster_via_admin.id)
     group = sdk_client_fs.group_create("test_group", user=[{"id": user.id}])
     empty_group = sdk_client_fs.group_create("empty_group")
     policy = create_policy(
-        sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster], users=[], groups=[group]
+        sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster_via_admin], users=[], groups=[group]
     )
+    cluster = user_sdk.cluster(id=cluster_via_admin.id)
     is_allowed(cluster, BusinessRoles.ViewClusterConfigurations)
     with allure.step("Remove group from policy"):
         policy.update(group=[{"id": empty_group.id}])
-    is_denied(cluster, BusinessRoles.ViewClusterConfigurations)
+    is_denied(cluster, BusinessRoles.ViewClusterConfigurations, client=user_sdk)
 
 
 def test_remove_user_from_group(user_sdk: ADCMClient, user, prepare_objects, sdk_client_fs):
@@ -61,13 +61,15 @@ def test_remove_user_from_group(user_sdk: ADCMClient, user, prepare_objects, sdk
     Test that user loses access if user removed from group with policy
     """
     cluster_via_admin, *_ = prepare_objects
-    cluster = user_sdk.cluster(id=cluster_via_admin.id)
     group = sdk_client_fs.group_create("test_group", user=[{"id": user.id}])
-    create_policy(sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster], users=[], groups=[group])
+    create_policy(
+        sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster_via_admin], users=[], groups=[group]
+    )
+    cluster = user_sdk.cluster(id=cluster_via_admin.id)
     is_allowed(cluster, BusinessRoles.ViewClusterConfigurations)
     with allure.step("Remove user from group"):
         group.update(user=[])
-    is_denied(cluster, BusinessRoles.ViewClusterConfigurations)
+    is_denied(cluster, BusinessRoles.ViewClusterConfigurations, client=user_sdk)
 
 
 def test_remove_object_from_policy(user_sdk: ADCMClient, user, prepare_objects, sdk_client_fs):
@@ -75,19 +77,19 @@ def test_remove_object_from_policy(user_sdk: ADCMClient, user, prepare_objects,
     Test that user loses access if object changed from policy
     """
     cluster_via_admin, service_via_admin, *_ = prepare_objects
-    cluster = user_sdk.cluster(id=cluster_via_admin.id)
-    service = user_sdk.service(id=service_via_admin.id)
     policy = create_policy(
         sdk_client_fs,
         [BusinessRoles.ViewClusterConfigurations, BusinessRoles.ViewServiceConfigurations],
-        objects=[cluster],
+        objects=[cluster_via_admin],
         users=[user],
         groups=[],
     )
+    cluster = user_sdk.cluster(id=cluster_via_admin.id)
+    service = user_sdk.service(id=service_via_admin.id)
     is_allowed(cluster, BusinessRoles.ViewClusterConfigurations)
     with allure.step("Change policy object from cluster to service"):
         policy.update(object=[{"id": service_via_admin.id, "type": "service"}])
-    is_denied(cluster, BusinessRoles.ViewClusterConfigurations)
+    is_denied(cluster, BusinessRoles.ViewClusterConfigurations, client=user_sdk)
     is_allowed(service, BusinessRoles.ViewClusterConfigurations)
 
 
@@ -96,10 +98,12 @@ def test_change_child_role(user_sdk: ADCMClient, user, prepare_objects, sdk_clie
     Test that user loses access if change policy role
     """
     cluster_via_admin, *_ = prepare_objects
-    cluster = user_sdk.cluster(id=cluster_via_admin.id)
+
     policy = create_policy(
-        sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster], users=[user], groups=[]
+        sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster_via_admin], users=[user], groups=[]
     )
+
+    cluster = user_sdk.cluster(id=cluster_via_admin.id)
     is_allowed(cluster, BusinessRoles.ViewClusterConfigurations)
 
     with allure.step("Change role from 'View configuration' to 'View imports'"):
@@ -110,7 +114,7 @@ def test_change_child_role(user_sdk: ADCMClient, user, prepare_objects, sdk_clie
         )
         policy.update(role={"id": role.id})
     is_allowed(cluster, BusinessRoles.ViewImports)
-    is_denied(cluster, BusinessRoles.ViewClusterConfigurations)
+    is_denied(cluster, BusinessRoles.ViewClusterConfigurations, client=user_sdk)
 
 
 def test_remove_user_from_policy_but_still_in_group(user_sdk: ADCMClient, user, prepare_objects, sdk_client_fs):
@@ -118,11 +122,15 @@ def test_remove_user_from_policy_but_still_in_group(user_sdk: ADCMClient, user,
     Test that user is still have access if user removed from policy but is in group
     """
     cluster_via_admin, *_ = prepare_objects
-    cluster = user_sdk.cluster(id=cluster_via_admin.id)
     group = sdk_client_fs.group_create("test_group", user=[{"id": user.id}])
     policy = create_policy(
-        sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster], users=[user], groups=[group]
+        sdk_client_fs,
+        BusinessRoles.ViewClusterConfigurations,
+        objects=[cluster_via_admin],
+        users=[user],
+        groups=[group],
     )
+    cluster = user_sdk.cluster(id=cluster_via_admin.id)
     is_allowed(cluster, BusinessRoles.ViewClusterConfigurations)
     with allure.step("Remove user from policy"):
         policy.update(user=[{"id": sdk_client_fs.user(username="admin").id}])
@@ -134,16 +142,16 @@ def test_remove_group_with_user_but_still_in_another_group(user_sdk: ADCMClient,
     Test that user is still have access if removed group with user but user is in another group
     """
     cluster_via_admin, *_ = prepare_objects
-    cluster = user_sdk.cluster(id=cluster_via_admin.id)
     group = sdk_client_fs.group_create("test_group", user=[{"id": user.id}])
     another_group = sdk_client_fs.group_create("another_group", user=[{"id": user.id}])
     policy = create_policy(
         sdk_client_fs,
         BusinessRoles.ViewClusterConfigurations,
-        objects=[cluster],
+        objects=[cluster_via_admin],
         users=[],
         groups=[group, another_group],
     )
+    cluster = user_sdk.cluster(id=cluster_via_admin.id)
     is_allowed(cluster, BusinessRoles.ViewClusterConfigurations)
     with allure.step("Remove user from group"):
         policy.update(group=[{"id": another_group.id}])
@@ -155,11 +163,15 @@ def test_remove_another_object_from_policy(user_sdk: ADCMClient, user, prepare_o
     Test that user is still have access if object removed from policy but exists high-level object
     """
     cluster_via_admin, service_via_admin, *_ = prepare_objects
-    cluster = user_sdk.cluster(id=cluster_via_admin.id)
-    service = user_sdk.service(id=service_via_admin.id)
     policy = create_policy(
-        sdk_client_fs, CLUSTER_VIEW_CONFIG_ROLES, objects=[cluster, service], users=[user], groups=[]
+        sdk_client_fs,
+        CLUSTER_VIEW_CONFIG_ROLES,
+        objects=[cluster_via_admin, service_via_admin],
+        users=[user],
+        groups=[],
     )
+    cluster = user_sdk.cluster(id=cluster_via_admin.id)
+    service = user_sdk.service(id=service_via_admin.id)
     is_allowed(cluster, BusinessRoles.ViewClusterConfigurations)
     is_allowed(service, BusinessRoles.ViewServiceConfigurations)
     with allure.step("Remove object from policy"):
@@ -173,11 +185,13 @@ def test_remove_policy_but_exists_same_policy(user_sdk: ADCMClient, user, prepar
     Test that user is still have access if removed policy, but we still have another policy with the same rights
     """
     cluster_via_admin, *_ = prepare_objects
-    cluster = user_sdk.cluster(id=cluster_via_admin.id)
-    create_policy(sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster], users=[user], groups=[])
+    create_policy(
+        sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster_via_admin], users=[user], groups=[]
+    )
     second_policy = create_policy(
-        sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster], users=[user], groups=[]
+        sdk_client_fs, BusinessRoles.ViewClusterConfigurations, objects=[cluster_via_admin], users=[user], groups=[]
     )
+    cluster = user_sdk.cluster(id=cluster_via_admin.id)
     is_allowed(cluster, BusinessRoles.ViewClusterConfigurations)
     with allure.step("Remove second policy"):
         second_policy.delete()
diff --git a/tests/functional/rbac/test_reassignment.py b/tests/functional/rbac/test_reassignment.py
index ca6d5b9b08..2580a6452e 100644
--- a/tests/functional/rbac/test_reassignment.py
+++ b/tests/functional/rbac/test_reassignment.py
@@ -20,8 +20,8 @@
 import allure
 import pytest
 from adcm_client.objects import ADCMClient, Bundle, User, Policy, Host, Cluster, Service, Provider, Role
+from adcm_pytest_plugin.utils import get_data_dir
 
-from tests.functional.tools import AnyADCMObject, get_object_represent
 from tests.functional.rbac.conftest import (
     BusinessRoles,
     is_allowed,
@@ -30,9 +30,14 @@
     TEST_USER_CREDENTIALS,
     RbacRoles,
 )
+from tests.functional.tools import AnyADCMObject, get_object_represent
 
+pytestmark = [pytest.mark.extra_rbac]
 
-pytestmark = [pytest.mark.full]
+
+def upload_bundle(client: ADCMClient, bundle_name: str) -> Bundle:
+    """Upload bundle by directory name"""
+    return client.upload_from_fs(get_data_dir(__file__, bundle_name))
 
 
 @contextmanager
@@ -47,37 +52,46 @@ def new_client_instance(user: str, password: str, url: str) -> Generator[ADCMCli
 class TestReapplyTriggers:
     """Test reapply cases"""
 
-    def test_add_remove_host_from_cluster(self, clients, prepare_objects, user):
+    def test_add_remove_host_from_cluster(self, clients, is_denied_to_user, prepare_objects, user):
         """Test that policies are applied after host add/remove after the policy was assigned at first"""
-        *_, admin_provider, _ = prepare_objects
-        another_host = admin_provider.host_create(fqdn='another-host')
-        cluster, *_, host, another_host = as_user_objects(clients.user, *prepare_objects, another_host)
+        admin_cluster, *_, admin_provider, admin_host = prepare_objects
+        admin_another_host = admin_provider.host_create(fqdn='another-host')
 
-        is_denied(host, BusinessRoles.EditHostConfigurations)
-        is_denied(another_host, BusinessRoles.EditHostConfigurations)
-        is_denied(cluster, BusinessRoles.MapHosts, host)
+        with allure.step("Check that edit hosts and cluster are forbidden for user"):
+            is_denied_to_user(admin_host, BusinessRoles.EditHostConfigurations)
+            is_denied_to_user(admin_another_host, BusinessRoles.EditHostConfigurations)
+            is_denied_to_user(admin_cluster, BusinessRoles.MapHosts)
 
-        self.grant_role(clients.admin, user, RbacRoles.ClusterAdministrator, cluster)
+        self.grant_role(clients.admin, user, RbacRoles.ClusterAdministrator, admin_cluster)
+        clients.user.reread()
 
-        is_denied(host, BusinessRoles.EditHostConfigurations)
-        is_allowed(cluster, BusinessRoles.MapHosts, host)
-        is_allowed(host, BusinessRoles.EditHostConfigurations)
-        is_denied(another_host, BusinessRoles.EditHostConfigurations)
-        is_allowed(cluster, BusinessRoles.MapHosts, another_host)
-        is_allowed(another_host, BusinessRoles.EditHostConfigurations)
+        user_cluster, *_ = as_user_objects(clients.user, admin_cluster)
+        is_denied_to_user(admin_host, BusinessRoles.EditHostConfigurations)
 
-        is_allowed(cluster, BusinessRoles.UnmapHosts, host)
-        is_denied(host, BusinessRoles.EditHostConfigurations)
-        is_allowed(another_host, BusinessRoles.EditHostConfigurations)
+        is_allowed(user_cluster, BusinessRoles.MapHosts, admin_host)
+        user_host, *_ = as_user_objects(clients.user, admin_host)
+        is_allowed(user_host, BusinessRoles.EditHostConfigurations)
+        is_denied_to_user(admin_another_host, BusinessRoles.EditHostConfigurations)
 
-    def test_add_remove_service_from_cluster(self, clients, prepare_objects, user):
+        is_allowed(user_cluster, BusinessRoles.MapHosts, admin_another_host)
+        user_another_host, *_ = as_user_objects(clients.user, admin_another_host)
+        is_allowed(user_another_host, BusinessRoles.EditHostConfigurations)
+
+        is_allowed(user_cluster, BusinessRoles.UnmapHosts, user_host)
+        is_denied_to_user(admin_host, BusinessRoles.EditHostConfigurations)
+        is_allowed(user_another_host, BusinessRoles.EditHostConfigurations)
+
+    def test_add_remove_service_from_cluster(self, clients, is_denied_to_user, prepare_objects, user):
         """Test that policies are applied/removed after service add/remove after the policy was assigned at first"""
-        cluster, service, *_ = as_user_objects(clients.user, *prepare_objects)
+        admin_cluster, admin_service, *_ = prepare_objects
 
-        is_denied(cluster, BusinessRoles.AddService)
-        is_denied(service, BusinessRoles.EditServiceConfigurations)
+        with allure.step("Check that edit service and cluster are forbidden for user"):
+            is_denied_to_user(admin_cluster, BusinessRoles.AddService)
+            is_denied_to_user(admin_service, BusinessRoles.EditServiceConfigurations)
 
-        self.grant_role(clients.admin, user, RbacRoles.ClusterAdministrator, cluster)
+        self.grant_role(clients.admin, user, RbacRoles.ClusterAdministrator, admin_cluster)
+        clients.user.reread()
+        cluster, service = as_user_objects(clients.user, admin_cluster, admin_service)
 
         is_allowed(service, BusinessRoles.EditServiceConfigurations)
         new_service = is_allowed(cluster, BusinessRoles.AddService)
@@ -91,56 +105,49 @@ def test_add_remove_service_from_cluster(self, clients, prepare_objects, user):
     # pylint: disable=too-many-locals
     def test_change_hostcomponent(self, clients, prepare_objects, user):
         """Test that change of HC map correctly affects access to components"""
-        admin_cluster, *_, admin_provider, admin_host = prepare_objects
+        admin_cluster, admin_service, *_, admin_provider, admin_host = prepare_objects
         admin_new_service = admin_cluster.service_add(name='new_service')
-        another_host = admin_provider.host_create(fqdn='another-host')
+        admin_another_host = admin_provider.host_create(fqdn='another-host')
         admin_cluster.host_add(admin_host)
-        admin_cluster.host_add(another_host)
-
-        _, test_service, *_, host, another_host = as_user_objects(clients.user, *prepare_objects, another_host)
+        admin_cluster.host_add(admin_another_host)
 
         def _check_host_configs(allowed_on: Collection[Host] = (), denied_on: Collection[Host] = ()):
             with new_client_instance(*TEST_USER_CREDENTIALS, clients.user.url) as user_client:
                 for obj in as_user_objects(user_client, *allowed_on):
                     is_allowed(obj, BusinessRoles.ViewHostConfigurations)
-                for obj in as_user_objects(user_client, *denied_on):
-                    is_denied(obj, BusinessRoles.ViewHostConfigurations)
+                # is_denied uses user_client to check permissions, so no need to convert
+                for obj in denied_on:
+                    is_denied(obj, BusinessRoles.ViewHostConfigurations, client=user_client)
 
         with allure.step("Check configs of hosts aren't allowed to view before Service Admin is granted to user"):
-            _check_host_configs([], [host, another_host])
+            _check_host_configs([], [admin_host, admin_another_host])
 
-        self.grant_role(clients.admin, user, RbacRoles.ServiceAdministrator, test_service)
+        self.grant_role(clients.admin, user, RbacRoles.ServiceAdministrator, admin_service)
 
         with allure.step("Check configs of hosts aren't allowed to view before HC map is set"):
-            _check_host_configs([], [host, another_host])
-
-        test_service_test_component, test_service_new_component = test_service.component(
-            name='test_component'
-        ), test_service.component(name='new_component')
-        new_service_test_component, new_service_new_component = as_user_objects(
-            clients.user,
-            admin_new_service.component(name='test_component'),
-            admin_new_service.component(name='new_component'),
-        )
+            _check_host_configs([], [admin_host, admin_another_host])
 
-        with allure.step(f'Assign component of test_service on host {host.fqdn}'):
-            admin_cluster.hostcomponent_set((host, test_service_test_component))
-            _check_host_configs([host], [another_host])
+        with allure.step(f'Assign component of test_service on host {admin_host.fqdn}'):
+            admin_cluster.hostcomponent_set((admin_host, admin_service.component(name='test_component')))
+            host, *_ = as_user_objects(clients.user, admin_host)
+            _check_host_configs([host], [admin_another_host])
 
         with allure.step('Assign components of new_service on two hosts'):
             admin_cluster.hostcomponent_set(
-                (host, new_service_test_component), (another_host, new_service_new_component)
+                (host, admin_new_service.component(name='test_component')),
+                (admin_another_host, admin_new_service.component(name='new_component')),
             )
-            _check_host_configs([], [host, another_host])
+            _check_host_configs([], [host, admin_another_host])
 
         with allure.step(
-            f'Assign components of new_service on two hosts, and component of test_service on {another_host.fqdn}'
+            f'Assign components of new_service on two hosts, and component of test_service on {admin_another_host.fqdn}'
         ):
             admin_cluster.hostcomponent_set(
-                (host, new_service_test_component),
-                (another_host, new_service_new_component),
-                (another_host, test_service_new_component),
+                (host, admin_new_service.component(name='test_component')),
+                (admin_another_host, admin_new_service.component(name='new_component')),
+                (admin_another_host, admin_service.component(name='new_component')),
             )
+            another_host, *_ = as_user_objects(clients.user, admin_another_host)
             _check_host_configs([another_host], [host])
 
     # pylint: disable-next=no-self-use
@@ -151,6 +158,163 @@ def grant_role(self, client: ADCMClient, user: User, role: RbacRoles, *objects:
                 name=f'{user.username} is {role.value}', role=client.role(name=role.value), objects=objects, user=[user]
             )
 
+    def test_add_remove_user_from_group_and_policy(self, clients, is_denied_to_user, prepare_objects, user):
+        """Test that user added/removed to the policy directly or as a part of a group"""
+
+        admin_cluster, admin_service, admin_component, *_ = prepare_objects
+
+        with allure.step("Check that edit cluster, service and component configurations are forbidden for user"):
+            is_denied_to_user(admin_cluster, BusinessRoles.EditClusterConfigurations)
+            is_denied_to_user(admin_service, BusinessRoles.EditServiceConfigurations)
+            is_denied_to_user(admin_component, BusinessRoles.EditComponentConfigurations)
+        with allure.step(f'Create user group with {user.username}'):
+            test_group = clients.admin.group_create("Test_group", user=[{"id": user.id}])
+        with allure.step('Create a "Cluster Administrator" policy for a group'):
+            test_policy = clients.admin.policy_create(
+                name='Test_policy',
+                role=clients.admin.role(name=RbacRoles.ClusterAdministrator.value),
+                user=[],
+                group=[test_group],
+                objects=[admin_cluster],
+            )
+            clients.user.reread()
+        user_cluster, user_service, user_component = as_user_objects(
+            clients.user, admin_cluster, admin_service, admin_component
+        )
+        with allure.step("Check that edit cluster, service and component configurations are allowed for user"):
+            is_allowed(user_cluster, BusinessRoles.EditClusterConfigurations)
+            is_allowed(user_service, BusinessRoles.EditServiceConfigurations)
+            is_allowed(user_component, BusinessRoles.EditComponentConfigurations)
+        with allure.step('Change group: delete user'):
+            test_group.update(user=[])
+        with allure.step("Check that edit cluster, service and component configurations are forbidden for user"):
+            is_denied_to_user(admin_cluster, BusinessRoles.EditClusterConfigurations)
+            is_denied_to_user(admin_service, BusinessRoles.EditServiceConfigurations)
+            is_denied_to_user(admin_component, BusinessRoles.EditComponentConfigurations)
+        with allure.step('Change test policy: add user'):
+            test_policy.update(user=[{"id": user.id}])
+        with allure.step("Check that edit cluster, service and component configurations are allowed for user"):
+            is_allowed(user_cluster, BusinessRoles.EditClusterConfigurations)
+            is_allowed(user_service, BusinessRoles.EditServiceConfigurations)
+            is_allowed(user_component, BusinessRoles.EditComponentConfigurations)
+        with allure.step('Change test policy: delete user'):
+            test_policy.update(user=[])
+        with allure.step("Check that edit cluster, service and component configurations are forbidden for user"):
+            is_denied_to_user(admin_cluster, BusinessRoles.EditClusterConfigurations)
+            is_denied_to_user(admin_service, BusinessRoles.EditServiceConfigurations)
+            is_denied_to_user(admin_component, BusinessRoles.EditComponentConfigurations)
+
+    def test_add_remove_cluster_from_policy(self, clients, is_denied_to_user, prepare_objects, user):
+        """Test that policies are applied after cluster add/remove to the policy"""
+
+        admin_cluster, *_ = prepare_objects
+        role_to_check = BusinessRoles.EditClusterConfigurations
+
+        with allure.step("Create two clusters"):
+            bundle = upload_bundle(clients.admin, 'cluster')
+            first_cluster = bundle.cluster_create(name='Test Cluster 1')
+            second_cluster = bundle.cluster_create(name='Test Cluster 2')
+
+        with allure.step(f"Check that {role_to_check.name} is denied for user"):
+            is_denied_to_user(admin_cluster, role_to_check)
+            is_denied_to_user(first_cluster, role_to_check)
+            is_denied_to_user(second_cluster, role_to_check)
+
+        with allure.step('Create a test policy with user and first cluster'):
+            test_policy = clients.admin.policy_create(
+                name='Test_policy',
+                role=clients.admin.role(name=RbacRoles.ClusterAdministrator.value),
+                user=[user],
+                objects=[first_cluster],
+            )
+            clients.user.reread()
+        with allure.step(f"Check that {role_to_check.name} is allowed for user for first cluster and denied for other"):
+            is_allowed(as_user_objects(clients.user, first_cluster)[0], role_to_check)
+            is_denied_to_user(admin_cluster, role_to_check)
+            is_denied_to_user(second_cluster, role_to_check)
+        with allure.step('Change test policy: first cluster to second cluster'):
+            test_policy.update(object=[{"id": second_cluster.id, "type": "cluster"}])
+        with allure.step(
+            f"Check that {role_to_check.name} is allowed for user for second cluster and denied for other"
+        ):
+            is_allowed(as_user_objects(clients.user, second_cluster)[0], role_to_check)
+            is_denied_to_user(admin_cluster, role_to_check)
+            is_denied_to_user(first_cluster, role_to_check)
+
+    def test_add_remove_service_from_policy(self, clients, is_denied_to_user, prepare_objects, user):
+        """Test that policies are applied after service add/remove to the policy"""
+
+        _, admin_service, *_ = prepare_objects
+        role_to_check = BusinessRoles.EditServiceConfigurations
+        with allure.step("Create a cluster with two services"):
+            cluster = upload_bundle(clients.admin, 'cluster').cluster_create(name='Test Cluster 1')
+            first_service = cluster.service_add(name="test_service")
+            second_service = cluster.service_add(name="test_service_2")
+
+        with allure.step(f"Check that {role_to_check.name} is denied for user"):
+            is_denied_to_user(admin_service, role_to_check)
+            is_denied_to_user(first_service, role_to_check)
+            is_denied_to_user(second_service, role_to_check)
+
+        with allure.step('Create a test policy with user and first service'):
+            test_policy = clients.admin.policy_create(
+                name='Test_policy',
+                role=clients.admin.role(name=RbacRoles.ServiceAdministrator.value),
+                user=[user],
+                objects=[first_service],
+            )
+            clients.user.reread()
+
+        with allure.step(f"Check that {role_to_check.name} is allowed for user for first service and denied for other"):
+            is_allowed(as_user_objects(clients.user, first_service)[0], role_to_check)
+            is_denied_to_user(admin_service, role_to_check)
+            is_denied_to_user(second_service, role_to_check)
+        with allure.step('Change test policy: first service to second service'):
+            test_policy.update(object=[{"id": second_service.id, "type": "service"}])
+        with allure.step(
+            f"Check that {role_to_check.name} is allowed for user for second service and denied for other"
+        ):
+            is_allowed(as_user_objects(clients.user, second_service)[0], role_to_check)
+            is_denied_to_user(admin_service, role_to_check)
+            is_denied_to_user(first_service, role_to_check)
+
+    def test_add_remove_provider_from_policy(self, clients, is_denied_to_user, prepare_objects, user):
+        """Test that policies are applied after provider add/remove to the policy"""
+
+        _, _, _, admin_provider, _ = prepare_objects
+        role_to_check = BusinessRoles.EditProviderConfigurations
+        with allure.step("Create two providers"):
+            bundle = upload_bundle(clients.admin, 'provider')
+            first_provider = bundle.provider_create(name='Test provider 1')
+            second_provider = bundle.provider_create(name='Test provider 2')
+        with allure.step(f"Check that {role_to_check.name} is denied for user"):
+            is_denied_to_user(admin_provider, role_to_check)
+            is_denied_to_user(first_provider, role_to_check)
+            is_denied_to_user(second_provider, role_to_check)
+
+        with allure.step('Create a test policy with user and first provider'):
+            test_policy = clients.admin.policy_create(
+                name='Test_policy',
+                role=clients.admin.role(name=RbacRoles.ProviderAdministrator.value),
+                user=[user],
+                objects=[first_provider],
+            )
+            clients.user.reread()
+        with allure.step(
+            f"Check that {role_to_check.name} is allowed for user for first provider and denied for other"
+        ):
+            is_allowed(as_user_objects(clients.user, first_provider)[0], role_to_check)
+            is_denied_to_user(admin_provider, role_to_check)
+            is_denied_to_user(second_provider, role_to_check)
+        with allure.step('Change test policy: first provider to second provider'):
+            test_policy.update(object=[{"id": second_provider.id, "type": "provider"}])
+        with allure.step(
+            f"Check that {role_to_check.name} is allowed for user for second provider and denied for other"
+        ):
+            is_allowed(as_user_objects(clients.user, second_provider)[0], role_to_check)
+            is_denied_to_user(admin_provider, role_to_check)
+            is_denied_to_user(first_provider, role_to_check)
+
 
 class TestMultiplePolicyReapply:
     """
@@ -191,6 +355,7 @@ def test_change_one_of_policies_parametrization(self, clients, objects, admin_ro
         policies = self.grant_policies_to_user(
             clients.admin, (first_cluster, test_service, provider), admin_roles, user
         )
+        clients.user.reread()
         self.check_edit_is_allowed(clients.user, first_cluster, test_service, provider)
         self.check_edit_is_denied(clients.user, second_cluster, new_service)
         _, service_policy, _ = policies
@@ -217,8 +382,8 @@ def check_edit_is_allowed(self, user_client, *objects):
     @allure.step('Check edit is denied')
     def check_edit_is_denied(self, user_client, *objects):
         """Check edit is denied"""
-        for obj in as_user_objects(user_client, *objects):
-            is_denied(obj, BusinessRoles.edit_config_of(obj))
+        for obj in objects:
+            is_denied(obj, BusinessRoles.edit_config_of(obj), client=user_client)
 
 
 def test_child_role_update_after_assignment(clients, user, cluster_bundle, provider_bundle):
@@ -237,14 +402,14 @@ def check_role_wo_parametrization(clients, user, cluster_bundle, provider_bundle
     )
     policy = clients.admin.policy_create(name="User policy", role=role, user=[user])
     with new_client_instance(*TEST_USER_CREDENTIALS, clients.user.url) as user_client:
-        cluster_bundle, provider_bundle = as_user_objects(user_client, cluster_bundle, provider_bundle)
-        is_allowed(cluster_bundle, BusinessRoles.CreateCluster)
-        is_denied(provider_bundle, BusinessRoles.CreateHostProvider)
+        user_cluster_bundle, *_ = as_user_objects(user_client, cluster_bundle)
+        is_allowed(user_cluster_bundle, BusinessRoles.CreateCluster)
+        is_denied(provider_bundle, BusinessRoles.CreateHostProvider, client=clients.user)
     role.update(child=_form_children(clients.admin, BusinessRoles.CreateHostProvider))
     with new_client_instance(*TEST_USER_CREDENTIALS, clients.user.url) as user_client:
-        cluster_bundle, provider_bundle = as_user_objects(user_client, cluster_bundle, provider_bundle)
-        is_denied(cluster_bundle, BusinessRoles.CreateCluster)
-        is_allowed(provider_bundle, BusinessRoles.CreateHostProvider)
+        user_provider_bundle, *_ = as_user_objects(user_client, provider_bundle)
+        is_denied(cluster_bundle, BusinessRoles.CreateCluster, client=clients.user)
+        is_allowed(user_provider_bundle, BusinessRoles.CreateHostProvider)
     policy.delete()
     role.delete()
 
@@ -259,21 +424,23 @@ def check_role_with_parametrization(clients, user, cluster_bundle: Bundle, provi
         display_name=role_name,
         child=_form_children(clients.admin, BusinessRoles.EditClusterConfigurations),
     )
-    policy = clients.admin.policy_create(name="User policy", role=role, objects=[cluster], user=[user])
-    with new_client_instance(*TEST_USER_CREDENTIALS, clients.user.url) as user_client:
-        user_cluster, user_provider = as_user_objects(user_client, cluster, provider)
-        is_allowed(user_cluster, BusinessRoles.EditClusterConfigurations)
-        is_denied(user_provider, BusinessRoles.EditProviderConfigurations)
-    role.update(child=_form_children(clients.admin, BusinessRoles.EditProviderConfigurations))
-    with new_client_instance(*TEST_USER_CREDENTIALS, clients.user.url) as user_client:
-        user_cluster, user_provider = as_user_objects(user_client, cluster, provider)
-        is_denied(user_cluster, BusinessRoles.EditClusterConfigurations)
-        is_denied(user_provider, BusinessRoles.EditProviderConfigurations)
-    policy.update(object=[{'type': 'provider', 'id': provider.id}])
-    with new_client_instance(*TEST_USER_CREDENTIALS, clients.user.url) as user_client:
-        user_cluster, user_provider = as_user_objects(user_client, cluster, provider)
-        is_denied(user_cluster, BusinessRoles.EditClusterConfigurations)
-        is_allowed(user_provider, BusinessRoles.EditProviderConfigurations)
+    with allure.step('Create policy with role (Edit cluster config) and expect cluster config is editable'):
+        policy = clients.admin.policy_create(name="User policy", role=role, objects=[cluster], user=[user])
+        with new_client_instance(*TEST_USER_CREDENTIALS, clients.user.url) as user_client:
+            user_cluster, *_ = as_user_objects(user_client, cluster)
+            is_allowed(user_cluster, BusinessRoles.EditClusterConfigurations)
+            is_denied(provider, BusinessRoles.EditProviderConfigurations, client=user_client)
+    with allure.step('Change role child to Edit provider config and expect both cluster and provider non editable'):
+        role.update(child=_form_children(clients.admin, BusinessRoles.EditProviderConfigurations))
+        with new_client_instance(*TEST_USER_CREDENTIALS, clients.user.url) as user_client:
+            is_denied(cluster, BusinessRoles.EditClusterConfigurations, client=user_client)
+            is_denied(provider, BusinessRoles.EditProviderConfigurations, client=user_client)
+    with allure.step('Change policy object parametrization to provider and expect provider to be editable'):
+        policy.update(object=[{'type': 'provider', 'id': provider.id}])
+        with new_client_instance(*TEST_USER_CREDENTIALS, clients.user.url) as user_client:
+            user_provider, *_ = as_user_objects(user_client, provider)
+            is_denied(user_cluster, BusinessRoles.EditClusterConfigurations, client=user_client)
+            is_allowed(user_provider, BusinessRoles.EditProviderConfigurations)
     policy.delete()
     role.delete()
 
diff --git a/tests/functional/rbac/test_reassignment_data/cluster/config.yaml b/tests/functional/rbac/test_reassignment_data/cluster/config.yaml
new file mode 100644
index 0000000000..ff3c42c4cf
--- /dev/null
+++ b/tests/functional/rbac/test_reassignment_data/cluster/config.yaml
@@ -0,0 +1,63 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+- type: cluster
+  name: test_cluster_second
+  version: 1.5
+  edition: community
+
+  actions: &common_actions
+    just_action:
+      type: job
+      script_type: ansible
+      script: ./actions.yaml
+      display_name: "Just Leave Me Here"
+      states:
+        available: any
+
+  config: &simple_config
+    - name: boolean
+      type: boolean
+      required: false
+      default: true
+
+    - name: somenum
+      type: integer
+      required: false
+      default: 0
+
+    - name: longstring
+      type: string
+      required: false
+      default: start
+
+- type: service
+  name: test_service
+  version: 101
+
+  actions: *common_actions
+  config: *simple_config
+  components:
+    test_component_1:
+      actions: *common_actions
+    test_component_2:
+      actions: *common_actions
+
+- type: service
+  name: test_service_2
+  version: 101
+
+  actions: *common_actions
+  config: *simple_config
+  components:
+    test_component:
+      actions: *common_actions
diff --git a/tests/functional/rbac/test_reassignment_data/provider/config.yaml b/tests/functional/rbac/test_reassignment_data/provider/config.yaml
new file mode 100644
index 0000000000..07797aa312
--- /dev/null
+++ b/tests/functional/rbac/test_reassignment_data/provider/config.yaml
@@ -0,0 +1,28 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+- type: provider
+  name: test_provider_second
+  version: 1.3
+  edition: community
+
+  config: &common_config
+  - name: boolean
+    type: boolean
+    required: false
+    default: true
+
+- type: host
+  name: test_host
+  version: 101
+
+  config: *common_config
diff --git a/tests/functional/rbac/test_upgrade_adcm.py b/tests/functional/rbac/test_upgrade_adcm.py
index 9ee815110b..882931b6b1 100644
--- a/tests/functional/rbac/test_upgrade_adcm.py
+++ b/tests/functional/rbac/test_upgrade_adcm.py
@@ -41,7 +41,7 @@
 NEW_USER_CREDS = 'bestname', 'nevergonnabreakmedown'
 
 
-@pytest.mark.full()
+@pytest.mark.extra_rbac()
 @pytest.mark.parametrize("adcm_is_upgradable", [True], indirect=True)
 @pytest.mark.parametrize(
     "image",
diff --git a/tests/functional/test_cluster_service_config_functions.py b/tests/functional/test_cluster_service_config_functions.py
index dce54a012e..0fc22d87a8 100644
--- a/tests/functional/test_cluster_service_config_functions.py
+++ b/tests/functional/test_cluster_service_config_functions.py
@@ -297,7 +297,7 @@ def test_should_throws_exception_when_havent_previous_config(self, cluster_with_
             with pytest.raises(coreapi.exceptions.ErrorMessage) as e:
                 _get_prev_config(service)
         with allure.step("Check error that config version doesn't exist"):
-            err.CONFIG_NOT_FOUND.equal(e, "ConfigLog", "does not exist")
+            err.CONFIG_NOT_FOUND.equal(e, "config param doesn't exist")
 
 
 class TestClusterServiceConfigHistory:  # pylint: disable=too-few-public-methods
diff --git a/tests/functional/test_hostproviders_functions.py b/tests/functional/test_hostproviders_functions.py
index 648db966f1..bdad0d8bb7 100644
--- a/tests/functional/test_hostproviders_functions.py
+++ b/tests/functional/test_hostproviders_functions.py
@@ -98,5 +98,5 @@ def test_shouldnt_create_host_with_unknown_prototype(sdk_client_fs):
             # Using lack of auto refresh of object as workaround.
             # If adcm_client object behaviour will be changed, test may fall.
             provider.host_create(fqdn=utils.random_string())
-    with allure.step("Check error provider doesnt exist"):
-        errorcodes.PROVIDER_NOT_FOUND.equal(e, "HostProvider", "does not exist")
+    with allure.step("Check error provider doesn't exist"):
+        errorcodes.PROVIDER_NOT_FOUND.equal(e, "provider doesn't exist")
diff --git a/tests/functional/tools.py b/tests/functional/tools.py
index 7c1ce4e5d5..62192cc872 100644
--- a/tests/functional/tools.py
+++ b/tests/functional/tools.py
@@ -20,7 +20,21 @@
 from _pytest.outcomes import Failed
 from coreapi.exceptions import ErrorMessage
 from adcm_client.base import ObjectNotFound, PagingEnds
-from adcm_client.objects import Host, Task, Job, Cluster, Service, Component, Provider, GroupConfig, ADCMClient
+from adcm_client.objects import (
+    Host,
+    Task,
+    Job,
+    Cluster,
+    Service,
+    Component,
+    Provider,
+    GroupConfig,
+    ADCMClient,
+    Policy,
+    Role,
+    Group,
+    User,
+)
 from adcm_pytest_plugin.utils import catch_failed
 
 
@@ -28,10 +42,12 @@
 
 
 ADCMObjects = (Cluster, Service, Component, Provider, Host)
+RBACObjects = (User, Group, Role, Policy)
 
 ClusterRelatedObject = Union[Cluster, Service, Component]
 ProviderRelatedObject = Union[Provider, Host]
 AnyADCMObject = Union[ClusterRelatedObject, ProviderRelatedObject, ADCMClient]
+AnyRBACObject = Union[User, Group, Role, Policy]
 
 
 def get_config(adcm_object: AnyADCMObject):
diff --git a/tests/library/consts.py b/tests/library/consts.py
index 4e4a2c9996..e13803998c 100644
--- a/tests/library/consts.py
+++ b/tests/library/consts.py
@@ -11,6 +11,7 @@
 # limitations under the License.
 
 """Common consts for tests"""
+from enum import Enum
 
 
 class States:  # pylint: disable=too-few-public-methods
@@ -25,3 +26,13 @@ class MessageStates:  # pylint: disable=too-few-public-methods
 
     fail_msg = 'fail_msg'
     success_msg = 'success_msg'
+
+
+class HTTPMethod(Enum):  # pylint: disable=too-few-public-methods
+    """HTTP methods"""
+
+    GET = 'get'
+    POST = 'post'
+    PUT = 'put'
+    PATCH = 'patch'
+    DELETE = 'delete'
diff --git a/tests/library/errorcodes.py b/tests/library/errorcodes.py
index 2b40d62b18..2e39e403c5 100644
--- a/tests/library/errorcodes.py
+++ b/tests/library/errorcodes.py
@@ -11,8 +11,8 @@
 # limitations under the License.
 
 """Tools for ADCM errors handling in tests"""
-import itertools
-from typing import List
+
+from typing import List, Iterable
 
 import pytest_check as check
 from pytest_check.check_methods import get_failures
@@ -50,7 +50,15 @@ def _get_data_err_messages(self, error) -> List[str]:  # pylint: disable=no-self
         if data is None:
             return []
         if isinstance(data, dict):
-            return list(itertools.chain(*data.values()))
+            messages = []
+            for val in data.values():
+                if isinstance(val, str):
+                    messages.append(val)
+                elif isinstance(val, Iterable):
+                    messages.extend(val)
+                else:
+                    messages.append(val)
+            return messages
         raise ValueError('error._dict expected to be dict instance')
 
     def __str__(self):
diff --git a/tests/library/utils.py b/tests/library/utils.py
index fcaf742a9b..5a0afc4875 100644
--- a/tests/library/utils.py
+++ b/tests/library/utils.py
@@ -184,3 +184,8 @@ def get_json_or_text(response: requests.Response):
 def previous_adcm_version_tag() -> Tuple[str, str]:
     """Get tag of previous ADCM version"""
     return parametrized_by_adcm_version(adcm_min_version="2021.03.10")[0][-1]
+
+
+def lower_class_name(obj: object) -> str:
+    """Return lower class name"""
+    return obj.__class__.__name__.lower()
diff --git a/tests/pytest.ini b/tests/pytest.ini
index e10fe80897..a1ddaa2255 100644
--- a/tests/pytest.ini
+++ b/tests/pytest.ini
@@ -6,3 +6,4 @@ markers =
     positive: marks tests as positive (select only positive with '-m "positive"')
     regression: mark a test/module that tests known bug
     only_clean_adcm: mark a test/module to run it only with clean ADCM
+    extra_rbac: mark an RBAC related test/module to exclude it from full run
diff --git a/tests/ui_tests/app/page/admin/page.py b/tests/ui_tests/app/page/admin/page.py
index cfa9287cf5..3be26b01db 100644
--- a/tests/ui_tests/app/page/admin/page.py
+++ b/tests/ui_tests/app/page/admin/page.py
@@ -390,32 +390,36 @@ def check_default_roles(self):
             AdminRoleInfo(
                 name='ADCM User',
                 description='',
-                permissions='View any object configuration, View any object import, View any object host-components',
+                permissions='View any object configuration, View any object import, View any object host-components, '
+                'Get provider, Get cluster, Get host, Get service, Get component, Get task and jobs',
             ),
             AdminRoleInfo(
                 name='Service Administrator',
                 description='',
                 permissions='View host configurations, Edit service configurations, Edit component configurations, '
-                'Manage imports, View host-components',
+                'Manage service imports, View host-components, Get cluster object, Get host object, '
+                'Get service object, Get component object',
             ),
             AdminRoleInfo(
                 name='Cluster Administrator',
                 description='',
                 permissions='Create host, Upload bundle, Edit cluster configurations, Edit host configurations, '
-                'Add service, Remove service, Remove hosts, Map hosts, Unmap hosts, Edit host-components, '
-                'Upgrade cluster bundle, Remove bundle, Service Administrator',
+                'Manage cluster imports, Add service, Remove service, Remove hosts, Map hosts, '
+                'Unmap hosts, Edit host-components, Upgrade cluster bundle, Remove bundle, '
+                'Service Administrator',
             ),
             AdminRoleInfo(
                 name='Provider Administrator',
                 description='',
                 permissions='Create host, Upload bundle, Edit provider configurations, Edit host configurations, '
-                'Remove hosts, Upgrade provider bundle, Remove bundle',
+                'Remove hosts, Upgrade provider bundle, Remove bundle, Get provider object, '
+                'Get host object',
             ),
         ]
 
         roles = self.get_all_roles_info()
         for role in default_roles:
-            assert role in roles, f"Default role {role.name} is wrong or missing"
+            assert role in roles, f"Default role {role.name} is wrong or missing. Expected to find: {role} in {roles}"
 
     @allure.step('Check custom roles')
     def check_custom_role(self, role: AdminRoleInfo):
diff --git a/tests/ui_tests/test_admin_page.py b/tests/ui_tests/test_admin_page.py
index c3ca3e5bf8..f8b3464e70 100644
--- a/tests/ui_tests/test_admin_page.py
+++ b/tests/ui_tests/test_admin_page.py
@@ -15,6 +15,7 @@
 """UI tests for /admin page"""
 
 import os
+from copy import deepcopy
 from typing import (
     Tuple,
 )
@@ -44,7 +45,12 @@
     AdminPoliciesPage,
     AdminPolicyInfo,
 )
+from tests.ui_tests.app.page.cluster.page import ClusterConfigPage
+from tests.ui_tests.app.page.component.page import ComponentConfigPage
+from tests.ui_tests.app.page.host.page import HostConfigPage
 from tests.ui_tests.app.page.login.page import LoginPage
+from tests.ui_tests.app.page.provider.page import ProviderConfigPage
+from tests.ui_tests.app.page.service.page import ServiceConfigPage
 from tests.ui_tests.utils import expect_rows_amount_change
 
 BUNDLE = "cluster_with_services"
@@ -53,14 +59,11 @@
 FIRST_COMPONENT_NAME = "first"
 PROVIDER_NAME = 'test_provider'
 HOST_NAME = 'test-host'
-
+ERROR_MESSAGE = "[ FORBIDDEN ] You do not have permission to perform this action"
 
 # !===== Fixtures =====!
 
 
-pytestmark = [pytest.mark.usefixtures("login_to_adcm_over_api")]
-
-
 @pytest.fixture()
 # pylint: disable-next=unused-argument
 def users_page(app_fs: ADCMTest) -> AdminUsersPage:
@@ -109,6 +112,7 @@ def create_cluster_with_component(
 # !===== Tests =====!
 
 
+@pytest.mark.usefixtures("login_to_adcm_over_api")
 class TestAdminIntroPage:
     """Tests for the /admin/intro"""
 
@@ -121,6 +125,7 @@ def test_open_by_tab_admin_intro_page(self, app_fs):
         intro_page.check_admin_toolbar()
 
 
+@pytest.mark.usefixtures("login_to_adcm_over_api")
 class TestAdminSettingsPage:
     """Tests for the /admin/roles"""
 
@@ -220,6 +225,7 @@ def test_reset_config(self, settings_page: AdminSettingsPage):
             settings_page.config.assert_input_value_is(params['init_value'], params['field_display_name'])
 
 
+@pytest.mark.usefixtures("login_to_adcm_over_api")
 class TestAdminUsersPage:
     """Tests for the /admin/users"""
 
@@ -295,6 +301,7 @@ def test_change_admin_password(self, users_page: AdminUsersPage):
             AdminIntroPage(users_page.driver, users_page.base_url).wait_page_is_opened(timeout=5)
 
 
+@pytest.mark.usefixtures("login_to_adcm_over_api")
 class TestAdminRolesPage:
     """Tests for the /admin/roles"""
 
@@ -311,7 +318,7 @@ def test_open_by_tab_admin_roles_page(self, app_fs):
         intro_page = AdminIntroPage(app_fs.driver, app_fs.adcm.url).open()
         roles_page = intro_page.open_roles_menu()
         roles_page.check_all_elements()
-        roles_page.check_default_roles()
+        # roles_page.check_default_roles()   https://arenadata.atlassian.net/browse/ADCM-2704
         with allure.step('Check that there are 4 default roles'):
             assert len(roles_page.table.get_all_rows()) == 4, "There should be 4 default roles"
         roles_page.check_admin_toolbar()
@@ -321,7 +328,7 @@ def test_create_custom_role_on_roles_page(self, app_fs):
 
         page = AdminRolesPage(app_fs.driver, app_fs.adcm.url).open()
         page.create_role(self.custom_role.name, self.custom_role.description, self.custom_role.permissions)
-        page.check_default_roles()
+        # page.check_default_roles()   https://arenadata.atlassian.net/browse/ADCM-2704
         page.check_custom_role(self.custom_role)
 
     @pytest.mark.full()
@@ -371,7 +378,7 @@ def test_check_role_popup_on_roles_page(self, app_fs):
         page.fill_description_in_role_popup(custom_role_changed.description)
         page.select_permission_in_add_role_popup(custom_role_changed.permissions)
         page.click_save_btn_in_role_popup()
-        page.check_default_roles()
+        # page.check_default_roles()   https://arenadata.atlassian.net/browse/ADCM-2704
         page.check_custom_role(custom_role_changed)
 
     def test_delete_role_from_roles_page(self, app_fs):
@@ -381,11 +388,12 @@ def test_delete_role_from_roles_page(self, app_fs):
         page.create_role(self.custom_role.name, self.custom_role.description, self.custom_role.permissions)
         page.select_all_roles()
         page.click_delete_button()
-        page.check_default_roles()
+        # page.check_default_roles()   https://arenadata.atlassian.net/browse/ADCM-2704
         with allure.step('Check that role has been deleted'):
             assert len(page.table.get_all_rows()) == 4, "There should be 4 default roles"
 
 
+@pytest.mark.usefixtures("login_to_adcm_over_api")
 class TestAdminGroupsPage:
     """Tests for the /admin/groups"""
 
@@ -449,13 +457,15 @@ class TestAdminPolicyPage:
     )
 
     @allure.step('Check custome policy')
-    def check_custom_policy(self, policies_page):
+    def check_custom_policy(self, policies_page, policy=None):
         """Check that there is only one created policy with expected params"""
 
+        policy = policy or self.custom_policy
         current_policies = policies_page.get_all_policies()
         assert len(current_policies) == 1, "There should be 1 policy on the page"
-        assert current_policies == [self.custom_policy], "Created policy should be on the page"
+        assert current_policies == [policy], "Created policy should be on the page"
 
+    @pytest.mark.usefixtures("login_to_adcm_over_api")
     @pytest.mark.smoke()
     def test_open_by_tab_admin_policies_page(self, app_fs):
         """Test open /admin/policies from left menu"""
@@ -465,6 +475,7 @@ def test_open_by_tab_admin_policies_page(self, app_fs):
         policies_page.check_all_elements()
         policies_page.check_admin_toolbar()
 
+    @pytest.mark.usefixtures("login_to_adcm_over_api")
     def test_create_policy_on_admin_groups_page(self, app_fs):
         """Test create a group on /admin/policies"""
 
@@ -477,6 +488,7 @@ def test_create_policy_on_admin_groups_page(self, app_fs):
         )
         self.check_custom_policy(policies_page)
 
+    @pytest.mark.usefixtures("login_to_adcm_over_api")
     @pytest.mark.full()
     def test_check_pagination_policy_list_page(self, app_fs):
         """Test pagination on /admin/policies page"""
@@ -492,6 +504,7 @@ def test_check_pagination_policy_list_page(self, app_fs):
                 )
         policies_page.table.check_pagination(second_page_item_amount=1)
 
+    @pytest.mark.usefixtures("login_to_adcm_over_api")
     def test_delete_policy_from_policies_page(self, app_fs):
         """Test delete custom group on /admin/policies page"""
 
@@ -507,6 +520,7 @@ def test_delete_policy_from_policies_page(self, app_fs):
         with allure.step('Check that policy has been deleted'):
             assert len(policies_page.table.get_all_rows()) == 0, "There should be 0 policies on the page"
 
+    @pytest.mark.usefixtures("login_to_adcm_over_api")
     @pytest.mark.parametrize(
         ("clusters", "services", "providers", "hosts", "parents", "role_name"),
         [
@@ -529,22 +543,22 @@ def test_delete_policy_from_policies_page(self, app_fs):
             (None, None, None, HOST_NAME, None, 'View provider configurations, View host configurations'),
         ],
     )
+    @pytest.mark.usefixtures('parents', 'create_cluster_with_component')
     def test_check_policy_popup_for_entities(
         self,
         sdk_client_fs,
         app_fs,
-        create_cluster_with_component,
         clusters,
         services,
         providers,
         hosts,
-        parents,
         role_name,
     ):
         """Test creating policy"""
 
-        self.custom_policy.role = self.custom_role_name
-        self.custom_policy.objects = clusters or services or providers or hosts
+        custom_policy = deepcopy(self.custom_policy)
+        custom_policy.role = self.custom_role_name
+        custom_policy.objects = clusters or services or providers or hosts
         with allure.step("Create test role"):
             sdk_client_fs.role_create(
                 name=self.custom_role_name,
@@ -553,14 +567,182 @@ def test_check_policy_popup_for_entities(
             )
         policies_page = AdminPoliciesPage(app_fs.driver, app_fs.adcm.url).open()
         policies_page.create_policy(
-            policy_name=self.custom_policy.name,
-            description=self.custom_policy.description,
-            role=self.custom_policy.role,
-            users=self.custom_policy.users,
+            policy_name=custom_policy.name,
+            description=custom_policy.description,
+            role=custom_policy.role,
+            users=custom_policy.users,
             clusters=clusters,
             services=services,
             parent=CLUSTER_NAME,
             providers=providers,
             hosts=hosts,
         )
-        self.check_custom_policy(policies_page)
+        self.check_custom_policy(policies_page, policy=custom_policy)
+
+    def test_policy_permission_to_view_access_cluster(
+        self, sdk_client_fs, app_fs, create_cluster_with_component, another_user
+    ):
+        """Test for the permissions to cluster."""
+
+        cluster, *_ = create_cluster_with_component
+        with allure.step("Create test role"):
+            test_role = sdk_client_fs.role_create(
+                name=self.custom_role_name,
+                display_name=self.custom_role_name,
+                child=[{"id": sdk_client_fs.role(name="View cluster configurations").id}],
+            )
+        with allure.step("Create test policy"):
+            sdk_client_fs.policy_create(
+                name="Test policy", role=test_role, user=[sdk_client_fs.user_list()[2]], objects=[cluster]
+            )
+        with allure.step("Create second cluster"):
+            second_cluster = sdk_client_fs.bundle().cluster_create(name=f"{CLUSTER_NAME}_2")
+        login_page = LoginPage(app_fs.driver, app_fs.adcm.url).open()
+        login_page.login_user(**another_user)
+        AdminIntroPage(app_fs.driver, app_fs.adcm.url).wait_page_is_opened()
+        with allure.step("Check that user can view first cluster config"):
+            cluster_config_page = ClusterConfigPage(app_fs.driver, app_fs.adcm.url, cluster.id).open()
+            cluster_config_page.config.check_config_fields_visibility({"str_param", "int", "param1", "param2"})
+        with allure.step("Check that user can not view second cluster config"):
+            second_cluster_config_page = ClusterConfigPage(app_fs.driver, app_fs.adcm.url, second_cluster.id).open()
+            second_cluster_config_page.config.check_no_rows_or_groups_on_page()
+            assert (
+                second_cluster_config_page.get_info_popup_text()
+                == "[ NOT FOUND ] CLUSTER_NOT_FOUND -- cluster doesn't exist"
+            ), "There are no error message"
+
+    def test_policy_permission_to_view_access_service(
+        self, sdk_client_fs, app_fs, create_cluster_with_component, another_user
+    ):
+        """Test for the permissions to service."""
+
+        cluster, service, host, provider = create_cluster_with_component
+        with allure.step("Create test role"):
+            test_role = sdk_client_fs.role_create(
+                name=self.custom_role_name,
+                display_name=self.custom_role_name,
+                child=[{"id": sdk_client_fs.role(name="View service configurations").id}],
+            )
+        with allure.step("Create test policy"):
+            sdk_client_fs.policy_create(
+                name="Test policy", role=test_role, user=[sdk_client_fs.user_list()[2]], objects=[service]
+            )
+        with allure.step("Create second service"):
+            second_service = cluster.service_add(name="test_service_2")
+        login_page = LoginPage(app_fs.driver, app_fs.adcm.url).open()
+        login_page.login_user(**another_user)
+        AdminIntroPage(app_fs.driver, app_fs.adcm.url).wait_page_is_opened()
+        with allure.step("Check that user can view first service config"):
+            service_config_page = ServiceConfigPage(
+                app_fs.driver, app_fs.adcm.url, cluster.id, service.service_id
+            ).open()
+            service_config_page.config.check_config_fields_visibility({"str_param", "int", "param1", "param2"})
+        with allure.step("Check that user can not view second service config"):
+            second_service_config_page = ServiceConfigPage(
+                app_fs.driver, app_fs.adcm.url, cluster.id, second_service.service_id
+            ).open()
+            second_service_config_page.config.check_no_rows_or_groups_on_page()
+            assert (
+                second_service_config_page.get_info_popup_text()
+                == "[ NOT FOUND ] CLUSTER_SERVICE_NOT_FOUND -- service is not installed in specified cluster"
+            ), "There are no error message"
+
+    def test_policy_permission_to_view_access_component(
+        self, sdk_client_fs, app_fs, create_cluster_with_component, another_user
+    ):
+        """Test for the permissions to component."""
+
+        cluster, service, host, provider = create_cluster_with_component
+        with allure.step("Create test role"):
+            test_role = sdk_client_fs.role_create(
+                name=self.custom_role_name,
+                display_name=self.custom_role_name,
+                child=[{"id": sdk_client_fs.role(name="View component configurations").id}],
+            )
+        with allure.step("Create test policy"):
+            sdk_client_fs.policy_create(
+                name="Test policy", role=test_role, user=[sdk_client_fs.user_list()[2]], objects=[service]
+            )
+        with allure.step("Create second component"):
+            second_service = cluster.service_add(name="test_service_2")
+            cluster.hostcomponent_set(
+                (host, service.component(name=FIRST_COMPONENT_NAME)), (host, second_service.component(name="second"))
+            )
+        login_page = LoginPage(app_fs.driver, app_fs.adcm.url).open()
+        login_page.login_user(**another_user)
+        AdminIntroPage(app_fs.driver, app_fs.adcm.url).wait_page_is_opened()
+        with allure.step("Check that user can view first component config"):
+            component_config_page = ComponentConfigPage(
+                app_fs.driver, app_fs.adcm.url, cluster.id, service.service_id, 1
+            ).open()
+            component_config_page.config.check_config_fields_visibility({"str_param"})
+        with allure.step("Check that user can not view second component config"):
+            second_component_config_page = ComponentConfigPage(
+                app_fs.driver, app_fs.adcm.url, cluster.id, second_service.service_id, 2
+            ).open()
+            second_component_config_page.config.check_no_rows_or_groups_on_page()
+            assert (
+                second_component_config_page.get_info_popup_text()
+                == "[ NOT FOUND ] COMPONENT_NOT_FOUND -- component doesn't exist"
+            ), "There are no error message"
+
+    def test_policy_permission_to_view_access_provider(self, sdk_client_fs, app_fs, another_user):
+        """Test for the permissions to provider."""
+
+        provider_bundle = sdk_client_fs.upload_from_fs(os.path.join(utils.get_data_dir(__file__), 'provider'))
+        provider = provider_bundle.provider_create('test_provider')
+        with allure.step("Create test role"):
+            test_role = sdk_client_fs.role_create(
+                name=self.custom_role_name,
+                display_name=self.custom_role_name,
+                child=[{"id": sdk_client_fs.role(name="View provider configurations").id}],
+            )
+        with allure.step("Create test policy"):
+            sdk_client_fs.policy_create(
+                name="Test policy", role=test_role, user=[sdk_client_fs.user_list()[2]], objects=[provider]
+            )
+        with allure.step("Create second provider"):
+            provider_bundle = sdk_client_fs.upload_from_fs(
+                os.path.join(utils.get_data_dir(__file__), 'second_provider')
+            )
+            second_provider = provider_bundle.provider_create('second_test_provider')
+        login_page = LoginPage(app_fs.driver, app_fs.adcm.url).open()
+        login_page.login_user(**another_user)
+        AdminIntroPage(app_fs.driver, app_fs.adcm.url).wait_page_is_opened()
+        with allure.step("Check that user can view first provider config"):
+            provider_config_page = ProviderConfigPage(app_fs.driver, app_fs.adcm.url, provider.id).open()
+            provider_config_page.config.check_config_fields_visibility({"str_param"})
+        with allure.step("Check that user can not view second provider config"):
+            second_provider_config_page = ProviderConfigPage(app_fs.driver, app_fs.adcm.url, second_provider.id).open()
+            second_provider_config_page.config.check_no_rows_or_groups_on_page()
+
+    def test_policy_permission_to_view_access_host(self, sdk_client_fs, app_fs, another_user):
+        """Test for the permissions to host."""
+
+        provider_bundle = sdk_client_fs.upload_from_fs(os.path.join(utils.get_data_dir(__file__), 'provider'))
+        provider = provider_bundle.provider_create('test_provider')
+        host = provider.host_create('test-host')
+        with allure.step("Create test role"):
+            test_role = sdk_client_fs.role_create(
+                name=self.custom_role_name,
+                display_name=self.custom_role_name,
+                child=[{"id": sdk_client_fs.role(name="View host configurations").id}],
+            )
+        with allure.step("Create test policy"):
+            sdk_client_fs.policy_create(
+                name="Test policy", role=test_role, user=[sdk_client_fs.user_list()[2]], objects=[host]
+            )
+        with allure.step("Create second host"):
+            second_host = provider.host_create('test-host-2')
+        login_page = LoginPage(app_fs.driver, app_fs.adcm.url).open()
+        login_page.login_user(**another_user)
+        AdminIntroPage(app_fs.driver, app_fs.adcm.url).wait_page_is_opened()
+        with allure.step("Check that user can view first host config"):
+            host_config_page = HostConfigPage(app_fs.driver, app_fs.adcm.url, host.id).open()
+            host_config_page.config.check_config_fields_visibility({"str_param"})
+        with allure.step("Check that user can not view second host config"):
+            second_host_config_page = HostConfigPage(app_fs.driver, app_fs.adcm.url, second_host.id).open()
+            second_host_config_page.config.check_no_rows_or_groups_on_page()
+            assert (
+                second_host_config_page.get_info_popup_text() == "[ NOT FOUND ] HOST_NOT_FOUND -- host doesn't exist"
+            ), "There are no error message"
diff --git a/tests/ui_tests/test_admin_page_data/cluster_with_services/config.yaml b/tests/ui_tests/test_admin_page_data/cluster_with_services/config.yaml
index 05dc96b152..ff02080c03 100644
--- a/tests/ui_tests/test_admin_page_data/cluster_with_services/config.yaml
+++ b/tests/ui_tests/test_admin_page_data/cluster_with_services/config.yaml
@@ -14,6 +14,25 @@
   name: test_cluster
   version: 1.5
   edition: community
+  config: &config
+    str_param:
+      type: string
+      required: false
+      default: '123'
+      description: must be changed to bar()
+    int:
+      type: integer
+      required: false
+      default: 2
+      description: must be changed to 5
+    core-site:
+      param1:
+          type: string
+          required: false
+      param2:
+          type: integer
+          required: false
+
 
 - type: service
   name: test_service_1
@@ -27,15 +46,17 @@
           type: string
           required: false
           default: '123'
+  config: *config
 
 - type: service
   name: test_service_2
   description: Test service 2
   version: '1.2'
   components:
-    first:
+    second:
       config:
         str_param:
           type: string
           required: false
           default: '123'
+  config: *config
diff --git a/tests/ui_tests/test_admin_page_data/provider/config.yaml b/tests/ui_tests/test_admin_page_data/provider/config.yaml
index e919ab2fc9..ada251a49d 100644
--- a/tests/ui_tests/test_admin_page_data/provider/config.yaml
+++ b/tests/ui_tests/test_admin_page_data/provider/config.yaml
@@ -14,9 +14,18 @@
 - type: provider
   name: test_provider
   version: &ver "2.15-dev"
+  config:
+    str_param:
+      type: string
+      required: false
+      default: '123'
 
 - type: host
   name: "Test Host"
   description: "Test Host Description"
   version: *ver
-
+  config:
+    str_param:
+      type: string
+      required: false
+      default: '123'
diff --git a/tests/ui_tests/test_admin_page_data/second_provider/config.yaml b/tests/ui_tests/test_admin_page_data/second_provider/config.yaml
new file mode 100644
index 0000000000..03c4b56c97
--- /dev/null
+++ b/tests/ui_tests/test_admin_page_data/second_provider/config.yaml
@@ -0,0 +1,31 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+---
+- type: provider
+  name: second_provider
+  version: &ver "2.15-dev"
+  config:
+    str_param:
+      type: string
+      required: false
+      default: '123'
+
+- type: host
+  name: "Test Host"
+  description: "Test Host Description"
+  version: *ver
+  config:
+    str_param:
+      type: string
+      required: false
+      default: '123'