mirror of https://github.com/jumpserver/jumpserver
				
				
				
			perf: rename ad to ds
							parent
							
								
									3f452daee8
								
							
						
					
					
						commit
						acaa4cf2d5
					
				|  | @ -139,17 +139,25 @@ class Account(AbsConnectivity, LabeledMixin, BaseAccount, JSONFilterMixin): | |||
|         return self.id | ||||
| 
 | ||||
|     @lazyproperty | ||||
|     def ad_domain(self): | ||||
|     def ds_id(self): | ||||
|         if self.username.startswith('@'): | ||||
|             return None | ||||
|         if self.platform.category == 'ad': | ||||
|             return self.asset.ad.domain_name | ||||
|         if self.platform.category == 'ds': | ||||
|             return self.asset.directoryservice.id | ||||
|         return None | ||||
| 
 | ||||
|     @lazyproperty | ||||
|     def ds_domain(self): | ||||
|         if self.username.startswith('@'): | ||||
|             return None | ||||
|         if self.ds_id: | ||||
|             return self.asset.ds.domain_name | ||||
|         return None | ||||
| 
 | ||||
|     @lazyproperty | ||||
|     def full_username(self): | ||||
|         if self.ad_domain: | ||||
|             return '{}@{}'.format(self.username, self.ad_domain) | ||||
|         if self.ds_domain: | ||||
|             return '{}@{}'.format(self.username, self.ds_domain) | ||||
|         return self.username | ||||
| 
 | ||||
|     @lazyproperty | ||||
|  |  | |||
|  | @ -241,7 +241,7 @@ class AccountSerializer(AccountCreateUpdateSerializerMixin, BaseAccountSerialize | |||
|             'date_change_secret', 'change_secret_status' | ||||
|         ] | ||||
|         fields = BaseAccountSerializer.Meta.fields + [ | ||||
|             'su_from', 'asset', 'version', "ad_domain", | ||||
|             'su_from', 'asset', 'version', 'ds_domain', | ||||
|             'source', 'source_id', 'secret_reset', | ||||
|         ] + AccountCreateUpdateSerializerMixin.Meta.fields + automation_fields | ||||
|         read_only_fields = BaseAccountSerializer.Meta.read_only_fields + automation_fields | ||||
|  |  | |||
|  | @ -87,7 +87,7 @@ class BaseAccountSerializer( | |||
|             "username": { | ||||
|                 "help_text": _( | ||||
|                     "* If no username is required for authentication, enter null.  " | ||||
|                     "For AD accounts, use the format username@domain." | ||||
|                     "For DS accounts, use the format username@domain." | ||||
|                 ) | ||||
|             }, | ||||
|         } | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ class VirtualAccountSerializer(serializers.ModelSerializer): | |||
|             'username': {'label': _('Username')}, | ||||
|             'secret_from_login': { | ||||
|                 'help_text': _( | ||||
|                     'Current only support login from AD/LDAP. Secret priority: ' | ||||
|                     'Current only support login from DS/LDAP. Secret priority: ' | ||||
|                     'Same account in asset secret > Login secret > Manual input. <br/ >' | ||||
|                     'For security, please set config CACHE_LOGIN_PASSWORD_ENABLED to true' | ||||
|                 ) | ||||
|  |  | |||
|  | @ -3,8 +3,8 @@ from .cloud import * | |||
| from .custom import * | ||||
| from .database import * | ||||
| from .device import * | ||||
| from .ds import * | ||||
| from .gpt import * | ||||
| from .host import * | ||||
| from .permission import * | ||||
| from .web import * | ||||
| from .ad import * | ||||
|  |  | |||
|  | @ -1,16 +0,0 @@ | |||
| from assets.models import AD, Asset | ||||
| from assets.serializers import ADSerializer | ||||
| 
 | ||||
| from .asset import AssetViewSet | ||||
| 
 | ||||
| __all__ = ['ADViewSet'] | ||||
| 
 | ||||
| 
 | ||||
| class ADViewSet(AssetViewSet): | ||||
|     model = AD | ||||
|     perm_model = Asset | ||||
| 
 | ||||
|     def get_serializer_classes(self): | ||||
|         serializer_classes = super().get_serializer_classes() | ||||
|         serializer_classes['default'] = ADSerializer | ||||
|         return serializer_classes | ||||
|  | @ -0,0 +1,16 @@ | |||
| from assets.models import DirectoryService, Asset | ||||
| from assets.serializers import DSSerializer | ||||
| 
 | ||||
| from .asset import AssetViewSet | ||||
| 
 | ||||
| __all__ = ['DSViewSet'] | ||||
| 
 | ||||
| 
 | ||||
| class DSViewSet(AssetViewSet): | ||||
|     model = DirectoryService | ||||
|     perm_model = Asset | ||||
| 
 | ||||
|     def get_serializer_classes(self): | ||||
|         serializer_classes = super().get_serializer_classes() | ||||
|         serializer_classes['default'] = DSSerializer | ||||
|         return serializer_classes | ||||
|  | @ -112,8 +112,7 @@ class BaseType(TextChoices): | |||
| 
 | ||||
|     @classmethod | ||||
|     def get_choices(cls): | ||||
|         if not settings.XPACK_LICENSE_IS_VALID: | ||||
|         choices = cls.choices | ||||
|         if not settings.XPACK_LICENSE_IS_VALID and hasattr(cls, 'get_community_types'): | ||||
|             choices = [(tp.value, tp.label) for tp in cls.get_community_types()] | ||||
|         else: | ||||
|             choices = cls.choices | ||||
|         return choices | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ class Category(ChoicesMixin, models.TextChoices): | |||
|     DATABASE = 'database', _("Database") | ||||
|     CLOUD = 'cloud', _("Cloud service") | ||||
|     WEB = 'web', _("Web") | ||||
|     AD = 'ad', _("Active Directory") | ||||
|     DS = 'ds', _("Directory service") | ||||
|     CUSTOM = 'custom', _("Custom type") | ||||
| 
 | ||||
|     @classmethod | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ class DeviceTypes(BaseType): | |||
|             '*': { | ||||
|                 'charset_enabled': False, | ||||
|                 'domain_enabled': True, | ||||
|                 'ad_enabled': False, | ||||
|                 'ds_enabled': False, | ||||
|                 'su_enabled': True, | ||||
|                 'su_methods': ['enable', 'super', 'super_level'] | ||||
|             } | ||||
|  |  | |||
|  | @ -3,11 +3,13 @@ from django.utils.translation import gettext_lazy as _ | |||
| from .base import BaseType | ||||
| 
 | ||||
| 
 | ||||
| class ADTypes(BaseType): | ||||
|     AD = 'ad', _('Active Directory') | ||||
| class DirectoryTypes(BaseType): | ||||
|     GENERAL = 'general', _('General') | ||||
|     # LDAP = 'ldap', _('LDAP') | ||||
|     # AD = 'ad', _('Active Directory') | ||||
|     WINDOWS_AD = 'windows_ad', _('Windows Active Directory') | ||||
|     LDAP = 'ldap', _('LDAP') | ||||
|     AZURE_AD = 'azure_ad', _('Azure Active Directory') | ||||
| 
 | ||||
|     # AZURE_AD = 'azure_ad', _('Azure Active Directory') | ||||
| 
 | ||||
|     @classmethod | ||||
|     def _get_base_constrains(cls) -> dict: | ||||
|  | @ -15,7 +17,7 @@ class ADTypes(BaseType): | |||
|             '*': { | ||||
|                 'charset_enabled': False, | ||||
|                 'domain_enabled': True, | ||||
|                 'ad_enabled': False, | ||||
|                 'ds_enabled': False, | ||||
|                 'su_enabled': True, | ||||
|             } | ||||
|         } | ||||
|  | @ -24,6 +26,9 @@ class ADTypes(BaseType): | |||
|     def _get_automation_constrains(cls) -> dict: | ||||
|         constrains = { | ||||
|             '*': { | ||||
|                 'ansible_enabled': False, | ||||
|             }, | ||||
|             cls.WINDOWS_AD: { | ||||
|                 'ansible_enabled': True, | ||||
|                 'ping_enabled': True, | ||||
|                 'gather_facts_enabled': False, | ||||
|  | @ -38,36 +43,24 @@ class ADTypes(BaseType): | |||
|     @classmethod | ||||
|     def _get_protocol_constrains(cls) -> dict: | ||||
|         return { | ||||
|             cls.GENERAL: { | ||||
|                 'choices': ['ssh'] | ||||
|             }, | ||||
|             cls.WINDOWS_AD: { | ||||
|                 'choices': ['rdp', 'ssh', 'vnc', 'winrm'] | ||||
|             }, | ||||
|             cls.LDAP: { | ||||
|                 'choices': ['ssh', 'ldap'] | ||||
|             }, | ||||
|             cls.AZURE_AD: { | ||||
|                 'choices': ['ldap'] | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     @classmethod | ||||
|     def internal_platforms(cls): | ||||
|         return { | ||||
|             cls.AD: [ | ||||
|                 {'name': 'Active Directory'} | ||||
|             ], | ||||
|             cls.WINDOWS_AD: [ | ||||
|                 {'name': 'Windows Active Directory'} | ||||
|             ], | ||||
|             cls.LDAP: [ | ||||
|                 {'name': 'LDAP'} | ||||
|             ], | ||||
|             cls.AZURE_AD: [ | ||||
|                 {'name': 'Azure Active Directory'} | ||||
|             ], | ||||
|         } | ||||
| 
 | ||||
|     @classmethod | ||||
|     def get_community_types(cls): | ||||
|         return [ | ||||
|             cls.LDAP, | ||||
|             cls.GENERAL, | ||||
|         ] | ||||
|  | @ -20,7 +20,7 @@ class HostTypes(BaseType): | |||
|                 'charset': 'utf-8',  # default | ||||
|                 'domain_enabled': True, | ||||
|                 'su_enabled': True, | ||||
|                 'ad_enabled': True, | ||||
|                 'ds_enabled': True, | ||||
|                 'su_methods': ['sudo', 'su', 'only_sudo', 'only_su'], | ||||
|             }, | ||||
|             cls.WINDOWS: { | ||||
|  |  | |||
|  | @ -13,10 +13,10 @@ from .cloud import CloudTypes | |||
| from .custom import CustomTypes | ||||
| from .database import DatabaseTypes | ||||
| from .device import DeviceTypes | ||||
| from .ds import DirectoryTypes | ||||
| from .gpt import GPTTypes | ||||
| from .host import HostTypes | ||||
| from .web import WebTypes | ||||
| from .ad import ADTypes | ||||
| 
 | ||||
| 
 | ||||
| class AllTypes(ChoicesMixin): | ||||
|  | @ -24,7 +24,7 @@ class AllTypes(ChoicesMixin): | |||
|     includes = [ | ||||
|         HostTypes, DeviceTypes, DatabaseTypes, | ||||
|         CloudTypes, WebTypes, CustomTypes, | ||||
|         ADTypes, GPTTypes | ||||
|         DirectoryTypes, GPTTypes | ||||
|     ] | ||||
|     _category_constrains = {} | ||||
|     _automation_methods = None | ||||
|  | @ -175,7 +175,7 @@ class AllTypes(ChoicesMixin): | |||
|             (Category.DATABASE, DatabaseTypes), | ||||
|             (Category.WEB, WebTypes), | ||||
|             (Category.CLOUD, CloudTypes), | ||||
|             (Category.AD, ADTypes), | ||||
|             (Category.DS, DirectoryTypes), | ||||
|             (Category.CUSTOM, CustomTypes) | ||||
|         ] | ||||
|         return types | ||||
|  |  | |||
|  | @ -0,0 +1,64 @@ | |||
| # 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"), | ||||
|         ), | ||||
|     ] | ||||
|  | @ -1,166 +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 | ||||
| 
 | ||||
| 
 | ||||
| def add_ad_host_type(apps, schema_editor): | ||||
|     data = """ | ||||
|      [ | ||||
|        { | ||||
|           "created_by": "system", | ||||
|           "updated_by": "system", | ||||
|           "comment": "", | ||||
|           "name": "Windows AD", | ||||
|           "category": "ad", | ||||
|           "type": "windows_ad", | ||||
|           "meta": {}, | ||||
|           "internal": true, | ||||
|           "domain_enabled": true, | ||||
|           "su_enabled": false, | ||||
|           "su_method": null, | ||||
|           "custom_fields": [], | ||||
|           "automation": { | ||||
|               "ansible_enabled": true, | ||||
|               "ansible_config": { | ||||
|                   "ansible_shell_type": "cmd", | ||||
|                   "ansible_connection": "ssh" | ||||
|               }, | ||||
|               "ping_enabled": true, | ||||
|               "ping_method": "ping_by_rdp", | ||||
|               "ping_params": {}, | ||||
|               "gather_facts_enabled": true, | ||||
|               "gather_facts_method": "gather_facts_windows", | ||||
|               "gather_facts_params": {}, | ||||
|               "change_secret_enabled": true, | ||||
|               "change_secret_method": "change_secret_ad_windows", | ||||
|               "change_secret_params": {}, | ||||
|               "push_account_enabled": true, | ||||
|               "push_account_method": "push_account_ad_windows", | ||||
|               "push_account_params": {}, | ||||
|               "verify_account_enabled": true, | ||||
|               "verify_account_method": "verify_account_by_rdp", | ||||
|               "verify_account_params": {}, | ||||
|               "gather_accounts_enabled": true, | ||||
|               "gather_accounts_method": "gather_accounts_ad_windows", | ||||
|               "gather_accounts_params": {}, | ||||
|               "remove_account_enabled": true, | ||||
|               "remove_account_method": "remove_account_ad_windows", | ||||
|               "remove_account_params": {} | ||||
|           }, | ||||
|           "protocols": [ | ||||
|               { | ||||
|                   "name": "rdp", | ||||
|                   "port": 3389, | ||||
|                   "primary": true, | ||||
|                   "required": false, | ||||
|                   "default": false, | ||||
|                   "public": true, | ||||
|                   "setting": { | ||||
|                       "console": false, | ||||
|                       "security": "any" | ||||
|                   } | ||||
|               }, | ||||
|               { | ||||
|                   "name": "ssh", | ||||
|                   "port": 22, | ||||
|                   "primary": false, | ||||
|                   "required": false, | ||||
|                   "default": false, | ||||
|                   "public": true, | ||||
|                   "setting": { | ||||
|                       "sftp_enabled": true, | ||||
|                       "sftp_home": "/tmp" | ||||
|                   } | ||||
|               }, | ||||
|               { | ||||
|                   "name": "vnc", | ||||
|                   "port": 5900, | ||||
|                   "primary": false, | ||||
|                   "required": false, | ||||
|                   "default": false, | ||||
|                   "public": true, | ||||
|                   "setting": {} | ||||
|               }, | ||||
|               { | ||||
|                   "name": "winrm", | ||||
|                   "port": 5985, | ||||
|                   "primary": false, | ||||
|                   "required": false, | ||||
|                   "default": false, | ||||
|                   "public": false, | ||||
|                   "setting": { | ||||
|                       "use_ssl": false | ||||
|                   } | ||||
|               } | ||||
|           ] | ||||
|       } | ||||
|     ] | ||||
|     """ | ||||
|     platform_model = apps.get_model('assets', 'Platform') | ||||
|     automation_cls = apps.get_model('assets', 'PlatformAutomation') | ||||
|     platform_datas = json.loads(data) | ||||
| 
 | ||||
|     for platform_data in platform_datas: | ||||
|         AllTypes.create_or_update_by_platform_data(platform_data, platform_cls=platform_model, | ||||
|                                                    automation_cls=automation_cls) | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
|     dependencies = [ | ||||
|         ("assets", "0015_automationexecution_type"), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.RunPython(add_ad_host_type), | ||||
|         migrations.CreateModel( | ||||
|             name="AD", | ||||
|             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="ad", | ||||
|             field=models.ForeignKey( | ||||
|                 blank=True, | ||||
|                 null=True, | ||||
|                 on_delete=django.db.models.deletion.SET_NULL, | ||||
|                 related_name="ad_platforms", | ||||
|                 to="assets.ad", | ||||
|                 verbose_name="Active Directory", | ||||
|             ), | ||||
|         ), | ||||
|         migrations.AddField( | ||||
|             model_name="platform", | ||||
|             name="ad_enabled", | ||||
|             field=models.BooleanField(default=False, verbose_name="AD enabled"), | ||||
|         ), | ||||
|     ] | ||||
|  | @ -0,0 +1,59 @@ | |||
| # Generated by Django 4.1.13 on 2025-04-03 09:51 | ||||
| 
 | ||||
| import django.db.models.deletion | ||||
| from django.db import migrations, models | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
|     dependencies = [ | ||||
|         ("assets", "0015_automationexecution_type"), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.CreateModel( | ||||
|             name="DirectoryService", | ||||
|             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": "Directory service", | ||||
|             }, | ||||
|             bases=("assets.asset",), | ||||
|         ), | ||||
|         migrations.AddField( | ||||
|             model_name="platform", | ||||
|             name="ds_enabled", | ||||
|             field=models.BooleanField(default=False, verbose_name="DS enabled"), | ||||
|         ), | ||||
|         migrations.AddField( | ||||
|             model_name="platform", | ||||
|             name="ds", | ||||
|             field=models.ForeignKey( | ||||
|                 blank=True, | ||||
|                 null=True, | ||||
|                 on_delete=django.db.models.deletion.SET_NULL, | ||||
|                 related_name="ds_platforms", | ||||
|                 to="assets.directoryservice", | ||||
|                 verbose_name="Active Directory", | ||||
|             ), | ||||
|         ), | ||||
|     ] | ||||
|  | @ -0,0 +1,168 @@ | |||
| # Generated by Django 4.1.13 on 2025-04-07 03:24 | ||||
| 
 | ||||
| import json | ||||
| 
 | ||||
| from django.db import migrations | ||||
| 
 | ||||
| from assets.const import AllTypes | ||||
| 
 | ||||
| 
 | ||||
| def add_ds_platforms(apps, schema_editor): | ||||
|     data = """ | ||||
| [ | ||||
|     { | ||||
|         "created_by": "system", | ||||
|         "updated_by": "system", | ||||
|         "comment": "", | ||||
|         "name": "Windows active directory", | ||||
|         "category": "ds", | ||||
|         "type": "windows_ad", | ||||
|         "meta": {}, | ||||
|         "internal": true, | ||||
|         "domain_enabled": true, | ||||
|         "su_enabled": false, | ||||
|         "su_method": null, | ||||
|         "custom_fields": [], | ||||
|         "automation": { | ||||
|             "ansible_enabled": true, | ||||
|             "ansible_config": { | ||||
|                 "ansible_shell_type": "cmd", | ||||
|                 "ansible_connection": "ssh" | ||||
|             }, | ||||
|             "ping_enabled": true, | ||||
|             "ping_method": "ping_by_rdp", | ||||
|             "ping_params": {}, | ||||
|             "gather_facts_enabled": true, | ||||
|             "gather_facts_method": "gather_facts_windows", | ||||
|             "gather_facts_params": {}, | ||||
|             "change_secret_enabled": true, | ||||
|             "change_secret_method": "change_secret_ad_windows", | ||||
|             "change_secret_params": { | ||||
|             }, | ||||
|             "push_account_enabled": true, | ||||
|             "push_account_method": "push_account_ad_windows", | ||||
|             "push_account_params": {}, | ||||
|             "verify_account_enabled": true, | ||||
|             "verify_account_method": "verify_account_by_rdp", | ||||
|             "verify_account_params": { | ||||
| 
 | ||||
|             }, | ||||
|             "gather_accounts_enabled": true, | ||||
|             "gather_accounts_method": "gather_accounts_ad_windows", | ||||
|             "gather_accounts_params": { | ||||
| 
 | ||||
|             }, | ||||
|             "remove_account_enabled": true, | ||||
|             "remove_account_method": "remove_account_ad_windows", | ||||
|             "remove_account_params": { | ||||
| 
 | ||||
|             } | ||||
|         }, | ||||
|         "protocols": [ | ||||
|             { | ||||
|                 "name": "rdp", | ||||
|                 "port": 3389, | ||||
|                 "primary": true, | ||||
|                 "required": false, | ||||
|                 "default": false, | ||||
|                 "public": true, | ||||
|                 "setting": { | ||||
|                     "console": false, | ||||
|                     "security": "any" | ||||
|                 } | ||||
|             }, | ||||
|             { | ||||
|                 "name": "ssh", | ||||
|                 "port": 22, | ||||
|                 "primary": false, | ||||
|                 "required": false, | ||||
|                 "default": false, | ||||
|                 "public": true, | ||||
|                 "setting": { | ||||
|                     "sftp_enabled": true, | ||||
|                     "sftp_home": "/tmp" | ||||
|                 } | ||||
|             }, | ||||
|             { | ||||
|                 "name": "vnc", | ||||
|                 "port": 5900, | ||||
|                 "primary": false, | ||||
|                 "required": false, | ||||
|                 "default": false, | ||||
|                 "public": true, | ||||
|                 "setting": { | ||||
| 
 | ||||
|                 } | ||||
|             }, | ||||
|             { | ||||
|                 "name": "winrm", | ||||
|                 "port": 5985, | ||||
|                 "primary": false, | ||||
|                 "required": false, | ||||
|                 "default": false, | ||||
|                 "public": false, | ||||
|                 "setting": { | ||||
|                     "use_ssl": false | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "created_by": "system", | ||||
|         "updated_by": "system", | ||||
|         "comment": "", | ||||
|         "name": "General", | ||||
|         "category": "ds", | ||||
|         "type": "general", | ||||
|         "meta": { | ||||
| 
 | ||||
|         }, | ||||
|         "internal": true, | ||||
|         "domain_enabled": false, | ||||
|         "su_enabled": false, | ||||
|         "su_method": null, | ||||
|         "custom_fields": [ | ||||
| 
 | ||||
|         ], | ||||
|         "automation": { | ||||
|             "ansible_enabled": false, | ||||
|             "ansible_config": { | ||||
| 
 | ||||
|             } | ||||
|         }, | ||||
|         "protocols": [ | ||||
|             { | ||||
|                 "name": "ssh", | ||||
|                 "port": 22, | ||||
|                 "primary": true, | ||||
|                 "required": false, | ||||
|                 "default": false, | ||||
|                 "public": true, | ||||
|                 "setting": { | ||||
|                     "sftp_enabled": true, | ||||
|                     "sftp_home": "/tmp" | ||||
|                 } | ||||
|             } | ||||
|         ] | ||||
|     } | ||||
| ] | ||||
|     """ | ||||
|     platform_model = apps.get_model('assets', 'Platform') | ||||
|     automation_cls = apps.get_model('assets', 'PlatformAutomation') | ||||
|     platform_datas = json.loads(data) | ||||
| 
 | ||||
|     for platform_data in platform_datas: | ||||
|         AllTypes.create_or_update_by_platform_data( | ||||
|             platform_data, platform_cls=platform_model, | ||||
|             automation_cls=automation_cls | ||||
|         ) | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
|     dependencies = [ | ||||
|         ("assets", "0016_directory_service"), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.RunPython(add_ds_platforms) | ||||
|     ] | ||||
|  | @ -1,9 +1,9 @@ | |||
| from .ad import * | ||||
| from .cloud import * | ||||
| from .common import * | ||||
| from .custom import * | ||||
| from .database import * | ||||
| from .device import * | ||||
| from .ds import * | ||||
| from .gpt import * | ||||
| from .host import * | ||||
| from .web import * | ||||
|  |  | |||
|  | @ -247,10 +247,10 @@ class Asset(NodesRelationMixin, LabeledMixin, AbsConnectivity, JSONFilterMixin, | |||
| 
 | ||||
|     @property | ||||
|     def all_accounts(self): | ||||
|         if not self.joined_ad_id: | ||||
|         if not self.joined_dir_svc_id: | ||||
|             queryset = self.accounts.all() | ||||
|         else: | ||||
|             queryset = self.accounts.model.objects.filter(asset__in=[self.id, self.joined_ad_id]) | ||||
|             queryset = self.accounts.model.objects.filter(asset__in=[self.id, self.joined_dir_svc_id]) | ||||
|         return queryset | ||||
| 
 | ||||
|     @lazyproperty | ||||
|  | @ -273,15 +273,15 @@ class Asset(NodesRelationMixin, LabeledMixin, AbsConnectivity, JSONFilterMixin, | |||
|         protocol = self.protocols.all().filter(name=protocol).first() | ||||
|         return protocol.port if protocol else 0 | ||||
| 
 | ||||
|     def is_ad(self): | ||||
|         return self.category == const.Category.AD | ||||
|     def is_dir_svc(self): | ||||
|         return self.category == const.Category.DS | ||||
| 
 | ||||
|     @property | ||||
|     def joined_ad_id(self): | ||||
|         return self.platform.ad_id | ||||
|     def joined_dir_svc_id(self): | ||||
|         return self.platform.ds_id | ||||
| 
 | ||||
|     def is_joined_ad(self): | ||||
|         if self.joined_ad_id: | ||||
|         if self.joined_dir_svc_id: | ||||
|             return True | ||||
|         else: | ||||
|             return False | ||||
|  |  | |||
|  | @ -3,11 +3,11 @@ from django.utils.translation import gettext_lazy as _ | |||
| 
 | ||||
| from .common import Asset | ||||
| 
 | ||||
| __all__ = ['AD'] | ||||
| __all__ = ['DirectoryService'] | ||||
| 
 | ||||
| 
 | ||||
| class AD(Asset): | ||||
| class DirectoryService(Asset): | ||||
|     domain_name = models.CharField(max_length=128, blank=True, default='', verbose_name=_("Domain name")) | ||||
| 
 | ||||
|     class Meta: | ||||
|         verbose_name = _("Active Directory") | ||||
|         verbose_name = _("Directory service") | ||||
|  | @ -102,10 +102,10 @@ class Platform(LabeledMixin, JMSBaseModel): | |||
|         max_length=8, verbose_name=_("Charset") | ||||
|     ) | ||||
|     domain_enabled = models.BooleanField(default=True, verbose_name=_("Gateway enabled")) | ||||
|     ad_enabled = models.BooleanField(default=False, verbose_name=_("AD enabled")) | ||||
|     ad = models.ForeignKey( | ||||
|         'assets.AD', on_delete=models.SET_NULL, null=True, blank=True, | ||||
|         verbose_name=_("Active Directory"), related_name='ad_platforms' | ||||
|     ds_enabled = models.BooleanField(default=False, verbose_name=_("DS enabled")) | ||||
|     ds = models.ForeignKey( | ||||
|         'DirectoryService', on_delete=models.SET_NULL, null=True, blank=True, | ||||
|         verbose_name=_("Directory service"), related_name='ds_platforms' | ||||
|     ) | ||||
|     # 账号有关的 | ||||
|     su_enabled = models.BooleanField(default=False, verbose_name=_("Su enabled")) | ||||
|  | @ -121,8 +121,8 @@ class Platform(LabeledMixin, JMSBaseModel): | |||
|         return self.assets.count() | ||||
| 
 | ||||
|     def save(self, *args, **kwargs): | ||||
|         if not self.ad_enabled: | ||||
|             self.ad = None | ||||
|         if not self.ds_enabled: | ||||
|             self.ds = None | ||||
|         super().save(*args, **kwargs) | ||||
| 
 | ||||
|     @classmethod | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ from .common import * | |||
| from .custom import * | ||||
| from .database import * | ||||
| from .device import * | ||||
| from .ds import * | ||||
| from .gpt import * | ||||
| from .host import * | ||||
| from .web import * | ||||
| from .ad import * | ||||
|  | @ -1,15 +1,14 @@ | |||
| from django.utils.translation import gettext_lazy as _ | ||||
| from rest_framework import serializers | ||||
| 
 | ||||
| from assets.models import AD | ||||
| from assets.models import DirectoryService | ||||
| from .common import AssetSerializer | ||||
| 
 | ||||
| __all__ = ['ADSerializer'] | ||||
| __all__ = ['DSSerializer'] | ||||
| 
 | ||||
| 
 | ||||
| class ADSerializer(AssetSerializer): | ||||
| class DSSerializer(AssetSerializer): | ||||
|     class Meta(AssetSerializer.Meta): | ||||
|         model = AD | ||||
|         model = DirectoryService | ||||
|         fields = AssetSerializer.Meta.fields + [ | ||||
|             'domain_name', | ||||
|         ] | ||||
|  | @ -194,8 +194,8 @@ class PlatformSerializer(ResourceLabelsMixin, CommonSerializerMixin, WritableNes | |||
|         ] | ||||
|         fields_m2m = ['assets', 'assets_amount'] | ||||
|         fields = fields_small + fields_m2m + [ | ||||
|             "protocols", "domain_enabled", "su_enabled", "su_method", "ad_enabled", "ad", | ||||
|             "automation", "comment", "custom_fields", "labels" | ||||
|             "protocols", "domain_enabled", "su_enabled", "su_method", | ||||
|             "ds_enabled", "ds", "automation", "comment", "custom_fields", "labels" | ||||
|         ] + read_only_fields | ||||
|         extra_kwargs = { | ||||
|             "su_enabled": { | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ router.register(r'databases', api.DatabaseViewSet, 'database') | |||
| router.register(r'webs', api.WebViewSet, 'web') | ||||
| router.register(r'clouds', api.CloudViewSet, 'cloud') | ||||
| router.register(r'gpts', api.GPTViewSet, 'gpt') | ||||
| router.register(r'directories', api.ADViewSet, 'ad') | ||||
| router.register(r'directories', api.DSViewSet, 'ds') | ||||
| router.register(r'customs', api.CustomViewSet, 'custom') | ||||
| router.register(r'platforms', api.AssetPlatformViewSet, 'platform') | ||||
| router.register(r'nodes', api.NodeViewSet, 'node') | ||||
|  |  | |||
|  | @ -8,7 +8,6 @@ from django.db import models | |||
| from django.shortcuts import get_object_or_404 | ||||
| from django.utils import timezone | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| from django.forms.models import model_to_dict | ||||
| from rest_framework.exceptions import PermissionDenied | ||||
| 
 | ||||
| from accounts.models import VirtualAccount | ||||
|  | @ -267,7 +266,7 @@ class ConnectionToken(JMSOrgBaseModel): | |||
|                 input_secret=self.input_secret, from_permed=False | ||||
|             ) | ||||
|         else: | ||||
|             account = self.asset.accounts.filter(name=self.account).first() | ||||
|             account = self.asset.all_valid_accounts.filter(id=self.account).first() | ||||
|             if not account.secret and self.input_secret: | ||||
|                 account.secret = self.input_secret | ||||
|         return account | ||||
|  |  | |||
|  | @ -40,6 +40,7 @@ class _ConnectionTokenAssetSerializer(serializers.ModelSerializer): | |||
| 
 | ||||
| class _SimpleAccountSerializer(serializers.ModelSerializer): | ||||
|     secret_type = LabeledChoiceField(choices=SecretType.choices, required=False, label=_('Secret type')) | ||||
|     username = serializers.CharField(label=_('Username'), source='full_username', read_only=True) | ||||
| 
 | ||||
|     class Meta: | ||||
|         model = Account | ||||
|  | @ -49,6 +50,7 @@ class _SimpleAccountSerializer(serializers.ModelSerializer): | |||
| class _ConnectionTokenAccountSerializer(serializers.ModelSerializer): | ||||
|     su_from = serializers.SerializerMethodField(label=_('Su from')) | ||||
|     secret_type = LabeledChoiceField(choices=SecretType.choices, required=False, label=_('Secret type')) | ||||
|     username = serializers.CharField(label=_('Username'), source='full_username', read_only=True) | ||||
| 
 | ||||
|     class Meta: | ||||
|         model = Account | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ FILE_END_GUARD = ">>> Content End <<<" | |||
| celery_task_pre_key = "CELERY_" | ||||
| KEY_CACHE_RESOURCE_IDS = "RESOURCE_IDS_{}" | ||||
| 
 | ||||
| # AD User AccountDisable | ||||
| # DS User AccountDisable | ||||
| # https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/useraccountcontrol-manipulate-account-properties | ||||
| LDAP_AD_ACCOUNT_DISABLE = 2 | ||||
| UUID_PATTERN = re.compile(r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') | ||||
|  |  | |||
|  | @ -121,8 +121,8 @@ LOGGING = { | |||
| 
 | ||||
| if CONFIG.DEBUG_DEV: | ||||
|     LOGGING['loggers']['django.db'] = { | ||||
|        'handlers': ['console', 'file'], | ||||
|        'level': 'DEBUG' | ||||
|         'handlers': ['console', 'file'], | ||||
|         'level': 'DEBUG' | ||||
|     } | ||||
| 
 | ||||
| SYSLOG_ENABLE = CONFIG.SYSLOG_ENABLE | ||||
|  | @ -138,4 +138,3 @@ if CONFIG.SYSLOG_ADDR != '' and len(CONFIG.SYSLOG_ADDR.split(':')) == 2: | |||
| 
 | ||||
| if not os.path.isdir(LOG_DIR): | ||||
|     os.makedirs(LOG_DIR, mode=0o755) | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,7 +20,7 @@ class TerminalSettingSerializer(serializers.Serializer): | |||
|     ) | ||||
|     SECURITY_SERVICE_ACCOUNT_REGISTRATION = serializers.ChoiceField( | ||||
|         choices=[ | ||||
|             ('auto', _('Auto(Enabled for the first 5 minutes after startup, then disabled.)')),  | ||||
|             ('auto', _('Auto(Enabled for the first 5 minutes after startup, then disabled.)')), | ||||
|             (True, _('Enable')), (False, _('Disable')) | ||||
|         ], | ||||
|         required=True, label=_('Registration'), | ||||
|  | @ -29,7 +29,7 @@ class TerminalSettingSerializer(serializers.Serializer): | |||
|         ) | ||||
|     ) | ||||
|     TERMINAL_PASSWORD_AUTH = serializers.BooleanField( | ||||
|         required=False, label=_("Password"),  | ||||
|         required=False, label=_("Password"), | ||||
|         help_text=_( | ||||
|             '* Allow users to log in to the KoKo component via password authentication' | ||||
|         ) | ||||
|  | @ -39,8 +39,8 @@ class TerminalSettingSerializer(serializers.Serializer): | |||
|         help_text=_( | ||||
|             '* Allow users to log in to the KoKo component via Public key authentication' | ||||
|             '<br/>' | ||||
|             'If third-party authentication services, such as AD/LDAP, are enabled, you should ' | ||||
|             'disable this option to prevent users from logging in after being deleted from the AD/LDAP server' | ||||
|             'If third-party authentication services, such as DS/LDAP, are enabled, you should ' | ||||
|             'disable this option to prevent users from logging in after being deleted from the DS/LDAP server' | ||||
|         ) | ||||
|     ) | ||||
|     TERMINAL_ASSET_LIST_SORT_BY = serializers.ChoiceField( | ||||
|  | @ -50,7 +50,7 @@ class TerminalSettingSerializer(serializers.Serializer): | |||
|         PAGE_SIZE_CHOICES, required=False, label=_('Asset page size') | ||||
|     ) | ||||
|     TERMINAL_MAGNUS_ENABLED = serializers.BooleanField( | ||||
|         label="Magnus",  | ||||
|         label="Magnus", | ||||
|         help_text=_( | ||||
|             '* You can individually configure the service address and port in the service endpoint' | ||||
|             '<br/>' | ||||
|  |  | |||
|  | @ -197,7 +197,7 @@ class LDAPServerUtil(object): | |||
|                     value = is_true(value) | ||||
| 
 | ||||
|             if attr == 'groups' and mapping.lower() == 'memberof': | ||||
|                 # AD: {'groups': 'memberOf'} | ||||
|                 # DS: {'groups': 'memberOf'} | ||||
|                 if isinstance(value, str) and value: | ||||
|                     value = [value] | ||||
|                 if not isinstance(value, list): | ||||
|  | @ -366,7 +366,7 @@ class LDAPSyncUtil(object): | |||
| 
 | ||||
| 
 | ||||
| class LDAPImportUtil(object): | ||||
|     user_group_name_prefix = 'AD ' | ||||
|     user_group_name_prefix = 'DS ' | ||||
| 
 | ||||
|     def __init__(self, category=User.Source.ldap.value, is_sync_all=True): | ||||
|         self.category = category | ||||
|  | @ -399,7 +399,7 @@ class LDAPImportUtil(object): | |||
|                 continue | ||||
|             if not isinstance(group, str): | ||||
|                 continue | ||||
|             # get group name for AD, Such as: CN=Users,CN=Builtin,DC=jms,DC=com | ||||
|             # get group name for DS, Such as: CN=Users,CN=Builtin,DC=jms,DC=com | ||||
|             group_name = group.split(',')[0].split('=')[-1] | ||||
|             group_name = f'{self.user_group_name_prefix}{group_name}'.strip() | ||||
|             group_names.append(group_name) | ||||
|  |  | |||
|  | @ -81,7 +81,7 @@ class Migration(migrations.Migration): | |||
|                  models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date password last updated')), | ||||
|                 ('need_update_password', models.BooleanField(default=False, verbose_name='Need update password')), | ||||
|                 ('source', models.CharField( | ||||
|                     choices=[('local', 'Local'), ('ldap', 'LDAP/AD'), ('ldap_ha', 'LDAP/AD (HA)'), ('openid', 'OpenID'), | ||||
|                     choices=[('local', 'Local'), ('ldap', 'LDAP/DS'), ('ldap_ha', 'LDAP/DS (HA)'), ('openid', 'OpenID'), | ||||
|                              ('radius', 'Radius'), ('cas', 'CAS'), ('saml2', 'SAML2'), ('oauth2', 'OAuth2'), | ||||
|                              ('wecom', 'WeCom'), ('dingtalk', 'DingTalk'), ('feishu', 'FeiShu'), ('lark', 'Lark'), | ||||
|                              ('slack', 'Slack'), ('custom', 'Custom')], default='local', max_length=30, | ||||
|  |  | |||
|  | @ -9,8 +9,8 @@ from django.utils.translation import gettext_lazy as _ | |||
| 
 | ||||
| class Source(models.TextChoices): | ||||
|     local = "local", _("Local") | ||||
|     ldap = "ldap", "LDAP/AD" | ||||
|     ldap_ha = "ldap_ha", "LDAP/AD (HA)" | ||||
|     ldap = "ldap", "LDAP/DS" | ||||
|     ldap_ha = "ldap_ha", "LDAP/DS (HA)" | ||||
|     openid = "openid", "OpenID" | ||||
|     radius = "radius", "Radius" | ||||
|     cas = "cas", "CAS" | ||||
|  |  | |||
|  | @ -247,7 +247,7 @@ class UserSerializer( | |||
|             }, | ||||
|             "source": { | ||||
|                 "help_text": _( | ||||
|                     "User source identifies where the user was created, which could be AD or other sources." | ||||
|                     "User source identifies where the user was created, which could be DS or other sources." | ||||
|                     "There are security settings that can restrict users to log in to the system only from the sources." | ||||
|                 ), | ||||
|             }, | ||||
|  |  | |||
|  | @ -53,7 +53,7 @@ REDIS_PORT: 6379 | |||
| # REDIS_DB_CELERY: 3 | ||||
| # REDIS_DB_CACHE: 4 | ||||
| 
 | ||||
| # LDAP/AD settings | ||||
| # LDAP/DS settings | ||||
| # LDAP 搜索分页数量 | ||||
| # AUTH_LDAP_SEARCH_PAGED_SIZE: 1000 | ||||
| # | ||||
|  | @ -99,4 +99,4 @@ REDIS_PORT: 6379 | |||
| # 开启人脸识别 XPACK 功能 | ||||
| #FACE_RECOGNITION_ENABLED: true | ||||
| #FACE_RECOGNITION_DISTANCE_THRESHOLD': 0.35 | ||||
| #FACE_RECOGNITION_COSINE_THRESHOLD': 0.95 | ||||
| #FACE_RECOGNITION_COSINE_THRESHOLD': 0.95 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 ibuler
						ibuler