mirror of https://github.com/jumpserver/jumpserver
Merge pull request #9688 from jumpserver/pr@dev@fix_job_center_account_not_in_perm
fix: 修复作业中心资产和用于没有过滤授权规则的问题pull/9694/head
commit
a4e920e410
|
@ -139,8 +139,11 @@ class JMSInventory:
|
||||||
self.make_ssh_account_vars(host, asset, account, automation, protocols, platform, gateway)
|
self.make_ssh_account_vars(host, asset, account, automation, protocols, platform, gateway)
|
||||||
return host
|
return host
|
||||||
|
|
||||||
|
def get_asset_accounts(self, asset):
|
||||||
|
return list(asset.accounts.filter(is_active=True))
|
||||||
|
|
||||||
def select_account(self, asset):
|
def select_account(self, asset):
|
||||||
accounts = list(asset.accounts.filter(is_active=True))
|
accounts = self.get_asset_accounts(asset)
|
||||||
if not accounts:
|
if not accounts:
|
||||||
return None
|
return None
|
||||||
account_selected = None
|
account_selected = None
|
||||||
|
|
|
@ -2,26 +2,90 @@ import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
from celery import current_task
|
from celery import current_task
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Q
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
__all__ = ["Job", "JobExecution"]
|
__all__ = ["Job", "JobExecution", "JMSPermedInventory"]
|
||||||
|
|
||||||
from simple_history.models import HistoricalRecords
|
from simple_history.models import HistoricalRecords
|
||||||
|
|
||||||
|
from accounts.models import Account
|
||||||
from acls.models import CommandFilterACL
|
from acls.models import CommandFilterACL
|
||||||
|
from assets.models import Asset
|
||||||
from ops.ansible import JMSInventory, AdHocRunner, PlaybookRunner
|
from ops.ansible import JMSInventory, AdHocRunner, PlaybookRunner
|
||||||
from ops.mixin import PeriodTaskModelMixin
|
from ops.mixin import PeriodTaskModelMixin
|
||||||
from ops.variables import *
|
from ops.variables import *
|
||||||
from ops.const import Types, Modules, RunasPolicies, JobStatus
|
from ops.const import Types, Modules, RunasPolicies, JobStatus
|
||||||
from orgs.mixins.models import JMSOrgBaseModel
|
from orgs.mixins.models import JMSOrgBaseModel
|
||||||
|
from perms.models import AssetPermission
|
||||||
|
from perms.utils import UserPermAssetUtil
|
||||||
from terminal.notifications import CommandExecutionAlert
|
from terminal.notifications import CommandExecutionAlert
|
||||||
|
|
||||||
|
|
||||||
|
def get_parent_keys(key, include_self=True):
|
||||||
|
keys = []
|
||||||
|
split_keys = key.split(':')
|
||||||
|
for i in range(len(split_keys)):
|
||||||
|
keys.append(':'.join(split_keys[:i + 1]))
|
||||||
|
if not include_self:
|
||||||
|
keys.pop()
|
||||||
|
return keys
|
||||||
|
|
||||||
|
|
||||||
|
class JMSPermedInventory(JMSInventory):
|
||||||
|
def __init__(self, assets, account_policy='privileged_first',
|
||||||
|
account_prefer='root,Administrator', host_callback=None, exclude_localhost=False, user=None):
|
||||||
|
super().__init__(assets, account_policy, account_prefer, host_callback, exclude_localhost)
|
||||||
|
self.user = user
|
||||||
|
self.assets_accounts_mapper = self.get_assets_accounts_mapper()
|
||||||
|
|
||||||
|
def get_asset_accounts(self, asset):
|
||||||
|
return self.assets_accounts_mapper.get(asset.id, [])
|
||||||
|
|
||||||
|
def get_assets_accounts_mapper(self):
|
||||||
|
mapper = defaultdict(set)
|
||||||
|
asset_ids = self.assets.values_list('id', flat=True)
|
||||||
|
asset_node_keys = Asset.nodes.through.objects \
|
||||||
|
.filter(asset_id__in=asset_ids) \
|
||||||
|
.values_list('asset_id', 'node__key')
|
||||||
|
|
||||||
|
node_asset_map = defaultdict(set)
|
||||||
|
for asset_id, node_key in asset_node_keys:
|
||||||
|
all_keys = get_parent_keys(node_key)
|
||||||
|
for key in all_keys:
|
||||||
|
node_asset_map[key].add(asset_id)
|
||||||
|
|
||||||
|
groups = self.user.groups.all()
|
||||||
|
perms = AssetPermission.objects \
|
||||||
|
.filter(date_expired__gte=timezone.now()) \
|
||||||
|
.filter(is_active=True) \
|
||||||
|
.filter(Q(users=self.user) | Q(user_groups__in=groups)) \
|
||||||
|
.filter(Q(assets__in=asset_ids) | Q(nodes__key__in=node_asset_map.keys())) \
|
||||||
|
.values_list('assets', 'nodes__key', 'accounts')
|
||||||
|
|
||||||
|
asset_permed_accounts_mapper = defaultdict(set)
|
||||||
|
for asset_id, node_key, accounts in perms:
|
||||||
|
if asset_id in asset_ids:
|
||||||
|
asset_permed_accounts_mapper[asset_id].update(accounts)
|
||||||
|
for my_asset in node_asset_map[node_key]:
|
||||||
|
asset_permed_accounts_mapper[my_asset].update(accounts)
|
||||||
|
|
||||||
|
accounts = Account.objects.filter(asset__in=asset_ids)
|
||||||
|
for account in accounts:
|
||||||
|
if account.asset_id not in asset_permed_accounts_mapper:
|
||||||
|
continue
|
||||||
|
permed_usernames = asset_permed_accounts_mapper[account.asset_id]
|
||||||
|
if "@ALL" in permed_usernames or account.username in permed_usernames:
|
||||||
|
mapper[account.asset_id].add(account)
|
||||||
|
return mapper
|
||||||
|
|
||||||
|
|
||||||
class Job(JMSOrgBaseModel, PeriodTaskModelMixin):
|
class Job(JMSOrgBaseModel, PeriodTaskModelMixin):
|
||||||
name = models.CharField(max_length=128, null=True, verbose_name=_('Name'))
|
name = models.CharField(max_length=128, null=True, verbose_name=_('Name'))
|
||||||
|
|
||||||
|
@ -90,7 +154,7 @@ class Job(JMSOrgBaseModel, PeriodTaskModelMixin):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def inventory(self):
|
def inventory(self):
|
||||||
return JMSInventory(self.assets.all(), self.runas_policy, self.runas)
|
return JMSPermedInventory(self.assets.all(), self.runas_policy, self.runas, user=self.creator)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def material(self):
|
def material(self):
|
||||||
|
@ -339,7 +403,19 @@ class JobExecution(JMSOrgBaseModel):
|
||||||
'dangerous keyword \'{}\'\033[0m'.format(line['line'], line['file'], line['keyword']))
|
'dangerous keyword \'{}\'\033[0m'.format(line['line'], line['file'], line['keyword']))
|
||||||
raise Exception("Playbook contains dangerous keywords")
|
raise Exception("Playbook contains dangerous keywords")
|
||||||
|
|
||||||
|
def check_assets_perms(self):
|
||||||
|
all_permed_assets = UserPermAssetUtil(self.creator).get_all_assets()
|
||||||
|
has_permed_assets = set(self.current_job.assets.all()) & set(all_permed_assets)
|
||||||
|
|
||||||
|
for asset in self.current_job.assets.all():
|
||||||
|
if asset not in has_permed_assets:
|
||||||
|
print("\033[31mAsset {}({}) has no access permission\033[0m".format(asset.name, asset.address))
|
||||||
|
|
||||||
|
if self.current_job.assets.count() != len(has_permed_assets):
|
||||||
|
raise Exception("You do not have access rights to some assets")
|
||||||
|
|
||||||
def before_start(self):
|
def before_start(self):
|
||||||
|
self.check_assets_perms()
|
||||||
if self.current_job.type == 'playbook':
|
if self.current_job.type == 'playbook':
|
||||||
self.check_danger_keywords()
|
self.check_danger_keywords()
|
||||||
if self.current_job.type == 'adhoc':
|
if self.current_job.type == 'adhoc':
|
||||||
|
|
|
@ -3,7 +3,7 @@ import uuid
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from assets.models import Node
|
from assets.models import Node, Asset
|
||||||
from perms.utils.user_perm import UserPermAssetUtil
|
from perms.utils.user_perm import UserPermAssetUtil
|
||||||
from common.serializers.fields import ReadableHiddenField
|
from common.serializers.fields import ReadableHiddenField
|
||||||
from ops.mixin import PeriodTaskSerializerMixin
|
from ops.mixin import PeriodTaskSerializerMixin
|
||||||
|
@ -17,6 +17,8 @@ class JobSerializer(BulkOrgResourceModelSerializer, PeriodTaskSerializerMixin):
|
||||||
nodes = serializers.ListField(required=False, child=serializers.CharField())
|
nodes = serializers.ListField(required=False, child=serializers.CharField())
|
||||||
date_last_run = serializers.DateTimeField(label=_('Date last run'), read_only=True)
|
date_last_run = serializers.DateTimeField(label=_('Date last run'), read_only=True)
|
||||||
name = serializers.CharField(label=_('Name'), max_length=128, allow_blank=True, required=False)
|
name = serializers.CharField(label=_('Name'), max_length=128, allow_blank=True, required=False)
|
||||||
|
assets = serializers.PrimaryKeyRelatedField(label=_('Assets'), queryset=Asset.objects, many=True,
|
||||||
|
required=False)
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
instant = data.get('instant', False)
|
instant = data.get('instant', False)
|
||||||
|
|
Loading…
Reference in New Issue