perf: 批量上传添加权限校验

pull/12954/head
wangruidong 2024-04-03 15:44:32 +08:00 committed by Bryan
parent 0aeea414f5
commit 9776d35140
7 changed files with 107 additions and 42 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:0bd11124a56e5fa0b2b8433528d4ffd8c454e5f529bdd72fea15d1a62434165e oid sha256:488d95a4a96d38c3c0633f183334498d9e247bdf66ce3a4bcc836f80e8320432
size 176114 size 176705

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-03 16:51+0800\n" "POT-Creation-Date: 2024-04-07 14:23+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -1362,13 +1362,13 @@ msgstr "アプリケーション"
msgid "Can match application" msgid "Can match application"
msgstr "アプリケーションを一致させることができます" msgstr "アプリケーションを一致させることができます"
#: assets/api/asset/asset.py:181 #: assets/api/asset/asset.py:180
msgid "Cannot create asset directly, you should create a host or other" msgid "Cannot create asset directly, you should create a host or other"
msgstr "" msgstr ""
"資産を直接作成することはできません。ホストまたはその他を作成する必要がありま" "資産を直接作成することはできません。ホストまたはその他を作成する必要がありま"
"す" "す"
#: assets/api/domain.py:68 #: assets/api/domain.py:67
msgid "Number required" msgid "Number required"
msgstr "必要な数" msgstr "必要な数"
@ -4137,11 +4137,24 @@ msgstr "タスクは存在しません"
msgid "Task {} args or kwargs error" msgid "Task {} args or kwargs error"
msgstr "タスク実行パラメータエラー" msgstr "タスク実行パラメータエラー"
#: ops/api/job.py:146 msgid ""
"Asset ({asset}) must have at least one of the following protocols added: "
"SSH, SFTP, or WinRM"
msgstr ""
"資産({asset})には、少なくともSSH、SFTP、WinRMのいずれか一つのプロトコルを追加す"
"る必要があります"
msgid "Asset ({asset}) authorization is missing SSH, SFTP, or WinRM protocol"
msgstr "資産({asset})の認証にはSSH、SFTP、またはWinRMプロトコルが不足しています"
msgid "Asset ({asset}) authorization lacks upload permissions"
msgstr "資産({asset})の認証にはアップロード権限が不足しています"
#: ops/api/job.py:168
msgid "Duplicate file exists" msgid "Duplicate file exists"
msgstr "重複したファイルが存在する" msgstr "重複したファイルが存在する"
#: ops/api/job.py:151 #: ops/api/job.py:173
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"File size exceeds maximum limit. Please select a file smaller than {limit}MB" "File size exceeds maximum limit. Please select a file smaller than {limit}MB"
@ -4149,7 +4162,7 @@ msgstr ""
"ファイルサイズが最大制限を超えています。{limit}MB より小さいファイルを選択し" "ファイルサイズが最大制限を超えています。{limit}MB より小さいファイルを選択し"
"てください。" "てください。"
#: ops/api/job.py:215 #: ops/api/job.py:237
msgid "" msgid ""
"The task is being created and cannot be interrupted. Please try again later." "The task is being created and cannot be interrupted. Please try again later."
msgstr "タスクを作成中で、中断できません。後でもう一度お試しください。" msgstr "タスクを作成中で、中断できません。後でもう一度お試しください。"
@ -4537,18 +4550,18 @@ msgstr "ジョブのID"
msgid "Name of the job" msgid "Name of the job"
msgstr "ジョブの名前" msgstr "ジョブの名前"
#: orgs/api.py:62 #: orgs/api.py:61
msgid "The current organization ({}) cannot be deleted" msgid "The current organization ({}) cannot be deleted"
msgstr "現在の組織 ({}) は削除できません" msgstr "現在の組織 ({}) は削除できません"
#: orgs/api.py:67 #: orgs/api.py:66
msgid "" msgid ""
"LDAP synchronization is set to the current organization. Please switch to " "LDAP synchronization is set to the current organization. Please switch to "
"another organization before deleting" "another organization before deleting"
msgstr "" msgstr ""
"LDAP 同期は現在の組織に設定されます。削除する前に別の組織に切り替えてください" "LDAP 同期は現在の組織に設定されます。削除する前に別の組織に切り替えてください"
#: orgs/api.py:77 #: orgs/api.py:76
msgid "The organization have resource ({}) cannot be deleted" msgid "The organization have resource ({}) cannot be deleted"
msgstr "組織のリソース ({}) は削除できません" msgstr "組織のリソース ({}) は削除できません"
@ -6531,11 +6544,11 @@ msgstr "これはエンタープライズ版アプレットです"
msgid "Not found protocol query params" msgid "Not found protocol query params"
msgstr "プロトコルクエリパラメータが見つかりません" msgstr "プロトコルクエリパラメータが見つかりません"
#: terminal/api/component/storage.py:30 #: terminal/api/component/storage.py:31
msgid "Deleting the default storage is not allowed" msgid "Deleting the default storage is not allowed"
msgstr "デフォルトのストレージの削除は許可されていません" msgstr "デフォルトのストレージの削除は許可されていません"
#: terminal/api/component/storage.py:33 #: terminal/api/component/storage.py:34
msgid "Cannot delete storage that is being used" msgid "Cannot delete storage that is being used"
msgstr "使用中のストレージを削除できません" msgstr "使用中のストレージを削除できません"
@ -6547,15 +6560,15 @@ msgstr "コマンドストア"
msgid "Invalid" msgid "Invalid"
msgstr "無効" msgstr "無効"
#: terminal/api/component/storage.py:131 terminal/tasks.py:149 #: terminal/api/component/storage.py:130 terminal/tasks.py:149
msgid "Test failure: {}" msgid "Test failure: {}"
msgstr "テスト失敗: {}" msgstr "テスト失敗: {}"
#: terminal/api/component/storage.py:134 #: terminal/api/component/storage.py:133
msgid "Test successful" msgid "Test successful"
msgstr "テスト成功" msgstr "テスト成功"
#: terminal/api/component/storage.py:136 #: terminal/api/component/storage.py:135
msgid "Test failure: Please check configuration" msgid "Test failure: Please check configuration"
msgstr "テストに失敗しました:構成を確認してください" msgstr "テストに失敗しました:構成を確認してください"
@ -7890,11 +7903,11 @@ msgstr "無効な承認アクション"
msgid "This user is not authorized to approve this ticket" msgid "This user is not authorized to approve this ticket"
msgstr "このユーザーはこの作業指示を承認する権限がありません" msgstr "このユーザーはこの作業指示を承認する権限がありません"
#: users/api/user.py:137 #: users/api/user.py:136
msgid "Can not invite self" msgid "Can not invite self"
msgstr "自分自身を招待することはできません" msgstr "自分自身を招待することはできません"
#: users/api/user.py:190 #: users/api/user.py:189
msgid "Could not reset self otp, use profile reset instead" msgid "Could not reset self otp, use profile reset instead"
msgstr "自己otpをリセットできませんでした、代わりにプロファイルリセットを使用" msgstr "自己otpをリセットできませんでした、代わりにプロファイルリセットを使用"
@ -9311,6 +9324,3 @@ msgstr "エンタープライズプロフェッショナル版"
#: xpack/plugins/license/models.py:86 #: xpack/plugins/license/models.py:86
msgid "Ultimate edition" msgid "Ultimate edition"
msgstr "エンタープライズ・フラッグシップ・エディション" msgstr "エンタープライズ・フラッグシップ・エディション"
#~ msgid "Reopen"
#~ msgstr "再オープン"

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:91ad10be95fda19937a09d07806d05f21057a1a79f40428350127d1162c7655d oid sha256:bd99d1b6018567413cefe5fe188a19019e09da46934c05ae9ce229943f712859
size 144168 size 144595

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n" "Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-03 16:51+0800\n" "POT-Creation-Date: 2024-04-07 14:23+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n" "Language-Team: JumpServer team<ibuler@qq.com>\n"
@ -1354,11 +1354,11 @@ msgstr "应用程序"
msgid "Can match application" msgid "Can match application"
msgstr "匹配应用" msgstr "匹配应用"
#: assets/api/asset/asset.py:181 #: assets/api/asset/asset.py:180
msgid "Cannot create asset directly, you should create a host or other" msgid "Cannot create asset directly, you should create a host or other"
msgstr "不能直接创建资产, 你应该创建主机或其他资产" msgstr "不能直接创建资产, 你应该创建主机或其他资产"
#: assets/api/domain.py:68 #: assets/api/domain.py:67
msgid "Number required" msgid "Number required"
msgstr "需要为数字" msgstr "需要为数字"
@ -4086,17 +4086,28 @@ msgstr "任务 {} 不存在"
msgid "Task {} args or kwargs error" msgid "Task {} args or kwargs error"
msgstr "任务 {} 执行参数错误" msgstr "任务 {} 执行参数错误"
#: ops/api/job.py:146 msgid ""
"Asset ({asset}) must have at least one of the following protocols added: "
"SSH, SFTP, or WinRM"
msgstr "资产({asset})至少要添加ssh,sftp,winrm其中一种协议"
msgid "Asset ({asset}) authorization is missing SSH, SFTP, or WinRM protocol"
msgstr "资产({asset})授权缺少ssh,sftp或winrm协议"
msgid "Asset ({asset}) authorization lacks upload permissions"
msgstr "资产({asset})授权缺少上传权限"
#: ops/api/job.py:168
msgid "Duplicate file exists" msgid "Duplicate file exists"
msgstr "存在同名文件" msgstr "存在同名文件"
#: ops/api/job.py:151 #: ops/api/job.py:173
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"File size exceeds maximum limit. Please select a file smaller than {limit}MB" "File size exceeds maximum limit. Please select a file smaller than {limit}MB"
msgstr "文件大小超过最大限制。请选择小于 {limit}MB 的文件。" msgstr "文件大小超过最大限制。请选择小于 {limit}MB 的文件。"
#: ops/api/job.py:215 #: ops/api/job.py:237
msgid "" msgid ""
"The task is being created and cannot be interrupted. Please try again later." "The task is being created and cannot be interrupted. Please try again later."
msgstr "正在创建任务,无法中断,请稍后重试。" msgstr "正在创建任务,无法中断,请稍后重试。"
@ -4484,17 +4495,17 @@ msgstr "Job ID"
msgid "Name of the job" msgid "Name of the job"
msgstr "Job 名称" msgstr "Job 名称"
#: orgs/api.py:62 #: orgs/api.py:61
msgid "The current organization ({}) cannot be deleted" msgid "The current organization ({}) cannot be deleted"
msgstr "当前组织 ({}) 不能被删除" msgstr "当前组织 ({}) 不能被删除"
#: orgs/api.py:67 #: orgs/api.py:66
msgid "" msgid ""
"LDAP synchronization is set to the current organization. Please switch to " "LDAP synchronization is set to the current organization. Please switch to "
"another organization before deleting" "another organization before deleting"
msgstr "LDAP 同步设置组织为当前组织,请切换其他组织后再进行删除操作" msgstr "LDAP 同步设置组织为当前组织,请切换其他组织后再进行删除操作"
#: orgs/api.py:77 #: orgs/api.py:76
msgid "The organization have resource ({}) cannot be deleted" msgid "The organization have resource ({}) cannot be deleted"
msgstr "组织存在资源 ({}) 不能被删除" msgstr "组织存在资源 ({}) 不能被删除"
@ -6435,11 +6446,11 @@ msgstr "企业版远程应用,在社区版中不能使用"
msgid "Not found protocol query params" msgid "Not found protocol query params"
msgstr "未发现 protocol 查询参数" msgstr "未发现 protocol 查询参数"
#: terminal/api/component/storage.py:30 #: terminal/api/component/storage.py:31
msgid "Deleting the default storage is not allowed" msgid "Deleting the default storage is not allowed"
msgstr "不允许删除默认存储配置" msgstr "不允许删除默认存储配置"
#: terminal/api/component/storage.py:33 #: terminal/api/component/storage.py:34
msgid "Cannot delete storage that is being used" msgid "Cannot delete storage that is being used"
msgstr "不允许删除正在使用的存储配置" msgstr "不允许删除正在使用的存储配置"
@ -6451,15 +6462,15 @@ msgstr "命令存储"
msgid "Invalid" msgid "Invalid"
msgstr "无效" msgstr "无效"
#: terminal/api/component/storage.py:131 terminal/tasks.py:149 #: terminal/api/component/storage.py:130 terminal/tasks.py:149
msgid "Test failure: {}" msgid "Test failure: {}"
msgstr "测试失败: {}" msgstr "测试失败: {}"
#: terminal/api/component/storage.py:134 #: terminal/api/component/storage.py:133
msgid "Test successful" msgid "Test successful"
msgstr "测试成功" msgstr "测试成功"
#: terminal/api/component/storage.py:136 #: terminal/api/component/storage.py:135
msgid "Test failure: Please check configuration" msgid "Test failure: Please check configuration"
msgstr "测试失败:请检查配置" msgstr "测试失败:请检查配置"
@ -7781,11 +7792,11 @@ msgstr "无效的审批动作"
msgid "This user is not authorized to approve this ticket" msgid "This user is not authorized to approve this ticket"
msgstr "此用户无权审批此工单" msgstr "此用户无权审批此工单"
#: users/api/user.py:137 #: users/api/user.py:136
msgid "Can not invite self" msgid "Can not invite self"
msgstr "不能邀请自己" msgstr "不能邀请自己"
#: users/api/user.py:190 #: users/api/user.py:189
msgid "Could not reset self otp, use profile reset instead" msgid "Could not reset self otp, use profile reset instead"
msgstr "不能在该页面重置 MFA 多因子认证, 请去个人信息页面重置" msgstr "不能在该页面重置 MFA 多因子认证, 请去个人信息页面重置"
@ -9182,6 +9193,3 @@ msgstr "企业专业版"
#: xpack/plugins/license/models.py:86 #: xpack/plugins/license/models.py:86
msgid "Ultimate edition" msgid "Ultimate edition"
msgstr "企业旗舰版" msgstr "企业旗舰版"
#~ msgid "Reopen"
#~ msgstr "重新打开"

View File

@ -32,6 +32,9 @@ from ops.variables import JMS_JOB_VARIABLE_HELP
from orgs.mixins.api import OrgBulkModelViewSet from orgs.mixins.api import OrgBulkModelViewSet
from orgs.utils import tmp_to_org, get_current_org from orgs.utils import tmp_to_org, get_current_org
from accounts.models import Account from accounts.models import Account
from assets.const import Protocol
from perms.const import ActionChoices
from perms.utils.asset_perm import PermAssetDetailUtil
from perms.models import PermNode from perms.models import PermNode
from perms.utils import UserPermAssetUtil from perms.utils import UserPermAssetUtil
from jumpserver.settings import get_file_md5 from jumpserver.settings import get_file_md5
@ -72,6 +75,22 @@ class JobViewSet(OrgBulkModelViewSet):
return self.permission_denied(request, "Command execution disabled") return self.permission_denied(request, "Command execution disabled")
return super().check_permissions(request) return super().check_permissions(request)
def check_upload_permission(self, assets, account_name):
protocols_required = {Protocol.ssh, Protocol.sftp, Protocol.winrm}
error_msg_missing_protocol = _(
"Asset ({asset}) must have at least one of the following protocols added: SSH, SFTP, or WinRM")
error_msg_auth_missing_protocol = _("Asset ({asset}) authorization is missing SSH, SFTP, or WinRM protocol")
error_msg_auth_missing_upload = _("Asset ({asset}) authorization lacks upload permissions")
for asset in assets:
protocols = asset.protocols.values_list("name", flat=True)
if not set(protocols).intersection(protocols_required):
self.permission_denied(self.request, error_msg_missing_protocol.format(asset=asset.name))
util = PermAssetDetailUtil(self.request.user, asset)
if not util.check_perm_protocols(protocols_required):
self.permission_denied(self.request, error_msg_auth_missing_protocol.format(asset=asset.name))
if not util.check_perm_actions(account_name, [ActionChoices.upload.value]):
self.permission_denied(self.request, error_msg_auth_missing_upload.format(asset=asset.name))
def get_queryset(self): def get_queryset(self):
queryset = super().get_queryset() queryset = super().get_queryset()
queryset = queryset \ queryset = queryset \
@ -89,6 +108,9 @@ class JobViewSet(OrgBulkModelViewSet):
assets = serializer.validated_data.get('assets') assets = serializer.validated_data.get('assets')
assets = merge_nodes_and_assets(node_ids, assets, self.request.user) assets = merge_nodes_and_assets(node_ids, assets, self.request.user)
serializer.validated_data['assets'] = assets serializer.validated_data['assets'] = assets
if serializer.validated_data.get('type') == Types.upload_file:
account_name = serializer.validated_data.get('runas')
self.check_upload_permission(assets, account_name)
instance = serializer.save() instance = serializer.save()
if instance.instant or run_after_save: if instance.instant or run_after_save:

View File

@ -42,6 +42,10 @@ class ActionChoices(BitChoices):
def contains(cls, total, action_value): def contains(cls, total, action_value):
return action_value & total == action_value return action_value & total == action_value
@classmethod
def contains_all(cls, total, action_values):
return all(cls.contains(total, action) for action in action_values)
@classmethod @classmethod
def display(cls, value): def display(cls, value):
return ', '.join([str(c.label) for c in cls if c.value & value == c.value]) return ', '.join([str(c.label) for c in cls if c.value & value == c.value])

View File

@ -6,6 +6,7 @@ from assets.models import Asset
from common.utils import lazyproperty from common.utils import lazyproperty
from orgs.utils import tmp_to_org, tmp_to_root_org from orgs.utils import tmp_to_org, tmp_to_root_org
from .permission import AssetPermissionUtil from .permission import AssetPermissionUtil
from perms.const import ActionChoices
__all__ = ['PermAssetDetailUtil'] __all__ = ['PermAssetDetailUtil']
@ -137,3 +138,23 @@ class PermAssetDetailUtil:
account.date_expired = max(cleaned_accounts_expired[account]) account.date_expired = max(cleaned_accounts_expired[account])
accounts.append(account) accounts.append(account)
return accounts return accounts
def check_perm_protocols(self, protocols):
"""
检查用户是否有某些协议权限
:param protocols: set
"""
perms_protocols = self.get_permed_protocols_for_user(only_name=True)
if "all" in perms_protocols:
return True
return protocols.intersection(perms_protocols)
def check_perm_actions(self, account_name, actions):
"""
检查用户是否有某个账号的某个资产操作权限
:param account_name: str
:param actions: list
"""
perms = self.user_asset_perms
action_bit_mapper, __ = self.parse_alias_action_date_expire(perms, self.asset)
return ActionChoices.contains_all(action_bit_mapper.get(account_name, 0), actions)