class AuthSerializer(serializers.ModelSerializer): password = EncryptedField(required=False, allow_blank=True, allow_null=True, max_length=1024, label=_('Password')) private_key = EncryptedField(required=False, allow_blank=True, allow_null=True, max_length=4096, label=_('Private key')) def gen_keys(self, private_key=None, password=None): if private_key is None: return None, None public_key = ssh_pubkey_gen(private_key=private_key, password=password) return private_key, public_key def save(self, **kwargs): password = self.validated_data.pop('password', None) or None private_key = self.validated_data.pop('private_key', None) or None self.instance = super().save(**kwargs) if password or private_key: private_key, public_key = self.gen_keys(private_key, password) self.instance.set_auth(password=password, private_key=private_key, public_key=public_key) return self.instance
class AuthSerializerMixin(serializers.ModelSerializer): password = EncryptedField(label=_('Password'), required=False, allow_blank=True, allow_null=True, max_length=1024, validators=[validate_password_for_ansible]) private_key = EncryptedField(label=_('SSH private key'), required=False, allow_blank=True, allow_null=True, max_length=4096) passphrase = serializers.CharField(allow_blank=True, allow_null=True, required=False, max_length=512, write_only=True, label=_('Key password')) def validate_password(self, password): return password def validate_private_key(self, private_key): if not private_key: return passphrase = self.initial_data.get('passphrase') passphrase = passphrase if passphrase else None valid = validate_ssh_private_key(private_key, password=passphrase) if not valid: raise serializers.ValidationError( _("private key invalid or passphrase error")) private_key = ssh_private_key_gen(private_key, password=passphrase) string_io = StringIO() private_key.write_private_key(string_io) private_key = string_io.getvalue() return private_key def validate_public_key(self, public_key): return public_key @staticmethod def clean_auth_fields(validated_data): for field in ('password', 'private_key', 'public_key'): value = validated_data.get(field) if not value: validated_data.pop(field, None) validated_data.pop('passphrase', None) def create(self, validated_data): self.clean_auth_fields(validated_data) return super().create(validated_data) def update(self, instance, validated_data): self.clean_auth_fields(validated_data) return super().update(instance, validated_data)
class VMwareClientSerializer(RemoteAppSerializer): PATH = r''' C:\Program Files (x86)\VMware\Infrastructure\Virtual Infrastructure Client\Launcher\VpxClient .exe ''' VMWARE_CLIENT_PATH = ''.join(PATH.split()) path = serializers.CharField(max_length=128, label=_('Application path'), default=VMWARE_CLIENT_PATH, allow_null=True) vmware_target = serializers.CharField(max_length=128, allow_blank=True, required=False, label=_('Target URL'), allow_null=True) vmware_username = serializers.CharField(max_length=128, allow_blank=True, required=False, label=_('Vmware username'), allow_null=True) vmware_password = EncryptedField(max_length=128, allow_blank=True, required=False, label=_('Vmware password'), allow_null=True)
class CustomSerializer(RemoteAppSerializer): custom_cmdline = serializers.CharField( max_length=128, allow_blank=True, required=False, label=_('Operating parameter'), allow_null=True, ) custom_target = serializers.CharField( max_length=128, allow_blank=True, required=False, label=_('Target url'), allow_null=True, ) custom_username = serializers.CharField( max_length=128, allow_blank=True, required=False, label=_('Custom Username'), allow_null=True, ) custom_password = EncryptedField( max_length=128, allow_blank=True, required=False, label=_('Custom password'), allow_null=True, )
class MySQLWorkbenchSerializer(RemoteAppSerializer): MYSQL_WORKBENCH_PATH = 'C:\Program Files\MySQL\MySQL Workbench 8.0 CE\MySQLWorkbench.exe' path = serializers.CharField( max_length=128, label=_('Application path'), default=MYSQL_WORKBENCH_PATH, allow_null=True, ) mysql_workbench_ip = serializers.CharField( max_length=128, allow_blank=True, required=False, label=_('IP'), allow_null=True, ) mysql_workbench_port = serializers.IntegerField( required=False, label=_('Port'), allow_null=True, ) mysql_workbench_name = serializers.CharField( max_length=128, allow_blank=True, required=False, label=_('Database'), allow_null=True, ) mysql_workbench_username = serializers.CharField( max_length=128, allow_blank=True, required=False, label=_('Mysql workbench username'), allow_null=True, ) mysql_workbench_password = EncryptedField( max_length=128, allow_blank=True, required=False, label=_('Mysql workbench password'), allow_null=True, )
class EmailSettingSerializer(serializers.Serializer): # encrypt_fields 现在使用 write_only 来判断了 EMAIL_HOST = serializers.CharField(max_length=1024, required=True, label=_("SMTP host")) EMAIL_PORT = serializers.CharField(max_length=5, required=True, label=_("SMTP port")) EMAIL_HOST_USER = serializers.CharField(max_length=128, required=True, label=_("SMTP account")) EMAIL_HOST_PASSWORD = EncryptedField( max_length=1024, required=False, label=_("SMTP password"), help_text=_("Tips: Some provider use token except password") ) EMAIL_FROM = serializers.CharField( max_length=128, allow_blank=True, required=False, label=_('Send user'), help_text=_('Tips: Send mail account, default SMTP account as the send account') ) EMAIL_RECIPIENT = serializers.CharField( max_length=128, allow_blank=True, required=False, label=_('Test recipient'), help_text=_('Tips: Used only as a test mail recipient') ) EMAIL_USE_SSL = serializers.BooleanField( required=False, label=_('Use SSL'), help_text=_('If SMTP port is 465, may be select') ) EMAIL_USE_TLS = serializers.BooleanField( required=False, label=_("Use TLS"), help_text=_('If SMTP port is 587, may be select') ) EMAIL_SUBJECT_PREFIX = serializers.CharField( max_length=1024, required=True, label=_('Subject prefix') )
class CommonSettingSerializer(serializers.Serializer): # OpenID 公有配置参数 (version <= 1.5.8 或 version >= 1.5.8) BASE_SITE_URL = serializers.CharField( required=False, allow_null=True, max_length=1024, label=_('Base site url') ) AUTH_OPENID_CLIENT_ID = serializers.CharField( required=False, max_length=1024, label=_('Client Id') ) AUTH_OPENID_CLIENT_SECRET = EncryptedField( required=False, max_length=1024, label=_('Client Secret') ) AUTH_OPENID_CLIENT_AUTH_METHOD = serializers.ChoiceField( default='client_secret_basic', choices=( ('client_secret_basic', 'Client Secret Basic'), ('client_secret_post', 'Client Secret Post') ), label=_('Client authentication method') ) AUTH_OPENID_SHARE_SESSION = serializers.BooleanField(required=False, label=_('Share session')) AUTH_OPENID_IGNORE_SSL_VERIFICATION = serializers.BooleanField( required=False, label=_('Ignore ssl verification') ) AUTH_OPENID_USER_ATTR_MAP = serializers.DictField( required=True, label=_('User attr map'), help_text=_('User attr map present how to map OpenID user attr to ' 'jumpserver, username,name,email is jumpserver attr') )
class VMwareClientSecretSerializer(RemoteAppSerializer): vmware_password = EncryptedField(max_length=128, allow_blank=True, required=False, write_only=False, label=_('Vmware password'), allow_null=True)
class RadiusSettingSerializer(serializers.Serializer): AUTH_RADIUS = serializers.BooleanField(required=False, label=_('Enable Radius Auth')) RADIUS_SERVER = serializers.CharField(required=False, allow_blank=True, max_length=1024, label=_('Host')) RADIUS_PORT = serializers.IntegerField(required=False, label=_('Port')) RADIUS_SECRET = EncryptedField( required=False, max_length=1024, allow_null=True, label=_('Secret'), ) OTP_IN_RADIUS = serializers.BooleanField(required=False, label=_('OTP in Radius'))
class FeiShuSettingSerializer(serializers.Serializer): FEISHU_APP_ID = serializers.CharField(max_length=256, required=True, label='App ID') FEISHU_APP_SECRET = EncryptedField(max_length=256, required=False, label='App Secret') AUTH_FEISHU = serializers.BooleanField(default=False, label=_('Enable FeiShu Auth'))
class CustomSecretSerializer(RemoteAppSerializer): custom_password = EncryptedField( max_length=128, allow_blank=True, required=False, write_only=False, label=_('Custom password'), allow_null=True, )
class LDAPTestConfigSerializer(serializers.Serializer): AUTH_LDAP_SERVER_URI = serializers.CharField(max_length=1024) AUTH_LDAP_BIND_DN = serializers.CharField(max_length=1024, required=False, allow_blank=True) AUTH_LDAP_BIND_PASSWORD = EncryptedField(required=False, allow_blank=True) AUTH_LDAP_SEARCH_OU = serializers.CharField() AUTH_LDAP_SEARCH_FILTER = serializers.CharField() AUTH_LDAP_USER_ATTR_MAP = serializers.CharField() AUTH_LDAP_START_TLS = serializers.BooleanField(required=False) AUTH_LDAP = serializers.BooleanField(required=False)
class WeComSettingSerializer(serializers.Serializer): WECOM_CORPID = serializers.CharField(max_length=256, required=True, label='corpid') WECOM_AGENTID = serializers.CharField(max_length=256, required=True, label='agentid') WECOM_SECRET = EncryptedField(max_length=256, required=False, label='secret') AUTH_WECOM = serializers.BooleanField(default=False, label=_('Enable WeCom Auth'))
class DingTalkSettingSerializer(serializers.Serializer): DINGTALK_AGENTID = serializers.CharField(max_length=256, required=True, label='AgentId') DINGTALK_APPKEY = serializers.CharField(max_length=256, required=True, label='AppKey') DINGTALK_APPSECRET = EncryptedField(max_length=256, required=False, label='AppSecret') AUTH_DINGTALK = serializers.BooleanField(default=False, label=_('Enable DingTalk Auth'))
class UserUpdateSecretKeySerializer(serializers.ModelSerializer): new_secret_key = EncryptedField(required=True, max_length=128) new_secret_key_again = EncryptedField(required=True, max_length=128) class Meta: model = User fields = ['new_secret_key', 'new_secret_key_again'] def validate(self, values): new_secret_key = values.get('new_secret_key', '') new_secret_key_again = values.get('new_secret_key_again', '') if new_secret_key != new_secret_key_again: msg = _('The newly set password is inconsistent') raise serializers.ValidationError({'new_secret_key_again': msg}) return values def update(self, instance, validated_data): new_secret_key = self.validated_data.get('new_secret_key') instance.secret_key = new_secret_key instance.save() return instance
class UserUpdatePasswordSerializer(serializers.ModelSerializer): old_password = EncryptedField(required=True, max_length=128) new_password = EncryptedField(required=True, max_length=128) new_password_again = EncryptedField(required=True, max_length=128) class Meta: model = User fields = ['old_password', 'new_password', 'new_password_again'] def validate_old_password(self, value): if not self.instance.check_password(value): msg = _('The old password is incorrect') raise serializers.ValidationError(msg) return value def validate_new_password(self, value): from ..utils import check_password_rules if not check_password_rules(value, is_org_admin=self.instance.is_org_admin): msg = _('Password does not match security rules') raise serializers.ValidationError(msg) if self.instance.is_history_password(value): limit_count = settings.OLD_PASSWORD_HISTORY_LIMIT_COUNT msg = _('The new password cannot be the last {} passwords').format( limit_count) raise serializers.ValidationError(msg) return value def validate(self, values): new_password = values.get('new_password', '') new_password_again = values.get('new_password_again', '') if new_password != new_password_again: msg = _('The newly set password is inconsistent') raise serializers.ValidationError({'new_password_again': msg}) return values def update(self, instance, validated_data): new_password = self.validated_data.get('new_password') instance.reset_password(new_password) return instance
class ReplayStorageTypeAzureSerializer(serializers.Serializer): class EndpointSuffixChoices(TextChoices): china = 'core.chinacloudapi.cn', 'core.chinacloudapi.cn' international = 'core.windows.net', 'core.windows.net' CONTAINER_NAME = serializers.CharField( max_length=1024, label=_('Container name'), allow_null=True ) ACCOUNT_NAME = serializers.CharField(max_length=1024, label=_('Account name'), allow_null=True) ACCOUNT_KEY = EncryptedField(max_length=1024, label=_('Account key'), allow_null=True) ENDPOINT_SUFFIX = serializers.ChoiceField( choices=EndpointSuffixChoices.choices, default=EndpointSuffixChoices.china.value, label=_('Endpoint suffix'), allow_null=True, )
class LDAPSettingSerializer(serializers.Serializer): # encrypt_fields 现在使用 write_only 来判断了 AUTH_LDAP_SERVER_URI = serializers.CharField( required=True, max_length=1024, label=_('LDAP server'), help_text=_('eg: ldap://localhost:389') ) AUTH_LDAP_BIND_DN = serializers.CharField(required=False, max_length=1024, label=_('Bind DN')) AUTH_LDAP_BIND_PASSWORD = EncryptedField( max_length=1024, required=False, label=_('Password') ) AUTH_LDAP_SEARCH_OU = serializers.CharField( max_length=1024, allow_blank=True, required=False, label=_('User OU'), help_text=_('Use | split multi OUs') ) AUTH_LDAP_SEARCH_FILTER = serializers.CharField( max_length=1024, required=True, label=_('User search filter'), help_text=_('Choice may be (cn|uid|sAMAccountName)=%(user)s)') ) AUTH_LDAP_USER_ATTR_MAP = serializers.DictField( required=True, label=_('User attr map'), help_text=_('User attr map present how to map LDAP user attr to ' 'jumpserver, username,name,email is jumpserver attr') ) AUTH_LDAP_SYNC_ORG_ID = serializers.CharField( required=False, label=_('Organization'), max_length=36 ) AUTH_LDAP_SYNC_IS_PERIODIC = serializers.BooleanField( required=False, label=_('Periodic perform') ) AUTH_LDAP_SYNC_CRONTAB = serializers.CharField( required=False, max_length=128, allow_null=True, allow_blank=True, label=_('Regularly perform') ) AUTH_LDAP_SYNC_INTERVAL = serializers.IntegerField( required=False, default=24, allow_null=True, label=_('Cycle perform') ) AUTH_LDAP_CONNECT_TIMEOUT = serializers.IntegerField( min_value=1, max_value=300, required=False, label=_('Connect timeout'), ) AUTH_LDAP_SEARCH_PAGED_SIZE = serializers.IntegerField(required=False, label=_('Search paged size')) AUTH_LDAP = serializers.BooleanField(required=False, label=_('Enable LDAP auth')) @staticmethod def post_save(): from users.tasks import import_ldap_user_periodic import_ldap_user_periodic()
class ReplayStorageTypeBaseSerializer(serializers.Serializer): BUCKET = serializers.CharField( required=True, max_length=1024, label=_('Bucket'), allow_null=True ) ACCESS_KEY = serializers.CharField( max_length=1024, required=False, allow_blank=True, label=_('Access key id'), allow_null=True, ) SECRET_KEY = EncryptedField( max_length=1024, required=False, allow_blank=True, label=_('Access key secret'), allow_null=True, ) ENDPOINT = serializers.CharField( validators=[replay_storage_endpoint_format_validator], required=True, max_length=1024, label=_('Endpoint'), allow_null=True, )
class ChromeSerializer(RemoteAppSerializer): CHROME_PATH = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe' path = serializers.CharField( max_length=128, label=_('Application path'), default=CHROME_PATH, allow_null=True, ) chrome_target = serializers.CharField( max_length=128, allow_blank=True, required=False, label=_('Target URL'), allow_null=True, ) chrome_username = serializers.CharField( max_length=128, allow_blank=True, required=False, label=_('Chrome username'), allow_null=True, ) chrome_password = EncryptedField( max_length=128, allow_blank=True, required=False, label=_('Chrome password'), allow_null=True )
class ConfirmSerializer(serializers.Serializer): confirm_type = serializers.ChoiceField(required=True, choices=ConfirmType.choices) secret_key = EncryptedField()
class UserSerializer(RolesSerializerMixin, CommonBulkSerializerMixin, serializers.ModelSerializer): password_strategy = serializers.ChoiceField( choices=PasswordStrategy.choices, default=PasswordStrategy.email, required=False, write_only=True, label=_('Password strategy')) mfa_enabled = serializers.BooleanField(read_only=True, label=_('MFA enabled')) mfa_force_enabled = serializers.BooleanField(read_only=True, label=_('MFA force enabled')) mfa_level_display = serializers.ReadOnlyField( source='get_mfa_level_display', label=_('MFA level display')) login_blocked = serializers.BooleanField(read_only=True, label=_('Login blocked')) is_expired = serializers.BooleanField(read_only=True, label=_('Is expired')) can_public_key_auth = serializers.ReadOnlyField( source='can_use_ssh_key_login', label=_('Can public key authentication')) password = EncryptedField(label=_('Password'), required=False, allow_blank=True, allow_null=True, max_length=1024) # Todo: 这里看看该怎么搞 # can_update = serializers.SerializerMethodField(label=_('Can update')) # can_delete = serializers.SerializerMethodField(label=_('Can delete')) custom_m2m_fields = { 'system_roles': [BuiltinRole.system_user], 'org_roles': [BuiltinRole.org_user] } class Meta: model = User # mini 是指能识别对象的最小单元 fields_mini = ['id', 'name', 'username'] # 只能写的字段, 这个虽然无法在框架上生效,但是更多对我们是提醒 fields_write_only = [ 'password', 'public_key', ] # small 指的是 不需要计算的直接能从一张表中获取到的数据 fields_small = fields_mini + fields_write_only + [ 'email', 'wechat', 'phone', 'mfa_level', 'source', 'source_display', 'can_public_key_auth', 'need_update_password', 'mfa_enabled', 'is_service_account', 'is_valid', 'is_expired', 'is_active', # 布尔字段 'date_expired', 'date_joined', 'last_login', # 日期字段 'created_by', 'comment', # 通用字段 'is_wecom_bound', 'is_dingtalk_bound', 'is_feishu_bound', 'is_otp_secret_key_bound', 'wecom_id', 'dingtalk_id', 'feishu_id' ] # 包含不太常用的字段,可以没有 fields_verbose = fields_small + [ 'mfa_level_display', 'mfa_force_enabled', 'is_first_login', 'date_password_last_updated', 'avatar_url', ] # 外键的字段 fields_fk = [] # 多对多字段 fields_m2m = [ 'groups', 'groups_display', 'system_roles', 'org_roles', 'system_roles_display', 'org_roles_display' ] # 在serializer 上定义的字段 fields_custom = ['login_blocked', 'password_strategy'] fields = fields_verbose + fields_fk + fields_m2m + fields_custom read_only_fields = [ 'date_joined', 'last_login', 'created_by', 'is_first_login', 'wecom_id', 'dingtalk_id', 'feishu_id' ] disallow_self_update_fields = ['is_active'] extra_kwargs = { 'password': { 'write_only': True, 'required': False, 'allow_null': True, 'allow_blank': True }, 'public_key': { 'write_only': True }, 'is_first_login': { 'label': _('Is first login'), 'read_only': True }, 'is_valid': { 'label': _('Is valid') }, 'is_service_account': { 'label': _('Is service account') }, 'is_expired': { 'label': _('Is expired') }, 'avatar_url': { 'label': _('Avatar url') }, 'created_by': { 'read_only': True, 'allow_blank': True }, 'groups_display': { 'label': _('Groups name') }, 'source_display': { 'label': _('Source name') }, 'org_role_display': { 'label': _('Organization role name') }, 'role_display': { 'label': _('Super role name') }, 'total_role_display': { 'label': _('Total role name') }, 'role': { 'default': "User" }, 'is_wecom_bound': { 'label': _('Is wecom bound') }, 'is_dingtalk_bound': { 'label': _('Is dingtalk bound') }, 'is_feishu_bound': { 'label': _('Is feishu bound') }, 'is_otp_secret_key_bound': { 'label': _('Is OTP bound') }, 'phone': { 'validators': [PhoneValidator()] }, 'system_role_display': { 'label': _('System role name') }, } def validate_password(self, password): password_strategy = self.initial_data.get('password_strategy') if self.instance is None and password_strategy != PasswordStrategy.custom: # 创建用户,使用邮件设置密码 return if self.instance and not password: # 更新用户, 未设置密码 return return password @staticmethod def change_password_to_raw(attrs): password = attrs.pop('password', None) if password: attrs['password_raw'] = password return attrs @staticmethod def clean_auth_fields(attrs): for field in ('password', 'public_key'): value = attrs.get(field) if not value: attrs.pop(field, None) return attrs def check_disallow_self_update_fields(self, attrs): request = self.context.get('request') if not request or not request.user.is_authenticated: return attrs if not self.instance: return attrs if request.user.id != self.instance.id: return attrs disallow_fields = set(list(attrs.keys())) & set( self.Meta.disallow_self_update_fields) if not disallow_fields: return attrs # 用户自己不能更新自己的一些字段 error = _('User cannot self-update fields: {}').format(disallow_fields) raise serializers.ValidationError(error) def validate(self, attrs): attrs = self.check_disallow_self_update_fields(attrs) attrs = self.change_password_to_raw(attrs) attrs = self.clean_auth_fields(attrs) attrs.pop('password_strategy', None) return attrs def save_and_set_custom_m2m_fields(self, validated_data, save_handler, created): m2m_values = {} for f, default_roles in self.custom_m2m_fields.items(): roles = validated_data.pop(f, None) if created and not roles: roles = [ Role.objects.filter(id=role.id).first() for role in default_roles ] m2m_values[f] = roles instance = save_handler(validated_data) for field_name, value in m2m_values.items(): if value is None: continue field = getattr(instance, field_name) field.set(value) return instance def update(self, instance, validated_data): save_handler = partial(super().update, instance) instance = self.save_and_set_custom_m2m_fields(validated_data, save_handler, created=False) return instance def create(self, validated_data): save_handler = super().create instance = self.save_and_set_custom_m2m_fields(validated_data, save_handler, created=True) return instance
class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): """ 系统用户 """ password = EncryptedField( label=_('Password'), required=False, allow_blank=True, allow_null=True, max_length=1024, trim_whitespace=False, validators=[validate_password_for_ansible], write_only=True ) auto_generate_key = serializers.BooleanField(initial=True, required=False, write_only=True) type_display = serializers.ReadOnlyField(source='get_type_display', label=_('Type display')) ssh_key_fingerprint = serializers.ReadOnlyField(label=_('SSH key fingerprint')) token = EncryptedField( label=_('Token'), required=False, write_only=True, style={'base_template': 'textarea.html'} ) applications_amount = serializers.IntegerField( source='apps_amount', read_only=True, label=_('Apps amount') ) class Meta: model = SystemUser fields_mini = ['id', 'name', 'username'] fields_write_only = ['password', 'public_key', 'private_key', 'passphrase'] fields_small = fields_mini + fields_write_only + [ 'token', 'ssh_key_fingerprint', 'type', 'type_display', 'protocol', 'is_asset_protocol', 'login_mode', 'login_mode_display', 'priority', 'sudo', 'shell', 'sftp_root', 'home', 'system_groups', 'ad_domain', 'username_same_with_user', 'auto_push', 'auto_generate_key', 'su_enabled', 'su_from', 'date_created', 'date_updated', 'comment', 'created_by', ] fields_m2m = ['cmd_filters', 'assets_amount', 'applications_amount', 'nodes'] fields = fields_small + fields_m2m extra_kwargs = { 'cmd_filters': {"required": False, 'label': _('Command filter')}, 'public_key': {"write_only": True}, 'private_key': {"write_only": True}, 'nodes_amount': {'label': _('Nodes amount')}, 'assets_amount': {'label': _('Assets amount')}, 'login_mode_display': {'label': _('Login mode display')}, 'created_by': {'read_only': True}, 'ad_domain': {'required': False, 'allow_blank': True, 'label': _('Ad domain')}, 'is_asset_protocol': {'label': _('Is asset protocol')}, 'su_from': {'help_text': _('Only ssh and automatic login system users are supported')} } def validate_auto_push(self, value): login_mode = self.get_initial_value("login_mode") protocol = self.get_initial_value("protocol") if login_mode == SystemUser.LOGIN_MANUAL: value = False elif protocol not in SystemUser.SUPPORT_PUSH_PROTOCOLS: value = False return value def validate_auto_generate_key(self, value): login_mode = self.get_initial_value("login_mode") protocol = self.get_initial_value("protocol") if self.context["request"].method.lower() != "post": value = False elif self.instance: value = False elif login_mode == SystemUser.LOGIN_MANUAL: value = False elif protocol not in SystemUser.SUPPORT_PUSH_PROTOCOLS: value = False return value def validate_username_same_with_user(self, username_same_with_user): if not username_same_with_user: return username_same_with_user protocol = self.get_initial_value("protocol", "ssh") queryset = SystemUser.objects.filter( protocol=protocol, username_same_with_user=True ) if self.instance: queryset = queryset.exclude(id=self.instance.id) exists = queryset.exists() if not exists: return username_same_with_user error = _("Username same with user with protocol {} only allow 1").format(protocol) raise serializers.ValidationError(error) def validate_username(self, username): protocol = self.get_initial_value("protocol") if username: if protocol == SystemUser.Protocol.telnet: regx = alphanumeric_cn_re elif protocol == SystemUser.Protocol.rdp: regx = alphanumeric_win_re else: regx = alphanumeric_re if not regx.match(username): raise serializers.ValidationError(_('Special char not allowed')) return username username_same_with_user = self.get_initial_value("username_same_with_user") if username_same_with_user: return '' login_mode = self.get_initial_value("login_mode") if login_mode == SystemUser.LOGIN_AUTO and protocol != SystemUser.Protocol.vnc \ and protocol != SystemUser.Protocol.redis: msg = _('* Automatic login mode must fill in the username.') raise serializers.ValidationError(msg) return username def validate_home(self, home): username_same_with_user = self.get_initial_value("username_same_with_user") if username_same_with_user: return '' return home @staticmethod def validate_sftp_root(value): if value in ['home', 'tmp']: return value if not value.startswith('/'): error = _("Path should starts with /") raise serializers.ValidationError(error) return value def validate_password(self, password): super().validate_password(password) auto_gen_key = self.get_initial_value('auto_generate_key', False) private_key = self.get_initial_value('private_key') login_mode = self.get_initial_value('login_mode') if not self.instance and not auto_gen_key and not password and \ not private_key and login_mode == SystemUser.LOGIN_AUTO: raise serializers.ValidationError(_("Password or private key required")) return password def validate_su_from(self, su_from: SystemUser): # self: su enabled su_enabled = self.get_initial_value('su_enabled', default=False) if not su_enabled: return if not su_from: error = _('This field is required.') raise serializers.ValidationError(error) # self: protocol ssh protocol = self.get_initial_value('protocol', default=SystemUser.Protocol.ssh.value) if protocol not in [SystemUser.Protocol.ssh.value]: error = _('Only ssh protocol system users are allowed') raise serializers.ValidationError(error) # su_from: protocol same if su_from.protocol != protocol: error = _('The protocol must be consistent with the current user: {}').format(protocol) raise serializers.ValidationError(error) # su_from: login model auto if su_from.login_mode != su_from.LOGIN_AUTO: error = _('Only system users with automatic login are allowed') raise serializers.ValidationError(error) return su_from def _validate_admin_user(self, attrs): if self.instance: tp = self.instance.type else: tp = attrs.get('type') if tp != SystemUser.Type.admin: return attrs attrs['protocol'] = SystemUser.Protocol.ssh attrs['login_mode'] = SystemUser.LOGIN_AUTO attrs['username_same_with_user'] = False attrs['auto_push'] = False return attrs def _validate_gen_key(self, attrs): username = attrs.get('username', 'manual') auto_gen_key = attrs.pop('auto_generate_key', False) protocol = attrs.get('protocol') if protocol not in SystemUser.SUPPORT_PUSH_PROTOCOLS: return attrs # 自动生成 if auto_gen_key and not self.instance: password = SystemUser.gen_password() attrs['password'] = password if protocol == SystemUser.Protocol.ssh: private_key, public_key = SystemUser.gen_key(username) attrs['private_key'] = private_key attrs['public_key'] = public_key # 如果设置了private key,没有设置public key则生成 elif attrs.get('private_key'): private_key = attrs['private_key'] password = attrs.get('password') public_key = ssh_pubkey_gen(private_key, password=password, username=username) attrs['public_key'] = public_key return attrs def _validate_login_mode(self, attrs): if 'login_mode' in attrs: login_mode = attrs['login_mode'] else: login_mode = self.instance.login_mode if self.instance else SystemUser.LOGIN_AUTO if login_mode == SystemUser.LOGIN_MANUAL: attrs['password'] = '' attrs['private_key'] = '' attrs['public_key'] = '' return attrs def validate(self, attrs): attrs = self._validate_admin_user(attrs) attrs = self._validate_gen_key(attrs) attrs = self._validate_login_mode(attrs) return attrs @classmethod def setup_eager_loading(cls, queryset): """ Perform necessary eager loading of data. """ queryset = queryset \ .annotate(assets_amount=Count("assets")) \ .prefetch_related('nodes', 'cmd_filters') return queryset
class LDAPTestLoginSerializer(serializers.Serializer): username = serializers.CharField(max_length=1024, required=True) password = EncryptedField(max_length=2014, required=True, label=_("Password"))
class MySQLWorkbenchSecretSerializer(RemoteAppSerializer): mysql_workbench_password = EncryptedField( max_length=128, allow_blank=True, required=False, write_only=False, label=_('Mysql workbench password'), allow_null=True, )
class PasswordVerifySerializer(serializers.Serializer): password = EncryptedField()
class ChromeSecretSerializer(ChromeSerializer): chrome_password = EncryptedField( max_length=128, allow_blank=True, required=False, label=_('Chrome password'), allow_null=True, write_only=False )