From 20cf7c7c52038bd2979568684ac5ad7596049246 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 29 Apr 2020 11:08:09 +0800 Subject: [PATCH 1/3] [Update] Add settings api --- apps/settings/api.py | 64 ++++++++++++++- apps/settings/serializers/__init__.py | 1 + apps/settings/serializers/settings.py | 113 ++++++++++++++++++++++++++ apps/settings/urls/api_urls.py | 6 ++ apps/settings/utils/__init__.py | 1 + apps/settings/utils/common.py | 18 ++++ 6 files changed, 199 insertions(+), 4 deletions(-) create mode 100644 apps/settings/serializers/settings.py create mode 100644 apps/settings/utils/common.py diff --git a/apps/settings/api.py b/apps/settings/api.py index 38167a7e3..69f0129f8 100644 --- a/apps/settings/api.py +++ b/apps/settings/api.py @@ -12,18 +12,19 @@ from django.utils.translation import ugettext_lazy as _ from .utils import ( LDAPServerUtil, LDAPCacheUtil, LDAPImportUtil, LDAPSyncUtil, - LDAP_USE_CACHE_FLAGS, LDAPTestUtil, + LDAP_USE_CACHE_FLAGS, LDAPTestUtil, ObjectDict ) from .tasks import sync_ldap_user_task from common.permissions import IsOrgAdmin, IsSuperUser from common.utils import get_logger from .serializers import ( MailTestSerializer, LDAPTestConfigSerializer, LDAPUserSerializer, - PublicSettingSerializer, LDAPTestLoginSerializer, + PublicSettingSerializer, LDAPTestLoginSerializer, BaseSettingSerializer, + BasicSettingSerializer, EmailContentSettingSerializer, EmailSettingSerializer, + SecuritySettingSerializer, LdapSettingSerializer, TerminalSettingSerializer ) from users.models import User - logger = get_logger(__file__) @@ -59,7 +60,7 @@ class MailTestingAPI(APIView): use_tls=email_use_tls, use_ssl=email_use_ssl, ) send_mail( - subject, message, email_from, [email_recipient], + subject, message, email_from, [email_recipient], connection=connection ) except SMTPSenderRefused as e: @@ -275,3 +276,58 @@ class PublicSettingApi(generics.RetrieveAPIView): return instance +class BaseSettingApi(generics.RetrieveUpdateAPIView): + permission_classes = (IsSuperUser,) + serializer_class = BaseSettingSerializer + setting_fields = [] + + def get_object(self): + instance = {field: getattr(settings, field) for field in self.setting_fields} + return ObjectDict(instance) + + def perform_update(self, serializer): + serializer.save() + + +class BasicSettingApi(BaseSettingApi): + serializer_class = BasicSettingSerializer + setting_fields = ['SITE_URL', 'USER_GUIDE_URL', 'EMAIL_SUBJECT_PREFIX'] + + +class EmailSettingApi(BaseSettingApi): + serializer_class = EmailSettingSerializer + setting_fields = ['EMAIL_HOST', 'EMAIL_PORT', 'EMAIL_HOST_USER', + 'EMAIL_HOST_PASSWORD', 'EMAIL_FROM', 'EMAIL_RECIPIENT', + 'EMAIL_USE_SSL', 'EMAIL_USE_TLS'] + + +class EmailContentSettingApi(BaseSettingApi): + serializer_class = EmailContentSettingSerializer + setting_fields = ['EMAIL_CUSTOM_USER_CREATED_SUBJECT', 'EMAIL_CUSTOM_USER_CREATED_HONORIFIC', + 'EMAIL_CUSTOM_USER_CREATED_BODY', 'EMAIL_CUSTOM_USER_CREATED_SIGNATURE', ] + + +class LdapSettingApi(BaseSettingApi): + serializer_class = LdapSettingSerializer + setting_fields = ['AUTH_LDAP_SERVER_URI', 'AUTH_LDAP_BIND_DN', + 'AUTH_LDAP_BIND_PASSWORD', 'AUTH_LDAP_SEARCH_OU', + 'AUTH_LDAP_SEARCH_FILTER', 'AUTH_LDAP_USER_ATTR_MAP', + 'AUTH_LDAP'] + + +class TerminalSettingApi(BaseSettingApi): + serializer_class = TerminalSettingSerializer + setting_fields = ['TERMINAL_PASSWORD_AUTH', 'TERMINAL_PUBLIC_KEY_AUTH', + 'TERMINAL_HEARTBEAT_INTERVAL', 'TERMINAL_ASSET_LIST_SORT_BY', + 'TERMINAL_ASSET_LIST_PAGE_SIZE', 'TERMINAL_SESSION_KEEP_DURATION', + 'TERMINAL_TELNET_REGEX'] + + +class SecuritySettingApi(BaseSettingApi): + serializer_class = SecuritySettingSerializer + setting_fields = ['SECURITY_MFA_AUTH', 'SECURITY_COMMAND_EXECUTION', + 'SECURITY_SERVICE_ACCOUNT_REGISTRATION', 'SECURITY_LOGIN_LIMIT_COUNT', + 'SECURITY_LOGIN_LIMIT_TIME', 'SECURITY_MAX_IDLE_TIME', + 'SECURITY_PASSWORD_EXPIRATION_TIME', 'SECURITY_PASSWORD_MIN_LENGTH', + 'SECURITY_PASSWORD_UPPER_CASE', 'SECURITY_PASSWORD_LOWER_CASE', + 'SECURITY_PASSWORD_NUMBER', 'SECURITY_PASSWORD_SPECIAL_CHAR'] diff --git a/apps/settings/serializers/__init__.py b/apps/settings/serializers/__init__.py index 045763364..5868a76df 100644 --- a/apps/settings/serializers/__init__.py +++ b/apps/settings/serializers/__init__.py @@ -4,3 +4,4 @@ from .email import * from .ldap import * from .public import * +from .settings import * diff --git a/apps/settings/serializers/settings.py b/apps/settings/serializers/settings.py new file mode 100644 index 000000000..de22ba2eb --- /dev/null +++ b/apps/settings/serializers/settings.py @@ -0,0 +1,113 @@ +# coding: utf-8 + +from django.db import transaction +from django.utils.translation import ugettext_lazy as _ +from rest_framework import serializers +from ..models import Setting + +__all__ = ['BaseSettingSerializer', 'BasicSettingSerializer', 'EmailSettingSerializer', + "EmailContentSettingSerializer", 'LdapSettingSerializer', + 'TerminalSettingSerializer', 'SecuritySettingSerializer'] + + +class BaseSettingSerializer(serializers.Serializer): + encrypt_fields = ["EMAIL_HOST_PASSWORD", "AUTH_LDAP_BIND_PASSWORD"] + + def create(self, validated_data): + pass + + def update(self, instance, validated_data): + self.update_validated_settings(validated_data) + for field_name, field_value in validated_data.items(): + setattr(instance, field_name, field_value) + return instance + + def update_validated_settings(self, validated_data, category='default'): + with transaction.atomic(): + for field_name, field_value in validated_data.items(): + try: + setting = Setting.objects.get(name=field_name) + except Setting.DoesNotExist: + setting = Setting() + encrypted = True if field_name in self.encrypt_fields else False + setting.name = field_name + setting.category = category + setting.encrypted = encrypted + setting.cleaned_value = field_value + setting.save() + + +class BasicSettingSerializer(BaseSettingSerializer): + SITE_URL = serializers.URLField(required=True) + USER_GUIDE_URL = serializers.URLField(required=False) + EMAIL_SUBJECT_PREFIX = serializers.CharField(max_length=1024, required=True) + + +class EmailSettingSerializer(BaseSettingSerializer): + encrypt_fields = ["EMAIL_HOST_PASSWORD", ] + + EMAIL_HOST = serializers.CharField(max_length=1024, required=True) + EMAIL_PORT = serializers.CharField(max_length=5, required=True) + EMAIL_HOST_USER = serializers.CharField(max_length=128, required=True) + EMAIL_HOST_PASSWORD = serializers.CharField(max_length=1024, required=False, write_only=True) + EMAIL_FROM = serializers.CharField(max_length=128, required=False) + EMAIL_RECIPIENT = serializers.CharField(max_length=128, allow_blank='', required=False) + EMAIL_USE_SSL = serializers.BooleanField(required=False) + EMAIL_USE_TLS = serializers.BooleanField(required=False) + + +class EmailContentSettingSerializer(BaseSettingSerializer): + EMAIL_CUSTOM_USER_CREATED_SUBJECT = serializers.CharField(max_length=1024, required=False, ) + EMAIL_CUSTOM_USER_CREATED_HONORIFIC = serializers.CharField(max_length=1024, required=False, ) + EMAIL_CUSTOM_USER_CREATED_BODY = serializers.CharField(max_length=4096, required=False) + EMAIL_CUSTOM_USER_CREATED_SIGNATURE = serializers.CharField(max_length=512, required=False) + + +class LdapSettingSerializer(BaseSettingSerializer): + encrypt_fields = ["AUTH_LDAP_BIND_PASSWORD", ] + + AUTH_LDAP_SERVER_URI = serializers.CharField(required=True) + AUTH_LDAP_BIND_DN = serializers.CharField(required=False) + AUTH_LDAP_BIND_PASSWORD = serializers.CharField(max_length=1024, write_only=True) + AUTH_LDAP_SEARCH_OU = serializers.CharField(max_length=1024, required=False) + AUTH_LDAP_SEARCH_FILTER = serializers.CharField(max_length=1024, required=True) + AUTH_LDAP_USER_ATTR_MAP = serializers.CharField(max_length=1024, required=True) + AUTH_LDAP = serializers.BooleanField(required=False) + + +class TerminalSettingSerializer(BaseSettingSerializer): + SORT_BY_CHOICES = ( + ('hostname', _('Hostname')), + ('ip', _('IP')) + ) + + PAGE_SIZE_CHOICES = ( + ('all', _('All')), + ('auto', _('Auto')), + (10, 10), + (15, 15), + (25, 25), + (50, 50), + ) + TERMINAL_PASSWORD_AUTH = serializers.BooleanField(required=False) + TERMINAL_PUBLIC_KEY_AUTH = serializers.BooleanField(required=False) + TERMINAL_HEARTBEAT_INTERVAL = serializers.IntegerField(min_value=5, max_value=99999, required=True) + TERMINAL_ASSET_LIST_SORT_BY = serializers.ChoiceField(SORT_BY_CHOICES) + TERMINAL_ASSET_LIST_PAGE_SIZE = serializers.ChoiceField(PAGE_SIZE_CHOICES) + TERMINAL_SESSION_KEEP_DURATION = serializers.IntegerField(min_value=1, max_value=99999, required=True) + TERMINAL_TELNET_REGEX = serializers.CharField(required=False) + + +class SecuritySettingSerializer(BaseSettingSerializer): + SECURITY_MFA_AUTH = serializers.BooleanField(required=False) + SECURITY_COMMAND_EXECUTION = serializers.BooleanField(required=False) + SECURITY_SERVICE_ACCOUNT_REGISTRATION = serializers.BooleanField(required=True) + SECURITY_LOGIN_LIMIT_COUNT = serializers.IntegerField(min_value=3, max_value=99999, required=True) + SECURITY_LOGIN_LIMIT_TIME = serializers.IntegerField(min_value=5, max_value=99999, required=True) + SECURITY_MAX_IDLE_TIME = serializers.IntegerField(min_value=5, max_value=99999, required=False) + SECURITY_PASSWORD_EXPIRATION_TIME = serializers.IntegerField(min_value=1, max_value=99999, required=True) + SECURITY_PASSWORD_MIN_LENGTH = serializers.IntegerField(min_value=6, max_value=30, required=True) + SECURITY_PASSWORD_UPPER_CASE = serializers.BooleanField(required=False) + SECURITY_PASSWORD_LOWER_CASE = serializers.BooleanField(required=False) + SECURITY_PASSWORD_NUMBER = serializers.BooleanField(required=False) + SECURITY_PASSWORD_SPECIAL_CHAR = serializers.BooleanField(required=False) diff --git a/apps/settings/urls/api_urls.py b/apps/settings/urls/api_urls.py index 689e1ea82..093bc9c15 100644 --- a/apps/settings/urls/api_urls.py +++ b/apps/settings/urls/api_urls.py @@ -14,5 +14,11 @@ urlpatterns = [ path('ldap/users/import/', api.LDAPUserImportAPI.as_view(), name='ldap-user-import'), path('ldap/cache/refresh/', api.LDAPCacheRefreshAPI.as_view(), name='ldap-cache-refresh'), + path('basic/', api.BasicSettingApi.as_view(), name='basic-settings'), + path('email/', api.EmailSettingApi.as_view(), name='email-settings'), + path('email-content/', api.EmailContentSettingApi.as_view(), name='email-content-settings'), + path('ldap/', api.LdapSettingApi.as_view(), name='ldap-settings'), + path('terminal/', api.TerminalSettingApi.as_view(), name='terminal-settings'), + path('security/', api.SecuritySettingApi.as_view(), name='security-settings'), path('public/', api.PublicSettingApi.as_view(), name='public-setting'), ] diff --git a/apps/settings/utils/__init__.py b/apps/settings/utils/__init__.py index 87bc6198f..e17c4e43c 100644 --- a/apps/settings/utils/__init__.py +++ b/apps/settings/utils/__init__.py @@ -2,3 +2,4 @@ # from .ldap import * +from .common import * diff --git a/apps/settings/utils/common.py b/apps/settings/utils/common.py new file mode 100644 index 000000000..e64ceaf7f --- /dev/null +++ b/apps/settings/utils/common.py @@ -0,0 +1,18 @@ +# coding: utf-8 + + +class ObjectDict(dict): + def __getattr__(self, name): + if name in self: + return self[name] + else: + raise AttributeError("No such attribute: " + name) + + def __setattr__(self, name, value): + self[name] = value + + def __delattr__(self, name): + if name in self: + del self[name] + else: + raise AttributeError("No such attribute: " + name) From 2d18acf6f70cad9340d1dd2edb1123dfe4702802 Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 29 Apr 2020 17:04:48 +0800 Subject: [PATCH 2/3] [Update] settings api --- apps/settings/api.py | 100 ++++++++++++------------- apps/settings/serializers/settings.py | 101 ++++++++++++++------------ apps/settings/urls/api_urls.py | 7 +- 3 files changed, 107 insertions(+), 101 deletions(-) diff --git a/apps/settings/api.py b/apps/settings/api.py index 69f0129f8..f6021f3f2 100644 --- a/apps/settings/api.py +++ b/apps/settings/api.py @@ -2,7 +2,7 @@ # import json - +from collections.abc import Iterable from smtplib import SMTPSenderRefused from rest_framework import generics from rest_framework.views import Response, APIView @@ -19,9 +19,7 @@ from common.permissions import IsOrgAdmin, IsSuperUser from common.utils import get_logger from .serializers import ( MailTestSerializer, LDAPTestConfigSerializer, LDAPUserSerializer, - PublicSettingSerializer, LDAPTestLoginSerializer, BaseSettingSerializer, - BasicSettingSerializer, EmailContentSettingSerializer, EmailSettingSerializer, - SecuritySettingSerializer, LdapSettingSerializer, TerminalSettingSerializer + PublicSettingSerializer, LDAPTestLoginSerializer, SettingsSerializer ) from users.models import User @@ -276,58 +274,60 @@ class PublicSettingApi(generics.RetrieveAPIView): return instance -class BaseSettingApi(generics.RetrieveUpdateAPIView): - permission_classes = (IsSuperUser,) - serializer_class = BaseSettingSerializer - setting_fields = [] +class SettingsApi(generics.RetrieveUpdateAPIView): + serializer_class = SettingsSerializer + BASIC_CATEGORY = ['SITE_URL', 'USER_GUIDE_URL', 'EMAIL_SUBJECT_PREFIX'] + + EMAIL_CATEGORY = ['EMAIL_HOST', 'EMAIL_PORT', 'EMAIL_HOST_USER', + 'EMAIL_HOST_PASSWORD', 'EMAIL_FROM', 'EMAIL_RECIPIENT', + 'EMAIL_USE_SSL', 'EMAIL_USE_TLS'] + + EMAIL_CONTENT_CATEGORY = ['EMAIL_CUSTOM_USER_CREATED_SUBJECT', 'EMAIL_CUSTOM_USER_CREATED_HONORIFIC', + 'EMAIL_CUSTOM_USER_CREATED_BODY', 'EMAIL_CUSTOM_USER_CREATED_SIGNATURE', ] + + LDAP_CATEGORY = ['AUTH_LDAP_SERVER_URI', 'AUTH_LDAP_BIND_DN', + 'AUTH_LDAP_BIND_PASSWORD', 'AUTH_LDAP_SEARCH_OU', + 'AUTH_LDAP_SEARCH_FILTER', 'AUTH_LDAP_USER_ATTR_MAP', + 'AUTH_LDAP'] + + TERMINAL_CATEGORY = ['TERMINAL_PASSWORD_AUTH', 'TERMINAL_PUBLIC_KEY_AUTH', + 'TERMINAL_HEARTBEAT_INTERVAL', 'TERMINAL_ASSET_LIST_SORT_BY', + 'TERMINAL_ASSET_LIST_PAGE_SIZE', 'TERMINAL_SESSION_KEEP_DURATION', + 'TERMINAL_TELNET_REGEX'] + + SECURITY_CATEGORY = ['SECURITY_MFA_AUTH', 'SECURITY_COMMAND_EXECUTION', + 'SECURITY_SERVICE_ACCOUNT_REGISTRATION', 'SECURITY_LOGIN_LIMIT_COUNT', + 'SECURITY_LOGIN_LIMIT_TIME', 'SECURITY_MAX_IDLE_TIME', + 'SECURITY_PASSWORD_EXPIRATION_TIME', 'SECURITY_PASSWORD_MIN_LENGTH', + 'SECURITY_PASSWORD_UPPER_CASE', 'SECURITY_PASSWORD_LOWER_CASE', + 'SECURITY_PASSWORD_NUMBER', 'SECURITY_PASSWORD_SPECIAL_CHAR'] + + SETTING_CATEGORIES = { + "basic": BASIC_CATEGORY, + 'email': EMAIL_CATEGORY, + 'email_content': EMAIL_CONTENT_CATEGORY, + 'ldap': LDAP_CATEGORY, + 'terminal': TERMINAL_CATEGORY, + 'security': SECURITY_CATEGORY + } def get_object(self): - instance = {field: getattr(settings, field) for field in self.setting_fields} + instance = {category_name: self._get_setting_fields_obj(category_fields) + for category_name, category_fields in self.SETTING_CATEGORIES.items()} + return ObjectDict(instance) def perform_update(self, serializer): serializer.save() + def _get_setting_fields_obj(self, category_fields): + if isinstance(category_fields, Iterable): + fields_data = {field_name: getattr(settings, field_name) + for field_name in category_fields} + return ObjectDict(fields_data) -class BasicSettingApi(BaseSettingApi): - serializer_class = BasicSettingSerializer - setting_fields = ['SITE_URL', 'USER_GUIDE_URL', 'EMAIL_SUBJECT_PREFIX'] + if isinstance(category_fields, str): + fields_data = {category_fields: getattr(settings, category_fields)} + return ObjectDict(fields_data) - -class EmailSettingApi(BaseSettingApi): - serializer_class = EmailSettingSerializer - setting_fields = ['EMAIL_HOST', 'EMAIL_PORT', 'EMAIL_HOST_USER', - 'EMAIL_HOST_PASSWORD', 'EMAIL_FROM', 'EMAIL_RECIPIENT', - 'EMAIL_USE_SSL', 'EMAIL_USE_TLS'] - - -class EmailContentSettingApi(BaseSettingApi): - serializer_class = EmailContentSettingSerializer - setting_fields = ['EMAIL_CUSTOM_USER_CREATED_SUBJECT', 'EMAIL_CUSTOM_USER_CREATED_HONORIFIC', - 'EMAIL_CUSTOM_USER_CREATED_BODY', 'EMAIL_CUSTOM_USER_CREATED_SIGNATURE', ] - - -class LdapSettingApi(BaseSettingApi): - serializer_class = LdapSettingSerializer - setting_fields = ['AUTH_LDAP_SERVER_URI', 'AUTH_LDAP_BIND_DN', - 'AUTH_LDAP_BIND_PASSWORD', 'AUTH_LDAP_SEARCH_OU', - 'AUTH_LDAP_SEARCH_FILTER', 'AUTH_LDAP_USER_ATTR_MAP', - 'AUTH_LDAP'] - - -class TerminalSettingApi(BaseSettingApi): - serializer_class = TerminalSettingSerializer - setting_fields = ['TERMINAL_PASSWORD_AUTH', 'TERMINAL_PUBLIC_KEY_AUTH', - 'TERMINAL_HEARTBEAT_INTERVAL', 'TERMINAL_ASSET_LIST_SORT_BY', - 'TERMINAL_ASSET_LIST_PAGE_SIZE', 'TERMINAL_SESSION_KEEP_DURATION', - 'TERMINAL_TELNET_REGEX'] - - -class SecuritySettingApi(BaseSettingApi): - serializer_class = SecuritySettingSerializer - setting_fields = ['SECURITY_MFA_AUTH', 'SECURITY_COMMAND_EXECUTION', - 'SECURITY_SERVICE_ACCOUNT_REGISTRATION', 'SECURITY_LOGIN_LIMIT_COUNT', - 'SECURITY_LOGIN_LIMIT_TIME', 'SECURITY_MAX_IDLE_TIME', - 'SECURITY_PASSWORD_EXPIRATION_TIME', 'SECURITY_PASSWORD_MIN_LENGTH', - 'SECURITY_PASSWORD_UPPER_CASE', 'SECURITY_PASSWORD_LOWER_CASE', - 'SECURITY_PASSWORD_NUMBER', 'SECURITY_PASSWORD_SPECIAL_CHAR'] + return ObjectDict() diff --git a/apps/settings/serializers/settings.py b/apps/settings/serializers/settings.py index de22ba2eb..d8dc8d708 100644 --- a/apps/settings/serializers/settings.py +++ b/apps/settings/serializers/settings.py @@ -5,77 +5,48 @@ from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers from ..models import Setting -__all__ = ['BaseSettingSerializer', 'BasicSettingSerializer', 'EmailSettingSerializer', - "EmailContentSettingSerializer", 'LdapSettingSerializer', - 'TerminalSettingSerializer', 'SecuritySettingSerializer'] +__all__ = ['SettingsSerializer'] -class BaseSettingSerializer(serializers.Serializer): - encrypt_fields = ["EMAIL_HOST_PASSWORD", "AUTH_LDAP_BIND_PASSWORD"] - - def create(self, validated_data): - pass - - def update(self, instance, validated_data): - self.update_validated_settings(validated_data) - for field_name, field_value in validated_data.items(): - setattr(instance, field_name, field_value) - return instance - - def update_validated_settings(self, validated_data, category='default'): - with transaction.atomic(): - for field_name, field_value in validated_data.items(): - try: - setting = Setting.objects.get(name=field_name) - except Setting.DoesNotExist: - setting = Setting() - encrypted = True if field_name in self.encrypt_fields else False - setting.name = field_name - setting.category = category - setting.encrypted = encrypted - setting.cleaned_value = field_value - setting.save() - - -class BasicSettingSerializer(BaseSettingSerializer): +class BasicSettingSerializer(serializers.Serializer): SITE_URL = serializers.URLField(required=True) - USER_GUIDE_URL = serializers.URLField(required=False) + USER_GUIDE_URL = serializers.URLField(required=False, allow_blank=True, ) EMAIL_SUBJECT_PREFIX = serializers.CharField(max_length=1024, required=True) -class EmailSettingSerializer(BaseSettingSerializer): +class EmailSettingSerializer(serializers.Serializer): encrypt_fields = ["EMAIL_HOST_PASSWORD", ] EMAIL_HOST = serializers.CharField(max_length=1024, required=True) EMAIL_PORT = serializers.CharField(max_length=5, required=True) EMAIL_HOST_USER = serializers.CharField(max_length=128, required=True) EMAIL_HOST_PASSWORD = serializers.CharField(max_length=1024, required=False, write_only=True) - EMAIL_FROM = serializers.CharField(max_length=128, required=False) - EMAIL_RECIPIENT = serializers.CharField(max_length=128, allow_blank='', required=False) + EMAIL_FROM = serializers.CharField(max_length=128, allow_blank=True, required=False) + EMAIL_RECIPIENT = serializers.CharField(max_length=128, allow_blank=True, required=False) EMAIL_USE_SSL = serializers.BooleanField(required=False) EMAIL_USE_TLS = serializers.BooleanField(required=False) -class EmailContentSettingSerializer(BaseSettingSerializer): - EMAIL_CUSTOM_USER_CREATED_SUBJECT = serializers.CharField(max_length=1024, required=False, ) - EMAIL_CUSTOM_USER_CREATED_HONORIFIC = serializers.CharField(max_length=1024, required=False, ) - EMAIL_CUSTOM_USER_CREATED_BODY = serializers.CharField(max_length=4096, required=False) - EMAIL_CUSTOM_USER_CREATED_SIGNATURE = serializers.CharField(max_length=512, required=False) +class EmailContentSettingSerializer(serializers.Serializer): + EMAIL_CUSTOM_USER_CREATED_SUBJECT = serializers.CharField(max_length=1024, allow_blank=True, required=False, ) + EMAIL_CUSTOM_USER_CREATED_HONORIFIC = serializers.CharField(max_length=1024, allow_blank=True, required=False, ) + EMAIL_CUSTOM_USER_CREATED_BODY = serializers.CharField(max_length=4096, allow_blank=True, required=False) + EMAIL_CUSTOM_USER_CREATED_SIGNATURE = serializers.CharField(max_length=512, allow_blank=True, required=False) -class LdapSettingSerializer(BaseSettingSerializer): +class LdapSettingSerializer(serializers.Serializer): encrypt_fields = ["AUTH_LDAP_BIND_PASSWORD", ] AUTH_LDAP_SERVER_URI = serializers.CharField(required=True) AUTH_LDAP_BIND_DN = serializers.CharField(required=False) AUTH_LDAP_BIND_PASSWORD = serializers.CharField(max_length=1024, write_only=True) - AUTH_LDAP_SEARCH_OU = serializers.CharField(max_length=1024, required=False) + AUTH_LDAP_SEARCH_OU = serializers.CharField(max_length=1024, allow_blank=True, required=False) AUTH_LDAP_SEARCH_FILTER = serializers.CharField(max_length=1024, required=True) AUTH_LDAP_USER_ATTR_MAP = serializers.CharField(max_length=1024, required=True) AUTH_LDAP = serializers.BooleanField(required=False) -class TerminalSettingSerializer(BaseSettingSerializer): +class TerminalSettingSerializer(serializers.Serializer): SORT_BY_CHOICES = ( ('hostname', _('Hostname')), ('ip', _('IP')) @@ -95,10 +66,10 @@ class TerminalSettingSerializer(BaseSettingSerializer): TERMINAL_ASSET_LIST_SORT_BY = serializers.ChoiceField(SORT_BY_CHOICES) TERMINAL_ASSET_LIST_PAGE_SIZE = serializers.ChoiceField(PAGE_SIZE_CHOICES) TERMINAL_SESSION_KEEP_DURATION = serializers.IntegerField(min_value=1, max_value=99999, required=True) - TERMINAL_TELNET_REGEX = serializers.CharField(required=False) + TERMINAL_TELNET_REGEX = serializers.CharField(required=False, allow_blank=True) -class SecuritySettingSerializer(BaseSettingSerializer): +class SecuritySettingSerializer(serializers.Serializer): SECURITY_MFA_AUTH = serializers.BooleanField(required=False) SECURITY_COMMAND_EXECUTION = serializers.BooleanField(required=False) SECURITY_SERVICE_ACCOUNT_REGISTRATION = serializers.BooleanField(required=True) @@ -111,3 +82,43 @@ class SecuritySettingSerializer(BaseSettingSerializer): SECURITY_PASSWORD_LOWER_CASE = serializers.BooleanField(required=False) SECURITY_PASSWORD_NUMBER = serializers.BooleanField(required=False) SECURITY_PASSWORD_SPECIAL_CHAR = serializers.BooleanField(required=False) + + +class SettingsSerializer(serializers.Serializer): + basic = BasicSettingSerializer(required=False) + email = EmailSettingSerializer(required=False) + email_content = EmailContentSettingSerializer(required=False) + ldap = LdapSettingSerializer(required=False) + terminal = TerminalSettingSerializer(required=False) + security = SecuritySettingSerializer(required=False) + + encrypt_fields = ["EMAIL_HOST_PASSWORD", "AUTH_LDAP_BIND_PASSWORD"] + + def create(self, validated_data): + pass + + def update(self, instance, validated_data): + for category, category_data in validated_data.items(): + if not category_data: + continue + self.update_validated_settings(category_data) + for field_name, field_value in category_data.items(): + setattr(getattr(instance, category), field_name, field_value) + + return instance + + def update_validated_settings(self, validated_data, category='default'): + if not validated_data: + return + with transaction.atomic(): + for field_name, field_value in validated_data.items(): + try: + setting = Setting.objects.get(name=field_name) + except Setting.DoesNotExist: + setting = Setting() + encrypted = True if field_name in self.encrypt_fields else False + setting.name = field_name + setting.category = category + setting.encrypted = encrypted + setting.cleaned_value = field_value + setting.save() diff --git a/apps/settings/urls/api_urls.py b/apps/settings/urls/api_urls.py index 093bc9c15..0db9c7c54 100644 --- a/apps/settings/urls/api_urls.py +++ b/apps/settings/urls/api_urls.py @@ -14,11 +14,6 @@ urlpatterns = [ path('ldap/users/import/', api.LDAPUserImportAPI.as_view(), name='ldap-user-import'), path('ldap/cache/refresh/', api.LDAPCacheRefreshAPI.as_view(), name='ldap-cache-refresh'), - path('basic/', api.BasicSettingApi.as_view(), name='basic-settings'), - path('email/', api.EmailSettingApi.as_view(), name='email-settings'), - path('email-content/', api.EmailContentSettingApi.as_view(), name='email-content-settings'), - path('ldap/', api.LdapSettingApi.as_view(), name='ldap-settings'), - path('terminal/', api.TerminalSettingApi.as_view(), name='terminal-settings'), - path('security/', api.SecuritySettingApi.as_view(), name='security-settings'), + path('setting/', api.SettingsApi.as_view(), name='settings-setting'), path('public/', api.PublicSettingApi.as_view(), name='public-setting'), ] From 79eb838250a3cfcf5c20dfc6f9cfc2bab7e2dc3b Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 29 Apr 2020 18:10:42 +0800 Subject: [PATCH 3/3] [Update] setting fields automatically generated by serializer --- apps/settings/api.py | 41 +++------------------------ apps/settings/serializers/settings.py | 10 +++---- 2 files changed, 9 insertions(+), 42 deletions(-) diff --git a/apps/settings/api.py b/apps/settings/api.py index f6021f3f2..b8ceaac06 100644 --- a/apps/settings/api.py +++ b/apps/settings/api.py @@ -9,6 +9,7 @@ from rest_framework.views import Response, APIView from django.conf import settings from django.core.mail import send_mail, get_connection from django.utils.translation import ugettext_lazy as _ +from rest_framework import serializers from .utils import ( LDAPServerUtil, LDAPCacheUtil, LDAPImportUtil, LDAPSyncUtil, @@ -276,45 +277,11 @@ class PublicSettingApi(generics.RetrieveAPIView): class SettingsApi(generics.RetrieveUpdateAPIView): serializer_class = SettingsSerializer - BASIC_CATEGORY = ['SITE_URL', 'USER_GUIDE_URL', 'EMAIL_SUBJECT_PREFIX'] - - EMAIL_CATEGORY = ['EMAIL_HOST', 'EMAIL_PORT', 'EMAIL_HOST_USER', - 'EMAIL_HOST_PASSWORD', 'EMAIL_FROM', 'EMAIL_RECIPIENT', - 'EMAIL_USE_SSL', 'EMAIL_USE_TLS'] - - EMAIL_CONTENT_CATEGORY = ['EMAIL_CUSTOM_USER_CREATED_SUBJECT', 'EMAIL_CUSTOM_USER_CREATED_HONORIFIC', - 'EMAIL_CUSTOM_USER_CREATED_BODY', 'EMAIL_CUSTOM_USER_CREATED_SIGNATURE', ] - - LDAP_CATEGORY = ['AUTH_LDAP_SERVER_URI', 'AUTH_LDAP_BIND_DN', - 'AUTH_LDAP_BIND_PASSWORD', 'AUTH_LDAP_SEARCH_OU', - 'AUTH_LDAP_SEARCH_FILTER', 'AUTH_LDAP_USER_ATTR_MAP', - 'AUTH_LDAP'] - - TERMINAL_CATEGORY = ['TERMINAL_PASSWORD_AUTH', 'TERMINAL_PUBLIC_KEY_AUTH', - 'TERMINAL_HEARTBEAT_INTERVAL', 'TERMINAL_ASSET_LIST_SORT_BY', - 'TERMINAL_ASSET_LIST_PAGE_SIZE', 'TERMINAL_SESSION_KEEP_DURATION', - 'TERMINAL_TELNET_REGEX'] - - SECURITY_CATEGORY = ['SECURITY_MFA_AUTH', 'SECURITY_COMMAND_EXECUTION', - 'SECURITY_SERVICE_ACCOUNT_REGISTRATION', 'SECURITY_LOGIN_LIMIT_COUNT', - 'SECURITY_LOGIN_LIMIT_TIME', 'SECURITY_MAX_IDLE_TIME', - 'SECURITY_PASSWORD_EXPIRATION_TIME', 'SECURITY_PASSWORD_MIN_LENGTH', - 'SECURITY_PASSWORD_UPPER_CASE', 'SECURITY_PASSWORD_LOWER_CASE', - 'SECURITY_PASSWORD_NUMBER', 'SECURITY_PASSWORD_SPECIAL_CHAR'] - - SETTING_CATEGORIES = { - "basic": BASIC_CATEGORY, - 'email': EMAIL_CATEGORY, - 'email_content': EMAIL_CONTENT_CATEGORY, - 'ldap': LDAP_CATEGORY, - 'terminal': TERMINAL_CATEGORY, - 'security': SECURITY_CATEGORY - } def get_object(self): - instance = {category_name: self._get_setting_fields_obj(category_fields) - for category_name, category_fields in self.SETTING_CATEGORIES.items()} - + instance = {category: self._get_setting_fields_obj(list(category_serializer.get_fields())) + for category, category_serializer in self.serializer_class().get_fields().items() + if isinstance(category_serializer, serializers.Serializer)} return ObjectDict(instance) def perform_update(self, serializer): diff --git a/apps/settings/serializers/settings.py b/apps/settings/serializers/settings.py index d8dc8d708..2e2fb2f6b 100644 --- a/apps/settings/serializers/settings.py +++ b/apps/settings/serializers/settings.py @@ -20,7 +20,7 @@ class EmailSettingSerializer(serializers.Serializer): EMAIL_HOST = serializers.CharField(max_length=1024, required=True) EMAIL_PORT = serializers.CharField(max_length=5, required=True) EMAIL_HOST_USER = serializers.CharField(max_length=128, required=True) - EMAIL_HOST_PASSWORD = serializers.CharField(max_length=1024, required=False, write_only=True) + EMAIL_HOST_PASSWORD = serializers.CharField(max_length=1024, write_only=True, required=False, ) EMAIL_FROM = serializers.CharField(max_length=128, allow_blank=True, required=False) EMAIL_RECIPIENT = serializers.CharField(max_length=128, allow_blank=True, required=False) EMAIL_USE_SSL = serializers.BooleanField(required=False) @@ -39,7 +39,7 @@ class LdapSettingSerializer(serializers.Serializer): AUTH_LDAP_SERVER_URI = serializers.CharField(required=True) AUTH_LDAP_BIND_DN = serializers.CharField(required=False) - AUTH_LDAP_BIND_PASSWORD = serializers.CharField(max_length=1024, write_only=True) + AUTH_LDAP_BIND_PASSWORD = serializers.CharField(max_length=1024, write_only=True, required=False) AUTH_LDAP_SEARCH_OU = serializers.CharField(max_length=1024, allow_blank=True, required=False) AUTH_LDAP_SEARCH_FILTER = serializers.CharField(max_length=1024, required=True) AUTH_LDAP_USER_ATTR_MAP = serializers.CharField(max_length=1024, required=True) @@ -63,10 +63,10 @@ class TerminalSettingSerializer(serializers.Serializer): TERMINAL_PASSWORD_AUTH = serializers.BooleanField(required=False) TERMINAL_PUBLIC_KEY_AUTH = serializers.BooleanField(required=False) TERMINAL_HEARTBEAT_INTERVAL = serializers.IntegerField(min_value=5, max_value=99999, required=True) - TERMINAL_ASSET_LIST_SORT_BY = serializers.ChoiceField(SORT_BY_CHOICES) - TERMINAL_ASSET_LIST_PAGE_SIZE = serializers.ChoiceField(PAGE_SIZE_CHOICES) + TERMINAL_ASSET_LIST_SORT_BY = serializers.ChoiceField(SORT_BY_CHOICES, required=False) + TERMINAL_ASSET_LIST_PAGE_SIZE = serializers.ChoiceField(PAGE_SIZE_CHOICES, required=False) TERMINAL_SESSION_KEEP_DURATION = serializers.IntegerField(min_value=1, max_value=99999, required=True) - TERMINAL_TELNET_REGEX = serializers.CharField(required=False, allow_blank=True) + TERMINAL_TELNET_REGEX = serializers.CharField(allow_blank=True, required=False) class SecuritySettingSerializer(serializers.Serializer):