Merge pull request #7825 from jumpserver/dev

v2.20.0-rc2
pull/7919/head
Jiangjie.Bai 2022-03-14 10:38:35 +08:00 committed by GitHub
commit a64ec8a1d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 118 additions and 67 deletions

View File

@ -214,7 +214,7 @@ class DatesLoginMetricMixin:
class IndexApi(DatesLoginMetricMixin, APIView):
http_method_names = ['get']
rbac_perms = {
'GET': 'rbac.view_dashboard'
'GET': 'rbac.view_audit | rbac.view_console'
}
def get(self, request, *args, **kwargs):

View File

@ -390,7 +390,6 @@ class Config(dict):
'HELP_DOCUMENT_URL': 'http://docs.jumpserver.org',
'HELP_SUPPORT_URL': 'http://www.jumpserver.org/support/',
'TICKETS_ENABLED': True,
'FORGOT_PASSWORD_URL': '',
'HEALTH_CHECK_TOKEN': '',
}

View File

@ -119,7 +119,6 @@ CHANGE_AUTH_PLAN_SECURE_MODE_ENABLED = CONFIG.CHANGE_AUTH_PLAN_SECURE_MODE_ENABL
DATETIME_DISPLAY_FORMAT = '%Y-%m-%d %H:%M:%S'
TICKETS_ENABLED = CONFIG.TICKETS_ENABLED
REFERER_CHECK_ENABLED = CONFIG.REFERER_CHECK_ENABLED
CONNECTION_TOKEN_ENABLED = CONFIG.CONNECTION_TOKEN_ENABLED

View File

@ -14,6 +14,7 @@ from orgs.models import Organization
from orgs.hands import set_current_org, Node, get_current_org
from perms.models import (AssetPermission, ApplicationPermission)
from users.models import UserGroup, User
from assets.models import SystemUser
from common.const.signals import PRE_REMOVE, POST_REMOVE
from common.decorator import on_transaction_commit
from common.signals import django_ready
@ -135,7 +136,7 @@ def _clear_users_from_org(org, users):
if not users:
return
models = (AssetPermission, ApplicationPermission, UserGroup)
models = (AssetPermission, ApplicationPermission, UserGroup, SystemUser)
for m in models:
_remove_users(m, users, org)

View File

@ -5,7 +5,7 @@ from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from perms.models import ApplicationPermission
from perms.models import ApplicationPermission, Action
from ..base import ActionsField, BasePermissionSerializer
__all__ = [

View File

@ -1,6 +1,7 @@
from rest_framework import serializers
from perms.models import Action
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
from rest_framework.fields import empty
__all__ = ['ActionsDisplayField', 'ActionsField', 'BasePermissionSerializer']
@ -10,6 +11,12 @@ class ActionsField(serializers.MultipleChoiceField):
kwargs['choices'] = Action.CHOICES
super().__init__(*args, **kwargs)
def run_validation(self, data=empty):
data = super(ActionsField, self).run_validation()
if isinstance(data, list):
data = Action.choices_to_value(value=data)
return data
def to_representation(self, value):
return Action.value_to_choices(value)

View File

@ -22,6 +22,7 @@ auditor_perms = user_perms + (
('terminal', 'sessionreplay', 'view,download', 'sessionreplay'),
('terminal', 'session', '*', '*'),
('terminal', 'command', '*', '*'),
('ops', 'commandexecution', 'view', 'commandexecution')
)

View File

@ -23,6 +23,10 @@ exclude_permissions = (
('common', 'setting', '*', '*'),
('authentication', 'privatetoken', '*', '*'),
('authentication', 'accesskey', 'change,delete', 'accesskey'),
('authentication', 'connectiontoken', 'change,delete', 'connectiontoken'),
('authentication', 'ssotoken', 'change,delete', 'ssotoken'),
('authentication', 'superconnectiontoken', 'change,delete', 'superconnectiontoken'),
('users', 'userpasswordhistory', '*', '*'),
('applications', 'applicationuser', '*', '*'),
('applications', 'historicalaccount', '*', '*'),
@ -56,10 +60,14 @@ exclude_permissions = (
('audits', 'passwordchangelog', 'add,change,delete', 'passwordchangelog'),
('audits', 'userloginlog', 'add,change,delete,change', 'userloginlog'),
('audits', 'ftplog', 'change,delete', 'ftplog'),
('tickets', 'ticket', '*', '*'),
('tickets', 'ticketassignee', '*', 'ticketassignee'),
('tickets', 'ticketflow', 'add,delete', 'ticketflow'),
('tickets', 'comment', 'change,delete', 'comment'),
('tickets', 'ticket', 'delete', 'ticket'),
('tickets', 'ticketstep', '*', '*'),
('tickets', 'ticketapprovalrule', '*', '*'),
('tickets', 'approvalrule', '*', '*'),
('tickets', 'superticket', 'delete', 'superticket'),
('tickets', 'ticketsession', 'delete', 'ticketsession'),
('xpack', 'interface', '*', '*'),
('xpack', 'license', '*', '*'),
('xpack', 'syncinstancedetail', 'add,delete,change', 'syncinstancedetail'),
@ -75,13 +83,13 @@ exclude_permissions = (
only_system_permissions = (
('assets', 'platform', '*', '*'),
('users', 'user', 'delete', 'user'),
('rbac', 'role', 'delete,add,change', 'role'),
('rbac', 'systemrole', '*', '*'),
('rbac', 'rolebinding', '*', '*'),
('rbac', 'systemrolebinding', '*', '*'),
('rbac', 'orgrole', 'delete,add,change', '*'),
('rbac', 'orgrolebinding', 'delete,add,change', '*'),
('orgs', 'organization', '*', '*'),
('xpack', 'license', '*', '*'),
('settings', 'setting', '*', '*'),

View File

@ -12,6 +12,6 @@ class Migration(migrations.Migration):
operations = [
migrations.AlterModelOptions(
name='menupermission',
options={'default_permissions': [], 'permissions': [('view_dashboard', 'Can view resource statistics'), ('view_console', 'Can view console view'), ('view_audit', 'Can view audit view'), ('view_workspace', 'Can view workspace view'), ('view_webterminal', 'Can view web terminal'), ('view_filemanager', 'Can view file manager')], 'verbose_name': 'Menu permission'},
options={'default_permissions': [], 'permissions': [('view_console', 'Can view console view'), ('view_audit', 'Can view audit view'), ('view_workspace', 'Can view workspace view'), ('view_webterminal', 'Can view web terminal'), ('view_filemanager', 'Can view file manager')], 'verbose_name': 'Menu permission'},
),
]

View File

@ -12,6 +12,6 @@ class Migration(migrations.Migration):
operations = [
migrations.AlterModelOptions(
name='menupermission',
options={'default_permissions': [], 'permissions': [('view_console', 'Can view console view'), ('view_audit', 'Can view audit view'), ('view_workspace', 'Can view workspace view'), ('view_webterminal', 'Can view web terminal'), ('view_filemanager', 'Can view file manager'), ('view_dashboard', 'Can view dashboard')], 'verbose_name': 'Menu permission'},
options={'default_permissions': [], 'permissions': [('view_console', 'Can view console view'), ('view_audit', 'Can view audit view'), ('view_workspace', 'Can view workspace view'), ('view_webterminal', 'Can view web terminal'), ('view_filemanager', 'Can view file manager') ], 'verbose_name': 'Menu permission'},
),
]

View File

@ -17,5 +17,4 @@ class MenuPermission(models.Model):
('view_workspace', _('Can view workspace view')),
('view_webterminal', _('Can view web terminal')),
('view_filemanager', _('Can view file manager')),
('view_dashboard', _('Can view dashboard')),
]

View File

@ -98,7 +98,14 @@ special_pid_mapper = {
"perms.view_mydatabaseapp": "my_apps",
"perms.connect_mydatabaseapp": "my_apps",
"xpack.interface": "view_setting",
"settings.change_terminal": "terminal_node"
"settings.change_terminal": "terminal_node",
"settings.view_setting": "view_setting",
"settings.change_setting": "view_setting",
"rbac.view_console": "view_console",
"rbac.view_audit": "view_audit",
"rbac.view_workspace": "view_workspace",
"rbac.view_webterminal": "view_workspace",
"rbac.view_filemanager": "view_workspace",
}
verbose_name_mapper = {
@ -115,6 +122,32 @@ xpack_nodes = [
]
def _sort_action(node):
value = 0
if 'view' in node.title:
value += 2
elif 'add' in node.title:
value += 4
elif 'change' in node.title:
value += 6
elif 'delete' in node.title:
value += 8
else:
value += 10
return value
def sort_nodes(node):
value = 0
if node.isParent:
value += 50
else:
value += _sort_action(node)
return value
class PermissionTreeUtil:
get_permissions: Callable
@ -122,7 +155,7 @@ class PermissionTreeUtil:
self.permissions = self.prefetch_permissions(permissions)
self.all_permissions = self.prefetch_permissions(
Permission.get_permissions(scope)
).order_by('-codename')
)
self.check_disabled = check_disabled
self.total_counts = defaultdict(int)
self.checked_counts = defaultdict(int)
@ -272,7 +305,7 @@ class PermissionTreeUtil:
# name 要特殊处理,解决 i18n 问题
name = self._get_permission_name(p, content_types_name_mapper)
if settings.DEBUG:
name += '({})'.format(p.app_label_codename)
name += '[{}]'.format(p.app_label_codename)
title = p.app_label_codename
pid = model_id
@ -320,9 +353,12 @@ class PermissionTreeUtil:
},
**data
}
if not node_data.get('title'):
node_data['title'] = node_data['name']
node_data['title'] = node_data['id']
node = TreeNode(**node_data)
if settings.DEBUG:
node.name += ('[' + node.id + ']')
if settings.DEBUG:
node.name += ('-' + node.id)
node.name += f'({checked_count}/{total_count})'
return node
@ -367,12 +403,12 @@ class PermissionTreeUtil:
return nodes
def create_tree_nodes(self):
nodes = [self._create_root_tree_node()]
perms_nodes = self._create_perms_nodes()
models_nodes = self._create_models_nodes()
apps_nodes = self.create_apps_nodes()
extra_nodes = self._create_extra_nodes()
views_nodes = self._create_views_node()
nodes = self._create_perms_nodes()
nodes += self._create_models_nodes()
nodes += self.create_apps_nodes()
nodes += self._create_extra_nodes()
nodes += self._create_views_node()
nodes += [self._create_root_tree_node()]
nodes += views_nodes + apps_nodes + models_nodes + perms_nodes + extra_nodes
nodes.sort(key=sort_nodes)
return nodes

View File

@ -11,6 +11,9 @@ from .. import serializers
class DingTalkTestingAPI(GenericAPIView):
serializer_class = serializers.DingTalkSettingSerializer
rbac_perms = {
'POST': 'settings.change_auth'
}
def post(self, request):
serializer = self.serializer_class(data=request.data)

View File

@ -43,7 +43,6 @@ class PublicSettingApi(generics.RetrieveAPIView):
"XPACK_LICENSE_INFO": get_xpack_license_info(),
"LOGIN_TITLE": self.get_login_title(),
"LOGO_URLS": self.get_logo_urls(),
"TICKETS_ENABLED": settings.TICKETS_ENABLED,
"PASSWORD_RULE": {
'SECURITY_PASSWORD_MIN_LENGTH': settings.SECURITY_PASSWORD_MIN_LENGTH,
'SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH': settings.SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH,

View File

@ -41,9 +41,41 @@ class SettingsApi(generics.RetrieveUpdateAPIView):
'tencent': serializers.TencentSMSSettingSerializer,
}
rbac_category_permissions = {
# 'all': 'view_setting',
'basic': 'view_setting',
'terminal': 'change_terminal',
'security': 'change_security',
'ldap': 'change_auth',
'email': 'change_email',
'email_content': 'change_email',
'wecom': 'change_auth',
'dingtalk': 'change_auth',
'feishu': 'change_auth',
'auth': 'change_auth',
'oidc': 'change_auth',
'keycloak': 'change_auth',
'radius': 'change_auth',
'cas': 'change_auth',
'sso': 'change_auth',
'saml2': 'change_auth',
'clean': 'change_clean',
'other': 'change_other',
'sms': 'change_sms',
'alibaba': 'change_sms',
'tencent': 'change_sms',
}
def get_queryset(self):
return Setting.objects.all()
def check_permissions(self, request):
category = request.query_params.get('category', 'basic')
require_perm = self.rbac_category_permissions.get(category)
if not request.user.has_perm(require_perm):
self.permission_denied(request)
return super().check_permissions(request)
def get_serializer_class(self):
category = self.request.query_params.get('category', 'basic')
default = serializers.BasicSettingSerializer

View File

@ -12,6 +12,6 @@ class Migration(migrations.Migration):
operations = [
migrations.AlterModelOptions(
name='setting',
options={'permissions': [('change_basic', 'Can change basic setting'), ('change_email', 'Can change email setting'), ('change_auth', 'Can change auth setting'), ('change_sms', 'Can change sms setting'), ('change_security', 'Can change security setting'), ('change_clean', 'Can change clean setting'), ('change_other', 'Can change other setting'), ('change_terminal_basic_setting', 'Can change terminal basic setting')], 'verbose_name': 'System setting'},
options={'permissions': [('change_email', 'Can change email setting'), ('change_auth', 'Can change auth setting'), ('change_systemmsgsubscription', 'Can sys msg sub setting'), ('change_sms', 'Can change sms setting'), ('change_security', 'Can change security setting'), ('change_clean', 'Can change clean setting'), ('change_interface', 'Can change interface setting'), ('change_license', 'Can change license setting'), ('change_terminal', 'Can change terminal setting'), ('change_other', 'Can change other setting')], 'verbose_name': 'System setting'},
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 3.1.14 on 2022-03-10 11:52
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('settings', '0005_auto_20220310_0616'),
]
operations = [
migrations.AlterModelOptions(
name='setting',
options={'permissions': [('change_basic', 'Can change basic setting'), ('change_email', 'Can change email setting'), ('change_auth', 'Can change auth setting'), ('change_sms', 'Can change sms setting'), ('change_security', 'Can change security setting'), ('change_clean', 'Can change clean setting'), ('change_other', 'Can change other setting'), ('change_interface', 'Can change interface setting'), ('change_license', 'Can change license setting'), ('change_terminal_basic_setting', 'Can change terminal basic setting')], 'verbose_name': 'System setting'},
),
]

View File

@ -1,17 +0,0 @@
# Generated by Django 3.1.14 on 2022-03-10 12:06
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('settings', '0006_auto_20220310_1952'),
]
operations = [
migrations.AlterModelOptions(
name='setting',
options={'permissions': [('change_basic', 'Can change basic setting'), ('change_email', 'Can change email setting'), ('change_auth', 'Can change auth setting'), ('change_sys_msg_sub', 'Can sys msg sub setting'), ('change_sms', 'Can change sms setting'), ('change_security', 'Can change security setting'), ('change_clean', 'Can change clean setting'), ('change_interface', 'Can change interface setting'), ('change_license', 'Can change license setting'), ('change_terminal', 'Can change terminal setting'), ('change_other', 'Can change other setting')], 'verbose_name': 'System setting'},
),
]

View File

@ -139,7 +139,6 @@ class Setting(models.Model):
db_table = "settings_setting"
verbose_name = _("System setting")
permissions = [
('change_basic', _('Can change basic setting')),
('change_email', _('Can change email setting')),
('change_auth', _('Can change auth setting')),
('change_systemmsgsubscription', _('Can sys msg sub setting')),

View File

@ -41,7 +41,6 @@ class BasicSettingSerializer(serializers.Serializer):
required=False, max_length=1024, allow_blank=True, allow_null=True, label=_("Global organization name"),
help_text=_('The name of global organization to display')
)
TICKETS_ENABLED = serializers.BooleanField(required=False, default=True, label=_("Enable tickets"))
ANNOUNCEMENT_ENABLED = serializers.BooleanField(label=_('Enable announcement'), default=True)
ANNOUNCEMENT = AnnouncementSerializer(label=_("Announcement"))

View File

@ -4,6 +4,7 @@
from rest_framework import viewsets, mixins
from common.exceptions import JMSException
from common.utils import lazyproperty
from rbac.permissions import RBACPermission
from tickets import serializers
from tickets.models import Ticket
from tickets.permissions.comment import IsAssignee, IsApplicant, IsSwagger
@ -14,7 +15,7 @@ __all__ = ['CommentViewSet']
class CommentViewSet(mixins.CreateModelMixin, viewsets.ReadOnlyModelViewSet):
serializer_class = serializers.CommentSerializer
permission_classes = (IsSwagger | IsAssignee | IsApplicant,)
permission_classes = (RBACPermission| IsSwagger | IsAssignee | IsApplicant)
@lazyproperty
def ticket(self):

View File

@ -19,7 +19,6 @@ __all__ = ['TicketViewSet', 'TicketFlowViewSet']
class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
permission_classes = (IsValidUser,)
serializer_class = serializers.TicketDisplaySerializer
serializer_classes = {
'open': serializers.TicketApplySerializer,

View File

@ -5,12 +5,13 @@ from django.db.models import F
from common.drf.api import JMSBulkRelationModelViewSet
from .. import serializers
from ..models import User
from ..models import User, UserGroup
__all__ = ['UserUserGroupRelationViewSet']
class UserUserGroupRelationViewSet(JMSBulkRelationModelViewSet):
perm_model = UserGroup
filterset_fields = ('user', 'usergroup')
search_fields = filterset_fields
serializer_class = serializers.UserUserGroupRelationSerializer

View File

@ -53,9 +53,11 @@ def clean_db_content_types():
('applications', 'remoteapp', 'view_remoteapp'),
('settings', 'setting', 'change_terminal_basic_setting'),
('rbac', 'menupermission', 'view_resourcestatistics'),
('settings', 'setting', 'change_sys_msg_sub'),
('settings', 'setting', 'change_basic'),
('rbac', 'menupermission', 'view_userview'),
('rbac', 'menupermission', 'view_adminview'),
('rbac', 'menupermission', 'view_auditview'),
]
for app, model, codename in permissions_delete_required:
print('delete {}.{} ({})'.format(app, codename, model))