diff --git a/.dockerignore b/.dockerignore index cbc1f8c97..0353b6cd4 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,4 +6,5 @@ tmp/* django.db celerybeat.pid ### Vagrant ### -.vagrant/ \ No newline at end of file +.vagrant/ +apps/xpack/.git \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index cf70c1d19..f9cbb8e35 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ +# 编译代码 FROM python:3.8.6-slim as stage-build MAINTAINER JumpServer Team ARG VERSION @@ -7,9 +8,12 @@ WORKDIR /opt/jumpserver ADD . . RUN cd utils && bash -ixeu build.sh +# 构建运行时环境 FROM python:3.8.6-slim ARG PIP_MIRROR=https://pypi.douban.com/simple ENV PIP_MIRROR=$PIP_MIRROR +ARG PIP_JMS_MIRROR=https://pypi.douban.com/simple +ENV PIP_JMS_MIRROR=$PIP_JMS_MIRROR 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 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} \ && rm -rf ~/.cache/pip diff --git a/apps/acls/migrations/0002_auto_20210926_1047.py b/apps/acls/migrations/0002_auto_20210926_1047.py index fa45cd25a..45171a5f7 100644 --- a/apps/acls/migrations/0002_auto_20210926_1047.py +++ b/apps/acls/migrations/0002_auto_20210926_1047.py @@ -54,6 +54,7 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('acls', '0001_initial'), + ('authentication', '0004_ssotoken'), ] operations = [ @@ -86,4 +87,12 @@ class Migration(migrations.Migration): model_name='loginacl', 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'}, + ), ] diff --git a/apps/acls/models/login_acl.py b/apps/acls/models/login_acl.py index bf69c1018..bdc1c8d9e 100644 --- a/apps/acls/models/login_acl.py +++ b/apps/acls/models/login_acl.py @@ -40,6 +40,7 @@ class LoginACL(BaseACL): class Meta: ordering = ('priority', '-date_updated', 'name') + verbose_name = _('Login acl') def __str__(self): return self.name diff --git a/apps/acls/models/login_asset_acl.py b/apps/acls/models/login_asset_acl.py index bf47fa578..0bde3c14f 100644 --- a/apps/acls/models/login_asset_acl.py +++ b/apps/acls/models/login_asset_acl.py @@ -37,6 +37,7 @@ class LoginAssetACL(BaseACL, OrgModelMixin): class Meta: unique_together = ('name', 'org_id') ordering = ('priority', '-date_updated', 'name') + verbose_name = _('Login asset acl') def __str__(self): return self.name diff --git a/apps/applications/migrations/0013_auto_20211026_1711.py b/apps/applications/migrations/0013_auto_20211026_1711.py new file mode 100644 index 000000000..28d80cdbc --- /dev/null +++ b/apps/applications/migrations/0013_auto_20211026_1711.py @@ -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'}, + ), + ] diff --git a/apps/applications/models/application.py b/apps/applications/models/application.py index 7b641b7c4..5df8e3dfd 100644 --- a/apps/applications/models/application.py +++ b/apps/applications/models/application.py @@ -180,6 +180,7 @@ class Application(CommonModelMixin, OrgModelMixin, ApplicationTreeNodeMixin): ) class Meta: + verbose_name = _('Application') unique_together = [('org_id', 'name')] ordering = ('name',) diff --git a/apps/applications/serializers/application.py b/apps/applications/serializers/application.py index 0eba3e3e9..6fecd3a67 100644 --- a/apps/applications/serializers/application.py +++ b/apps/applications/serializers/application.py @@ -104,7 +104,8 @@ class AppAccountSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): extra_kwargs = { 'username': {'default': '', 'required': False}, 'password': {'write_only': True}, - 'app_display': {'label': _('Application display')} + 'app_display': {'label': _('Application display')}, + 'systemuser_display': {'label': _('System User')} } use_model_bulk_create = True model_bulk_create_kwargs = { @@ -134,4 +135,6 @@ class AppAccountSecretSerializer(AppAccountSerializer): 'password': {'write_only': False}, 'private_key': {'write_only': False}, 'public_key': {'write_only': False}, + 'app_display': {'label': _('Application display')}, + 'systemuser_display': {'label': _('System User')} } diff --git a/apps/assets/api/system_user.py b/apps/assets/api/system_user.py index 01baf000b..213858e13 100644 --- a/apps/assets/api/system_user.py +++ b/apps/assets/api/system_user.py @@ -41,7 +41,7 @@ class SystemUserViewSet(SuggestionMixin, OrgBulkModelViewSet): 'default': serializers.SystemUserSerializer, 'suggestion': serializers.MiniSystemUserSerializer } - ordering_fields = ('name', 'protocol') + ordering_fields = ('name', 'protocol', 'login_mode') ordering = ('name', ) permission_classes = (IsOrgAdminOrAppUser,) diff --git a/apps/assets/serializers/system_user.py b/apps/assets/serializers/system_user.py index 85968ca25..b662d062c 100644 --- a/apps/assets/serializers/system_user.py +++ b/apps/assets/serializers/system_user.py @@ -26,7 +26,9 @@ class SystemUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer): auto_generate_key = serializers.BooleanField(initial=True, required=False, write_only=True) type_display = serializers.ReadOnlyField(source='get_type_display', label=_('Type display')) ssh_key_fingerprint = serializers.ReadOnlyField(label=_('SSH key fingerprint')) - 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: model = SystemUser diff --git a/apps/authentication/errors.py b/apps/authentication/errors.py index a1c7dd427..8a6f219bd 100644 --- a/apps/authentication/errors.py +++ b/apps/authentication/errors.py @@ -372,9 +372,19 @@ class NotEnableMFAError(JMSException): default_detail = mfa_unset_msg -class OTPRequiredError(JMSException): +class OTPBindRequiredError(JMSException): default_detail = otp_unset_msg def __init__(self, url, *args, **kwargs): super().__init__(*args, **kwargs) 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') diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index 5a3fc4bbc..d07cfb0d7 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -242,7 +242,12 @@ class AuthMixin(PasswordEncryptionViewMixin): data = request.POST code = data.get('code') 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) def _check_login_acl(self, user, ip): @@ -405,9 +410,12 @@ class AuthMixin(PasswordEncryptionViewMixin): if not user.mfa_enabled: 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: 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() self.check_mfa_is_block(user.username, ip) diff --git a/apps/authentication/views/login.py b/apps/authentication/views/login.py index c39f9b7ec..ab86f2a0b 100644 --- a/apps/authentication/views/login.py +++ b/apps/authentication/views/login.py @@ -124,18 +124,19 @@ class UserLoginView(mixins.AuthMixin, FormView): except ( errors.PasswdTooSimple, errors.PasswordRequireResetError, - errors.PasswdNeedUpdate + errors.PasswdNeedUpdate, + errors.OTPBindRequiredError ) as e: return redirect(e.url) except ( - errors.MFAUnsetError, errors.MFAFailedError, - errors.BlockMFAError + errors.BlockMFAError, + errors.OTPCodeRequiredError, + errors.SMSCodeRequiredError, + errors.UserPhoneNotSet ) as e: form.add_error('code', e.msg) return super().form_invalid(form) - except errors.OTPRequiredError as e: - return redirect(e.url) self.clear_rsa_key() return self.redirect_to_guard_view() diff --git a/apps/common/utils/timezone.py b/apps/common/utils/timezone.py index 6848e7428..c38fcdc92 100644 --- a/apps/common/utils/timezone.py +++ b/apps/common/utils/timezone.py @@ -25,7 +25,7 @@ def utc_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'): diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index 9cc3284a2..b525dff3c 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -18,6 +18,7 @@ import copy from importlib import import_module from django.urls import reverse_lazy 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__))) PROJECT_DIR = os.path.dirname(BASE_DIR) @@ -263,6 +264,11 @@ class Config(dict): 'TENCENT_VERIFY_SIGN_NAME': '', '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_ISSUER_NAME': 'JumpServer', 'EMAIL_SUFFIX': 'example.com', diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index dac4a4b09..aa4a2071d 100644 --- a/apps/locale/zh/LC_MESSAGES/django.mo +++ b/apps/locale/zh/LC_MESSAGES/django.mo @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:55a2062981ea7eef4ca28142f325f52e15cb7679ad0a2600234a5bdb6d005c87 -size 89996 +oid sha256:cc8a022ddc7438e50aa0cdb4ce24eec327638143731dbe0ed0ad783df06ecbaf +size 89882 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 5dcdd8488..763d0a248 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\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" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -74,7 +74,7 @@ msgstr "拒绝" msgid "Allow" 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 msgid "Login confirm" msgstr "登录复核" @@ -116,14 +116,20 @@ msgstr "动作" msgid "Reviewers" msgstr "审批人" +#: acls/models/login_acl.py:43 +msgid "Login acl" +msgstr "登录访问控制" + #: acls/models/login_asset_acl.py:21 +#: applications/serializers/application.py:108 +#: applications/serializers/application.py:139 msgid "System User" msgstr "系统用户" #: acls/models/login_asset_acl.py:22 #: applications/serializers/attrs/application_category/remote_app.py:37 #: 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 #: templates/index.html:82 terminal/backends/command/models.py:19 #: terminal/backends/command/serializers.py:13 terminal/models/session.py:40 @@ -135,7 +141,11 @@ msgstr "系统用户" msgid "Asset" 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" msgstr "登录资产复核" @@ -153,7 +163,7 @@ msgstr "格式为逗号分隔的字符串, * 表示匹配所有. " #: audits/models.py:105 authentication/forms.py:15 authentication/forms.py:17 #: authentication/templates/authentication/_msg_different_city.html:9 #: 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 #: xpack/plugins/change_auth_plan/models/asset.py:35 #: xpack/plugins/change_auth_plan/models/asset.py:191 @@ -312,6 +322,11 @@ msgstr "网域" msgid "Attrs" 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:89 assets/serializers/label.py:13 #: perms/serializers/application/permission.py:16 @@ -330,6 +345,7 @@ msgid "Type display" msgstr "类型名称" #: applications/serializers/application.py:107 +#: applications/serializers/application.py:138 msgid "Application display" msgstr "应用名称" @@ -384,7 +400,7 @@ msgstr "目标URL" #: authentication/forms.py:22 #: authentication/templates/authentication/login.html:151 #: 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_password_update.html:43 #: users/templates/users/user_password_verify.html:18 @@ -747,7 +763,7 @@ msgstr "全称" msgid "Parent key" 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:73 #: users/templates/users/user_asset_permission.html:158 @@ -848,7 +864,7 @@ msgstr "节点名称" msgid "Hardware info" 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 msgid "Org name" msgstr "组织名称" @@ -862,7 +878,7 @@ msgid "private key invalid" msgstr "密钥不合法" #: 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 msgid "Assets amount" msgstr "资产数量" @@ -892,52 +908,52 @@ msgstr "同级别节点名字不能重复" msgid "SSH key fingerprint" msgstr "密钥指纹" -#: assets/serializers/system_user.py:29 +#: assets/serializers/system_user.py:30 msgid "Apps amount" msgstr "应用数量" -#: assets/serializers/system_user.py:53 +#: assets/serializers/system_user.py:55 #: perms/serializers/asset/permission.py:73 msgid "Nodes amount" 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" msgstr "认证方式名称" -#: assets/serializers/system_user.py:57 +#: assets/serializers/system_user.py:59 msgid "Ad domain" msgstr "Ad 网域" -#: assets/serializers/system_user.py:58 +#: assets/serializers/system_user.py:60 msgid "Is asset protocol" msgstr "" -#: assets/serializers/system_user.py:98 +#: assets/serializers/system_user.py:100 msgid "Username same with user with protocol {} only allow 1" 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" msgstr "不能包含特殊字符" -#: assets/serializers/system_user.py:117 +#: assets/serializers/system_user.py:119 msgid "* Automatic login mode must fill in the username." msgstr "自动登录模式,必须填写用户名" -#: assets/serializers/system_user.py:132 +#: assets/serializers/system_user.py:134 msgid "Path should starts with /" msgstr "路径应该以 / 开头" -#: assets/serializers/system_user.py:144 +#: assets/serializers/system_user.py:146 msgid "Password or private key required" msgstr "密码或密钥密码需要一个" -#: assets/serializers/system_user.py:248 +#: assets/serializers/system_user.py:250 msgid "System user name" msgstr "系统用户名称" -#: assets/serializers/system_user.py:258 +#: assets/serializers/system_user.py:260 msgid "Asset hostname" msgstr "资产主机名" @@ -1257,12 +1273,12 @@ msgstr "" msgid "Auth Token" 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 msgid "WeCom" 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 msgid "DingTalk" msgstr "钉钉" @@ -1424,7 +1440,7 @@ msgstr "{ApplicationPermission} 移除 {UserGroup}" #: audits/signals_handler.py:157 perms/models/application_permission.py:37 msgid "Application permission" -msgstr "应用管理" +msgstr "应用授权" #: audits/signals_handler.py:158 #, python-brace-format @@ -1641,15 +1657,15 @@ msgstr "该 时间段 不被允许登录" msgid "SSO auth closed" 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" 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" 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" msgstr "您的密码已过期,先修改再登录" @@ -1661,6 +1677,18 @@ msgstr "您的密码无效" msgid "No upload or download permission" 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 msgid "{} days auto login" msgstr "{} 天内自动登录" @@ -1681,11 +1709,11 @@ msgstr "多因子认证验证码" msgid "Dynamic code" msgstr "动态码" -#: authentication/mixins.py:330 +#: authentication/mixins.py:335 msgid "Please change your password" msgstr "请修改密码" -#: authentication/mixins.py:515 +#: authentication/mixins.py:523 msgid "SMS" msgstr "短信" @@ -1796,6 +1824,7 @@ msgstr "代码错误" #: authentication/templates/authentication/_msg_different_city.html:3 #: authentication/templates/authentication/_msg_reset_password.html:3 #: 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_permed_items_expire.html:3 #: users/templates/users/_msg_account_expire_reminder.html:4 @@ -1830,12 +1859,12 @@ msgid "Click here reset password" msgstr "点击这里重置密码" #: 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" msgstr "这个链接有效期1小时, 超过时间您可以" #: 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" msgstr "重新申请" @@ -1999,12 +2028,12 @@ msgstr "正在跳转到 {} 认证" msgid "Please enable cookies and try again." 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 msgid "FeiShu" msgstr "飞书" -#: authentication/views/login.py:268 +#: authentication/views/login.py:269 msgid "" "Wait for {} confirm, You also can copy link to her/him
\n" " Don't close this page" @@ -2012,15 +2041,15 @@ msgstr "" "等待 {} 确认, 你也可以复制链接发给他/她
\n" " 不要关闭本页面" -#: authentication/views/login.py:273 +#: authentication/views/login.py:274 msgid "No ticket found" msgstr "没有发现工单" -#: authentication/views/login.py:305 +#: authentication/views/login.py:306 msgid "Logout success" msgstr "退出登录成功" -#: authentication/views/login.py:306 +#: authentication/views/login.py:307 msgid "Logout success, return login page" msgstr "退出登录成功,返回到登录页面" @@ -2207,6 +2236,14 @@ msgstr "不能包含特殊字符" msgid "The mobile phone number format is incorrect" 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 msgid "JumpServer Open Source Bastion Host" msgstr "JumpServer 开源堡垒机" @@ -2467,10 +2504,6 @@ msgstr "管理员正在修改授权,请稍等" msgid "The authorization cannot be revoked for the time being" 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 msgid "All" msgstr "全部" @@ -3100,7 +3133,7 @@ msgstr "提示: 创建用户时,发送设置密码邮件的主题 (例如: 创 #: settings/serializers/email.py:54 msgid "Create user honorific" -msgstr "邮件的敬语" +msgstr "邮件问候语" #: settings/serializers/email.py:55 msgid "Tips: When creating a user, send the honorific of the email (eg:Hello)" @@ -3671,14 +3704,6 @@ msgstr "请输入验证码" msgid "Send verification code" 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 msgid "Wait: " msgstr "等待:" @@ -3989,6 +4014,27 @@ msgstr "前" msgid "Login in " 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 msgid "Filters" msgstr "过滤" @@ -4776,10 +4822,6 @@ msgstr "设置密码" msgid "MFA not enabled" msgstr "MFA没有开启" -#: users/exceptions.py:15 -msgid "Phone not set" -msgstr "手机号没有设置" - #: users/exceptions.py:20 msgid "MFA method not support" msgstr "MFA 方法不支持" @@ -4908,38 +4950,30 @@ msgstr "管理员" msgid "Administrator is the super user of system" msgstr "Administrator是初始的超级管理员" -#: users/notifications.py:15 -msgid "Create account successfully" -msgstr "创建账户成功" - -#: users/notifications.py:19 -msgid "Hello {}" -msgstr "你好" - -#: users/notifications.py:51 +#: users/notifications.py:48 #: users/templates/users/_msg_password_expire_reminder.html:17 #: users/templates/users/reset_password.html:5 #: users/templates/users/reset_password.html:6 msgid "Reset password" 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" msgstr "重置密码成功" -#: users/notifications.py:107 +#: users/notifications.py:104 msgid "Password is about expire" msgstr "密码即将过期" -#: users/notifications.py:135 +#: users/notifications.py:132 msgid "Account is about expire" msgstr "账号即将过期" -#: users/notifications.py:157 +#: users/notifications.py:154 msgid "Reset SSH Key" msgstr "重置 SSH 密钥" -#: users/notifications.py:178 +#: users/notifications.py:175 msgid "Reset MFA" msgstr "重置 MFA" @@ -5109,11 +5143,7 @@ msgstr "点击这里设置" msgid "Your ssh public key has been reset by site administrator" msgstr "你的 SSH 密钥已经被管理员重置" -#: users/templates/users/_msg_user_created.html:8 -msgid "Your account has been created successfully" -msgstr "您的账户已创建成功" - -#: users/templates/users/_msg_user_created.html:13 +#: users/templates/users/_msg_user_created.html:15 msgid "click here to set your password" msgstr "点击这里设置密码" @@ -5500,15 +5530,15 @@ msgstr "* 请输入正确的密码长度" msgid "* Password length range 6-30 bits" 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" 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" 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" msgstr "无法将数据发送到远程" @@ -5866,7 +5896,7 @@ msgstr "执行次数" msgid "Instance count" msgstr "实例个数" -#: xpack/plugins/cloud/utils.py:65 +#: xpack/plugins/cloud/utils.py:68 msgid "Account unavailable" msgstr "账户无效" @@ -5954,6 +5984,10 @@ msgstr "旗舰版" msgid "Community edition" msgstr "社区版" +#, python-brace-format +#~ msgid "Hello {name}" +#~ msgstr "你好 {name}" + #~ msgid "Login direct" #~ msgstr "直接登录" diff --git a/apps/templates/resource_download.html b/apps/templates/resource_download.html index df1dbc31c..f03b20686 100644 --- a/apps/templates/resource_download.html +++ b/apps/templates/resource_download.html @@ -1,16 +1,36 @@ {% extends '_without_nav_base.html' %} +{% load i18n %} {% block body %} +
-

JumpServer Clients

+

JumpServer {% trans 'Client' %}

+

+ {% trans 'JumpServer Client, currently used to launch the client, now only support launch RDP client, The SSH client will next' %} +{# //JumpServer 客户端,支持 RDP 的本地拉起,后续会支持拉起 ssh。#} +

-

RDP Clients

+

{% trans 'Microsoft' %} RDP {% trans 'Official' %}{% trans 'Client' %}

+

+ {% trans 'macOS needs to download the client to connect RDP asset, which comes with Windows' %} +

diff --git a/apps/terminal/backends/command/es.py b/apps/terminal/backends/command/es.py index 678698ff6..7863dbbfb 100644 --- a/apps/terminal/backends/command/es.py +++ b/apps/terminal/backends/command/es.py @@ -131,10 +131,13 @@ class CommandStore(): index=self.index, doc_type=self.doc_type, body=body, from_=from_, size=size, 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( - [item['_source'] for item in data['hits']['hits'] if item] - ) + return AbstractSessionCommand.from_multi_dict(source_data) def count(self, **query): body = self.get_query_body(**query) @@ -160,11 +163,16 @@ class CommandStore(): new_kwargs[k] = str(v) if isinstance(v, UUID) else v kwargs = new_kwargs + index_in_field = 'id__in' exact_fields = self.exact_fields match_fields = self.match_fields match = {} exact = {} + index = {} + + if index_in_field in kwargs: + index['values'] = kwargs[index_in_field] for k, v in kwargs.items(): if k in exact_fields: @@ -221,6 +229,10 @@ class CommandStore(): 'timestamp': timestamp_range } } + ] + [ + { + 'ids': {k: v} + } for k, v in index.items() ] } }, diff --git a/apps/terminal/serializers/command.py b/apps/terminal/serializers/command.py index d1e14aa49..01343e825 100644 --- a/apps/terminal/serializers/command.py +++ b/apps/terminal/serializers/command.py @@ -8,3 +8,4 @@ class InsecureCommandAlertSerializer(serializers.Serializer): user = serializers.CharField() risk_level = serializers.IntegerField() session = serializers.UUIDField() + org_id = serializers.CharField() diff --git a/apps/tickets/api/ticket.py b/apps/tickets/api/ticket.py index 86d06f062..82fd8bd55 100644 --- a/apps/tickets/api/ticket.py +++ b/apps/tickets/api/ticket.py @@ -29,7 +29,7 @@ class TicketViewSet(CommonApiMixin, viewsets.ModelViewSet): search_fields = [ 'title', 'action', 'type', 'status', 'applicant_display' ] - ordering_fields = ('title',) + ordering_fields = ('title', 'applicant_display', 'status', 'state', 'action_display', 'date_created') ordering = ('title', ) def create(self, request, *args, **kwargs): diff --git a/apps/users/notifications.py b/apps/users/notifications.py index 83ab9c532..c97a5d690 100644 --- a/apps/users/notifications.py +++ b/apps/users/notifications.py @@ -12,21 +12,18 @@ from notifications.notifications import UserMessage class UserCreatedMsg(UserMessage): def get_html_msg(self) -> dict: 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) - signature = settings.EMAIL_CUSTOM_USER_CREATED_SIGNATURE or 'JumpServer' + subject = str(settings.EMAIL_CUSTOM_USER_CREATED_SUBJECT) + honorific = str(settings.EMAIL_CUSTOM_USER_CREATED_HONORIFIC) + content = str(settings.EMAIL_CUSTOM_USER_CREATED_BODY) context = { 'honorific': honorific, - 'signature': signature, - 'username': user.username, + 'content': content, + 'user': user, 'rest_password_url': reverse('authentication:reset-password', external=True), 'rest_password_token': user.generate_reset_token(), 'forget_password_url': reverse('authentication:forgot-password', external=True), - 'email': user.email, 'login_url': reverse('authentication:login', external=True), } message = render_to_string('users/_msg_user_created.html', context) diff --git a/apps/users/templates/users/_msg_user_created.html b/apps/users/templates/users/_msg_user_created.html index c0515e9f6..678ca237f 100644 --- a/apps/users/templates/users/_msg_user_created.html +++ b/apps/users/templates/users/_msg_user_created.html @@ -1,13 +1,15 @@ {% load i18n %}

- {{ honorific }}: + {{ honorific }} {{ user }},

-

{% trans 'Your account has been created successfully' %}

- {% trans 'Username' %}: {{ username }}
+ {{ content }} +

+

+ {% trans 'Username' %}: {{ user.username }}
{% trans 'Password' %}: {% trans 'click here to set your password' %} @@ -15,6 +17,6 @@

{% trans 'This link is valid for 1 hour. After it expires' %} - {% trans 'request new one' %} + {% trans 'request new one' %}

diff --git a/apps/users/utils.py b/apps/users/utils.py index 8be6a4928..cadbe6790 100644 --- a/apps/users/utils.py +++ b/apps/users/utils.py @@ -22,7 +22,7 @@ def send_user_created_mail(user): from .notifications import UserCreatedMsg recipient_list = [user.email] - msg = UserCreatedMsg.html_msg + msg = UserCreatedMsg(user).html_msg subject = msg['subject'] message = msg['message'] diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 49d7c5a5e..b3873af1d 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -96,7 +96,7 @@ ipython huaweicloud-sdk-python==1.0.21 django-redis==4.11.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 gmssl==3.2.1 azure-mgmt-compute==4.6.2 @@ -119,4 +119,4 @@ cx-Oracle==8.2.1 psycopg2-binary==2.9.1 alibabacloud_dysmsapi20170525==2.0.2 geoip2==4.4.0 -html2text==2020.1.16 \ No newline at end of file +html2text==2020.1.16