From 333bb64b8b2933db72899cae91dcf918afa47f85 Mon Sep 17 00:00:00 2001 From: xinwen Date: Wed, 26 Jan 2022 16:45:41 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20Authbook=20=E5=8F=96=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E4=BF=A1=E6=81=AFbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/assets/models/user.py | 38 +++++++++++++---- apps/assets/tasks/push_system_user.py | 59 ++++++++------------------- 2 files changed, 47 insertions(+), 50 deletions(-) diff --git a/apps/assets/models/user.py b/apps/assets/models/user.py index 999d51ad3..a888b404b 100644 --- a/apps/assets/models/user.py +++ b/apps/assets/models/user.py @@ -150,17 +150,37 @@ class AuthMixin: def load_asset_special_auth(self, asset, username=''): """ + AuthBook 的数据状态 + | asset | systemuser | username | + 1 | * | * | x | + 2 | * | x | * | + + 当前 AuthBook 只有以上两种状态,systemuser 与 username 不会并存。 + 正常的资产与系统用户关联产生的是第1种状态,改密则产生第2种状态。改密之后 + 只有 username 而没有 systemuser 。 + + Freq: 关联同一资产的多个系统用户指定同一用户名时,修改用户密码会影响所有系统用户 + + 这里有一个不对称的行为,同名系统用户密码覆盖 + 当有相同 username 的多个系统用户时,有改密动作之后,所有的同名系统用户都使用最后 + 一次改动,但如果没有发生过改密,同名系统用户使用的密码还是各自的。 + """ - authbooks = list(AuthBook.objects.filter(asset=asset).filter( - Q(username=username) | Q(systemuser=self) - )) - if len(authbooks) == 0: + if username == '': + username = self.username + + authbook = AuthBook.objects.filter( + asset=asset, username=username, systemuser__isnull=True + ).order_by('-date_created').first() + + if not authbook: + authbook = AuthBook.objects.filter( + asset=asset, systemuser=self + ).order_by('-date_created').first() + + if not authbook: return None - elif len(authbooks) == 1: - authbook = authbooks[0] - else: - authbooks.sort(key=lambda x: 1 if x.username == username else 0, reverse=True) - authbook = authbooks[0] + authbook.load_auth() self.password = authbook.password self.private_key = authbook.private_key diff --git a/apps/assets/tasks/push_system_user.py b/apps/assets/tasks/push_system_user.py index 9181f4fb7..4270f5e0f 100644 --- a/apps/assets/tasks/push_system_user.py +++ b/apps/assets/tasks/push_system_user.py @@ -4,10 +4,10 @@ from itertools import groupby from celery import shared_task from common.db.utils import get_object_if_need, get_objects from django.utils.translation import ugettext as _, gettext_noop -from django.db.models import Empty, Q +from django.db.models import Empty from common.utils import encrypt_password, get_logger -from assets.models import SystemUser, Asset, AuthBook +from assets.models import SystemUser, Asset from orgs.utils import org_aware_func, tmp_to_root_org from . import const from .utils import clean_ansible_task_hosts, group_asset_by_platform @@ -178,6 +178,7 @@ def get_push_windows_system_user_tasks(system_user: SystemUser, username=None): def get_push_system_user_tasks(system_user, platform="unixlike", username=None): """ + 获取推送系统用户的 ansible 命令,跟资产无关 :param system_user: :param platform: :param username: 当动态时,近推送某个 @@ -209,18 +210,10 @@ def push_system_user_util(system_user, assets, task_name, username=None): if not assets: return {} + # 资产按平台分类 assets_sorted = sorted(assets, key=group_asset_by_platform) platform_hosts = groupby(assets_sorted, key=group_asset_by_platform) - def run_task(_tasks, _hosts): - if not _tasks: - return - task, created = update_or_create_ansible_task( - task_name=task_name, hosts=_hosts, tasks=_tasks, pattern='all', - options=const.TASK_OPTIONS, run_as_admin=True, - ) - task.run() - if system_user.username_same_with_user: if username is None: # 动态系统用户,但是没有指定 username @@ -232,6 +225,15 @@ def push_system_user_util(system_user, assets, task_name, username=None): assert username is None, 'Only Dynamic user can assign `username`' usernames = [system_user.username] + def run_task(_tasks, _hosts): + if not _tasks: + return + task, created = update_or_create_ansible_task( + task_name=task_name, hosts=_hosts, tasks=_tasks, pattern='all', + options=const.TASK_OPTIONS, run_as_admin=True, + ) + task.run() + for platform, _assets in platform_hosts: _assets = list(_assets) if not _assets: @@ -239,36 +241,11 @@ def push_system_user_util(system_user, assets, task_name, username=None): print(_("Start push system user for platform: [{}]").format(platform)) print(_("Hosts count: {}").format(len(_assets))) - id_asset_map = {_asset.id: _asset for _asset in _assets} - asset_ids = id_asset_map.keys() - no_special_auth = [] - special_auth_set = set() - - auth_books = AuthBook.objects.filter(asset_id__in=asset_ids).filter( - Q(username__in=usernames) | Q(systemuser=system_user) - ).prefetch_related('systemuser') - - for auth_book in auth_books: - auth_book.load_auth() - special_auth_set.add((auth_book.username, auth_book.asset_id)) - - for _username in usernames: - no_special_assets = [] - for asset_id in asset_ids: - if (_username, asset_id) not in special_auth_set: - no_special_assets.append(id_asset_map[asset_id]) - if no_special_assets: - no_special_auth.append((_username, no_special_assets)) - - for _username, no_special_assets in no_special_auth: - tasks = get_push_system_user_tasks(system_user, platform, username=_username) - run_task(tasks, no_special_assets) - - for auth_book in auth_books: - system_user._merge_auth(auth_book) - tasks = get_push_system_user_tasks(system_user, platform, username=auth_book.username) - asset = id_asset_map[auth_book.asset_id] - run_task(tasks, [asset]) + for u in usernames: + for a in _assets: + system_user.load_asset_special_auth(a, u) + tasks = get_push_system_user_tasks(system_user, platform, username=u) + run_task(tasks, [a]) @shared_task(queue="ansible")