From d9a9f890f5fe6e0a74f24950996859542affb2b3 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Wed, 20 Nov 2024 14:07:04 +0800 Subject: [PATCH 01/18] perf: Lina AzureKeyVault translate --- apps/i18n/lina/en.json | 1 + apps/i18n/lina/ja.json | 1 + apps/i18n/lina/zh.json | 1 + apps/i18n/lina/zh_hant.json | 1 + 4 files changed, 4 insertions(+) diff --git a/apps/i18n/lina/en.json b/apps/i18n/lina/en.json index f4d47d487..49c65e37a 100644 --- a/apps/i18n/lina/en.json +++ b/apps/i18n/lina/en.json @@ -177,6 +177,7 @@ "AwaitingMyApproval": "Assigned", "Azure": "Azure (China)", "Azure_Int": "Azure (International)", + "AzureKeyVault": "Azure vault", "Backup": "Backup", "BackupAccountsHelpText": "Backup account information externally. it can be stored in an external system or sent via email, supporting segmented delivery.", "BadConflictErrorMsg": "Refreshing, please try again later", diff --git a/apps/i18n/lina/ja.json b/apps/i18n/lina/ja.json index ba957ef8b..57288b30a 100644 --- a/apps/i18n/lina/ja.json +++ b/apps/i18n/lina/ja.json @@ -177,6 +177,7 @@ "AwaitingMyApproval": "私の承認待ち", "Azure": "Azure(中国)", "Azure_Int": "アジュール(インターナショナル)", + "AzureKeyVault": "Azure vault", "Backup": "バックアップ", "BackupAccountsHelpText": "アカウント情報を外部にバックアップする。外部システムに保存するかメールを送信することもできます、セクション方式をサポートしています", "BadConflictErrorMsg": "更新中です、しばらくお待ちください", diff --git a/apps/i18n/lina/zh.json b/apps/i18n/lina/zh.json index 73c7ea3ad..7c82132b3 100644 --- a/apps/i18n/lina/zh.json +++ b/apps/i18n/lina/zh.json @@ -177,6 +177,7 @@ "AwaitingMyApproval": "待我审批", "Azure": "Azure (中国)", "Azure_Int": "Azure (国际)", + "AzureKeyVault": "Azure vault", "Backup": "备份", "BackupAccountsHelpText": "备份账号信息到外部。可以存储到外部系统或发送邮件,支持分段方式", "BadConflictErrorMsg": "正在刷新中,请稍后再试", diff --git a/apps/i18n/lina/zh_hant.json b/apps/i18n/lina/zh_hant.json index 3a07509bc..4adc747de 100644 --- a/apps/i18n/lina/zh_hant.json +++ b/apps/i18n/lina/zh_hant.json @@ -238,6 +238,7 @@ "AwaitingMyApproval": "待我審批", "Azure": "Azure (中國)", "Azure_Int": "Azure (國際)", + "AzureKeyVault": "Azure vault", "Backup": "備份", "BackupAccountsHelpText": "備份帳號資訊至外部。可以儲存到外部系統或寄送郵件,支援分段方式", "BadConflictErrorMsg": "正在刷新中,請稍後再試", From 9cfe974c52b8ce187ad73c21780bb608a0f71116 Mon Sep 17 00:00:00 2001 From: Aaron3S Date: Wed, 20 Nov 2024 14:11:29 +0800 Subject: [PATCH 02/18] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20mfa=20middle?= =?UTF-8?q?ware=20=E7=99=BD=E5=90=8D=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/authentication/middleware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/authentication/middleware.py b/apps/authentication/middleware.py index d1f3b087b..64f8818a9 100644 --- a/apps/authentication/middleware.py +++ b/apps/authentication/middleware.py @@ -35,7 +35,7 @@ class MFAMiddleware: # 这个是 mfa 登录页需要的请求, 也得放出来, 用户其实已经在 CAS/OIDC 中完成登录了 white_urls = [ - 'login/mfa', 'mfa/select', 'jsi18n/', '/static/', + 'login/mfa', 'mfa/select', 'mfa/face','jsi18n/', '/static/', '/profile/otp', '/logout/', ] for url in white_urls: From 9966ad4c71ce5a45db6da70e9b040adc5c5bcc08 Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Wed, 20 Nov 2024 15:02:58 +0800 Subject: [PATCH 03/18] perf: Dynamic update vault --- apps/accounts/backends/__init__.py | 8 ++++++-- apps/accounts/signal_handlers.py | 20 +++++++++++++++++++- apps/i18n/lina/en.json | 1 + apps/i18n/lina/ja.json | 1 + apps/i18n/lina/zh.json | 1 + apps/i18n/lina/zh_hant.json | 1 + apps/settings/serializers/feature.py | 17 +++++++++++++---- 7 files changed, 42 insertions(+), 7 deletions(-) diff --git a/apps/accounts/backends/__init__.py b/apps/accounts/backends/__init__.py index 832033b73..5e26cfc76 100644 --- a/apps/accounts/backends/__init__.py +++ b/apps/accounts/backends/__init__.py @@ -5,8 +5,7 @@ from django.utils.functional import LazyObject from common.utils import get_logger from ..const import VaultTypeChoices -__all__ = ['vault_client', 'get_vault_client'] - +__all__ = ['vault_client', 'get_vault_client', 'refresh_vault_client'] logger = get_logger(__file__) @@ -38,3 +37,8 @@ class VaultClient(LazyObject): """ 为了安全, 页面修改配置, 重启服务后才会重新初始化 vault_client """ vault_client = VaultClient() + + +def refresh_vault_client(): + vault_client._wrapped = None + vault_client._setup() diff --git a/apps/accounts/signal_handlers.py b/apps/accounts/signal_handlers.py index ad07c9bb3..04c2cc333 100644 --- a/apps/accounts/signal_handlers.py +++ b/apps/accounts/signal_handlers.py @@ -3,14 +3,17 @@ from collections import defaultdict from django.db.models.signals import post_delete from django.db.models.signals import pre_save, post_save from django.dispatch import receiver +from django.utils.functional import LazyObject from django.utils.translation import gettext_noop -from accounts.backends import vault_client +from accounts.backends import vault_client, refresh_vault_client from accounts.const import Source from audits.const import ActivityChoices from audits.signal_handlers import create_activities from common.decorators import merge_delay_run +from common.signals import django_ready from common.utils import get_logger, i18n_fmt +from common.utils.connection import RedisPubSub from .models import Account, AccountTemplate from .tasks.push_account import push_accounts_to_assets_task @@ -91,3 +94,18 @@ class VaultSignalHandler(object): for model in (Account, AccountTemplate, Account.history.model): post_save.connect(VaultSignalHandler.save_to_vault, sender=model) post_delete.connect(VaultSignalHandler.delete_to_vault, sender=model) + + +class VaultPubSub(LazyObject): + def _setup(self): + self._wrapped = RedisPubSub('refresh_vault') + + +vault_pub_sub = VaultPubSub() + + +@receiver(django_ready) +def subscribe_vault_change(sender, **kwargs): + logger.debug("Start subscribe vault change") + + vault_pub_sub.subscribe(lambda name: refresh_vault_client()) diff --git a/apps/i18n/lina/en.json b/apps/i18n/lina/en.json index 49c65e37a..fecab5059 100644 --- a/apps/i18n/lina/en.json +++ b/apps/i18n/lina/en.json @@ -178,6 +178,7 @@ "Azure": "Azure (China)", "Azure_Int": "Azure (International)", "AzureKeyVault": "Azure vault", + "HashicorpVault": "HCP vault", "Backup": "Backup", "BackupAccountsHelpText": "Backup account information externally. it can be stored in an external system or sent via email, supporting segmented delivery.", "BadConflictErrorMsg": "Refreshing, please try again later", diff --git a/apps/i18n/lina/ja.json b/apps/i18n/lina/ja.json index 57288b30a..b4bd08b0b 100644 --- a/apps/i18n/lina/ja.json +++ b/apps/i18n/lina/ja.json @@ -178,6 +178,7 @@ "Azure": "Azure(中国)", "Azure_Int": "アジュール(インターナショナル)", "AzureKeyVault": "Azure vault", + "HashicorpVault": "HCP vault", "Backup": "バックアップ", "BackupAccountsHelpText": "アカウント情報を外部にバックアップする。外部システムに保存するかメールを送信することもできます、セクション方式をサポートしています", "BadConflictErrorMsg": "更新中です、しばらくお待ちください", diff --git a/apps/i18n/lina/zh.json b/apps/i18n/lina/zh.json index 7c82132b3..f84e5c540 100644 --- a/apps/i18n/lina/zh.json +++ b/apps/i18n/lina/zh.json @@ -178,6 +178,7 @@ "Azure": "Azure (中国)", "Azure_Int": "Azure (国际)", "AzureKeyVault": "Azure vault", + "HashicorpVault": "HCP vault", "Backup": "备份", "BackupAccountsHelpText": "备份账号信息到外部。可以存储到外部系统或发送邮件,支持分段方式", "BadConflictErrorMsg": "正在刷新中,请稍后再试", diff --git a/apps/i18n/lina/zh_hant.json b/apps/i18n/lina/zh_hant.json index 4adc747de..1216087ee 100644 --- a/apps/i18n/lina/zh_hant.json +++ b/apps/i18n/lina/zh_hant.json @@ -239,6 +239,7 @@ "Azure": "Azure (中國)", "Azure_Int": "Azure (國際)", "AzureKeyVault": "Azure vault", + "HashicorpVault": "HCP vault", "Backup": "備份", "BackupAccountsHelpText": "備份帳號資訊至外部。可以儲存到外部系統或寄送郵件,支援分段方式", "BadConflictErrorMsg": "正在刷新中,請稍後再試", diff --git a/apps/settings/serializers/feature.py b/apps/settings/serializers/feature.py index 23a484571..b6dcacc08 100644 --- a/apps/settings/serializers/feature.py +++ b/apps/settings/serializers/feature.py @@ -1,9 +1,9 @@ import uuid + from django.utils import timezone from django.utils.translation import gettext_lazy as _ from rest_framework import serializers -from accounts.const import VaultTypeChoices from assets.const import Protocol from common.serializers.fields import EncryptedField from common.utils import date_expired_default @@ -43,7 +43,16 @@ class AnnouncementSettingSerializer(serializers.Serializer): ANNOUNCEMENT = AnnouncementSerializer(label=_("Announcement")) -class VaultSettingSerializer(serializers.Serializer): +class BaseVaultSettingSerializer(serializers.Serializer): + + def validate(self, data): + from accounts.signal_handlers import vault_pub_sub + data = super().validate(data) + vault_pub_sub.publish('vault') + return data + + +class VaultSettingSerializer(BaseVaultSettingSerializer, serializers.Serializer): PREFIX_TITLE = _('Vault') VAULT_ENABLED = serializers.BooleanField( @@ -65,7 +74,7 @@ class VaultSettingSerializer(serializers.Serializer): ) -class HashicorpKVSerializer(serializers.Serializer): +class HashicorpKVSerializer(BaseVaultSettingSerializer, serializers.Serializer): PREFIX_TITLE = _('HCP Vault') VAULT_HCP_HOST = serializers.CharField( max_length=256, allow_blank=True, required=False, label=_('Host') @@ -78,7 +87,7 @@ class HashicorpKVSerializer(serializers.Serializer): ) -class AzureKVSerializer(serializers.Serializer): +class AzureKVSerializer(BaseVaultSettingSerializer, serializers.Serializer): PREFIX_TITLE = _('Azure Key Vault') VAULT_AZURE_HOST = serializers.CharField( max_length=256, allow_blank=True, required=False, label=_('Host') From 4068b5c76a09e8fe2588395a59e1096a29a39cee Mon Sep 17 00:00:00 2001 From: feng <1304903146@qq.com> Date: Wed, 20 Nov 2024 16:18:10 +0800 Subject: [PATCH 04/18] perf: Change secret ssh_key_change_strategy modify the default value --- apps/accounts/const/automation.py | 4 ++-- apps/accounts/migrations/0002_auto_20220616_0021.py | 4 ++-- apps/accounts/models/automations/base.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/accounts/const/automation.py b/apps/accounts/const/automation.py index c0419486d..d8388b6bc 100644 --- a/apps/accounts/const/automation.py +++ b/apps/accounts/const/automation.py @@ -49,9 +49,9 @@ class SecretStrategy(models.TextChoices): class SSHKeyStrategy(models.TextChoices): - add = 'add', _('Append SSH KEY') - set = 'set', _('Empty and append SSH KEY') set_jms = 'set_jms', _('Replace (Replace only keys pushed by JumpServer) ') + set = 'set', _('Empty and append SSH KEY') + add = 'add', _('Append SSH KEY') class TriggerChoice(models.TextChoices, TreeChoices): diff --git a/apps/accounts/migrations/0002_auto_20220616_0021.py b/apps/accounts/migrations/0002_auto_20220616_0021.py index 5ac195d63..8fe829dd6 100644 --- a/apps/accounts/migrations/0002_auto_20220616_0021.py +++ b/apps/accounts/migrations/0002_auto_20220616_0021.py @@ -50,7 +50,7 @@ class Migration(migrations.Migration): ('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')), ('secret_strategy', models.CharField(choices=[('specific', 'Specific secret'), ('random', 'Random generate')], default='specific', max_length=16, verbose_name='Secret strategy')), ('password_rules', models.JSONField(default=dict, verbose_name='Password rules')), - ('ssh_key_change_strategy', models.CharField(choices=[('add', 'Append SSH KEY'), ('set', 'Empty and append SSH KEY'), ('set_jms', 'Replace (Replace only keys pushed by JumpServer) ')], default='add', max_length=16, verbose_name='SSH key change strategy')), + ('ssh_key_change_strategy', models.CharField(choices=[('set_jms', 'Replace (Replace only keys pushed by JumpServer) '), ('set', 'Empty and append SSH KEY'), ('add', 'Append SSH KEY')], default='set_jms', max_length=16, verbose_name='SSH key change strategy')), ], options={ 'verbose_name': 'Change secret automation', @@ -76,7 +76,7 @@ class Migration(migrations.Migration): ('secret', common.db.fields.EncryptTextField(blank=True, null=True, verbose_name='Secret')), ('secret_strategy', models.CharField(choices=[('specific', 'Specific secret'), ('random', 'Random generate')], default='specific', max_length=16, verbose_name='Secret strategy')), ('password_rules', models.JSONField(default=dict, verbose_name='Password rules')), - ('ssh_key_change_strategy', models.CharField(choices=[('add', 'Append SSH KEY'), ('set', 'Empty and append SSH KEY'), ('set_jms', 'Replace (Replace only keys pushed by JumpServer) ')], default='add', max_length=16, verbose_name='SSH key change strategy')), + ('ssh_key_change_strategy', models.CharField(choices=[('set_jms', 'Replace (Replace only keys pushed by JumpServer) '), ('set', 'Empty and append SSH KEY'), ('add', 'Append SSH KEY')], default='set_jms', max_length=16, verbose_name='SSH key change strategy')), ('triggers', models.JSONField(default=list, max_length=16, verbose_name='Triggers')), ('username', models.CharField(max_length=128, verbose_name='Username')), ('action', models.CharField(max_length=16, verbose_name='Action')), diff --git a/apps/accounts/models/automations/base.py b/apps/accounts/models/automations/base.py index 1adc84bfe..b001e8cc7 100644 --- a/apps/accounts/models/automations/base.py +++ b/apps/accounts/models/automations/base.py @@ -51,7 +51,7 @@ class AutomationExecution(AssetAutomationExecution): class ChangeSecretMixin(SecretWithRandomMixin): ssh_key_change_strategy = models.CharField( choices=SSHKeyStrategy.choices, max_length=16, - default=SSHKeyStrategy.add, verbose_name=_('SSH key change strategy') + default=SSHKeyStrategy.set_jms, verbose_name=_('SSH key change strategy') ) get_all_assets: callable # get all assets From 88302c8846917dfa3998d8f1f9dd6a4f085fbc2a Mon Sep 17 00:00:00 2001 From: Aaron3S Date: Wed, 20 Nov 2024 16:36:43 +0800 Subject: [PATCH 05/18] feat: add 'face_context' to check_api white list --- apps/common/management/commands/check_api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/common/management/commands/check_api.py b/apps/common/management/commands/check_api.py index f8de10f08..b195b2207 100644 --- a/apps/common/management/commands/check_api.py +++ b/apps/common/management/commands/check_api.py @@ -73,6 +73,7 @@ known_unauth_urls = [ "/api/v1/authentication/password/reset-code/", "/api/v1/authentication/login-confirm-ticket/status/", "/api/v1/authentication/mfa/select/", + "/api/v1/authentication/mfa/face/context/", "/api/v1/authentication/mfa/send-code/", "/api/v1/authentication/sso/login/", "/api/v1/authentication/user-session/", From bdbbebab769ec401fa8bb3286f8af1b51159fc37 Mon Sep 17 00:00:00 2001 From: Aaron3S Date: Wed, 20 Nov 2024 17:50:46 +0800 Subject: [PATCH 06/18] feat: perf face capture page --- apps/authentication/mixins.py | 2 +- .../authentication/face_capture.html | 28 ++++++------------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index c00335ec0..92b49f64e 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -238,7 +238,7 @@ class MFAFaceMixin: if not self.is_context_success(context): msg = context.get('error_message', '') - raise RuntimeError("Face recognition failed,{}".format(msg)) + raise RuntimeError(msg) face_code = context.get('face_code') if not face_code: diff --git a/apps/authentication/templates/authentication/face_capture.html b/apps/authentication/templates/authentication/face_capture.html index 4d0f66096..f04716a59 100644 --- a/apps/authentication/templates/authentication/face_capture.html +++ b/apps/authentication/templates/authentication/face_capture.html @@ -2,28 +2,18 @@ {% load i18n %} {% load static %} - {% block content %} - - {% if 'code' in form.errors %} -

{{ form.code.errors.as_text }}

+
+

{{ form.code.errors.as_text }}

+
{% endif %} + +