From bdcf9ba15332f0954fbe176fe88207e56ed4ceba Mon Sep 17 00:00:00 2001 From: BaiJiangJie <32935519+BaiJiangJie@users.noreply.github.com> Date: Thu, 12 Sep 2019 18:25:22 +0800 Subject: [PATCH] Dev remoteapp (#3205) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Update] 修改RemoteApp关联的系统用户:从RemoteApp中转移到RemoteAppPermission中(未提交迁移文件) * [Update] 修改RemoteApp关联的系统用户:提交迁移文件 * [Update] 修改RemoteApp关联的系统用户:修改迁移文件 * [Update] 修改迁移文件1 * [Update] 修改迁移文件2 * [Update] 修改迁移文件3 * [Update] 修改RemoteAppPermsUtil获取系统用户的逻辑 --- apps/applications/forms/remote_app.py | 9 +-- .../0002_remove_remoteapp_system_user.py | 18 +++++ apps/applications/models/remote_app.py | 11 --- apps/applications/serializers/remote_app.py | 8 +- .../remote_app_create_update.html | 1 - .../applications/remote_app_detail.html | 4 - .../applications/remote_app_list.html | 11 +-- .../applications/user_remote_app_list.html | 8 +- apps/applications/urls/api_urls.py | 4 +- apps/perms/api/mixin.py | 41 +++++++++- apps/perms/api/user_permission.py | 30 +------ apps/perms/api/user_remote_app_permission.py | 35 +++++++- apps/perms/forms/remote_app_permission.py | 3 + .../0008_remoteapppermission_system_users.py | 32 ++++++++ apps/perms/models/remote_app_permission.py | 1 + .../serializers/remote_app_permission.py | 4 +- apps/perms/serializers/user_permission.py | 14 +++- .../remote_app_permission_create_update.html | 3 +- .../perms/remote_app_permission_detail.html | 80 ++++++++++++++++++- apps/perms/urls/api_urls.py | 4 + apps/perms/utils/remote_app_permission.py | 12 ++- apps/perms/views/remote_app_permission.py | 5 +- 22 files changed, 250 insertions(+), 88 deletions(-) create mode 100644 apps/applications/migrations/0002_remove_remoteapp_system_user.py create mode 100644 apps/perms/migrations/0008_remoteapppermission_system_users.py diff --git a/apps/applications/forms/remote_app.py b/apps/applications/forms/remote_app.py index 81fc20b2b..b12759462 100644 --- a/apps/applications/forms/remote_app.py +++ b/apps/applications/forms/remote_app.py @@ -89,23 +89,16 @@ class RemoteAppCreateUpdateForm(RemoteAppTypeForms, OrgModelForm): super().__init__(*args, **kwargs) field_asset = self.fields['asset'] field_asset.queryset = field_asset.queryset.has_protocol('rdp') - field_system_user = self.fields['system_user'] - field_system_user.queryset = field_system_user.queryset.filter( - protocol=SystemUser.PROTOCOL_RDP - ) class Meta: model = RemoteApp fields = [ - 'name', 'asset', 'system_user', 'type', 'path', 'comment' + 'name', 'asset', 'type', 'path', 'comment' ] widgets = { 'asset': forms.Select(attrs={ 'class': 'select2', 'data-placeholder': _('Asset') }), - 'system_user': forms.Select(attrs={ - 'class': 'select2', 'data-placeholder': _('System user') - }) } def _clean_params(self): diff --git a/apps/applications/migrations/0002_remove_remoteapp_system_user.py b/apps/applications/migrations/0002_remove_remoteapp_system_user.py new file mode 100644 index 000000000..31d497f57 --- /dev/null +++ b/apps/applications/migrations/0002_remove_remoteapp_system_user.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.7 on 2019-09-09 09:57 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('applications', '0001_initial'), + ('perms', '0008_remoteapppermission_system_users'), + ] + + operations = [ + migrations.RemoveField( + model_name='remoteapp', + name='system_user', + ), + ] diff --git a/apps/applications/models/remote_app.py b/apps/applications/models/remote_app.py index 636eb1f66..17746833c 100644 --- a/apps/applications/models/remote_app.py +++ b/apps/applications/models/remote_app.py @@ -22,10 +22,6 @@ class RemoteApp(OrgModelMixin): asset = models.ForeignKey( 'assets.Asset', on_delete=models.CASCADE, verbose_name=_('Asset') ) - system_user = models.ForeignKey( - 'assets.SystemUser', on_delete=models.CASCADE, - verbose_name=_('System user') - ) type = models.CharField( default=const.REMOTE_APP_TYPE_CHROME, choices=const.REMOTE_APP_TYPE_CHOICES, @@ -80,10 +76,3 @@ class RemoteApp(OrgModelMixin): 'id': self.asset.id, 'hostname': self.asset.hostname } - - @property - def system_user_info(self): - return { - 'id': self.system_user.id, - 'name': self.system_user.name - } diff --git a/apps/applications/serializers/remote_app.py b/apps/applications/serializers/remote_app.py index 80faff539..168a02280 100644 --- a/apps/applications/serializers/remote_app.py +++ b/apps/applications/serializers/remote_app.py @@ -73,13 +73,13 @@ class RemoteAppSerializer(BulkOrgResourceModelSerializer): model = RemoteApp list_serializer_class = AdaptedBulkListSerializer fields = [ - 'id', 'name', 'asset', 'system_user', 'type', 'path', 'params', + 'id', 'name', 'asset', 'type', 'path', 'params', 'comment', 'created_by', 'date_created', 'asset_info', - 'system_user_info', 'get_type_display', + 'get_type_display', ] read_only_fields = [ 'created_by', 'date_created', 'asset_info', - 'system_user_info', 'get_type_display' + 'get_type_display' ] @@ -89,7 +89,7 @@ class RemoteAppConnectionInfoSerializer(serializers.ModelSerializer): class Meta: model = RemoteApp fields = [ - 'id', 'name', 'asset', 'system_user', 'parameter_remote_app', + 'id', 'name', 'asset', 'parameter_remote_app', ] read_only_fields = ['parameter_remote_app'] diff --git a/apps/applications/templates/applications/remote_app_create_update.html b/apps/applications/templates/applications/remote_app_create_update.html index 246479fb3..b193dfff5 100644 --- a/apps/applications/templates/applications/remote_app_create_update.html +++ b/apps/applications/templates/applications/remote_app_create_update.html @@ -13,7 +13,6 @@ {% csrf_token %} {% bootstrap_field form.name layout="horizontal" %} {% bootstrap_field form.asset layout="horizontal" %} - {% bootstrap_field form.system_user layout="horizontal" %} {% bootstrap_field form.type layout="horizontal" %} {% bootstrap_field form.path layout="horizontal" %} diff --git a/apps/applications/templates/applications/remote_app_detail.html b/apps/applications/templates/applications/remote_app_detail.html index d006bb51a..19105da89 100644 --- a/apps/applications/templates/applications/remote_app_detail.html +++ b/apps/applications/templates/applications/remote_app_detail.html @@ -57,10 +57,6 @@ {% trans 'Asset' %}: {{ remote_app.asset.hostname }} - - {% trans 'System user' %}: - {{ remote_app.system_user.name }} - {% trans 'App type' %}: {{ remote_app.get_type_display }} diff --git a/apps/applications/templates/applications/remote_app_list.html b/apps/applications/templates/applications/remote_app_list.html index 54f1806e9..3dbe4f8eb 100644 --- a/apps/applications/templates/applications/remote_app_list.html +++ b/apps/applications/templates/applications/remote_app_list.html @@ -20,7 +20,6 @@ {% trans 'Name' %} {% trans 'App type' %} {% trans 'Asset' %} - {% trans 'System user' %} {% trans 'Comment' %} {% trans 'Action' %} @@ -47,12 +46,11 @@ function initTable() { var detail_btn = '' + hostname + ''; $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', cellData.id)); }}, - {targets: 4, createdCell: function (td, cellData, rowData) { - var name = htmlEscape(cellData.name); - var detail_btn = '' + name + ''; - $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', cellData.id)); + {targets: 3, createdCell: function (td, cellData, rowData) { + var comment = htmlEscape(cellData); + $(td).html(comment) }}, - {targets: 6, createdCell: function (td, cellData, rowData) { + {targets: 5, createdCell: function (td, cellData, rowData) { var update_btn = '{% trans "Update" %}'.replace("{{ DEFAULT_PK }}", cellData); var del_btn = '{% trans "Delete" %}'.replace('{{ DEFAULT_PK }}', cellData); $(td).html(update_btn + del_btn) @@ -64,7 +62,6 @@ function initTable() { {data: "name" }, {data: "get_type_display", orderable: false}, {data: "asset_info", orderable: false}, - {data: "system_user_info", orderable: false}, {data: "comment"}, {data: "id", orderable: false} ], diff --git a/apps/applications/templates/applications/user_remote_app_list.html b/apps/applications/templates/applications/user_remote_app_list.html index 4199e805f..3559232ef 100644 --- a/apps/applications/templates/applications/user_remote_app_list.html +++ b/apps/applications/templates/applications/user_remote_app_list.html @@ -16,7 +16,6 @@ {% trans 'Name' %} {% trans 'App type' %} {% trans 'Asset' %} - {% trans 'System user' %} {% trans 'Comment' %} {% trans 'Action' %} @@ -49,11 +48,7 @@ function initTable() { var hostname = htmlEscape(cellData.hostname); $(td).html(hostname); }}, - {targets: 4, createdCell: function (td, cellData, rowData) { - var name = htmlEscape(cellData.name); - $(td).html(name); - }}, - {targets: 6, createdCell: function (td, cellData, rowData) { + {targets: 5, createdCell: function (td, cellData, rowData) { var conn_btn = '{% trans "Connect" %}'.replace("{{ DEFAULT_PK }}", cellData); $(td).html(conn_btn) }} @@ -64,7 +59,6 @@ function initTable() { {data: "name"}, {data: "get_type_display", orderable: false}, {data: "asset_info", orderable: false}, - {data: "system_user_info", orderable: false}, {data: "comment", orderable: false}, {data: "id", orderable: false} ] diff --git a/apps/applications/urls/api_urls.py b/apps/applications/urls/api_urls.py index 137cea733..6384f5dac 100644 --- a/apps/applications/urls/api_urls.py +++ b/apps/applications/urls/api_urls.py @@ -13,9 +13,7 @@ router = BulkRouter() router.register(r'remote-apps', api.RemoteAppViewSet, 'remote-app') urlpatterns = [ - path('remote-apps//connection-info/', - api.RemoteAppConnectionInfoApi.as_view(), - name='remote-app-connection-info') + path('remote-apps//connection-info/', api.RemoteAppConnectionInfoApi.as_view(), name='remote-app-connection-info'), ] old_version_urlpatterns = [ re_path('(?Premote-app)/.*', capi.redirect_plural_name_api) diff --git a/apps/perms/api/mixin.py b/apps/perms/api/mixin.py index 2227857ca..e2cdb139b 100644 --- a/apps/perms/api/mixin.py +++ b/apps/perms/api/mixin.py @@ -9,16 +9,49 @@ from rest_framework.views import Response from django.utils.decorators import method_decorator from django.views.decorators.http import condition +from rest_framework.generics import get_object_or_404 from django.utils.translation import ugettext as _ -from common.utils import get_logger from assets.utils import LabelFilterMixin -from .. import const -from ..hands import Asset, Node, SystemUser +from common.permissions import IsValidUser, IsOrgAdminOrAppUser, IsOrgAdmin +from common.utils import get_logger +from orgs.utils import set_to_root_org +from ..hands import User, Asset, Node, SystemUser from .. import serializers +from .. import const + logger = get_logger(__name__) -__all__ = ['UserPermissionCacheMixin', 'GrantAssetsMixin', 'NodesWithUngroupMixin'] +__all__ = [ + 'UserPermissionCacheMixin', 'GrantAssetsMixin', 'NodesWithUngroupMixin', + 'UserPermissionMixin', +] + + +class UserPermissionMixin: + permission_classes = (IsOrgAdminOrAppUser,) + obj = None + + def initial(self, *args, **kwargs): + super().initial(*args, *kwargs) + self.obj = self.get_obj() + + def get(self, request, *args, **kwargs): + set_to_root_org() + return super().get(request, *args, **kwargs) + + def get_obj(self): + user_id = self.kwargs.get('pk', '') + if user_id: + user = get_object_or_404(User, id=user_id) + else: + user = self.request.user + return user + + def get_permissions(self): + if self.kwargs.get('pk') is None: + self.permission_classes = (IsValidUser,) + return super().get_permissions() # def get_etag(request, *args, **kwargs): diff --git a/apps/perms/api/user_permission.py b/apps/perms/api/user_permission.py index 7c7e513cf..0754e52c8 100644 --- a/apps/perms/api/user_permission.py +++ b/apps/perms/api/user_permission.py @@ -8,16 +8,16 @@ from rest_framework.generics import ( ListAPIView, get_object_or_404, RetrieveAPIView ) -from common.permissions import IsValidUser, IsOrgAdminOrAppUser, IsOrgAdmin +from common.permissions import IsOrgAdminOrAppUser, IsOrgAdmin from common.tree import TreeNodeSerializer from common.utils import get_logger -from orgs.utils import set_to_root_org from ..utils import ( ParserNode, AssetPermissionUtilV2 ) from ..hands import User, Asset, Node, SystemUser, NodeSerializer from .. import serializers from ..models import Action +from .mixin import UserPermissionMixin logger = get_logger(__name__) @@ -39,32 +39,6 @@ __all__ = [ ] -class UserPermissionMixin: - permission_classes = (IsOrgAdminOrAppUser,) - obj = None - - def initial(self, *args, **kwargs): - super().initial(*args, *kwargs) - self.obj = self.get_obj() - - def get(self, request, *args, **kwargs): - set_to_root_org() - return super().get(request, *args, **kwargs) - - def get_obj(self): - user_id = self.kwargs.get('pk', '') - if user_id: - user = get_object_or_404(User, id=user_id) - else: - user = self.request.user - return user - - def get_permissions(self): - if self.kwargs.get('pk') is None: - self.permission_classes = (IsValidUser,) - return super().get_permissions() - - class UserAssetPermissionMixin(UserPermissionMixin): util = None diff --git a/apps/perms/api/user_remote_app_permission.py b/apps/perms/api/user_remote_app_permission.py index e650022f6..84518c875 100644 --- a/apps/perms/api/user_remote_app_permission.py +++ b/apps/perms/api/user_remote_app_permission.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +import uuid from django.shortcuts import get_object_or_404 from rest_framework.views import APIView, Response from rest_framework.generics import ( @@ -12,13 +13,16 @@ from ..utils import ( RemoteAppPermissionUtil, construct_remote_apps_tree_root, parse_remote_app_to_tree_node, ) -from ..hands import User, RemoteAppSerializer, UserGroup +from ..hands import User, RemoteApp, RemoteAppSerializer, UserGroup, SystemUser from ..mixins import RemoteAppFilterMixin +from .mixin import UserPermissionMixin +from .. import serializers __all__ = [ 'UserGrantedRemoteAppsApi', 'ValidateUserRemoteAppPermissionApi', 'UserGrantedRemoteAppsAsTreeApi', 'UserGroupGrantedRemoteAppsApi', + 'UserGrantedRemoteAppSystemUsersApi', ] @@ -65,18 +69,43 @@ class UserGrantedRemoteAppsAsTreeApi(UserGrantedRemoteAppsApi): return super().get_serializer(data, many=True) +class UserGrantedRemoteAppSystemUsersApi(UserPermissionMixin, ListAPIView): + permission_classes = (IsOrgAdminOrAppUser,) + serializer_class = serializers.RemoteAppSystemUserSerializer + only_fields = serializers.RemoteAppSystemUserSerializer.Meta.only_fields + + def get_queryset(self): + util = RemoteAppPermissionUtil(self.obj) + remote_app_id = self.kwargs.get('remote_app_id') + remote_app = get_object_or_404(RemoteApp, id=remote_app_id) + system_users = util.get_remote_app_system_users(remote_app) + return system_users + + class ValidateUserRemoteAppPermissionApi(APIView): permission_classes = (IsOrgAdminOrAppUser,) def get(self, request, *args, **kwargs): user_id = request.query_params.get('user_id', '') remote_app_id = request.query_params.get('remote_app_id', '') + system_id = request.query_params.get('system_user_id', '') + + try: + user_id = uuid.UUID(user_id) + remote_app_id = uuid.UUID(remote_app_id) + system_id = uuid.UUID(system_id) + except ValueError: + return Response({'msg': False}, status=403) user = get_object_or_404(User, id=user_id) + remote_app = get_object_or_404(RemoteApp, id=remote_app_id) + system_user = get_object_or_404(SystemUser, id=system_id) + util = RemoteAppPermissionUtil(user) - remote_app = util.get_remote_apps().filter(id=remote_app_id).exists() - if remote_app: + system_users = util.get_remote_app_system_users(remote_app) + if system_user in system_users: return Response({'msg': True}, status=200) + return Response({'msg': False}, status=403) diff --git a/apps/perms/forms/remote_app_permission.py b/apps/perms/forms/remote_app_permission.py index 57fc3507a..d08066ba4 100644 --- a/apps/perms/forms/remote_app_permission.py +++ b/apps/perms/forms/remote_app_permission.py @@ -35,6 +35,9 @@ class RemoteAppPermissionCreateUpdateForm(OrgModelForm): ), 'remote_apps': forms.SelectMultiple( attrs={'class': 'select2', 'data-placeholder': _('RemoteApp')} + ), + 'system_users': forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('System user')} ) } diff --git a/apps/perms/migrations/0008_remoteapppermission_system_users.py b/apps/perms/migrations/0008_remoteapppermission_system_users.py new file mode 100644 index 000000000..26246929b --- /dev/null +++ b/apps/perms/migrations/0008_remoteapppermission_system_users.py @@ -0,0 +1,32 @@ +# Generated by Django 2.1.7 on 2019-09-09 09:09 + +from django.db import migrations, models +from assets.models import SystemUser + + +def migrate_system_user_from_remote_app_to_remote_app_perms(apps, schema_editor): + remote_app_perms_model = apps.get_model("perms", "RemoteAppPermission") + db_alias = schema_editor.connection.alias + perms = remote_app_perms_model.objects.using(db_alias).all() + for perm in perms: + system_users_ids = perm.remote_apps.values_list('system_user', flat=True) + perm.system_users.set(system_users_ids) + + +class Migration(migrations.Migration): + + dependencies = [ + ('assets', '0037_auto_20190724_2002'), + ('perms', '0007_remove_assetpermission_actions'), + ] + + operations = [ + migrations.AddField( + model_name='remoteapppermission', + name='system_users', + field=models.ManyToManyField(related_name='granted_by_remote_app_permissions', to='assets.SystemUser', verbose_name='System user'), + ), + migrations.RunPython( + code=migrate_system_user_from_remote_app_to_remote_app_perms, + ), + ] diff --git a/apps/perms/models/remote_app_permission.py b/apps/perms/models/remote_app_permission.py index 706467396..57a806b80 100644 --- a/apps/perms/models/remote_app_permission.py +++ b/apps/perms/models/remote_app_permission.py @@ -13,6 +13,7 @@ __all__ = [ class RemoteAppPermission(BasePermission): remote_apps = models.ManyToManyField('applications.RemoteApp', related_name='granted_by_permissions', blank=True, verbose_name=_("RemoteApp")) + system_users = models.ManyToManyField('assets.SystemUser', related_name='granted_by_remote_app_permissions', verbose_name=_("System user")) class Meta: unique_together = [('org_id', 'name')] diff --git a/apps/perms/serializers/remote_app_permission.py b/apps/perms/serializers/remote_app_permission.py index 48a1fce0a..4361cff88 100644 --- a/apps/perms/serializers/remote_app_permission.py +++ b/apps/perms/serializers/remote_app_permission.py @@ -20,8 +20,8 @@ class RemoteAppPermissionSerializer(BulkOrgResourceModelSerializer): model = RemoteAppPermission list_serializer_class = AdaptedBulkListSerializer fields = [ - 'id', 'name', 'users', 'user_groups', 'remote_apps', 'comment', - 'is_active', 'date_start', 'date_expired', 'is_valid', + 'id', 'name', 'users', 'user_groups', 'remote_apps', 'system_users', + 'comment', 'is_active', 'date_start', 'date_expired', 'is_valid', 'created_by', 'date_created', ] read_only_fields = ['created_by', 'date_created'] diff --git a/apps/perms/serializers/user_permission.py b/apps/perms/serializers/user_permission.py index 149b618eb..d83c15b6f 100644 --- a/apps/perms/serializers/user_permission.py +++ b/apps/perms/serializers/user_permission.py @@ -12,6 +12,7 @@ __all__ = [ 'NodeGrantedSerializer', 'AssetGrantedSerializer', 'ActionsSerializer', 'AssetSystemUserSerializer', + 'RemoteAppSystemUserSerializer', ] @@ -24,13 +25,22 @@ class AssetSystemUserSerializer(serializers.ModelSerializer): class Meta: model = SystemUser only_fields = ( - 'id', 'name', 'username', 'priority', - 'protocol', 'login_mode', + 'id', 'name', 'username', 'priority', 'protocol', 'login_mode', ) fields = list(only_fields) + ["actions"] read_only_fields = fields +class RemoteAppSystemUserSerializer(serializers.ModelSerializer): + class Meta: + model = SystemUser + only_fields = ( + 'id', 'name', 'username', 'priority', 'protocol', 'login_mode', + ) + fields = list(only_fields) + read_only_fields = fields + + class AssetGrantedSerializer(serializers.ModelSerializer): """ 被授权资产的数据结构 diff --git a/apps/perms/templates/perms/remote_app_permission_create_update.html b/apps/perms/templates/perms/remote_app_permission_create_update.html index 66bbcdffa..ce37d788b 100644 --- a/apps/perms/templates/perms/remote_app_permission_create_update.html +++ b/apps/perms/templates/perms/remote_app_permission_create_update.html @@ -47,6 +47,7 @@

{% trans 'RemoteApp' %}

{% bootstrap_field form.remote_apps layout="horizontal" %} + {% bootstrap_field form.system_users layout="horizontal" %}

{% trans 'Other' %}

@@ -127,7 +128,7 @@ $(document).ready(function () { the_url = '{% url "api-perms:remote-app-permission-detail" pk=object.id %}'; method = "PUT"; {% endif %} - objectAttrsIsList(data, ['users', 'user_groups', 'remote_apps']); + objectAttrsIsList(data, ['users', 'user_groups', 'remote_apps', 'system_users']); objectAttrsIsDatetime(data, ['date_expired', 'date_start']); objectAttrsIsBool(data, ['is_active']); var props = { diff --git a/apps/perms/templates/perms/remote_app_permission_detail.html b/apps/perms/templates/perms/remote_app_permission_detail.html index d855e71a0..f2ec8fa35 100644 --- a/apps/perms/templates/perms/remote_app_permission_detail.html +++ b/apps/perms/templates/perms/remote_app_permission_detail.html @@ -126,7 +126,42 @@ +
+
+ {% trans 'System user' %} +
+
+ + + + + + + + + + + {% for system_user in object.system_users.all %} + + + + + {% endfor %} + +
+ +
+ +
{{ system_user }} + +
+
+
@@ -136,6 +171,20 @@ {% endblock %} {% block custom_foot_js %}