diff --git a/apps/accounts/automations/change_secret/custom/ssh/main.yml b/apps/accounts/automations/change_secret/custom/ssh/main.yml index 54707a7d5..966454bfc 100644 --- a/apps/accounts/automations/change_secret/custom/ssh/main.yml +++ b/apps/accounts/automations/change_secret/custom/ssh/main.yml @@ -41,7 +41,7 @@ commands: "{{ params.commands }}" first_conn_delay_time: "{{ first_conn_delay_time | default(0.5) }}" ignore_errors: true - when: ping_info is succeeded + when: ping_info is succeeded and check_conn_after_change register: change_info delegate_to: localhost @@ -59,3 +59,4 @@ old_ssh_version: "{{ jms_asset.old_ssh_version | default(False) }}" gateway_args: "{{ jms_asset.ansible_ssh_common_args | default(None) }}" delegate_to: localhost + when: check_conn_after_change \ No newline at end of file diff --git a/apps/accounts/automations/change_secret/database/mongodb/main.yml b/apps/accounts/automations/change_secret/database/mongodb/main.yml index 8ea631c18..0c4240b37 100644 --- a/apps/accounts/automations/change_secret/database/mongodb/main.yml +++ b/apps/accounts/automations/change_secret/database/mongodb/main.yml @@ -53,3 +53,4 @@ ssl_certfile: "{{ jms_asset.secret_info.client_key | default('') }}" connection_options: - tlsAllowInvalidHostnames: "{{ jms_asset.spec_info.allow_invalid_cert}}" + when: check_conn_after_change \ No newline at end of file diff --git a/apps/accounts/automations/change_secret/database/mysql/main.yml b/apps/accounts/automations/change_secret/database/mysql/main.yml index 15648e76d..2e4123882 100644 --- a/apps/accounts/automations/change_secret/database/mysql/main.yml +++ b/apps/accounts/automations/change_secret/database/mysql/main.yml @@ -54,3 +54,4 @@ client_cert: "{{ ssl_cert if check_ssl and ssl_cert | length > 0 else omit }}" client_key: "{{ ssl_key if check_ssl and ssl_key | length > 0 else omit }}" filter: version + when: check_conn_after_change \ No newline at end of file diff --git a/apps/accounts/automations/change_secret/database/oracle/main.yml b/apps/accounts/automations/change_secret/database/oracle/main.yml index 5a94f3184..e881cdaa6 100644 --- a/apps/accounts/automations/change_secret/database/oracle/main.yml +++ b/apps/accounts/automations/change_secret/database/oracle/main.yml @@ -40,3 +40,4 @@ login_port: "{{ jms_asset.port }}" login_database: "{{ jms_asset.spec_info.db_name }}" mode: "{{ account.mode }}" + when: check_conn_after_change diff --git a/apps/accounts/automations/change_secret/database/postgresql/main.yml b/apps/accounts/automations/change_secret/database/postgresql/main.yml index b73baac4a..c15accca2 100644 --- a/apps/accounts/automations/change_secret/database/postgresql/main.yml +++ b/apps/accounts/automations/change_secret/database/postgresql/main.yml @@ -56,3 +56,4 @@ ssl_cert: "{{ ssl_cert if check_ssl and ssl_cert | length > 0 else omit }}" ssl_key: "{{ ssl_key if check_ssl and ssl_key | length > 0 else omit }}" ssl_mode: "{{ 'verify-full' if check_ca else 'require' if check_ssl else 'prefer' }}" + when: check_conn_after_change diff --git a/apps/accounts/automations/change_secret/database/sqlserver/main.yml b/apps/accounts/automations/change_secret/database/sqlserver/main.yml index eb1746c09..b223824b5 100644 --- a/apps/accounts/automations/change_secret/database/sqlserver/main.yml +++ b/apps/accounts/automations/change_secret/database/sqlserver/main.yml @@ -64,3 +64,4 @@ name: '{{ jms_asset.spec_info.db_name }}' script: | SELECT @@version + when: check_conn_after_change diff --git a/apps/accounts/automations/change_secret/host/aix/main.yml b/apps/accounts/automations/change_secret/host/aix/main.yml index c61029d74..40e110ab7 100644 --- a/apps/accounts/automations/change_secret/host/aix/main.yml +++ b/apps/accounts/automations/change_secret/host/aix/main.yml @@ -100,7 +100,7 @@ become_password: "{{ account.become.ansible_password | default('') }}" become_private_key_path: "{{ account.become.ansible_ssh_private_key_file | default(None) }}" old_ssh_version: "{{ jms_asset.old_ssh_version | default(False) }}" - when: account.secret_type == "password" + when: account.secret_type == "password" and check_conn_after_change delegate_to: localhost - name: "Verify {{ account.username }} SSH KEY (paramiko)" @@ -111,5 +111,5 @@ login_private_key_path: "{{ account.private_key_path }}" gateway_args: "{{ jms_asset.ansible_ssh_common_args | default(None) }}" old_ssh_version: "{{ jms_asset.old_ssh_version | default(False) }}" - when: account.secret_type == "ssh_key" + when: account.secret_type == "ssh_key" and check_conn_after_change delegate_to: localhost diff --git a/apps/accounts/automations/change_secret/host/posix/main.yml b/apps/accounts/automations/change_secret/host/posix/main.yml index e36ecdd33..5403f94ca 100644 --- a/apps/accounts/automations/change_secret/host/posix/main.yml +++ b/apps/accounts/automations/change_secret/host/posix/main.yml @@ -100,7 +100,7 @@ become_password: "{{ account.become.ansible_password | default('') }}" become_private_key_path: "{{ account.become.ansible_ssh_private_key_file | default(None) }}" old_ssh_version: "{{ jms_asset.old_ssh_version | default(False) }}" - when: account.secret_type == "password" + when: account.secret_type == "password" and check_conn_after_change delegate_to: localhost - name: "Verify {{ account.username }} SSH KEY (paramiko)" @@ -111,5 +111,5 @@ login_private_key_path: "{{ account.private_key_path }}" gateway_args: "{{ jms_asset.ansible_ssh_common_args | default(None) }}" old_ssh_version: "{{ jms_asset.old_ssh_version | default(False) }}" - when: account.secret_type == "ssh_key" + when: account.secret_type == "ssh_key" and check_conn_after_change delegate_to: localhost diff --git a/apps/accounts/automations/change_secret/host/windows/main.yml b/apps/accounts/automations/change_secret/host/windows/main.yml index a97166fef..c0efa18ea 100644 --- a/apps/accounts/automations/change_secret/host/windows/main.yml +++ b/apps/accounts/automations/change_secret/host/windows/main.yml @@ -4,10 +4,6 @@ - name: Test privileged account ansible.windows.win_ping: -# - name: Print variables -# debug: -# msg: "Username: {{ account.username }}, Password: {{ account.secret }}" - - name: Change password ansible.windows.win_user: fullname: "{{ account.username}}" @@ -28,4 +24,4 @@ vars: ansible_user: "{{ account.username }}" ansible_password: "{{ account.secret }}" - when: account.secret_type == "password" + when: account.secret_type == "password" and check_conn_after_change diff --git a/apps/accounts/automations/change_secret/host/windows_rdp_verify/main.yml b/apps/accounts/automations/change_secret/host/windows_rdp_verify/main.yml index 31da190ef..1d03f0a37 100644 --- a/apps/accounts/automations/change_secret/host/windows_rdp_verify/main.yml +++ b/apps/accounts/automations/change_secret/host/windows_rdp_verify/main.yml @@ -4,10 +4,6 @@ - name: Test privileged account ansible.windows.win_ping: -# - name: Print variables -# debug: -# msg: "Username: {{ account.username }}, Password: {{ account.secret }}" - - name: Change password ansible.windows.win_user: fullname: "{{ account.username}}" @@ -31,5 +27,5 @@ login_password: "{{ account.secret }}" login_secret_type: "{{ account.secret_type }}" gateway_args: "{{ jms_gateway | default(None) }}" - when: account.secret_type == "password" + when: account.secret_type == "password" and check_conn_after_change delegate_to: localhost diff --git a/apps/accounts/automations/change_secret/manager.py b/apps/accounts/automations/change_secret/manager.py index 38e6eee77..d4ca1c2f3 100644 --- a/apps/accounts/automations/change_secret/manager.py +++ b/apps/accounts/automations/change_secret/manager.py @@ -93,6 +93,8 @@ class ChangeSecretManager(AccountBasePlaybookManager): if host.get('error'): return host + host['check_conn_after_change'] = self.execution.snapshot.get('check_conn_after_change', True) + accounts = self.get_accounts(account) error_msg = _("No pending accounts found") if not accounts: diff --git a/apps/accounts/automations/push_account/custom/ssh/main.yml b/apps/accounts/automations/push_account/custom/ssh/main.yml new file mode 100644 index 000000000..966454bfc --- /dev/null +++ b/apps/accounts/automations/push_account/custom/ssh/main.yml @@ -0,0 +1,62 @@ +- hosts: custom + gather_facts: no + vars: + ansible_connection: local + ansible_become: false + + tasks: + - name: Test privileged account (paramiko) + ssh_ping: + login_host: "{{ jms_asset.address }}" + login_port: "{{ jms_asset.port }}" + login_user: "{{ jms_account.username }}" + login_password: "{{ jms_account.secret }}" + login_secret_type: "{{ jms_account.secret_type }}" + login_private_key_path: "{{ jms_account.private_key_path }}" + become: "{{ jms_custom_become | default(False) }}" + become_method: "{{ jms_custom_become_method | default('su') }}" + become_user: "{{ jms_custom_become_user | default('') }}" + become_password: "{{ jms_custom_become_password | default('') }}" + become_private_key_path: "{{ jms_custom_become_private_key_path | default(None) }}" + old_ssh_version: "{{ jms_asset.old_ssh_version | default(False) }}" + gateway_args: "{{ jms_asset.ansible_ssh_common_args | default(None) }}" + register: ping_info + delegate_to: localhost + + - name: Change asset password (paramiko) + custom_command: + login_user: "{{ jms_account.username }}" + login_password: "{{ jms_account.secret }}" + login_host: "{{ jms_asset.address }}" + login_port: "{{ jms_asset.port }}" + login_secret_type: "{{ jms_account.secret_type }}" + login_private_key_path: "{{ jms_account.private_key_path }}" + become: "{{ jms_custom_become | default(False) }}" + become_method: "{{ jms_custom_become_method | default('su') }}" + become_user: "{{ jms_custom_become_user | default('') }}" + become_password: "{{ jms_custom_become_password | default('') }}" + become_private_key_path: "{{ jms_custom_become_private_key_path | default(None) }}" + name: "{{ account.username }}" + password: "{{ account.secret }}" + commands: "{{ params.commands }}" + first_conn_delay_time: "{{ first_conn_delay_time | default(0.5) }}" + ignore_errors: true + when: ping_info is succeeded and check_conn_after_change + register: change_info + delegate_to: localhost + + - name: Verify password (paramiko) + ssh_ping: + login_user: "{{ account.username }}" + login_password: "{{ account.secret }}" + login_host: "{{ jms_asset.address }}" + login_port: "{{ jms_asset.port }}" + become: "{{ account.become.ansible_become | default(False) }}" + become_method: su + become_user: "{{ account.become.ansible_user | default('') }}" + become_password: "{{ account.become.ansible_password | default('') }}" + become_private_key_path: "{{ account.become.ansible_ssh_private_key_file | default(None) }}" + old_ssh_version: "{{ jms_asset.old_ssh_version | default(False) }}" + gateway_args: "{{ jms_asset.ansible_ssh_common_args | default(None) }}" + delegate_to: localhost + when: check_conn_after_change \ No newline at end of file diff --git a/apps/accounts/automations/push_account/custom/ssh/manifest.yml b/apps/accounts/automations/push_account/custom/ssh/manifest.yml new file mode 100644 index 000000000..2330224ca --- /dev/null +++ b/apps/accounts/automations/push_account/custom/ssh/manifest.yml @@ -0,0 +1,32 @@ +id: push_account_by_ssh +name: "{{ 'SSH account push' | trans }}" +category: + - device + - host +type: + - all +method: push_account +protocol: ssh +priority: 50 +params: + - name: commands + type: list + label: "{{ 'Params commands label' | trans }}" + default: [ '' ] + help_text: "{{ 'Params commands help text' | trans }}" + +i18n: + SSH account push: + zh: '使用 SSH 命令行自定义推送' + ja: 'SSHコマンドラインを使用してプッシュをカスタマイズする' + en: 'Custom push using SSH command line' + + Params commands help text: + zh: '自定义命令中如需包含账号的 账号、密码、SSH 连接的用户密码 字段,
请使用 {username}、{password}、{login_password}格式,执行任务时会进行替换 。
比如针对 Cisco 主机进行改密,一般需要配置五条命令:
1. enable
2. {login_password}
3. configure terminal
4. username {username} privilege 0 password {password}
5. end' + ja: 'カスタム コマンドに SSH 接続用のアカウント番号、パスワード、ユーザー パスワード フィールドを含める必要がある場合は、
{ユーザー名}、{パスワード}、{login_password& を使用してください。 # 125; 形式。タスクの実行時に置き換えられます。
たとえば、Cisco ホストのパスワードを変更するには、通常、次の 5 つのコマンドを設定する必要があります:
1.enable
2.{login_password}
3 .ターミナルの設定
4. ユーザー名 {ユーザー名} 権限 0 パスワード {パスワード}
5. 終了' + en: 'If the custom command needs to include the account number, password, and user password field for SSH connection,
Please use {username}, {password}, {login_password&# 125; format, which will be replaced when executing the task.
For example, to change the password of a Cisco host, you generally need to configure five commands:
1. enable
2. {login_password}
3. configure terminal
4. username {username} privilege 0 password {password}
5. end' + + Params commands label: + zh: '自定义命令' + ja: 'カスタムコマンド' + en: 'Custom command' diff --git a/apps/accounts/automations/push_account/database/mongodb/main.yml b/apps/accounts/automations/push_account/database/mongodb/main.yml index 724c59a94..73c5707d1 100644 --- a/apps/accounts/automations/push_account/database/mongodb/main.yml +++ b/apps/accounts/automations/push_account/database/mongodb/main.yml @@ -53,3 +53,4 @@ ssl_certfile: "{{ jms_asset.secret_info.client_key | default('') }}" connection_options: - tlsAllowInvalidHostnames: "{{ jms_asset.spec_info.allow_invalid_cert}}" + when: check_conn_after_change diff --git a/apps/accounts/automations/push_account/database/mysql/main.yml b/apps/accounts/automations/push_account/database/mysql/main.yml index 15648e76d..3ae597d42 100644 --- a/apps/accounts/automations/push_account/database/mysql/main.yml +++ b/apps/accounts/automations/push_account/database/mysql/main.yml @@ -54,3 +54,4 @@ client_cert: "{{ ssl_cert if check_ssl and ssl_cert | length > 0 else omit }}" client_key: "{{ ssl_key if check_ssl and ssl_key | length > 0 else omit }}" filter: version + when: check_conn_after_change diff --git a/apps/accounts/automations/push_account/database/oracle/main.yml b/apps/accounts/automations/push_account/database/oracle/main.yml index 5a94f3184..e881cdaa6 100644 --- a/apps/accounts/automations/push_account/database/oracle/main.yml +++ b/apps/accounts/automations/push_account/database/oracle/main.yml @@ -40,3 +40,4 @@ login_port: "{{ jms_asset.port }}" login_database: "{{ jms_asset.spec_info.db_name }}" mode: "{{ account.mode }}" + when: check_conn_after_change diff --git a/apps/accounts/automations/push_account/database/postgresql/main.yml b/apps/accounts/automations/push_account/database/postgresql/main.yml index 3678e4fe2..e148c1193 100644 --- a/apps/accounts/automations/push_account/database/postgresql/main.yml +++ b/apps/accounts/automations/push_account/database/postgresql/main.yml @@ -60,5 +60,6 @@ when: - result is succeeded - change_info is succeeded + - check_conn_after_change register: result failed_when: not result.is_available diff --git a/apps/accounts/automations/push_account/database/sqlserver/main.yml b/apps/accounts/automations/push_account/database/sqlserver/main.yml index ee6c4aa5f..38418af22 100644 --- a/apps/accounts/automations/push_account/database/sqlserver/main.yml +++ b/apps/accounts/automations/push_account/database/sqlserver/main.yml @@ -66,3 +66,4 @@ name: '{{ jms_asset.spec_info.db_name }}' script: | SELECT @@version + when: check_conn_after_change diff --git a/apps/accounts/automations/push_account/host/aix/main.yml b/apps/accounts/automations/push_account/host/aix/main.yml index 8e451fb83..b7e822489 100644 --- a/apps/accounts/automations/push_account/host/aix/main.yml +++ b/apps/accounts/automations/push_account/host/aix/main.yml @@ -100,7 +100,7 @@ become_password: "{{ account.become.ansible_password | default('') }}" become_private_key_path: "{{ account.become.ansible_ssh_private_key_file | default(None) }}" old_ssh_version: "{{ jms_asset.old_ssh_version | default(False) }}" - when: account.secret_type == "password" + when: account.secret_type == "password" and check_conn_after_change delegate_to: localhost - name: "Verify {{ account.username }} SSH KEY (paramiko)" @@ -111,6 +111,6 @@ login_private_key_path: "{{ account.private_key_path }}" gateway_args: "{{ jms_asset.ansible_ssh_common_args | default(None) }}" old_ssh_version: "{{ jms_asset.old_ssh_version | default(False) }}" - when: account.secret_type == "ssh_key" + when: account.secret_type == "ssh_key" and check_conn_after_change delegate_to: localhost diff --git a/apps/accounts/automations/push_account/host/posix/main.yml b/apps/accounts/automations/push_account/host/posix/main.yml index 537256a3d..577ccf4de 100644 --- a/apps/accounts/automations/push_account/host/posix/main.yml +++ b/apps/accounts/automations/push_account/host/posix/main.yml @@ -100,7 +100,7 @@ become_password: "{{ account.become.ansible_password | default('') }}" become_private_key_path: "{{ account.become.ansible_ssh_private_key_file | default(None) }}" old_ssh_version: "{{ jms_asset.old_ssh_version | default(False) }}" - when: account.secret_type == "password" + when: account.secret_type == "password" and check_conn_after_change delegate_to: localhost - name: "Verify {{ account.username }} SSH KEY (paramiko)" @@ -111,6 +111,6 @@ login_private_key_path: "{{ account.private_key_path }}" gateway_args: "{{ jms_asset.ansible_ssh_common_args | default(None) }}" old_ssh_version: "{{ jms_asset.old_ssh_version | default(False) }}" - when: account.secret_type == "ssh_key" + when: account.secret_type == "ssh_key" and check_conn_after_change delegate_to: localhost diff --git a/apps/accounts/automations/push_account/host/windows/main.yml b/apps/accounts/automations/push_account/host/windows/main.yml index 17f68b660..0cb67a3a7 100644 --- a/apps/accounts/automations/push_account/host/windows/main.yml +++ b/apps/accounts/automations/push_account/host/windows/main.yml @@ -4,10 +4,6 @@ - name: Test privileged account ansible.windows.win_ping: -# - name: Print variables -# debug: -# msg: "Username: {{ account.username }}, Password: {{ account.secret }}" - - name: Push user password ansible.windows.win_user: fullname: "{{ account.username}}" @@ -28,4 +24,4 @@ vars: ansible_user: "{{ account.username }}" ansible_password: "{{ account.secret }}" - when: account.secret_type == "password" + when: account.secret_type == "password" and check_conn_after_change diff --git a/apps/accounts/automations/push_account/host/windows_rdp_verify/main.yml b/apps/accounts/automations/push_account/host/windows_rdp_verify/main.yml index e15b5889e..75e2ceceb 100644 --- a/apps/accounts/automations/push_account/host/windows_rdp_verify/main.yml +++ b/apps/accounts/automations/push_account/host/windows_rdp_verify/main.yml @@ -4,10 +4,6 @@ - name: Test privileged account ansible.windows.win_ping: -# - name: Print variables -# debug: -# msg: "Username: {{ account.username }}, Password: {{ account.secret }}" - - name: Push user password ansible.windows.win_user: fullname: "{{ account.username}}" @@ -31,5 +27,5 @@ login_password: "{{ account.secret }}" login_secret_type: "{{ account.secret_type }}" gateway_args: "{{ jms_gateway | default(None) }}" - when: account.secret_type == "password" + when: account.secret_type == "password" and check_conn_after_change delegate_to: localhost diff --git a/apps/accounts/migrations/0007_alter_accountrisk_risk.py b/apps/accounts/migrations/0007_alter_accountrisk_risk.py index d806f7f3b..e5bc75ae4 100644 --- a/apps/accounts/migrations/0007_alter_accountrisk_risk.py +++ b/apps/accounts/migrations/0007_alter_accountrisk_risk.py @@ -15,17 +15,17 @@ class Migration(migrations.Migration): name="risk", field=models.CharField( choices=[ - ("zombie", "Long time no login"), - ("ghost", "Not managed"), - ("long_time_password", "Long time no change"), - ("weak_password", "Weak password"), - ("group_changed", "Group change"), - ("sudo_changed", "Sudo changed"), - ("account_deleted", "Account delete"), - ("password_expired", "Password expired"), - ("no_admin_account", "No admin account"), - ("password_error", "Password error"), - ("others", "Others"), + ('zombie', 'Long time no login'), + ('ghost', 'Not managed'), + ('long_time_password', 'Long time no change'), + ('weak_password', 'Weak password'), + ('password_error', 'Password error'), + ('password_expired', 'Password expired'), + ('group_changed', 'Group change'), + ('sudo_changed', 'Sudo changed'), + ('account_deleted', 'Account delete'), + ('no_admin_account', 'No admin account'), + ('others', 'Others') ], max_length=128, verbose_name="Risk", diff --git a/apps/accounts/migrations/0008_automation_check_conn_after_change.py b/apps/accounts/migrations/0008_automation_check_conn_after_change.py new file mode 100644 index 000000000..91baa4075 --- /dev/null +++ b/apps/accounts/migrations/0008_automation_check_conn_after_change.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.13 on 2024-10-21 09:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0007_alter_accountrisk_risk'), + ] + + operations = [ + migrations.AddField( + model_name='changesecretautomation', + name='check_conn_after_change', + field=models.BooleanField(default=True, verbose_name='Check connection after change'), + ), + migrations.AddField( + model_name='pushaccountautomation', + name='check_conn_after_change', + field=models.BooleanField(default=True, verbose_name='Check connection after change'), + ), + ] diff --git a/apps/accounts/models/automations/base.py b/apps/accounts/models/automations/base.py index b001e8cc7..837830759 100644 --- a/apps/accounts/models/automations/base.py +++ b/apps/accounts/models/automations/base.py @@ -50,8 +50,14 @@ class AutomationExecution(AssetAutomationExecution): class ChangeSecretMixin(SecretWithRandomMixin): ssh_key_change_strategy = models.CharField( - choices=SSHKeyStrategy.choices, max_length=16, - default=SSHKeyStrategy.set_jms, verbose_name=_('SSH key change strategy') + choices=SSHKeyStrategy.choices, + max_length=16, + default=SSHKeyStrategy.set_jms, + verbose_name=_('SSH key change strategy') + ) + check_conn_after_change = models.BooleanField( + default=True, + verbose_name=_('Check connection after change') ) get_all_assets: callable # get all assets @@ -81,5 +87,6 @@ class ChangeSecretMixin(SecretWithRandomMixin): 'password_rules': self.password_rules, 'secret_strategy': self.secret_strategy, 'ssh_key_change_strategy': self.ssh_key_change_strategy, + 'check_conn_after_change': self.check_conn_after_change, }) return attr_json diff --git a/apps/accounts/serializers/automations/change_secret.py b/apps/accounts/serializers/automations/change_secret.py index eebdcfcc4..c4d9830fd 100644 --- a/apps/accounts/serializers/automations/change_secret.py +++ b/apps/accounts/serializers/automations/change_secret.py @@ -52,8 +52,7 @@ class ChangeSecretAutomationSerializer(AuthValidateMixin, BaseAutomationSerializ read_only_fields = BaseAutomationSerializer.Meta.read_only_fields fields = BaseAutomationSerializer.Meta.fields + read_only_fields + [ 'secret_type', 'secret_strategy', 'secret', 'password_rules', - 'ssh_key_change_strategy', 'passphrase', 'params', - 'recipients', + 'ssh_key_change_strategy', 'passphrase', 'recipients', 'params', 'check_conn_after_change' ] extra_kwargs = {**BaseAutomationSerializer.Meta.extra_kwargs, **{ 'accounts': {'required': True, 'help_text': _('Please enter your account username')}, diff --git a/apps/authentication/api/connection_token.py b/apps/authentication/api/connection_token.py index 37fb3e968..ef2c7ad2b 100644 --- a/apps/authentication/api/connection_token.py +++ b/apps/authentication/api/connection_token.py @@ -29,14 +29,14 @@ from terminal.models import EndpointRule, Endpoint from users.const import FileNameConflictResolution from users.const import RDPSmartSize, RDPColorQuality from users.models import Preference -from ..models import ConnectionToken, date_expired_default +from ..models import ConnectionToken, AdminConnectionToken, date_expired_default from ..serializers import ( ConnectionTokenSerializer, ConnectionTokenSecretSerializer, SuperConnectionTokenSerializer, ConnectTokenAppletOptionSerializer, ConnectionTokenReusableSerializer, ConnectTokenVirtualAppOptionSerializer ) -__all__ = ['ConnectionTokenViewSet', 'SuperConnectionTokenViewSet'] +__all__ = ['ConnectionTokenViewSet', 'SuperConnectionTokenViewSet', 'AdminConnectionTokenViewSet'] logger = get_logger(__name__) @@ -558,3 +558,14 @@ class SuperConnectionTokenViewSet(ConnectionTokenViewSet): else: logger.error('Release applet account error: {}'.format(lock_key)) return Response({'error': 'not found or expired'}, status=400) + + +class AdminConnectionTokenViewSet(SuperConnectionTokenViewSet): + + def check_permissions(self, request): + user = request.user + if not user.is_superuser: + self.permission_denied(request) + + def get_queryset(self): + return AdminConnectionToken.objects.all() diff --git a/apps/authentication/const.py b/apps/authentication/const.py index 1e06a4d35..341a14e24 100644 --- a/apps/authentication/const.py +++ b/apps/authentication/const.py @@ -37,3 +37,9 @@ class MFAType(TextChoices): SMS = MFASms.name, MFASms.display_name Radius = MFARadius.name, MFARadius.display_name Custom = MFACustom.name, MFACustom.display_name + + +class ConnectionTokenType(TextChoices): + ADMIN = 'admin', 'Admin' + SUPER = 'super', 'Super' + USER = 'user', 'User' diff --git a/apps/authentication/migrations/0004_connectiontoken_type.py b/apps/authentication/migrations/0004_connectiontoken_type.py new file mode 100644 index 000000000..02f22686b --- /dev/null +++ b/apps/authentication/migrations/0004_connectiontoken_type.py @@ -0,0 +1,30 @@ +# Generated by Django 4.1.13 on 2024-11-11 11:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authentication', '0003_sshkey'), + ] + + operations = [ + migrations.AddField( + model_name='connectiontoken', + name='type', + field=models.CharField(choices=[('admin', 'Admin'), ('super', 'Super'), ('user', 'User')], default='user', max_length=16, verbose_name='Type'), + ), + migrations.CreateModel( + name='AdminConnectionToken', + fields=[ + ], + options={ + 'verbose_name': 'Admin connection token', + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('authentication.connectiontoken',), + ), + ] diff --git a/apps/authentication/models/connection_token.py b/apps/authentication/models/connection_token.py index fcf1d43c8..94c56b030 100644 --- a/apps/authentication/models/connection_token.py +++ b/apps/authentication/models/connection_token.py @@ -12,6 +12,7 @@ from rest_framework.exceptions import PermissionDenied from accounts.models import VirtualAccount from assets.const import Protocol from assets.const.host import GATEWAY_NAME +from authentication.const import ConnectionTokenType from common.db.fields import EncryptTextField from common.exceptions import JMSException from common.utils import lazyproperty, pretty_string, bulk_get @@ -26,6 +27,8 @@ def date_expired_default(): class ConnectionToken(JMSOrgBaseModel): + _type = ConnectionTokenType.USER + value = models.CharField(max_length=64, default='', verbose_name=_("Value")) user = models.ForeignKey( 'users.User', on_delete=models.SET_NULL, null=True, blank=True, @@ -52,6 +55,11 @@ class ConnectionToken(JMSOrgBaseModel): ) is_active = models.BooleanField(default=True, verbose_name=_("Active")) + type = models.CharField( + max_length=16, choices=ConnectionTokenType.choices, + default=ConnectionTokenType.USER, verbose_name=_('Type') + ) + class Meta: ordering = ('-date_expired',) permissions = [ @@ -60,6 +68,10 @@ class ConnectionToken(JMSOrgBaseModel): ] verbose_name = _('Connection token') + def save(self, *args, **kwargs): + self.type = self._meta.model._type + return super().save(*args, **kwargs) + @property def is_expired(self): return self.date_expired < timezone.now() @@ -268,9 +280,28 @@ class ConnectionToken(JMSOrgBaseModel): class SuperConnectionToken(ConnectionToken): + _type = ConnectionTokenType.SUPER + class Meta: proxy = True permissions = [ ('view_superconnectiontokensecret', _('Can view super connection token secret')) ] verbose_name = _("Super connection token") + + +class AdminConnectionTokenManager(models.Manager): + def get_queryset(self): + queryset = super().get_queryset() + queryset = queryset.filter(type=ConnectionTokenType.ADMIN) + return queryset + + +class AdminConnectionToken(ConnectionToken): + _type = ConnectionTokenType.ADMIN + + objects = AdminConnectionTokenManager() + + class Meta: + proxy = True + verbose_name = _("Admin connection token") diff --git a/apps/authentication/urls/api_urls.py b/apps/authentication/urls/api_urls.py index 8f74f2907..c115f9e2c 100644 --- a/apps/authentication/urls/api_urls.py +++ b/apps/authentication/urls/api_urls.py @@ -13,6 +13,7 @@ router.register('sso', api.SSOViewSet, 'sso') router.register('temp-tokens', api.TempTokenViewSet, 'temp-token') router.register('connection-token', api.ConnectionTokenViewSet, 'connection-token') router.register('super-connection-token', api.SuperConnectionTokenViewSet, 'super-connection-token') +router.register('admin-connection-token', api.AdminConnectionTokenViewSet, 'admin-connection-token') router.register('confirm', api.UserConfirmationViewSet, 'confirm') router.register('ssh-key', api.SSHkeyViewSet, 'ssh-key')