mirror of https://github.com/jumpserver/jumpserver
Merge branch 'dev' into pr@dev@revert_dockerfile
commit
479378aa46
|
@ -43,7 +43,7 @@ class BaseVault(ABC):
|
|||
'name', 'username', 'secret_type',
|
||||
'connectivity', 'su_from', 'privileged'
|
||||
])
|
||||
metadata = {field: str(value) for field, value in metadata.items()}
|
||||
metadata = {k: str(v)[:500] for k, v in metadata.items() if v}
|
||||
return self._save_metadata(instance, metadata)
|
||||
|
||||
# -------- abstractmethod -------- #
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
from common.db.utils import get_logger
|
||||
from .entries import build_entry
|
||||
from .service import VaultKVClient
|
||||
from ..base import BaseVault
|
||||
|
||||
__all__ = ['Vault']
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class Vault(BaseVault):
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -43,5 +46,8 @@ class Vault(BaseVault):
|
|||
instance.mark_secret_save_to_vault()
|
||||
|
||||
def _save_metadata(self, instance, metadata):
|
||||
entry = build_entry(instance)
|
||||
self.client.update_metadata(path=entry.full_path, metadata=metadata)
|
||||
try:
|
||||
entry = build_entry(instance)
|
||||
self.client.update_metadata(path=entry.full_path, metadata=metadata)
|
||||
except Exception as e:
|
||||
logger.error(f'save metadata error: {e}')
|
||||
|
|
|
@ -59,7 +59,6 @@ class VaultKVClient(object):
|
|||
mount_point=self.mount_point
|
||||
)
|
||||
except exceptions.InvalidPath as e:
|
||||
logger.error('Get secret error: {}'.format(e))
|
||||
return {}
|
||||
data = response.get('data', {})
|
||||
return data
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
# Generated by Django 4.1.10 on 2023-08-03 08:28
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
import common.db.encoder
|
||||
|
||||
|
||||
def migrate_recipients(apps, schema_editor):
|
||||
account_backup_model = apps.get_model('accounts', 'AccountBackupAutomation')
|
||||
|
@ -13,13 +14,22 @@ def migrate_recipients(apps, schema_editor):
|
|||
continue
|
||||
account_backup.recipients_part_one.set(recipients)
|
||||
|
||||
execution_bojs = []
|
||||
objs = []
|
||||
for execution in execution_model.objects.all():
|
||||
snapshot = execution.snapshot
|
||||
recipients = snapshot.pop('recipients', {})
|
||||
snapshot.update({'recipients_part_one': recipients, 'recipients_part_two': {}})
|
||||
execution_bojs.append(execution)
|
||||
execution_model.objects.bulk_update(execution_bojs, ['snapshot'])
|
||||
objs.append(execution)
|
||||
execution_model.objects.bulk_update(objs, ['snapshot'])
|
||||
|
||||
|
||||
def migrate_snapshot(apps, schema_editor):
|
||||
model = apps.get_model('accounts', 'AccountBackupExecution')
|
||||
objs = []
|
||||
for execution in model.objects.all():
|
||||
execution.snapshot = execution.plan_snapshot
|
||||
objs.append(execution)
|
||||
model.objects.bulk_update(objs, ['snapshot'])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
@ -45,12 +55,20 @@ class Migration(migrations.Migration):
|
|||
to=settings.AUTH_USER_MODEL, verbose_name='Recipient part two'
|
||||
),
|
||||
),
|
||||
migrations.RenameField(
|
||||
migrations.AddField(
|
||||
model_name='accountbackupexecution',
|
||||
old_name='plan_snapshot',
|
||||
new_name='snapshot',
|
||||
name='snapshot',
|
||||
field=models.JSONField(
|
||||
default=dict, encoder=common.db.encoder.ModelJSONFieldEncoder,
|
||||
null=True, blank=True, verbose_name='Account backup snapshot'
|
||||
),
|
||||
),
|
||||
migrations.RunPython(migrate_snapshot),
|
||||
migrations.RunPython(migrate_recipients),
|
||||
migrations.RemoveField(
|
||||
model_name='accountbackupexecution',
|
||||
name='plan_snapshot',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='accountbackupautomation',
|
||||
name='recipients',
|
||||
|
|
|
@ -86,7 +86,7 @@ class ChangeSecretRecord(JMSBaseModel):
|
|||
asset = models.ForeignKey('assets.Asset', on_delete=models.CASCADE, null=True)
|
||||
account = models.ForeignKey('accounts.Account', on_delete=models.CASCADE, null=True)
|
||||
old_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Old secret'))
|
||||
new_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('Secret'))
|
||||
new_secret = fields.EncryptTextField(blank=True, null=True, verbose_name=_('New secret'))
|
||||
date_started = models.DateTimeField(blank=True, null=True, verbose_name=_('Date started'))
|
||||
date_finished = models.DateTimeField(blank=True, null=True, verbose_name=_('Date finished'))
|
||||
status = models.CharField(max_length=16, default='pending')
|
||||
|
|
|
@ -52,17 +52,18 @@ class VaultModelMixin(models.Model):
|
|||
abstract = True
|
||||
|
||||
# 缓存 secret 值, lazy-property 不能用
|
||||
__secret = False
|
||||
__secret = None
|
||||
|
||||
@property
|
||||
def secret(self):
|
||||
if self.__secret is False:
|
||||
from accounts.backends import vault_client
|
||||
secret = vault_client.get(self)
|
||||
if not secret and not self.secret_has_save_to_vault:
|
||||
# vault_client 获取不到, 并且 secret 没有保存到 vault, 就从 self._secret 获取
|
||||
secret = self._secret
|
||||
self.__secret = secret
|
||||
if self.__secret:
|
||||
return self.__secret
|
||||
from accounts.backends import vault_client
|
||||
secret = vault_client.get(self)
|
||||
if not secret and not self.secret_has_save_to_vault:
|
||||
# vault_client 获取不到, 并且 secret 没有保存到 vault, 就从 self._secret 获取
|
||||
secret = self._secret
|
||||
self.__secret = secret
|
||||
return self.__secret
|
||||
|
||||
@secret.setter
|
||||
|
@ -72,6 +73,7 @@ class VaultModelMixin(models.Model):
|
|||
先保存到 db, 再保存到 vault 同时删除本地 db _secret 值
|
||||
"""
|
||||
self._secret = value
|
||||
self.__secret = value
|
||||
|
||||
_secret_save_to_vault_mark = '# Secret-has-been-saved-to-vault #'
|
||||
|
||||
|
|
|
@ -95,6 +95,8 @@ class AccountCreateUpdateSerializerMixin(serializers.Serializer):
|
|||
field.name for field in template._meta.fields
|
||||
if field.name not in ignore_fields
|
||||
]
|
||||
field_names = [name if name != '_secret' else 'secret' for name in field_names]
|
||||
|
||||
attrs = {}
|
||||
for name in field_names:
|
||||
value = getattr(template, name, None)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import datetime
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from datetime import datetime
|
||||
|
||||
from celery import shared_task
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
@ -12,6 +13,22 @@ from ..const import VaultTypeChoices
|
|||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def sync_instance(instance):
|
||||
instance_desc = f'[{instance._meta.verbose_name}-{instance.id}-{instance}]'
|
||||
if instance.secret_has_save_to_vault:
|
||||
msg = f'\033[32m- 跳过同步: {instance_desc}, 原因: [已同步]'
|
||||
return "skipped", msg
|
||||
|
||||
try:
|
||||
vault_client.create(instance)
|
||||
except Exception as e:
|
||||
msg = f'\033[31m- 同步失败: {instance_desc}, 原因: [{e}]'
|
||||
return "failed", msg
|
||||
else:
|
||||
msg = f'\033[32m- 同步成功: {instance_desc}'
|
||||
return "succeeded", msg
|
||||
|
||||
|
||||
@shared_task(verbose_name=_('Sync secret to vault'))
|
||||
def sync_secret_to_vault():
|
||||
if vault_client.is_type(VaultTypeChoices.local):
|
||||
|
@ -19,38 +36,34 @@ def sync_secret_to_vault():
|
|||
print('\033[35m>>> 当前 Vault 类型为本地数据库, 不需要同步')
|
||||
return
|
||||
|
||||
print('\033[33m>>> 开始同步密钥数据到 Vault ({})'.format(datetime.datetime.now()))
|
||||
failed, skipped, succeeded = 0, 0, 0
|
||||
to_sync_models = [Account, AccountTemplate, Account.history.model]
|
||||
print(f'\033[33m>>> 开始同步密钥数据到 Vault ({datetime.now().strftime("%Y-%m-%d %H:%M:%S")})')
|
||||
with tmp_to_root_org():
|
||||
to_sync_models = [Account, AccountTemplate, Account.history.model]
|
||||
instances = []
|
||||
for model in to_sync_models:
|
||||
print(f'\033[33m>>> 开始同步: {model.__module__}')
|
||||
succeeded = []
|
||||
failed = []
|
||||
skipped = []
|
||||
instances = model.objects.all()
|
||||
for instance in instances:
|
||||
instance_desc = f'[{instance}]'
|
||||
if instance.secret_has_save_to_vault:
|
||||
print(f'\033[32m- 跳过同步: {instance_desc}, 原因: [已同步]')
|
||||
skipped.append(instance)
|
||||
continue
|
||||
try:
|
||||
vault_client.create(instance)
|
||||
except Exception as e:
|
||||
failed.append(instance)
|
||||
print(f'\033[31m- 同步失败: {instance_desc}, 原因: [{e}]')
|
||||
else:
|
||||
succeeded.append(instance)
|
||||
print(f'\033[32m- 同步成功: {instance_desc}')
|
||||
instances += list(model.objects.all())
|
||||
|
||||
total = len(succeeded) + len(failed) + len(skipped)
|
||||
print(
|
||||
f'\033[33m>>> 同步完成: {model.__module__}, '
|
||||
f'共计: {total}, '
|
||||
f'成功: {len(succeeded)}, '
|
||||
f'失败: {len(failed)}, '
|
||||
f'跳过: {len(skipped)}'
|
||||
)
|
||||
with ThreadPoolExecutor(max_workers=10) as executor:
|
||||
tasks = [executor.submit(sync_instance, instance) for instance in instances]
|
||||
|
||||
print('\033[33m>>> 全部同步完成 ({})'.format(datetime.datetime.now()))
|
||||
for future in as_completed(tasks):
|
||||
status, msg = future.result()
|
||||
print(msg)
|
||||
if status == "succeeded":
|
||||
succeeded += 1
|
||||
elif status == "failed":
|
||||
failed += 1
|
||||
elif status == "skipped":
|
||||
skipped += 1
|
||||
|
||||
total = succeeded + failed + skipped
|
||||
print(
|
||||
f'\033[33m>>> 同步完成: {model.__module__}, '
|
||||
f'共计: {total}, '
|
||||
f'成功: {succeeded}, '
|
||||
f'失败: {failed}, '
|
||||
f'跳过: {skipped}'
|
||||
)
|
||||
print(f'\033[33m>>> 全部同步完成 ({datetime.now().strftime("%Y-%m-%d %H:%M:%S")})')
|
||||
print('\033[0m')
|
||||
|
|
|
@ -224,7 +224,7 @@ class AllTypes(ChoicesMixin):
|
|||
return dict(id='ROOT', name=_('All types'), title=_('All types'), open=True, isParent=True)
|
||||
|
||||
@classmethod
|
||||
def get_tree_nodes(cls, resource_platforms, include_asset=False):
|
||||
def get_tree_nodes(cls, resource_platforms, include_asset=False, get_root=True):
|
||||
from ..models import Platform
|
||||
platform_count = defaultdict(int)
|
||||
for platform_id in resource_platforms:
|
||||
|
@ -239,10 +239,10 @@ class AllTypes(ChoicesMixin):
|
|||
category_type_mapper[p.category] += platform_count[p.id]
|
||||
tp_platforms[p.category + '_' + p.type].append(p)
|
||||
|
||||
nodes = [cls.get_root_nodes()]
|
||||
nodes = [cls.get_root_nodes()] if get_root else []
|
||||
for category, type_cls in cls.category_types():
|
||||
# Category 格式化
|
||||
meta = {'type': 'category', 'category': category.value}
|
||||
meta = {'type': 'category', 'category': category.value, '_type': category.value}
|
||||
category_node = cls.choice_to_node(category, 'ROOT', meta=meta)
|
||||
category_count = category_type_mapper.get(category, 0)
|
||||
category_node['name'] += f'({category_count})'
|
||||
|
|
|
@ -52,7 +52,11 @@ class UserResetPasswordSendCodeApi(CreateAPIView):
|
|||
other_args = {}
|
||||
|
||||
target = serializer.validated_data[form_type]
|
||||
query_key = 'phone' if form_type == 'sms' else form_type
|
||||
if form_type == 'sms':
|
||||
query_key = 'phone'
|
||||
target = target.lstrip('+')
|
||||
else:
|
||||
query_key = form_type
|
||||
user, err = self.is_valid_user(username=username, **{query_key: target})
|
||||
if not user:
|
||||
return Response({'error': err}, status=400)
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
import time
|
||||
|
||||
import requests
|
||||
import requests.exceptions
|
||||
|
||||
from django.core.exceptions import MiddlewareNotUsed
|
||||
from django.conf import settings
|
||||
from django.contrib import auth
|
||||
from django.core.exceptions import MiddlewareNotUsed
|
||||
|
||||
from common.utils import get_logger
|
||||
|
||||
from .utils import validate_and_return_id_token
|
||||
from .decorator import ssl_verification
|
||||
|
||||
from .utils import validate_and_return_id_token
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
||||
|
@ -25,11 +24,16 @@ class OIDCRefreshIDTokenMiddleware:
|
|||
|
||||
def __call__(self, request):
|
||||
# Refreshes tokens only in the applicable cases.
|
||||
if request.method == 'GET' and not request.is_ajax() and request.user.is_authenticated and settings.AUTH_OPENID:
|
||||
if request.method == 'GET' and not self.is_ajax(request) and \
|
||||
request.user.is_authenticated and settings.AUTH_OPENID:
|
||||
self.refresh_token(request)
|
||||
response = self.get_response(request)
|
||||
return response
|
||||
|
||||
@staticmethod
|
||||
def is_ajax(request):
|
||||
return request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
|
||||
|
||||
@ssl_verification
|
||||
def refresh_token(self, request):
|
||||
""" Refreshes the token of the current user. """
|
||||
|
|
|
@ -191,7 +191,7 @@ class ConnectionToken(JMSOrgBaseModel):
|
|||
raise JMSException({'error': 'No host account available'})
|
||||
|
||||
host, account, lock_key, ttl = bulk_get(host_account, ('host', 'account', 'lock_key', 'ttl'))
|
||||
gateway = host.gateway.select_gateway() if host.domain else None
|
||||
gateway = host.domain.select_gateway() if host.domain else None
|
||||
|
||||
data = {
|
||||
'id': account.id,
|
||||
|
|
|
@ -116,9 +116,13 @@ class FeiShu(RequestMixin):
|
|||
'receive_id_type': 'user_id'
|
||||
}
|
||||
|
||||
"""
|
||||
https://open.feishu.cn/document/common-capabilities/message-card/message-cards-content
|
||||
/using-markdown-tags
|
||||
"""
|
||||
body = {
|
||||
'msg_type': 'text',
|
||||
'content': json.dumps({'text': msg})
|
||||
'msg_type': 'interactive',
|
||||
'content': json.dumps({'elements': [{'tag': 'markdown', 'content': msg}]})
|
||||
}
|
||||
|
||||
invalid_users = []
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7bc2e996c082d5f9348277e69cd70b7b9884dc416d9d83e075656a4d8b9bc141
|
||||
size 152939
|
||||
oid sha256:810d46e14e09a2309a8d898bc391f33082bfc5c164dec246bd95cea8436e33ee
|
||||
size 154540
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d1a6a042b4813d67922799caf3ac81ce3f1e831aed1a771dc9a16dab147a0692
|
||||
size 125568
|
||||
oid sha256:da4f312ed86d27fa8b6bde8da3bc70b0f32fe40811ee855f9fe81d89a68a646f
|
||||
size 126402
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -177,8 +177,10 @@ class UserPermedNodeChildrenWithAssetsAsCategoryTreeApi(
|
|||
return []
|
||||
pid = f'ROOT_{str(assets[0].category).upper()}_{tp}'
|
||||
return self.serialize_assets(assets, pid=pid)
|
||||
params = self.request.query_params
|
||||
get_root = not list(filter(lambda x: params.get(x), ('type', 'n')))
|
||||
resource_platforms = assets.order_by('id').values_list('platform_id', flat=True)
|
||||
node_all = AllTypes.get_tree_nodes(resource_platforms)
|
||||
node_all = AllTypes.get_tree_nodes(resource_platforms, get_root=get_root)
|
||||
pattern = re.compile(r'\(0\)?')
|
||||
nodes = []
|
||||
for node in node_all:
|
||||
|
|
|
@ -144,7 +144,9 @@ only_system_permissions = (
|
|||
('terminal', 'task', '*', '*'),
|
||||
('terminal', 'endpoint', '*', '*'),
|
||||
('terminal', 'endpointrule', '*', '*'),
|
||||
('authentication', '*', '*', '*'),
|
||||
('authentication', 'accesskey', '*', '*'),
|
||||
('authentication', 'superconnectiontoken', '*', '*'),
|
||||
('authentication', 'temptoken', '*', '*'),
|
||||
('tickets', '*', '*', '*'),
|
||||
('orgs', 'organization', 'view', 'rootorg'),
|
||||
('terminal', 'applet', '*', '*'),
|
||||
|
|
|
@ -70,6 +70,9 @@ special_pid_mapper = {
|
|||
'xpack.syncinstancedetail': 'cloud_import',
|
||||
'xpack.syncinstancetask': 'cloud_import',
|
||||
'xpack.syncinstancetaskexecution': 'cloud_import',
|
||||
'xpack.strategy': 'cloud_import',
|
||||
'xpack.strategyaction': 'cloud_import',
|
||||
'xpack.strategyrule': 'cloud_import',
|
||||
'terminal.applet': 'remote_application',
|
||||
'terminal.applethost': 'remote_application',
|
||||
'accounts.accountbackupautomation': "backup_account_node",
|
||||
|
|
|
@ -28,6 +28,11 @@ class SettingsApi(generics.RetrieveUpdateAPIView):
|
|||
'basic': serializers.BasicSettingSerializer,
|
||||
'terminal': serializers.TerminalSettingSerializer,
|
||||
'security': serializers.SecuritySettingSerializer,
|
||||
'security_auth': serializers.SecurityAuthSerializer,
|
||||
'security_basic': serializers.SecurityBasicSerializer,
|
||||
'security_session': serializers.SecuritySessionSerializer,
|
||||
'security_password': serializers.SecurityPasswordRuleSerializer,
|
||||
'security_login_limit': serializers.SecurityLoginLimitSerializer,
|
||||
'ldap': serializers.LDAPSettingSerializer,
|
||||
'email': serializers.EmailSettingSerializer,
|
||||
'email_content': serializers.EmailContentSettingSerializer,
|
||||
|
@ -39,7 +44,6 @@ class SettingsApi(generics.RetrieveUpdateAPIView):
|
|||
'keycloak': serializers.KeycloakSettingSerializer,
|
||||
'radius': serializers.RadiusSettingSerializer,
|
||||
'cas': serializers.CASSettingSerializer,
|
||||
'sso': serializers.SSOSettingSerializer,
|
||||
'saml2': serializers.SAML2SettingSerializer,
|
||||
'oauth2': serializers.OAuth2SettingSerializer,
|
||||
'clean': serializers.CleaningSerializer,
|
||||
|
@ -51,6 +55,9 @@ class SettingsApi(generics.RetrieveUpdateAPIView):
|
|||
'cmpp2': serializers.CMPP2SMSSettingSerializer,
|
||||
'custom': serializers.CustomSMSSettingSerializer,
|
||||
'vault': serializers.VaultSettingSerializer,
|
||||
'announcement': serializers.AnnouncementSettingSerializer,
|
||||
'ticket': serializers.TicketSettingSerializer,
|
||||
'ops': serializers.OpsSettingSerializer,
|
||||
}
|
||||
|
||||
rbac_category_permissions = {
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
import importlib
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import status
|
||||
from rest_framework.exceptions import APIException
|
||||
from rest_framework.generics import ListAPIView, GenericAPIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.exceptions import APIException
|
||||
from rest_framework import status
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from common.sdk.sms import BACKENDS
|
||||
from common.exceptions import JMSException
|
||||
from settings.serializers.sms import SMSBackendSerializer
|
||||
from common.sdk.sms import BACKENDS
|
||||
from settings.models import Setting
|
||||
|
||||
from settings.serializers import SMSBackendSerializer
|
||||
from .. import serializers
|
||||
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
from .auth import *
|
||||
from .basic import *
|
||||
from .cleaning import *
|
||||
from .email import *
|
||||
from .feature import *
|
||||
from .msg import *
|
||||
from .msg import *
|
||||
from .other import *
|
||||
from .public import *
|
||||
from .security import *
|
||||
from .settings import *
|
||||
from .terminal import *
|
||||
from .vault import *
|
||||
|
||||
|
|
|
@ -9,14 +9,16 @@ __all__ = [
|
|||
class AuthSettingSerializer(serializers.Serializer):
|
||||
PREFIX_TITLE = _('Authentication')
|
||||
|
||||
AUTH_LDAP = serializers.BooleanField(required=False, label=_('LDAP Auth'))
|
||||
AUTH_CAS = serializers.BooleanField(required=False, label=_('CAS Auth'))
|
||||
AUTH_OPENID = serializers.BooleanField(required=False, label=_('OPENID Auth'))
|
||||
AUTH_SAML2 = serializers.BooleanField(default=False, label=_("SAML2 Auth"))
|
||||
AUTH_OAUTH2 = serializers.BooleanField(default=False, label=_("OAuth2 Auth"))
|
||||
AUTH_RADIUS = serializers.BooleanField(required=False, label=_('RADIUS Auth'))
|
||||
AUTH_DINGTALK = serializers.BooleanField(default=False, label=_('DingTalk Auth'))
|
||||
AUTH_FEISHU = serializers.BooleanField(default=False, label=_('FeiShu Auth'))
|
||||
AUTH_WECOM = serializers.BooleanField(default=False, label=_('WeCom Auth'))
|
||||
AUTH_SSO = serializers.BooleanField(default=False, label=_("SSO Auth"))
|
||||
AUTH_SAML2 = serializers.BooleanField(default=False, label=_("SAML2 Auth"))
|
||||
FORGOT_PASSWORD_URL = serializers.CharField(
|
||||
required=False, allow_blank=True, max_length=1024,
|
||||
label=_("Forgot password url")
|
||||
|
|
|
@ -7,6 +7,9 @@ __all__ = [
|
|||
|
||||
|
||||
class SSOSettingSerializer(serializers.Serializer):
|
||||
"""
|
||||
不对外开放了,只能通过配置文件修改,比较这个稍微有点危险
|
||||
"""
|
||||
PREFIX_TITLE = _('SSO')
|
||||
|
||||
AUTH_SSO = serializers.BooleanField(
|
||||
|
|
|
@ -1,51 +1,30 @@
|
|||
import uuid
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class AnnouncementSerializer(serializers.Serializer):
|
||||
ID = serializers.CharField(required=False, allow_blank=True, allow_null=True)
|
||||
SUBJECT = serializers.CharField(required=True, max_length=1024, label=_("Subject"))
|
||||
CONTENT = serializers.CharField(label=_("Content"))
|
||||
LINK = serializers.URLField(
|
||||
required=False, allow_null=True, allow_blank=True,
|
||||
label=_("More url"), default='',
|
||||
)
|
||||
|
||||
def to_representation(self, instance):
|
||||
defaults = {'ID': '', 'SUBJECT': '', 'CONTENT': '', 'LINK': '', 'ENABLED': False}
|
||||
data = {**defaults, **instance}
|
||||
return super().to_representation(data)
|
||||
|
||||
def to_internal_value(self, data):
|
||||
data['ID'] = str(uuid.uuid4())
|
||||
return super().to_internal_value(data)
|
||||
|
||||
|
||||
class BasicSettingSerializer(serializers.Serializer):
|
||||
PREFIX_TITLE = _('Basic')
|
||||
|
||||
SITE_URL = serializers.URLField(
|
||||
required=True, label=_("Site url"),
|
||||
help_text=_('eg: http://dev.jumpserver.org:8080')
|
||||
help_text=_('Email links or other system callbacks are used to access it, eg: http://dev.jumpserver.org:8080')
|
||||
)
|
||||
USER_GUIDE_URL = serializers.URLField(
|
||||
required=False, allow_blank=True, allow_null=True, label=_("User guide url"),
|
||||
help_text=_('User first login update profile done redirect to it')
|
||||
)
|
||||
FORGOT_PASSWORD_URL = serializers.URLField(
|
||||
required=False, allow_blank=True, allow_null=True, label=_("Forgot password url"),
|
||||
help_text=_('The forgot password url on login page, If you use '
|
||||
'ldap or cas external authentication, you can set it')
|
||||
)
|
||||
GLOBAL_ORG_DISPLAY_NAME = serializers.CharField(
|
||||
required=False, max_length=1024, allow_blank=True, allow_null=True, label=_("Global organization name"),
|
||||
help_text=_('The name of global organization to display')
|
||||
)
|
||||
ANNOUNCEMENT_ENABLED = serializers.BooleanField(label=_('Enable announcement'), default=True)
|
||||
ANNOUNCEMENT = AnnouncementSerializer(label=_("Announcement"))
|
||||
TICKETS_ENABLED = serializers.BooleanField(required=False, default=True, label=_("Enable tickets"))
|
||||
HELP_DOCUMENT_URL = serializers.URLField(
|
||||
required=False, allow_blank=True, allow_null=True, label=_("Help Docs URL"),
|
||||
help_text=_('default: http://docs.jumpserver.org')
|
||||
)
|
||||
HELP_SUPPORT_URL = serializers.URLField(
|
||||
required=False, allow_blank=True, allow_null=True, label=_("Help Support URL"),
|
||||
help_text=_('default: http://www.jumpserver.org/support/')
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def validate_SITE_URL(s):
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
import uuid
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from accounts.const import VaultTypeChoices
|
||||
from common.serializers.fields import EncryptedField
|
||||
|
||||
__all__ = [
|
||||
'AnnouncementSettingSerializer', 'OpsSettingSerializer',
|
||||
'VaultSettingSerializer', 'TicketSettingSerializer'
|
||||
]
|
||||
|
||||
|
||||
class AnnouncementSerializer(serializers.Serializer):
|
||||
ID = serializers.CharField(required=False, allow_blank=True, allow_null=True)
|
||||
SUBJECT = serializers.CharField(required=True, max_length=1024, label=_("Subject"))
|
||||
CONTENT = serializers.CharField(label=_("Content"))
|
||||
LINK = serializers.URLField(
|
||||
required=False, allow_null=True, allow_blank=True,
|
||||
label=_("More url"), default='',
|
||||
)
|
||||
|
||||
def to_representation(self, instance):
|
||||
defaults = {'ID': '', 'SUBJECT': '', 'CONTENT': '', 'LINK': '', 'ENABLED': False}
|
||||
data = {**defaults, **instance}
|
||||
return super().to_representation(data)
|
||||
|
||||
def to_internal_value(self, data):
|
||||
data['ID'] = str(uuid.uuid4())
|
||||
return super().to_internal_value(data)
|
||||
|
||||
|
||||
class AnnouncementSettingSerializer(serializers.Serializer):
|
||||
PREFIX_TITLE = _('Announcement')
|
||||
|
||||
ANNOUNCEMENT_ENABLED = serializers.BooleanField(label=_('Enable announcement'), default=True)
|
||||
ANNOUNCEMENT = AnnouncementSerializer(label=_("Announcement"))
|
||||
|
||||
|
||||
class VaultSettingSerializer(serializers.Serializer):
|
||||
PREFIX_TITLE = _('Vault')
|
||||
|
||||
VAULT_TYPE = serializers.ChoiceField(
|
||||
default=VaultTypeChoices.local, choices=VaultTypeChoices.choices,
|
||||
required=False, label=_('Type')
|
||||
)
|
||||
VAULT_HCP_HOST = serializers.CharField(
|
||||
max_length=256, allow_blank=True, required=False, label=_('Host')
|
||||
)
|
||||
VAULT_HCP_TOKEN = EncryptedField(
|
||||
max_length=256, allow_blank=True, required=False, label=_('Token'), default=''
|
||||
)
|
||||
VAULT_HCP_MOUNT_POINT = serializers.CharField(
|
||||
max_length=256, allow_blank=True, required=False, label=_('Mount Point')
|
||||
)
|
||||
|
||||
def validate(self, attrs):
|
||||
attrs.pop('VAULT_TYPE', None)
|
||||
return attrs
|
||||
|
||||
|
||||
class TicketSettingSerializer(serializers.Serializer):
|
||||
PREFIX_TITLE = _('Ticket')
|
||||
|
||||
TICKETS_ENABLED = serializers.BooleanField(required=False, default=True, label=_("Enable tickets"))
|
||||
TICKET_AUTHORIZE_DEFAULT_TIME = serializers.IntegerField(
|
||||
min_value=1, max_value=999999, required=False,
|
||||
label=_("Ticket authorize default time")
|
||||
)
|
||||
TICKET_AUTHORIZE_DEFAULT_TIME_UNIT = serializers.ChoiceField(
|
||||
choices=[('day', _("day")), ('hour', _("hour"))],
|
||||
label=_("Ticket authorize default time unit"), required=False,
|
||||
)
|
||||
|
||||
|
||||
class OpsSettingSerializer(serializers.Serializer):
|
||||
PREFIX_TITLE = _('Feature')
|
||||
|
||||
SECURITY_COMMAND_EXECUTION = serializers.BooleanField(
|
||||
required=False, label=_('Operation center'),
|
||||
help_text=_('Allow user run batch command or not using ansible')
|
||||
)
|
||||
SECURITY_COMMAND_BLACKLIST = serializers.ListField(
|
||||
child=serializers.CharField(max_length=1024, ),
|
||||
label=_('Operation center command blacklist'),
|
||||
help_text=_("Commands that are not allowed execute.")
|
||||
)
|
|
@ -6,7 +6,10 @@ from rest_framework import serializers
|
|||
|
||||
from common.serializers.fields import EncryptedField
|
||||
|
||||
__all__ = ['MailTestSerializer', 'EmailSettingSerializer', 'EmailContentSettingSerializer']
|
||||
__all__ = [
|
||||
'MailTestSerializer', 'EmailSettingSerializer',
|
||||
'EmailContentSettingSerializer', 'SMSBackendSerializer',
|
||||
]
|
||||
|
||||
|
||||
class MailTestSerializer(serializers.Serializer):
|
||||
|
@ -44,6 +47,10 @@ class EmailSettingSerializer(serializers.Serializer):
|
|||
EMAIL_SUBJECT_PREFIX = serializers.CharField(
|
||||
max_length=1024, required=True, label=_('Subject prefix')
|
||||
)
|
||||
EMAIL_SUFFIX = serializers.CharField(
|
||||
required=False, max_length=1024, label=_("Email suffix"),
|
||||
help_text=_('This is used by default if no email is returned during SSO authentication')
|
||||
)
|
||||
|
||||
|
||||
class EmailContentSettingSerializer(serializers.Serializer):
|
||||
|
@ -69,3 +76,8 @@ class EmailContentSettingSerializer(serializers.Serializer):
|
|||
max_length=512, allow_blank=True, required=False, label=_('Signature'),
|
||||
help_text=_('Tips: Email signature (eg:jumpserver)')
|
||||
)
|
||||
|
||||
|
||||
class SMSBackendSerializer(serializers.Serializer):
|
||||
name = serializers.CharField(max_length=256, required=True, label=_('Name'))
|
||||
label = serializers.CharField(max_length=256, required=True, label=_('Label'))
|
|
@ -1,46 +1,17 @@
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
__all__ = ['OtherSettingSerializer']
|
||||
|
||||
|
||||
class OtherSettingSerializer(serializers.Serializer):
|
||||
PREFIX_TITLE = _('More...')
|
||||
|
||||
EMAIL_SUFFIX = serializers.CharField(
|
||||
required=False, max_length=1024, label=_("Email suffix"),
|
||||
help_text=_('This is used by default if no email is returned during SSO authentication')
|
||||
)
|
||||
|
||||
OTP_ISSUER_NAME = serializers.CharField(
|
||||
required=False, max_length=16, label=_('OTP issuer name'),
|
||||
)
|
||||
OTP_VALID_WINDOW = serializers.IntegerField(
|
||||
min_value=1, max_value=10,
|
||||
label=_("OTP valid window")
|
||||
)
|
||||
|
||||
PERM_SINGLE_ASSET_TO_UNGROUP_NODE = serializers.BooleanField(
|
||||
required=False, label=_("Perm ungroup node"),
|
||||
help_text=_("Perm single to ungroup node")
|
||||
)
|
||||
|
||||
TICKET_AUTHORIZE_DEFAULT_TIME = serializers.IntegerField(
|
||||
min_value=1, max_value=999999, required=False,
|
||||
label=_("Ticket authorize default time")
|
||||
)
|
||||
TICKET_AUTHORIZE_DEFAULT_TIME_UNIT = serializers.ChoiceField(
|
||||
choices=[('day', _("day")), ('hour', _("hour"))],
|
||||
label=_("Ticket authorize default time unit"), required=False,
|
||||
)
|
||||
HELP_DOCUMENT_URL = serializers.URLField(
|
||||
required=False, allow_blank=True, allow_null=True, label=_("Help Docs URL"),
|
||||
help_text=_('default: http://docs.jumpserver.org')
|
||||
)
|
||||
|
||||
HELP_SUPPORT_URL = serializers.URLField(
|
||||
required=False, allow_blank=True, allow_null=True, label=_("Help Support URL"),
|
||||
help_text=_('default: http://www.jumpserver.org/support/')
|
||||
)
|
||||
|
||||
# 准备废弃
|
||||
# PERIOD_TASK_ENABLED = serializers.BooleanField(
|
||||
# required=False, label=_("Enable period task")
|
||||
|
|
|
@ -3,8 +3,31 @@ from rest_framework import serializers
|
|||
|
||||
from acls.serializers.rules import ip_group_help_text, ip_group_child_validator
|
||||
|
||||
__all__ = [
|
||||
'SecurityPasswordRuleSerializer', 'SecuritySessionSerializer',
|
||||
'SecurityAuthSerializer', 'SecuritySettingSerializer',
|
||||
'SecurityLoginLimitSerializer', 'SecurityBasicSerializer',
|
||||
]
|
||||
|
||||
|
||||
class SecurityPasswordRuleSerializer(serializers.Serializer):
|
||||
SECURITY_PASSWORD_EXPIRATION_TIME = serializers.IntegerField(
|
||||
min_value=1, max_value=99999, required=True,
|
||||
label=_('User password expiration (day)'),
|
||||
help_text=_(
|
||||
'If the user does not update the password during the time, '
|
||||
'the user password will expire failure;The password expiration reminder mail will be '
|
||||
'automatic sent to the user by system within 5 days (daily) before the password expires'
|
||||
)
|
||||
)
|
||||
OLD_PASSWORD_HISTORY_LIMIT_COUNT = serializers.IntegerField(
|
||||
min_value=0, max_value=99999, required=True,
|
||||
label=_('Number of repeated historical passwords'),
|
||||
help_text=_(
|
||||
'Tip: When the user resets the password, it cannot be '
|
||||
'the previous n historical passwords of the user'
|
||||
)
|
||||
)
|
||||
SECURITY_PASSWORD_MIN_LENGTH = serializers.IntegerField(
|
||||
min_value=6, max_value=30, required=True,
|
||||
label=_('Password minimum length')
|
||||
|
@ -33,20 +56,7 @@ login_ip_limit_time_help_text = _(
|
|||
)
|
||||
|
||||
|
||||
class SecurityAuthSerializer(serializers.Serializer):
|
||||
SECURITY_MFA_AUTH = serializers.ChoiceField(
|
||||
choices=(
|
||||
[0, _('Not enabled')],
|
||||
[1, _('All users')],
|
||||
[2, _('Only admin users')],
|
||||
),
|
||||
required=False, label=_("Global MFA auth")
|
||||
)
|
||||
SECURITY_MFA_AUTH_ENABLED_FOR_THIRD_PARTY = serializers.BooleanField(
|
||||
required=False, default=True,
|
||||
label=_('Third-party login users perform MFA authentication'),
|
||||
help_text=_('The third-party login modes include OIDC, CAS, and SAML2'),
|
||||
)
|
||||
class SecurityLoginLimitSerializer(serializers.Serializer):
|
||||
SECURITY_LOGIN_LIMIT_COUNT = serializers.IntegerField(
|
||||
min_value=3, max_value=99999,
|
||||
label=_('Limit the number of user login failures')
|
||||
|
@ -56,6 +66,7 @@ class SecurityAuthSerializer(serializers.Serializer):
|
|||
label=_('Block user login interval (minute)'),
|
||||
help_text=login_ip_limit_time_help_text
|
||||
)
|
||||
|
||||
SECURITY_LOGIN_IP_LIMIT_COUNT = serializers.IntegerField(
|
||||
min_value=3, max_value=99999,
|
||||
label=_('Limit the number of IP login failures')
|
||||
|
@ -75,23 +86,6 @@ class SecurityAuthSerializer(serializers.Serializer):
|
|||
child=serializers.CharField(max_length=1024, validators=[ip_group_child_validator]),
|
||||
help_text=ip_group_help_text
|
||||
)
|
||||
SECURITY_PASSWORD_EXPIRATION_TIME = serializers.IntegerField(
|
||||
min_value=1, max_value=99999, required=True,
|
||||
label=_('User password expiration (day)'),
|
||||
help_text=_(
|
||||
'If the user does not update the password during the time, '
|
||||
'the user password will expire failure;The password expiration reminder mail will be '
|
||||
'automatic sent to the user by system within 5 days (daily) before the password expires'
|
||||
)
|
||||
)
|
||||
OLD_PASSWORD_HISTORY_LIMIT_COUNT = serializers.IntegerField(
|
||||
min_value=0, max_value=99999, required=True,
|
||||
label=_('Number of repeated historical passwords'),
|
||||
help_text=_(
|
||||
'Tip: When the user resets the password, it cannot be '
|
||||
'the previous n historical passwords of the user'
|
||||
)
|
||||
)
|
||||
USER_LOGIN_SINGLE_MACHINE_ENABLED = serializers.BooleanField(
|
||||
required=False, default=False, label=_("Only single device login"),
|
||||
help_text=_("After the user logs in on the new device, other logged-in devices will automatically log out")
|
||||
|
@ -99,24 +93,59 @@ class SecurityAuthSerializer(serializers.Serializer):
|
|||
ONLY_ALLOW_EXIST_USER_AUTH = serializers.BooleanField(
|
||||
required=False, default=False, label=_("Only exist user login"),
|
||||
help_text=_(
|
||||
"If enabled, non-existent users will not be allowed to log in; if disabled, users of other authentication methods except local authentication methods are allowed to log in and automatically create users (if the user does not exist)")
|
||||
"If enabled, non-existent users will not be allowed to log in; if disabled, "
|
||||
"users of other authentication methods except local authentication methods are allowed "
|
||||
"to log in and automatically create users (if the user does not exist)"
|
||||
)
|
||||
)
|
||||
ONLY_ALLOW_AUTH_FROM_SOURCE = serializers.BooleanField(
|
||||
required=False, default=False, label=_("Only from source login"),
|
||||
help_text=_(
|
||||
"If it is enabled, the user will only authenticate to the source when logging in; if it is disabled, the user will authenticate all the enabled authentication methods in a certain order when logging in, and as long as one of the authentication methods is successful, they can log in directly")
|
||||
"If it is enabled, the user will only authenticate to the source when logging in; "
|
||||
"if it is disabled, the user will authenticate all the enabled authentication methods "
|
||||
"in a certain order when logging in, and as long as one of the authentication methods is successful, "
|
||||
"they can log in directly"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class SecurityAuthSerializer(serializers.Serializer):
|
||||
SECURITY_MFA_AUTH = serializers.ChoiceField(
|
||||
choices=(
|
||||
[0, _('Not enabled')],
|
||||
[1, _('All users')],
|
||||
[2, _('Only admin users')],
|
||||
),
|
||||
required=False, label=_("Global MFA auth")
|
||||
)
|
||||
SECURITY_MFA_AUTH_ENABLED_FOR_THIRD_PARTY = serializers.BooleanField(
|
||||
required=False, default=True,
|
||||
label=_('Third-party login users perform MFA authentication'),
|
||||
help_text=_('The third-party login modes include OIDC, CAS, and SAML2'),
|
||||
)
|
||||
OTP_ISSUER_NAME = serializers.CharField(
|
||||
required=False, max_length=16, label=_('OTP issuer name'),
|
||||
)
|
||||
OTP_VALID_WINDOW = serializers.IntegerField(
|
||||
min_value=1, max_value=10,
|
||||
label=_("OTP valid window")
|
||||
)
|
||||
SECURITY_MFA_VERIFY_TTL = serializers.IntegerField(
|
||||
min_value=5, max_value=60 * 60 * 10,
|
||||
label=_("MFA verify TTL (secend)"),
|
||||
label=_("MFA verify TTL"),
|
||||
help_text=_(
|
||||
"The verification MFA takes effect only when you view the account password"
|
||||
"Unit: second, The verification MFA takes effect only when you view the account password"
|
||||
)
|
||||
)
|
||||
SECURITY_MFA_IN_LOGIN_PAGE = serializers.BooleanField(
|
||||
required=False, default=False,
|
||||
label=_("MFA in login page"),
|
||||
help_text=_("Eu security regulations(GDPR) require MFA to be on the login page")
|
||||
)
|
||||
VERIFY_CODE_TTL = serializers.IntegerField(
|
||||
min_value=5, max_value=60 * 60 * 10,
|
||||
label=_("Verify code TTL"),
|
||||
help_text=_("Unit: second, reset password and send SMS code expiration time")
|
||||
label=_("Verify code TTL (second)"),
|
||||
help_text=_("Reset password and send SMS code expiration time")
|
||||
)
|
||||
SECURITY_LOGIN_CHALLENGE_ENABLED = serializers.BooleanField(
|
||||
required=False, default=False,
|
||||
|
@ -124,15 +153,22 @@ class SecurityAuthSerializer(serializers.Serializer):
|
|||
help_text=_("The password and additional code are sent to a third party "
|
||||
"authentication system for verification")
|
||||
)
|
||||
SECURITY_MFA_IN_LOGIN_PAGE = serializers.BooleanField(
|
||||
required=False, default=False,
|
||||
label=_("MFA in login page"),
|
||||
help_text=_("Eu security regulations(GDPR) require MFA to be on the login page")
|
||||
)
|
||||
SECURITY_LOGIN_CAPTCHA_ENABLED = serializers.BooleanField(
|
||||
required=False, default=False, label=_("Enable Login captcha"),
|
||||
help_text=_("Enable captcha to prevent robot authentication")
|
||||
)
|
||||
SECURITY_CHECK_DIFFERENT_CITY_LOGIN = serializers.BooleanField(
|
||||
required=False, label=_('Remote Login Protection'),
|
||||
help_text=_(
|
||||
'The system determines whether the login IP address belongs to a common login city. '
|
||||
'If the account is logged in from a common login city, the system sends a remote login reminder'
|
||||
)
|
||||
)
|
||||
SECURITY_UNCOMMON_USERS_TTL = serializers.IntegerField(
|
||||
min_value=30, max_value=99999, required=False,
|
||||
label=_('Unused user timeout (day)'),
|
||||
help_text=_("Detect infrequent users daily and disable them if they exceed the predetermined time limit.")
|
||||
)
|
||||
|
||||
def validate(self, attrs):
|
||||
if attrs.get('SECURITY_MFA_AUTH') != 1:
|
||||
|
@ -149,15 +185,7 @@ class SecurityAuthSerializer(serializers.Serializer):
|
|||
return data
|
||||
|
||||
|
||||
class SecuritySettingSerializer(SecurityPasswordRuleSerializer, SecurityAuthSerializer):
|
||||
PREFIX_TITLE = _('Security')
|
||||
|
||||
SECURITY_SERVICE_ACCOUNT_REGISTRATION = serializers.BooleanField(
|
||||
required=True, label=_('Enable terminal register'),
|
||||
help_text=_(
|
||||
"Allow terminal register, after all terminal setup, you should disable this for security"
|
||||
)
|
||||
)
|
||||
class SecuritySessionSerializer(serializers.Serializer):
|
||||
SECURITY_WATERMARK_ENABLED = serializers.BooleanField(
|
||||
required=True, label=_('Enable watermark'),
|
||||
help_text=_('Enabled, the web session and replay contains watermark information')
|
||||
|
@ -175,6 +203,13 @@ class SecuritySettingSerializer(SecurityPasswordRuleSerializer, SecurityAuthSeri
|
|||
SECURITY_LUNA_REMEMBER_AUTH = serializers.BooleanField(
|
||||
label=_("Remember manual auth")
|
||||
)
|
||||
SECURITY_SESSION_SHARE = serializers.BooleanField(
|
||||
required=True, label=_('Session share'),
|
||||
help_text=_("Enabled, Allows user active session to be shared with other users")
|
||||
)
|
||||
|
||||
|
||||
class SecurityBasicSerializer(serializers.Serializer):
|
||||
SECURITY_INSECURE_COMMAND = serializers.BooleanField(
|
||||
required=False, label=_('Insecure command alert')
|
||||
)
|
||||
|
@ -182,28 +217,11 @@ class SecuritySettingSerializer(SecurityPasswordRuleSerializer, SecurityAuthSeri
|
|||
max_length=8192, required=False, allow_blank=True, label=_('Email recipient'),
|
||||
help_text=_('Multiple user using , split')
|
||||
)
|
||||
SECURITY_COMMAND_EXECUTION = serializers.BooleanField(
|
||||
required=False, label=_('Operation center'),
|
||||
help_text=_('Allow user run batch command or not using ansible')
|
||||
)
|
||||
SECURITY_COMMAND_BLACKLIST = serializers.ListField(
|
||||
child=serializers.CharField(max_length=1024, ),
|
||||
label=_('Operation center command blacklist'),
|
||||
help_text=_("Commands that are not allowed execute.")
|
||||
)
|
||||
SECURITY_SESSION_SHARE = serializers.BooleanField(
|
||||
required=True, label=_('Session share'),
|
||||
help_text=_("Enabled, Allows user active session to be shared with other users")
|
||||
)
|
||||
SECURITY_UNCOMMON_USERS_TTL = serializers.IntegerField(
|
||||
min_value=30, max_value=99999, required=False,
|
||||
label=_('Unused user timeout (day)'),
|
||||
help_text=_("Detect infrequent users daily and disable them if they exceed the predetermined time limit.")
|
||||
)
|
||||
SECURITY_CHECK_DIFFERENT_CITY_LOGIN = serializers.BooleanField(
|
||||
required=False, label=_('Remote Login Protection'),
|
||||
help_text=_(
|
||||
'The system determines whether the login IP address belongs to a common login city. '
|
||||
'If the account is logged in from a common login city, the system sends a remote login reminder'
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class SecuritySettingSerializer(
|
||||
SecurityPasswordRuleSerializer, SecurityAuthSerializer,
|
||||
SecuritySessionSerializer, SecurityBasicSerializer,
|
||||
SecurityLoginLimitSerializer,
|
||||
):
|
||||
PREFIX_TITLE = _('Security')
|
||||
|
|
|
@ -9,12 +9,12 @@ from .auth import (
|
|||
CASSettingSerializer, RadiusSettingSerializer, FeiShuSettingSerializer,
|
||||
WeComSettingSerializer, DingTalkSettingSerializer, AlibabaSMSSettingSerializer,
|
||||
TencentSMSSettingSerializer, CMPP2SMSSettingSerializer, AuthSettingSerializer,
|
||||
SAML2SettingSerializer, OAuth2SettingSerializer, SSOSettingSerializer,
|
||||
SAML2SettingSerializer, OAuth2SettingSerializer,
|
||||
CustomSMSSettingSerializer,
|
||||
)
|
||||
from .basic import BasicSettingSerializer
|
||||
from .cleaning import CleaningSerializer
|
||||
from .email import EmailSettingSerializer, EmailContentSettingSerializer
|
||||
from .msg import EmailSettingSerializer, EmailContentSettingSerializer
|
||||
from .other import OtherSettingSerializer
|
||||
from .security import SecuritySettingSerializer
|
||||
from .terminal import TerminalSettingSerializer
|
||||
|
@ -42,7 +42,6 @@ class SettingsSerializer(
|
|||
KeycloakSettingSerializer,
|
||||
CASSettingSerializer,
|
||||
RadiusSettingSerializer,
|
||||
SSOSettingSerializer,
|
||||
CleaningSerializer,
|
||||
AlibabaSMSSettingSerializer,
|
||||
TencentSMSSettingSerializer,
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class SMSBackendSerializer(serializers.Serializer):
|
||||
name = serializers.CharField(max_length=256, required=True, label=_('Name'))
|
||||
label = serializers.CharField(max_length=256, required=True, label=_('Label'))
|
|
@ -18,6 +18,12 @@ class TerminalSettingSerializer(serializers.Serializer):
|
|||
('25', '25'),
|
||||
('50', '50'),
|
||||
)
|
||||
SECURITY_SERVICE_ACCOUNT_REGISTRATION = serializers.BooleanField(
|
||||
required=True, label=_('Enable terminal register'),
|
||||
help_text=_(
|
||||
"Allow terminal register, after all terminal setup, you should disable this for security"
|
||||
)
|
||||
)
|
||||
TERMINAL_PASSWORD_AUTH = serializers.BooleanField(required=False, label=_('Password auth'))
|
||||
TERMINAL_PUBLIC_KEY_AUTH = serializers.BooleanField(
|
||||
required=False, label=_('Public key auth'),
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from accounts.const import VaultTypeChoices
|
||||
from common.serializers.fields import EncryptedField
|
||||
|
||||
__all__ = ['VaultSettingSerializer']
|
||||
|
||||
|
||||
class VaultSettingSerializer(serializers.Serializer):
|
||||
VAULT_TYPE = serializers.ChoiceField(
|
||||
default=VaultTypeChoices.local, choices=VaultTypeChoices.choices,
|
||||
required=False, label=_('Type')
|
||||
)
|
||||
VAULT_HCP_HOST = serializers.CharField(
|
||||
max_length=256, allow_blank=True, required=False, label=_('Host')
|
||||
)
|
||||
VAULT_HCP_TOKEN = EncryptedField(
|
||||
max_length=256, allow_blank=True, required=False, label=_('Token'), default=''
|
||||
)
|
||||
VAULT_HCP_MOUNT_POINT = serializers.CharField(
|
||||
max_length=256, allow_blank=True, required=False, label=_('Mount Point')
|
||||
)
|
||||
|
||||
def validate(self, attrs):
|
||||
attrs.pop('VAULT_TYPE', None)
|
||||
return attrs
|
|
@ -147,7 +147,7 @@ class AppletHostDeployment(JMSBaseModel):
|
|||
|
||||
def start(self, **kwargs):
|
||||
# 重新初始化部署,applet host 关联的终端需要删除
|
||||
# 否则 tinker 会因终端注册名称相同,造成冲突,执行任务失败
|
||||
# 否则 tinker 会因组件注册名称相同,造成冲突,执行任务失败
|
||||
if self.host.terminal:
|
||||
terminal = self.host.terminal
|
||||
self.host.terminal = None
|
||||
|
|
|
@ -96,3 +96,6 @@ REDIS_PORT: 6379
|
|||
# 仅允许已存在的用户登录,不允许第三方认证后,自动创建用户
|
||||
# ONLY_ALLOW_EXIST_USER_AUTH: False
|
||||
|
||||
# 当前存储的类型,默认 local,新增类型 hcp 为远端 vault 存储
|
||||
# VAULT_TYPE: local
|
||||
|
||||
|
|
|
@ -2259,44 +2259,24 @@ url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
|||
reference = "tsinghua"
|
||||
|
||||
[[package]]
|
||||
name = "elastic-transport"
|
||||
version = "8.4.0"
|
||||
description = "Transport classes and utilities shared among Python Elastic client libraries"
|
||||
name = "elasticsearch"
|
||||
version = "7.8.0"
|
||||
description = "Python client for Elasticsearch"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4"
|
||||
files = [
|
||||
{file = "elastic-transport-8.4.0.tar.gz", hash = "sha256:b9ad708ceb7fcdbc6b30a96f886609a109f042c0b9d9f2e44403b3133ba7ff10"},
|
||||
{file = "elastic_transport-8.4.0-py3-none-any.whl", hash = "sha256:19db271ab79c9f70f8c43f8f5b5111408781a6176b54ab2e54d713b6d9ceb815"},
|
||||
{file = "elasticsearch-7.8.0-py2.py3-none-any.whl", hash = "sha256:6fb566dd23b91b5871ce12212888674b4cf33374e92b71b1080916c931e44dcb"},
|
||||
{file = "elasticsearch-7.8.0.tar.gz", hash = "sha256:e637d8cf4e27e279b5ff8ca8edc0c086f4b5df4bf2b48e2f950b7833aca3a792"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
certifi = "*"
|
||||
urllib3 = ">=1.26.2,<2"
|
||||
urllib3 = ">=1.21.1"
|
||||
|
||||
[package.extras]
|
||||
develop = ["aiohttp", "mock", "pytest", "pytest-asyncio", "pytest-cov", "pytest-httpserver", "pytest-mock", "requests", "trustme"]
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "tsinghua"
|
||||
|
||||
[[package]]
|
||||
name = "elasticsearch"
|
||||
version = "8.8.2"
|
||||
description = "Python client for Elasticsearch"
|
||||
optional = false
|
||||
python-versions = ">=3.6, <4"
|
||||
files = [
|
||||
{file = "elasticsearch-8.8.2-py3-none-any.whl", hash = "sha256:bffd6ce4faaacf90e6f617241773b3da8fb94e2e83554f5508e2fab92ca79643"},
|
||||
{file = "elasticsearch-8.8.2.tar.gz", hash = "sha256:bed8cf8fcc6c3be7c254b579de4c29afab021f373c832246f912d37aef3c6bd5"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
elastic-transport = ">=8,<9"
|
||||
|
||||
[package.extras]
|
||||
async = ["aiohttp (>=3,<4)"]
|
||||
async = ["aiohttp (>=3,<4)", "yarl"]
|
||||
develop = ["black", "coverage", "jinja2", "mock", "pytest", "pytest-cov", "pyyaml", "requests (>=2.0.0,<3.0.0)", "sphinx (<1.7)", "sphinx-rtd-theme"]
|
||||
docs = ["sphinx (<1.7)", "sphinx-rtd-theme"]
|
||||
requests = ["requests (>=2.4.0,<3.0.0)"]
|
||||
|
||||
[package.source]
|
||||
|
@ -3343,12 +3323,12 @@ reference = "tsinghua"
|
|||
|
||||
[[package]]
|
||||
name = "jms-storage"
|
||||
version = "0.0.50"
|
||||
version = "0.0.51"
|
||||
description = "Jumpserver storage python sdk tools"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "jms-storage-0.0.50.tar.gz", hash = "sha256:f757180e145a9eb3390b8b32663a5feebcb1e720a6f2c36cc16f726ac047f28b"},
|
||||
{file = "jms-storage-0.0.51.tar.gz", hash = "sha256:47a50ac4d952a21693b0e2f926f42fa0d02bc1fa8e507a8284059743b2b81911"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -3360,7 +3340,7 @@ certifi = "2023.7.22"
|
|||
chardet = "5.1.0"
|
||||
crcmod = "1.7"
|
||||
docutils = "0.20.1"
|
||||
elasticsearch = "8.8.2"
|
||||
elasticsearch = "7.8.0"
|
||||
esdk-obs-python = "3.21.4"
|
||||
idna = "3.4"
|
||||
oss2 = "2.18.1"
|
||||
|
|
|
@ -47,7 +47,7 @@ pynacl = "1.5.0"
|
|||
python-dateutil = "2.8.2"
|
||||
pyyaml = "6.0.1"
|
||||
requests = "2.31.0"
|
||||
jms-storage = "0.0.50"
|
||||
jms-storage = "0.0.51"
|
||||
simplejson = "3.19.1"
|
||||
six = "1.16.0"
|
||||
sshtunnel = "0.4.0"
|
||||
|
|
Loading…
Reference in New Issue