diff --git a/apps/locale/ja/LC_MESSAGES/django.mo b/apps/locale/ja/LC_MESSAGES/django.mo index 1805ce8e9..ae50e7b1e 100644 --- a/apps/locale/ja/LC_MESSAGES/django.mo +++ b/apps/locale/ja/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0bd11124a56e5fa0b2b8433528d4ffd8c454e5f529bdd72fea15d1a62434165e -size 176114 +oid sha256:488d95a4a96d38c3c0633f183334498d9e247bdf66ce3a4bcc836f80e8320432 +size 176705 diff --git a/apps/locale/ja/LC_MESSAGES/django.po b/apps/locale/ja/LC_MESSAGES/django.po index dd8c8d41b..42318fc26 100644 --- a/apps/locale/ja/LC_MESSAGES/django.po +++ b/apps/locale/ja/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\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" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1362,13 +1362,13 @@ msgstr "アプリケーション" msgid "Can match application" 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" msgstr "" "資産を直接作成することはできません。ホストまたはその他を作成する必要がありま" "す" -#: assets/api/domain.py:68 +#: assets/api/domain.py:67 msgid "Number required" msgstr "必要な数" @@ -4137,11 +4137,24 @@ msgstr "タスクは存在しません" msgid "Task {} args or kwargs error" 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" msgstr "重複したファイルが存在する" -#: ops/api/job.py:151 +#: ops/api/job.py:173 #, python-brace-format msgid "" "File size exceeds maximum limit. Please select a file smaller than {limit}MB" @@ -4149,7 +4162,7 @@ msgstr "" "ファイルサイズが最大制限を超えています。{limit}MB より小さいファイルを選択し" "てください。" -#: ops/api/job.py:215 +#: ops/api/job.py:237 msgid "" "The task is being created and cannot be interrupted. Please try again later." msgstr "タスクを作成中で、中断できません。後でもう一度お試しください。" @@ -4537,18 +4550,18 @@ msgstr "ジョブのID" msgid "Name of the job" msgstr "ジョブの名前" -#: orgs/api.py:62 +#: orgs/api.py:61 msgid "The current organization ({}) cannot be deleted" msgstr "現在の組織 ({}) は削除できません" -#: orgs/api.py:67 +#: orgs/api.py:66 msgid "" "LDAP synchronization is set to the current organization. Please switch to " "another organization before deleting" msgstr "" "LDAP 同期は現在の組織に設定されます。削除する前に別の組織に切り替えてください" -#: orgs/api.py:77 +#: orgs/api.py:76 msgid "The organization have resource ({}) cannot be deleted" msgstr "組織のリソース ({}) は削除できません" @@ -6531,11 +6544,11 @@ msgstr "これはエンタープライズ版アプレットです" msgid "Not found protocol query params" msgstr "プロトコルクエリパラメータが見つかりません" -#: terminal/api/component/storage.py:30 +#: terminal/api/component/storage.py:31 msgid "Deleting the default storage is not allowed" msgstr "デフォルトのストレージの削除は許可されていません" -#: terminal/api/component/storage.py:33 +#: terminal/api/component/storage.py:34 msgid "Cannot delete storage that is being used" msgstr "使用中のストレージを削除できません" @@ -6547,15 +6560,15 @@ msgstr "コマンドストア" msgid "Invalid" msgstr "無効" -#: terminal/api/component/storage.py:131 terminal/tasks.py:149 +#: terminal/api/component/storage.py:130 terminal/tasks.py:149 msgid "Test failure: {}" msgstr "テスト失敗: {}" -#: terminal/api/component/storage.py:134 +#: terminal/api/component/storage.py:133 msgid "Test successful" msgstr "テスト成功" -#: terminal/api/component/storage.py:136 +#: terminal/api/component/storage.py:135 msgid "Test failure: Please check configuration" msgstr "テストに失敗しました:構成を確認してください" @@ -7890,11 +7903,11 @@ msgstr "無効な承認アクション" msgid "This user is not authorized to approve this ticket" msgstr "このユーザーはこの作業指示を承認する権限がありません" -#: users/api/user.py:137 +#: users/api/user.py:136 msgid "Can not invite self" msgstr "自分自身を招待することはできません" -#: users/api/user.py:190 +#: users/api/user.py:189 msgid "Could not reset self otp, use profile reset instead" msgstr "自己otpをリセットできませんでした、代わりにプロファイルリセットを使用" @@ -9311,6 +9324,3 @@ msgstr "エンタープライズプロフェッショナル版" #: xpack/plugins/license/models.py:86 msgid "Ultimate edition" msgstr "エンタープライズ・フラッグシップ・エディション" - -#~ msgid "Reopen" -#~ msgstr "再オープン" diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 2d8086cf6..1a3b0eb5f 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91ad10be95fda19937a09d07806d05f21057a1a79f40428350127d1162c7655d -size 144168 +oid sha256:bd99d1b6018567413cefe5fe188a19019e09da46934c05ae9ce229943f712859 +size 144595 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index ac7831a71..9698cbb94 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\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" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -1354,11 +1354,11 @@ msgstr "应用程序" msgid "Can match application" 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" msgstr "不能直接创建资产, 你应该创建主机或其他资产" -#: assets/api/domain.py:68 +#: assets/api/domain.py:67 msgid "Number required" msgstr "需要为数字" @@ -4086,17 +4086,28 @@ msgstr "任务 {} 不存在" msgid "Task {} args or kwargs error" 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" msgstr "存在同名文件" -#: ops/api/job.py:151 +#: ops/api/job.py:173 #, python-brace-format msgid "" "File size exceeds maximum limit. Please select a file smaller than {limit}MB" msgstr "文件大小超过最大限制。请选择小于 {limit}MB 的文件。" -#: ops/api/job.py:215 +#: ops/api/job.py:237 msgid "" "The task is being created and cannot be interrupted. Please try again later." msgstr "正在创建任务,无法中断,请稍后重试。" @@ -4484,17 +4495,17 @@ msgstr "Job ID" msgid "Name of the job" msgstr "Job 名称" -#: orgs/api.py:62 +#: orgs/api.py:61 msgid "The current organization ({}) cannot be deleted" msgstr "当前组织 ({}) 不能被删除" -#: orgs/api.py:67 +#: orgs/api.py:66 msgid "" "LDAP synchronization is set to the current organization. Please switch to " "another organization before deleting" msgstr "LDAP 同步设置组织为当前组织,请切换其他组织后再进行删除操作" -#: orgs/api.py:77 +#: orgs/api.py:76 msgid "The organization have resource ({}) cannot be deleted" msgstr "组织存在资源 ({}) 不能被删除" @@ -6435,11 +6446,11 @@ msgstr "企业版远程应用,在社区版中不能使用" msgid "Not found protocol query params" msgstr "未发现 protocol 查询参数" -#: terminal/api/component/storage.py:30 +#: terminal/api/component/storage.py:31 msgid "Deleting the default storage is not allowed" msgstr "不允许删除默认存储配置" -#: terminal/api/component/storage.py:33 +#: terminal/api/component/storage.py:34 msgid "Cannot delete storage that is being used" msgstr "不允许删除正在使用的存储配置" @@ -6451,15 +6462,15 @@ msgstr "命令存储" msgid "Invalid" msgstr "无效" -#: terminal/api/component/storage.py:131 terminal/tasks.py:149 +#: terminal/api/component/storage.py:130 terminal/tasks.py:149 msgid "Test failure: {}" msgstr "测试失败: {}" -#: terminal/api/component/storage.py:134 +#: terminal/api/component/storage.py:133 msgid "Test successful" msgstr "测试成功" -#: terminal/api/component/storage.py:136 +#: terminal/api/component/storage.py:135 msgid "Test failure: Please check configuration" msgstr "测试失败:请检查配置" @@ -7781,11 +7792,11 @@ msgstr "无效的审批动作" msgid "This user is not authorized to approve this ticket" msgstr "此用户无权审批此工单" -#: users/api/user.py:137 +#: users/api/user.py:136 msgid "Can not invite self" msgstr "不能邀请自己" -#: users/api/user.py:190 +#: users/api/user.py:189 msgid "Could not reset self otp, use profile reset instead" msgstr "不能在该页面重置 MFA 多因子认证, 请去个人信息页面重置" @@ -9182,6 +9193,3 @@ msgstr "企业专业版" #: xpack/plugins/license/models.py:86 msgid "Ultimate edition" msgstr "企业旗舰版" - -#~ msgid "Reopen" -#~ msgstr "重新打开" diff --git a/apps/ops/api/job.py b/apps/ops/api/job.py index 91ffea79d..c65392e06 100644 --- a/apps/ops/api/job.py +++ b/apps/ops/api/job.py @@ -32,6 +32,9 @@ from ops.variables import JMS_JOB_VARIABLE_HELP from orgs.mixins.api import OrgBulkModelViewSet from orgs.utils import tmp_to_org, get_current_org 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.utils import UserPermAssetUtil from jumpserver.settings import get_file_md5 @@ -72,6 +75,22 @@ class JobViewSet(OrgBulkModelViewSet): return self.permission_denied(request, "Command execution disabled") 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): queryset = super().get_queryset() queryset = queryset \ @@ -89,6 +108,9 @@ class JobViewSet(OrgBulkModelViewSet): assets = serializer.validated_data.get('assets') assets = merge_nodes_and_assets(node_ids, assets, self.request.user) 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() if instance.instant or run_after_save: diff --git a/apps/perms/const.py b/apps/perms/const.py index 1e2851b3d..603824e19 100644 --- a/apps/perms/const.py +++ b/apps/perms/const.py @@ -42,6 +42,10 @@ class ActionChoices(BitChoices): def contains(cls, 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 def display(cls, value): return ', '.join([str(c.label) for c in cls if c.value & value == c.value]) diff --git a/apps/perms/utils/asset_perm.py b/apps/perms/utils/asset_perm.py index 178a5ab21..6de84121f 100644 --- a/apps/perms/utils/asset_perm.py +++ b/apps/perms/utils/asset_perm.py @@ -6,6 +6,7 @@ from assets.models import Asset from common.utils import lazyproperty from orgs.utils import tmp_to_org, tmp_to_root_org from .permission import AssetPermissionUtil +from perms.const import ActionChoices __all__ = ['PermAssetDetailUtil'] @@ -137,3 +138,23 @@ class PermAssetDetailUtil: account.date_expired = max(cleaned_accounts_expired[account]) accounts.append(account) 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)