mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-07-16 16:01:35 +00:00
perf: windows ad gather account
This commit is contained in:
parent
d6b1a577fc
commit
1254d28463
@ -13,6 +13,7 @@ def parse_date(date_str, default=None):
|
||||
formats = [
|
||||
'%Y/%m/%d %H:%M:%S',
|
||||
'%Y-%m-%dT%H:%M:%S',
|
||||
'%Y-%m-%d %H:%M:%S',
|
||||
'%d-%m-%Y %H:%M:%S',
|
||||
'%Y/%m/%d',
|
||||
'%d-%m-%Y',
|
||||
@ -26,7 +27,6 @@ def parse_date(date_str, default=None):
|
||||
return default
|
||||
|
||||
|
||||
# TODO 后期会挪到 playbook 中
|
||||
class GatherAccountsFilter:
|
||||
def __init__(self, tp):
|
||||
self.tp = tp
|
||||
@ -208,14 +208,35 @@ class GatherAccountsFilter:
|
||||
key, value = parts
|
||||
user_info[key.strip()] = value.strip()
|
||||
detail = {'groups': user_info.get('Global Group memberships', ''), }
|
||||
user = {
|
||||
'username': user_info.get('User name', ''),
|
||||
'date_password_change': parse_date(user_info.get('Password last set', '')),
|
||||
'date_password_expired': parse_date(user_info.get('Password expires', '')),
|
||||
'date_last_login': parse_date(user_info.get('Last logon', '')),
|
||||
|
||||
username = user_info.get('User name')
|
||||
if not username:
|
||||
continue
|
||||
|
||||
result[username] = {
|
||||
'username': username,
|
||||
'date_password_change': parse_date(user_info.get('Password last set')),
|
||||
'date_password_expired': parse_date(user_info.get('Password expires')),
|
||||
'date_last_login': parse_date(user_info.get('Last logon')),
|
||||
'groups': detail,
|
||||
}
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def windows_ad_filter(info):
|
||||
result = {}
|
||||
for user_info in info['user_details']:
|
||||
detail = {'groups': user_info.get('GlobalGroupMemberships', ''), }
|
||||
username = user_info.get('SamAccountName')
|
||||
if not username:
|
||||
continue
|
||||
result[username] = {
|
||||
'username': username,
|
||||
'date_password_change': parse_date(user_info.get('PasswordLastSet')),
|
||||
'date_password_expired': parse_date(user_info.get('PasswordExpires')),
|
||||
'date_last_login': parse_date(user_info.get('LastLogonDate')),
|
||||
'groups': detail,
|
||||
}
|
||||
result[user['username']] = user
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
|
@ -4,10 +4,10 @@ version: 1
|
||||
method: gather_accounts
|
||||
category:
|
||||
- host
|
||||
- ds
|
||||
|
||||
type:
|
||||
- windows
|
||||
- windows_ad
|
||||
|
||||
|
||||
i18n:
|
||||
Windows account gather:
|
||||
|
@ -0,0 +1,74 @@
|
||||
- hosts: demo
|
||||
gather_facts: no
|
||||
tasks:
|
||||
- name: Import ActiveDirectory module
|
||||
win_shell: Import-Module ActiveDirectory
|
||||
args:
|
||||
warn: false
|
||||
|
||||
- name: Get the SamAccountName list of all AD users
|
||||
win_shell: |
|
||||
Import-Module ActiveDirectory
|
||||
Get-ADUser -Filter * | Select-Object -ExpandProperty SamAccountName
|
||||
register: ad_user_list
|
||||
|
||||
- name: Set the all_users variable
|
||||
set_fact:
|
||||
all_users: "{{ ad_user_list.stdout_lines }}"
|
||||
|
||||
- name: Get detailed information for each user
|
||||
win_shell: |
|
||||
Import-Module ActiveDirectory
|
||||
|
||||
$user = Get-ADUser -Identity {{ item }} -Properties Name, SamAccountName, Enabled, LastLogonDate, PasswordLastSet, msDS-UserPasswordExpiryTimeComputed, MemberOf
|
||||
|
||||
$globalGroups = @()
|
||||
if ($user.MemberOf) {
|
||||
$globalGroups = $user.MemberOf | ForEach-Object {
|
||||
try {
|
||||
$group = Get-ADGroup $_ -ErrorAction Stop
|
||||
if ($group.GroupScope -eq 'Global') { $group.Name }
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$passwordExpiry = $null
|
||||
$expiryRaw = $user.'msDS-UserPasswordExpiryTimeComputed'
|
||||
if ($expiryRaw) {
|
||||
try {
|
||||
$passwordExpiry = [datetime]::FromFileTime($expiryRaw)
|
||||
} catch {
|
||||
$passwordExpiry = $null
|
||||
}
|
||||
}
|
||||
|
||||
$output = [PSCustomObject]@{
|
||||
Name = $user.Name
|
||||
SamAccountName = $user.SamAccountName
|
||||
Enabled = $user.Enabled
|
||||
LastLogonDate = if ($user.LastLogonDate) { $user.LastLogonDate.ToString("yyyy-MM-dd HH:mm:ss") } else { $null }
|
||||
PasswordLastSet = if ($user.PasswordLastSet) { $user.PasswordLastSet.ToString("yyyy-MM-dd HH:mm:ss") } else { $null }
|
||||
PasswordExpires = if ($passwordExpiry) { $passwordExpiry.ToString("yyyy-MM-dd HH:mm:ss") } else { $null }
|
||||
GlobalGroupMemberships = $globalGroups
|
||||
}
|
||||
|
||||
$output | ConvertTo-Json -Depth 3
|
||||
loop: "{{ all_users }}"
|
||||
register: ad_user_details
|
||||
ignore_errors: yes
|
||||
|
||||
|
||||
- set_fact:
|
||||
info:
|
||||
user_details: >-
|
||||
{{
|
||||
ad_user_details.results
|
||||
| selectattr('rc', 'equalto', 0)
|
||||
| map(attribute='stdout')
|
||||
| select('truthy')
|
||||
| map('from_json')
|
||||
}}
|
||||
|
||||
- debug:
|
||||
var: info
|
@ -0,0 +1,15 @@
|
||||
id: gather_accounts_windows_ad
|
||||
name: "{{ 'Windows account gather' | trans }}"
|
||||
version: 1
|
||||
method: gather_accounts
|
||||
category:
|
||||
- ds
|
||||
|
||||
type:
|
||||
- windows_ad
|
||||
|
||||
i18n:
|
||||
Windows account gather:
|
||||
zh: 使用命令 Get-ADUser 收集 Windows 账号
|
||||
ja: コマンド Get-ADUser を使用して Windows アカウントを収集する
|
||||
en: Using command Get-ADUser to gather accounts
|
@ -1,6 +1,6 @@
|
||||
import time
|
||||
from collections import defaultdict
|
||||
|
||||
import time
|
||||
from django.utils import timezone
|
||||
|
||||
from accounts.const import AutomationTypes
|
||||
@ -222,6 +222,7 @@ class GatherAccountsManager(AccountBasePlaybookManager):
|
||||
def _collect_asset_account_info(self, asset, info):
|
||||
result = self._filter_success_result(asset.type, info)
|
||||
accounts = []
|
||||
|
||||
for username, info in result.items():
|
||||
self.asset_usernames_mapper[str(asset.id)].add(username)
|
||||
|
||||
|
@ -1,64 +0,0 @@
|
||||
# Generated by Django 4.1.13 on 2025-03-31 02:49
|
||||
|
||||
import json
|
||||
|
||||
import django
|
||||
from django.db import migrations, models
|
||||
|
||||
from assets.const.types import AllTypes
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("assets", "0015_automationexecution_type"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(add_ad_host_type),
|
||||
migrations.CreateModel(
|
||||
name="DS",
|
||||
fields=[
|
||||
(
|
||||
"asset_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="assets.asset",
|
||||
),
|
||||
),
|
||||
(
|
||||
"domain_name",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
max_length=128,
|
||||
verbose_name="Domain name",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Active Directory",
|
||||
},
|
||||
bases=("assets.asset",),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="platform",
|
||||
name="ds",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="ad_platforms",
|
||||
to="assets.ds",
|
||||
verbose_name="Active Directory",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="platform",
|
||||
name="ds_enabled",
|
||||
field=models.BooleanField(default=False, verbose_name="DS enabled"),
|
||||
),
|
||||
]
|
@ -48,7 +48,7 @@ def add_ds_platforms(apps, schema_editor):
|
||||
|
||||
},
|
||||
"gather_accounts_enabled": true,
|
||||
"gather_accounts_method": "gather_accounts_windows",
|
||||
"gather_accounts_method": "gather_accounts_windows_ad",
|
||||
"gather_accounts_params": {
|
||||
|
||||
},
|
||||
|
@ -2,6 +2,7 @@
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
|
||||
import sys
|
||||
@ -194,6 +195,7 @@ class JMSInventory:
|
||||
secret_info = {k: v for k, v in asset.secret_info.items() if v}
|
||||
host = {
|
||||
'name': name,
|
||||
'local_python_interpreter': sys.executable,
|
||||
'jms_asset': {
|
||||
'id': str(asset.id), 'name': asset.name, 'address': asset.address,
|
||||
'type': tp, 'category': category,
|
||||
|
Loading…
Reference in New Issue
Block a user