mirror of https://github.com/jumpserver/jumpserver
				
				
				
			Dev remoteapp (#3205)
* [Update] 修改RemoteApp关联的系统用户:从RemoteApp中转移到RemoteAppPermission中(未提交迁移文件) * [Update] 修改RemoteApp关联的系统用户:提交迁移文件 * [Update] 修改RemoteApp关联的系统用户:修改迁移文件 * [Update] 修改迁移文件1 * [Update] 修改迁移文件2 * [Update] 修改迁移文件3 * [Update] 修改RemoteAppPermsUtil获取系统用户的逻辑pull/3224/head
							parent
							
								
									3a8fad7c7d
								
							
						
					
					
						commit
						bdcf9ba153
					
				| 
						 | 
				
			
			@ -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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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',
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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']
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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" %}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,10 +57,6 @@
 | 
			
		|||
                                            <td>{% trans 'Asset' %}:</td>
 | 
			
		||||
                                            <td><b><a href="{% url 'assets:asset-detail' pk=remote_app.asset.id %}">{{ remote_app.asset.hostname }}</a></b></td>
 | 
			
		||||
                                        </tr>
 | 
			
		||||
                                        <tr>
 | 
			
		||||
                                            <td>{% trans 'System user' %}:</td>
 | 
			
		||||
                                            <td><b><a href="{% url 'assets:system-user-detail' pk=remote_app.system_user.id %}">{{ remote_app.system_user.name }}</a></b></td>
 | 
			
		||||
                                        </tr>
 | 
			
		||||
                                        <tr>
 | 
			
		||||
                                            <td>{% trans 'App type' %}:</td>
 | 
			
		||||
                                            <td><b>{{ remote_app.get_type_display }}</b></td>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,6 @@
 | 
			
		|||
            <th class="text-center">{% trans 'Name' %}</th>
 | 
			
		||||
            <th class="text-center">{% trans 'App type' %}</th>
 | 
			
		||||
            <th class="text-center">{% trans 'Asset' %}</th>
 | 
			
		||||
            <th class="text-center">{% trans 'System user' %}</th>
 | 
			
		||||
            <th class="text-center">{% trans 'Comment' %}</th>
 | 
			
		||||
            <th class="text-center">{% trans 'Action' %}</th>
 | 
			
		||||
        </tr>
 | 
			
		||||
| 
						 | 
				
			
			@ -47,12 +46,11 @@ function initTable() {
 | 
			
		|||
                    var detail_btn = '<a href="{% url 'assets:asset-detail' pk=DEFAULT_PK %}">' + hostname + '</a>';
 | 
			
		||||
                    $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', cellData.id));
 | 
			
		||||
                }},
 | 
			
		||||
            {targets: 4, createdCell: function (td, cellData, rowData) {
 | 
			
		||||
                    var name = htmlEscape(cellData.name);
 | 
			
		||||
                    var detail_btn = '<a href="{% url 'assets:system-user-detail' pk=DEFAULT_PK %}">' + name + '</a>';
 | 
			
		||||
                    $(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 = '<a href="{% url "applications:remote-app-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
 | 
			
		||||
                    var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-delete" data-rid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.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}
 | 
			
		||||
        ],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,7 +16,6 @@
 | 
			
		|||
            <th class="text-center">{% trans 'Name' %}</th>
 | 
			
		||||
            <th class="text-center">{% trans 'App type' %}</th>
 | 
			
		||||
            <th class="text-center">{% trans 'Asset' %}</th>
 | 
			
		||||
            <th class="text-center">{% trans 'System user' %}</th>
 | 
			
		||||
            <th class="text-center">{% trans 'Comment' %}</th>
 | 
			
		||||
            <th class="text-center">{% trans 'Action' %}</th>
 | 
			
		||||
        </tr>
 | 
			
		||||
| 
						 | 
				
			
			@ -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 = '<a href="{% url "luna-view" %}?login_to=' +  cellData +'" class="btn btn-xs btn-primary">{% trans "Connect" %}</a>'.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}
 | 
			
		||||
        ]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,9 +13,7 @@ router = BulkRouter()
 | 
			
		|||
router.register(r'remote-apps', api.RemoteAppViewSet, 'remote-app')
 | 
			
		||||
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
    path('remote-apps/<uuid:pk>/connection-info/',
 | 
			
		||||
         api.RemoteAppConnectionInfoApi.as_view(),
 | 
			
		||||
         name='remote-app-connection-info')
 | 
			
		||||
    path('remote-apps/<uuid:pk>/connection-info/', api.RemoteAppConnectionInfoApi.as_view(), name='remote-app-connection-info'),
 | 
			
		||||
]
 | 
			
		||||
old_version_urlpatterns = [
 | 
			
		||||
    re_path('(?P<resource>remote-app)/.*', capi.redirect_plural_name_api)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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')}
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
| 
						 | 
				
			
			@ -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')]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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']
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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):
 | 
			
		||||
    """
 | 
			
		||||
    被授权资产的数据结构
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,6 +47,7 @@
 | 
			
		|||
 | 
			
		||||
                            <h3>{% trans 'RemoteApp' %}</h3>
 | 
			
		||||
                            {% bootstrap_field form.remote_apps layout="horizontal" %}
 | 
			
		||||
                            {% bootstrap_field form.system_users layout="horizontal" %}
 | 
			
		||||
                            <div class="hr-line-dashed"></div>
 | 
			
		||||
 | 
			
		||||
                            <h3>{% trans 'Other' %}</h3>
 | 
			
		||||
| 
						 | 
				
			
			@ -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 = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -126,7 +126,42 @@
 | 
			
		|||
                                    </table>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <div class="panel panel-info">
 | 
			
		||||
                                <div class="panel-heading">
 | 
			
		||||
                                    <i class="fa fa-info-circle"></i> {% trans 'System user' %}
 | 
			
		||||
                                </div>
 | 
			
		||||
                                <div class="panel-body">
 | 
			
		||||
                                    <table class="table" id="system-user-table">
 | 
			
		||||
                                        <tbody>
 | 
			
		||||
                                        <form>
 | 
			
		||||
                                            <tr class="no-borders-tr">
 | 
			
		||||
                                                <td colspan="2">
 | 
			
		||||
                                                    <select data-placeholder="{% trans 'Select system users' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
 | 
			
		||||
                                                        {% for system_user in system_users_remain %}
 | 
			
		||||
                                                            <option value="{{ system_user.id }}" id="opt_{{ system_user.id }}">{{ system_user }}</option>
 | 
			
		||||
                                                        {% endfor %}
 | 
			
		||||
                                                    </select>
 | 
			
		||||
                                                </td>
 | 
			
		||||
                                            </tr>
 | 
			
		||||
                                            <tr class="no-borders-tr">
 | 
			
		||||
                                                <td colspan="2">
 | 
			
		||||
                                                    <button type="button" class="btn btn-info btn-small" id="btn-add-system-user">{% trans 'Add' %}</button>
 | 
			
		||||
                                                </td>
 | 
			
		||||
                                            </tr>
 | 
			
		||||
                                        </form>
 | 
			
		||||
 | 
			
		||||
                                        {% for system_user in object.system_users.all %}
 | 
			
		||||
                                            <tr {% if forloop.counter == 1 %} class="no-borders-tr" {% endif %} >
 | 
			
		||||
                                                <td ><b class="bdg-system-user" data-uid={{ system_user.id }}>{{ system_user }}</b></td>
 | 
			
		||||
                                                <td>
 | 
			
		||||
                                                    <button class="btn btn-danger btn-xs btn-remove-user" data-uid="{{ system_user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
 | 
			
		||||
                                                </td>
 | 
			
		||||
                                            </tr>
 | 
			
		||||
                                        {% endfor %}
 | 
			
		||||
                                        </tbody>
 | 
			
		||||
                                    </table>
 | 
			
		||||
                                </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -136,6 +171,20 @@
 | 
			
		|||
{% endblock %}
 | 
			
		||||
{% block custom_foot_js %}
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
jumpserver.system_users_selected = {};
 | 
			
		||||
function updateSystemUser(system_users) {
 | 
			
		||||
    var the_url = "{% url 'api-perms:remote-app-permission-detail' pk=object.id %}";
 | 
			
		||||
    var body = {
 | 
			
		||||
        system_users: Object.assign([], system_users)
 | 
			
		||||
    };
 | 
			
		||||
    requestApi({
 | 
			
		||||
        url: the_url,
 | 
			
		||||
        body: JSON.stringify(body),
 | 
			
		||||
        success: function () {window.location.reload()}
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
    $('.select2').select2()
 | 
			
		||||
        .on('select2:select', function(evt) {
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +196,36 @@ $(document).ready(function () {
 | 
			
		|||
            delete jumpserver.system_users_selected[data.id]
 | 
			
		||||
        })
 | 
			
		||||
})
 | 
			
		||||
.on('click', '.btn-delete', function () {
 | 
			
		||||
.on('click', '#btn-add-system-user', function () {
 | 
			
		||||
    if (Object.keys(jumpserver.system_users_selected).length === 0) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    var system_users = $('.bdg-system-user').map(function() {
 | 
			
		||||
        return $(this).data('uid');
 | 
			
		||||
    }).get();
 | 
			
		||||
 | 
			
		||||
    $.map(jumpserver.system_users_selected, function(name, index) {
 | 
			
		||||
        system_users.push(index);
 | 
			
		||||
        $('#opt_' + index).remove();
 | 
			
		||||
        $('.group_edit tbody').append(
 | 
			
		||||
            '<tr>' +
 | 
			
		||||
            '<td><b class="bdg-system-user" data-gid="' + index + '">' + name + '</b></td>' +
 | 
			
		||||
            '<td><button class="btn btn-danger btn-xs pull-right btn-remove-user" type="button"><i class="fa fa-minus"></i></button></td>' +
 | 
			
		||||
            '</tr>'
 | 
			
		||||
        )
 | 
			
		||||
    });
 | 
			
		||||
    updateSystemUser(system_users);
 | 
			
		||||
}).on('click', '.btn-remove-user', function () {
 | 
			
		||||
    var $this = $(this);
 | 
			
		||||
    var $tr = $this.closest('tr');
 | 
			
		||||
    var system_users = $('.bdg-system-user').map(function() {
 | 
			
		||||
        if ($(this).data('uid') !== $this.data('uid')){
 | 
			
		||||
            return $(this).data('uid');
 | 
			
		||||
        }
 | 
			
		||||
    }).get();
 | 
			
		||||
    updateSystemUser(system_users);
 | 
			
		||||
    $tr.remove()
 | 
			
		||||
}).on('click', '.btn-delete', function () {
 | 
			
		||||
    var $this = $(this);
 | 
			
		||||
    var name = "{{ object.name }}";
 | 
			
		||||
    var rid = "{{ object.id }}";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,6 +91,10 @@ remote_app_permission_urlpatterns = [
 | 
			
		|||
    # 查询用户组授权的RemoteApp
 | 
			
		||||
    path('user-groups/<uuid:pk>/remote-apps/', api.UserGroupGrantedRemoteAppsApi.as_view(), name='user-group-remote-apps'),
 | 
			
		||||
 | 
			
		||||
    # RemoteApp System users
 | 
			
		||||
    path('users/<uuid:pk>/remote-apps/<uuid:remote_app_id>/system-users/', api.UserGrantedRemoteAppSystemUsersApi.as_view(), name='user-remote-app-system-users'),
 | 
			
		||||
    path('users/remote-apps/<uuid:remote_app_id>/system-users/', api.UserGrantedRemoteAppSystemUsersApi.as_view(), name='my-remote-app-system-users'),
 | 
			
		||||
 | 
			
		||||
    # 校验用户对RemoteApp的权限
 | 
			
		||||
    path('remote-app-permissions/user/validate/', api.ValidateUserRemoteAppPermissionApi.as_view(), name='validate-user-remote-app-permission'),
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ from common.tree import TreeNode
 | 
			
		|||
from orgs.utils import set_to_root_org
 | 
			
		||||
 | 
			
		||||
from ..models import RemoteAppPermission
 | 
			
		||||
from ..hands import RemoteApp
 | 
			
		||||
from ..hands import RemoteApp, SystemUser
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__all__ = [
 | 
			
		||||
| 
						 | 
				
			
			@ -59,6 +59,16 @@ class RemoteAppPermissionUtil:
 | 
			
		|||
        )
 | 
			
		||||
        return remote_apps
 | 
			
		||||
 | 
			
		||||
    def get_remote_app_system_users(self, remote_app):
 | 
			
		||||
        queryset = self.permissions
 | 
			
		||||
        kwargs = {"remote_apps": remote_app}
 | 
			
		||||
        queryset = queryset.filter(**kwargs)
 | 
			
		||||
        system_users_ids = queryset.values_list('system_users', flat=True)
 | 
			
		||||
        system_users_ids = system_users_ids.distinct()
 | 
			
		||||
        system_users = SystemUser.objects.filter(id__in=system_users_ids)
 | 
			
		||||
        system_users = system_users.order_by('-priority')
 | 
			
		||||
        return system_users
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def construct_remote_apps_tree_root():
 | 
			
		||||
    tree_root = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ from django.conf import settings
 | 
			
		|||
from common.permissions import PermissionsMixin, IsOrgAdmin
 | 
			
		||||
from orgs.utils import current_org
 | 
			
		||||
 | 
			
		||||
from ..hands import RemoteApp, UserGroup
 | 
			
		||||
from ..hands import RemoteApp, UserGroup, SystemUser
 | 
			
		||||
from ..models import RemoteAppPermission
 | 
			
		||||
from ..forms import RemoteAppPermissionCreateUpdateForm
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -80,6 +80,9 @@ class RemoteAppPermissionDetailView(PermissionsMixin, DetailView):
 | 
			
		|||
        context = {
 | 
			
		||||
            'app': _('Perms'),
 | 
			
		||||
            'action': _('RemoteApp permission detail'),
 | 
			
		||||
            'system_users_remain': SystemUser.objects.exclude(
 | 
			
		||||
                granted_by_remote_app_permissions=self.object
 | 
			
		||||
            ),
 | 
			
		||||
        }
 | 
			
		||||
        kwargs.update(context)
 | 
			
		||||
        return super().get_context_data(**kwargs)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue