Merge pull request #8119 from jumpserver/dev

v2.21.0-rc6
pull/8133/head
Jiangjie.Bai 2022-04-20 20:25:43 +08:00 committed by GitHub
commit e83d676712
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 281 additions and 198 deletions

View File

@ -156,10 +156,7 @@ class AccountBackupHandler:
logger.info('步骤完成: 用时 {}s'.format(timedelta))
return files
def send_backup_mail(self, files):
recipients = self.execution.plan_snapshot.get('recipients')
if not recipients:
return
def send_backup_mail(self, files, recipients):
if not files:
return
recipients = User.objects.filter(id__in=list(recipients))
@ -198,8 +195,16 @@ class AccountBackupHandler:
is_success = False
error = '-'
try:
recipients = self.execution.plan_snapshot.get('recipients')
if not recipients:
logger.info(
'\n'
'\033[32m>>> 该备份任务未分配收件人\033[0m'
''
)
else:
files = self.create_excel()
self.send_backup_mail(files)
self.send_backup_mail(files, recipients)
except Exception as e:
self.is_frozen = True
logger.error('任务执行被异常中断')

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4e6962699271d0f5402223321e65211f1c7ad0b7a9b43524f3a0fac7ea2541d9
size 125623
oid sha256:f2c88ade4bfae213bdcdafad656af73f764e3b1b3f2b0c59aa39626e967730ca
size 125911

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-19 15:57+0800\n"
"POT-Creation-Date: 2022-04-20 16:35+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -29,7 +29,7 @@ msgstr "Acls"
#: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24
#: 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/endpoint.py:10 terminal/models/endpoint.py:55
#: terminal/models/endpoint.py:10 terminal/models/endpoint.py:58
#: terminal/models/storage.py:23 terminal/models/task.py:16
#: terminal/models/terminal.py:100 users/forms/profile.py:32
#: users/models/group.py:15 users/models/user.py:661
@ -38,12 +38,12 @@ msgid "Name"
msgstr "名前"
#: acls/models/base.py:27 assets/models/cmd_filter.py:84
#: assets/models/user.py:247 terminal/models/endpoint.py:58
#: assets/models/user.py:247 terminal/models/endpoint.py:61
msgid "Priority"
msgstr "優先順位"
#: acls/models/base.py:28 assets/models/cmd_filter.py:84
#: assets/models/user.py:247 terminal/models/endpoint.py:59
#: assets/models/user.py:247 terminal/models/endpoint.py:62
msgid "1-100, the lower the value will be match first"
msgstr "1-100、低い値は最初に一致します"
@ -61,7 +61,7 @@ msgstr "アクティブ"
#: assets/models/domain.py:64 assets/models/group.py:23
#: 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/endpoint.py:20 terminal/models/endpoint.py:65
#: terminal/models/endpoint.py:20 terminal/models/endpoint.py:68
#: terminal/models/storage.py:26 terminal/models/terminal.py:114
#: tickets/models/comment.py:24 tickets/models/ticket.py:154
#: users/models/group.py:16 users/models/user.py:698
@ -1360,7 +1360,7 @@ msgstr "監査"
#: audits/models.py:27 audits/models.py:57
#: authentication/templates/authentication/_access_key_modal.html:65
#: rbac/tree.py:166
#: rbac/tree.py:168
msgid "Delete"
msgstr "削除"
@ -1413,11 +1413,11 @@ msgstr "ファイル転送ログ"
#: audits/models.py:55
#: authentication/templates/authentication/_access_key_modal.html:22
#: rbac/tree.py:163
#: rbac/tree.py:165
msgid "Create"
msgstr "作成"
#: audits/models.py:56 rbac/tree.py:165 templates/_csv_import_export.html:18
#: audits/models.py:56 rbac/tree.py:167 templates/_csv_import_export.html:18
#: templates/_csv_update_modal.html:6
msgid "Update"
msgstr "更新"
@ -2886,15 +2886,22 @@ msgstr "タスクログ"
msgid "Update task content: {}"
msgstr "タスク内容の更新: {}"
#: orgs/api.py:68
#: orgs/api.py:69
msgid "The current organization ({}) cannot be deleted"
msgstr "現在の組織 ({}) は削除できません"
#: orgs/api.py:76
#: orgs/api.py:74
msgid ""
"LDAP synchronization is set to the current organization. Please switch to "
"another organization before deleting"
msgstr ""
"LDAP 同期は現在の組織に設定されます。削除する前に別の組織に切り替えてください"
#: orgs/api.py:83
msgid "The organization have resource ({}) cannot be deleted"
msgstr "組織のリソース ({}) は削除できません"
#: orgs/apps.py:7 rbac/tree.py:112
#: orgs/apps.py:7 rbac/tree.py:114
msgid "App organizations"
msgstr "アプリ組織"
@ -3202,18 +3209,18 @@ msgstr "組織の役割"
msgid "Role binding"
msgstr "ロールバインディング"
#: rbac/models/rolebinding.py:150
#: rbac/models/rolebinding.py:151
msgid ""
"User last role in org, can not be delete, you can remove user from org "
"instead"
msgstr ""
"ユーザーの最後のロールは削除できません。ユーザーを組織から削除できます。"
#: rbac/models/rolebinding.py:157
#: rbac/models/rolebinding.py:158
msgid "Organization role binding"
msgstr "組織の役割バインディング"
#: rbac/models/rolebinding.py:172
#: rbac/models/rolebinding.py:173
msgid "System role binding"
msgstr "システムロールバインディング"
@ -3301,27 +3308,27 @@ msgstr "私の資産"
msgid "My apps"
msgstr "マイアプリ"
#: rbac/tree.py:113
#: rbac/tree.py:115
msgid "Ticket comment"
msgstr "チケットコメント"
#: rbac/tree.py:114 tickets/models/ticket.py:163
#: rbac/tree.py:116 tickets/models/ticket.py:163
msgid "Ticket"
msgstr "チケット"
#: rbac/tree.py:115
#: rbac/tree.py:117
msgid "Common setting"
msgstr "共通設定"
#: rbac/tree.py:116
#: rbac/tree.py:118
msgid "View permission tree"
msgstr "権限ツリーの表示"
#: rbac/tree.py:117
#: rbac/tree.py:119
msgid "Execute batch command"
msgstr "バッチ実行コマンド"
#: rbac/tree.py:164
#: rbac/tree.py:166
msgid "View"
msgstr "表示"
@ -4228,8 +4235,8 @@ msgid ""
"Tips: The login success message varies with devices. if you cannot log in to "
"the device through Telnet, set this parameter"
msgstr ""
"ヒント: ログイン成功メッセージはデバイスによって異なります。Telnet経由でデバイスにロ"
"グインできない場合は、このパラメーターを設定します。"
"ヒント: ログイン成功メッセージはデバイスによって異なります。Telnet経由でデバ"
"イスにログインできない場合は、このパラメーターを設定します。"
#: settings/serializers/terminal.py:36
msgid "Enable database proxy"
@ -4243,104 +4250,104 @@ msgstr "XRDPの有効化"
msgid "Enable KoKo SSH"
msgstr "KoKo SSHの有効化"
#: settings/utils/ldap.py:417
#: settings/utils/ldap.py:419
msgid "ldap:// or ldaps:// protocol is used."
msgstr "ldap:// または ldaps:// プロトコルが使用されます。"
#: settings/utils/ldap.py:428
#: settings/utils/ldap.py:430
msgid "Host or port is disconnected: {}"
msgstr "ホストまたはポートが切断されました: {}"
#: settings/utils/ldap.py:430
#: settings/utils/ldap.py:432
msgid "The port is not the port of the LDAP service: {}"
msgstr "ポートはLDAPサービスのポートではありません: {}"
#: settings/utils/ldap.py:432
#: settings/utils/ldap.py:434
msgid "Please add certificate: {}"
msgstr "証明書を追加してください: {}"
#: settings/utils/ldap.py:436 settings/utils/ldap.py:463
#: settings/utils/ldap.py:493 settings/utils/ldap.py:521
#: settings/utils/ldap.py:438 settings/utils/ldap.py:465
#: settings/utils/ldap.py:495 settings/utils/ldap.py:523
msgid "Unknown error: {}"
msgstr "不明なエラー: {}"
#: settings/utils/ldap.py:450
#: settings/utils/ldap.py:452
msgid "Bind DN or Password incorrect"
msgstr "DNまたはパスワードのバインドが正しくありません"
#: settings/utils/ldap.py:457
#: settings/utils/ldap.py:459
msgid "Please enter Bind DN: {}"
msgstr "バインドDN: {} を入力してください"
#: settings/utils/ldap.py:459
#: settings/utils/ldap.py:461
msgid "Please enter Password: {}"
msgstr "パスワードを入力してください: {}"
#: settings/utils/ldap.py:461
#: settings/utils/ldap.py:463
msgid "Please enter correct Bind DN and Password: {}"
msgstr "正しいバインドDNとパスワードを入力してください: {}"
#: settings/utils/ldap.py:479
#: settings/utils/ldap.py:481
msgid "Invalid User OU or User search filter: {}"
msgstr "無効なユーザー OU またはユーザー検索フィルター: {}"
#: settings/utils/ldap.py:510
#: settings/utils/ldap.py:512
msgid "LDAP User attr map not include: {}"
msgstr "LDAP ユーザーattrマップは含まれません: {}"
#: settings/utils/ldap.py:517
#: settings/utils/ldap.py:519
msgid "LDAP User attr map is not dict"
msgstr "LDAPユーザーattrマップはdictではありません"
#: settings/utils/ldap.py:536
#: settings/utils/ldap.py:538
msgid "LDAP authentication is not enabled"
msgstr "LDAP 認証が有効になっていない"
#: settings/utils/ldap.py:554
#: settings/utils/ldap.py:556
msgid "Error (Invalid LDAP server): {}"
msgstr "エラー (LDAPサーバーが無効): {}"
#: settings/utils/ldap.py:556
#: settings/utils/ldap.py:558
msgid "Error (Invalid Bind DN): {}"
msgstr "エラー (DNのバインドが無効): {}"
#: settings/utils/ldap.py:558
#: settings/utils/ldap.py:560
msgid "Error (Invalid LDAP User attr map): {}"
msgstr "エラー (LDAPユーザーattrマップが無効): {}"
#: settings/utils/ldap.py:560
#: settings/utils/ldap.py:562
msgid "Error (Invalid User OU or User search filter): {}"
msgstr "エラー (ユーザーOUまたはユーザー検索フィルターが無効): {}"
#: settings/utils/ldap.py:562
#: settings/utils/ldap.py:564
msgid "Error (Not enabled LDAP authentication): {}"
msgstr "エラー (LDAP認証が有効化されていません): {}"
#: settings/utils/ldap.py:564
#: settings/utils/ldap.py:566
msgid "Error (Unknown): {}"
msgstr "エラー (不明): {}"
#: settings/utils/ldap.py:567
#: settings/utils/ldap.py:569
msgid "Succeed: Match {} s user"
msgstr "成功: {} 人のユーザーに一致"
#: settings/utils/ldap.py:600
#: settings/utils/ldap.py:602
msgid "Authentication failed (configuration incorrect): {}"
msgstr "認証に失敗しました (設定が正しくありません): {}"
#: settings/utils/ldap.py:602
#: settings/utils/ldap.py:604
msgid "Authentication failed (before login check failed): {}"
msgstr "認証に失敗しました (ログインチェックが失敗する前): {}"
#: settings/utils/ldap.py:604
#: settings/utils/ldap.py:606
msgid "Authentication failed (username or password incorrect): {}"
msgstr "認証に失敗しました (ユーザー名またはパスワードが正しくありません): {}"
#: settings/utils/ldap.py:606
#: settings/utils/ldap.py:608
msgid "Authentication failed (Unknown): {}"
msgstr "認証に失敗しました (不明): {}"
#: settings/utils/ldap.py:609
#: settings/utils/ldap.py:611
msgid "Authentication success: {}"
msgstr "認証成功: {}"
@ -4725,18 +4732,18 @@ msgstr "MariaDB ポート"
msgid "PostgreSQL Port"
msgstr "PostgreSQL ポート"
#: terminal/models/endpoint.py:25 terminal/models/endpoint.py:63
#: terminal/models/endpoint.py:25 terminal/models/endpoint.py:66
#: terminal/serializers/endpoint.py:40 terminal/serializers/storage.py:37
#: terminal/serializers/storage.py:49 terminal/serializers/storage.py:79
#: terminal/serializers/storage.py:89 terminal/serializers/storage.py:97
msgid "Endpoint"
msgstr "エンドポイント"
#: terminal/models/endpoint.py:56
#: terminal/models/endpoint.py:59
msgid "IP group"
msgstr "IP グループ"
#: terminal/models/endpoint.py:68
#: terminal/models/endpoint.py:71
msgid "Endpoint rule"
msgstr "エンドポイントルール"

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3462a9a3eef8f372bf341f2066a33d85e1f01aca5a8fe506528a1cd0a37e98b4
size 103951
oid sha256:c75e0a1f2a047dac1374916c630bc0e8ef5ad5eea7518ffc21e93f747fc1235e
size 104165

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-04-19 15:57+0800\n"
"POT-Creation-Date: 2022-04-20 16:35+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"
@ -28,7 +28,7 @@ msgstr "访问控制"
#: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24
#: 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/endpoint.py:10 terminal/models/endpoint.py:55
#: terminal/models/endpoint.py:10 terminal/models/endpoint.py:58
#: terminal/models/storage.py:23 terminal/models/task.py:16
#: terminal/models/terminal.py:100 users/forms/profile.py:32
#: users/models/group.py:15 users/models/user.py:661
@ -37,12 +37,12 @@ msgid "Name"
msgstr "名称"
#: acls/models/base.py:27 assets/models/cmd_filter.py:84
#: assets/models/user.py:247 terminal/models/endpoint.py:58
#: assets/models/user.py:247 terminal/models/endpoint.py:61
msgid "Priority"
msgstr "优先级"
#: acls/models/base.py:28 assets/models/cmd_filter.py:84
#: assets/models/user.py:247 terminal/models/endpoint.py:59
#: assets/models/user.py:247 terminal/models/endpoint.py:62
msgid "1-100, the lower the value will be match first"
msgstr "优先级可选范围为 1-100 (数值越小越优先)"
@ -60,7 +60,7 @@ msgstr "激活中"
#: assets/models/domain.py:64 assets/models/group.py:23
#: 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/endpoint.py:20 terminal/models/endpoint.py:65
#: terminal/models/endpoint.py:20 terminal/models/endpoint.py:68
#: terminal/models/storage.py:26 terminal/models/terminal.py:114
#: tickets/models/comment.py:24 tickets/models/ticket.py:154
#: users/models/group.py:16 users/models/user.py:698
@ -1348,7 +1348,7 @@ msgstr "日志审计"
#: audits/models.py:27 audits/models.py:57
#: authentication/templates/authentication/_access_key_modal.html:65
#: rbac/tree.py:166
#: rbac/tree.py:168
msgid "Delete"
msgstr "删除"
@ -1401,11 +1401,11 @@ msgstr "文件管理"
#: audits/models.py:55
#: authentication/templates/authentication/_access_key_modal.html:22
#: rbac/tree.py:163
#: rbac/tree.py:165
msgid "Create"
msgstr "创建"
#: audits/models.py:56 rbac/tree.py:165 templates/_csv_import_export.html:18
#: audits/models.py:56 rbac/tree.py:167 templates/_csv_import_export.html:18
#: templates/_csv_update_modal.html:6
msgid "Update"
msgstr "更新"
@ -2851,15 +2851,21 @@ msgstr "任务列表"
msgid "Update task content: {}"
msgstr "更新任务内容: {}"
#: orgs/api.py:68
#: orgs/api.py:69
msgid "The current organization ({}) cannot be deleted"
msgstr "当前组织 ({}) 不能被删除"
#: orgs/api.py:76
#: orgs/api.py:74
msgid ""
"LDAP synchronization is set to the current organization. Please switch to "
"another organization before deleting"
msgstr "LDAP 同步设置组织为当前组织,请切换其他组织后再进行删除操作"
#: orgs/api.py:83
msgid "The organization have resource ({}) cannot be deleted"
msgstr "组织存在资源 ({}) 不能被删除"
#: orgs/apps.py:7 rbac/tree.py:112
#: orgs/apps.py:7 rbac/tree.py:114
msgid "App organizations"
msgstr "组织管理"
@ -3165,17 +3171,17 @@ msgstr "组织角色"
msgid "Role binding"
msgstr "角色绑定"
#: rbac/models/rolebinding.py:150
#: rbac/models/rolebinding.py:151
msgid ""
"User last role in org, can not be delete, you can remove user from org "
"instead"
msgstr "用户最后一个角色,不能删除,你可以将用户从组织移除"
#: rbac/models/rolebinding.py:157
#: rbac/models/rolebinding.py:158
msgid "Organization role binding"
msgstr "组织角色绑定"
#: rbac/models/rolebinding.py:172
#: rbac/models/rolebinding.py:173
msgid "System role binding"
msgstr "系统角色绑定"
@ -3263,27 +3269,27 @@ msgstr "我的资产"
msgid "My apps"
msgstr "我的应用"
#: rbac/tree.py:113
#: rbac/tree.py:115
msgid "Ticket comment"
msgstr "工单评论"
#: rbac/tree.py:114 tickets/models/ticket.py:163
#: rbac/tree.py:116 tickets/models/ticket.py:163
msgid "Ticket"
msgstr "工单管理"
#: rbac/tree.py:115
#: rbac/tree.py:117
msgid "Common setting"
msgstr "一般设置"
#: rbac/tree.py:116
#: rbac/tree.py:118
msgid "View permission tree"
msgstr "查看授权树"
#: rbac/tree.py:117
#: rbac/tree.py:119
msgid "Execute batch command"
msgstr "执行批量命令"
#: rbac/tree.py:164
#: rbac/tree.py:166
msgid "View"
msgstr "查看"
@ -4167,7 +4173,8 @@ msgstr "Telnet 成功正则表达式"
msgid ""
"Tips: The login success message varies with devices. if you cannot log in to "
"the device through Telnet, set this parameter"
msgstr "提示: 不同设备登录成功提示不一样,所以如果 telnet 不能正常登录,可以这里设置"
msgstr ""
"提示: 不同设备登录成功提示不一样,所以如果 telnet 不能正常登录,可以这里设置"
#: settings/serializers/terminal.py:36
msgid "Enable database proxy"
@ -4181,104 +4188,104 @@ msgstr "启用 XRDP 服务"
msgid "Enable KoKo SSH"
msgstr "启用 KoKo SSH"
#: settings/utils/ldap.py:417
#: settings/utils/ldap.py:419
msgid "ldap:// or ldaps:// protocol is used."
msgstr "使用 ldap:// 或 ldaps:// 协议"
#: settings/utils/ldap.py:428
#: settings/utils/ldap.py:430
msgid "Host or port is disconnected: {}"
msgstr "主机或端口不可连接: {}"
#: settings/utils/ldap.py:430
#: settings/utils/ldap.py:432
msgid "The port is not the port of the LDAP service: {}"
msgstr "端口不是LDAP服务端口: {}"
#: settings/utils/ldap.py:432
#: settings/utils/ldap.py:434
msgid "Please add certificate: {}"
msgstr "请添加证书"
#: settings/utils/ldap.py:436 settings/utils/ldap.py:463
#: settings/utils/ldap.py:493 settings/utils/ldap.py:521
#: settings/utils/ldap.py:438 settings/utils/ldap.py:465
#: settings/utils/ldap.py:495 settings/utils/ldap.py:523
msgid "Unknown error: {}"
msgstr "未知错误: {}"
#: settings/utils/ldap.py:450
#: settings/utils/ldap.py:452
msgid "Bind DN or Password incorrect"
msgstr "绑定DN或密码错误"
#: settings/utils/ldap.py:457
#: settings/utils/ldap.py:459
msgid "Please enter Bind DN: {}"
msgstr "请输入绑定DN: {}"
#: settings/utils/ldap.py:459
#: settings/utils/ldap.py:461
msgid "Please enter Password: {}"
msgstr "请输入密码: {}"
#: settings/utils/ldap.py:461
#: settings/utils/ldap.py:463
msgid "Please enter correct Bind DN and Password: {}"
msgstr "请输入正确的绑定DN和密码: {}"
#: settings/utils/ldap.py:479
#: settings/utils/ldap.py:481
msgid "Invalid User OU or User search filter: {}"
msgstr "不合法的用户OU或用户过滤器: {}"
#: settings/utils/ldap.py:510
#: settings/utils/ldap.py:512
msgid "LDAP User attr map not include: {}"
msgstr "LDAP属性映射没有包含: {}"
#: settings/utils/ldap.py:517
#: settings/utils/ldap.py:519
msgid "LDAP User attr map is not dict"
msgstr "LDAP属性映射不合法"
#: settings/utils/ldap.py:536
#: settings/utils/ldap.py:538
msgid "LDAP authentication is not enabled"
msgstr "LDAP认证没有启用"
#: settings/utils/ldap.py:554
#: settings/utils/ldap.py:556
msgid "Error (Invalid LDAP server): {}"
msgstr "错误 不合法的LDAP服务器地址: {}"
#: settings/utils/ldap.py:556
#: settings/utils/ldap.py:558
msgid "Error (Invalid Bind DN): {}"
msgstr "错误不合法的绑定DN: {}"
#: settings/utils/ldap.py:558
#: settings/utils/ldap.py:560
msgid "Error (Invalid LDAP User attr map): {}"
msgstr "错误不合法的LDAP属性映射: {}"
#: settings/utils/ldap.py:560
#: settings/utils/ldap.py:562
msgid "Error (Invalid User OU or User search filter): {}"
msgstr "错误不合法的用户OU或用户过滤器: {}"
#: settings/utils/ldap.py:562
#: settings/utils/ldap.py:564
msgid "Error (Not enabled LDAP authentication): {}"
msgstr "错误没有启用LDAP认证: {}"
#: settings/utils/ldap.py:564
#: settings/utils/ldap.py:566
msgid "Error (Unknown): {}"
msgstr "错误(未知): {}"
#: settings/utils/ldap.py:567
#: settings/utils/ldap.py:569
msgid "Succeed: Match {} s user"
msgstr "成功匹配 {} 个用户"
#: settings/utils/ldap.py:600
#: settings/utils/ldap.py:602
msgid "Authentication failed (configuration incorrect): {}"
msgstr "认证失败(配置错误): {}"
#: settings/utils/ldap.py:602
#: settings/utils/ldap.py:604
msgid "Authentication failed (before login check failed): {}"
msgstr "认证失败(登录前检查失败): {}"
#: settings/utils/ldap.py:604
#: settings/utils/ldap.py:606
msgid "Authentication failed (username or password incorrect): {}"
msgstr "认证失败 (用户名或密码不正确): {}"
#: settings/utils/ldap.py:606
#: settings/utils/ldap.py:608
msgid "Authentication failed (Unknown): {}"
msgstr "认证失败: (未知): {}"
#: settings/utils/ldap.py:609
#: settings/utils/ldap.py:611
msgid "Authentication success: {}"
msgstr "认证成功: {}"
@ -4651,18 +4658,18 @@ msgstr "MariaDB 端口"
msgid "PostgreSQL Port"
msgstr "PostgreSQL 端口"
#: terminal/models/endpoint.py:25 terminal/models/endpoint.py:63
#: terminal/models/endpoint.py:25 terminal/models/endpoint.py:66
#: terminal/serializers/endpoint.py:40 terminal/serializers/storage.py:37
#: terminal/serializers/storage.py:49 terminal/serializers/storage.py:79
#: terminal/serializers/storage.py:89 terminal/serializers/storage.py:97
msgid "Endpoint"
msgstr "端点"
#: terminal/models/endpoint.py:56
#: terminal/models/endpoint.py:59
msgid "IP group"
msgstr "IP 组"
#: terminal/models/endpoint.py:68
#: terminal/models/endpoint.py:71
msgid "Endpoint rule"
msgstr "端点规则"

View File

@ -2,6 +2,7 @@
#
from django.utils.translation import ugettext as _
from django.conf import settings
from rest_framework_bulk import BulkModelViewSet
from rest_framework.generics import RetrieveAPIView
from rest_framework.exceptions import PermissionDenied
@ -68,6 +69,12 @@ class OrgViewSet(BulkModelViewSet):
msg = _('The current organization ({}) cannot be deleted').format(current_org)
raise PermissionDenied(detail=msg)
if str(instance.id) == settings.AUTH_LDAP_SYNC_ORG_ID:
msg = _(
'LDAP synchronization is set to the current organization. Please switch to another organization before deleting'
)
raise PermissionDenied(detail=msg)
for model in org_related_models:
data = self.get_data_from_model(instance, model)
if not data:

View File

@ -90,7 +90,7 @@ class SystemRolePermissionsViewSet(BaseRolePermissionsViewSet):
role_pk = 'system_role_pk'
model = SystemRole
rbac_perms = (
('get_tree', 'rbac.view_systemrole'),
('get_tree', 'rbac.view_permission'),
)
@ -99,6 +99,6 @@ class OrgRolePermissionsViewSet(BaseRolePermissionsViewSet):
role_pk = 'org_role_pk'
model = OrgRole
rbac_perms = (
('get_tree', 'rbac.view_orgrole'),
('get_tree', 'rbac.view_permission'),
)

View File

@ -2,15 +2,10 @@ from django.utils.translation import ugettext_noop
from .const import Scope, system_exclude_permissions, org_exclude_permissions
system_user_perms = (
('authentication', 'connectiontoken', 'add', 'connectiontoken'),
('authentication', 'temptoken', 'add,change,view', 'temptoken'),
('authentication', 'accesskey', '*', '*'),
('tickets', 'ticket', 'view', 'ticket'),
_view_root_perms = (
('orgs', 'organization', 'view', 'rootorg'),
)
# Todo: 获取应该区分 系统用户,和组织用户的权限
# 工作台也区分组织后再考虑
user_perms = (
('rbac', 'menupermission', 'view', 'workbench'),
@ -25,16 +20,28 @@ user_perms = (
('ops', 'commandexecution', 'add', 'commandexecution'),
)
auditor_perms = user_perms + (
system_user_perms = (
('authentication', 'connectiontoken', 'add', 'connectiontoken'),
('authentication', 'temptoken', 'add,change,view', 'temptoken'),
('authentication', 'accesskey', '*', '*'),
('tickets', 'ticket', 'view', 'ticket'),
) + user_perms
_auditor_perms = (
('rbac', 'menupermission', 'view', 'audit'),
('audits', '*', '*', '*'),
('terminal', 'commandstorage', 'view', 'commandstorage'),
('terminal', 'sessionreplay', 'view,download', 'sessionreplay'),
('terminal', 'session', '*', '*'),
('terminal', 'command', '*', '*'),
('ops', 'commandexecution', 'view', 'commandexecution')
('ops', 'commandexecution', 'view', 'commandexecution'),
)
auditor_perms = user_perms + _auditor_perms
system_auditor_perms = system_user_perms + _auditor_perms + _view_root_perms
app_exclude_perms = [
('users', 'user', 'add,delete', 'user'),
('orgs', 'org', 'add,delete,change', 'org'),
@ -102,7 +109,7 @@ class BuiltinRole:
'1', ugettext_noop('SystemAdmin'), Scope.system, []
)
system_auditor = PredefineRole(
'2', ugettext_noop('SystemAuditor'), Scope.system, auditor_perms
'2', ugettext_noop('SystemAuditor'), Scope.system, system_auditor_perms
)
system_component = PredefineRole(
'4', ugettext_noop('SystemComponent'), Scope.system, app_exclude_perms, 'exclude'

View File

@ -108,8 +108,11 @@ only_system_permissions = (
('terminal', 'replaystorage', '*', '*'),
('terminal', 'status', '*', '*'),
('terminal', 'task', '*', '*'),
('terminal', 'endpoint', '*', '*'),
('terminal', 'endpointrule', '*', '*'),
('authentication', '*', '*', '*'),
('tickets', '*', '*', '*'),
('orgs', 'organization', 'view', 'rootorg'),
)
only_org_permissions = (

View File

@ -6,7 +6,7 @@ from rest_framework.serializers import ValidationError
from common.db.models import JMSModel
from common.utils import lazyproperty
from orgs.utils import current_org
from orgs.utils import current_org, tmp_to_root_org
from .role import Role
from ..const import Scope
@ -105,20 +105,25 @@ class RoleBinding(JMSModel):
from orgs.models import Organization
roles = Role.get_roles_by_perm(perm)
with tmp_to_root_org():
bindings = list(cls.objects.root_all().filter(role__in=roles, user=user))
system_bindings = [b for b in bindings if b.scope == Role.Scope.system.value]
system_bindings = [b for b in bindings if b.scope == Role.Scope.system.value]
# 工作台仅限于自己加入的组织
if perm == 'rbac.view_workbench':
all_orgs = user.orgs.all()
else:
all_orgs = Organization.objects.all()
# 有系统级别的绑定,就代表在所有组织有这个权限
if system_bindings:
orgs = all_orgs
else:
org_ids = [b.org.id for b in bindings if b.org]
orgs = all_orgs.filter(id__in=org_ids)
if orgs and user.has_perm('orgs.view_rootorg'):
# 全局组织
if orgs and perm != 'rbac.view_workbench' and user.has_perm('orgs.view_rootorg'):
orgs = [Organization.root(), *list(orgs)]
return orgs

View File

@ -1,7 +1,8 @@
#!/usr/bin/python
import os
from collections import defaultdict
from typing import Callable
from treelib import Tree
from treelib.exceptions import NodeIDAbsentError
from django.utils.translation import gettext_lazy as _, gettext, get_language
from django.conf import settings
@ -159,6 +160,65 @@ def sort_nodes(node):
return value
class CounterTree(Tree):
def get_total_count(self, node):
count = getattr(node, '_total_count', None)
if count is not None:
return count
if not node.data.isParent:
return 1
count = 0
children = self.children(node.identifier)
for child in children:
if child.data.isParent:
count += self.get_total_count(child)
else:
count += 1
node._total_count = count
return count
def get_checked_count(self, node):
count = getattr(node, '_checked_count', None)
if count is not None:
return count
if not node.data.isParent:
if node.data.checked:
return 1
else:
return 0
count = 0
children = self.children(node.identifier)
for child in children:
if child.data.isParent:
count += self.get_checked_count(child)
else:
if child.data.checked:
count += 1
node._checked_count = count
return count
def add_nodes_to_tree(self, ztree_nodes, retry=0):
failed = []
for node in ztree_nodes:
pid = node.pId
if retry == 2:
pid = '$ROOT$'
try:
self.create_node(node.name, node.id, pid, data=node)
except NodeIDAbsentError:
failed.append(node)
if retry > 2:
return
if failed:
retry += 1
return self.add_nodes_to_tree(failed, retry)
class PermissionTreeUtil:
get_permissions: Callable
action_mapper = {
@ -183,8 +243,6 @@ class PermissionTreeUtil:
Permission.get_permissions(scope)
)
self.check_disabled = check_disabled
self.total_counts = defaultdict(int)
self.checked_counts = defaultdict(int)
self.lang = get_language()
@staticmethod
@ -211,38 +269,10 @@ class PermissionTreeUtil:
'name': name,
'pId': view,
}
total_count = self.total_counts[app]
checked_count = self.checked_counts[app]
if total_count == 0:
continue
self.total_counts[view] += total_count
self.checked_counts[view] += checked_count
node = self._create_node(
app_data, total_count, checked_count,
'app', is_open=False
)
node = self._create_node(app_data, 'app', is_open=False)
nodes.append(node)
return nodes
def _get_model_counts_mapper(self):
model_counts = self.all_permissions \
.values('model', 'app', 'content_type') \
.order_by('content_type') \
.annotate(count=Count('content_type'))
model_check_counts = self.permissions \
.values('content_type', 'model') \
.order_by('content_type') \
.annotate(count=Count('content_type'))
model_counts_mapper = {
i['content_type']: i['count']
for i in model_counts
}
model_check_counts_mapper = {
i['content_type']: i['count']
for i in model_check_counts
}
return model_counts_mapper, model_check_counts_mapper
@staticmethod
def _check_model_xpack(model_id):
app, model = model_id.split('.', 2)
@ -263,17 +293,10 @@ class PermissionTreeUtil:
if not self._check_model_xpack(model_id):
continue
total_count = self.total_counts[model_id]
checked_count = self.checked_counts[model_id]
if total_count == 0:
continue
# 获取 pid
app = ct.app_label
if model_id in special_pid_mapper:
app = special_pid_mapper[model_id]
self.total_counts[app] += total_count
self.checked_counts[app] += checked_count
# 获取 name
name = f'{ct.name}'
@ -284,7 +307,7 @@ class PermissionTreeUtil:
'id': model_id,
'name': name,
'pId': app,
}, total_count, checked_count, 'model', is_open=False)
}, 'model', is_open=False)
nodes.append(node)
return nodes
@ -334,10 +357,7 @@ class PermissionTreeUtil:
if title in special_pid_mapper:
pid = special_pid_mapper[title]
self.total_counts[pid] += 1
checked = p.id in permissions_id
if checked:
self.checked_counts[pid] += 1
node = TreeNode(**{
'id': p.id,
@ -347,7 +367,7 @@ class PermissionTreeUtil:
'isParent': False,
'chkDisabled': self.check_disabled,
'iconSkin': icon,
'checked': p.id in permissions_id,
'checked': checked,
'open': False,
'meta': {
'type': 'perm',
@ -356,13 +376,11 @@ class PermissionTreeUtil:
nodes.append(node)
return nodes
def _create_node(self, data, total_count, checked_count, tp,
is_parent=True, is_open=True, icon='', checked=None):
def _create_node(self, data, tp, is_parent=True, is_open=True, icon='', checked=None):
assert data.get('id')
assert data.get('name')
assert data.get('pId') is not None
if checked is None:
checked = total_count == checked_count
node_data = {
'isParent': is_parent,
'iconSkin': icon,
@ -380,46 +398,58 @@ class PermissionTreeUtil:
node.name += ('[' + node.id + ']')
if DEBUG_DB:
node.name += ('-' + node.id)
node.name += f'({checked_count}/{total_count})'
return node
def _create_root_tree_node(self):
total_count = self.all_permissions.count()
checked_count = self.permissions.count()
node = self._create_node(root_node_data, total_count, checked_count, 'root')
node = self._create_node(root_node_data, 'root')
return node
def _create_views_node(self):
nodes = []
for view_data in view_nodes_data:
view = view_data['id']
data = {
**view_data,
'pId': '$ROOT$',
}
total_count = self.total_counts[view]
checked_count = self.checked_counts[view]
if total_count == 0:
continue
node = self._create_node(data, total_count, checked_count, 'view', is_open=True)
node = self._create_node(data, 'view', is_open=True)
nodes.append(node)
return nodes
def _create_extra_nodes(self):
nodes = []
for data in extra_nodes_data:
i = data['id']
pid = data['pId']
checked_count = self.checked_counts[i]
total_count = self.total_counts[i]
node = self._create_node(data, 'extra', is_open=False)
nodes.append(node)
return nodes
@staticmethod
def compute_nodes_count(ztree_nodes):
tree = CounterTree()
reverse_nodes = ztree_nodes[::-1]
root = reverse_nodes[0]
tree.create_node(root.name, root.id, data=root)
tree.add_nodes_to_tree(reverse_nodes[1:])
counter_nodes = tree.all_nodes()
node_counts = {}
for n in counter_nodes:
if not n:
continue
total_count = tree.get_total_count(n)
checked_count = tree.get_checked_count(n)
node_counts[n.identifier] = [checked_count, total_count]
nodes = []
for node in ztree_nodes:
counter = node_counts[node.id]
if not counter:
counter = [0, 0]
checked_count, total_count = counter
if total_count == 0:
continue
self.total_counts[pid] += total_count
self.checked_counts[pid] += checked_count
node = self._create_node(
data, total_count, checked_count,
'extra', is_open=False
)
node.name += '({}/{})'.format(checked_count, total_count)
if checked_count != 0:
node.checked = True
nodes.append(node)
return nodes
@ -431,5 +461,6 @@ class PermissionTreeUtil:
nodes += self._create_views_node()
nodes += [self._create_root_tree_node()]
nodes = self.compute_nodes_count(nodes)
nodes.sort(key=sort_nodes)
return nodes

View File

@ -376,7 +376,9 @@ class LDAPImportUtil(object):
except Exception as e:
errors.append({user['username']: str(e)})
logger.error(e)
if org and org.is_root():
if not org:
return
if org.is_root():
return
for obj in objs:
org.add_member(obj)

View File

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

View File

@ -81,8 +81,14 @@ def import_ldap_user():
util_server = LDAPServerUtil()
util_import = LDAPImportUtil()
users = util_server.search()
if settings.XPACK_ENABLED:
org_id = settings.AUTH_LDAP_SYNC_ORG_ID
org = Organization.get_instance(org_id)
default_org = None
else:
# 社区版默认导入Default组织
org_id = Organization.DEFAULT_ID
default_org = Organization.default()
org = Organization.get_instance(org_id, default=default_org)
errors = util_import.perform_import(users, org)
if errors:
logger.error("Imported LDAP users errors: {}".format(errors))
@ -106,6 +112,9 @@ def import_ldap_user_periodic():
else:
interval = None
crontab = settings.AUTH_LDAP_SYNC_CRONTAB
if crontab:
# 优先使用 crontab
interval = None
tasks = {
task_name: {
'task': import_ldap_user.name,