mirror of https://github.com/jumpserver/jumpserver
parent
7560a5cd1f
commit
ebfc3b7b38
|
@ -1,17 +1,28 @@
|
|||
import os
|
||||
import time
|
||||
import random
|
||||
import string
|
||||
from copy import deepcopy
|
||||
from openpyxl import Workbook
|
||||
from collections import defaultdict
|
||||
|
||||
from django.utils import timezone
|
||||
from django.conf import settings
|
||||
|
||||
from common.utils import lazyproperty, gen_key_pair
|
||||
from common.utils.timezone import local_now_display
|
||||
from common.utils.file import encrypt_and_compress_zip_file
|
||||
from common.utils import get_logger, lazyproperty, gen_key_pair
|
||||
from users.models import User
|
||||
from assets.models import ChangeSecretRecord
|
||||
from assets.notifications import ChangeSecretExecutionTaskMsg
|
||||
from assets.serializers import ChangeSecretRecordBackUpSerializer
|
||||
from assets.const import (
|
||||
AutomationTypes, SecretType, SecretStrategy, SSHKeyStrategy, DEFAULT_PASSWORD_RULES
|
||||
)
|
||||
from ..base.manager import BasePlaybookManager
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class ChangeSecretManager(BasePlaybookManager):
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -125,7 +136,7 @@ class ChangeSecretManager(BasePlaybookManager):
|
|||
new_secret = self.get_secret()
|
||||
|
||||
recorder = ChangeSecretRecord(
|
||||
account=account, execution=self.execution,
|
||||
asset=asset, account=account, execution=self.execution,
|
||||
old_secret=account.secret, new_secret=new_secret,
|
||||
)
|
||||
records.append(recorder)
|
||||
|
@ -172,4 +183,51 @@ class ChangeSecretManager(BasePlaybookManager):
|
|||
recorder.save()
|
||||
|
||||
def on_runner_failed(self, runner, e):
|
||||
pass
|
||||
logger.error("Change secret error: ", e)
|
||||
|
||||
def run(self, *args, **kwargs):
|
||||
super().run(*args, **kwargs)
|
||||
recorders = self.name_recorder_mapper.values()
|
||||
recorders = list(recorders)
|
||||
self.send_recorder_mail(recorders)
|
||||
|
||||
def send_recorder_mail(self, recorders):
|
||||
if not recorders:
|
||||
return
|
||||
recipients = self.execution.recipients
|
||||
if not recipients:
|
||||
return
|
||||
recipients = User.objects.filter(id__in=list(recipients))
|
||||
|
||||
name = self.execution.snapshot['name']
|
||||
path = os.path.join(os.path.dirname(settings.BASE_DIR), 'tmp')
|
||||
filename = os.path.join(path, f'{name}-{local_now_display()}-{time.time()}.xlsx')
|
||||
if not self.create_file(recorders, filename):
|
||||
return
|
||||
|
||||
for user in recipients:
|
||||
attachments = []
|
||||
if user.secret_key:
|
||||
password = user.secret_key.encode('utf8')
|
||||
attachment = os.path.join(path, f'{name}-{local_now_display()}-{time.time()}.zip')
|
||||
encrypt_and_compress_zip_file(attachment, password, [filename])
|
||||
attachments = [attachment]
|
||||
ChangeSecretExecutionTaskMsg(name, user).publish(attachments)
|
||||
os.remove(filename)
|
||||
|
||||
@staticmethod
|
||||
def create_file(recorders, filename):
|
||||
serializer_cls = ChangeSecretRecordBackUpSerializer
|
||||
serializer = serializer_cls(recorders, many=True)
|
||||
header = [v.label for v in serializer.child.fields.values()]
|
||||
rows = [list(row.values()) for row in serializer.data]
|
||||
if not rows:
|
||||
return False
|
||||
|
||||
rows.insert(0, header)
|
||||
wb = Workbook(filename)
|
||||
ws = wb.create_sheet('Sheet1')
|
||||
for row in rows:
|
||||
ws.append(row)
|
||||
wb.save(filename)
|
||||
return True
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 3.2.14 on 2022-11-03 13:57
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0109_rename_categories_to_types'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='changesecretrecord',
|
||||
name='asset',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='assets.asset'),
|
||||
),
|
||||
]
|
|
@ -111,6 +111,13 @@ class AutomationExecution(OrgModelMixin):
|
|||
def manager_type(self):
|
||||
return self.snapshot['type']
|
||||
|
||||
@property
|
||||
def recipients(self):
|
||||
recipients = self.snapshot.get('recipients')
|
||||
if not recipients:
|
||||
return []
|
||||
return recipients.values()
|
||||
|
||||
def start(self):
|
||||
from assets.automations.endpoint import ExecutionManager
|
||||
manager = ExecutionManager(execution=self)
|
||||
|
|
|
@ -51,6 +51,7 @@ class ChangeSecretAutomation(BaseAutomation):
|
|||
|
||||
class ChangeSecretRecord(JMSBaseModel):
|
||||
execution = models.ForeignKey('assets.AutomationExecution', on_delete=models.CASCADE)
|
||||
asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, null=True)
|
||||
account = models.ForeignKey('assets.Account', on_delete=models.CASCADE, null=True)
|
||||
old_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Old secret'))
|
||||
new_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Secret'))
|
||||
|
|
|
@ -158,7 +158,6 @@ class BaseAccount(OrgModelMixin):
|
|||
return {
|
||||
'name': self.name,
|
||||
'username': self.username,
|
||||
'password': self.password,
|
||||
'public_key': self.public_key,
|
||||
}
|
||||
|
||||
|
|
|
@ -15,11 +15,35 @@ class AccountBackupExecutionTaskMsg(object):
|
|||
def message(self):
|
||||
name = self.name
|
||||
if self.user.secret_key:
|
||||
return _('{} - The account backup passage task has been completed. See the attachment for details').format(name)
|
||||
return _('{} - The account backup passage task has been completed. See the attachment for details').format(
|
||||
name)
|
||||
return _("{} - The account backup passage task has been completed: the encryption password has not been set - "
|
||||
"please go to personal information -> file encryption password to set the encryption password").format(name)
|
||||
"please go to personal information -> file encryption password to set the encryption password").format(
|
||||
name)
|
||||
|
||||
def publish(self, attachment_list=None):
|
||||
send_mail_attachment_async.delay(
|
||||
self.subject, self.message, [self.user.email], attachment_list
|
||||
)
|
||||
|
||||
|
||||
class ChangeSecretExecutionTaskMsg(object):
|
||||
subject = _('Notification of implementation result of encryption change plan')
|
||||
|
||||
def __init__(self, name: str, user: User):
|
||||
self.name = name
|
||||
self.user = user
|
||||
|
||||
@property
|
||||
def message(self):
|
||||
name = self.name
|
||||
if self.user.secret_key:
|
||||
return _('{} - The encryption change task has been completed. See the attachment for details').format(name)
|
||||
return _("{} - The encryption change task has been completed: the encryption password has not been set - "
|
||||
"please go to personal information -> file encryption password to set the encryption password").format(
|
||||
name)
|
||||
|
||||
def publish(self, attachments=None):
|
||||
send_mail_attachment_async.delay(
|
||||
self.subject, self.message, [self.user.email], attachments
|
||||
)
|
||||
|
|
|
@ -11,3 +11,4 @@ from .account import *
|
|||
from assets.serializers.account.backup import *
|
||||
from .platform import *
|
||||
from .cagegory import *
|
||||
from .automation import *
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
from django.utils.translation import ugettext as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from common.utils import get_logger
|
||||
|
||||
from assets.models import ChangeSecretRecord
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
||||
class ChangeSecretRecordBackUpSerializer(serializers.ModelSerializer):
|
||||
asset = serializers.SerializerMethodField(label=_('Asset'))
|
||||
account = serializers.SerializerMethodField(label=_('Account'))
|
||||
is_success = serializers.SerializerMethodField(label=_('Is success'))
|
||||
|
||||
class Meta:
|
||||
model = ChangeSecretRecord
|
||||
fields = [
|
||||
'id', 'asset', 'account', 'old_secret', 'new_secret',
|
||||
'status', 'error', 'is_success'
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def get_asset(instance):
|
||||
return str(instance.asset)
|
||||
|
||||
@staticmethod
|
||||
def get_account(instance):
|
||||
return str(instance.account)
|
||||
|
||||
@staticmethod
|
||||
def get_is_success(obj):
|
||||
if obj.status == 'success':
|
||||
return _("Success")
|
||||
return _("Failed")
|
Loading…
Reference in New Issue