diff --git a/apps/perms/api/application/user_permission/common.py b/apps/perms/api/application/user_permission/common.py index 4e7d0b5f2..2a64d122d 100644 --- a/apps/perms/api/application/user_permission/common.py +++ b/apps/perms/api/application/user_permission/common.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- # -import uuid +import time + from django.shortcuts import get_object_or_404 from django.utils.decorators import method_decorator from rest_framework.views import APIView, Response +from rest_framework import status from rest_framework.generics import ( ListAPIView, get_object_or_404 ) @@ -12,7 +14,8 @@ from orgs.utils import tmp_to_root_org from applications.models import Application from perms.utils.application.permission import ( has_application_system_permission, - get_application_system_user_ids + get_application_system_user_ids, + validate_permission, ) from perms.api.asset.user_permission.mixin import RoleAdminMixin, RoleUserMixin from common.permissions import IsOrgAdminOrAppUser @@ -61,18 +64,13 @@ class ValidateUserApplicationPermissionApi(APIView): application_id = request.query_params.get('application_id', '') system_user_id = request.query_params.get('system_user_id', '') - try: - user_id = uuid.UUID(user_id) - application_id = uuid.UUID(application_id) - system_user_id = uuid.UUID(system_user_id) - except ValueError: - return Response({'msg': False}, status=403) + if not all((user_id, application_id, system_user_id)): + return Response({'has_permission': False, 'expire_at': int(time.time())}) - user = get_object_or_404(User, id=user_id) - application = get_object_or_404(Application, id=application_id) - system_user = get_object_or_404(SystemUser, id=system_user_id) + user = User.objects.get(id=user_id) + application = Application.objects.get(id=application_id) + system_user = SystemUser.objects.get(id=system_user_id) - if has_application_system_permission(user, application, system_user): - return Response({'msg': True}, status=200) - - return Response({'msg': False}, status=403) + has_permission, expire_at = validate_permission(user, application, system_user) + status_code = status.HTTP_200_OK if has_permission else status.HTTP_403_FORBIDDEN + return Response({'has_permission': has_permission, 'expire_at': int(expire_at)}, status=status_code) diff --git a/apps/perms/api/asset/user_permission/common.py b/apps/perms/api/asset/user_permission/common.py index 88b5422d9..1d09274c8 100644 --- a/apps/perms/api/asset/user_permission/common.py +++ b/apps/perms/api/asset/user_permission/common.py @@ -1,22 +1,23 @@ # -*- coding: utf-8 -*- # import uuid +import time from django.shortcuts import get_object_or_404 from django.utils.decorators import method_decorator from rest_framework.views import APIView, Response +from rest_framework import status from rest_framework.generics import ( ListAPIView, get_object_or_404, RetrieveAPIView, DestroyAPIView ) from orgs.utils import tmp_to_root_org -from perms.utils.asset.permission import get_asset_system_user_ids_with_actions_by_user +from perms.utils.asset.permission import get_asset_system_user_ids_with_actions_by_user, validate_permission from common.permissions import IsOrgAdminOrAppUser, IsOrgAdmin, IsValidUser from common.utils import get_logger, lazyproperty from perms.hands import User, Asset, SystemUser from perms import serializers -from perms.models import Action logger = get_logger(__name__) @@ -65,32 +66,22 @@ class ValidateUserAssetPermissionApi(APIView): def get_cache_policy(self): return 0 - def get_user(self): - user_id = self.request.query_params.get('user_id', '') - user = get_object_or_404(User, id=user_id) - return user - def get(self, request, *args, **kwargs): + user_id = self.request.query_params.get('user_id', '') asset_id = request.query_params.get('asset_id', '') system_id = request.query_params.get('system_user_id', '') action_name = request.query_params.get('action_name', '') - try: - asset_id = uuid.UUID(asset_id) - system_id = uuid.UUID(system_id) - except ValueError: - return Response({'msg': False}, status=403) + if not all((user_id, asset_id, system_id, action_name)): + return Response({'has_permission': False, 'expire_at': int(time.time())}) - asset = get_object_or_404(Asset, id=asset_id, is_active=True) - system_user = get_object_or_404(SystemUser, id=system_id) + user = User.objects.get(id=user_id) + asset = Asset.objects.valid().get(id=asset_id) + system_user = SystemUser.objects.get(id=system_id) - system_users_actions = get_asset_system_user_ids_with_actions_by_user(self.get_user(), asset) - actions = system_users_actions.get(system_user.id) - if actions is None: - return Response({'msg': False}, status=403) - if action_name in Action.value_to_choices(actions): - return Response({'msg': True}, status=200) - return Response({'msg': False}, status=403) + has_permission, expire_at = validate_permission(user, asset, system_user, action_name) + status_code = status.HTTP_200_OK if has_permission else status.HTTP_403_FORBIDDEN + return Response({'has_permission': has_permission, 'expire_at': int(expire_at)}, status=status_code) # TODO 删除 diff --git a/apps/perms/utils/application/permission.py b/apps/perms/utils/application/permission.py index 4e4c8113d..c4ebb5bdb 100644 --- a/apps/perms/utils/application/permission.py +++ b/apps/perms/utils/application/permission.py @@ -1,3 +1,5 @@ +import time + from django.db.models import Q from common.utils import get_logger @@ -6,6 +8,58 @@ from perms.models import ApplicationPermission logger = get_logger(__file__) +def get_user_all_app_perm_ids(user) -> set: + app_perm_ids = set() + user_perm_id = ApplicationPermission.users.through.objects \ + .filter(user_id=user.id) \ + .values_list('applicationpermission_id', flat=True) \ + .distinct() + app_perm_ids.update(user_perm_id) + + group_ids = user.groups.through.objects \ + .filter(user_id=user.id) \ + .values_list('usergroup_id', flat=True) \ + .distinct() + group_ids = list(group_ids) + groups_perm_id = ApplicationPermission.user_groups.through.objects \ + .filter(usergroup_id__in=group_ids) \ + .values_list('applicationpermission_id', flat=True) \ + .distinct() + app_perm_ids.update(groups_perm_id) + + app_perm_ids = ApplicationPermission.objects.filter( + id__in=app_perm_ids).valid().values_list('id', flat=True) + app_perm_ids = set(app_perm_ids) + return app_perm_ids + + +def validate_permission(user, application, system_user): + app_perm_ids = get_user_all_app_perm_ids(user) + app_perm_ids = ApplicationPermission.applications.through.objects.filter( + applicationpermission_id__in=app_perm_ids, + application_id=application.id + ).values_list('applicationpermission_id', flat=True) + + app_perm_ids = set(app_perm_ids) + + app_perm_ids = ApplicationPermission.system_users.through.objects.filter( + applicationpermission_id__in=app_perm_ids, + systemuser_id=system_user.id + ).values_list('applicationpermission_id', flat=True) + + app_perm_ids = set(app_perm_ids) + + app_perm = ApplicationPermission.objects.filter( + id__in=app_perm_ids + ).order_by('-date_expired').first() + + app_perm: ApplicationPermission + if app_perm: + return True, app_perm.date_expired.timestamp() + else: + return False, time.time() + + def get_application_system_user_ids(user, application): queryset = ApplicationPermission.objects.valid()\ .filter( diff --git a/apps/perms/utils/asset/permission.py b/apps/perms/utils/asset/permission.py index 197abc9d9..949ee6873 100644 --- a/apps/perms/utils/asset/permission.py +++ b/apps/perms/utils/asset/permission.py @@ -1,15 +1,61 @@ +import time from collections import defaultdict from django.db.models import Q from common.utils import get_logger -from perms.models import AssetPermission -from perms.hands import Asset, User, UserGroup, SystemUser +from perms.models import AssetPermission, Action +from perms.hands import Asset, User, UserGroup, SystemUser, Node from perms.utils.asset.user_permission import get_user_all_asset_perm_ids logger = get_logger(__file__) +def validate_permission(user, asset, system_user, action_name): + + if not system_user.protocol in asset.protocols_as_dict.keys(): + return False, time.time() + + asset_perm_ids = get_user_all_asset_perm_ids(user) + + asset_perm_ids_from_asset = AssetPermission.assets.through.objects.filter( + assetpermission_id__in=asset_perm_ids, + asset_id=asset.id + ).values_list('assetpermission_id', flat=True) + + nodes = asset.get_nodes() + node_keys = set() + for node in nodes: + ancestor_keys = node.get_ancestor_keys(with_self=True) + node_keys.update(ancestor_keys) + node_ids = Node.objects.filter(key__in=node_keys).values_list('id', flat=True) + + node_ids = set(node_ids) + + asset_perm_ids_from_node = AssetPermission.nodes.through.objects.filter( + assetpermission_id__in=asset_perm_ids, + node_id__in=node_ids + ).values_list('assetpermission_id', flat=True) + + asset_perm_ids = {*asset_perm_ids_from_asset, *asset_perm_ids_from_node} + + asset_perm_ids = AssetPermission.system_users.through.objects.filter( + assetpermission_id__in=asset_perm_ids, + systemuser_id=system_user.id + ).values_list('assetpermission_id', flat=True) + + asset_perm_ids = set(asset_perm_ids) + + asset_perms = AssetPermission.objects.filter( + id__in=asset_perm_ids + ).order_by('-date_expired') + + for asset_perm in asset_perms: + if action_name in Action.value_to_choices(asset_perm.actions): + return True, asset_perm.date_expired.timestamp() + return False, time.time() + + def get_asset_system_user_ids_with_actions(asset_perm_ids, asset: Asset): nodes = asset.get_nodes() node_keys = set()