Merge pull request #7888 from jumpserver/dev

v2.20.0-rc5
pull/7919/head
Jiangjie.Bai 2022-03-16 20:49:53 +08:00 committed by GitHub
commit 91a34d1a88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 339 additions and 180 deletions

View File

@ -28,7 +28,7 @@ class ApplicationViewSet(SuggestionMixin, OrgBulkModelViewSet):
}
rbac_perms = {
'get_tree': 'applications.view_application',
'match': 'assets.match_application'
'match': 'applications.match_application'
}
@action(methods=['GET'], detail=False, url_path='tree')

View File

@ -0,0 +1,18 @@
# Generated by Django 3.1.14 on 2022-03-16 12:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('applications', '0019_auto_20220310_1853'),
]
operations = [
migrations.AlterField(
model_name='application',
name='type',
field=models.CharField(choices=[('mysql', 'MySQL'), ('mariadb', 'MariaDB'), ('oracle', 'Oracle'), ('postgresql', 'PostgreSQL'), ('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'),
),
]

View File

@ -205,6 +205,9 @@ class AssetGatewayListApi(generics.ListAPIView):
class BaseAssetPermUserOrUserGroupListApi(ListAPIView):
rbac_perms = {
'GET': 'assets.view_asset'
}
def get_object(self):
asset_id = self.kwargs.get('pk')
@ -222,6 +225,9 @@ class AssetPermUserListApi(BaseAssetPermUserOrUserGroupListApi):
filterset_class = UserFilter
search_fields = ('username', 'email', 'name', 'id', 'source', 'role')
serializer_class = UserSerializer
rbac_perms = {
'GET': 'assets.view_asset'
}
def get_queryset(self):
perms = self.get_asset_related_perms()

View File

@ -132,7 +132,7 @@ class CommandExecutionHostRelationViewSet(OrgRelationMixin, OrgBulkModelViewSet)
search_fields = ('asset__hostname', )
http_method_names = ['options', 'get']
rbac_perms = {
'GET': 'audits.view_commandexecution'
'GET': 'ops.view_commandexecution'
}
def get_queryset(self):

View File

@ -83,6 +83,6 @@ class SSOViewSet(AuthMixin, JMSGenericViewSet):
return HttpResponseRedirect(next_url)
user = token.user
login(self.request, user, 'authentication.backends.api.SSOAuthentication')
login(self.request, user, settings.AUTH_BACKEND_SSO)
self.send_auth_signal(success=True, user=user)
return HttpResponseRedirect(next_url)

View File

@ -22,8 +22,10 @@ class JMSBaseAuthBackend:
Reject users with is_valid=False. Custom user models that don't have
that attribute are allowed.
"""
is_valid = getattr(user, 'is_valid', None)
return is_valid or is_valid is None
# 在 check_user_auth 中进行了校验,可以返回对应的错误信息
# is_valid = getattr(user, 'is_valid', None)
# return is_valid or is_valid is None
return True
# allow user to authenticate
def username_allow_authenticate(self, username):

View File

@ -1,9 +1,9 @@
from django.conf import settings
from .base import JMSBaseAuthBackend
from .base import JMSModelBackend
class SSOAuthentication(JMSBaseAuthBackend):
class SSOAuthentication(JMSModelBackend):
"""
什么也不做呀😺
"""
@ -16,7 +16,7 @@ class SSOAuthentication(JMSBaseAuthBackend):
pass
class WeComAuthentication(JMSBaseAuthBackend):
class WeComAuthentication(JMSModelBackend):
"""
什么也不做呀😺
"""
@ -29,7 +29,7 @@ class WeComAuthentication(JMSBaseAuthBackend):
pass
class DingTalkAuthentication(JMSBaseAuthBackend):
class DingTalkAuthentication(JMSModelBackend):
"""
什么也不做呀😺
"""
@ -42,7 +42,7 @@ class DingTalkAuthentication(JMSBaseAuthBackend):
pass
class FeiShuAuthentication(JMSBaseAuthBackend):
class FeiShuAuthentication(JMSModelBackend):
"""
什么也不做呀😺
"""
@ -55,7 +55,7 @@ class FeiShuAuthentication(JMSBaseAuthBackend):
pass
class AuthorizationTokenAuthentication(JMSBaseAuthBackend):
class AuthorizationTokenAuthentication(JMSModelBackend):
"""
什么也不做呀😺
"""

View File

@ -32,6 +32,7 @@ class SimpleMetadataWithFilters(SimpleMetadata):
the fields that are accepted for 'PUT' and 'POST' methods.
"""
actions = {}
view.raw_action = getattr(view, 'action', None)
for method in self.methods & set(view.allowed_methods):
if hasattr(view, 'action_map'):
view.action = view.action_map.get(method.lower(), view.action)

View File

@ -14,9 +14,9 @@ __all__ = ['celery_flower_view']
@csrf_exempt
def celery_flower_view(request, path):
if not request.user.is_superuser:
if not request.user.has_perm('ops.view_taskmonitor'):
return HttpResponse("Forbidden")
remote_url = 'http://{}/{}'.format(flower_url, path)
remote_url = 'http://{}/core/flower/{}'.format(flower_url, path)
try:
response = proxy_view(request, remote_url)
except Exception as e:

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a8c1155ea28b70a0eb06aa39ab6ae04619cd30d02f59698fadaa6068d91a7900
size 104348
oid sha256:f529bbca004aeba7532d9faf50f6f8ab5532b19bf0afd650f8360f418c03c15c
size 104629

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-03-15 19:46+0800\n"
"POT-Creation-Date: 2022-03-16 20:38+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n"
@ -22,11 +22,11 @@ msgid "Acls"
msgstr "访问控制"
#: acls/models/base.py:25 acls/serializers/login_asset_acl.py:47
#: applications/models/application.py:202 assets/models/asset.py:138
#: applications/models/application.py:209 assets/models/asset.py:138
#: assets/models/base.py:175 assets/models/cluster.py:18
#: assets/models/cmd_filter.py:27 assets/models/domain.py:23
#: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24
#: orgs/models.py:12 perms/models/base.py:83 rbac/models/role.py:29
#: orgs/models.py:65 perms/models/base.py:83 rbac/models/role.py:29
#: settings/models.py:29 settings/serializers/sms.py:6
#: terminal/models/storage.py:23 terminal/models/task.py:16
#: terminal/models/terminal.py:100 users/forms/profile.py:32
@ -56,13 +56,13 @@ msgstr "优先级可选范围为 1-100 (数值越小越优先)"
msgid "Active"
msgstr "激活中"
#: acls/models/base.py:32 applications/models/application.py:215
#: acls/models/base.py:32 applications/models/application.py:222
#: assets/models/asset.py:143 assets/models/asset.py:231
#: assets/models/backup.py:54 assets/models/base.py:180
#: assets/models/cluster.py:29 assets/models/cmd_filter.py:48
#: assets/models/cmd_filter.py:96 assets/models/domain.py:24
#: assets/models/domain.py:64 assets/models/group.py:23
#: assets/models/label.py:23 ops/models/adhoc.py:38 orgs/models.py:15
#: assets/models/label.py:23 ops/models/adhoc.py:38 orgs/models.py:68
#: perms/models/base.py:93 rbac/models/role.py:37 settings/models.py:34
#: terminal/models/storage.py:26 terminal/models/terminal.py:114
#: tickets/models/comment.py:24 tickets/models/ticket.py:154
@ -89,13 +89,13 @@ msgstr "登录复核"
#: acls/models/login_acl.py:24 acls/models/login_asset_acl.py:20
#: assets/models/cmd_filter.py:30 assets/models/label.py:15 audits/models.py:37
#: audits/models.py:60 audits/models.py:85 audits/serializers.py:100
#: authentication/models.py:50 orgs/models.py:196 perms/models/base.py:84
#: rbac/builtin.py:97 rbac/models/rolebinding.py:35 templates/index.html:78
#: authentication/models.py:50 orgs/models.py:214 perms/models/base.py:84
#: rbac/builtin.py:97 rbac/models/rolebinding.py:39 templates/index.html:78
#: terminal/backends/command/models.py:19
#: terminal/backends/command/serializers.py:12 terminal/models/session.py:42
#: terminal/notifications.py:88 terminal/notifications.py:136
#: tickets/models/comment.py:17 users/const.py:14 users/models/user.py:793
#: users/models/user.py:824 users/serializers/group.py:19
#: tickets/models/comment.py:17 users/const.py:14 users/models/user.py:795
#: users/models/user.py:826 users/serializers/group.py:19
#: users/templates/users/user_asset_permission.html:38
#: users/templates/users/user_asset_permission.html:64
#: users/templates/users/user_database_app_permission.html:37
@ -254,7 +254,7 @@ msgstr "时段"
msgid "My applications"
msgstr "我的应用"
#: applications/apps.py:9 applications/models/application.py:60
#: applications/apps.py:9 applications/models/application.py:61
msgid "Applications"
msgstr "应用管理"
@ -269,11 +269,11 @@ msgstr "数据库"
msgid "Remote app"
msgstr "远程应用"
#: applications/const.py:31
#: applications/const.py:35
msgid "Custom"
msgstr "自定义"
#: applications/models/account.py:12 applications/models/application.py:219
#: applications/models/account.py:12 applications/models/application.py:226
#: assets/models/backup.py:32 assets/models/cmd_filter.py:45
#: perms/models/application_permission.py:28
msgid "Application"
@ -313,7 +313,7 @@ msgstr "可以查看应用账号密码"
msgid "Can change application account secret"
msgstr "可以查看应用账号密码"
#: applications/models/application.py:204
#: applications/models/application.py:211
#: applications/serializers/application.py:99 assets/models/label.py:21
#: perms/models/application_permission.py:21
#: perms/serializers/application/user_permission.py:33
@ -322,7 +322,7 @@ msgstr "可以查看应用账号密码"
msgid "Category"
msgstr "类别"
#: applications/models/application.py:207
#: applications/models/application.py:214
#: applications/serializers/application.py:101 assets/models/backup.py:49
#: assets/models/cmd_filter.py:82 assets/models/user.py:233
#: perms/models/application_permission.py:24
@ -335,20 +335,20 @@ msgstr "类别"
msgid "Type"
msgstr "类型"
#: applications/models/application.py:211 assets/models/asset.py:217
#: applications/models/application.py:218 assets/models/asset.py:217
#: assets/models/domain.py:29 assets/models/domain.py:63
msgid "Domain"
msgstr "网域"
#: applications/models/application.py:213 xpack/plugins/cloud/models.py:33
#: applications/models/application.py:220 xpack/plugins/cloud/models.py:33
msgid "Attrs"
msgstr "属性"
#: applications/models/application.py:223
#: applications/models/application.py:230
msgid "Can match application"
msgstr "匹配应用"
#: applications/models/application.py:271
#: applications/models/application.py:278
msgid "Application user"
msgstr "应用用户"
@ -375,8 +375,8 @@ msgstr "类型名称"
#: assets/models/group.py:22 assets/models/label.py:25
#: assets/serializers/account.py:18 common/db/models.py:113
#: common/mixins/models.py:50 ops/models/adhoc.py:39 ops/models/command.py:30
#: orgs/models.py:14 orgs/models.py:199 perms/models/base.py:92
#: users/models/group.py:18 users/models/user.py:825
#: orgs/models.py:67 orgs/models.py:217 perms/models/base.py:92
#: users/models/group.py:18 users/models/user.py:827
#: xpack/plugins/cloud/models.py:125
msgid "Date created"
msgstr "创建日期"
@ -384,7 +384,7 @@ msgstr "创建日期"
#: applications/serializers/application.py:104 assets/models/base.py:182
#: assets/models/gathered_user.py:20 assets/serializers/account.py:21
#: common/db/models.py:114 common/mixins/models.py:51 ops/models/adhoc.py:40
#: orgs/models.py:200
#: orgs/models.py:218
msgid "Date updated"
msgstr "更新日期"
@ -626,8 +626,8 @@ msgstr "标签管理"
#: assets/models/asset.py:229 assets/models/base.py:183
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:52
#: assets/models/cmd_filter.py:99 assets/models/group.py:21
#: common/db/models.py:111 common/mixins/models.py:49 orgs/models.py:13
#: orgs/models.py:201 perms/models/base.py:91 users/models/user.py:619
#: common/db/models.py:111 common/mixins/models.py:49 orgs/models.py:66
#: orgs/models.py:219 perms/models/base.py:91 users/models/user.py:619
#: users/serializers/group.py:33
#: xpack/plugins/change_auth_plan/models/base.py:48
#: xpack/plugins/cloud/models.py:122 xpack/plugins/gathered_user/models.py:30
@ -834,7 +834,7 @@ msgid "Default"
msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:14 rbac/const.py:6
#: users/models/user.py:810
#: users/models/user.py:812
msgid "System"
msgstr "系统"
@ -1255,6 +1255,7 @@ msgid "System user name"
msgstr "系统用户名称"
#: assets/serializers/system_user.py:282 orgs/mixins/serializers.py:26
#: rbac/serializers/rolebinding.py:23
msgid "Org name"
msgstr "组织名称"
@ -1383,7 +1384,7 @@ msgstr "日志审计"
#: audits/models.py:27 audits/models.py:57
#: authentication/templates/authentication/_access_key_modal.html:65
#: rbac/tree.py:158 users/templates/users/user_asset_permission.html:128
#: rbac/tree.py:162 users/templates/users/user_asset_permission.html:128
#: users/templates/users/user_database_app_permission.html:111
msgid "Delete"
msgstr "删除"
@ -1437,11 +1438,11 @@ msgstr "文件管理"
#: audits/models.py:55
#: authentication/templates/authentication/_access_key_modal.html:22
#: rbac/tree.py:155
#: rbac/tree.py:159
msgid "Create"
msgstr "创建"
#: audits/models.py:56 rbac/tree.py:157 templates/_csv_import_export.html:18
#: audits/models.py:56 rbac/tree.py:161 templates/_csv_import_export.html:18
#: templates/_csv_update_modal.html:6
#: users/templates/users/user_asset_permission.html:127
#: users/templates/users/user_database_app_permission.html:110
@ -1565,7 +1566,7 @@ msgstr "运行用户"
msgid "Run as display"
msgstr "运行用户名称"
#: audits/serializers.py:102 rbac/serializers/rolebinding.py:22
#: audits/serializers.py:102 rbac/serializers/rolebinding.py:21
msgid "User display"
msgstr "用户名称"
@ -2804,7 +2805,7 @@ msgstr "汇总"
#: ops/models/adhoc.py:339
msgid "AdHoc execution"
msgstr "任务执行历史"
msgstr "任务执行"
#: ops/models/command.py:32
msgid "Date finished"
@ -2878,25 +2879,25 @@ msgstr "当前组织 ({}) 不能被删除"
msgid "The organization have resource ({}) cannot be deleted"
msgstr "组织存在资源 ({}) 不能被删除"
#: orgs/apps.py:7 rbac/tree.py:111
#: orgs/apps.py:7 rbac/tree.py:110
msgid "App organizations"
msgstr "组织管理"
#: orgs/mixins/models.py:46 orgs/mixins/serializers.py:25 orgs/models.py:27
#: orgs/models.py:193 rbac/const.py:7 rbac/models/rolebinding.py:42
#: orgs/mixins/models.py:46 orgs/mixins/serializers.py:25 orgs/models.py:80
#: orgs/models.py:211 rbac/const.py:7 rbac/models/rolebinding.py:46
#: rbac/serializers/rolebinding.py:40 tickets/serializers/ticket/ticket.py:77
msgid "Organization"
msgstr "组织"
#: orgs/models.py:21
#: orgs/models.py:74
msgid "GLOBAL"
msgstr "全局组织"
#: orgs/models.py:29
#: orgs/models.py:82
msgid "Can view root org"
msgstr "可以查看全局组织"
#: orgs/models.py:198 rbac/models/role.py:46 rbac/models/rolebinding.py:38
#: orgs/models.py:216 rbac/models/role.py:46 rbac/models/rolebinding.py:42
#: users/models/user.py:584 users/templates/users/_select_user_modal.html:15
msgid "Role"
msgstr "角色"
@ -3111,17 +3112,17 @@ msgstr "如果有疑问或需求,请联系系统管理员"
#: rbac/api/role.py:32
msgid "Internal role, can't be destroy"
msgstr ""
msgstr "内部角色,不能删除"
#: rbac/api/role.py:36
msgid "The role has been bound to users, can't be destroy"
msgstr ""
msgstr "角色已绑定用户,不能删除"
#: rbac/api/role.py:43
msgid "Internal role, can't be update"
msgstr ""
msgstr "内部角色,不能更新"
#: rbac/api/rolebinding.py:46
#: rbac/api/rolebinding.py:52
msgid "{} at least one system role"
msgstr "{} 至少有一个系统角色"
@ -3129,27 +3130,27 @@ msgstr "{} 至少有一个系统角色"
msgid "RBAC"
msgstr "RBAC"
#: rbac/builtin.py:88
#: rbac/builtin.py:89
msgid "SystemAdmin"
msgstr "系统管理员"
#: rbac/builtin.py:91
#: rbac/builtin.py:92
msgid "SystemAuditor"
msgstr "系统审计员"
#: rbac/builtin.py:94
#: rbac/builtin.py:95
msgid "SystemComponent"
msgstr "系统组件"
#: rbac/builtin.py:100
#: rbac/builtin.py:101
msgid "OrgAdmin"
msgstr "组织管理员"
#: rbac/builtin.py:103
#: rbac/builtin.py:104
msgid "OrgAuditor"
msgstr "组织审计员"
#: rbac/builtin.py:106
#: rbac/builtin.py:107
msgid "OrgUser"
msgstr "组织用户"
@ -3179,9 +3180,9 @@ msgstr "文件管理"
#: rbac/models/permission.py:26
msgid "Permission"
msgstr "权"
msgstr "权"
#: rbac/models/role.py:31 rbac/models/rolebinding.py:32
#: rbac/models/role.py:31 rbac/models/rolebinding.py:36
msgid "Scope"
msgstr "范围"
@ -3201,21 +3202,21 @@ msgstr "系统角色"
msgid "Organization role"
msgstr "组织角色"
#: rbac/models/rolebinding.py:47
#: rbac/models/rolebinding.py:51
msgid "Role binding"
msgstr "角色绑定"
#: rbac/models/rolebinding.py:113
#: rbac/models/rolebinding.py:123
msgid ""
"User last role in org, can not be delete, you can remove user from org "
"instead"
msgstr "用户最后一个角色,不能删除,你可以将用户从组织移除"
#: rbac/models/rolebinding.py:120
#: rbac/models/rolebinding.py:130
msgid "Organization role binding"
msgstr "组织角色绑定"
#: rbac/models/rolebinding.py:134
#: rbac/models/rolebinding.py:145
msgid "System role binding"
msgstr "系统角色绑定"
@ -3231,7 +3232,7 @@ msgstr "范围名称"
msgid "Display name"
msgstr "显示名称"
#: rbac/serializers/rolebinding.py:23
#: rbac/serializers/rolebinding.py:22
msgid "Role display"
msgstr "角色显示"
@ -3239,79 +3240,91 @@ msgstr "角色显示"
msgid "Has bound this role"
msgstr "已经绑定"
#: rbac/tree.py:17 rbac/tree.py:18
#: rbac/tree.py:16 rbac/tree.py:17
msgid "All permissions"
msgstr "所有权限"
#: rbac/tree.py:24
#: rbac/tree.py:23
msgid "Console view"
msgstr "控制台"
#: rbac/tree.py:25
#: rbac/tree.py:24
msgid "Workspace view"
msgstr "工作台"
#: rbac/tree.py:26
#: rbac/tree.py:25
msgid "Audit view"
msgstr "审计台"
#: rbac/tree.py:27 settings/models.py:140
#: rbac/tree.py:26 settings/models.py:140
msgid "System setting"
msgstr "系统设置"
#: rbac/tree.py:28
#: rbac/tree.py:27
msgid "Other"
msgstr "其它"
#: rbac/tree.py:36
#: rbac/tree.py:35
msgid "Accounts"
msgstr "账号管理"
#: rbac/tree.py:40
#: rbac/tree.py:39
msgid "Session audits"
msgstr "会话审计"
#: rbac/tree.py:50
#: rbac/tree.py:49
msgid "Cloud import"
msgstr "云同步"
#: rbac/tree.py:51
#: rbac/tree.py:50
msgid "Backup account"
msgstr "备份账号"
#: rbac/tree.py:52
#: rbac/tree.py:51
msgid "Gather account"
msgstr "收集账号"
#: rbac/tree.py:53
#: rbac/tree.py:52
msgid "App change auth"
msgstr "应用改密"
#: rbac/tree.py:54
#: rbac/tree.py:53
msgid "Asset change auth"
msgstr "资产改密"
#: rbac/tree.py:55
#: rbac/tree.py:54
msgid "Terminal setting"
msgstr "终端设置"
#: rbac/tree.py:56
#: rbac/tree.py:55
msgid "My assets"
msgstr "我的资产"
#: rbac/tree.py:57
#: rbac/tree.py:56
msgid "My apps"
msgstr "我的应用"
#: rbac/tree.py:112
#: rbac/tree.py:111
msgid "Ticket comment"
msgstr "工单评论"
#: rbac/tree.py:112 tickets/models/ticket.py:163
msgid "Ticket"
msgstr "工单管理"
#: rbac/tree.py:113
msgid "Common setting"
msgstr "一般设置"
#: rbac/tree.py:156
#: rbac/tree.py:115
msgid "View permission tree"
msgstr "查看授权树"
#: rbac/tree.py:116
msgid "Execute batch command"
msgstr "执行批量命令"
#: rbac/tree.py:160
msgid "View"
msgstr "查看"
@ -5363,10 +5376,6 @@ msgstr "流程"
msgid "TicketFlow"
msgstr "工单流程"
#: tickets/models/ticket.py:163
msgid "Ticket"
msgstr "工单管理"
#: tickets/models/ticket.py:311
msgid "Please try again"
msgstr "请再次尝试"
@ -5674,27 +5683,27 @@ msgstr "最后更新密码日期"
msgid "Need update password"
msgstr "需要更新密码"
#: users/models/user.py:795
#: users/models/user.py:797
msgid "Can invite user"
msgstr "可以邀请用户"
#: users/models/user.py:796
#: users/models/user.py:798
msgid "Can remove user"
msgstr "可以移除用户"
#: users/models/user.py:797
#: users/models/user.py:799
msgid "Can match user"
msgstr "可以匹配用户"
#: users/models/user.py:806
#: users/models/user.py:808
msgid "Administrator"
msgstr "管理员"
#: users/models/user.py:809
#: users/models/user.py:811
msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员"
#: users/models/user.py:834
#: users/models/user.py:836
msgid "User password history"
msgstr "用户密码历史"
@ -6177,7 +6186,7 @@ msgstr "重置密码成功,返回到登录页面"
msgid "XPACK"
msgstr ""
#: xpack/plugins/change_auth_plan/api/app.py:109
#: xpack/plugins/change_auth_plan/api/app.py:112
#: xpack/plugins/change_auth_plan/api/asset.py:95
msgid "The parameter 'action' must be [{}]"
msgstr "参数 'action' 必须是 [{}]"
@ -6835,6 +6844,21 @@ msgstr "旗舰版"
msgid "Community edition"
msgstr "社区版"
#, fuzzy
#~| msgid "Create"
#~ msgid "create"
#~ msgstr "创建"
#, fuzzy
#~| msgid "Update"
#~ msgid "update"
#~ msgstr "更新"
#, fuzzy
#~| msgid "Delete"
#~ msgid "delete"
#~ msgstr "删除"
#~ msgid "Can connect my assets"
#~ msgstr "可以连接我的资产"
@ -7012,9 +7036,6 @@ msgstr "社区版"
#~ msgid "Overview"
#~ msgstr "概览"
#~ msgid "View permission user"
#~ msgstr "查看授权用户"
#~ msgid "Add user to role"
#~ msgstr "添加用户到角色"

View File

@ -42,6 +42,9 @@ class TaskViewSet(OrgBulkModelViewSet):
class TaskRun(generics.RetrieveAPIView):
queryset = Task.objects.all()
serializer_class = CeleryTaskSerializer
rbac_perms = {
'retrieve': 'ops.add_adhoc'
}
def retrieve(self, request, *args, **kwargs):
task = self.get_object()

View File

@ -7,7 +7,60 @@ from common.utils import lazyproperty, settings
from common.tree import TreeNode
class Organization(models.Model):
class OrgRoleMixin:
members: models.Manager
def get_members(self):
return self.members.all().distinct()
def add_member(self, user, role=None):
from rbac.builtin import BuiltinRole
from .utils import tmp_to_org
role_id = BuiltinRole.org_user.id
if role:
role_id = role.id
with tmp_to_org(self):
defaults = {
'user': user, 'role_id': role_id,
'org_id': self.id, 'scope': 'org'
}
self.members.through.objects.update_or_create(**defaults, defaults=defaults)
def get_origin_role_members(self, role_name):
from rbac.models import OrgRoleBinding
from users.models import User
from rbac.builtin import BuiltinRole
from .utils import tmp_to_org
role_mapper = {
'user': BuiltinRole.org_user,
'auditor': BuiltinRole.org_auditor,
'admin': BuiltinRole.org_admin
}
assert role_name in role_mapper
role = role_mapper.get(role_name).get_role()
with tmp_to_org(self):
org_admins = OrgRoleBinding.get_role_users(role)
return org_admins
@property
def admins(self):
from users.models import User
admins = self.get_origin_role_members('admin')
if not admins:
admins = User.objects.filter(username='admin')
return admins
@property
def auditors(self):
return self.get_origin_role_members('auditor')
@property
def users(self):
return self.get_origin_role_members('user')
class Organization(OrgRoleMixin, models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, unique=True, verbose_name=_("Name"))
created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
@ -101,21 +154,6 @@ class Organization(models.Model):
from .caches import OrgResourceStatisticsCache
return OrgResourceStatisticsCache(self)
def get_members(self):
return self.members.all().distinct()
def add_member(self, user, role=None):
from rbac.builtin import BuiltinRole
from .utils import tmp_to_org
role_id = BuiltinRole.org_user.id
if role:
role_id = role.id
with tmp_to_org(self):
defaults = {
'user': user, 'role_id': role_id, 'org_id': self.id, 'scope': 'org'
}
self.members.through.objects.update_or_create(**defaults, defaults=defaults)
def get_total_resources_amount(self):
from django.apps import apps
from orgs.mixins.models import OrgModelMixin
@ -163,26 +201,6 @@ class Organization(models.Model):
return super().delete(*args, **kwargs)
# class OrgMemberManager(models.Manager):
# def remove_users(self, org, users):
# from users.models import User
# pk_set = []
# for user in users:
# if hasattr(user, 'pk'):
# pk_set.append(user.pk)
# else:
# pk_set.append(user)
#
# send = partial(
# signals.m2m_changed.send, sender=self.model,
# instance=org, reverse=False, model=User,
# pk_set=pk_set, using=self.db
# )
# send(action="pre_remove")
# self.filter(org_id=org.id, user_id__in=pk_set).delete()
# send(action="post_remove")
class OrganizationMember(models.Model):
"""
注意直接调用该 `Model.delete` `Model.objects.delete` 不会触发清理该用户的信号

View File

@ -0,0 +1,18 @@
# Generated by Django 3.1.14 on 2022-03-16 12:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('perms', '0027_auto_20220310_1802'),
]
operations = [
migrations.AlterField(
model_name='applicationpermission',
name='type',
field=models.CharField(choices=[('mysql', 'MySQL'), ('mariadb', 'MariaDB'), ('oracle', 'Oracle'), ('postgresql', 'PostgreSQL'), ('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'),
),
]

View File

@ -8,7 +8,10 @@ from common.exceptions import JMSException
from .. import serializers
from ..models import RoleBinding, SystemRoleBinding, OrgRoleBinding
__all__ = ['RoleBindingViewSet', 'SystemRoleBindingViewSet', 'OrgRoleBindingViewSet']
__all__ = [
'RoleBindingViewSet', 'SystemRoleBindingViewSet',
'OrgRoleBindingViewSet'
]
class RoleBindingViewSet(OrgBulkModelViewSet):
@ -23,8 +26,8 @@ class RoleBindingViewSet(OrgBulkModelViewSet):
]
def get_queryset(self):
queryset = super().get_queryset() \
.prefetch_related('user', 'role') \
queryset = self._get_queryset()\
.prefetch_related('user', 'role', 'org') \
.annotate(
user_display=Concat(
F('user__name'), Value('('),
@ -34,6 +37,9 @@ class RoleBindingViewSet(OrgBulkModelViewSet):
)
return queryset
def _get_queryset(self):
return super().get_queryset()
class SystemRoleBindingViewSet(RoleBindingViewSet):
model = SystemRoleBinding
@ -49,9 +55,11 @@ class SystemRoleBindingViewSet(RoleBindingViewSet):
class OrgRoleBindingViewSet(RoleBindingViewSet):
model = OrgRoleBinding
serializer_class = serializers.OrgRoleBindingSerializer
def _get_queryset(self):
return OrgRoleBinding.objects.root_all()
def perform_bulk_create(self, serializer):
validated_data = serializer.validated_data
bindings = [

View File

@ -12,6 +12,7 @@ user_perms = (
('assets', 'systemuser', 'match', 'systemuser'),
('assets', 'node', 'match', 'node'),
('ops', 'commandexecution', 'add', 'commandexecution'),
('authentication', 'connectiontoken', 'add', 'connectiontoken'),
)
auditor_perms = user_perms + (

View File

@ -24,7 +24,7 @@ exclude_permissions = (
('authentication', 'privatetoken', '*', '*'),
('authentication', 'accesskey', 'change,delete', 'accesskey'),
('authentication', 'connectiontoken', 'change,delete', 'connectiontoken'),
('authentication', 'ssotoken', 'change,delete', 'ssotoken'),
('authentication', 'ssotoken', '*', '*'),
('authentication', 'superconnectiontoken', 'change,delete', 'superconnectiontoken'),
('users', 'userpasswordhistory', '*', '*'),
('applications', 'applicationuser', '*', '*'),
@ -50,7 +50,7 @@ exclude_permissions = (
('rbac', 'rolebinding', '*', '*'),
('rbac', 'role', '*', '*'),
('ops', 'adhoc', 'delete,change', '*'),
('ops', 'adhocexecution', 'delete,change', '*'),
('ops', 'adhocexecution', 'add,delete,change', '*'),
('ops', 'celerytask', '*', '*'),
('ops', 'task', 'add,change', 'task'),
('ops', 'commandexecution', 'delete,change', 'commandexecution'),
@ -62,18 +62,19 @@ exclude_permissions = (
('audits', 'ftplog', 'change,delete', 'ftplog'),
('tickets', 'ticketassignee', '*', 'ticketassignee'),
('tickets', 'ticketflow', 'add,delete', 'ticketflow'),
('tickets', 'comment', 'change,delete', 'comment'),
('tickets', 'ticket', 'delete', 'ticket'),
('tickets', 'comment', '*', '*'),
('tickets', 'ticket', 'add,delete,change', 'ticket'),
('tickets', 'ticketstep', '*', '*'),
('tickets', 'approvalrule', '*', '*'),
('tickets', 'superticket', 'delete', 'superticket'),
('tickets', 'ticketsession', 'delete', 'ticketsession'),
('tickets', 'ticketsession', 'view,delete', 'ticketsession'),
('xpack', 'interface', '*', '*'),
('xpack', 'license', '*', '*'),
('xpack', 'syncinstancedetail', 'add,delete,change', 'syncinstancedetail'),
('xpack', 'syncinstancetaskexecution', 'delete,change', 'syncinstancetaskexecution'),
('xpack', 'changeauthplanexecution', 'delete,change', 'changeauthplanexecution'),
('xpack', 'changeauthplantask', 'add,delete', 'changeauthplantask'),
('xpack', 'gatherusertaskexecution', 'change,delete', 'gatherusertaskexecution'),
('common', 'permission', 'add,delete,view,change', 'permission'),
('terminal', 'command', 'delete,change', 'command'),
('terminal', 'status', 'delete,change', 'status'),
@ -102,7 +103,7 @@ only_system_permissions = (
('terminal', 'replaystorage', '*', '*'),
('terminal', 'status', '*', '*'),
('terminal', 'task', '*', '*'),
('tickets', 'ticketflow', '*', '*'),
('authentication', '*', '*', '*'),
)
only_org_permissions = (

View File

@ -15,14 +15,18 @@ __all__ = ['RoleBinding', 'SystemRoleBinding', 'OrgRoleBinding']
class RoleBindingManager(models.Manager):
def get_queryset(self):
queryset = super(RoleBindingManager, self).get_queryset()
q = Q(scope=Scope.system, org__isnull=True)
if not current_org.is_root():
q = Q(scope=Scope.system) | Q(org_id=current_org.id, scope=Scope.org)
else:
q = Q()
q |= Q(org_id=current_org.id, scope=Scope.org)
queryset = queryset.filter(q)
return queryset
def root_all(self):
queryset = super().get_queryset()
if current_org.is_root():
return queryset
return self.get_queryset()
class RoleBinding(JMSModel):
Scope = Scope
@ -55,6 +59,12 @@ class RoleBinding(JMSModel):
display += ' | {org}'.format(org=self.org)
return display
@property
def org_name(self):
if self.org:
return self.org.name
return ''
def save(self, *args, **kwargs):
self.scope = self.role.scope
return super().save(*args, **kwargs)
@ -67,7 +77,7 @@ class RoleBinding(JMSModel):
@classmethod
def get_role_users(cls, role):
from users.models import User
bindings = cls.objects.filter(role=role, scope=role.scope)
bindings = cls.objects.root_all().filter(role=role, scope=role.scope)
user_ids = bindings.values_list('user', flat=True).distinct()
return User.objects.filter(id__in=user_ids)
@ -86,13 +96,13 @@ class RoleBinding(JMSModel):
return self.role.display_name
class OrgRoleBindingManager(models.Manager):
class OrgRoleBindingManager(RoleBindingManager):
def get_queryset(self):
queryset = super().get_queryset()
queryset = super(RoleBindingManager, self).get_queryset()
if current_org.is_root():
queryset = queryset.filter(scope=Scope.org)
queryset = queryset.none()
else:
queryset = queryset.filter(org=current_org.id, scope=Scope.org)
queryset = queryset.filter(org_id=current_org.id, scope=Scope.org)
return queryset
@ -120,9 +130,10 @@ class OrgRoleBinding(RoleBinding):
verbose_name = _('Organization role binding')
class SystemRoleBindingManager(models.Manager):
class SystemRoleBindingManager(RoleBindingManager):
def get_queryset(self):
queryset = super().get_queryset().filter(scope=Scope.system)
queryset = super(RoleBindingManager, self).get_queryset()\
.filter(scope=Scope.system)
return queryset

View File

@ -54,6 +54,7 @@ class RBACPermission(permissions.DjangoModelPermissions):
def get_default_action_perms(self, model_cls):
if model_cls is None:
return {}
perms = {}
for action, tmpl in dict(self.default_rbac_perms_tmpl).items():
perms[action] = self.format_perms(tmpl, model_cls)
@ -62,20 +63,25 @@ class RBACPermission(permissions.DjangoModelPermissions):
def get_rbac_perms(self, view, model_cls) -> dict:
if hasattr(view, 'get_rbac_perms'):
return dict(view.get_rbac_perms())
perms = self.get_default_action_perms(model_cls)
perms = {}
if hasattr(view, 'rbac_perms'):
perms.update(dict(view.rbac_perms))
if '*' not in perms:
perms.update(self.get_default_action_perms(model_cls))
return perms
def _get_action_perms(self, action, model_cls, view):
action_perms_map = self.get_rbac_perms(view, model_cls)
if action not in action_perms_map:
if action in action_perms_map:
perms = action_perms_map[action]
elif '*' in action_perms_map:
perms = action_perms_map['*']
else:
msg = 'Action not allowed: {}, only `{}` supported'.format(
action, ','.join(list(action_perms_map.keys()))
)
logger.error(msg)
raise exceptions.PermissionDenied(msg)
perms = action_perms_map[action]
return perms
def get_model_cls(self, view):
@ -96,7 +102,6 @@ class RBACPermission(permissions.DjangoModelPermissions):
:param view:
:return:
"""
model_cls = self.get_model_cls(view)
action = getattr(view, 'action', None)
if not action:
@ -114,8 +119,8 @@ class RBACPermission(permissions.DjangoModelPermissions):
if request.user.is_anonymous and self.authenticated_users_only:
return False
action = getattr(view, 'action', None)
if action == 'metadata':
raw_action = getattr(view, 'raw_action', None)
if raw_action == 'metadata':
return True
perms = self.get_require_perms(request, view)

View File

@ -2,7 +2,6 @@ from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from orgs.serializers import CurrentOrgDefault
from orgs.utils import current_org
from ..models import RoleBinding, SystemRoleBinding, OrgRoleBinding
__all__ = [
@ -15,12 +14,13 @@ class RoleBindingSerializer(serializers.ModelSerializer):
model = RoleBinding
fields = [
'id', 'user', 'user_display', 'role', 'role_display',
'scope', 'org',
'scope', 'org', 'org_name',
]
read_only_fields = ['scope']
extra_kwargs = {
'user_display': {'label': _('User display')},
'role_display': {'label': _('Role display')},
'org_name': {'label': _("Org name")}
}

View File

@ -2,11 +2,10 @@
from collections import defaultdict
from typing import Callable
from django.utils.translation import gettext_lazy as _, gettext
from django.utils.translation import gettext_lazy as _, gettext, get_language
from django.conf import settings
from django.apps import apps
from django.db.models import F, Count
from django.utils.translation import ugettext
from common.tree import TreeNode
from .models import Permission, ContentType
@ -104,19 +103,24 @@ special_pid_mapper = {
"rbac.view_workspace": "view_workspace",
"rbac.view_webterminal": "view_workspace",
"rbac.view_filemanager": "view_workspace",
'tickets.view_ticket': 'tickets'
}
verbose_name_mapper = {
'orgs.organization': _("App organizations"),
'tickets.comment': _("Ticket comment"),
'tickets.view_ticket': _("Ticket"),
'settings.setting': _("Common setting"),
'rbac.view_permission': _('View permission tree'),
'ops.add_commandexecution': _('Execute batch command')
}
xpack_nodes = [
'xpack', 'tickets', 'applications.remoteapp',
"assets.accountbackupplan", "assets.accountbackupplanexecution",
"rbac.orgrole", "rbac.orgrolebinding",
"settings.change_interface",
"settings.change_interface", 'assets.gathereduser',
'gather_account_node'
]
@ -151,10 +155,10 @@ def sort_nodes(node):
class PermissionTreeUtil:
get_permissions: Callable
action_mapper = {
'add': ugettext('Create'),
'view': ugettext('View'),
'change': ugettext('Update'),
'delete': ugettext('Delete')
'add': _('Create'),
'view': _('View'),
'change': _('Update'),
'delete': _('Delete')
}
action_icon = {
'add': 'add',
@ -174,6 +178,7 @@ class PermissionTreeUtil:
self.check_disabled = check_disabled
self.total_counts = defaultdict(int)
self.checked_counts = defaultdict(int)
self.lang = get_language()
@staticmethod
def prefetch_permissions(perms):
@ -278,14 +283,24 @@ class PermissionTreeUtil:
def _get_permission_name_icon(self, p: Permission, content_types_name_mapper: dict):
action, resource = p.codename.split('_', 1)
icon = self.action_icon.get(action, 'file')
name = verbose_name_mapper.get(p.app_label_codename)
if name:
return name, icon
app_model = '%s.%s' % (p.content_type.app_label, resource)
if action in self.action_mapper and app_model in content_types_name_mapper:
if self.lang == 'en':
name = p.name
# 因为默认的权限位是没有翻译的,所以我们要用 action + resource name 去拼
elif action in self.action_mapper and app_model in content_types_name_mapper:
action_name = self.action_mapper[action]
name = action_name + content_types_name_mapper[app_model]
resource_name = content_types_name_mapper[app_model]
sep = ''
name = '{}{}{}'.format(action_name, sep, resource_name)
# 手动创建的 permission
else:
name = gettext(p.name)
icon = self.action_icon.get(action, 'file')
name = name.replace('Can ', '').replace('可以', '')
name = name.replace('Can ', '').replace('可以', '').capitalize()
return name, icon
def _create_perms_nodes(self):

View File

@ -64,7 +64,7 @@ class SessionViewSet(OrgBulkModelViewSet):
]
extra_filter_backends = [DatetimeRangeFilter]
rbac_perms = {
'download': ['terminal.download_sessionreplay']
'download': ['terminal.download_sessionreplay|terminal.view_sessionreplay']
}
@staticmethod

View File

@ -16,6 +16,9 @@ __all__ = ['CommentViewSet']
class CommentViewSet(mixins.CreateModelMixin, viewsets.ReadOnlyModelViewSet):
serializer_class = serializers.CommentSerializer
permission_classes = (RBACPermission, IsSwagger | IsAssignee | IsApplicant)
rbac_perms = {
'*': 'tickets.view_ticket'
}
@lazyproperty
def ticket(self):

View File

@ -18,6 +18,9 @@ class TicketSessionRelationViewSet(CreateModelMixin, JMSGenericViewSet):
# Todo: 放到上面的 ViewSet 中
class TicketSessionApi(views.APIView):
perm_model = TicketSession
rbac_perms = {
'*': ['tickets.view_ticket']
}
def get(self, request, *args, **kwargs):
with tmp_to_root_org():

View File

@ -7,9 +7,10 @@ from rest_framework.response import Response
from common.const.http import POST, PUT
from common.mixins.api import CommonApiMixin
from common.permissions import IsValidUser
from common.drf.api import JMSBulkModelViewSet
from rbac.permissions import RBACPermission
from tickets import serializers
from tickets.models import Ticket, TicketFlow
from tickets.filters import TicketFilter
@ -33,6 +34,9 @@ class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
'date_created', 'serial_num',
)
ordering = ('-date_created',)
rbac_perms = {
'open': 'tickets.view_ticket',
}
def create(self, request, *args, **kwargs):
raise MethodNotAllowed(self.action)
@ -53,7 +57,7 @@ class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
instance.process_map = instance.create_process_map()
instance.open(applicant=self.request.user)
@action(detail=False, methods=[POST], permission_classes=[IsValidUser, ])
@action(detail=False, methods=[POST], permission_classes=[RBACPermission, ])
def open(self, request, *args, **kwargs):
return super().create(request, *args, **kwargs)

View File

@ -783,11 +783,17 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser):
.exclude(name=BuiltinRole.system_user.name)\
.exists()
if has_system_role:
orgs = [Organization.root()] + list(Organization.objects.all())
orgs = list(Organization.objects.all())
else:
orgs = list(self.orgs.all().distinct())
if self.has_perm('orgs.view_rootorg'):
orgs = [Organization.root()] + orgs
return orgs
@property
def my_orgs(self):
return list(self.orgs.all().distinct())
class Meta:
ordering = ['username']
verbose_name = _("User")

View File

@ -122,12 +122,13 @@ class UserProfileSerializer(UserSerializer):
guide_url = serializers.SerializerMethodField()
receive_backends = serializers.ListField(child=serializers.CharField(), read_only=True)
orgs = UserOrgSerializer(many=True, read_only=True, source='all_orgs')
myorgs = UserOrgSerializer(many=True, read_only=True, source='my_orgs')
perms = serializers.ListField(label=_("Perms"), read_only=True)
class Meta(UserSerializer.Meta):
read_only_fields = [
'date_joined', 'last_login', 'created_by', 'source',
'receive_backends', 'orgs', 'perms',
'receive_backends', 'orgs', 'myorgs', 'perms',
]
fields = UserSerializer.Meta.fields + [
'public_key_comment', 'public_key_hash_md5', 'guide_url',

View File

@ -33,6 +33,20 @@ def clean_db_content_types():
('perms', 'applicationpermission', 'connect_myapps'),
('perms', 'applicationpermission', 'view_userapps'),
('perms', 'applicationpermission', 'view_usergroupapps'),
('perms', 'databaseapppermission', 'view_databaseapppermission'),
('perms', 'databaseapppermission', 'add_databaseapppermission'),
('perms', 'databaseapppermission', 'change_databaseapppermission'),
('perms', 'databaseapppermission', 'delete_databaseapppermission'),
('perms', 'k8sapppermission', 'view_k8sapppermission'),
('perms', 'k8sapppermission', 'add_k8sapppermission'),
('perms', 'k8sapppermission', 'change_k8sapppermission'),
('perms', 'k8sapppermission', 'delete_k8sapppermission'),
('perms', 'remoteapppermission', 'view_remoteapppermission'),
('perms', 'remoteapppermission', 'add_remoteapppermission'),
('perms', 'remoteapppermission', 'change_remoteapppermission'),
('perms', 'remoteapppermission', 'delete_remoteapppermission'),
('perms', 'permeddatabaseapp', 'connect_mydatabaseapp'),