diff --git a/apps/applications/migrations/0018_auto_20220223_1539.py b/apps/applications/migrations/0018_auto_20220223_1539.py new file mode 100644 index 000000000..637d8cb86 --- /dev/null +++ b/apps/applications/migrations/0018_auto_20220223_1539.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.13 on 2022-02-23 07:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('applications', '0017_auto_20220217_2135'), + ] + + operations = [ + migrations.AlterField( + model_name='application', + name='type', + field=models.CharField(choices=[('mysql', 'MySQL'), ('oracle', 'Oracle'), ('postgresql', 'PostgreSQL'), ('mariadb', 'MariaDB'), ('sqlserver', 'SQLServer'), ('redis', 'Redis'), ('mongodb', 'MongoDB'), ('chrome', 'Chrome'), ('mysql_workbench', 'MySQL Workbench'), ('vmware_client', 'vSphere Client'), ('custom', 'Custom'), ('k8s', 'Kubernetes')], max_length=16, verbose_name='Type'), + ), + ] diff --git a/apps/applications/migrations/0018_auto_20220223_1642.py b/apps/applications/migrations/0018_auto_20220223_1642.py new file mode 100644 index 000000000..5f3af1455 --- /dev/null +++ b/apps/applications/migrations/0018_auto_20220223_1642.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.14 on 2022-02-23 08:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('applications', '0017_auto_20220217_2135'), + ] + + operations = [ + migrations.AlterField( + model_name='application', + name='type', + field=models.CharField(choices=[('mysql', 'MySQL'), ('oracle', 'Oracle'), ('postgresql', 'PostgreSQL'), ('mariadb', 'MariaDB'), ('sqlserver', 'SQLServer'), ('redis', 'Redis'), ('mongodb', 'MongoDB'), ('chrome', 'Chrome'), ('mysql_workbench', 'MySQL Workbench'), ('vmware_client', 'vSphere Client'), ('custom', 'Custom'), ('k8s', 'Kubernetes')], max_length=16, verbose_name='Type'), + ), + ] diff --git a/apps/assets/migrations/0087_auto_20220223_1539.py b/apps/assets/migrations/0087_auto_20220223_1539.py new file mode 100644 index 000000000..6c3302e51 --- /dev/null +++ b/apps/assets/migrations/0087_auto_20220223_1539.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.13 on 2022-02-23 07:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('assets', '0086_auto_20220217_2135'), + ] + + operations = [ + migrations.AlterField( + model_name='systemuser', + name='protocol', + field=models.CharField(choices=[('ssh', 'SSH'), ('rdp', 'RDP'), ('telnet', 'Telnet'), ('vnc', 'VNC'), ('mysql', 'MySQL'), ('oracle', 'Oracle'), ('mariadb', 'MariaDB'), ('postgresql', 'PostgreSQL'), ('sqlserver', 'SQLServer'), ('redis', 'Redis'), ('mongodb', 'MongoDB'), ('k8s', 'K8S')], default='ssh', max_length=16, verbose_name='Protocol'), + ), + ] diff --git a/apps/assets/migrations/0087_auto_20220223_1642.py b/apps/assets/migrations/0087_auto_20220223_1642.py new file mode 100644 index 000000000..c2a1b020f --- /dev/null +++ b/apps/assets/migrations/0087_auto_20220223_1642.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.14 on 2022-02-23 08:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('assets', '0086_auto_20220217_2135'), + ] + + operations = [ + migrations.AlterField( + model_name='systemuser', + name='protocol', + field=models.CharField(choices=[('ssh', 'SSH'), ('rdp', 'RDP'), ('telnet', 'Telnet'), ('vnc', 'VNC'), ('mysql', 'MySQL'), ('oracle', 'Oracle'), ('mariadb', 'MariaDB'), ('postgresql', 'PostgreSQL'), ('sqlserver', 'SQLServer'), ('redis', 'Redis'), ('mongodb', 'MongoDB'), ('k8s', 'K8S')], default='ssh', max_length=16, verbose_name='Protocol'), + ), + ] diff --git a/apps/common/migrations/0007_permission.py b/apps/common/migrations/0007_permission.py new file mode 100644 index 000000000..8794b7c5b --- /dev/null +++ b/apps/common/migrations/0007_permission.py @@ -0,0 +1,24 @@ +# Generated by Django 3.1.14 on 2022-02-23 08:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('common', '0006_auto_20190304_1515'), + ] + + operations = [ + migrations.CreateModel( + name='Permission', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + options={ + 'permissions': [('view_resourcestatistics', 'Can view resource statistics')], + }, + ), + ] diff --git a/apps/common/models.py b/apps/common/models.py new file mode 100644 index 000000000..e716113cd --- /dev/null +++ b/apps/common/models.py @@ -0,0 +1,9 @@ +from django.db import models +from django.utils.translation import gettext_lazy as _ + + +class Permission(models.Model): + class Meta: + permissions = [ + ('view_resourcestatistics', _('Can view resource statistics')) + ] diff --git a/apps/jumpserver/api.py b/apps/jumpserver/api.py index 8edc35e76..d69d27c68 100644 --- a/apps/jumpserver/api.py +++ b/apps/jumpserver/api.py @@ -214,7 +214,7 @@ class DatesLoginMetricMixin: class IndexApi(DatesLoginMetricMixin, APIView): http_method_names = ['get'] rbac_perms = { - 'GET': 'view_auditview' + 'GET': 'common.view_resourcestatistics' } def get(self, request, *args, **kwargs): diff --git a/apps/perms/migrations/0025_auto_20220223_1539.py b/apps/perms/migrations/0025_auto_20220223_1539.py new file mode 100644 index 000000000..47d3487c7 --- /dev/null +++ b/apps/perms/migrations/0025_auto_20220223_1539.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.13 on 2022-02-23 07:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('perms', '0024_auto_20220217_2135'), + ] + + operations = [ + migrations.AlterField( + model_name='applicationpermission', + name='type', + field=models.CharField(choices=[('mysql', 'MySQL'), ('oracle', 'Oracle'), ('postgresql', 'PostgreSQL'), ('mariadb', 'MariaDB'), ('sqlserver', 'SQLServer'), ('redis', 'Redis'), ('mongodb', 'MongoDB'), ('chrome', 'Chrome'), ('mysql_workbench', 'MySQL Workbench'), ('vmware_client', 'vSphere Client'), ('custom', 'Custom'), ('k8s', 'Kubernetes')], max_length=16, verbose_name='Type'), + ), + ] diff --git a/apps/perms/migrations/0025_auto_20220223_1642.py b/apps/perms/migrations/0025_auto_20220223_1642.py new file mode 100644 index 000000000..120039e40 --- /dev/null +++ b/apps/perms/migrations/0025_auto_20220223_1642.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.14 on 2022-02-23 08:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('perms', '0024_auto_20220217_2135'), + ] + + operations = [ + migrations.AlterField( + model_name='applicationpermission', + name='type', + field=models.CharField(choices=[('mysql', 'MySQL'), ('oracle', 'Oracle'), ('postgresql', 'PostgreSQL'), ('mariadb', 'MariaDB'), ('sqlserver', 'SQLServer'), ('redis', 'Redis'), ('mongodb', 'MongoDB'), ('chrome', 'Chrome'), ('mysql_workbench', 'MySQL Workbench'), ('vmware_client', 'vSphere Client'), ('custom', 'Custom'), ('k8s', 'Kubernetes')], max_length=16, verbose_name='Type'), + ), + ] diff --git a/apps/rbac/builtin.py b/apps/rbac/builtin.py index 71f7d0bc4..6d8d2490f 100644 --- a/apps/rbac/builtin.py +++ b/apps/rbac/builtin.py @@ -4,6 +4,7 @@ from .const import Scope, system_exclude_permissions, org_exclude_permissions auditor_perms = ( + ('common', 'permission', 'view', 'resourcestatistics'), ('audits', '*', '*', '*'), ('rbac', 'menupermission', 'view', 'auditview'), ('terminal', 'session', '*', '*'), diff --git a/apps/terminal/api/session.py b/apps/terminal/api/session.py index 6bc76bd81..334a19cf4 100644 --- a/apps/terminal/api/session.py +++ b/apps/terminal/api/session.py @@ -3,7 +3,6 @@ import os import tarfile -from django.db.models import F, Max from django.shortcuts import get_object_or_404, reverse from django.utils.translation import ugettext as _ from django.utils.encoding import escape_uri_path @@ -16,7 +15,6 @@ from rest_framework.permissions import IsAuthenticated from rest_framework import generics from common.utils import data_to_json -from assets.models import Asset from common.const.http import GET from common.utils import get_logger, get_object_or_none from common.mixins.api import AsyncApiMixin @@ -30,11 +28,10 @@ from ..utils import find_session_replay_local, download_session_replay from ..models import Session from .. import serializers from terminal.utils import is_session_approver -from assets.serializers import AssetSerializer __all__ = [ 'SessionViewSet', 'SessionReplayViewSet', 'SessionJoinValidateAPI', - 'MySessionAPIView', 'MySessionAssetAPIView', + 'MySessionAPIView', ] logger = get_logger(__name__) @@ -51,42 +48,6 @@ class MySessionAPIView(generics.ListAPIView): return qs -class MySessionAssetAPIView(generics.ListAPIView): - queryset = Asset.objects.all() - permission_classes = (IsAuthenticated, ) - serializer_class = AssetSerializer - - def list(self, request, *args, **kwargs): - with tmp_to_root_org(): - user = self.request.user - - asset_ids = Session.objects.filter(user_id=user.id).exclude( - asset_id='' # xrdp bug 没有提交 asset_id,已修复,但要兼容旧数据 - ).values_list('asset_id').annotate( - max_date_start=Max(F('date_start')) - ).order_by('-max_date_start').values_list('asset_id', flat=True) - page = self.paginate_queryset(asset_ids) - if page is not None: - serializer = self._to_serializer(page) - return self.get_paginated_response(serializer.data) - - serializer = self._to_serializer(asset_ids) - return Response(serializer.data) - - def _to_serializer(self, asset_ids): - assets_qs = Asset.objects.filter(id__in=list(asset_ids)) - serializer_cls = self.get_serializer_class() - if hasattr(serializer_cls, 'setup_eager_loading'): - assets_qs = serializer_cls.setup_eager_loading(assets_qs) - - id_asset_map = {str(asset.id): asset for asset in assets_qs} - assets = [] - for i in asset_ids: - assets.append(id_asset_map[i]) - serializer = self.get_serializer(assets, many=True) - return serializer - - class SessionViewSet(OrgBulkModelViewSet): model = Session serializer_classes = { @@ -164,8 +125,8 @@ class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet): download_cache_key = "SESSION_REPLAY_DOWNLOAD_{}" session = None rbac_perms = { - 'create': 'terminal.upload_session', - 'retrieve': 'terminal.download_session', + 'create': 'terminal.upload_sessionreplay', + 'retrieve': 'terminal.download_sessionreplay', } def create(self, request, *args, **kwargs): diff --git a/apps/terminal/api/task.py b/apps/terminal/api/task.py index 937ed2faf..c7e1a2681 100644 --- a/apps/terminal/api/task.py +++ b/apps/terminal/api/task.py @@ -12,7 +12,6 @@ from .. import serializers from terminal.utils import is_session_approver from orgs.utils import tmp_to_root_org - __all__ = ['TaskViewSet', 'KillSessionAPI', 'KillSessionForTicketAPI'] logger = logging.getLogger(__file__) @@ -45,6 +44,11 @@ class KillSessionAPI(APIView): 'POST': 'terminal.terminate_session' } + def post(self, request, *args, **kwargs): + session_ids = request.data + validated_session = kill_sessions(session_ids, request.user) + return Response({"ok": validated_session}) + class KillSessionForTicketAPI(APIView): permission_classes = (IsAuthenticated, ) @@ -61,4 +65,3 @@ class KillSessionForTicketAPI(APIView): validated_session = kill_sessions(session_ids, request.user) return Response({"ok": validated_session}) - diff --git a/apps/terminal/migrations/0044_auto_20220223_1539.py b/apps/terminal/migrations/0044_auto_20220223_1539.py new file mode 100644 index 000000000..a1557b008 --- /dev/null +++ b/apps/terminal/migrations/0044_auto_20220223_1539.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.13 on 2022-02-23 07:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('terminal', '0043_auto_20220217_2135'), + ] + + operations = [ + migrations.AlterField( + model_name='session', + name='protocol', + field=models.CharField(choices=[('ssh', 'ssh'), ('rdp', 'rdp'), ('vnc', 'vnc'), ('telnet', 'telnet'), ('mysql', 'mysql'), ('oracle', 'oracle'), ('mariadb', 'mariadb'), ('sqlserver', 'sqlserver'), ('postgresql', 'postgresql'), ('redis', 'redis'), ('mongodb', 'MongoDB'), ('k8s', 'kubernetes')], db_index=True, default='ssh', max_length=16), + ), + ] diff --git a/apps/terminal/migrations/0044_auto_20220223_1642.py b/apps/terminal/migrations/0044_auto_20220223_1642.py new file mode 100644 index 000000000..463312f8e --- /dev/null +++ b/apps/terminal/migrations/0044_auto_20220223_1642.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.14 on 2022-02-23 08:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('terminal', '0043_auto_20220217_2135'), + ] + + operations = [ + migrations.AlterField( + model_name='session', + name='protocol', + field=models.CharField(choices=[('ssh', 'ssh'), ('rdp', 'rdp'), ('vnc', 'vnc'), ('telnet', 'telnet'), ('mysql', 'mysql'), ('oracle', 'oracle'), ('mariadb', 'mariadb'), ('sqlserver', 'sqlserver'), ('postgresql', 'postgresql'), ('redis', 'redis'), ('mongodb', 'MongoDB'), ('k8s', 'kubernetes')], db_index=True, default='ssh', max_length=16), + ), + ] diff --git a/apps/terminal/urls/api_urls.py b/apps/terminal/urls/api_urls.py index f03ba083a..9366332e2 100644 --- a/apps/terminal/urls/api_urls.py +++ b/apps/terminal/urls/api_urls.py @@ -24,7 +24,6 @@ router.register(r'session-sharings', api.SessionSharingViewSet, 'session-sharing router.register(r'session-join-records', api.SessionJoinRecordsViewSet, 'session-sharing-record') urlpatterns = [ - path('my-login-assets/', api.MySessionAssetAPIView.as_view(), name='my-login-asset'), path('my-sessions/', api.MySessionAPIView.as_view(), name='my-session'), path('terminal-registrations/', api.TerminalRegistrationApi.as_view(), name='terminal-registration'), path('registration/', api.TerminalRegistrationApi.as_view(), name='registration'), diff --git a/apps/users/api/user.py b/apps/users/api/user.py index 7fcd29f18..dc818a5cb 100644 --- a/apps/users/api/user.py +++ b/apps/users/api/user.py @@ -23,7 +23,6 @@ from ..models import User from ..signals import post_user_create from ..filters import UserFilter - logger = get_logger(__name__) __all__ = [ 'UserViewSet', 'UserChangePasswordApi', @@ -40,7 +39,7 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet): 'invite': InviteSerializer, } ordering_fields = ('name',) - ordering = ('name', ) + ordering = ('name',) rbac_perms = { 'suggestion': 'users.match_user', 'invite': 'users.invite_user', @@ -52,6 +51,19 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet): queryset = super().get_queryset().prefetch_related('groups') return queryset + def list(self, request, *args, **kwargs): + queryset = self.filter_queryset(self.get_queryset()) + + page = self.paginate_queryset(queryset) + if page is not None: + page = self.set_users_roles_for_cache(page) + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + + queryset = self.set_users_roles_for_cache(queryset) + serializer = self.get_serializer(queryset, many=True) + return Response(serializer.data) + @staticmethod def set_users_roles_for_cache(queryset): # Todo: 未来有机会用 SQL 实现 @@ -80,11 +92,6 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet): u.system_roles.cache_set(system_roles) return queryset_list - def filter_queryset(self, queryset): - queryset = super().filter_queryset(queryset) - queryset_list = self.set_users_roles_for_cache(queryset) - return queryset_list - def perform_create(self, serializer): users = serializer.save() if isinstance(users, User): diff --git a/apps/users/models/user.py b/apps/users/models/user.py index e40aedf17..f99434745 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -341,7 +341,7 @@ class RoleMixin: @classmethod def get_org_users(cls, org=None): - queryset = cls.objects.all() + queryset = cls.get_nature_users() if org is None: org = current_org if not org.is_root():