Merge pull request #7089 from jumpserver/dev

v2.15.0-rc3
pull/7119/head
Jiangjie.Bai 2021-10-27 19:24:42 +08:00 committed by GitHub
commit 7183f0d274
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 245 additions and 114 deletions

View File

@ -6,4 +6,5 @@ tmp/*
django.db django.db
celerybeat.pid celerybeat.pid
### Vagrant ### ### Vagrant ###
.vagrant/ .vagrant/
apps/xpack/.git

View File

@ -1,3 +1,4 @@
# 编译代码
FROM python:3.8.6-slim as stage-build FROM python:3.8.6-slim as stage-build
MAINTAINER JumpServer Team <ibuler@qq.com> MAINTAINER JumpServer Team <ibuler@qq.com>
ARG VERSION ARG VERSION
@ -7,9 +8,12 @@ WORKDIR /opt/jumpserver
ADD . . ADD . .
RUN cd utils && bash -ixeu build.sh RUN cd utils && bash -ixeu build.sh
# 构建运行时环境
FROM python:3.8.6-slim FROM python:3.8.6-slim
ARG PIP_MIRROR=https://pypi.douban.com/simple ARG PIP_MIRROR=https://pypi.douban.com/simple
ENV PIP_MIRROR=$PIP_MIRROR ENV PIP_MIRROR=$PIP_MIRROR
ARG PIP_JMS_MIRROR=https://pypi.douban.com/simple
ENV PIP_JMS_MIRROR=$PIP_JMS_MIRROR
WORKDIR /opt/jumpserver WORKDIR /opt/jumpserver
@ -27,6 +31,7 @@ RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list \
COPY ./requirements/requirements.txt ./requirements/requirements.txt COPY ./requirements/requirements.txt ./requirements/requirements.txt
RUN pip install --upgrade pip==20.2.4 setuptools==49.6.0 wheel==0.34.2 -i ${PIP_MIRROR} \ RUN pip install --upgrade pip==20.2.4 setuptools==49.6.0 wheel==0.34.2 -i ${PIP_MIRROR} \
&& pip install --no-cache-dir $(grep -E 'jms|jumpserver' requirements/requirements.txt) -i ${PIP_JMS_MIRROR} \
&& pip install --no-cache-dir -r requirements/requirements.txt -i ${PIP_MIRROR} \ && pip install --no-cache-dir -r requirements/requirements.txt -i ${PIP_MIRROR} \
&& rm -rf ~/.cache/pip && rm -rf ~/.cache/pip

View File

@ -54,6 +54,7 @@ class Migration(migrations.Migration):
dependencies = [ dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('acls', '0001_initial'), ('acls', '0001_initial'),
('authentication', '0004_ssotoken'),
] ]
operations = [ operations = [
@ -86,4 +87,12 @@ class Migration(migrations.Migration):
model_name='loginacl', model_name='loginacl',
name='ip_group', name='ip_group',
), ),
migrations.AlterModelOptions(
name='loginacl',
options={'ordering': ('priority', '-date_updated', 'name'), 'verbose_name': 'Login acl'},
),
migrations.AlterModelOptions(
name='loginassetacl',
options={'ordering': ('priority', '-date_updated', 'name'), 'verbose_name': 'Login asset acl'},
),
] ]

View File

@ -40,6 +40,7 @@ class LoginACL(BaseACL):
class Meta: class Meta:
ordering = ('priority', '-date_updated', 'name') ordering = ('priority', '-date_updated', 'name')
verbose_name = _('Login acl')
def __str__(self): def __str__(self):
return self.name return self.name

View File

@ -37,6 +37,7 @@ class LoginAssetACL(BaseACL, OrgModelMixin):
class Meta: class Meta:
unique_together = ('name', 'org_id') unique_together = ('name', 'org_id')
ordering = ('priority', '-date_updated', 'name') ordering = ('priority', '-date_updated', 'name')
verbose_name = _('Login asset acl')
def __str__(self): def __str__(self):
return self.name return self.name

View File

@ -0,0 +1,17 @@
# Generated by Django 3.1.13 on 2021-10-26 09:11
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('applications', '0012_auto_20211014_2209'),
]
operations = [
migrations.AlterModelOptions(
name='application',
options={'ordering': ('name',), 'verbose_name': 'Application'},
),
]

View File

@ -180,6 +180,7 @@ class Application(CommonModelMixin, OrgModelMixin, ApplicationTreeNodeMixin):
) )
class Meta: class Meta:
verbose_name = _('Application')
unique_together = [('org_id', 'name')] unique_together = [('org_id', 'name')]
ordering = ('name',) ordering = ('name',)

View File

@ -104,7 +104,8 @@ class AppAccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
extra_kwargs = { extra_kwargs = {
'username': {'default': '', 'required': False}, 'username': {'default': '', 'required': False},
'password': {'write_only': True}, 'password': {'write_only': True},
'app_display': {'label': _('Application display')} 'app_display': {'label': _('Application display')},
'systemuser_display': {'label': _('System User')}
} }
use_model_bulk_create = True use_model_bulk_create = True
model_bulk_create_kwargs = { model_bulk_create_kwargs = {
@ -134,4 +135,6 @@ class AppAccountSecretSerializer(AppAccountSerializer):
'password': {'write_only': False}, 'password': {'write_only': False},
'private_key': {'write_only': False}, 'private_key': {'write_only': False},
'public_key': {'write_only': False}, 'public_key': {'write_only': False},
'app_display': {'label': _('Application display')},
'systemuser_display': {'label': _('System User')}
} }

View File

@ -41,7 +41,7 @@ class SystemUserViewSet(SuggestionMixin, OrgBulkModelViewSet):
'default': serializers.SystemUserSerializer, 'default': serializers.SystemUserSerializer,
'suggestion': serializers.MiniSystemUserSerializer 'suggestion': serializers.MiniSystemUserSerializer
} }
ordering_fields = ('name', 'protocol') ordering_fields = ('name', 'protocol', 'login_mode')
ordering = ('name', ) ordering = ('name', )
permission_classes = (IsOrgAdminOrAppUser,) permission_classes = (IsOrgAdminOrAppUser,)

View File

@ -26,7 +26,9 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
auto_generate_key = serializers.BooleanField(initial=True, required=False, write_only=True) auto_generate_key = serializers.BooleanField(initial=True, required=False, write_only=True)
type_display = serializers.ReadOnlyField(source='get_type_display', label=_('Type display')) type_display = serializers.ReadOnlyField(source='get_type_display', label=_('Type display'))
ssh_key_fingerprint = serializers.ReadOnlyField(label=_('SSH key fingerprint')) ssh_key_fingerprint = serializers.ReadOnlyField(label=_('SSH key fingerprint'))
applications_amount = serializers.IntegerField(source='apps_amount', label=_('Apps amount')) applications_amount = serializers.IntegerField(
source='apps_amount', read_only=True, label=_('Apps amount')
)
class Meta: class Meta:
model = SystemUser model = SystemUser

View File

@ -372,9 +372,19 @@ class NotEnableMFAError(JMSException):
default_detail = mfa_unset_msg default_detail = mfa_unset_msg
class OTPRequiredError(JMSException): class OTPBindRequiredError(JMSException):
default_detail = otp_unset_msg default_detail = otp_unset_msg
def __init__(self, url, *args, **kwargs): def __init__(self, url, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.url = url self.url = url
class OTPCodeRequiredError(AuthFailedError):
msg = _("Please enter MFA code")
class SMSCodeRequiredError(AuthFailedError):
msg = _("Please enter SMS code")
class UserPhoneNotSet(AuthFailedError):
msg = _('Phone not set')

View File

@ -242,7 +242,12 @@ class AuthMixin(PasswordEncryptionViewMixin):
data = request.POST data = request.POST
code = data.get('code') code = data.get('code')
mfa_type = data.get('mfa_type') mfa_type = data.get('mfa_type')
if settings.SECURITY_MFA_IN_LOGIN_PAGE and code and mfa_type: if settings.SECURITY_MFA_IN_LOGIN_PAGE and mfa_type:
if not code:
if mfa_type == MFAType.OTP and bool(user.otp_secret_key):
raise errors.OTPCodeRequiredError
elif mfa_type == MFAType.SMS_CODE:
raise errors.SMSCodeRequiredError
self.check_user_mfa(code, mfa_type, user=user) self.check_user_mfa(code, mfa_type, user=user)
def _check_login_acl(self, user, ip): def _check_login_acl(self, user, ip):
@ -405,9 +410,12 @@ class AuthMixin(PasswordEncryptionViewMixin):
if not user.mfa_enabled: if not user.mfa_enabled:
return return
if not bool(user.phone) and mfa_type == MFAType.SMS_CODE:
raise errors.UserPhoneNotSet
if not bool(user.otp_secret_key) and mfa_type == MFAType.OTP: if not bool(user.otp_secret_key) and mfa_type == MFAType.OTP:
self.set_passwd_verify_on_session(user) self.set_passwd_verify_on_session(user)
raise errors.OTPRequiredError(reverse_lazy('authentication:user-otp-enable-bind')) raise errors.OTPBindRequiredError(reverse_lazy('authentication:user-otp-enable-bind'))
ip = self.get_request_ip() ip = self.get_request_ip()
self.check_mfa_is_block(user.username, ip) self.check_mfa_is_block(user.username, ip)

View File

@ -124,18 +124,19 @@ class UserLoginView(mixins.AuthMixin, FormView):
except ( except (
errors.PasswdTooSimple, errors.PasswdTooSimple,
errors.PasswordRequireResetError, errors.PasswordRequireResetError,
errors.PasswdNeedUpdate errors.PasswdNeedUpdate,
errors.OTPBindRequiredError
) as e: ) as e:
return redirect(e.url) return redirect(e.url)
except ( except (
errors.MFAUnsetError,
errors.MFAFailedError, errors.MFAFailedError,
errors.BlockMFAError errors.BlockMFAError,
errors.OTPCodeRequiredError,
errors.SMSCodeRequiredError,
errors.UserPhoneNotSet
) as e: ) as e:
form.add_error('code', e.msg) form.add_error('code', e.msg)
return super().form_invalid(form) return super().form_invalid(form)
except errors.OTPRequiredError as e:
return redirect(e.url)
self.clear_rsa_key() self.clear_rsa_key()
return self.redirect_to_guard_view() return self.redirect_to_guard_view()

View File

@ -25,7 +25,7 @@ def utc_now():
def local_now(): def local_now():
return as_current_tz(utc_now()) return dj_timezone.localtime(dj_timezone.now())
def local_now_display(fmt='%Y-%m-%d %H:%M:%S'): def local_now_display(fmt='%Y-%m-%d %H:%M:%S'):

View File

@ -18,6 +18,7 @@ import copy
from importlib import import_module from importlib import import_module
from django.urls import reverse_lazy from django.urls import reverse_lazy
from urllib.parse import urljoin, urlparse from urllib.parse import urljoin, urlparse
from django.utils.translation import ugettext_lazy as _
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_DIR = os.path.dirname(BASE_DIR) PROJECT_DIR = os.path.dirname(BASE_DIR)
@ -263,6 +264,11 @@ class Config(dict):
'TENCENT_VERIFY_SIGN_NAME': '', 'TENCENT_VERIFY_SIGN_NAME': '',
'TENCENT_VERIFY_TEMPLATE_CODE': '', 'TENCENT_VERIFY_TEMPLATE_CODE': '',
# Email
'EMAIL_CUSTOM_USER_CREATED_SUBJECT': _('Create account successfully'),
'EMAIL_CUSTOM_USER_CREATED_HONORIFIC': _('Hello'),
'EMAIL_CUSTOM_USER_CREATED_BODY': _('Your account has been created successfully'),
'OTP_VALID_WINDOW': 2, 'OTP_VALID_WINDOW': 2,
'OTP_ISSUER_NAME': 'JumpServer', 'OTP_ISSUER_NAME': 'JumpServer',
'EMAIL_SUFFIX': 'example.com', 'EMAIL_SUFFIX': 'example.com',

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:55a2062981ea7eef4ca28142f325f52e15cb7679ad0a2600234a5bdb6d005c87 oid sha256:cc8a022ddc7438e50aa0cdb4ce24eec327638143731dbe0ed0ad783df06ecbaf
size 89996 size 89882

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n" "Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-10-25 14:56+0800\n" "POT-Creation-Date: 2021-10-26 17:16+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler <ibuler@qq.com>\n" "Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n" "Language-Team: JumpServer team<ibuler@qq.com>\n"
@ -74,7 +74,7 @@ msgstr "拒绝"
msgid "Allow" msgid "Allow"
msgstr "允许" msgstr "允许"
#: acls/models/login_acl.py:21 acls/models/login_acl.py:113 #: acls/models/login_acl.py:21 acls/models/login_acl.py:114
#: acls/models/login_asset_acl.py:17 tickets/const.py:9 #: acls/models/login_asset_acl.py:17 tickets/const.py:9
msgid "Login confirm" msgid "Login confirm"
msgstr "登录复核" msgstr "登录复核"
@ -116,14 +116,20 @@ msgstr "动作"
msgid "Reviewers" msgid "Reviewers"
msgstr "审批人" msgstr "审批人"
#: acls/models/login_acl.py:43
msgid "Login acl"
msgstr "登录访问控制"
#: acls/models/login_asset_acl.py:21 #: acls/models/login_asset_acl.py:21
#: applications/serializers/application.py:108
#: applications/serializers/application.py:139
msgid "System User" msgid "System User"
msgstr "系统用户" msgstr "系统用户"
#: acls/models/login_asset_acl.py:22 #: acls/models/login_asset_acl.py:22
#: applications/serializers/attrs/application_category/remote_app.py:37 #: applications/serializers/attrs/application_category/remote_app.py:37
#: assets/models/asset.py:357 assets/models/authbook.py:18 #: assets/models/asset.py:357 assets/models/authbook.py:18
#: assets/models/gathered_user.py:14 assets/serializers/system_user.py:231 #: assets/models/gathered_user.py:14 assets/serializers/system_user.py:233
#: audits/models.py:38 perms/models/asset_permission.py:99 #: audits/models.py:38 perms/models/asset_permission.py:99
#: templates/index.html:82 terminal/backends/command/models.py:19 #: templates/index.html:82 terminal/backends/command/models.py:19
#: terminal/backends/command/serializers.py:13 terminal/models/session.py:40 #: terminal/backends/command/serializers.py:13 terminal/models/session.py:40
@ -135,7 +141,11 @@ msgstr "系统用户"
msgid "Asset" msgid "Asset"
msgstr "资产" msgstr "资产"
#: acls/models/login_asset_acl.py:89 tickets/const.py:12 #: acls/models/login_asset_acl.py:40
msgid "Login asset acl"
msgstr "登录资产访问控制"
#: acls/models/login_asset_acl.py:90 tickets/const.py:12
msgid "Login asset confirm" msgid "Login asset confirm"
msgstr "登录资产复核" msgstr "登录资产复核"
@ -153,7 +163,7 @@ msgstr "格式为逗号分隔的字符串, * 表示匹配所有. "
#: audits/models.py:105 authentication/forms.py:15 authentication/forms.py:17 #: audits/models.py:105 authentication/forms.py:15 authentication/forms.py:17
#: authentication/templates/authentication/_msg_different_city.html:9 #: authentication/templates/authentication/_msg_different_city.html:9
#: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:595 #: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:595
#: users/templates/users/_msg_user_created.html:10 #: users/templates/users/_msg_user_created.html:12
#: users/templates/users/_select_user_modal.html:14 #: users/templates/users/_select_user_modal.html:14
#: xpack/plugins/change_auth_plan/models/asset.py:35 #: xpack/plugins/change_auth_plan/models/asset.py:35
#: xpack/plugins/change_auth_plan/models/asset.py:191 #: xpack/plugins/change_auth_plan/models/asset.py:191
@ -312,6 +322,11 @@ msgstr "网域"
msgid "Attrs" msgid "Attrs"
msgstr "" msgstr ""
#: applications/models/application.py:183
#: perms/models/application_permission.py:27 users/models/user.py:174
msgid "Application"
msgstr "应用程序"
#: applications/serializers/application.py:59 #: applications/serializers/application.py:59
#: applications/serializers/application.py:89 assets/serializers/label.py:13 #: applications/serializers/application.py:89 assets/serializers/label.py:13
#: perms/serializers/application/permission.py:16 #: perms/serializers/application/permission.py:16
@ -330,6 +345,7 @@ msgid "Type display"
msgstr "类型名称" msgstr "类型名称"
#: applications/serializers/application.py:107 #: applications/serializers/application.py:107
#: applications/serializers/application.py:138
msgid "Application display" msgid "Application display"
msgstr "应用名称" msgstr "应用名称"
@ -384,7 +400,7 @@ msgstr "目标URL"
#: authentication/forms.py:22 #: authentication/forms.py:22
#: authentication/templates/authentication/login.html:151 #: authentication/templates/authentication/login.html:151
#: settings/serializers/auth/ldap.py:44 users/forms/profile.py:21 #: settings/serializers/auth/ldap.py:44 users/forms/profile.py:21
#: users/templates/users/_msg_user_created.html:11 #: users/templates/users/_msg_user_created.html:13
#: users/templates/users/user_otp_check_password.html:13 #: users/templates/users/user_otp_check_password.html:13
#: users/templates/users/user_password_update.html:43 #: users/templates/users/user_password_update.html:43
#: users/templates/users/user_password_verify.html:18 #: users/templates/users/user_password_verify.html:18
@ -747,7 +763,7 @@ msgstr "全称"
msgid "Parent key" msgid "Parent key"
msgstr "ssh私钥" msgstr "ssh私钥"
#: assets/models/node.py:559 assets/serializers/system_user.py:230 #: assets/models/node.py:559 assets/serializers/system_user.py:232
#: users/templates/users/user_asset_permission.html:41 #: users/templates/users/user_asset_permission.html:41
#: users/templates/users/user_asset_permission.html:73 #: users/templates/users/user_asset_permission.html:73
#: users/templates/users/user_asset_permission.html:158 #: users/templates/users/user_asset_permission.html:158
@ -848,7 +864,7 @@ msgstr "节点名称"
msgid "Hardware info" msgid "Hardware info"
msgstr "硬件信息" msgstr "硬件信息"
#: assets/serializers/asset.py:104 assets/serializers/system_user.py:249 #: assets/serializers/asset.py:104 assets/serializers/system_user.py:251
#: orgs/mixins/serializers.py:26 #: orgs/mixins/serializers.py:26
msgid "Org name" msgid "Org name"
msgstr "组织名称" msgstr "组织名称"
@ -862,7 +878,7 @@ msgid "private key invalid"
msgstr "密钥不合法" msgstr "密钥不合法"
#: assets/serializers/domain.py:13 assets/serializers/label.py:12 #: assets/serializers/domain.py:13 assets/serializers/label.py:12
#: assets/serializers/system_user.py:54 #: assets/serializers/system_user.py:56
#: perms/serializers/asset/permission.py:72 #: perms/serializers/asset/permission.py:72
msgid "Assets amount" msgid "Assets amount"
msgstr "资产数量" msgstr "资产数量"
@ -892,52 +908,52 @@ msgstr "同级别节点名字不能重复"
msgid "SSH key fingerprint" msgid "SSH key fingerprint"
msgstr "密钥指纹" msgstr "密钥指纹"
#: assets/serializers/system_user.py:29 #: assets/serializers/system_user.py:30
msgid "Apps amount" msgid "Apps amount"
msgstr "应用数量" msgstr "应用数量"
#: assets/serializers/system_user.py:53 #: assets/serializers/system_user.py:55
#: perms/serializers/asset/permission.py:73 #: perms/serializers/asset/permission.py:73
msgid "Nodes amount" msgid "Nodes amount"
msgstr "节点数量" msgstr "节点数量"
#: assets/serializers/system_user.py:55 assets/serializers/system_user.py:232 #: assets/serializers/system_user.py:57 assets/serializers/system_user.py:234
msgid "Login mode display" msgid "Login mode display"
msgstr "认证方式名称" msgstr "认证方式名称"
#: assets/serializers/system_user.py:57 #: assets/serializers/system_user.py:59
msgid "Ad domain" msgid "Ad domain"
msgstr "Ad 网域" msgstr "Ad 网域"
#: assets/serializers/system_user.py:58 #: assets/serializers/system_user.py:60
msgid "Is asset protocol" msgid "Is asset protocol"
msgstr "" msgstr ""
#: assets/serializers/system_user.py:98 #: assets/serializers/system_user.py:100
msgid "Username same with user with protocol {} only allow 1" msgid "Username same with user with protocol {} only allow 1"
msgstr "用户名和用户相同的一种协议只允许存在一个" msgstr "用户名和用户相同的一种协议只允许存在一个"
#: assets/serializers/system_user.py:108 common/validators.py:14 #: assets/serializers/system_user.py:110 common/validators.py:14
msgid "Special char not allowed" msgid "Special char not allowed"
msgstr "不能包含特殊字符" msgstr "不能包含特殊字符"
#: assets/serializers/system_user.py:117 #: assets/serializers/system_user.py:119
msgid "* Automatic login mode must fill in the username." msgid "* Automatic login mode must fill in the username."
msgstr "自动登录模式,必须填写用户名" msgstr "自动登录模式,必须填写用户名"
#: assets/serializers/system_user.py:132 #: assets/serializers/system_user.py:134
msgid "Path should starts with /" msgid "Path should starts with /"
msgstr "路径应该以 / 开头" msgstr "路径应该以 / 开头"
#: assets/serializers/system_user.py:144 #: assets/serializers/system_user.py:146
msgid "Password or private key required" msgid "Password or private key required"
msgstr "密码或密钥密码需要一个" msgstr "密码或密钥密码需要一个"
#: assets/serializers/system_user.py:248 #: assets/serializers/system_user.py:250
msgid "System user name" msgid "System user name"
msgstr "系统用户名称" msgstr "系统用户名称"
#: assets/serializers/system_user.py:258 #: assets/serializers/system_user.py:260
msgid "Asset hostname" msgid "Asset hostname"
msgstr "资产主机名" msgstr "资产主机名"
@ -1257,12 +1273,12 @@ msgstr ""
msgid "Auth Token" msgid "Auth Token"
msgstr "认证令牌" msgstr "认证令牌"
#: audits/signals_handler.py:68 authentication/views/login.py:168 #: audits/signals_handler.py:68 authentication/views/login.py:169
#: notifications/backends/__init__.py:11 users/models/user.py:652 #: notifications/backends/__init__.py:11 users/models/user.py:652
msgid "WeCom" msgid "WeCom"
msgstr "企业微信" msgstr "企业微信"
#: audits/signals_handler.py:69 authentication/views/login.py:174 #: audits/signals_handler.py:69 authentication/views/login.py:175
#: notifications/backends/__init__.py:12 users/models/user.py:653 #: notifications/backends/__init__.py:12 users/models/user.py:653
msgid "DingTalk" msgid "DingTalk"
msgstr "钉钉" msgstr "钉钉"
@ -1424,7 +1440,7 @@ msgstr "{ApplicationPermission} 移除 {UserGroup}"
#: audits/signals_handler.py:157 perms/models/application_permission.py:37 #: audits/signals_handler.py:157 perms/models/application_permission.py:37
msgid "Application permission" msgid "Application permission"
msgstr "应用管理" msgstr "应用授权"
#: audits/signals_handler.py:158 #: audits/signals_handler.py:158
#, python-brace-format #, python-brace-format
@ -1641,15 +1657,15 @@ msgstr "该 时间段 不被允许登录"
msgid "SSO auth closed" msgid "SSO auth closed"
msgstr "SSO 认证关闭了" msgstr "SSO 认证关闭了"
#: authentication/errors.py:310 authentication/mixins.py:340 #: authentication/errors.py:310 authentication/mixins.py:345
msgid "Your password is too simple, please change it for security" msgid "Your password is too simple, please change it for security"
msgstr "你的密码过于简单,为了安全,请修改" msgstr "你的密码过于简单,为了安全,请修改"
#: authentication/errors.py:319 authentication/mixins.py:347 #: authentication/errors.py:319 authentication/mixins.py:352
msgid "You should to change your password before login" msgid "You should to change your password before login"
msgstr "登录完成前,请先修改密码" msgstr "登录完成前,请先修改密码"
#: authentication/errors.py:328 authentication/mixins.py:354 #: authentication/errors.py:328 authentication/mixins.py:359
msgid "Your password has expired, please reset before logging in" msgid "Your password has expired, please reset before logging in"
msgstr "您的密码已过期,先修改再登录" msgstr "您的密码已过期,先修改再登录"
@ -1661,6 +1677,18 @@ msgstr "您的密码无效"
msgid "No upload or download permission" msgid "No upload or download permission"
msgstr "没有上传下载权限" msgstr "没有上传下载权限"
#: authentication/errors.py:384 templates/_mfa_otp_login.html:37
msgid "Please enter MFA code"
msgstr "请输入6位动态安全码"
#: authentication/errors.py:387 templates/_mfa_otp_login.html:38
msgid "Please enter SMS code"
msgstr "请输入短信验证码"
#: authentication/errors.py:390 users/exceptions.py:15
msgid "Phone not set"
msgstr "手机号没有设置"
#: authentication/forms.py:35 #: authentication/forms.py:35
msgid "{} days auto login" msgid "{} days auto login"
msgstr "{} 天内自动登录" msgstr "{} 天内自动登录"
@ -1681,11 +1709,11 @@ msgstr "多因子认证验证码"
msgid "Dynamic code" msgid "Dynamic code"
msgstr "动态码" msgstr "动态码"
#: authentication/mixins.py:330 #: authentication/mixins.py:335
msgid "Please change your password" msgid "Please change your password"
msgstr "请修改密码" msgstr "请修改密码"
#: authentication/mixins.py:515 #: authentication/mixins.py:523
msgid "SMS" msgid "SMS"
msgstr "短信" msgstr "短信"
@ -1796,6 +1824,7 @@ msgstr "代码错误"
#: authentication/templates/authentication/_msg_different_city.html:3 #: authentication/templates/authentication/_msg_different_city.html:3
#: authentication/templates/authentication/_msg_reset_password.html:3 #: authentication/templates/authentication/_msg_reset_password.html:3
#: authentication/templates/authentication/_msg_rest_password_success.html:2 #: authentication/templates/authentication/_msg_rest_password_success.html:2
#: jumpserver/conf.py:269
#: perms/templates/perms/_msg_item_permissions_expire.html:3 #: perms/templates/perms/_msg_item_permissions_expire.html:3
#: perms/templates/perms/_msg_permed_items_expire.html:3 #: perms/templates/perms/_msg_permed_items_expire.html:3
#: users/templates/users/_msg_account_expire_reminder.html:4 #: users/templates/users/_msg_account_expire_reminder.html:4
@ -1830,12 +1859,12 @@ msgid "Click here reset password"
msgstr "点击这里重置密码" msgstr "点击这里重置密码"
#: authentication/templates/authentication/_msg_reset_password.html:15 #: authentication/templates/authentication/_msg_reset_password.html:15
#: users/templates/users/_msg_user_created.html:17 #: users/templates/users/_msg_user_created.html:19
msgid "This link is valid for 1 hour. After it expires" msgid "This link is valid for 1 hour. After it expires"
msgstr "这个链接有效期1小时, 超过时间您可以" msgstr "这个链接有效期1小时, 超过时间您可以"
#: authentication/templates/authentication/_msg_reset_password.html:17 #: authentication/templates/authentication/_msg_reset_password.html:17
#: users/templates/users/_msg_user_created.html:18 #: users/templates/users/_msg_user_created.html:20
msgid "request new one" msgid "request new one"
msgstr "重新申请" msgstr "重新申请"
@ -1999,12 +2028,12 @@ msgstr "正在跳转到 {} 认证"
msgid "Please enable cookies and try again." msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie" msgstr "设置你的浏览器支持cookie"
#: authentication/views/login.py:180 notifications/backends/__init__.py:14 #: authentication/views/login.py:181 notifications/backends/__init__.py:14
#: users/models/user.py:654 #: users/models/user.py:654
msgid "FeiShu" msgid "FeiShu"
msgstr "飞书" msgstr "飞书"
#: authentication/views/login.py:268 #: authentication/views/login.py:269
msgid "" msgid ""
"Wait for <b>{}</b> confirm, You also can copy link to her/him <br/>\n" "Wait for <b>{}</b> confirm, You also can copy link to her/him <br/>\n"
" Don't close this page" " Don't close this page"
@ -2012,15 +2041,15 @@ msgstr ""
"等待 <b>{}</b> 确认, 你也可以复制链接发给他/她 <br/>\n" "等待 <b>{}</b> 确认, 你也可以复制链接发给他/她 <br/>\n"
" 不要关闭本页面" " 不要关闭本页面"
#: authentication/views/login.py:273 #: authentication/views/login.py:274
msgid "No ticket found" msgid "No ticket found"
msgstr "没有发现工单" msgstr "没有发现工单"
#: authentication/views/login.py:305 #: authentication/views/login.py:306
msgid "Logout success" msgid "Logout success"
msgstr "退出登录成功" msgstr "退出登录成功"
#: authentication/views/login.py:306 #: authentication/views/login.py:307
msgid "Logout success, return login page" msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面" msgstr "退出登录成功,返回到登录页面"
@ -2207,6 +2236,14 @@ msgstr "不能包含特殊字符"
msgid "The mobile phone number format is incorrect" msgid "The mobile phone number format is incorrect"
msgstr "手机号格式不正确" msgstr "手机号格式不正确"
#: jumpserver/conf.py:268
msgid "Create account successfully"
msgstr "创建账户成功"
#: jumpserver/conf.py:270
msgid "Your account has been created successfully"
msgstr "你的账户已创建成功"
#: jumpserver/context_processor.py:17 #: jumpserver/context_processor.py:17
msgid "JumpServer Open Source Bastion Host" msgid "JumpServer Open Source Bastion Host"
msgstr "JumpServer 开源堡垒机" msgstr "JumpServer 开源堡垒机"
@ -2467,10 +2504,6 @@ msgstr "管理员正在修改授权,请稍等"
msgid "The authorization cannot be revoked for the time being" msgid "The authorization cannot be revoked for the time being"
msgstr "该授权暂时不能撤销" msgstr "该授权暂时不能撤销"
#: perms/models/application_permission.py:27 users/models/user.py:174
msgid "Application"
msgstr "应用程序"
#: perms/models/asset_permission.py:37 settings/serializers/terminal.py:12 #: perms/models/asset_permission.py:37 settings/serializers/terminal.py:12
msgid "All" msgid "All"
msgstr "全部" msgstr "全部"
@ -3100,7 +3133,7 @@ msgstr "提示: 创建用户时,发送设置密码邮件的主题 (例如: 创
#: settings/serializers/email.py:54 #: settings/serializers/email.py:54
msgid "Create user honorific" msgid "Create user honorific"
msgstr "邮件的敬语" msgstr "邮件问候语"
#: settings/serializers/email.py:55 #: settings/serializers/email.py:55
msgid "Tips: When creating a user, send the honorific of the email (eg:Hello)" msgid "Tips: When creating a user, send the honorific of the email (eg:Hello)"
@ -3671,14 +3704,6 @@ msgstr "请输入验证码"
msgid "Send verification code" msgid "Send verification code"
msgstr "发送验证码" msgstr "发送验证码"
#: templates/_mfa_otp_login.html:37
msgid "Please enter MFA code"
msgstr "请输入6位动态安全码"
#: templates/_mfa_otp_login.html:38
msgid "Please enter SMS code"
msgstr "请输入短信验证码"
#: templates/_mfa_otp_login.html:60 templates/_mfa_otp_login.html:65 #: templates/_mfa_otp_login.html:60 templates/_mfa_otp_login.html:65
msgid "Wait: " msgid "Wait: "
msgstr "等待:" msgstr "等待:"
@ -3989,6 +4014,27 @@ msgstr "前"
msgid "Login in " msgid "Login in "
msgstr "登录了" msgstr "登录了"
#: templates/resource_download.html:15 templates/resource_download.html:21
#: templates/resource_download.html:22 templates/resource_download.html:27
msgid "Client"
msgstr "客户端"
#: templates/resource_download.html:17
msgid ""
"JumpServer Client, currently used to launch the client, now only support "
"launch RDP client, The SSH client will next"
msgstr "JumpServer 客户端,目前用来唤起 特定客户端程序 连接资产, 目前仅支持 RDP 客户端SSH、Telnet 会在未来支持"
#: templates/resource_download.html:27
msgid "Official"
msgstr "官方"
#: templates/resource_download.html:29
msgid ""
"macOS needs to download the client to connect RDP asset, which comes with "
"Windows"
msgstr "macOS 需要下载客户端来连接 RDP 资产Windows 系统默认安装了该程序"
#: templates/rest_framework/base.html:128 #: templates/rest_framework/base.html:128
msgid "Filters" msgid "Filters"
msgstr "过滤" msgstr "过滤"
@ -4776,10 +4822,6 @@ msgstr "设置密码"
msgid "MFA not enabled" msgid "MFA not enabled"
msgstr "MFA没有开启" msgstr "MFA没有开启"
#: users/exceptions.py:15
msgid "Phone not set"
msgstr "手机号没有设置"
#: users/exceptions.py:20 #: users/exceptions.py:20
msgid "MFA method not support" msgid "MFA method not support"
msgstr "MFA 方法不支持" msgstr "MFA 方法不支持"
@ -4908,38 +4950,30 @@ msgstr "管理员"
msgid "Administrator is the super user of system" msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员" msgstr "Administrator是初始的超级管理员"
#: users/notifications.py:15 #: users/notifications.py:48
msgid "Create account successfully"
msgstr "创建账户成功"
#: users/notifications.py:19
msgid "Hello {}"
msgstr "你好"
#: users/notifications.py:51
#: users/templates/users/_msg_password_expire_reminder.html:17 #: users/templates/users/_msg_password_expire_reminder.html:17
#: users/templates/users/reset_password.html:5 #: users/templates/users/reset_password.html:5
#: users/templates/users/reset_password.html:6 #: users/templates/users/reset_password.html:6
msgid "Reset password" msgid "Reset password"
msgstr "重置密码" msgstr "重置密码"
#: users/notifications.py:81 users/views/profile/reset.py:127 #: users/notifications.py:78 users/views/profile/reset.py:127
msgid "Reset password success" msgid "Reset password success"
msgstr "重置密码成功" msgstr "重置密码成功"
#: users/notifications.py:107 #: users/notifications.py:104
msgid "Password is about expire" msgid "Password is about expire"
msgstr "密码即将过期" msgstr "密码即将过期"
#: users/notifications.py:135 #: users/notifications.py:132
msgid "Account is about expire" msgid "Account is about expire"
msgstr "账号即将过期" msgstr "账号即将过期"
#: users/notifications.py:157 #: users/notifications.py:154
msgid "Reset SSH Key" msgid "Reset SSH Key"
msgstr "重置 SSH 密钥" msgstr "重置 SSH 密钥"
#: users/notifications.py:178 #: users/notifications.py:175
msgid "Reset MFA" msgid "Reset MFA"
msgstr "重置 MFA" msgstr "重置 MFA"
@ -5109,11 +5143,7 @@ msgstr "点击这里设置"
msgid "Your ssh public key has been reset by site administrator" msgid "Your ssh public key has been reset by site administrator"
msgstr "你的 SSH 密钥已经被管理员重置" msgstr "你的 SSH 密钥已经被管理员重置"
#: users/templates/users/_msg_user_created.html:8 #: users/templates/users/_msg_user_created.html:15
msgid "Your account has been created successfully"
msgstr "您的账户已创建成功"
#: users/templates/users/_msg_user_created.html:13
msgid "click here to set your password" msgid "click here to set your password"
msgstr "点击这里设置密码" msgstr "点击这里设置密码"
@ -5500,15 +5530,15 @@ msgstr "* 请输入正确的密码长度"
msgid "* Password length range 6-30 bits" msgid "* Password length range 6-30 bits"
msgstr "* 密码长度范围 6-30 位" msgstr "* 密码长度范围 6-30 位"
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:248 #: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:249
msgid "Invalid/incorrect password" msgid "Invalid/incorrect password"
msgstr "无效/错误 密码" msgstr "无效/错误 密码"
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:250 #: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:251
msgid "Failed to connect to the host" msgid "Failed to connect to the host"
msgstr "连接主机失败" msgstr "连接主机失败"
#: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:252 #: xpack/plugins/change_auth_plan/task_handlers/base/handler.py:253
msgid "Data could not be sent to remote" msgid "Data could not be sent to remote"
msgstr "无法将数据发送到远程" msgstr "无法将数据发送到远程"
@ -5866,7 +5896,7 @@ msgstr "执行次数"
msgid "Instance count" msgid "Instance count"
msgstr "实例个数" msgstr "实例个数"
#: xpack/plugins/cloud/utils.py:65 #: xpack/plugins/cloud/utils.py:68
msgid "Account unavailable" msgid "Account unavailable"
msgstr "账户无效" msgstr "账户无效"
@ -5954,6 +5984,10 @@ msgstr "旗舰版"
msgid "Community edition" msgid "Community edition"
msgstr "社区版" msgstr "社区版"
#, python-brace-format
#~ msgid "Hello {name}"
#~ msgstr "你好 {name}"
#~ msgid "Login direct" #~ msgid "Login direct"
#~ msgstr "直接登录" #~ msgstr "直接登录"

View File

@ -1,16 +1,36 @@
{% extends '_without_nav_base.html' %} {% extends '_without_nav_base.html' %}
{% load i18n %}
{% block body %} {% block body %}
<style>
li {
list-style: disc;
}
ul {
padding-left: 30px;
padding-top: 10px;
}
p {
padding-top: 10px;
}
</style>
<div style="margin: 0 200px"> <div style="margin: 0 200px">
<div class="group"> <div class="group">
<h2>JumpServer Clients</h2> <h2>JumpServer {% trans 'Client' %}</h2>
<p>
{% trans 'JumpServer Client, currently used to launch the client, now only support launch RDP client, The SSH client will next' %}
{# //JumpServer 客户端,支持 RDP 的本地拉起,后续会支持拉起 ssh。#}
</p>
<ul> <ul>
<li><a href="/download/JumpServer-Client-Installer.msi">jumpserver-client-windows.msi</a></li> <li> <a href="/download/JumpServer-Client-Installer.msi">Windows {% trans 'Client' %}</a></li>
<li><a href="/download/JumpServer-Client-Installer.dmg">jumpserver-client-macos.dmg</a></li> <li> <a href="/download/JumpServer-Client-Installer.dmg">macOS {% trans 'Client' %}</a></li>
</ul> </ul>
</div> </div>
<div class="group"> <div class="group">
<h2>RDP Clients</h2> <h2>{% trans 'Microsoft' %} RDP {% trans 'Official' %}{% trans 'Client' %}</h2>
<p>
{% trans 'macOS needs to download the client to connect RDP asset, which comes with Windows' %}
</p>
<ul> <ul>
<li><a href="/download/Microsoft_Remote_Desktop_10.6.7_installer.pkg">Microsoft_Remote_Desktop_10.6.7_installer.pkg</a></li> <li><a href="/download/Microsoft_Remote_Desktop_10.6.7_installer.pkg">Microsoft_Remote_Desktop_10.6.7_installer.pkg</a></li>
</ul> </ul>

View File

@ -131,10 +131,13 @@ class CommandStore():
index=self.index, doc_type=self.doc_type, body=body, from_=from_, size=size, index=self.index, doc_type=self.doc_type, body=body, from_=from_, size=size,
sort=sort sort=sort
) )
source_data = []
for item in data['hits']['hits']:
if item:
item['_source'].update({'id': item['_id']})
source_data.append(item['_source'])
return AbstractSessionCommand.from_multi_dict( return AbstractSessionCommand.from_multi_dict(source_data)
[item['_source'] for item in data['hits']['hits'] if item]
)
def count(self, **query): def count(self, **query):
body = self.get_query_body(**query) body = self.get_query_body(**query)
@ -160,11 +163,16 @@ class CommandStore():
new_kwargs[k] = str(v) if isinstance(v, UUID) else v new_kwargs[k] = str(v) if isinstance(v, UUID) else v
kwargs = new_kwargs kwargs = new_kwargs
index_in_field = 'id__in'
exact_fields = self.exact_fields exact_fields = self.exact_fields
match_fields = self.match_fields match_fields = self.match_fields
match = {} match = {}
exact = {} exact = {}
index = {}
if index_in_field in kwargs:
index['values'] = kwargs[index_in_field]
for k, v in kwargs.items(): for k, v in kwargs.items():
if k in exact_fields: if k in exact_fields:
@ -221,6 +229,10 @@ class CommandStore():
'timestamp': timestamp_range 'timestamp': timestamp_range
} }
} }
] + [
{
'ids': {k: v}
} for k, v in index.items()
] ]
} }
}, },

View File

@ -8,3 +8,4 @@ class InsecureCommandAlertSerializer(serializers.Serializer):
user = serializers.CharField() user = serializers.CharField()
risk_level = serializers.IntegerField() risk_level = serializers.IntegerField()
session = serializers.UUIDField() session = serializers.UUIDField()
org_id = serializers.CharField()

View File

@ -29,7 +29,7 @@ class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet):
search_fields = [ search_fields = [
'title', 'action', 'type', 'status', 'applicant_display' 'title', 'action', 'type', 'status', 'applicant_display'
] ]
ordering_fields = ('title',) ordering_fields = ('title', 'applicant_display', 'status', 'state', 'action_display', 'date_created')
ordering = ('title', ) ordering = ('title', )
def create(self, request, *args, **kwargs): def create(self, request, *args, **kwargs):

View File

@ -12,21 +12,18 @@ from notifications.notifications import UserMessage
class UserCreatedMsg(UserMessage): class UserCreatedMsg(UserMessage):
def get_html_msg(self) -> dict: def get_html_msg(self) -> dict:
user = self.user user = self.user
subject = _('Create account successfully')
if settings.EMAIL_CUSTOM_USER_CREATED_SUBJECT:
subject = settings.EMAIL_CUSTOM_USER_CREATED_SUBJECT
honorific = settings.EMAIL_CUSTOM_USER_CREATED_HONORIFIC or _('Hello {}').format(user.name) subject = str(settings.EMAIL_CUSTOM_USER_CREATED_SUBJECT)
signature = settings.EMAIL_CUSTOM_USER_CREATED_SIGNATURE or 'JumpServer' honorific = str(settings.EMAIL_CUSTOM_USER_CREATED_HONORIFIC)
content = str(settings.EMAIL_CUSTOM_USER_CREATED_BODY)
context = { context = {
'honorific': honorific, 'honorific': honorific,
'signature': signature, 'content': content,
'username': user.username, 'user': user,
'rest_password_url': reverse('authentication:reset-password', external=True), 'rest_password_url': reverse('authentication:reset-password', external=True),
'rest_password_token': user.generate_reset_token(), 'rest_password_token': user.generate_reset_token(),
'forget_password_url': reverse('authentication:forgot-password', external=True), 'forget_password_url': reverse('authentication:forgot-password', external=True),
'email': user.email,
'login_url': reverse('authentication:login', external=True), 'login_url': reverse('authentication:login', external=True),
} }
message = render_to_string('users/_msg_user_created.html', context) message = render_to_string('users/_msg_user_created.html', context)

View File

@ -1,13 +1,15 @@
{% load i18n %} {% load i18n %}
<p> <p>
{{ honorific }}: {{ honorific }} {{ user }},
</p> </p>
<div> <div>
<p>{% trans 'Your account has been created successfully' %}</p>
<p> <p>
{% trans 'Username' %}: {{ username }} <br /> {{ content }}
</p>
<p>
{% trans 'Username' %}: {{ user.username }} <br />
{% trans 'Password' %}: {% trans 'Password' %}:
<a href="{{ rest_password_url}}?token={{ rest_password_token }}"> <a href="{{ rest_password_url}}?token={{ rest_password_token }}">
{% trans 'click here to set your password' %} {% trans 'click here to set your password' %}
@ -15,6 +17,6 @@
</p> </p>
<p> <p>
{% trans 'This link is valid for 1 hour. After it expires' %} {% trans 'This link is valid for 1 hour. After it expires' %}
<a href="{{ forget_password_url }}?email={{ email }}">{% trans 'request new one' %}</a> <a href="{{ forget_password_url }}?email={{ user.email }}">{% trans 'request new one' %}</a>
</p> </p>
</div> </div>

View File

@ -22,7 +22,7 @@ def send_user_created_mail(user):
from .notifications import UserCreatedMsg from .notifications import UserCreatedMsg
recipient_list = [user.email] recipient_list = [user.email]
msg = UserCreatedMsg.html_msg msg = UserCreatedMsg(user).html_msg
subject = msg['subject'] subject = msg['subject']
message = msg['message'] message = msg['message']

View File

@ -96,7 +96,7 @@ ipython
huaweicloud-sdk-python==1.0.21 huaweicloud-sdk-python==1.0.21
django-redis==4.11.0 django-redis==4.11.0
python-redis-lock==3.5.0 python-redis-lock==3.5.0
jumpserver-django-oidc-rp==0.3.7.7 jumpserver-django-oidc-rp==0.3.7.8
django-mysql==3.9.0 django-mysql==3.9.0
gmssl==3.2.1 gmssl==3.2.1
azure-mgmt-compute==4.6.2 azure-mgmt-compute==4.6.2
@ -119,4 +119,4 @@ cx-Oracle==8.2.1
psycopg2-binary==2.9.1 psycopg2-binary==2.9.1
alibabacloud_dysmsapi20170525==2.0.2 alibabacloud_dysmsapi20170525==2.0.2
geoip2==4.4.0 geoip2==4.4.0
html2text==2020.1.16 html2text==2020.1.16