From 36301503e902bd3e0ff9a0e4ec403a7bbec5a9f6 Mon Sep 17 00:00:00 2001
From: feng <1304903146@qq.com>
Date: Mon, 9 Dec 2024 11:17:36 +0800
Subject: [PATCH 1/4] perf: Account push
---
apps/accounts/api/automations/push_account.py | 9 ++++++-
...ter_changesecretrecord_options_and_more.py | 24 +++++++++++++++++++
.../models/automations/change_secret.py | 5 +++-
.../accounts/change_secret_report.html | 2 +-
4 files changed, 37 insertions(+), 3 deletions(-)
create mode 100644 apps/accounts/migrations/0022_alter_changesecretrecord_options_and_more.py
diff --git a/apps/accounts/api/automations/push_account.py b/apps/accounts/api/automations/push_account.py
index 7b27cc7ca..b91bad379 100644
--- a/apps/accounts/api/automations/push_account.py
+++ b/apps/accounts/api/automations/push_account.py
@@ -30,6 +30,7 @@ class PushAccountExecutionViewSet(AutomationExecutionViewSet):
("list", "accounts.view_pushaccountexecution"),
("retrieve", "accounts.view_pushaccountexecution"),
("create", "accounts.add_pushaccountexecution"),
+ ("report", "accounts.view_pushaccountexecution"),
)
tp = AutomationTypes.push_account
@@ -44,9 +45,15 @@ class PushAccountRecordViewSet(ChangeSecretRecordViewSet):
serializer_class = serializers.ChangeSecretRecordSerializer
tp = AutomationTypes.push_account
+ rbac_perms = {
+ 'list': 'accounts.view_pushsecretrecord',
+ 'execute': 'accounts.add_pushsecretexecution',
+ 'secret': 'accounts.view_pushsecretrecord',
+ }
+
def get_queryset(self):
qs = ChangeSecretRecord.get_valid_records()
- return qs.objects.filter(
+ return qs.filter(
execution__automation__type=self.tp
)
diff --git a/apps/accounts/migrations/0022_alter_changesecretrecord_options_and_more.py b/apps/accounts/migrations/0022_alter_changesecretrecord_options_and_more.py
new file mode 100644
index 000000000..21bbc2c08
--- /dev/null
+++ b/apps/accounts/migrations/0022_alter_changesecretrecord_options_and_more.py
@@ -0,0 +1,24 @@
+# Generated by Django 4.1.13 on 2024-12-09 03:15
+
+from django.db import migrations
+import private_storage.fields
+import private_storage.storage.files
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('accounts', '0021_remove_pushaccountautomation_action_and_more'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='changesecretrecord',
+ options={'permissions': [('view_pushsecretrecord', 'Can view change secret execution'), ('add_pushsecretexecution', 'Can add change secret execution')], 'verbose_name': 'Change secret record'},
+ ),
+ migrations.AlterField(
+ model_name='integrationapplication',
+ name='logo',
+ field=private_storage.fields.PrivateImageField(max_length=128, storage=private_storage.storage.files.PrivateFileSystemStorage(), upload_to='images', verbose_name='Logo'),
+ ),
+ ]
diff --git a/apps/accounts/models/automations/change_secret.py b/apps/accounts/models/automations/change_secret.py
index 00e7cad04..d79c6660c 100644
--- a/apps/accounts/models/automations/change_secret.py
+++ b/apps/accounts/models/automations/change_secret.py
@@ -45,8 +45,11 @@ class ChangeSecretRecord(JMSBaseModel):
error = models.TextField(blank=True, null=True, verbose_name=_('Error'))
class Meta:
- ordering = ('-date_created',)
verbose_name = _("Change secret record")
+ permissions = [
+ ('view_pushsecretrecord', _('Can view change secret execution')),
+ ('add_pushsecretexecution', _('Can add change secret execution')),
+ ]
def __str__(self):
return f'{self.account.username}@{self.asset}'
diff --git a/apps/accounts/templates/accounts/change_secret_report.html b/apps/accounts/templates/accounts/change_secret_report.html
index 5459d23d6..2f836b2f8 100644
--- a/apps/accounts/templates/accounts/change_secret_report.html
+++ b/apps/accounts/templates/accounts/change_secret_report.html
@@ -1,7 +1,7 @@
{% load i18n %}
-
{% trans 'The following is a summary of account change secret tasks, please review and handle them' %}
+
{% trans 'The following is a summary of account change secret or push tasks, please read and process' %}
From 6806708820bb1019d2adced7e7eb5b5e27dd974d Mon Sep 17 00:00:00 2001
From: feng <1304903146@qq.com>
Date: Mon, 9 Dec 2024 15:18:14 +0800
Subject: [PATCH 2/4] perf: Random secret string
---
apps/common/utils/random.py | 52 +++++++++++++++++++++++++------------
1 file changed, 36 insertions(+), 16 deletions(-)
diff --git a/apps/common/utils/random.py b/apps/common/utils/random.py
index 7978267b9..2fcebdf94 100644
--- a/apps/common/utils/random.py
+++ b/apps/common/utils/random.py
@@ -18,9 +18,8 @@ def random_ip():
return socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
-def random_replace_char(s, chars, length):
+def random_replace_char(seq, chars, length):
using_index = set()
- seq = list(s)
while length > 0:
index = secrets.randbelow(len(seq) - 1)
@@ -29,7 +28,7 @@ def random_replace_char(s, chars, length):
seq[index] = secrets.choice(chars)
using_index.add(index)
length -= 1
- return ''.join(seq)
+ return seq
def remove_exclude_char(s, exclude_chars):
@@ -47,19 +46,40 @@ def random_string(
if length < 4:
raise ValueError('The length of the string must be greater than 3')
- chars_map = (
- (lower, string.ascii_lowercase),
- (upper, string.ascii_uppercase),
- (digit, string.digits),
- )
- chars = ''.join([i[1] for i in chars_map if i[0]])
- chars = remove_exclude_char(chars, exclude_chars)
- texts = list(secrets.choice(chars) for __ in range(length))
- texts = ''.join(texts)
+ char_list = []
+ if lower:
+
+ lower_chars = remove_exclude_char(string.ascii_lowercase, exclude_chars)
+ if not lower_chars:
+ raise ValueError('After excluding characters, no lowercase letters are available.')
+ char_list.append(lower_chars)
+
+ if upper:
+ upper_chars = remove_exclude_char(string.ascii_uppercase, exclude_chars)
+ if not upper_chars:
+ raise ValueError('After excluding characters, no uppercase letters are available.')
+ char_list.append(upper_chars)
+
+ if digit:
+ digit_chars = remove_exclude_char(string.digits, exclude_chars)
+ if not digit_chars:
+ raise ValueError('After excluding characters, no digits are available.')
+ char_list.append(digit_chars)
+
+ secret_chars = [secrets.choice(chars) for chars in char_list]
+
+ all_chars = ''.join(char_list)
+
+ remaining_length = length - len(secret_chars)
+ seq = [secrets.choice(all_chars) for _ in range(remaining_length)]
- # 控制一下特殊字符的数量, 别随机出来太多
if special_char:
- symbols = remove_exclude_char(symbols, exclude_chars)
+ special_chars = remove_exclude_char(symbols, exclude_chars)
+ if not special_chars:
+ raise ValueError('After excluding characters, no special characters are available.')
symbol_num = length // 16 + 1
- texts = random_replace_char(texts, symbols, symbol_num)
- return texts
+ seq = random_replace_char(seq, symbols, symbol_num)
+ secret_chars += seq
+
+ secrets.SystemRandom().shuffle(secret_chars)
+ return ''.join(secret_chars)
From 2e5d1f1cee32b66657eea00da69143f1e9b12ca1 Mon Sep 17 00:00:00 2001
From: wangruidong <940853815@qq.com>
Date: Mon, 9 Dec 2024 16:04:07 +0800
Subject: [PATCH 3/4] perf: Enhance SQL query and update risk handling in
accounts
---
.../database/sqlserver/main.yml | 21 ++++++++++++++++++-
.../automations/gather_account/filter.py | 10 ++++++---
.../automations/gather_account/manager.py | 4 ++--
apps/accounts/risk_handlers.py | 3 ++-
4 files changed, 31 insertions(+), 7 deletions(-)
diff --git a/apps/accounts/automations/gather_account/database/sqlserver/main.yml b/apps/accounts/automations/gather_account/database/sqlserver/main.yml
index 90bbe8cdb..252f5095e 100644
--- a/apps/accounts/automations/gather_account/database/sqlserver/main.yml
+++ b/apps/accounts/automations/gather_account/database/sqlserver/main.yml
@@ -12,7 +12,26 @@
login_port: "{{ jms_asset.port }}"
name: '{{ jms_asset.spec_info.db_name }}'
script: |
- select * from sys.sql_logins
+ SELECT
+ l.name,
+ l.modify_date,
+ l.is_disabled,
+ l.create_date,
+ l.default_database_name,
+ LOGINPROPERTY(name, 'DaysUntilExpiration') AS days_until_expiration,
+ MAX(s.login_time) AS last_login_time
+ FROM
+ sys.sql_logins l
+ LEFT JOIN
+ sys.dm_exec_sessions s
+ ON
+ l.name = s.login_name
+ WHERE
+ s.is_user_process = 1 OR s.login_name IS NULL
+ GROUP BY
+ l.name, l.create_date, l.modify_date, l.is_disabled, l.default_database_name
+ ORDER BY
+ last_login_time DESC;
output: dict
register: db_info
diff --git a/apps/accounts/automations/gather_account/filter.py b/apps/accounts/automations/gather_account/filter.py
index 757232fe3..809e99f9d 100644
--- a/apps/accounts/automations/gather_account/filter.py
+++ b/apps/accounts/automations/gather_account/filter.py
@@ -72,11 +72,14 @@ class GatherAccountsFilter:
return {}
result = {}
for user_info in info[0][0]:
+ days_until_expiration = user_info.get('days_until_expiration')
+ date_password_expired = timezone.now() + timezone.timedelta(
+ days=int(days_until_expiration)) if days_until_expiration else None
user = {
'username': user_info.get('name', ''),
- 'date_password_change': None,
- 'date_password_expired': None,
- 'date_last_login': None,
+ 'date_password_change': parse_date(user_info.get('modify_date')),
+ 'date_password_expired': date_password_expired,
+ 'date_last_login': parse_date(user_info.get('last_login_time')),
'groups': '',
}
detail = {
@@ -84,6 +87,7 @@ class GatherAccountsFilter:
'is_disabled': user_info.get('is_disabled', ''),
'default_database_name': user_info.get('default_database_name', ''),
}
+ print(user)
user['detail'] = detail
result[user['username']] = user
return result
diff --git a/apps/accounts/automations/gather_account/manager.py b/apps/accounts/automations/gather_account/manager.py
index f2ee64bbb..4d7840073 100644
--- a/apps/accounts/automations/gather_account/manager.py
+++ b/apps/accounts/automations/gather_account/manager.py
@@ -270,7 +270,7 @@ class GatherAccountsManager(AccountBasePlaybookManager):
lost_users = ori_ga_users - remote_users
if lost_users:
queryset.filter(username__in=lost_users).update(
- status="", remote_present=False
+ status=ConfirmOrIgnore.pending, remote_present=False
)
self.summary["lost_accounts"] += len(lost_users)
for username in lost_users:
@@ -285,7 +285,7 @@ class GatherAccountsManager(AccountBasePlaybookManager):
# 标识状态为 待处理, 让管理员去确认
ga_added_users = ori_ga_users - ori_users
if ga_added_users:
- queryset.filter(username__in=ga_added_users).update(status="")
+ queryset.filter(username__in=ga_added_users).update(status=ConfirmOrIgnore.pending)
# 收集的账号 比 账号列表少的
# 这个好像不不用对比,原始情况就这样
diff --git a/apps/accounts/risk_handlers.py b/apps/accounts/risk_handlers.py
index c7161a969..0f90886e7 100644
--- a/apps/accounts/risk_handlers.py
+++ b/apps/accounts/risk_handlers.py
@@ -53,7 +53,8 @@ class RiskHandler:
return r.first()
def handle_ignore(self):
- pass
+ GatheredAccount.objects.filter(asset=self.asset, username=self.username).update(status=ConfirmOrIgnore.ignored)
+ self.risk = 'ignored'
def handle_review(self):
pass
From c3766b9e1fa84dc5c59d7ecd73d024caa2ed6e9a Mon Sep 17 00:00:00 2001
From: feng <1304903146@qq.com>
Date: Mon, 9 Dec 2024 16:54:36 +0800
Subject: [PATCH 4/4] perf: Ticket filter assignee_id
---
apps/tickets/filters.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/apps/tickets/filters.py b/apps/tickets/filters.py
index dcba10036..edfba460d 100644
--- a/apps/tickets/filters.py
+++ b/apps/tickets/filters.py
@@ -23,7 +23,8 @@ class TicketFilter(BaseFilterSet):
def filter_assignees_id(self, queryset, name, value):
return queryset.filter(
- ticket_steps__ticket_assignees__assignee__id=value
+ ticket_steps__level=F('approval_step'),
+ ticket_steps__ticket_assignees__assignee_id=value
)
def filter_relevant_asset(self, queryset, name, value):