Compare commits

...

36 Commits

Author SHA1 Message Date
fit2bot
d1c11eb2d7 feat: Update v2.28.14 2023-05-09 14:04:24 +08:00
Bai
8a77a7b8b5 perf: 优化系统用户和资产,只有协议包含时才进行关联和推送 2023-05-08 19:07:59 +08:00
Bai
7eed182627 perf: 优化系统用户和资产,只有协议包含时才进行关联和推送 2023-05-08 18:14:19 +08:00
feng626
ec847d3ecb Fix v2.28.7 ssh key (#10399)
* feat: Update v2.28.7

* fix: 修复旧 ssh 私钥,解析失败的问题

* perf: 解决历史版本中因保存密码,造成 ssh 私钥解析失败问题

* fix: 动态用户可执行批量任务

---------

Co-authored-by: fit2bot <fit2bot@fit2cloud.com>
Co-authored-by: Eric <xplzv@126.com>
2023-05-08 14:28:23 +08:00
Eric
a0994e2e12 fix: 修复旧 ssh 私钥,解析失败的问题 2023-04-27 17:49:52 +08:00
ibuler
17e3ddda05 perf: 支持 rdp console 2023-04-25 14:35:28 +08:00
Bai
6e2e92be5e fix: perf: 修改OAuth2的access_token前缀格式 2023-04-20 14:59:54 +08:00
老广
e90d8c8561 Merge pull request #10121 from jumpserver/pr@v2.28@fix_ldapuserimport_v2.28
fix: 修复 LDAP 导入用户时指定其他组织,还会导入到 Default 组织的问题
2023-04-03 17:09:58 +08:00
Bai
cf972942fa fix: 修复 LDAP 导入用户时指定其他组织,还会导入到 Default 组织的问题 2023-04-03 16:54:14 +08:00
老广
72e35d5553 Merge pull request #10046 from jumpserver/pr@v2.28@fix_systemuserlist
fix: 去掉系统用户序列类中的资产数量和应用数量
2023-03-23 14:13:33 +08:00
Bai
0ba84e7e18 fix: 去掉系统用户序列类中的资产数量和应用数量 2023-03-23 11:52:18 +08:00
Bai
fbc5ae1b9b fix: 修复日志记录到syslog时中文编码问题 2023-03-15 19:45:40 +08:00
halo
2fcf045826 fix: 修复celery api 报错 2023-03-15 15:36:54 +08:00
Bai
32cba4f2a1 fix: 修复语言切换问题 2023-03-14 14:40:23 +08:00
Jiangjie.Bai
b76aa3b259 feat: 支持飞书国际版(lark) (#9916) 2023-03-10 15:49:15 +08:00
Eric
3f9a17347d fix: 修复存储故障造成的录像获取失败问题 2023-03-09 11:52:23 +08:00
老广
c01d1973d9 Merge pull request #9877 from jumpserver/pr@v2.28@fix_operatelog_hide_sth
fix: 操作日志显示用户加密后的密文,及日期格式调整
2023-03-08 14:05:20 +08:00
jiangweidong
b216a9abc0 fix: 操作日志显示用户加密后的密文,及日期格式调整 2023-03-08 11:36:48 +08:00
Bai
c628ba1c4b fix: 修复翻译 2023-03-02 12:25:29 +08:00
fit2bot
ebbae36c49 perf: k8s update api (#9833)
Co-authored-by: feng <1304903146@qq.com>
2023-03-02 11:03:29 +08:00
Bai
69ef25666e fix: 修复认证MFA失败次数清空问题 2023-02-24 14:44:32 +08:00
Bai
d0475397d0 fix: 修复第三方用户登录复核可以跳过的问题 2023-02-09 19:50:13 +08:00
老广
dad45e7ace Merge pull request #9233 from jumpserver/pr@v2.28@perf_dockerfile
build(deps): 优化龙芯构建依赖包
2022-12-22 12:43:37 +08:00
吴小白
720f9cd397 build(deps): 优化龙芯构建依赖包 2022-12-22 12:40:53 +08:00
Bai
81dee0c403 perf: 修改方法名称 check_db_port_mapper 2022-12-22 10:43:07 +08:00
老广
105ef791b8 Merge pull request #9230 from jumpserver/pr@v2.28@v2.28_perf_dbportmapper
fix: 修改db_port_mapper策略; 启动时进行check校验;
2022-12-21 18:59:47 +08:00
Bai
a19c0bde60 fix: 修改db_port_mapper策略; 启动时进行check校验; 2022-12-21 18:43:44 +08:00
halo
3996daf4a7 fix: 导入翻译引用 2022-12-16 11:47:39 +08:00
halo
ac235f788e perf: 优化oauth2的服务地址参数拼接 2022-12-16 11:47:39 +08:00
老广
67e334bf43 Merge pull request #9213 from jumpserver/pr@v2.28@perf_fingerprint
fix: 修复非 ssh 协议的系统用户存在错误私钥,引发的解析问题
2022-12-15 15:25:40 +08:00
Eric
f7f9fb1bdf fix: 修复非 ssh 协议的系统用户存在错误私钥,引发的解析问题 2022-12-15 15:17:36 +08:00
Eric
8979228e0b fix: 修复 ssh 私钥推送等问题 2022-12-13 16:21:54 +08:00
吴小白
024beca690 Merge pull request #9200 from jumpserver/pr@v2.28@perf_support_openid_pkce
perf: OpenID支持PKCE方式对接
2022-12-13 16:12:17 +08:00
jiangweidong
5c0359e394 perf: OpenID支持PKCE方式对接 2022-12-13 15:11:21 +08:00
feng
4ce4bde368 fix: ticket xss inject 2022-12-12 17:03:29 +08:00
halo
809bad271a fix: 密钥指纹参数 2022-12-09 13:41:38 +08:00
38 changed files with 579 additions and 383 deletions

View File

@@ -38,8 +38,8 @@ ARG TOOLS=" \
default-mysql-client \
iputils-ping \
locales \
netcat \
redis-server \
procps \
redis-tools \
telnet \
vim \
unzip \

1
GITSHA Normal file
View File

@@ -0,0 +1 @@
8a77a7b8b57c5b0fb8455f3b34fc9b6f3c3a24c1

View File

@@ -1,4 +1,4 @@
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from common.drf.serializers import BulkModelSerializer
from common.drf.serializers import MethodSerializer

View File

@@ -1,18 +1,14 @@
# -*- coding: utf-8 -*-
from urllib3.exceptions import MaxRetryError
from urllib.parse import urlencode
from kubernetes import client
from kubernetes.client import api_client
from kubernetes.client.api import core_v1_api
from kubernetes import client
from kubernetes.client.exceptions import ApiException
from rest_framework.generics import get_object_or_404
from common.utils import get_logger
from common.tree import TreeNode
from assets.models import SystemUser
from common.tree import TreeNode
from common.utils import get_logger
from .. import const
logger = get_logger(__file__)
@@ -23,7 +19,8 @@ class KubernetesClient:
self.url = url
self.token = token
def get_api(self):
@property
def api(self):
configuration = client.Configuration()
configuration.host = self.url
configuration.verify_ssl = False
@@ -32,63 +29,46 @@ class KubernetesClient:
api = core_v1_api.CoreV1Api(c)
return api
def get_namespace_list(self):
api = self.get_api()
namespace_list = []
for ns in api.list_namespace().items:
namespace_list.append(ns.metadata.name)
return namespace_list
def get_namespaces(self):
namespaces = []
resp = self.api.list_namespace()
for ns in resp.items:
namespaces.append(ns.metadata.name)
return namespaces
def get_services(self):
api = self.get_api()
ret = api.list_service_for_all_namespaces(watch=False)
for i in ret.items:
print("%s \t%s \t%s \t%s \t%s \n" % (
i.kind, i.metadata.namespace, i.metadata.name, i.spec.cluster_ip, i.spec.ports))
def get_pods(self, namespace):
pods = []
resp = self.api.list_namespaced_pod(namespace)
for pd in resp.items:
pods.append(pd.metadata.name)
return pods
def get_pod_info(self, namespace, pod):
api = self.get_api()
resp = api.read_namespaced_pod(namespace=namespace, name=pod)
return resp
def get_containers(self, namespace, pod_name):
containers = []
resp = self.api.read_namespaced_pod(pod_name, namespace)
for container in resp.spec.containers:
containers.append(container.name)
return containers
def get_pod_logs(self, namespace, pod):
api = self.get_api()
log_content = api.read_namespaced_pod_log(pod, namespace, pretty=True, tail_lines=200)
return log_content
@classmethod
def run(cls, asset, secret, tp='namespace'):
k8s_url = f'{asset.address}'
k8s = cls(k8s_url, secret)
func_name = f'get_{tp}s'
if hasattr(k8s, func_name):
return getattr(k8s, func_name)()
return []
def get_pods(self):
api = self.get_api()
try:
ret = api.list_pod_for_all_namespaces(watch=False, _request_timeout=(3, 3))
except MaxRetryError:
logger.warning('Kubernetes connection timed out')
return
except ApiException as e:
if e.status == 401:
logger.warning('Kubernetes User not authenticated')
else:
logger.warning(e)
return
data = {}
for i in ret.items:
namespace = i.metadata.namespace
pod_info = {
'pod_name': i.metadata.name,
'containers': [j.name for j in i.spec.containers]
}
if namespace in data:
data[namespace].append(pod_info)
else:
data[namespace] = [pod_info, ]
return data
@staticmethod
def get_kubernetes_data(app_id, system_user_id):
@classmethod
def get_kubernetes_data(cls, app_id, system_user_id, tp, *args):
from ..models import Application
app = get_object_or_404(Application, id=app_id)
system_user = get_object_or_404(SystemUser, id=system_user_id)
k8s = KubernetesClient(app.attrs['cluster'], system_user.token)
return k8s.get_pods()
k8s = cls(app.attrs['cluster'], system_user.token)
func_name = f'get_{tp}s'
if hasattr(k8s, func_name):
return getattr(k8s, func_name)(*args)
return []
class KubernetesTree:
@@ -118,11 +98,10 @@ class KubernetesTree:
)
return node
def as_namespace_pod_tree_node(self, name, meta, type, counts=0, is_container=False):
def as_namespace_pod_tree_node(self, name, meta, type, is_container=False):
from ..models import ApplicationTreeNodeMixin
i = ApplicationTreeNodeMixin.create_tree_id(self.tree_id, type, name)
meta.update({type: name})
name = name if is_container else f'{name}({counts})'
node = self.create_tree_node(
i, self.tree_id, name, type, meta, icon='cloud', is_container=is_container
)
@@ -157,30 +136,30 @@ class KubernetesTree:
system_user_id = parent_info.get('system_user_id')
tree_nodes = []
data = KubernetesClient.get_kubernetes_data(app_id, system_user_id)
if not data:
return tree_nodes
if pod_name:
for container in next(
filter(
lambda x: x['pod_name'] == pod_name, data[namespace]
)
)['containers']:
tp = 'container'
containers = KubernetesClient.get_kubernetes_data(
app_id, system_user_id, tp, namespace, pod_name
)
for container in containers:
container_node = self.as_namespace_pod_tree_node(
container, parent_info, 'container', is_container=True
container, parent_info, tp, is_container=True
)
tree_nodes.append(container_node)
elif namespace:
for pod in data[namespace]:
pod_nodes = self.as_namespace_pod_tree_node(
pod['pod_name'], parent_info, 'pod', len(pod['containers'])
tp = 'pod'
pods = KubernetesClient.get_kubernetes_data(app_id, system_user_id, tp, namespace)
for pod in pods:
pod_node = self.as_namespace_pod_tree_node(
pod, parent_info, tp
)
tree_nodes.append(pod_nodes)
tree_nodes.append(pod_node)
elif system_user_id:
for namespace, pods in data.items():
tp = 'namespace'
namespaces = KubernetesClient.get_kubernetes_data(app_id, system_user_id, tp)
for namespace in namespaces:
namespace_node = self.as_namespace_pod_tree_node(
namespace, parent_info, 'namespace', len(pods)
namespace, parent_info, tp
)
tree_nodes.append(namespace_node)
return tree_nodes

View File

@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
#
import io
import os
import uuid
from hashlib import md5
@@ -18,7 +17,9 @@ from common.utils import random_string
from common.utils import (
ssh_key_string_to_obj, ssh_key_gen, get_logger, lazyproperty
)
from common.utils.encode import parse_ssh_public_key_str
from common.utils.encode import (
parse_ssh_public_key_str, parse_ssh_private_key_str
)
from orgs.mixins.models import OrgModelMixin
logger = get_logger(__file__)
@@ -62,16 +63,16 @@ class AuthMixin:
@property
def ssh_key_fingerprint(self):
public_key = None
if self.public_key:
public_key = self.public_key
elif self.private_key:
try:
public_key = parse_ssh_public_key_str(private_key=self.private_key, password=self.password)
public_key = parse_ssh_public_key_str(self.private_key, password=self.password)
except IOError as e:
return str(e)
else:
if not public_key:
return ''
public_key_obj = sshpubkeys.SSHKey(public_key)
fingerprint = public_key_obj.hash_md5()
return fingerprint
@@ -86,24 +87,29 @@ class AuthMixin:
@property
def private_key_file(self):
if not self.private_key_obj:
if not self.private_key:
return None
private_key_str = self.get_private_key()
if not private_key_str:
return None
project_dir = settings.PROJECT_DIR
tmp_dir = os.path.join(project_dir, 'tmp')
key_name = '.' + md5(self.private_key.encode('utf-8')).hexdigest()
key_path = os.path.join(tmp_dir, key_name)
if not os.path.exists(key_path):
self.private_key_obj.write_private_key_file(key_path)
with open(key_path, 'w') as f:
f.write(private_key_str)
os.chmod(key_path, 0o400)
return key_path
def get_private_key(self):
if not self.private_key_obj:
if not self.private_key:
return None
string_io = io.StringIO()
self.private_key_obj.write_private_key(string_io)
private_key = string_io.getvalue()
return private_key
private_key_str = parse_ssh_private_key_str(self.private_key, password=self.password)
if not private_key_str and self.password:
# 由于历史原因,密码可能是真实的密码,而非私钥的 passphrase所以这里再尝试一次
private_key_str = parse_ssh_private_key_str(self.private_key)
return private_key_str
@property
def public_key_obj(self):

View File

@@ -9,7 +9,7 @@ from django.utils.translation import ugettext_lazy as _
from django.core.validators import MinValueValidator, MaxValueValidator
from django.core.cache import cache
from common.utils import signer, get_object_or_none
from common.utils import signer, get_object_or_none, is_uuid
from .base import BaseUser
from .asset import Asset
from .authbook import AuthBook
@@ -322,9 +322,20 @@ class SystemUser(ProtocolMixin, AuthMixin, BaseUser):
assets = Asset.objects.filter(id__in=asset_ids)
return assets
def filter_contain_protocol_assets(self, assets_or_ids):
if not assets_or_ids:
return assets_or_ids
if is_uuid(assets_or_ids[0]):
assets = Asset.objects.filter(id__in=assets_or_ids)
else:
assets = assets_or_ids
assets = [asset for asset in assets if self.protocol in asset.protocols_as_dict]
return assets
def add_related_assets(self, assets_or_ids):
self.assets.add(*tuple(assets_or_ids))
self.add_related_assets_to_su_from_if_need(assets_or_ids)
assets = self.filter_contain_protocol_assets(assets_or_ids)
self.assets.add(*tuple(assets))
self.add_related_assets_to_su_from_if_need(assets)
def add_related_assets_to_su_from_if_need(self, assets_or_ids):
if self.protocol not in [self.Protocol.ssh.value]:

View File

@@ -36,9 +36,6 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
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
@@ -53,7 +50,7 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
'su_enabled', 'su_from',
'date_created', 'date_updated', 'comment', 'created_by',
]
fields_m2m = ['cmd_filters', 'assets_amount', 'applications_amount', 'nodes']
fields_m2m = ['cmd_filters', 'nodes']
fields = fields_small + fields_m2m
extra_kwargs = {
'cmd_filters': {"required": False, 'label': _('Command filter')},
@@ -241,7 +238,6 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
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

View File

@@ -50,6 +50,10 @@ def clean_ansible_task_hosts(assets, system_user=None):
for asset in assets:
if not check_asset_can_run_ansible(asset):
continue
# 资产平台不包含系统用户的协议, 不推送
if system_user and system_user.protocol not in asset.protocols_as_dict:
logger.info(_('Asset protocol not support system user protocol, skipped: {}').format(system_user.protocol))
continue
cleaned_assets.append(asset)
if not cleaned_assets:
logger.info(_("No assets matched, stop task"))

View File

@@ -2,13 +2,14 @@ import csv
import codecs
from itertools import chain
from datetime import datetime
from django.http import HttpResponse
from django.db import models
from settings.serializers import SettingsSerializer
from common.utils.timezone import as_current_tz
from common.utils import validate_ip, get_ip_city, get_logger
from common.db import fields
from .const import DEFAULT_CITY
@@ -78,6 +79,8 @@ def model_to_dict_for_operate_log(
f.verbose_name = 'id'
elif isinstance(value, list):
value = [str(v) for v in value]
elif isinstance(value, datetime):
value = as_current_tz(value).strftime('%Y-%m-%d %H:%M:%S')
if include_model_fields or getattr(f, 'primary_key', False):
data[str(f.verbose_name)] = value

View File

@@ -1,26 +1,27 @@
import abc
import os
import json
import base64
import json
import os
import urllib.parse
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from rest_framework.exceptions import PermissionDenied
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied
from rest_framework.request import Request
from rest_framework.response import Response
from common.drf.api import JMSModelViewSet
from common.http import is_true
from orgs.mixins.api import RootOrgViewMixin
from perms.models.base import Action
from terminal.models import EndpointRule
from ..models import ConnectionToken
from ..serializers import (
ConnectionTokenSerializer, ConnectionTokenSecretSerializer,
SuperConnectionTokenSerializer, ConnectionTokenDisplaySerializer,
)
from ..models import ConnectionToken
__all__ = ['ConnectionTokenViewSet', 'SuperConnectionTokenViewSet']
@@ -165,6 +166,9 @@ class ConnectionTokenMixin:
rdp_options['session bpp:i'] = os.getenv('JUMPSERVER_COLOR_DEPTH', '32')
rdp_options['audiomode:i'] = self.parse_env_bool('JUMPSERVER_DISABLE_AUDIO', 'false', '2', '0')
if token.asset and token.asset.platform.meta.get('console', None) == 'true':
rdp_options['administrative session:i:'] = '1'
if token.asset:
name = token.asset.hostname
elif token.application and token.application.category_remote_app:

View File

@@ -20,6 +20,7 @@ class TicketStatusApi(mixins.AuthMixin, APIView):
try:
self.check_user_login_confirm()
self.request.session['auth_third_party_done'] = 1
self.request.session.pop('auth_third_party_required', '')
return Response({"msg": "ok"})
except errors.LoginConfirmOtherError as e:
reason = e.msg

View File

@@ -2,6 +2,7 @@
#
import requests
from django.utils.translation import gettext_lazy as _
from django.contrib.auth import get_user_model
from django.utils.http import urlencode
from django.conf import settings
@@ -90,8 +91,12 @@ class OAuth2Backend(JMSModelBackend):
request, path=reverse(settings.AUTH_OAUTH2_AUTH_LOGIN_CALLBACK_URL_NAME)
)
}
access_token_url = '{url}?{query}'.format(
url=settings.AUTH_OAUTH2_ACCESS_TOKEN_ENDPOINT, query=urlencode(query_dict)
if '?' in settings.AUTH_OAUTH2_ACCESS_TOKEN_ENDPOINT:
separator = '&'
else:
separator = '?'
access_token_url = '{url}{separator}{query}'.format(
url=settings.AUTH_OAUTH2_ACCESS_TOKEN_ENDPOINT, separator=separator, query=urlencode(query_dict)
)
token_method = settings.AUTH_OAUTH2_ACCESS_TOKEN_METHOD.lower()
requests_func = getattr(requests, token_method, requests.get)
@@ -114,12 +119,16 @@ class OAuth2Backend(JMSModelBackend):
headers = {
'Accept': 'application/json',
'Authorization': 'token {}'.format(response_data.get('access_token', ''))
'Authorization': 'Bearer {}'.format(response_data.get('access_token', ''))
}
logger.debug(log_prompt.format('Get userinfo endpoint'))
userinfo_url = '{url}?{query}'.format(
url=settings.AUTH_OAUTH2_PROVIDER_USERINFO_ENDPOINT,
if '?' in settings.AUTH_OAUTH2_PROVIDER_USERINFO_ENDPOINT:
separator = '&'
else:
separator = '?'
userinfo_url = '{url}{separator}{query}'.format(
url=settings.AUTH_OAUTH2_PROVIDER_USERINFO_ENDPOINT, separator=separator,
query=urlencode(query_dict)
)
userinfo_response = requests.get(userinfo_url, headers=headers)

View File

@@ -26,8 +26,13 @@ class OAuth2AuthRequestView(View):
)
}
redirect_url = '{url}?{query}'.format(
if '?' in settings.AUTH_OAUTH2_PROVIDER_AUTHORIZATION_ENDPOINT:
separator = '&'
else:
separator = '?'
redirect_url = '{url}{separator}{query}'.format(
url=settings.AUTH_OAUTH2_PROVIDER_AUTHORIZATION_ENDPOINT,
separator=separator,
query=urlencode(query_dict)
)
logger.debug(log_prompt.format('Redirect login url'))

View File

@@ -88,7 +88,7 @@ class OIDCAuthCodeBackend(OIDCBaseBackend):
"""
@ssl_verification
def authenticate(self, request, nonce=None, **kwargs):
def authenticate(self, request, nonce=None, code_verifier=None, **kwargs):
""" Authenticates users in case of the OpenID Connect Authorization code flow. """
log_prompt = "Process authenticate [OIDCAuthCodeBackend]: {}"
logger.debug(log_prompt.format('start'))
@@ -134,6 +134,8 @@ class OIDCAuthCodeBackend(OIDCBaseBackend):
request, path=reverse(settings.AUTH_OPENID_AUTH_LOGIN_CALLBACK_URL_NAME)
)
}
if settings.AUTH_OPENID_PKCE and code_verifier:
token_payload['code_verifier'] = code_verifier
if settings.AUTH_OPENID_CLIENT_AUTH_METHOD == 'client_secret_post':
token_payload.update({
'client_id': settings.AUTH_OPENID_CLIENT_ID,

View File

@@ -9,7 +9,10 @@
"""
import base64
import hashlib
import time
import secrets
from django.conf import settings
from django.contrib import auth
@@ -38,6 +41,19 @@ class OIDCAuthRequestView(View):
http_method_names = ['get', ]
@staticmethod
def gen_code_verifier(length=128):
# length range 43 ~ 128
return secrets.token_urlsafe(length-32)
@staticmethod
def gen_code_challenge(code_verifier, code_challenge_method):
if code_challenge_method == 'plain':
return code_verifier
h = hashlib.sha256(code_verifier.encode('ascii')).digest()
b = base64.urlsafe_b64encode(h)
return b.decode('ascii')[:-1]
def get(self, request):
""" Processes GET requests. """
@@ -56,6 +72,16 @@ class OIDCAuthRequestView(View):
)
})
if settings.AUTH_OPENID_PKCE:
code_verifier = self.gen_code_verifier()
code_challenge_method = settings.AUTH_OPENID_CODE_CHALLENGE_METHOD or 'S256'
code_challenge = self.gen_code_challenge(code_verifier, code_challenge_method)
authentication_request_params.update({
'code_challenge_method': code_challenge_method,
'code_challenge': code_challenge
})
request.session['oidc_auth_code_verifier'] = code_verifier
# States should be used! They are recommended in order to maintain state between the
# authentication request and the callback.
if settings.AUTH_OPENID_USE_STATE:
@@ -138,8 +164,9 @@ class OIDCAuthCallbackView(View):
# Authenticates the end-user.
next_url = request.session.get('oidc_auth_next_url', None)
code_verifier = request.session.get('oidc_auth_code_verifier', None)
logger.debug(log_prompt.format('Process authenticate'))
user = auth.authenticate(nonce=nonce, request=request)
user = auth.authenticate(nonce=nonce, request=request, code_verifier=code_verifier)
if user and user.is_valid:
logger.debug(log_prompt.format('Login: {}'.format(user)))
auth.login(self.request, user)

View File

@@ -61,6 +61,18 @@ class ThirdPartyLoginMiddleware(mixins.AuthMixin):
return response
if not request.session.get('auth_third_party_required'):
return response
white_urls = [
'jsi18n/', '/static/',
'login/guard', 'login/wait-confirm',
'login-confirm-ticket/status',
'settings/public/open',
'core/auth/login', 'core/auth/logout'
]
for url in white_urls:
if request.path.find(url) > -1:
return response
ip = get_request_ip(request)
try:
self.request = request
@@ -88,7 +100,6 @@ class ThirdPartyLoginMiddleware(mixins.AuthMixin):
guard_url = "%s?%s" % (guard_url, args)
response = redirect(guard_url)
finally:
request.session.pop('auth_third_party_required', '')
return response

View File

@@ -225,6 +225,7 @@ class MFAMixin:
self.request.session['auth_mfa_time'] = time.time()
self.request.session['auth_mfa_required'] = 0
self.request.session['auth_mfa_type'] = mfa_type
MFABlockUtils(self.request.user.username, self.get_request_ip()).clean_failed_count()
def clean_mfa_mark(self):
keys = ['auth_mfa', 'auth_mfa_time', 'auth_mfa_required', 'auth_mfa_type']
@@ -369,7 +370,7 @@ class AuthACLMixin:
def check_user_login_confirm(self):
ticket = self.get_ticket()
if not ticket:
raise errors.LoginConfirmOtherError('', "Not found")
raise errors.LoginConfirmOtherError('', "Not found", '')
elif ticket.is_state(ticket.State.approved):
self.request.session["auth_confirm_required"] = ''
return
@@ -512,4 +513,20 @@ class AuthMixin(CommonMixin, AuthPreCheckMixin, AuthACLMixin, MFAMixin, AuthPost
args = self.request.META.get('QUERY_STRING', '')
if args:
guard_url = "%s?%s" % (guard_url, args)
return redirect(guard_url)
response = redirect(guard_url)
self.set_browser_default_language_if_need(response)
return response
def set_browser_default_language_if_need(self, response):
# en, ja, zh-CN,zh;q=0.9
browser_lang = self.request.headers.get('Accept-Language', '')
# 浏览器首选语言
if browser_lang.startswith('en'):
browser_lang = 'en'
elif browser_lang.startswith('ja'):
browser_lang = 'ja'
else:
browser_lang = 'zh'
request_lang = self.request.LANGUAGE_CODE
lang = request_lang or browser_lang
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang)

View File

@@ -60,7 +60,7 @@ class FeiShuQRMixin(UserConfirmRequiredExceptionMixin, PermissionsMixin, View):
'state': state,
'redirect_uri': redirect_uri,
}
url = URL.AUTHEN + '?' + urlencode(params)
url = URL().authen + '?' + urlencode(params)
return url
@staticmethod

View File

@@ -32,11 +32,14 @@ class UserLoginMFAView(mixins.AuthMixin, FormView):
return super().get(*args, **kwargs)
def form_valid(self, form):
from users.utils import MFABlockUtils
code = form.cleaned_data.get('code')
mfa_type = form.cleaned_data.get('mfa_type')
try:
self._do_check_user_mfa(code, mfa_type)
user, ip = self.get_user_from_session(), self.get_request_ip()
MFABlockUtils(user.username, ip).clean_failed_count()
return redirect_to_guard_view('mfa_ok')
except (errors.MFAFailedError, errors.BlockMFAError) as e:
form.add_error('code', e.msg)

View File

@@ -1,7 +1,7 @@
from werkzeug.local import Local
thread_local = Local()
encrypted_field_set = set()
encrypted_field_set = {'password'}
def _find(attr):

View File

@@ -3,6 +3,7 @@ import json
from django.utils.translation import ugettext_lazy as _
from rest_framework.exceptions import APIException
from django.conf import settings
from common.utils.common import get_logger
from common.sdk.im.utils import digest
from common.sdk.im.mixin import RequestMixin, BaseRequest
@@ -11,14 +12,30 @@ logger = get_logger(__name__)
class URL:
AUTHEN = 'https://open.feishu.cn/open-apis/authen/v1/index'
GET_TOKEN = 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal/'
# https://open.feishu.cn/document/ukTMukTMukTM/uEDO4UjLxgDO14SM4gTN
GET_USER_INFO_BY_CODE = 'https://open.feishu.cn/open-apis/authen/v1/access_token'
@property
def host(self):
if settings.FEISHU_VERSION == 'feishu':
h = 'https://open.feishu.cn'
else:
h = 'https://open.larksuite.com'
return h
SEND_MESSAGE = 'https://open.feishu.cn/open-apis/im/v1/messages'
@property
def authen(self):
return f'{self.host}/open-apis/authen/v1/index'
@property
def get_token(self):
return f'{self.host}/open-apis/auth/v3/tenant_access_token/internal/'
@property
def get_user_info_by_code(self):
return f'{self.host}/open-apis/authen/v1/access_token'
@property
def send_message(self):
return f'{self.host}/open-apis/im/v1/messages'
class ErrorCode:
@@ -51,7 +68,7 @@ class FeishuRequests(BaseRequest):
def request_access_token(self):
data = {'app_id': self._app_id, 'app_secret': self._app_secret}
response = self.raw_request('post', url=URL.GET_TOKEN, data=data)
response = self.raw_request('post', url=URL().get_token, data=data)
self.check_errcode_is_0(response)
access_token = response['tenant_access_token']
@@ -86,7 +103,7 @@ class FeiShu(RequestMixin):
'code': code
}
data = self._requests.post(URL.GET_USER_INFO_BY_CODE, json=body, check_errcode_is_0=False)
data = self._requests.post(URL().get_user_info_by_code, json=body, check_errcode_is_0=False)
self._requests.check_errcode_is_0(data)
return data['data']['user_id']
@@ -107,7 +124,7 @@ class FeiShu(RequestMixin):
try:
logger.info(f'Feishu send text: user_ids={user_ids} msg={msg}')
self._requests.post(URL.SEND_MESSAGE, params=params, json=body)
self._requests.post(URL().send_message, params=params, json=body)
except APIException as e:
# 只处理可预知的错误
logger.exception(e)

View File

@@ -79,7 +79,7 @@ _supported_paramiko_ssh_key_types = (
def ssh_key_string_to_obj(text, password=None):
key = None
for ssh_key_type in _supported_paramiko_ssh_key_types:
if not isinstance(ssh_key_type, paramiko.PKey):
if not issubclass(ssh_key_type, paramiko.PKey):
continue
try:
key = ssh_key_type.from_private_key(StringIO(text), password=password)
@@ -173,6 +173,8 @@ def _parse_ssh_private_key(text, password=None):
dsa.DSAPrivateKey,
ed25519.Ed25519PrivateKey,
"""
if not bool(password):
password = None
if isinstance(text, str):
try:
text = text.encode("utf-8")
@@ -274,4 +276,4 @@ def ensure_last_char_is_ascii(data):
def data_to_json(data, sort_keys=True, indent=2, cls=None):
if cls is None:
cls = DjangoJSONEncoder
return json.dumps(data, sort_keys=sort_keys, indent=indent, cls=cls)
return json.dumps(data, ensure_ascii=False, sort_keys=sort_keys, indent=indent, cls=cls)

View File

@@ -270,6 +270,8 @@ class Config(dict):
'AUTH_OPENID_USER_ATTR_MAP': {
'name': 'name', 'username': 'preferred_username', 'email': 'email'
},
'AUTH_OPENID_PKCE': False,
'AUTH_OPENID_CODE_CHALLENGE_METHOD': 'S256',
# OpenID 新配置参数 (version >= 1.5.9)
'AUTH_OPENID_PROVIDER_ENDPOINT': 'https://oidc.example.com/',
@@ -374,6 +376,7 @@ class Config(dict):
'AUTH_FEISHU': False,
'FEISHU_APP_ID': '',
'FEISHU_APP_SECRET': '',
'FEISHU_VERSION': 'feishu',
'LOGIN_REDIRECT_TO_BACKEND': '', # 'OPENID / CAS / SAML2
'LOGIN_REDIRECT_MSG_ENABLED': True,

View File

@@ -78,6 +78,8 @@ AUTH_OPENID_SHARE_SESSION = CONFIG.AUTH_OPENID_SHARE_SESSION
AUTH_OPENID_IGNORE_SSL_VERIFICATION = CONFIG.AUTH_OPENID_IGNORE_SSL_VERIFICATION
AUTH_OPENID_ALWAYS_UPDATE_USER = CONFIG.AUTH_OPENID_ALWAYS_UPDATE_USER
AUTH_OPENID_USER_ATTR_MAP = CONFIG.AUTH_OPENID_USER_ATTR_MAP
AUTH_OPENID_PKCE = CONFIG.AUTH_OPENID_PKCE
AUTH_OPENID_CODE_CHALLENGE_METHOD = CONFIG.AUTH_OPENID_CODE_CHALLENGE_METHOD
AUTH_OPENID_AUTH_LOGIN_URL_NAME = 'authentication:openid:login'
AUTH_OPENID_AUTH_LOGIN_CALLBACK_URL_NAME = 'authentication:openid:login-callback'
AUTH_OPENID_AUTH_LOGOUT_URL_NAME = 'authentication:openid:logout'
@@ -135,6 +137,7 @@ DINGTALK_APPSECRET = CONFIG.DINGTALK_APPSECRET
AUTH_FEISHU = CONFIG.AUTH_FEISHU
FEISHU_APP_ID = CONFIG.FEISHU_APP_ID
FEISHU_APP_SECRET = CONFIG.FEISHU_APP_SECRET
FEISHU_VERSION = CONFIG.FEISHU_VERSION
# Saml2 auth
AUTH_SAML2 = CONFIG.AUTH_SAML2

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7db985efdf818137dafe489f339955f4d71a245ffd6becc8f6efac539a625682
size 133463
oid sha256:0cc37a87259f2cd3794ad628ee40497bd97beaee7219be3d9773e1e544c3e352
size 134193

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-17 17:34+0800\n"
"POT-Creation-Date: 2023-05-08 18:10+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -24,13 +24,13 @@ msgstr "Acls"
#: acls/models/base.py:25 acls/serializers/login_asset_acl.py:47
#: applications/models/application.py:219 assets/models/asset.py:138
#: assets/models/base.py:175 assets/models/cluster.py:18
#: assets/models/base.py:177 assets/models/cluster.py:18
#: assets/models/cmd_filter.py:27 assets/models/domain.py:23
#: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24
#: orgs/models.py:70 perms/models/base.py:83 rbac/models/role.py:29
#: settings/models.py:33 settings/serializers/sms.py:6
#: terminal/models/endpoint.py:14 terminal/models/endpoint.py:87
#: terminal/models/storage.py:27 terminal/models/task.py:16
#: terminal/models/storage.py:26 terminal/models/task.py:16
#: terminal/models/terminal.py:101 users/forms/profile.py:33
#: users/models/group.py:15 users/models/user.py:673
#: xpack/plugins/cloud/models.py:27
@@ -55,14 +55,14 @@ msgstr "アクティブ"
#: acls/models/base.py:32 applications/models/application.py:232
#: assets/models/asset.py:143 assets/models/asset.py:231
#: assets/models/backup.py:54 assets/models/base.py:180
#: assets/models/backup.py:54 assets/models/base.py:182
#: assets/models/cluster.py:29 assets/models/cmd_filter.py:52
#: assets/models/cmd_filter.py:100 assets/models/domain.py:24
#: assets/models/domain.py:65 assets/models/group.py:23
#: assets/models/label.py:23 ops/models/adhoc.py:38 orgs/models.py:73
#: perms/models/base.py:93 rbac/models/role.py:37 settings/models.py:38
#: terminal/models/endpoint.py:22 terminal/models/endpoint.py:97
#: terminal/models/storage.py:30 terminal/models/terminal.py:115
#: terminal/models/storage.py:29 terminal/models/terminal.py:115
#: tickets/models/comment.py:32 tickets/models/ticket/general.py:288
#: users/models/group.py:16 users/models/user.py:712
#: xpack/plugins/change_auth_plan/models/base.py:44
@@ -131,7 +131,7 @@ msgstr "システムユーザー"
#: assets/models/asset.py:386 assets/models/authbook.py:19
#: assets/models/backup.py:31 assets/models/cmd_filter.py:42
#: assets/models/gathered_user.py:14 assets/serializers/label.py:30
#: assets/serializers/system_user.py:268 audits/models.py:40
#: assets/serializers/system_user.py:264 audits/models.py:40
#: authentication/models.py:66 authentication/models.py:90
#: perms/models/asset_permission.py:23 terminal/backends/command/models.py:21
#: terminal/backends/command/serializers.py:14 terminal/models/session.py:47
@@ -155,7 +155,7 @@ msgid "Format for comma-delimited string, with * indicating a match all. "
msgstr "コンマ区切り文字列の形式。* はすべて一致することを示します。"
#: acls/serializers/login_acl.py:15 acls/serializers/login_asset_acl.py:17
#: acls/serializers/login_asset_acl.py:51 assets/models/base.py:176
#: acls/serializers/login_asset_acl.py:51 assets/models/base.py:178
#: assets/models/gathered_user.py:15 audits/models.py:139
#: authentication/forms.py:25 authentication/forms.py:27
#: authentication/models.py:260
@@ -186,7 +186,7 @@ msgstr ""
#: authentication/templates/authentication/_msg_oauth_bind.html:12
#: authentication/templates/authentication/_msg_rest_password_success.html:8
#: authentication/templates/authentication/_msg_rest_public_key_success.html:8
#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:54
#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:58
msgid "IP"
msgstr "IP"
@@ -269,7 +269,7 @@ msgid "Application"
msgstr "アプリケーション"
#: applications/models/account.py:15 assets/models/authbook.py:20
#: assets/models/cmd_filter.py:46 assets/models/user.py:343 audits/models.py:41
#: assets/models/cmd_filter.py:46 assets/models/user.py:354 audits/models.py:41
#: authentication/models.py:83 perms/models/application_permission.py:33
#: perms/models/asset_permission.py:25 terminal/backends/command/models.py:22
#: terminal/backends/command/serializers.py:36 terminal/models/session.py:49
@@ -280,7 +280,7 @@ msgid "System user"
msgstr "システムユーザー"
#: applications/models/account.py:17 assets/models/authbook.py:21
#: settings/serializers/auth/cas.py:20
#: settings/serializers/auth/cas.py:20 settings/serializers/auth/feishu.py:20
msgid "Version"
msgstr "バージョン"
@@ -310,7 +310,7 @@ msgstr "カテゴリ"
#: assets/models/cmd_filter.py:86 assets/models/user.py:251
#: authentication/models.py:70 perms/models/application_permission.py:24
#: perms/serializers/application/user_permission.py:34
#: terminal/models/storage.py:59 terminal/models/storage.py:145
#: terminal/models/storage.py:58 terminal/models/storage.py:147
#: tickets/models/comment.py:26 tickets/models/flow.py:57
#: tickets/models/ticket/apply_application.py:18
#: tickets/models/ticket/general.py:273
@@ -353,7 +353,7 @@ msgid "Type display"
msgstr "タイプ表示"
#: applications/serializers/application.py:105 assets/models/asset.py:230
#: assets/models/base.py:181 assets/models/cluster.py:26
#: assets/models/base.py:183 assets/models/cluster.py:26
#: assets/models/cmd_filter.py:53 assets/models/domain.py:26
#: assets/models/gathered_user.py:19 assets/models/group.py:22
#: assets/models/label.py:25 assets/serializers/account.py:18
@@ -367,7 +367,7 @@ msgstr "タイプ表示"
msgid "Date created"
msgstr "作成された日付"
#: applications/serializers/application.py:106 assets/models/base.py:182
#: applications/serializers/application.py:106 assets/models/base.py:184
#: assets/models/cmd_filter.py:54 assets/models/gathered_user.py:20
#: assets/serializers/account.py:21 assets/serializers/cmd_filter.py:29
#: assets/serializers/cmd_filter.py:49 common/db/models.py:117
@@ -445,7 +445,7 @@ msgid "Application path"
msgstr "アプリケーションパス"
#: applications/serializers/attrs/application_category/remote_app.py:44
#: assets/serializers/system_user.py:167
#: assets/serializers/system_user.py:164
#: tickets/serializers/ticket/apply_application.py:38
#: tickets/serializers/ticket/common.py:59
#: xpack/plugins/change_auth_plan/serializers/asset.py:67
@@ -634,7 +634,7 @@ msgid "Is active"
msgstr "アクティブです。"
#: assets/models/asset.py:222 assets/models/cluster.py:19
#: assets/models/user.py:240 assets/models/user.py:395
#: assets/models/user.py:240 assets/models/user.py:406
msgid "Admin user"
msgstr "管理ユーザー"
@@ -650,7 +650,7 @@ msgstr "資産番号"
msgid "Labels"
msgstr "ラベル"
#: assets/models/asset.py:229 assets/models/base.py:183
#: assets/models/asset.py:229 assets/models/base.py:185
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:56
#: assets/models/cmd_filter.py:103 assets/models/group.py:21
#: common/db/models.py:114 common/mixins/models.py:49 orgs/models.py:71
@@ -786,32 +786,32 @@ msgstr "成功は"
msgid "Account backup execution"
msgstr "アカウントバックアップの実行"
#: assets/models/base.py:30 assets/tasks/const.py:51 audits/const.py:5
#: assets/models/base.py:29 assets/tasks/const.py:51 audits/const.py:5
#: common/utils/ip/geoip/utils.py:31 common/utils/ip/geoip/utils.py:37
#: common/utils/ip/utils.py:84
msgid "Unknown"
msgstr "不明"
#: assets/models/base.py:31
#: assets/models/base.py:30
msgid "Ok"
msgstr "OK"
#: assets/models/base.py:32 audits/models.py:136
#: assets/models/base.py:31 audits/models.py:136
#: xpack/plugins/change_auth_plan/serializers/app.py:88
#: xpack/plugins/change_auth_plan/serializers/asset.py:199
#: xpack/plugins/cloud/const.py:41
msgid "Failed"
msgstr "失敗しました"
#: assets/models/base.py:38 assets/serializers/domain.py:47
#: assets/models/base.py:37 assets/serializers/domain.py:47
msgid "Connectivity"
msgstr "接続性"
#: assets/models/base.py:40 authentication/models.py:263
#: assets/models/base.py:39 authentication/models.py:263
msgid "Date verified"
msgstr "確認済みの日付"
#: assets/models/base.py:177 assets/serializers/base.py:15
#: assets/models/base.py:179 assets/serializers/base.py:14
#: assets/serializers/base.py:37 assets/serializers/system_user.py:29
#: audits/signal_handlers.py:58 authentication/confirm/password.py:9
#: authentication/forms.py:32
@@ -829,14 +829,14 @@ msgstr "確認済みの日付"
msgid "Password"
msgstr "パスワード"
#: assets/models/base.py:178 assets/serializers/base.py:41
#: assets/models/base.py:180 assets/serializers/base.py:41
#: xpack/plugins/change_auth_plan/models/asset.py:53
#: xpack/plugins/change_auth_plan/models/asset.py:130
#: xpack/plugins/change_auth_plan/models/asset.py:206
msgid "SSH private key"
msgstr "SSH秘密鍵"
#: assets/models/base.py:179 xpack/plugins/change_auth_plan/models/asset.py:56
#: assets/models/base.py:181 xpack/plugins/change_auth_plan/models/asset.py:56
#: xpack/plugins/change_auth_plan/models/asset.py:126
#: xpack/plugins/change_auth_plan/models/asset.py:202
msgid "SSH public key"
@@ -889,7 +889,7 @@ msgstr "デフォルトクラスター"
msgid "User group"
msgstr "ユーザーグループ"
#: assets/models/cmd_filter.py:64 assets/serializers/system_user.py:59
#: assets/models/cmd_filter.py:64 assets/serializers/system_user.py:56
msgid "Command filter"
msgstr "コマンドフィルター"
@@ -954,7 +954,7 @@ msgstr "テストゲートウェイ"
msgid "Unable to connect to port {port} on {ip}"
msgstr "{ip} でポート {port} に接続できません"
#: assets/models/domain.py:134 authentication/middleware.py:75
#: assets/models/domain.py:134 authentication/middleware.py:87
#: xpack/plugins/cloud/providers/fc.py:48
msgid "Authentication failed"
msgstr "認証に失敗しました"
@@ -1015,7 +1015,7 @@ msgstr "フルバリュー"
msgid "Parent key"
msgstr "親キー"
#: assets/models/node.py:566 assets/serializers/system_user.py:267
#: assets/models/node.py:566 assets/serializers/system_user.py:263
#: xpack/plugins/cloud/models.py:95 xpack/plugins/cloud/serializers/task.py:75
msgid "Node"
msgstr "ノード"
@@ -1095,7 +1095,7 @@ msgstr "ユーザースイッチ"
msgid "Switch from"
msgstr "から切り替え"
#: assets/models/user.py:345
#: assets/models/user.py:356
msgid "Can match system user"
msgstr "システムユーザーに一致できます"
@@ -1192,7 +1192,7 @@ msgstr "ssh秘密鍵"
msgid "Key password"
msgstr "キーパスワード"
#: assets/serializers/base.py:58
#: assets/serializers/base.py:58 assets/serializers/utils.py:24
msgid "private key invalid or passphrase error"
msgstr "秘密鍵が無効またはpassphraseエラー"
@@ -1205,7 +1205,7 @@ msgid "Pattern"
msgstr "パターン"
#: assets/serializers/domain.py:14 assets/serializers/label.py:12
#: assets/serializers/system_user.py:63
#: assets/serializers/system_user.py:60
#: perms/serializers/asset/permission.py:49
msgid "Assets amount"
msgstr "資産額"
@@ -1234,86 +1234,81 @@ msgstr "同じレベルのノード名を同じにすることはできません
msgid "SSH key fingerprint"
msgstr "SSHキー指紋"
#: assets/serializers/system_user.py:40
#: perms/serializers/application/permission.py:46
msgid "Apps amount"
msgstr "アプリの量"
#: assets/serializers/system_user.py:62
#: assets/serializers/system_user.py:59
#: perms/serializers/asset/permission.py:50
msgid "Nodes amount"
msgstr "ノード量"
#: assets/serializers/system_user.py:64 assets/serializers/system_user.py:269
#: assets/serializers/system_user.py:61 assets/serializers/system_user.py:265
msgid "Login mode display"
msgstr "ログインモード表示"
#: assets/serializers/system_user.py:66
#: assets/serializers/system_user.py:63
msgid "Ad domain"
msgstr "広告ドメイン"
#: assets/serializers/system_user.py:67
#: assets/serializers/system_user.py:64
msgid "Is asset protocol"
msgstr "資産プロトコルです"
#: assets/serializers/system_user.py:68
#: assets/serializers/system_user.py:65
msgid "Only ssh and automatic login system users are supported"
msgstr "sshと自動ログインシステムのユーザーのみがサポートされています"
#: assets/serializers/system_user.py:108
#: assets/serializers/system_user.py:105
msgid "Username same with user with protocol {} only allow 1"
msgstr "プロトコル {} のユーザーと同じユーザー名は1のみ許可します"
#: assets/serializers/system_user.py:121 common/validators.py:14
#: assets/serializers/system_user.py:118 common/validators.py:14
msgid "Special char not allowed"
msgstr "特別なcharは許可されていません"
#: assets/serializers/system_user.py:131
#: assets/serializers/system_user.py:128
msgid "* Automatic login mode must fill in the username."
msgstr "* 自動ログインモードはユーザー名を入力する必要があります。"
#: assets/serializers/system_user.py:146
#: assets/serializers/system_user.py:143
msgid "Path should starts with /"
msgstr "パスは/で始まる必要があります"
#: assets/serializers/system_user.py:158
#: assets/serializers/system_user.py:155
msgid "Password or private key required"
msgstr "パスワードまたは秘密鍵が必要"
#: assets/serializers/system_user.py:172
#: assets/serializers/system_user.py:169
msgid "Only ssh protocol system users are allowed"
msgstr "Sshプロトコルシステムユーザーのみが許可されています"
#: assets/serializers/system_user.py:176
#: assets/serializers/system_user.py:173
msgid "The protocol must be consistent with the current user: {}"
msgstr "プロトコルは現在のユーザーと一致している必要があります: {}"
#: assets/serializers/system_user.py:180
#: assets/serializers/system_user.py:177
msgid "Only system users with automatic login are allowed"
msgstr "自動ログインを持つシステムユーザーのみが許可されます"
#: assets/serializers/system_user.py:288
#: assets/serializers/system_user.py:284
msgid "System user name"
msgstr "システムユーザー名"
#: assets/serializers/system_user.py:289 orgs/mixins/serializers.py:26
#: assets/serializers/system_user.py:285 orgs/mixins/serializers.py:26
#: rbac/serializers/rolebinding.py:23
msgid "Org name"
msgstr "組織名"
#: assets/serializers/system_user.py:298
#: assets/serializers/system_user.py:294
msgid "Asset hostname"
msgstr "資産ホスト名"
#: assets/serializers/utils.py:11
#: assets/serializers/utils.py:13
msgid "Password can not contains `{{` "
msgstr "パスワードには '{{' を含まない"
#: assets/serializers/utils.py:14
#: assets/serializers/utils.py:16
msgid "Password can not contains `'` "
msgstr "パスワードには `'` を含まない"
#: assets/serializers/utils.py:16
#: assets/serializers/utils.py:18
msgid "Password can not contains `\"` "
msgstr "パスワードには `\"` を含まない"
@@ -1429,6 +1424,10 @@ msgid "For security, do not push user {}"
msgstr "セキュリティのために、ユーザー {} をプッシュしないでください"
#: assets/tasks/utils.py:55
msgid "Asset protocol not support system user protocol, skipped: {}"
msgstr "アセット プロトコルはシステム ユーザー プロトコルをサポートしていません。次をスキップします: {}"
#: assets/tasks/utils.py:59
msgid "No assets matched, stop task"
msgstr "一致する資産がない、タスクを停止"
@@ -1664,7 +1663,8 @@ msgstr "企業微信"
#: audits/signal_handlers.py:62 authentication/views/feishu.py:144
#: authentication/views/login.py:85 notifications/backends/__init__.py:14
#: settings/serializers/auth/feishu.py:10 users/models/user.py:736
#: settings/serializers/auth/feishu.py:10
#: settings/serializers/auth/feishu.py:13 users/models/user.py:736
msgid "FeiShu"
msgstr "本を飛ばす"
@@ -1722,7 +1722,7 @@ msgid "Authentication"
msgstr "認証"
#: authentication/backends/custom.py:58
#: authentication/backends/oauth2/backends.py:158 authentication/models.py:158
#: authentication/backends/oauth2/backends.py:167 authentication/models.py:158
msgid "User invalid, disabled or expired"
msgstr "ユーザーが無効、無効、または期限切れです"
@@ -1937,15 +1937,15 @@ msgstr "本を飛ばすは拘束されていません"
msgid "Your password is invalid"
msgstr "パスワードが無効です"
#: authentication/errors/redirect.py:85 authentication/mixins.py:306
#: authentication/errors/redirect.py:85 authentication/mixins.py:307
msgid "Your password is too simple, please change it for security"
msgstr "パスワードがシンプルすぎるので、セキュリティのために変更してください"
#: authentication/errors/redirect.py:93 authentication/mixins.py:313
#: authentication/errors/redirect.py:93 authentication/mixins.py:314
msgid "You should to change your password before login"
msgstr "ログインする前にパスワードを変更する必要があります"
#: authentication/errors/redirect.py:101 authentication/mixins.py:320
#: authentication/errors/redirect.py:101 authentication/mixins.py:321
msgid "Your password has expired, please reset before logging in"
msgstr ""
"パスワードの有効期限が切れました。ログインする前にリセットしてください。"
@@ -2044,15 +2044,15 @@ msgstr "電話番号を設定して有効にする"
msgid "Clear phone number to disable"
msgstr "無効にする電話番号をクリアする"
#: authentication/middleware.py:76 settings/utils/ldap.py:652
#: authentication/middleware.py:88 settings/utils/ldap.py:652
msgid "Authentication failed (before login check failed): {}"
msgstr "認証に失敗しました (ログインチェックが失敗する前): {}"
#: authentication/mixins.py:256
#: authentication/mixins.py:257
msgid "The MFA type ({}) is not enabled"
msgstr "MFAタイプ ({}) が有効になっていない"
#: authentication/mixins.py:296
#: authentication/mixins.py:297
msgid "Please change your password"
msgstr "パスワードを変更してください"
@@ -2263,7 +2263,7 @@ msgstr "コードエラー"
#: authentication/templates/authentication/_msg_reset_password_code.html:9
#: authentication/templates/authentication/_msg_rest_password_success.html:2
#: authentication/templates/authentication/_msg_rest_public_key_success.html:2
#: jumpserver/conf.py:413 ops/tasks.py:145 ops/tasks.py:148
#: jumpserver/conf.py:417 ops/tasks.py:145 ops/tasks.py:148
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: perms/templates/perms/_msg_permed_items_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:33
@@ -2747,11 +2747,11 @@ msgstr "特殊文字を含むべきではない"
msgid "The mobile phone number format is incorrect"
msgstr "携帯電話番号の形式が正しくありません"
#: jumpserver/conf.py:412
#: jumpserver/conf.py:416
msgid "Create account successfully"
msgstr "アカウントを正常に作成"
#: jumpserver/conf.py:414
#: jumpserver/conf.py:418
msgid "Your account has been created successfully"
msgstr "アカウントが正常に作成されました"
@@ -3198,6 +3198,10 @@ msgstr "ユーザーグループの量"
msgid "System users amount"
msgstr "システムユーザー数"
#: perms/serializers/application/permission.py:46
msgid "Apps amount"
msgstr "アプリの量"
#: perms/serializers/application/permission.py:79
msgid ""
"The application list contains applications that are different from the "
@@ -3603,7 +3607,7 @@ msgstr "CAS"
msgid "Enable CAS Auth"
msgstr "CAS 認証の有効化"
#: settings/serializers/auth/cas.py:13 settings/serializers/auth/oidc.py:49
#: settings/serializers/auth/cas.py:13 settings/serializers/auth/oidc.py:54
msgid "Server url"
msgstr "サービス側アドレス"
@@ -3636,7 +3640,7 @@ msgstr "そうでない場合はユーザーを作成"
msgid "Enable DingTalk Auth"
msgstr "ピン認証の有効化"
#: settings/serializers/auth/feishu.py:14
#: settings/serializers/auth/feishu.py:16
msgid "Enable FeiShu Auth"
msgstr "飛本認証の有効化"
@@ -3723,11 +3727,11 @@ msgstr "クライアントID"
msgid "Client Secret"
msgstr "クライアント秘密"
#: settings/serializers/auth/oauth2.py:40 settings/serializers/auth/oidc.py:63
#: settings/serializers/auth/oauth2.py:40 settings/serializers/auth/oidc.py:68
msgid "Provider auth endpoint"
msgstr "認証エンドポイントアドレス"
#: settings/serializers/auth/oauth2.py:43 settings/serializers/auth/oidc.py:66
#: settings/serializers/auth/oauth2.py:43 settings/serializers/auth/oidc.py:71
msgid "Provider token endpoint"
msgstr "プロバイダートークンエンドポイント"
@@ -3735,15 +3739,15 @@ msgstr "プロバイダートークンエンドポイント"
msgid "Client authentication method"
msgstr "クライアント認証方式"
#: settings/serializers/auth/oauth2.py:50 settings/serializers/auth/oidc.py:72
#: settings/serializers/auth/oauth2.py:50 settings/serializers/auth/oidc.py:77
msgid "Provider userinfo endpoint"
msgstr "プロバイダーuserinfoエンドポイント"
#: settings/serializers/auth/oauth2.py:53 settings/serializers/auth/oidc.py:75
#: settings/serializers/auth/oauth2.py:53 settings/serializers/auth/oidc.py:80
msgid "Provider end session endpoint"
msgstr "プロバイダーのセッション終了エンドポイント"
#: settings/serializers/auth/oauth2.py:60 settings/serializers/auth/oidc.py:93
#: settings/serializers/auth/oauth2.py:60 settings/serializers/auth/oidc.py:98
#: settings/serializers/auth/saml2.py:35
msgid "Always update user"
msgstr "常にユーザーを更新"
@@ -3772,51 +3776,59 @@ msgstr ""
"ユーザー属性マッピングは、OpenIDのユーザー属性をjumpserverユーザーにマッピン"
"グする方法、username, name,emailはjumpserverのユーザーが必要とする属性です"
#: settings/serializers/auth/oidc.py:46
#: settings/serializers/auth/oidc.py:41
msgid "Enable PKCE"
msgstr "启启PKCE"
#: settings/serializers/auth/oidc.py:43
msgid "Code challenge method"
msgstr "Code暗号化方式です"
#: settings/serializers/auth/oidc.py:51
msgid "Use Keycloak"
msgstr "Keycloakを使用する"
#: settings/serializers/auth/oidc.py:52
#: settings/serializers/auth/oidc.py:57
msgid "Realm name"
msgstr "レルム名"
#: settings/serializers/auth/oidc.py:58
#: settings/serializers/auth/oidc.py:63
msgid "Enable OPENID Auth"
msgstr "OIDC認証の有効化"
#: settings/serializers/auth/oidc.py:60
#: settings/serializers/auth/oidc.py:65
msgid "Provider endpoint"
msgstr "プロバイダーエンドポイント"
#: settings/serializers/auth/oidc.py:69
#: settings/serializers/auth/oidc.py:74
msgid "Provider jwks endpoint"
msgstr "プロバイダーjwksエンドポイント"
#: settings/serializers/auth/oidc.py:78
#: settings/serializers/auth/oidc.py:83
msgid "Provider sign alg"
msgstr "プロビダーサインalg"
#: settings/serializers/auth/oidc.py:81
#: settings/serializers/auth/oidc.py:86
msgid "Provider sign key"
msgstr "プロバイダ署名キー"
#: settings/serializers/auth/oidc.py:83
#: settings/serializers/auth/oidc.py:88
msgid "Scopes"
msgstr "スコープ"
#: settings/serializers/auth/oidc.py:85
#: settings/serializers/auth/oidc.py:90
msgid "Id token max age"
msgstr "IDトークンの最大年齢"
#: settings/serializers/auth/oidc.py:88
#: settings/serializers/auth/oidc.py:93
msgid "Id token include claims"
msgstr "IDトークンにはクレームが含まれます"
#: settings/serializers/auth/oidc.py:90
#: settings/serializers/auth/oidc.py:95
msgid "Use state"
msgstr "使用状態"
#: settings/serializers/auth/oidc.py:91
#: settings/serializers/auth/oidc.py:96
msgid "Use nonce"
msgstr "Nonceを使用"
@@ -4731,8 +4743,8 @@ msgstr "期限切れです。"
#, python-format
msgid ""
"\n"
" Your password has expired, please click <a href="
"\"%(user_password_update_url)s\"> this link </a> update password.\n"
" Your password has expired, please click <a "
"href=\"%(user_password_update_url)s\"> this link </a> update password.\n"
" "
msgstr ""
"\n"
@@ -4753,34 +4765,34 @@ msgid ""
" "
msgstr ""
"\n"
" クリックしてください <a href=\"%(user_password_update_url)s"
"\"> リンク </a> パスワードの更新\n"
" クリックしてください <a "
"href=\"%(user_password_update_url)s\"> リンク </a> パスワードの更新\n"
" "
#: templates/_message.html:43
#, python-format
msgid ""
"\n"
" Your information was incomplete. Please click <a href="
"\"%(first_login_url)s\"> this link </a>to complete your information.\n"
" Your information was incomplete. Please click <a "
"href=\"%(first_login_url)s\"> this link </a>to complete your information.\n"
" "
msgstr ""
"\n"
" あなたの情報が不完全なので、クリックしてください。 <a href="
"\"%(first_login_url)s\"> リンク </a> 補完\n"
" あなたの情報が不完全なので、クリックしてください。 <a "
"href=\"%(first_login_url)s\"> リンク </a> 補完\n"
" "
#: templates/_message.html:56
#, python-format
msgid ""
"\n"
" Your ssh public key not set or expired. Please click <a href="
"\"%(user_pubkey_update)s\"> this link </a>to update\n"
" Your ssh public key not set or expired. Please click <a "
"href=\"%(user_pubkey_update)s\"> this link </a>to update\n"
" "
msgstr ""
"\n"
" SSHキーが設定されていないか無効になっている場合は、 <a href="
"\"%(user_pubkey_update)s\"> リンク </a> 更新\n"
" SSHキーが設定されていないか無効になっている場合は、 <a "
"href=\"%(user_pubkey_update)s\"> リンク </a> 更新\n"
" "
#: templates/_mfa_login_field.html:28
@@ -5000,7 +5012,7 @@ msgid "RDP Port"
msgstr "RDP ポート"
#: terminal/models/endpoint.py:27 terminal/models/endpoint.py:95
#: terminal/serializers/endpoint.py:57 terminal/serializers/storage.py:38
#: terminal/serializers/endpoint.py:61 terminal/serializers/storage.py:38
#: terminal/serializers/storage.py:50 terminal/serializers/storage.py:80
#: terminal/serializers/storage.py:90 terminal/serializers/storage.py:98
msgid "Endpoint"
@@ -5038,23 +5050,23 @@ msgstr "リプレイ"
msgid "Date end"
msgstr "終了日"
#: terminal/models/session.py:261
#: terminal/models/session.py:265
msgid "Session record"
msgstr "セッション記録"
#: terminal/models/session.py:263
#: terminal/models/session.py:267
msgid "Can monitor session"
msgstr "セッションを監視できます"
#: terminal/models/session.py:264
#: terminal/models/session.py:268
msgid "Can share session"
msgstr "セッションを共有できます"
#: terminal/models/session.py:265
#: terminal/models/session.py:269
msgid "Can terminate session"
msgstr "セッションを終了できます"
#: terminal/models/session.py:266
#: terminal/models/session.py:270
msgid "Can validate session action perm"
msgstr "セッションアクションのパーマを検証できます"
@@ -5139,15 +5151,15 @@ msgstr "スレッド"
msgid "Boot Time"
msgstr "ブート時間"
#: terminal/models/storage.py:29
#: terminal/models/storage.py:28
msgid "Default storage"
msgstr "デフォルトのストレージ"
#: terminal/models/storage.py:139 terminal/models/terminal.py:109
#: terminal/models/storage.py:141 terminal/models/terminal.py:109
msgid "Command storage"
msgstr "コマンドストレージ"
#: terminal/models/storage.py:199 terminal/models/terminal.py:110
#: terminal/models/storage.py:201 terminal/models/terminal.py:110
msgid "Replay storage"
msgstr "再生ストレージ"
@@ -5191,15 +5203,15 @@ msgstr "レベル"
msgid "Batch danger command alert"
msgstr "一括危険コマンド警告"
#: terminal/serializers/endpoint.py:14
#: terminal/serializers/endpoint.py:15
msgid "Magnus listen db port"
msgstr "Magnus がリッスンするデータベース ポート"
#: terminal/serializers/endpoint.py:17
#: terminal/serializers/endpoint.py:18
msgid "Magnus Listen port range"
msgstr "Magnus がリッスンするポート範囲"
#: terminal/serializers/endpoint.py:19
#: terminal/serializers/endpoint.py:20
msgid ""
"The range of ports that Magnus listens on is modified in the configuration "
"file"
@@ -5207,10 +5219,15 @@ msgstr "Magnus がリッスンするポート範囲を構成ファイルで変
#: terminal/serializers/endpoint.py:51
msgid ""
"If asset IP addresses under different endpoints conflict, use asset labels"
"Format for comma-delimited string, with * indicating a match all. Such as: "
"192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:"
"db8:1a:1110::/64<br>If asset IP addresses under different endpoints "
"conflict, use asset labels"
msgstr ""
"異なるエンドポイントの下に競合するアセットIPがある場合は、アセットタグを使用"
"して実装します"
"コンマ区切り文字列の形式。* はすべて一致することを示します。例: "
"192.168.10.1、192.168.1.0/24、10.1.1.1-10.1.1.20、2001:db8:2de::e13、2001:"
"db8:1a:1110:::/64<br>異なるエンドポイントの下に競合するアセットIPがある場合"
"は、アセットタグを使用して実装します"
#: terminal/serializers/session.py:15 terminal/serializers/session.py:42
msgid "Terminal display"
@@ -5334,7 +5351,7 @@ msgstr "見つかりません"
msgid "view"
msgstr "表示"
#: terminal/utils/db_port_mapper.py:65
#: terminal/utils/db_port_mapper.py:78
msgid ""
"No available port is matched. The number of databases may have exceeded the "
"number of ports open to the database agent service, Contact the "
@@ -5344,7 +5361,7 @@ msgstr ""
"サービスによって開かれたポートの数を超えた可能性があります。さらにポートを開"
"くには、管理者に連絡してください。"
#: terminal/utils/db_port_mapper.py:91
#: terminal/utils/db_port_mapper.py:104
msgid ""
"No ports can be used, check and modify the limit on the number of ports that "
"Magnus listens on in the configuration file."
@@ -5352,7 +5369,7 @@ msgstr ""
"使用できるポートがありません。設定ファイルで Magnus がリッスンするポート数の"
"制限を確認して変更してください. "
#: terminal/utils/db_port_mapper.py:93
#: terminal/utils/db_port_mapper.py:106
msgid "All available port count: {}, Already use port count: {}"
msgstr "使用可能なすべてのポート数: {}、すでに使用しているポート数: {}"
@@ -5444,19 +5461,19 @@ msgstr ""
"チケットのタイトル: {} チケット申請者: {} チケットプロセッサ: {} チケットID: "
"{}"
#: tickets/handlers/base.py:84
#: tickets/handlers/base.py:86
msgid "Change field"
msgstr "フィールドを変更"
#: tickets/handlers/base.py:84
#: tickets/handlers/base.py:86
msgid "Before change"
msgstr "変更前"
#: tickets/handlers/base.py:84
#: tickets/handlers/base.py:86
msgid "After change"
msgstr "変更後"
#: tickets/handlers/base.py:96
#: tickets/handlers/base.py:98
msgid "{} {} the ticket"
msgstr "{} {} チケット"
@@ -7071,3 +7088,9 @@ msgstr "究極のエディション"
#: xpack/plugins/license/models.py:77
msgid "Community edition"
msgstr "コミュニティ版"
#~ msgid ""
#~ "If asset IP addresses under different endpoints conflict, use asset labels"
#~ msgstr ""
#~ "異なるエンドポイントの下に競合するアセットIPがある場合は、アセットタグを使"
#~ "用して実装します"

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b143c62843946c3e18b623d05065f12e9d3c578efe5cd0d2016056d2b8448ae8
size 109495
oid sha256:62e47d2577f103b524a1ae75e3357cdeb5f90d89f89c58a8c8fa8f63d67749f8
size 110097

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-17 17:34+0800\n"
"POT-Creation-Date: 2023-05-08 18:10+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n"
@@ -23,13 +23,13 @@ msgstr "访问控制"
#: acls/models/base.py:25 acls/serializers/login_asset_acl.py:47
#: applications/models/application.py:219 assets/models/asset.py:138
#: assets/models/base.py:175 assets/models/cluster.py:18
#: assets/models/base.py:177 assets/models/cluster.py:18
#: assets/models/cmd_filter.py:27 assets/models/domain.py:23
#: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24
#: orgs/models.py:70 perms/models/base.py:83 rbac/models/role.py:29
#: settings/models.py:33 settings/serializers/sms.py:6
#: terminal/models/endpoint.py:14 terminal/models/endpoint.py:87
#: terminal/models/storage.py:27 terminal/models/task.py:16
#: terminal/models/storage.py:26 terminal/models/task.py:16
#: terminal/models/terminal.py:101 users/forms/profile.py:33
#: users/models/group.py:15 users/models/user.py:673
#: xpack/plugins/cloud/models.py:27
@@ -54,14 +54,14 @@ msgstr "激活中"
#: acls/models/base.py:32 applications/models/application.py:232
#: assets/models/asset.py:143 assets/models/asset.py:231
#: assets/models/backup.py:54 assets/models/base.py:180
#: assets/models/backup.py:54 assets/models/base.py:182
#: assets/models/cluster.py:29 assets/models/cmd_filter.py:52
#: assets/models/cmd_filter.py:100 assets/models/domain.py:24
#: assets/models/domain.py:65 assets/models/group.py:23
#: assets/models/label.py:23 ops/models/adhoc.py:38 orgs/models.py:73
#: perms/models/base.py:93 rbac/models/role.py:37 settings/models.py:38
#: terminal/models/endpoint.py:22 terminal/models/endpoint.py:97
#: terminal/models/storage.py:30 terminal/models/terminal.py:115
#: terminal/models/storage.py:29 terminal/models/terminal.py:115
#: tickets/models/comment.py:32 tickets/models/ticket/general.py:288
#: users/models/group.py:16 users/models/user.py:712
#: xpack/plugins/change_auth_plan/models/base.py:44
@@ -130,7 +130,7 @@ msgstr "系统用户"
#: assets/models/asset.py:386 assets/models/authbook.py:19
#: assets/models/backup.py:31 assets/models/cmd_filter.py:42
#: assets/models/gathered_user.py:14 assets/serializers/label.py:30
#: assets/serializers/system_user.py:268 audits/models.py:40
#: assets/serializers/system_user.py:264 audits/models.py:40
#: authentication/models.py:66 authentication/models.py:90
#: perms/models/asset_permission.py:23 terminal/backends/command/models.py:21
#: terminal/backends/command/serializers.py:14 terminal/models/session.py:47
@@ -154,7 +154,7 @@ msgid "Format for comma-delimited string, with * indicating a match all. "
msgstr "格式为逗号分隔的字符串, * 表示匹配所有. "
#: acls/serializers/login_acl.py:15 acls/serializers/login_asset_acl.py:17
#: acls/serializers/login_asset_acl.py:51 assets/models/base.py:176
#: acls/serializers/login_asset_acl.py:51 assets/models/base.py:178
#: assets/models/gathered_user.py:15 audits/models.py:139
#: authentication/forms.py:25 authentication/forms.py:27
#: authentication/models.py:260
@@ -184,7 +184,7 @@ msgstr ""
#: authentication/templates/authentication/_msg_oauth_bind.html:12
#: authentication/templates/authentication/_msg_rest_password_success.html:8
#: authentication/templates/authentication/_msg_rest_public_key_success.html:8
#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:54
#: settings/serializers/terminal.py:10 terminal/serializers/endpoint.py:58
msgid "IP"
msgstr "IP"
@@ -264,7 +264,7 @@ msgid "Application"
msgstr "应用程序"
#: applications/models/account.py:15 assets/models/authbook.py:20
#: assets/models/cmd_filter.py:46 assets/models/user.py:343 audits/models.py:41
#: assets/models/cmd_filter.py:46 assets/models/user.py:354 audits/models.py:41
#: authentication/models.py:83 perms/models/application_permission.py:33
#: perms/models/asset_permission.py:25 terminal/backends/command/models.py:22
#: terminal/backends/command/serializers.py:36 terminal/models/session.py:49
@@ -275,7 +275,7 @@ msgid "System user"
msgstr "系统用户"
#: applications/models/account.py:17 assets/models/authbook.py:21
#: settings/serializers/auth/cas.py:20
#: settings/serializers/auth/cas.py:20 settings/serializers/auth/feishu.py:20
msgid "Version"
msgstr "版本"
@@ -305,7 +305,7 @@ msgstr "类别"
#: assets/models/cmd_filter.py:86 assets/models/user.py:251
#: authentication/models.py:70 perms/models/application_permission.py:24
#: perms/serializers/application/user_permission.py:34
#: terminal/models/storage.py:59 terminal/models/storage.py:145
#: terminal/models/storage.py:58 terminal/models/storage.py:147
#: tickets/models/comment.py:26 tickets/models/flow.py:57
#: tickets/models/ticket/apply_application.py:18
#: tickets/models/ticket/general.py:273
@@ -348,7 +348,7 @@ msgid "Type display"
msgstr "类型名称"
#: applications/serializers/application.py:105 assets/models/asset.py:230
#: assets/models/base.py:181 assets/models/cluster.py:26
#: assets/models/base.py:183 assets/models/cluster.py:26
#: assets/models/cmd_filter.py:53 assets/models/domain.py:26
#: assets/models/gathered_user.py:19 assets/models/group.py:22
#: assets/models/label.py:25 assets/serializers/account.py:18
@@ -362,7 +362,7 @@ msgstr "类型名称"
msgid "Date created"
msgstr "创建日期"
#: applications/serializers/application.py:106 assets/models/base.py:182
#: applications/serializers/application.py:106 assets/models/base.py:184
#: assets/models/cmd_filter.py:54 assets/models/gathered_user.py:20
#: assets/serializers/account.py:21 assets/serializers/cmd_filter.py:29
#: assets/serializers/cmd_filter.py:49 common/db/models.py:117
@@ -440,7 +440,7 @@ msgid "Application path"
msgstr "应用路径"
#: applications/serializers/attrs/application_category/remote_app.py:44
#: assets/serializers/system_user.py:167
#: assets/serializers/system_user.py:164
#: tickets/serializers/ticket/apply_application.py:38
#: tickets/serializers/ticket/common.py:59
#: xpack/plugins/change_auth_plan/serializers/asset.py:67
@@ -627,7 +627,7 @@ msgid "Is active"
msgstr "激活"
#: assets/models/asset.py:222 assets/models/cluster.py:19
#: assets/models/user.py:240 assets/models/user.py:395
#: assets/models/user.py:240 assets/models/user.py:406
msgid "Admin user"
msgstr "特权用户"
@@ -643,7 +643,7 @@ msgstr "资产编号"
msgid "Labels"
msgstr "标签管理"
#: assets/models/asset.py:229 assets/models/base.py:183
#: assets/models/asset.py:229 assets/models/base.py:185
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:56
#: assets/models/cmd_filter.py:103 assets/models/group.py:21
#: common/db/models.py:114 common/mixins/models.py:49 orgs/models.py:71
@@ -779,32 +779,32 @@ msgstr "是否成功"
msgid "Account backup execution"
msgstr "账号备份执行"
#: assets/models/base.py:30 assets/tasks/const.py:51 audits/const.py:5
#: assets/models/base.py:29 assets/tasks/const.py:51 audits/const.py:5
#: common/utils/ip/geoip/utils.py:31 common/utils/ip/geoip/utils.py:37
#: common/utils/ip/utils.py:84
msgid "Unknown"
msgstr "未知"
#: assets/models/base.py:31
#: assets/models/base.py:30
msgid "Ok"
msgstr "成功"
#: assets/models/base.py:32 audits/models.py:136
#: assets/models/base.py:31 audits/models.py:136
#: xpack/plugins/change_auth_plan/serializers/app.py:88
#: xpack/plugins/change_auth_plan/serializers/asset.py:199
#: xpack/plugins/cloud/const.py:41
msgid "Failed"
msgstr "失败"
#: assets/models/base.py:38 assets/serializers/domain.py:47
#: assets/models/base.py:37 assets/serializers/domain.py:47
msgid "Connectivity"
msgstr "可连接性"
#: assets/models/base.py:40 authentication/models.py:263
#: assets/models/base.py:39 authentication/models.py:263
msgid "Date verified"
msgstr "校验日期"
#: assets/models/base.py:177 assets/serializers/base.py:15
#: assets/models/base.py:179 assets/serializers/base.py:14
#: assets/serializers/base.py:37 assets/serializers/system_user.py:29
#: audits/signal_handlers.py:58 authentication/confirm/password.py:9
#: authentication/forms.py:32
@@ -822,14 +822,14 @@ msgstr "校验日期"
msgid "Password"
msgstr "密码"
#: assets/models/base.py:178 assets/serializers/base.py:41
#: assets/models/base.py:180 assets/serializers/base.py:41
#: xpack/plugins/change_auth_plan/models/asset.py:53
#: xpack/plugins/change_auth_plan/models/asset.py:130
#: xpack/plugins/change_auth_plan/models/asset.py:206
msgid "SSH private key"
msgstr "SSH密钥"
#: assets/models/base.py:179 xpack/plugins/change_auth_plan/models/asset.py:56
#: assets/models/base.py:181 xpack/plugins/change_auth_plan/models/asset.py:56
#: xpack/plugins/change_auth_plan/models/asset.py:126
#: xpack/plugins/change_auth_plan/models/asset.py:202
msgid "SSH public key"
@@ -882,7 +882,7 @@ msgstr "默认Cluster"
msgid "User group"
msgstr "用户组"
#: assets/models/cmd_filter.py:64 assets/serializers/system_user.py:59
#: assets/models/cmd_filter.py:64 assets/serializers/system_user.py:56
msgid "Command filter"
msgstr "命令过滤器"
@@ -947,7 +947,7 @@ msgstr "测试网关"
msgid "Unable to connect to port {port} on {ip}"
msgstr "无法连接到 {ip} 上的端口 {port}"
#: assets/models/domain.py:134 authentication/middleware.py:75
#: assets/models/domain.py:134 authentication/middleware.py:87
#: xpack/plugins/cloud/providers/fc.py:48
msgid "Authentication failed"
msgstr "认证失败"
@@ -1008,7 +1008,7 @@ msgstr "全称"
msgid "Parent key"
msgstr "ssh私钥"
#: assets/models/node.py:566 assets/serializers/system_user.py:267
#: assets/models/node.py:566 assets/serializers/system_user.py:263
#: xpack/plugins/cloud/models.py:95 xpack/plugins/cloud/serializers/task.py:75
msgid "Node"
msgstr "节点"
@@ -1088,7 +1088,7 @@ msgstr "用户切换"
msgid "Switch from"
msgstr "切换自"
#: assets/models/user.py:345
#: assets/models/user.py:356
msgid "Can match system user"
msgstr "可以匹配系统用户"
@@ -1182,7 +1182,7 @@ msgstr "ssh私钥"
msgid "Key password"
msgstr "密钥密码"
#: assets/serializers/base.py:58
#: assets/serializers/base.py:58 assets/serializers/utils.py:24
msgid "private key invalid or passphrase error"
msgstr "密钥不合法或密钥密码错误"
@@ -1195,7 +1195,7 @@ msgid "Pattern"
msgstr "模式"
#: assets/serializers/domain.py:14 assets/serializers/label.py:12
#: assets/serializers/system_user.py:63
#: assets/serializers/system_user.py:60
#: perms/serializers/asset/permission.py:49
msgid "Assets amount"
msgstr "资产数量"
@@ -1224,86 +1224,81 @@ msgstr "同级别节点名字不能重复"
msgid "SSH key fingerprint"
msgstr "密钥指纹"
#: assets/serializers/system_user.py:40
#: perms/serializers/application/permission.py:46
msgid "Apps amount"
msgstr "应用数量"
#: assets/serializers/system_user.py:62
#: assets/serializers/system_user.py:59
#: perms/serializers/asset/permission.py:50
msgid "Nodes amount"
msgstr "节点数量"
#: assets/serializers/system_user.py:64 assets/serializers/system_user.py:269
#: assets/serializers/system_user.py:61 assets/serializers/system_user.py:265
msgid "Login mode display"
msgstr "认证方式名称"
#: assets/serializers/system_user.py:66
#: assets/serializers/system_user.py:63
msgid "Ad domain"
msgstr "Ad 网域"
#: assets/serializers/system_user.py:67
#: assets/serializers/system_user.py:64
msgid "Is asset protocol"
msgstr "资产协议"
#: assets/serializers/system_user.py:68
#: assets/serializers/system_user.py:65
msgid "Only ssh and automatic login system users are supported"
msgstr "仅支持ssh协议和自动登录的系统用户"
#: assets/serializers/system_user.py:108
#: assets/serializers/system_user.py:105
msgid "Username same with user with protocol {} only allow 1"
msgstr "用户名和用户相同的一种协议只允许存在一个"
#: assets/serializers/system_user.py:121 common/validators.py:14
#: assets/serializers/system_user.py:118 common/validators.py:14
msgid "Special char not allowed"
msgstr "不能包含特殊字符"
#: assets/serializers/system_user.py:131
#: assets/serializers/system_user.py:128
msgid "* Automatic login mode must fill in the username."
msgstr "自动登录模式,必须填写用户名"
#: assets/serializers/system_user.py:146
#: assets/serializers/system_user.py:143
msgid "Path should starts with /"
msgstr "路径应该以 / 开头"
#: assets/serializers/system_user.py:158
#: assets/serializers/system_user.py:155
msgid "Password or private key required"
msgstr "密码或密钥密码需要一个"
#: assets/serializers/system_user.py:172
#: assets/serializers/system_user.py:169
msgid "Only ssh protocol system users are allowed"
msgstr "仅允许ssh协议的系统用户"
#: assets/serializers/system_user.py:176
#: assets/serializers/system_user.py:173
msgid "The protocol must be consistent with the current user: {}"
msgstr "协议必须和当前用户保持一致: {}"
#: assets/serializers/system_user.py:180
#: assets/serializers/system_user.py:177
msgid "Only system users with automatic login are allowed"
msgstr "仅允许自动登录的系统用户"
#: assets/serializers/system_user.py:288
#: assets/serializers/system_user.py:284
msgid "System user name"
msgstr "系统用户名称"
#: assets/serializers/system_user.py:289 orgs/mixins/serializers.py:26
#: assets/serializers/system_user.py:285 orgs/mixins/serializers.py:26
#: rbac/serializers/rolebinding.py:23
msgid "Org name"
msgstr "组织名称"
#: assets/serializers/system_user.py:298
#: assets/serializers/system_user.py:294
msgid "Asset hostname"
msgstr "资产主机名"
#: assets/serializers/utils.py:11
#: assets/serializers/utils.py:13
msgid "Password can not contains `{{` "
msgstr "密码不能包含 `{{` 字符"
#: assets/serializers/utils.py:14
#: assets/serializers/utils.py:16
msgid "Password can not contains `'` "
msgstr "密码不能包含 `'` 字符"
#: assets/serializers/utils.py:16
#: assets/serializers/utils.py:18
msgid "Password can not contains `\"` "
msgstr "密码不能包含 `\"` 字符"
@@ -1415,6 +1410,10 @@ msgid "For security, do not push user {}"
msgstr "为了安全,禁止推送用户 {}"
#: assets/tasks/utils.py:55
msgid "Asset protocol not support system user protocol, skipped: {}"
msgstr "资产协议不支持系统用户协议,跳过: {}"
#: assets/tasks/utils.py:59
msgid "No assets matched, stop task"
msgstr "没有匹配到资产,结束任务"
@@ -1650,7 +1649,8 @@ msgstr "企业微信"
#: audits/signal_handlers.py:62 authentication/views/feishu.py:144
#: authentication/views/login.py:85 notifications/backends/__init__.py:14
#: settings/serializers/auth/feishu.py:10 users/models/user.py:736
#: settings/serializers/auth/feishu.py:10
#: settings/serializers/auth/feishu.py:13 users/models/user.py:736
msgid "FeiShu"
msgstr "飞书"
@@ -1706,7 +1706,7 @@ msgid "Authentication"
msgstr "认证"
#: authentication/backends/custom.py:58
#: authentication/backends/oauth2/backends.py:158 authentication/models.py:158
#: authentication/backends/oauth2/backends.py:167 authentication/models.py:158
msgid "User invalid, disabled or expired"
msgstr "用户无效,已禁用或已过期"
@@ -1913,15 +1913,15 @@ msgstr "没有绑定飞书"
msgid "Your password is invalid"
msgstr "您的密码无效"
#: authentication/errors/redirect.py:85 authentication/mixins.py:306
#: authentication/errors/redirect.py:85 authentication/mixins.py:307
msgid "Your password is too simple, please change it for security"
msgstr "你的密码过于简单,为了安全,请修改"
#: authentication/errors/redirect.py:93 authentication/mixins.py:313
#: authentication/errors/redirect.py:93 authentication/mixins.py:314
msgid "You should to change your password before login"
msgstr "登录完成前,请先修改密码"
#: authentication/errors/redirect.py:101 authentication/mixins.py:320
#: authentication/errors/redirect.py:101 authentication/mixins.py:321
msgid "Your password has expired, please reset before logging in"
msgstr "您的密码已过期,先修改再登录"
@@ -2018,15 +2018,15 @@ msgstr "设置手机号码启用"
msgid "Clear phone number to disable"
msgstr "清空手机号码禁用"
#: authentication/middleware.py:76 settings/utils/ldap.py:652
#: authentication/middleware.py:88 settings/utils/ldap.py:652
msgid "Authentication failed (before login check failed): {}"
msgstr "认证失败(登录前检查失败): {}"
#: authentication/mixins.py:256
#: authentication/mixins.py:257
msgid "The MFA type ({}) is not enabled"
msgstr "该 MFA ({}) 方式没有启用"
#: authentication/mixins.py:296
#: authentication/mixins.py:297
msgid "Please change your password"
msgstr "请修改密码"
@@ -2233,7 +2233,7 @@ msgstr "代码错误"
#: authentication/templates/authentication/_msg_reset_password_code.html:9
#: authentication/templates/authentication/_msg_rest_password_success.html:2
#: authentication/templates/authentication/_msg_rest_public_key_success.html:2
#: jumpserver/conf.py:413 ops/tasks.py:145 ops/tasks.py:148
#: jumpserver/conf.py:417 ops/tasks.py:145 ops/tasks.py:148
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: perms/templates/perms/_msg_permed_items_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:33
@@ -2708,11 +2708,11 @@ msgstr "不能包含特殊字符"
msgid "The mobile phone number format is incorrect"
msgstr "手机号格式不正确"
#: jumpserver/conf.py:412
#: jumpserver/conf.py:416
msgid "Create account successfully"
msgstr "创建账号成功"
#: jumpserver/conf.py:414
#: jumpserver/conf.py:418
msgid "Your account has been created successfully"
msgstr "你的账号已创建成功"
@@ -3153,6 +3153,10 @@ msgstr "用户组数量"
msgid "System users amount"
msgstr "系统用户数量"
#: perms/serializers/application/permission.py:46
msgid "Apps amount"
msgstr "应用数量"
#: perms/serializers/application/permission.py:79
msgid ""
"The application list contains applications that are different from the "
@@ -3555,7 +3559,7 @@ msgstr "CAS"
msgid "Enable CAS Auth"
msgstr "启用 CAS 认证"
#: settings/serializers/auth/cas.py:13 settings/serializers/auth/oidc.py:49
#: settings/serializers/auth/cas.py:13 settings/serializers/auth/oidc.py:54
msgid "Server url"
msgstr "服务端地址"
@@ -3588,7 +3592,7 @@ msgstr "创建用户(如果不存在)"
msgid "Enable DingTalk Auth"
msgstr "启用钉钉认证"
#: settings/serializers/auth/feishu.py:14
#: settings/serializers/auth/feishu.py:16
msgid "Enable FeiShu Auth"
msgstr "启用飞书认证"
@@ -3675,11 +3679,11 @@ msgstr "客户端 ID"
msgid "Client Secret"
msgstr "客户端密钥"
#: settings/serializers/auth/oauth2.py:40 settings/serializers/auth/oidc.py:63
#: settings/serializers/auth/oauth2.py:40 settings/serializers/auth/oidc.py:68
msgid "Provider auth endpoint"
msgstr "授权端点地址"
#: settings/serializers/auth/oauth2.py:43 settings/serializers/auth/oidc.py:66
#: settings/serializers/auth/oauth2.py:43 settings/serializers/auth/oidc.py:71
msgid "Provider token endpoint"
msgstr "token 端点地址"
@@ -3687,15 +3691,15 @@ msgstr "token 端点地址"
msgid "Client authentication method"
msgstr "客户端认证方式"
#: settings/serializers/auth/oauth2.py:50 settings/serializers/auth/oidc.py:72
#: settings/serializers/auth/oauth2.py:50 settings/serializers/auth/oidc.py:77
msgid "Provider userinfo endpoint"
msgstr "用户信息端点地址"
#: settings/serializers/auth/oauth2.py:53 settings/serializers/auth/oidc.py:75
#: settings/serializers/auth/oauth2.py:53 settings/serializers/auth/oidc.py:80
msgid "Provider end session endpoint"
msgstr "注销会话端点地址"
#: settings/serializers/auth/oauth2.py:60 settings/serializers/auth/oidc.py:93
#: settings/serializers/auth/oauth2.py:60 settings/serializers/auth/oidc.py:98
#: settings/serializers/auth/saml2.py:35
msgid "Always update user"
msgstr "总是更新用户信息"
@@ -3724,51 +3728,59 @@ msgstr ""
"用户属性映射代表怎样将OpenID中用户属性映射到jumpserver用户上username, name,"
"email 是jumpserver的用户需要属性"
#: settings/serializers/auth/oidc.py:46
#: settings/serializers/auth/oidc.py:41
msgid "Enable PKCE"
msgstr "启用 PKCE"
#: settings/serializers/auth/oidc.py:43
msgid "Code challenge method"
msgstr "Code加密方式"
#: settings/serializers/auth/oidc.py:51
msgid "Use Keycloak"
msgstr "使用 Keycloak"
#: settings/serializers/auth/oidc.py:52
#: settings/serializers/auth/oidc.py:57
msgid "Realm name"
msgstr "域"
#: settings/serializers/auth/oidc.py:58
#: settings/serializers/auth/oidc.py:63
msgid "Enable OPENID Auth"
msgstr "启用 OIDC 认证"
#: settings/serializers/auth/oidc.py:60
#: settings/serializers/auth/oidc.py:65
msgid "Provider endpoint"
msgstr "端点地址"
#: settings/serializers/auth/oidc.py:69
#: settings/serializers/auth/oidc.py:74
msgid "Provider jwks endpoint"
msgstr "jwks 端点地址"
#: settings/serializers/auth/oidc.py:78
#: settings/serializers/auth/oidc.py:83
msgid "Provider sign alg"
msgstr "签名算法"
#: settings/serializers/auth/oidc.py:81
#: settings/serializers/auth/oidc.py:86
msgid "Provider sign key"
msgstr "签名 Key"
#: settings/serializers/auth/oidc.py:83
#: settings/serializers/auth/oidc.py:88
msgid "Scopes"
msgstr "连接范围"
#: settings/serializers/auth/oidc.py:85
#: settings/serializers/auth/oidc.py:90
msgid "Id token max age"
msgstr "令牌有效时间"
#: settings/serializers/auth/oidc.py:88
#: settings/serializers/auth/oidc.py:93
msgid "Id token include claims"
msgstr "声明"
#: settings/serializers/auth/oidc.py:90
#: settings/serializers/auth/oidc.py:95
msgid "Use state"
msgstr "使用状态"
#: settings/serializers/auth/oidc.py:91
#: settings/serializers/auth/oidc.py:96
msgid "Use nonce"
msgstr "临时使用"
@@ -4652,13 +4664,13 @@ msgstr "过期。"
#, python-format
msgid ""
"\n"
" Your password has expired, please click <a href="
"\"%(user_password_update_url)s\"> this link </a> update password.\n"
" Your password has expired, please click <a "
"href=\"%(user_password_update_url)s\"> this link </a> update password.\n"
" "
msgstr ""
"\n"
" 您的密码已经过期,请点击 <a href="
"\"%(user_password_update_url)s\"> 链接 </a> 更新密码\n"
" 您的密码已经过期,请点击 <a "
"href=\"%(user_password_update_url)s\"> 链接 </a> 更新密码\n"
" "
#: templates/_message.html:30
@@ -4682,8 +4694,8 @@ msgstr ""
#, python-format
msgid ""
"\n"
" Your information was incomplete. Please click <a href="
"\"%(first_login_url)s\"> this link </a>to complete your information.\n"
" Your information was incomplete. Please click <a "
"href=\"%(first_login_url)s\"> this link </a>to complete your information.\n"
" "
msgstr ""
"\n"
@@ -4695,13 +4707,13 @@ msgstr ""
#, python-format
msgid ""
"\n"
" Your ssh public key not set or expired. Please click <a href="
"\"%(user_pubkey_update)s\"> this link </a>to update\n"
" Your ssh public key not set or expired. Please click <a "
"href=\"%(user_pubkey_update)s\"> this link </a>to update\n"
" "
msgstr ""
"\n"
" 您的SSH密钥没有设置或已失效请点击 <a href="
"\"%(user_pubkey_update)s\"> 链接 </a> 更新\n"
" 您的SSH密钥没有设置或已失效请点击 <a "
"href=\"%(user_pubkey_update)s\"> 链接 </a> 更新\n"
" "
#: templates/_mfa_login_field.html:28
@@ -4914,7 +4926,7 @@ msgid "RDP Port"
msgstr "RDP 端口"
#: terminal/models/endpoint.py:27 terminal/models/endpoint.py:95
#: terminal/serializers/endpoint.py:57 terminal/serializers/storage.py:38
#: terminal/serializers/endpoint.py:61 terminal/serializers/storage.py:38
#: terminal/serializers/storage.py:50 terminal/serializers/storage.py:80
#: terminal/serializers/storage.py:90 terminal/serializers/storage.py:98
msgid "Endpoint"
@@ -4952,23 +4964,23 @@ msgstr "回放"
msgid "Date end"
msgstr "结束日期"
#: terminal/models/session.py:261
#: terminal/models/session.py:265
msgid "Session record"
msgstr "会话记录"
#: terminal/models/session.py:263
#: terminal/models/session.py:267
msgid "Can monitor session"
msgstr "可以监控会话"
#: terminal/models/session.py:264
#: terminal/models/session.py:268
msgid "Can share session"
msgstr "可以分享会话"
#: terminal/models/session.py:265
#: terminal/models/session.py:269
msgid "Can terminate session"
msgstr "可以终断会话"
#: terminal/models/session.py:266
#: terminal/models/session.py:270
msgid "Can validate session action perm"
msgstr "可以验证会话动作权限"
@@ -5053,15 +5065,15 @@ msgstr "线程数"
msgid "Boot Time"
msgstr "运行时间"
#: terminal/models/storage.py:29
#: terminal/models/storage.py:28
msgid "Default storage"
msgstr "默认存储"
#: terminal/models/storage.py:139 terminal/models/terminal.py:109
#: terminal/models/storage.py:141 terminal/models/terminal.py:109
msgid "Command storage"
msgstr "命令存储"
#: terminal/models/storage.py:199 terminal/models/terminal.py:110
#: terminal/models/storage.py:201 terminal/models/terminal.py:110
msgid "Replay storage"
msgstr "录像存储"
@@ -5105,15 +5117,15 @@ msgstr "级别"
msgid "Batch danger command alert"
msgstr "批量危险命令告警"
#: terminal/serializers/endpoint.py:14
#: terminal/serializers/endpoint.py:15
msgid "Magnus listen db port"
msgstr "Magnus 监听的数据库端口"
#: terminal/serializers/endpoint.py:17
#: terminal/serializers/endpoint.py:18
msgid "Magnus Listen port range"
msgstr "Magnus 监听的端口范围"
#: terminal/serializers/endpoint.py:19
#: terminal/serializers/endpoint.py:20
msgid ""
"The range of ports that Magnus listens on is modified in the configuration "
"file"
@@ -5121,8 +5133,14 @@ msgstr "请在配置文件中修改 Magnus 监听的端口范围"
#: terminal/serializers/endpoint.py:51
msgid ""
"If asset IP addresses under different endpoints conflict, use asset labels"
msgstr "如果不同端点下的资产 IP 有冲突,使用资产标签实现"
"Format for comma-delimited string, with * indicating a match all. Such as: "
"192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:"
"db8:1a:1110::/64<br>If asset IP addresses under different endpoints "
"conflict, use asset labels"
msgstr ""
"格式为逗号分隔的字符串, * 表示匹配所有。例如: 192.168.10.1, 192.168.1.0/24, "
"10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64<br>如果不同端点"
"下的资产 IP 有冲突,使用资产标签实现"
#: terminal/serializers/session.py:15 terminal/serializers/session.py:42
msgid "Terminal display"
@@ -5246,7 +5264,7 @@ msgstr "没有发现"
msgid "view"
msgstr "查看"
#: terminal/utils/db_port_mapper.py:65
#: terminal/utils/db_port_mapper.py:78
msgid ""
"No available port is matched. The number of databases may have exceeded the "
"number of ports open to the database agent service, Contact the "
@@ -5255,13 +5273,13 @@ msgstr ""
"未匹配到可用端口,数据库的数量可能已经超过数据库代理服务开放的端口数量,请联"
"系管理员开放更多端口。"
#: terminal/utils/db_port_mapper.py:91
#: terminal/utils/db_port_mapper.py:104
msgid ""
"No ports can be used, check and modify the limit on the number of ports that "
"Magnus listens on in the configuration file."
msgstr "没有端口可以使用,检查并修改配置文件中 Magnus 监听的端口数量限制。"
#: terminal/utils/db_port_mapper.py:93
#: terminal/utils/db_port_mapper.py:106
msgid "All available port count: {}, Already use port count: {}"
msgstr "所有可用端口数量:{},已使用端口数量:{}"
@@ -5351,19 +5369,19 @@ msgid ""
msgstr ""
"通过工单创建, 工单标题: {}, 工单申请人: {}, 工单处理人: {}, 工单 ID: {}"
#: tickets/handlers/base.py:84
#: tickets/handlers/base.py:86
msgid "Change field"
msgstr "变更字段"
#: tickets/handlers/base.py:84
#: tickets/handlers/base.py:86
msgid "Before change"
msgstr "变更前"
#: tickets/handlers/base.py:84
#: tickets/handlers/base.py:86
msgid "After change"
msgstr "变更后"
#: tickets/handlers/base.py:96
#: tickets/handlers/base.py:98
msgid "{} {} the ticket"
msgstr "{} {} 工单"
@@ -6961,3 +6979,7 @@ msgstr "旗舰版"
#: xpack/plugins/license/models.py:77
msgid "Community edition"
msgstr "社区版"
#~ msgid ""
#~ "If asset IP addresses under different endpoints conflict, use asset labels"
#~ msgstr "如果不同端点下的资产 IP 有冲突,使用资产标签实现"

View File

@@ -82,7 +82,7 @@ class CeleryResultApi(generics.RetrieveAPIView):
def get_object(self):
pk = self.kwargs.get('pk')
return AsyncResult(pk)
return AsyncResult(str(pk))
class CeleryPeriodTaskViewSet(CommonApiMixin, viewsets.ModelViewSet):

View File

@@ -2,9 +2,9 @@
#
from django.conf import settings
from .ansible.inventory import BaseInventory
from common.utils import get_logger
from .ansible.inventory import BaseInventory
__all__ = [
'JMSInventory', 'JMSCustomInventory',
@@ -110,7 +110,10 @@ class JMSInventory(JMSBaseInventory):
if self.system_user:
self.system_user.load_asset_special_auth(asset=asset, username=self.run_as)
return self.system_user._to_secret_json()
info = self.system_user._to_secret_json()
if self.run_as:
info['username'] = self.run_as
return info
else:
return {}

View File

@@ -9,7 +9,13 @@ __all__ = ['FeiShuSettingSerializer']
class FeiShuSettingSerializer(serializers.Serializer):
PREFIX_TITLE = '%s-%s' % (_('Authentication'), _('FeiShu'))
VERSION_CHOICES = (
('feishu', _('FeiShu')),
('lark', 'Lark')
)
AUTH_FEISHU = serializers.BooleanField(default=False, label=_('Enable FeiShu Auth'))
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'))
FEISHU_VERSION = serializers.ChoiceField(
choices=VERSION_CHOICES, default='feishu', label=_('Version')
)

View File

@@ -38,6 +38,11 @@ class CommonSettingSerializer(serializers.Serializer):
help_text=_('User attr map present how to map OpenID user attr to '
'jumpserver, username,name,email is jumpserver attr')
)
AUTH_OPENID_PKCE = serializers.BooleanField(required=False, label=_('Enable PKCE'))
AUTH_OPENID_CODE_CHALLENGE_METHOD = serializers.ChoiceField(
default='S256', label=_('Code challenge method'),
choices=(('S256', 'HS256'), ('plain', 'Plain'))
)
class KeycloakSettingSerializer(CommonSettingSerializer):

View File

@@ -118,9 +118,13 @@ class Session(OrgModelMixin):
def find_ok_relative_path_in_storage(self, storage):
session_paths = self.get_all_possible_relative_path()
for rel_path in session_paths:
if storage.exists(rel_path):
return rel_path
# storage 为多个外部存储时, 可能会因部分不可用,
# 抛出异常, 影响录像的获取
try:
if storage.exists(rel_path):
return rel_path
except:
pass
@property
def asset_obj(self):
return Asset.objects.get(id=self.asset_id)

View File

@@ -1,6 +1,7 @@
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _
from common.drf.serializers import BulkModelSerializer
from common.utils import lazyproperty
from acls.serializers.rules import ip_group_child_validator, ip_group_help_text
from ..utils import db_port_manager
from ..models import Endpoint, EndpointRule
@@ -46,9 +47,12 @@ class EndpointSerializer(BulkModelSerializer):
class EndpointRuleSerializer(BulkModelSerializer):
_ip_group_help_text = '{} <br> {}'.format(
ip_group_help_text,
_('If asset IP addresses under different endpoints conflict, use asset labels')
_ip_group_help_text = _(
'Format for comma-delimited string, with * indicating a match all. '
'Such as: '
'192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64'
'<br>'
'If asset IP addresses under different endpoints conflict, use asset labels'
)
ip_group = serializers.ListField(
default=['*'], label=_('IP'), help_text=_ip_group_help_text,

View File

@@ -16,10 +16,10 @@ logger = get_logger(__file__)
@receiver(django_ready)
def init_db_port_mapper(sender, **kwargs):
def check_db_port_mapper(sender, **kwargs):
logger.info('Init db port mapper')
try:
db_port_manager.init()
db_port_manager.check()
except (ProgrammingError,) as e:
pass

View File

@@ -35,9 +35,22 @@ class DBPortManager(object):
def magnus_listen_port_range(self):
return settings.MAGNUS_PORTS
def init(self):
@staticmethod
def fetch_dbs():
with tmp_to_root_org():
db_ids = Application.objects.filter(category=AppCategory.db).values_list('id', flat=True)
dbs = Application.objects.filter(category=AppCategory.db)
return dbs
def check(self):
dbs = self.fetch_dbs()
for db in dbs:
port = self.get_port_by_db(db, raise_exception=False)
if not port:
self.add(db)
def init(self):
dbs = self.fetch_dbs()
db_ids = dbs.values_list('id', flat=True)
db_ids = [str(i) for i in db_ids]
mapper = dict(zip(self.all_available_ports, list(db_ids)))
self.set_mapper(mapper)

View File

@@ -1,3 +1,5 @@
from html import escape
from django.utils.translation import ugettext as _
from django.template.loader import render_to_string
@@ -96,11 +98,19 @@ class BaseHandler:
approve_info = _('{} {} the ticket').format(user_display, state_display)
context = self._diff_prev_approve_context(state)
context.update({'approve_info': approve_info})
body = self.reject_html_script(
render_to_string('tickets/ticket_approve_diff.html', context)
)
data = {
'body': render_to_string('tickets/ticket_approve_diff.html', context),
'body': body,
'user': user,
'user_display': str(user),
'type': 'state',
'state': state
}
return self.ticket.comments.create(**data)
@staticmethod
def reject_html_script(unsafe_html):
safe_html = escape(unsafe_html)
return safe_html

View File

@@ -4,6 +4,7 @@
from celery import shared_task
from django.conf import settings
from django.utils import timezone
from django.db import transaction
from users.notifications import PasswordExpirationReminderMsg
from ops.celery.utils import (
@@ -80,6 +81,7 @@ def check_user_expired_periodic():
@shared_task
@transaction.atomic
def import_ldap_user():
logger.info("Start import ldap user task")
util_server = LDAPServerUtil()