From c929c1a87e5232b95293136d7fae999438df3c1e Mon Sep 17 00:00:00 2001 From: BaiJiangJie <32935519+BaiJiangJie@users.noreply.github.com> Date: Wed, 24 Jul 2019 12:50:39 +0800 Subject: [PATCH] =?UTF-8?q?[Bugfix]=20=E8=A7=A3=E5=86=B3=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=E6=A8=A1=E7=89=88=E6=97=B6KeyError=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=88=E6=95=B0=E6=8D=AE=E4=B8=BA=E7=A9=BA?= =?UTF-8?q?=E6=97=B6=EF=BC=89=20(#3017)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Bugfix] 解决下载导入模版时KeyError的问题(数据为空时) * [Bugfix] 解决下载导入模版时KeyError的问题(数据为空时)2 * [Bugfix] 解决下载导入模版时KeyError的问题(数据为空时)3 * [Update] 解决LDAP用户禁用后,终端还可以登录成功一次的问题 * [Update] 解决LDAP用户禁用后,终端还可以登录成功一次的问题2 * [Update] LDAP AD Server可以通过UserAccountControl映射is_active字段 * [Update] 限制只有local用户可以更新ssh key * [Update] 限制只有local用户可以更新ssh key 2 --- apps/authentication/backends/ldap.py | 25 +- .../backends/openid/backends.py | 4 +- apps/common/const.py | 4 + apps/common/permissions.py | 10 + apps/common/renders/csv.py | 4 +- apps/locale/zh/LC_MESSAGES/django.mo | Bin 77852 -> 77965 bytes apps/locale/zh/LC_MESSAGES/django.po | 410 +++++++++--------- apps/settings/utils.py | 12 +- apps/users/forms.py | 2 +- apps/users/models/user.py | 3 + apps/users/templates/users/first_login.html | 54 ++- apps/users/templates/users/user_detail.html | 4 + .../templates/users/user_password_update.html | 4 + apps/users/templates/users/user_profile.html | 6 + .../templates/users/user_profile_update.html | 4 + .../templates/users/user_pubkey_update.html | 4 + apps/users/templates/users/user_update.html | 19 +- apps/users/utils.py | 2 +- apps/users/views/user.py | 31 +- 19 files changed, 338 insertions(+), 264 deletions(-) diff --git a/apps/authentication/backends/ldap.py b/apps/authentication/backends/ldap.py index 3e58e08fa..9dd151561 100644 --- a/apps/authentication/backends/ldap.py +++ b/apps/authentication/backends/ldap.py @@ -8,6 +8,7 @@ from django_auth_ldap.backend import _LDAPUser, LDAPBackend from django_auth_ldap.config import _LDAPConfig, LDAPSearch, LDAPSearchUnion from users.utils import construct_user_email +from common.const import LDAP_AD_ACCOUNT_DISABLE logger = _LDAPConfig.get_logger() @@ -17,6 +18,15 @@ class LDAPAuthorizationBackend(LDAPBackend): Override this class to override _LDAPUser to LDAPUser """ + @staticmethod + def user_can_authenticate(user): + """ + Reject users with is_active=False. Custom user models that don't have + that attribute are allowed. + """ + is_valid = getattr(user, 'is_valid', None) + return is_valid or is_valid is None + def authenticate(self, request=None, username=None, password=None, **kwargs): logger.info('Authentication LDAP backend') if not username: @@ -25,34 +35,29 @@ class LDAPAuthorizationBackend(LDAPBackend): ldap_user = LDAPUser(self, username=username.strip(), request=request) user = self.authenticate_ldap_user(ldap_user, password) logger.info('Authenticate user: {}'.format(user)) - return user + return user if self.user_can_authenticate(user) else None def get_user(self, user_id): user = None - try: user = self.get_user_model().objects.get(pk=user_id) LDAPUser(self, user=user) # This sets user.ldap_user except ObjectDoesNotExist: pass - return user def get_group_permissions(self, user, obj=None): if not hasattr(user, 'ldap_user') and self.settings.AUTHORIZE_ALL_USERS: LDAPUser(self, user=user) # This sets user.ldap_user - if hasattr(user, 'ldap_user'): permissions = user.ldap_user.get_group_permissions() else: permissions = set() - return permissions def populate_user(self, username): ldap_user = LDAPUser(self, username=username) user = ldap_user.populate_user() - return user @@ -91,13 +96,19 @@ class LDAPUser(_LDAPUser): for field, attr in self.settings.USER_ATTR_MAP.items(): try: value = self.attrs[attr][0] + if attr.lower() == 'useraccountcontrol' \ + and field == 'is_active' and value: + value = int(value) & LDAP_AD_ACCOUNT_DISABLE \ + != LDAP_AD_ACCOUNT_DISABLE except LookupError: logger.warning("{} does not have a value for the attribute {}".format(self.dn, attr)) else: if not hasattr(self._user, field): continue if isinstance(getattr(self._user, field), bool): - value = value.lower() in ['true', '1'] + if isinstance(value, str): + value = value.lower() + value = value in ['true', '1', True] setattr(self._user, field, value) email = getattr(self._user, 'email', '') diff --git a/apps/authentication/backends/openid/backends.py b/apps/authentication/backends/openid/backends.py index f6285d1ed..938566e2a 100644 --- a/apps/authentication/backends/openid/backends.py +++ b/apps/authentication/backends/openid/backends.py @@ -26,8 +26,8 @@ class BaseOpenIDAuthorizationBackend(object): Reject users with is_active=False. Custom user models that don't have that attribute are allowed. """ - is_active = getattr(user, 'is_active', None) - return is_active or is_active is None + is_valid = getattr(user, 'is_valid', None) + return is_valid or is_valid is None def get_user(self, user_id): try: diff --git a/apps/common/const.py b/apps/common/const.py index 72d92da81..65d445eec 100644 --- a/apps/common/const.py +++ b/apps/common/const.py @@ -8,3 +8,7 @@ update_success_msg = _("%(name)s was updated successfully") FILE_END_GUARD = ">>> Content End <<<" celery_task_pre_key = "CELERY_" KEY_CACHE_RESOURCES_ID = "RESOURCES_ID_{}" + +# AD User AccountDisable +# https://blog.csdn.net/bytxl/article/details/17763975 +LDAP_AD_ACCOUNT_DISABLE = 2 diff --git a/apps/common/permissions.py b/apps/common/permissions.py index bdc25fe21..8bea6b390 100644 --- a/apps/common/permissions.py +++ b/apps/common/permissions.py @@ -137,6 +137,16 @@ class PermissionsMixin(UserPassesTestMixin): return True +class UserCanUpdatePassword: + def has_permission(self, request, view): + return request.user.can_update_password() + + +class UserCanUpdateSSHKey: + def has_permission(self, request, view): + return request.user.can_update_ssh_key() + + class NeedMFAVerify(permissions.BasePermission): def has_permission(self, request, view): mfa_verify_time = request.session.get('MFA_VERIFY_TIME', 0) diff --git a/apps/common/renders/csv.py b/apps/common/renders/csv.py index 9bd60cfbc..f80498f55 100644 --- a/apps/common/renders/csv.py +++ b/apps/common/renders/csv.py @@ -58,8 +58,8 @@ class JMSCSVRender(BaseRenderer): template = request.query_params.get('template', 'export') view = renderer_context['view'] - if isinstance(data, dict) and data.get("count"): - data = data["results"] + if isinstance(data, dict): + data = data.get("results", []) if template == 'import': data = [data[0]] if data else data diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 10f1b3d14f4892b3f6e87ed733d0f01fe041537f..9b03f5645d46799aad709624a09b42520379bfaa 100644 GIT binary patch delta 18415 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 R)QmTFPTVr4OyI+?{{uJM@k9Us delta 18310 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
  • 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\n" "Language-Team: Jumpserver team\n" @@ -167,13 +167,13 @@ msgstr "系统用户" #: settings/templates/settings/terminal_setting.html:105 terminal/models.py:22 #: terminal/models.py:258 terminal/templates/terminal/terminal_detail.html:43 #: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14 -#: users/models/user.py:324 users/templates/users/_select_user_modal.html:13 +#: users/models/user.py:327 users/templates/users/_select_user_modal.html:13 #: users/templates/users/user_detail.html:63 #: users/templates/users/user_group_detail.html:55 #: users/templates/users/user_group_list.html:35 #: users/templates/users/user_list.html:35 #: users/templates/users/user_profile.html:51 -#: users/templates/users/user_pubkey_update.html:53 +#: users/templates/users/user_pubkey_update.html:57 #: xpack/plugins/change_auth_plan/forms.py:98 #: xpack/plugins/change_auth_plan/models.py:61 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:61 @@ -218,7 +218,7 @@ msgstr "参数" #: perms/models/asset_permission.py:117 perms/models/base.py:41 #: perms/templates/perms/asset_permission_detail.html:98 #: perms/templates/perms/remote_app_permission_detail.html:90 -#: users/models/user.py:365 users/serializers/v1.py:120 +#: users/models/user.py:368 users/serializers/v1.py:120 #: users/templates/users/user_detail.html:111 #: xpack/plugins/change_auth_plan/models.py:106 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113 @@ -279,10 +279,10 @@ msgstr "创建日期" #: perms/templates/perms/remote_app_permission_detail.html:94 #: settings/models.py:34 terminal/models.py:32 #: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15 -#: users/models/user.py:357 users/templates/users/user_detail.html:127 +#: users/models/user.py:360 users/templates/users/user_detail.html:127 #: users/templates/users/user_group_detail.html:67 #: users/templates/users/user_group_list.html:37 -#: users/templates/users/user_profile.html:134 +#: users/templates/users/user_profile.html:138 #: xpack/plugins/change_auth_plan/models.py:102 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:117 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:19 @@ -331,11 +331,11 @@ msgstr "远程应用" #: users/templates/users/_user.html:50 #: users/templates/users/user_bulk_update.html:23 #: users/templates/users/user_detail.html:176 -#: users/templates/users/user_password_update.html:71 -#: users/templates/users/user_profile.html:204 -#: users/templates/users/user_profile_update.html:63 -#: users/templates/users/user_pubkey_update.html:70 -#: users/templates/users/user_pubkey_update.html:76 +#: users/templates/users/user_password_update.html:75 +#: users/templates/users/user_profile.html:209 +#: users/templates/users/user_profile_update.html:67 +#: users/templates/users/user_pubkey_update.html:74 +#: users/templates/users/user_pubkey_update.html:80 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:71 #: xpack/plugins/cloud/templates/cloud/account_create_update.html:33 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:35 @@ -373,9 +373,9 @@ msgstr "重置" #: users/templates/users/forgot_password.html:42 #: users/templates/users/user_bulk_update.html:24 #: users/templates/users/user_list.html:57 -#: users/templates/users/user_password_update.html:72 -#: users/templates/users/user_profile_update.html:64 -#: users/templates/users/user_pubkey_update.html:77 +#: users/templates/users/user_password_update.html:76 +#: users/templates/users/user_profile_update.html:68 +#: users/templates/users/user_pubkey_update.html:81 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:72 #: xpack/plugins/interface/templates/interface/interface.html:74 #: xpack/plugins/vault/templates/vault/vault_create.html:46 @@ -393,7 +393,7 @@ msgstr "提交" #: assets/templates/assets/system_user_detail.html:18 #: ops/templates/ops/adhoc_history.html:130 #: ops/templates/ops/task_adhoc.html:116 -#: ops/templates/ops/task_history.html:136 +#: ops/templates/ops/task_history.html:137 #: perms/templates/perms/asset_permission_asset.html:18 #: perms/templates/perms/asset_permission_detail.html:18 #: perms/templates/perms/asset_permission_user.html:18 @@ -410,13 +410,13 @@ msgstr "详情" #: applications/templates/applications/remote_app_detail.html:21 #: applications/templates/applications/remote_app_list.html:56 -#: assets/templates/assets/_asset_user_list.html:70 +#: assets/templates/assets/_asset_user_list.html:69 #: assets/templates/assets/admin_user_detail.html:24 #: assets/templates/assets/admin_user_list.html:26 #: assets/templates/assets/admin_user_list.html:111 #: assets/templates/assets/asset_detail.html:27 #: assets/templates/assets/asset_list.html:78 -#: assets/templates/assets/asset_list.html:169 +#: assets/templates/assets/asset_list.html:168 #: assets/templates/assets/cmd_filter_detail.html:29 #: assets/templates/assets/cmd_filter_list.html:58 #: assets/templates/assets/cmd_filter_rule_list.html:86 @@ -441,9 +441,9 @@ msgstr "详情" #: users/templates/users/user_list.html:20 #: users/templates/users/user_list.html:102 #: users/templates/users/user_list.html:105 -#: users/templates/users/user_profile.html:177 -#: users/templates/users/user_profile.html:187 -#: users/templates/users/user_profile.html:196 +#: users/templates/users/user_profile.html:181 +#: users/templates/users/user_profile.html:191 +#: users/templates/users/user_profile.html:201 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:29 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:55 #: xpack/plugins/cloud/templates/cloud/account_detail.html:23 @@ -458,7 +458,7 @@ msgstr "更新" #: assets/templates/assets/admin_user_detail.html:28 #: assets/templates/assets/admin_user_list.html:112 #: assets/templates/assets/asset_detail.html:31 -#: assets/templates/assets/asset_list.html:170 +#: assets/templates/assets/asset_list.html:169 #: assets/templates/assets/cmd_filter_detail.html:33 #: assets/templates/assets/cmd_filter_list.html:59 #: assets/templates/assets/cmd_filter_rule_list.html:87 @@ -723,7 +723,7 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC" #: perms/templates/perms/asset_permission_user.html:55 #: perms/templates/perms/remote_app_permission_user.html:54 #: settings/templates/settings/_ldap_list_users_modal.html:37 users/forms.py:14 -#: users/models/user.py:322 users/templates/users/_select_user_modal.html:14 +#: users/models/user.py:325 users/templates/users/_select_user_modal.html:14 #: users/templates/users/user_detail.html:67 #: users/templates/users/user_list.html:36 #: users/templates/users/user_profile.html:47 @@ -751,9 +751,9 @@ msgstr "密码或密钥密码" #: settings/forms.py:110 users/forms.py:16 users/forms.py:28 #: users/templates/users/reset_password.html:53 #: users/templates/users/user_password_authentication.html:18 -#: users/templates/users/user_password_update.html:43 -#: users/templates/users/user_profile_update.html:40 -#: users/templates/users/user_pubkey_update.html:40 +#: users/templates/users/user_password_update.html:44 +#: users/templates/users/user_profile_update.html:41 +#: users/templates/users/user_pubkey_update.html:41 #: users/templates/users/user_update.html:20 #: xpack/plugins/change_auth_plan/models.py:93 #: xpack/plugins/change_auth_plan/models.py:264 @@ -762,7 +762,7 @@ msgstr "密码" #: assets/forms/user.py:29 assets/serializers/asset_user.py:70 #: assets/templates/assets/_asset_user_auth_update_modal.html:27 -#: users/models/user.py:351 +#: users/models/user.py:354 msgid "Private key" msgstr "ssh私钥" @@ -968,7 +968,7 @@ msgstr "带宽" msgid "Contact" msgstr "联系人" -#: assets/models/cluster.py:22 users/models/user.py:343 +#: assets/models/cluster.py:22 users/models/user.py:346 #: users/templates/users/user_detail.html:76 msgid "Phone" msgstr "手机" @@ -994,7 +994,7 @@ msgid "Default" msgstr "默认" #: assets/models/cluster.py:36 assets/models/label.py:14 -#: users/models/user.py:451 +#: users/models/user.py:454 msgid "System" msgstr "系统" @@ -1113,9 +1113,9 @@ msgstr "默认资产组" #: terminal/templates/terminal/command_list.html:65 #: terminal/templates/terminal/session_list.html:27 #: terminal/templates/terminal/session_list.html:71 users/forms.py:316 -#: users/models/user.py:121 users/models/user.py:439 +#: users/models/user.py:124 users/models/user.py:442 #: users/serializers/v1.py:109 users/templates/users/user_group_detail.html:78 -#: users/templates/users/user_group_list.html:36 users/views/user.py:251 +#: users/templates/users/user_group_list.html:36 users/views/user.py:243 #: xpack/plugins/orgs/forms.py:26 #: xpack/plugins/orgs/templates/orgs/org_detail.html:113 #: xpack/plugins/orgs/templates/orgs/org_list.html:14 @@ -1153,9 +1153,9 @@ msgstr "手动登录" #: assets/templates/assets/system_user_detail.html:22 #: assets/views/admin_user.py:30 assets/views/admin_user.py:49 #: assets/views/admin_user.py:67 assets/views/admin_user.py:84 -#: assets/views/admin_user.py:109 assets/views/asset.py:40 -#: assets/views/asset.py:57 assets/views/asset.py:106 assets/views/asset.py:133 -#: assets/views/asset.py:173 assets/views/asset.py:203 +#: assets/views/admin_user.py:109 assets/views/asset.py:38 +#: assets/views/asset.py:55 assets/views/asset.py:104 assets/views/asset.py:131 +#: assets/views/asset.py:171 assets/views/asset.py:203 #: assets/views/cmd_filter.py:31 assets/views/cmd_filter.py:48 #: assets/views/cmd_filter.py:66 assets/views/cmd_filter.py:84 #: assets/views/cmd_filter.py:104 assets/views/cmd_filter.py:138 @@ -1220,11 +1220,11 @@ msgid "Backend" msgstr "后端" #: assets/serializers/asset_user.py:66 users/forms.py:263 -#: users/models/user.py:354 users/templates/users/first_login.html:42 -#: users/templates/users/user_password_update.html:46 -#: users/templates/users/user_profile.html:68 -#: users/templates/users/user_profile_update.html:43 -#: users/templates/users/user_pubkey_update.html:43 +#: users/models/user.py:357 users/templates/users/first_login.html:42 +#: users/templates/users/user_password_update.html:49 +#: users/templates/users/user_profile.html:69 +#: users/templates/users/user_profile_update.html:46 +#: users/templates/users/user_pubkey_update.html:46 msgid "Public key" msgstr "ssh公钥" @@ -1237,7 +1237,7 @@ msgstr "暂不支持OPENSSH格式的密钥,使用 ssh-keygen -t rsa -m pem生 msgid "private key invalid" msgstr "密钥不合法" -#: assets/serializers/node.py:32 +#: assets/serializers/node.py:33 msgid "The same level node name cannot be the same" msgstr "同级别节点名字不能重复" @@ -1375,7 +1375,7 @@ msgstr "启用MFA" msgid "Import assets" msgstr "导入资产" -#: assets/templates/assets/_asset_list_modal.html:7 assets/views/asset.py:41 +#: assets/templates/assets/_asset_list_modal.html:7 assets/views/asset.py:39 #: templates/_nav.html:22 xpack/plugins/change_auth_plan/views.py:116 msgid "Asset list" msgstr "资产列表" @@ -1395,8 +1395,8 @@ msgstr "请输入密码" #: assets/templates/assets/_asset_user_auth_update_modal.html:68 #: assets/templates/assets/asset_detail.html:307 -#: users/templates/users/user_detail.html:307 -#: users/templates/users/user_detail.html:334 +#: users/templates/users/user_detail.html:309 +#: users/templates/users/user_detail.html:336 #: xpack/plugins/interface/views.py:35 msgid "Update successfully!" msgstr "更新成功" @@ -1435,11 +1435,11 @@ msgstr "日期" msgid "Test datetime: " msgstr "测试日期: " -#: assets/templates/assets/_asset_user_list.html:69 +#: assets/templates/assets/_asset_user_list.html:68 msgid "View" msgstr "查看" -#: assets/templates/assets/_asset_user_list.html:71 +#: assets/templates/assets/_asset_user_list.html:70 #: assets/templates/assets/admin_user_assets.html:61 #: assets/templates/assets/asset_asset_user_list.html:57 #: assets/templates/assets/asset_detail.html:178 @@ -1448,7 +1448,7 @@ msgstr "查看" msgid "Test" msgstr "测试" -#: assets/templates/assets/_asset_user_list.html:72 +#: assets/templates/assets/_asset_user_list.html:71 #: assets/templates/assets/system_user_assets.html:72 #: assets/templates/assets/system_user_detail.html:142 msgid "Push" @@ -1478,19 +1478,19 @@ msgstr "重命名节点" msgid "Delete node" msgstr "删除节点" -#: assets/templates/assets/_node_tree.html:154 +#: assets/templates/assets/_node_tree.html:160 msgid "Create node failed" msgstr "创建节点失败" -#: assets/templates/assets/_node_tree.html:166 +#: assets/templates/assets/_node_tree.html:172 msgid "Have child node, cancel" msgstr "存在子节点,不能删除" -#: assets/templates/assets/_node_tree.html:168 +#: assets/templates/assets/_node_tree.html:174 msgid "Have assets, cancel" msgstr "存在资产,不能删除" -#: assets/templates/assets/_node_tree.html:242 +#: assets/templates/assets/_node_tree.html:248 msgid "Rename success" msgstr "重命名成功" @@ -1577,7 +1577,7 @@ msgstr "选择节点" #: assets/templates/assets/admin_user_detail.html:100 #: assets/templates/assets/asset_detail.html:207 -#: assets/templates/assets/asset_list.html:387 +#: assets/templates/assets/asset_list.html:386 #: assets/templates/assets/cmd_filter_detail.html:106 #: assets/templates/assets/system_user_assets.html:100 #: assets/templates/assets/system_user_detail.html:182 @@ -1585,10 +1585,10 @@ msgstr "选择节点" #: authentication/templates/authentication/_mfa_confirm_modal.html:20 #: settings/templates/settings/terminal_setting.html:168 #: templates/_modal.html:23 terminal/templates/terminal/session_detail.html:108 -#: users/templates/users/user_detail.html:388 -#: users/templates/users/user_detail.html:414 -#: users/templates/users/user_detail.html:437 -#: users/templates/users/user_detail.html:482 +#: users/templates/users/user_detail.html:390 +#: users/templates/users/user_detail.html:416 +#: users/templates/users/user_detail.html:439 +#: users/templates/users/user_detail.html:484 #: users/templates/users/user_group_create_update.html:32 #: users/templates/users/user_group_list.html:119 #: users/templates/users/user_list.html:255 @@ -1640,8 +1640,8 @@ msgstr "创建管理用户" #: assets/templates/assets/admin_user_list.html:162 #: assets/templates/assets/admin_user_list.html:193 -#: assets/templates/assets/asset_list.html:268 -#: assets/templates/assets/asset_list.html:305 +#: assets/templates/assets/asset_list.html:267 +#: assets/templates/assets/asset_list.html:304 #: assets/templates/assets/system_user_list.html:192 #: assets/templates/assets/system_user_list.html:223 #: users/templates/users/user_group_list.html:163 @@ -1653,7 +1653,7 @@ msgid "Please select file" msgstr "选择文件" #: assets/templates/assets/asset_asset_user_list.html:16 -#: assets/templates/assets/asset_detail.html:23 assets/views/asset.py:58 +#: assets/templates/assets/asset_detail.html:23 assets/views/asset.py:56 msgid "Asset user list" msgstr "资产用户列表" @@ -1665,7 +1665,7 @@ msgstr "资产用户" #: assets/templates/assets/asset_detail.html:144 #: terminal/templates/terminal/session_detail.html:81 #: users/templates/users/user_detail.html:138 -#: users/templates/users/user_profile.html:146 +#: users/templates/users/user_profile.html:150 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:128 #: xpack/plugins/license/templates/license/license_detail.html:102 msgid "Quick modify" @@ -1691,7 +1691,7 @@ msgstr "硬盘" #: assets/templates/assets/asset_detail.html:128 #: users/templates/users/user_detail.html:115 -#: users/templates/users/user_profile.html:104 +#: users/templates/users/user_profile.html:106 msgid "Date joined" msgstr "创建日期" @@ -1725,7 +1725,7 @@ msgstr "" "左侧是资产树,右击可以新建、删除、更改树节点,授权资产也是以节点方式组织的," "右侧是属于该节点下的资产" -#: assets/templates/assets/asset_list.html:61 assets/views/asset.py:107 +#: assets/templates/assets/asset_list.html:61 assets/views/asset.py:105 msgid "Create asset" msgstr "创建资产" @@ -1757,51 +1757,51 @@ msgstr "禁用所选" msgid "Active selected" msgstr "激活所选" -#: assets/templates/assets/asset_list.html:191 +#: assets/templates/assets/asset_list.html:190 msgid "Add assets to node" msgstr "添加资产到节点" -#: assets/templates/assets/asset_list.html:192 +#: assets/templates/assets/asset_list.html:191 msgid "Move assets to node" msgstr "移动资产到节点" -#: assets/templates/assets/asset_list.html:194 +#: assets/templates/assets/asset_list.html:193 msgid "Refresh node hardware info" msgstr "更新节点资产硬件信息" -#: assets/templates/assets/asset_list.html:195 +#: assets/templates/assets/asset_list.html:194 msgid "Test node connective" msgstr "测试节点资产可连接性" -#: assets/templates/assets/asset_list.html:197 +#: assets/templates/assets/asset_list.html:196 msgid "Display only current node assets" msgstr "仅显示当前节点资产" -#: assets/templates/assets/asset_list.html:198 +#: assets/templates/assets/asset_list.html:197 msgid "Displays all child node assets" msgstr "显示所有子节点资产" -#: assets/templates/assets/asset_list.html:381 +#: assets/templates/assets/asset_list.html:380 #: assets/templates/assets/system_user_list.html:133 -#: users/templates/users/user_detail.html:382 -#: users/templates/users/user_detail.html:408 -#: users/templates/users/user_detail.html:476 +#: users/templates/users/user_detail.html:384 +#: users/templates/users/user_detail.html:410 +#: users/templates/users/user_detail.html:478 #: users/templates/users/user_group_list.html:113 #: users/templates/users/user_list.html:249 #: xpack/plugins/interface/templates/interface/interface.html:97 msgid "Are you sure?" msgstr "你确认吗?" -#: assets/templates/assets/asset_list.html:382 +#: assets/templates/assets/asset_list.html:381 msgid "This will delete the selected assets !!!" msgstr "删除选择资产" -#: assets/templates/assets/asset_list.html:385 +#: assets/templates/assets/asset_list.html:384 #: assets/templates/assets/system_user_list.html:137 #: settings/templates/settings/terminal_setting.html:166 -#: users/templates/users/user_detail.html:386 -#: users/templates/users/user_detail.html:412 -#: users/templates/users/user_detail.html:480 +#: users/templates/users/user_detail.html:388 +#: users/templates/users/user_detail.html:414 +#: users/templates/users/user_detail.html:482 #: users/templates/users/user_group_create_update.html:31 #: users/templates/users/user_group_list.html:117 #: users/templates/users/user_list.html:253 @@ -1810,16 +1810,16 @@ msgstr "删除选择资产" msgid "Cancel" msgstr "取消" -#: assets/templates/assets/asset_list.html:398 +#: assets/templates/assets/asset_list.html:397 msgid "Asset Deleted." msgstr "已被删除" -#: assets/templates/assets/asset_list.html:399 -#: assets/templates/assets/asset_list.html:403 +#: assets/templates/assets/asset_list.html:398 +#: assets/templates/assets/asset_list.html:402 msgid "Asset Delete" msgstr "删除" -#: assets/templates/assets/asset_list.html:402 +#: assets/templates/assets/asset_list.html:401 msgid "Asset Deleting failed." msgstr "删除失败" @@ -2024,19 +2024,19 @@ msgstr "管理用户列表" msgid "Admin user detail" msgstr "管理用户详情" -#: assets/views/asset.py:70 templates/_nav_user.html:4 +#: assets/views/asset.py:68 templates/_nav_user.html:4 msgid "My assets" msgstr "我的资产" -#: assets/views/asset.py:134 +#: assets/views/asset.py:132 msgid "Update asset" msgstr "更新资产" -#: assets/views/asset.py:146 +#: assets/views/asset.py:144 msgid "Bulk update asset success" msgstr "批量更新资产成功" -#: assets/views/asset.py:174 +#: assets/views/asset.py:172 msgid "Bulk update asset" msgstr "批量更新资产" @@ -2131,7 +2131,7 @@ msgstr "文件名" #: audits/templates/audits/ftp_log_list.html:76 #: ops/templates/ops/command_execution_list.html:65 #: ops/templates/ops/task_list.html:31 -#: users/templates/users/user_detail.html:458 +#: users/templates/users/user_detail.html:460 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:14 #: xpack/plugins/cloud/api.py:62 msgid "Success" @@ -2206,7 +2206,7 @@ msgstr "Agent" #: audits/models.py:99 audits/templates/audits/login_log_list.html:56 #: authentication/templates/authentication/_mfa_confirm_modal.html:14 -#: users/forms.py:175 users/models/user.py:346 +#: users/forms.py:175 users/models/user.py:349 #: users/templates/users/first_login.html:45 msgid "MFA" msgstr "MFA" @@ -2493,7 +2493,7 @@ msgstr "" #: authentication/templates/authentication/login_otp.html:46 #: users/templates/users/user_detail.html:91 -#: users/templates/users/user_profile.html:85 +#: users/templates/users/user_profile.html:87 msgid "MFA certification" msgstr "MFA认证" @@ -2516,7 +2516,7 @@ msgid "Six figures" msgstr "6位数字" #: authentication/templates/authentication/login_otp.html:67 -#: users/templates/users/first_login.html:105 +#: users/templates/users/first_login.html:108 #: users/templates/users/user_otp_authentication.html:26 #: users/templates/users/user_otp_enable_bind.html:29 #: users/templates/users/user_otp_enable_install_app.html:26 @@ -2536,8 +2536,8 @@ msgstr "欢迎回来,请输入用户名和密码登录" msgid "Please enable cookies and try again." msgstr "设置你的浏览器支持cookie" -#: authentication/views/login.py:172 users/views/user.py:399 -#: users/views/user.py:424 +#: authentication/views/login.py:172 users/views/user.py:386 +#: users/views/user.py:411 msgid "MFA code invalid, or ntp sync server time" msgstr "MFA验证码不正确,或者服务器端时间不对" @@ -2988,11 +2988,11 @@ msgstr "命令执行" msgid "Organization" msgstr "组织" -#: perms/api/mixin.py:142 +#: perms/api/mixin.py:148 msgid "ungrouped" msgstr "未分组" -#: perms/api/mixin.py:147 +#: perms/api/mixin.py:153 msgid "empty" msgstr "空" @@ -3003,8 +3003,8 @@ msgstr "空" #: perms/templates/perms/asset_permission_list.html:114 #: perms/templates/perms/remote_app_permission_list.html:16 #: templates/_nav.html:14 users/forms.py:286 users/models/group.py:26 -#: users/models/user.py:330 users/templates/users/_select_user_modal.html:16 -#: users/templates/users/user_detail.html:213 +#: users/models/user.py:333 users/templates/users/_select_user_modal.html:16 +#: users/templates/users/user_detail.html:215 #: users/templates/users/user_list.html:38 #: xpack/plugins/orgs/templates/orgs/org_list.html:15 msgid "User group" @@ -3052,8 +3052,8 @@ msgstr "资产授权" #: perms/models/asset_permission.py:116 perms/models/base.py:40 #: perms/templates/perms/asset_permission_detail.html:90 #: perms/templates/perms/remote_app_permission_detail.html:82 -#: users/models/user.py:362 users/templates/users/user_detail.html:107 -#: users/templates/users/user_profile.html:116 +#: users/models/user.py:365 users/templates/users/user_detail.html:107 +#: users/templates/users/user_profile.html:120 msgid "Date expired" msgstr "失效日期" @@ -3104,7 +3104,7 @@ msgid "Add node to this permission" msgstr "添加节点" #: perms/templates/perms/asset_permission_asset.html:112 -#: users/templates/users/user_detail.html:230 +#: users/templates/users/user_detail.html:232 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:121 msgid "Join" msgstr "加入" @@ -3198,9 +3198,9 @@ msgstr "添加用户" msgid "Add user group to this permission" msgstr "添加用户组" -#: perms/views/asset_permission.py:33 perms/views/asset_permission.py:64 -#: perms/views/asset_permission.py:81 perms/views/asset_permission.py:98 -#: perms/views/asset_permission.py:135 perms/views/asset_permission.py:169 +#: perms/views/asset_permission.py:34 perms/views/asset_permission.py:65 +#: perms/views/asset_permission.py:82 perms/views/asset_permission.py:99 +#: perms/views/asset_permission.py:136 perms/views/asset_permission.py:173 #: perms/views/remote_app_permission.py:33 #: perms/views/remote_app_permission.py:49 #: perms/views/remote_app_permission.py:66 @@ -3211,27 +3211,27 @@ msgstr "添加用户组" msgid "Perms" msgstr "权限管理" -#: perms/views/asset_permission.py:34 +#: perms/views/asset_permission.py:35 msgid "Asset permission list" msgstr "资产授权列表" -#: perms/views/asset_permission.py:65 +#: perms/views/asset_permission.py:66 msgid "Create asset permission" msgstr "创建权限规则" -#: perms/views/asset_permission.py:82 +#: perms/views/asset_permission.py:83 msgid "Update asset permission" msgstr "更新资产授权" -#: perms/views/asset_permission.py:99 +#: perms/views/asset_permission.py:100 msgid "Asset permission detail" msgstr "资产授权详情" -#: perms/views/asset_permission.py:136 +#: perms/views/asset_permission.py:137 msgid "Asset permission user list" msgstr "资产授权用户列表" -#: perms/views/asset_permission.py:170 +#: perms/views/asset_permission.py:174 msgid "Asset permission asset list" msgstr "资产授权资产列表" @@ -3598,7 +3598,7 @@ msgid "Please submit the LDAP configuration before import" msgstr "请先提交LDAP配置再进行导入" #: settings/templates/settings/_ldap_list_users_modal.html:39 -#: users/models/user.py:326 users/templates/users/user_detail.html:71 +#: users/models/user.py:329 users/templates/users/user_detail.html:71 #: users/templates/users/user_profile.html:59 msgid "Email" msgstr "邮件" @@ -3792,11 +3792,11 @@ msgstr "删除失败" msgid "Are you sure about deleting it?" msgstr "您确定删除吗?" -#: settings/utils.py:84 +#: settings/utils.py:90 msgid "Search no entry matched in ou {}" msgstr "在ou:{}中没有匹配条目" -#: settings/utils.py:112 +#: settings/utils.py:120 msgid "The user source is not LDAP" msgstr "用户来源不是LDAP" @@ -3837,8 +3837,8 @@ msgstr "商业支持" #: users/templates/users/user_password_update.html:40 #: users/templates/users/user_profile.html:17 #: users/templates/users/user_profile_update.html:37 -#: users/templates/users/user_profile_update.html:57 -#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:232 +#: users/templates/users/user_profile_update.html:61 +#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:224 msgid "Profile" msgstr "个人信息" @@ -3928,13 +3928,13 @@ msgstr "" #: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:45 #: users/views/group.py:63 users/views/group.py:81 users/views/group.py:98 -#: users/views/login.py:154 users/views/user.py:68 users/views/user.py:85 -#: users/views/user.py:129 users/views/user.py:196 users/views/user.py:218 -#: users/views/user.py:270 users/views/user.py:311 +#: users/views/login.py:154 users/views/user.py:60 users/views/user.py:77 +#: users/views/user.py:121 users/views/user.py:188 users/views/user.py:210 +#: users/views/user.py:263 users/views/user.py:298 msgid "Users" msgstr "用户管理" -#: templates/_nav.html:13 users/views/user.py:69 +#: templates/_nav.html:13 users/views/user.py:61 msgid "User list" msgstr "用户列表" @@ -4253,7 +4253,7 @@ msgstr "参数" msgid "Export command" msgstr "导出命令" -#: terminal/templates/terminal/command_list.html:189 +#: terminal/templates/terminal/command_list.html:191 msgid "Goto" msgstr "转到" @@ -4381,7 +4381,7 @@ msgstr "你没有权限" msgid "Could not reset self otp, use profile reset instead" msgstr "不能再该页面重置MFA, 请去个人信息页面重置" -#: users/forms.py:33 users/models/user.py:334 +#: users/forms.py:33 users/models/user.py:337 #: users/templates/users/_select_user_modal.html:15 #: users/templates/users/user_detail.html:87 #: users/templates/users/user_list.html:37 @@ -4390,6 +4390,7 @@ msgid "Role" msgstr "角色" #: users/forms.py:36 users/forms.py:233 +#: users/templates/users/user_update.html:30 msgid "ssh public key" msgstr "ssh公钥" @@ -4401,7 +4402,7 @@ msgstr "" msgid "Paste user id_rsa.pub here." msgstr "复制用户公钥到这里" -#: users/forms.py:52 users/templates/users/user_detail.html:221 +#: users/forms.py:52 users/templates/users/user_detail.html:223 msgid "Join user groups" msgstr "添加到用户组" @@ -4413,7 +4414,7 @@ msgstr "不能和原来的密钥相同" msgid "Not a valid ssh public key" msgstr "ssh密钥不合法" -#: users/forms.py:104 users/views/login.py:114 users/views/user.py:293 +#: users/forms.py:104 users/views/login.py:114 users/views/user.py:280 msgid "* Your password does not meet the requirements" msgstr "* 您的密码不符合要求" @@ -4435,16 +4436,16 @@ msgstr "密码策略" #: users/forms.py:160 msgid "" -"Tip: when enabled, you will enter the MFA binding process the next time you " -"log in. you can also directly bind in \"personal information -> quick " +"When enabled, you will enter the MFA binding process the next time you log " +"in. you can also directly bind in \"personal information -> quick " "modification -> change MFA Settings\"!" msgstr "" -"提示:启用之后您将会在下次登录时进入MFA绑定流程;您也可以在(个人信息->快速修" -"改->更改MFA设置)中直接绑定!" +"启用之后您将会在下次登录时进入MFA绑定流程;您也可以在(个人信息->快速修改->更" +"改MFA设置)中直接绑定!" #: users/forms.py:170 msgid "* Enable MFA authentication to make the account more secure." -msgstr "* 启用MFA认证,使账号更加安全." +msgstr "* 启用MFA认证,使账号更加安全。" #: users/forms.py:180 msgid "" @@ -4456,8 +4457,8 @@ msgstr "" "设置复杂密码,启用MFA认证)" #: users/forms.py:187 users/templates/users/first_login.html:48 -#: users/templates/users/first_login.html:107 -#: users/templates/users/first_login.html:130 +#: users/templates/users/first_login.html:110 +#: users/templates/users/first_login.html:139 msgid "Finish" msgstr "完成" @@ -4495,56 +4496,56 @@ msgid "Select users" msgstr "选择用户" #: users/models/user.py:50 users/templates/users/user_update.html:22 -#: users/views/login.py:46 users/views/login.py:107 users/views/user.py:283 +#: users/views/login.py:46 users/views/login.py:107 msgid "User auth from {}, go there change password" msgstr "用户认证源来自 {}, 请去相应系统修改密码" -#: users/models/user.py:120 users/models/user.py:447 +#: users/models/user.py:123 users/models/user.py:450 msgid "Administrator" msgstr "管理员" -#: users/models/user.py:122 +#: users/models/user.py:125 msgid "Application" msgstr "应用程序" -#: users/models/user.py:123 +#: users/models/user.py:126 msgid "Auditor" msgstr "审计员" -#: users/models/user.py:281 users/templates/users/user_profile.html:92 -#: users/templates/users/user_profile.html:159 -#: users/templates/users/user_profile.html:162 +#: users/models/user.py:284 users/templates/users/user_profile.html:94 +#: users/templates/users/user_profile.html:163 +#: users/templates/users/user_profile.html:166 msgid "Disable" msgstr "禁用" -#: users/models/user.py:282 users/templates/users/user_profile.html:90 -#: users/templates/users/user_profile.html:166 +#: users/models/user.py:285 users/templates/users/user_profile.html:92 +#: users/templates/users/user_profile.html:170 msgid "Enable" msgstr "启用" -#: users/models/user.py:283 users/templates/users/user_profile.html:88 +#: users/models/user.py:286 users/templates/users/user_profile.html:90 msgid "Force enable" msgstr "强制启用" -#: users/models/user.py:337 +#: users/models/user.py:340 msgid "Avatar" msgstr "头像" -#: users/models/user.py:340 users/templates/users/user_detail.html:82 +#: users/models/user.py:343 users/templates/users/user_detail.html:82 msgid "Wechat" msgstr "微信" -#: users/models/user.py:369 users/templates/users/user_detail.html:103 +#: users/models/user.py:372 users/templates/users/user_detail.html:103 #: users/templates/users/user_list.html:39 -#: users/templates/users/user_profile.html:100 +#: users/templates/users/user_profile.html:102 msgid "Source" msgstr "用户来源" -#: users/models/user.py:373 +#: users/models/user.py:376 msgid "Date password last updated" msgstr "最后更新密码日期" -#: users/models/user.py:450 +#: users/models/user.py:453 msgid "Administrator is the super user of system" msgstr "Administrator是初始的超级管理员" @@ -4597,7 +4598,7 @@ msgid "Security token validation" msgstr "安全令牌验证" #: users/templates/users/_base_otp.html:44 users/templates/users/_user.html:13 -#: users/templates/users/user_profile_update.html:51 +#: users/templates/users/user_profile_update.html:55 #: xpack/plugins/cloud/models.py:120 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:57 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:13 @@ -4634,7 +4635,7 @@ msgid "Import users" msgstr "导入用户" #: users/templates/users/_user_update_modal.html:4 -#: users/templates/users/user_update.html:4 users/views/user.py:130 +#: users/templates/users/user_update.html:4 users/views/user.py:122 msgid "Update user" msgstr "更新用户" @@ -4655,7 +4656,12 @@ msgstr "我同意条款和条件" msgid "Please choose the terms and conditions." msgstr "请选择同意条款和条件" -#: users/templates/users/first_login.html:101 +#: users/templates/users/first_login.html:77 +#: users/templates/users/user_update.html:32 +msgid "User auth from {}, ssh key login is not supported" +msgstr "用户认证源来自 {}, 不支持使用 SSH Key 登录" + +#: users/templates/users/first_login.html:104 msgid "Previous" msgstr "上一步" @@ -4707,20 +4713,20 @@ msgid "Always young, always with tears in my eyes. Stay foolish Stay hungry" msgstr "永远年轻,永远热泪盈眶 stay foolish stay hungry" #: users/templates/users/reset_password.html:46 -#: users/templates/users/user_detail.html:373 users/utils.py:88 +#: users/templates/users/user_detail.html:375 users/utils.py:88 msgid "Reset password" msgstr "重置密码" #: users/templates/users/reset_password.html:59 #: users/templates/users/user_create.html:13 -#: users/templates/users/user_password_update.html:61 +#: users/templates/users/user_password_update.html:65 #: users/templates/users/user_update.html:13 msgid "Your password must satisfy" msgstr "您的密码必须满足:" #: users/templates/users/reset_password.html:60 #: users/templates/users/user_create.html:14 -#: users/templates/users/user_password_update.html:62 +#: users/templates/users/user_password_update.html:66 #: users/templates/users/user_update.html:14 msgid "Password strength" msgstr "密码强度:" @@ -4731,53 +4737,53 @@ msgstr "再次输入密码" #: users/templates/users/reset_password.html:105 #: users/templates/users/user_create.html:33 -#: users/templates/users/user_password_update.html:99 -#: users/templates/users/user_update.html:46 +#: users/templates/users/user_password_update.html:103 +#: users/templates/users/user_update.html:55 msgid "Very weak" msgstr "很弱" #: users/templates/users/reset_password.html:106 #: users/templates/users/user_create.html:34 -#: users/templates/users/user_password_update.html:100 -#: users/templates/users/user_update.html:47 +#: users/templates/users/user_password_update.html:104 +#: users/templates/users/user_update.html:56 msgid "Weak" msgstr "弱" #: users/templates/users/reset_password.html:107 #: users/templates/users/user_create.html:35 -#: users/templates/users/user_password_update.html:101 -#: users/templates/users/user_update.html:48 +#: users/templates/users/user_password_update.html:105 +#: users/templates/users/user_update.html:57 msgid "Normal" msgstr "正常" #: users/templates/users/reset_password.html:108 #: users/templates/users/user_create.html:36 -#: users/templates/users/user_password_update.html:102 -#: users/templates/users/user_update.html:49 +#: users/templates/users/user_password_update.html:106 +#: users/templates/users/user_update.html:58 msgid "Medium" msgstr "一般" #: users/templates/users/reset_password.html:109 #: users/templates/users/user_create.html:37 -#: users/templates/users/user_password_update.html:103 -#: users/templates/users/user_update.html:50 +#: users/templates/users/user_password_update.html:107 +#: users/templates/users/user_update.html:59 msgid "Strong" msgstr "强" #: users/templates/users/reset_password.html:110 #: users/templates/users/user_create.html:38 -#: users/templates/users/user_password_update.html:104 -#: users/templates/users/user_update.html:51 +#: users/templates/users/user_password_update.html:108 +#: users/templates/users/user_update.html:60 msgid "Very strong" msgstr "很强" #: users/templates/users/user_create.html:4 -#: users/templates/users/user_list.html:28 users/views/user.py:86 +#: users/templates/users/user_list.html:28 users/views/user.py:78 msgid "Create user" msgstr "创建用户" #: users/templates/users/user_detail.html:19 -#: users/templates/users/user_granted_asset.html:18 users/views/user.py:197 +#: users/templates/users/user_granted_asset.html:18 users/views/user.py:189 msgid "User detail" msgstr "用户详情" @@ -4793,12 +4799,12 @@ msgid "Force enabled" msgstr "强制启用" #: users/templates/users/user_detail.html:119 -#: users/templates/users/user_profile.html:108 +#: users/templates/users/user_profile.html:110 msgid "Last login" msgstr "最后登录" #: users/templates/users/user_detail.html:123 -#: users/templates/users/user_profile.html:112 +#: users/templates/users/user_profile.html:115 msgid "Last password updated" msgstr "最后更新密码" @@ -4815,63 +4821,63 @@ msgid "Send reset password mail" msgstr "发送重置密码邮件" #: users/templates/users/user_detail.html:185 -#: users/templates/users/user_detail.html:194 +#: users/templates/users/user_detail.html:195 msgid "Send" msgstr "发送" -#: users/templates/users/user_detail.html:191 +#: users/templates/users/user_detail.html:192 msgid "Send reset ssh key mail" msgstr "发送重置密钥邮件" -#: users/templates/users/user_detail.html:199 -#: users/templates/users/user_detail.html:461 +#: users/templates/users/user_detail.html:201 +#: users/templates/users/user_detail.html:463 msgid "Unblock user" msgstr "解除登录限制" -#: users/templates/users/user_detail.html:202 +#: users/templates/users/user_detail.html:204 msgid "Unblock" msgstr "解除" -#: users/templates/users/user_detail.html:316 +#: users/templates/users/user_detail.html:318 msgid "Goto profile page enable MFA" msgstr "请去个人信息页面启用自己的MFA" -#: users/templates/users/user_detail.html:372 +#: users/templates/users/user_detail.html:374 msgid "An e-mail has been sent to the user`s mailbox." msgstr "已发送邮件到用户邮箱" -#: users/templates/users/user_detail.html:383 +#: users/templates/users/user_detail.html:385 msgid "This will reset the user password and send a reset mail" msgstr "将失效用户当前密码,并发送重设密码邮件到用户邮箱" -#: users/templates/users/user_detail.html:398 +#: users/templates/users/user_detail.html:400 msgid "" "The reset-ssh-public-key E-mail has been sent successfully. Please inform " "the user to update his new ssh public key." msgstr "重设密钥邮件将会发送到用户邮箱" -#: users/templates/users/user_detail.html:399 +#: users/templates/users/user_detail.html:401 msgid "Reset SSH public key" msgstr "重置SSH密钥" -#: users/templates/users/user_detail.html:409 +#: users/templates/users/user_detail.html:411 msgid "This will reset the user public key and send a reset mail" msgstr "将会失效用户当前密钥,并发送重置邮件到用户邮箱" -#: users/templates/users/user_detail.html:427 +#: users/templates/users/user_detail.html:429 msgid "Successfully updated the SSH public key." msgstr "更新ssh密钥成功" -#: users/templates/users/user_detail.html:428 -#: users/templates/users/user_detail.html:432 +#: users/templates/users/user_detail.html:430 +#: users/templates/users/user_detail.html:434 msgid "User SSH public key update" msgstr "ssh密钥" -#: users/templates/users/user_detail.html:477 +#: users/templates/users/user_detail.html:479 msgid "After unlocking the user, the user can log in normally." msgstr "解除用户登录限制后,此用户即可正常登录" -#: users/templates/users/user_detail.html:491 +#: users/templates/users/user_detail.html:493 msgid "Reset user MFA success" msgstr "重置用户MFA成功" @@ -4973,51 +4979,51 @@ msgid "" "installed, go to the next step directly)." msgstr "安装完成后点击下一步进入绑定页面(如已安装,直接进入下一步" -#: users/templates/users/user_profile.html:95 +#: users/templates/users/user_profile.html:97 msgid "Administrator Settings force MFA login" msgstr "管理员设置强制使用MFA登录" -#: users/templates/users/user_profile.html:120 +#: users/templates/users/user_profile.html:124 msgid "User groups" msgstr "用户组" -#: users/templates/users/user_profile.html:152 +#: users/templates/users/user_profile.html:156 msgid "Set MFA" msgstr "设置MFA" -#: users/templates/users/user_profile.html:174 +#: users/templates/users/user_profile.html:178 msgid "Update password" msgstr "更改密码" -#: users/templates/users/user_profile.html:184 +#: users/templates/users/user_profile.html:188 msgid "Update MFA" msgstr "更改MFA" -#: users/templates/users/user_profile.html:193 +#: users/templates/users/user_profile.html:198 msgid "Update SSH public key" msgstr "更改SSH密钥" -#: users/templates/users/user_profile.html:201 +#: users/templates/users/user_profile.html:206 msgid "Reset public key and download" msgstr "重置并下载SSH密钥" -#: users/templates/users/user_pubkey_update.html:51 +#: users/templates/users/user_pubkey_update.html:55 msgid "Old public key" msgstr "原来ssh密钥" -#: users/templates/users/user_pubkey_update.html:59 +#: users/templates/users/user_pubkey_update.html:63 msgid "Fingerprint" msgstr "指纹" -#: users/templates/users/user_pubkey_update.html:65 +#: users/templates/users/user_pubkey_update.html:69 msgid "Update public key" msgstr "更新密钥" -#: users/templates/users/user_pubkey_update.html:68 +#: users/templates/users/user_pubkey_update.html:72 msgid "Or reset by server" msgstr "或者重置并下载密钥" -#: users/templates/users/user_pubkey_update.html:94 +#: users/templates/users/user_pubkey_update.html:98 msgid "" "The new public key has been set successfully, Please download the " "corresponding private key." @@ -5256,47 +5262,47 @@ msgstr "密码不一致" msgid "First login" msgstr "首次登录" -#: users/views/user.py:148 +#: users/views/user.py:140 msgid "Bulk update user success" msgstr "批量更新用户成功" -#: users/views/user.py:176 +#: users/views/user.py:168 msgid "Bulk update user" msgstr "批量更新用户" -#: users/views/user.py:219 +#: users/views/user.py:211 msgid "User granted assets" msgstr "用户授权资产" -#: users/views/user.py:252 +#: users/views/user.py:244 msgid "Profile setting" msgstr "个人信息设置" -#: users/views/user.py:271 +#: users/views/user.py:264 msgid "Password update" msgstr "密码更新" -#: users/views/user.py:312 +#: users/views/user.py:299 msgid "Public key update" msgstr "密钥更新" -#: users/views/user.py:354 +#: users/views/user.py:341 msgid "Password invalid" msgstr "用户名或密码无效" -#: users/views/user.py:454 +#: users/views/user.py:441 msgid "MFA enable success" msgstr "MFA 绑定成功" -#: users/views/user.py:455 +#: users/views/user.py:442 msgid "MFA enable success, return login page" msgstr "MFA 绑定成功,返回到登录页面" -#: users/views/user.py:457 +#: users/views/user.py:444 msgid "MFA disable success" msgstr "MFA 解绑成功" -#: users/views/user.py:458 +#: users/views/user.py:445 msgid "MFA disable success, return login page" msgstr "MFA 解绑成功,返回登录页面" diff --git a/apps/settings/utils.py b/apps/settings/utils.py index adcd2c839..232224dcc 100644 --- a/apps/settings/utils.py +++ b/apps/settings/utils.py @@ -7,6 +7,7 @@ from django.utils.translation import ugettext_lazy as _ from users.models import User from users.utils import construct_user_email from common.utils import get_logger +from common.const import LDAP_AD_ACCOUNT_DISABLE from .models import settings @@ -70,7 +71,12 @@ class LDAPUtil: for attr, mapping in self.attr_map.items(): if not hasattr(entry, mapping): continue - user_item[attr] = getattr(entry, mapping).value or '' + value = getattr(entry, mapping).value or '' + if mapping.lower() == 'useraccountcontrol' and attr == 'is_active'\ + and value: + value = int(value) & LDAP_AD_ACCOUNT_DISABLE \ + != LDAP_AD_ACCOUNT_DISABLE + user_item[attr] = value return user_item def search_user_items(self): @@ -102,7 +108,9 @@ class LDAPUtil: if not hasattr(user, field): continue if isinstance(getattr(user, field), bool): - value = value.lower() in ['true', 1] + if isinstance(value, str): + value = value.lower() + value = value in ['true', 1, True] setattr(user, field, value) user.save() diff --git a/apps/users/forms.py b/apps/users/forms.py index 96357c7b5..44044c434 100644 --- a/apps/users/forms.py +++ b/apps/users/forms.py @@ -157,7 +157,7 @@ UserProfileForm.verbose_name = _("Profile") class UserMFAForm(forms.ModelForm): mfa_description = _( - 'Tip: when enabled, ' + 'When enabled, ' 'you will enter the MFA binding process the next time you log in. ' 'you can also directly bind in ' '"personal information -> quick modification -> change MFA Settings"!') diff --git a/apps/users/models/user.py b/apps/users/models/user.py index 88abe4dd3..f6c083c56 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -54,6 +54,9 @@ class AuthMixin: def can_update_password(self): return self.is_local + def can_update_ssh_key(self): + return self.is_local + def check_otp(self, code): from ..utils import check_otp_code return check_otp_code(self.otp_secret_key, code) diff --git a/apps/users/templates/users/first_login.html b/apps/users/templates/users/first_login.html index 9687949d1..1038fb8c8 100644 --- a/apps/users/templates/users/first_login.html +++ b/apps/users/templates/users/first_login.html @@ -73,14 +73,17 @@ {% endif %} - {% bootstrap_form wizard.form %} + {% if wizard.steps.current == '1' and not request.user.can_update_ssh_key %} + {% trans 'User auth from {}, ssh key login is not supported' %} + {% else %} + {% bootstrap_form wizard.form %} + {% endif %} {% if form.mfa_description %} {{ form.mfa_description }} {% endif %} - {% if form.pubkey_description %} - 或者: + {% if form.pubkey_description and request.user.can_update_ssh_key %} {{ form.pubkey_description }} {% endif %} @@ -121,26 +124,33 @@ {% block custom_foot_js %} {% endblock %} diff --git a/apps/users/templates/users/user_detail.html b/apps/users/templates/users/user_detail.html index 929d7def4..b39671a73 100644 --- a/apps/users/templates/users/user_detail.html +++ b/apps/users/templates/users/user_detail.html @@ -119,10 +119,12 @@ {% trans 'Last login' %}: {{ user_object.last_login|date:"Y-m-j H:i:s" }} + {% if user_object.can_update_password %} {% trans 'Last password updated' %}: {{ user_object.date_password_last_updated|date:"Y-m-j H:i:s" }} + {% endif %} {% trans 'Comment' %}: {{ user_object.comment }} @@ -187,6 +189,7 @@ {% endif %} + {% if user_object.can_update_ssh_key %} {% trans 'Send reset ssh key mail' %}: @@ -195,6 +198,7 @@ + {% endif %} {% trans 'Unblock user' %} diff --git a/apps/users/templates/users/user_password_update.html b/apps/users/templates/users/user_password_update.html index 8056edb87..7148dd622 100644 --- a/apps/users/templates/users/user_password_update.html +++ b/apps/users/templates/users/user_password_update.html @@ -39,12 +39,16 @@
  • {% trans 'Profile' %}
  • + {% if request.user.can_update_password %}
  • {% trans 'Password' %}
  • + {% endif %} + {% if request.user.can_update_ssh_key %}
  • {% trans 'Public key' %}
  • + {% endif %}
    diff --git a/apps/users/templates/users/user_profile.html b/apps/users/templates/users/user_profile.html index 7a06df4c9..9c6644baa 100644 --- a/apps/users/templates/users/user_profile.html +++ b/apps/users/templates/users/user_profile.html @@ -64,6 +64,7 @@ {{ user.is_active|yesno:"Yes,No,Unkown" }} + {% if user.can_update_ssh_key %} {% trans 'Public key' %} @@ -81,6 +82,7 @@ + {% endif %} {% trans 'MFA certification' %} @@ -108,10 +110,12 @@ {% trans 'Last login' %} {{ user.last_login|date:"Y-m-d H:i:s" }} + {% if user.can_update_password %} {% trans 'Last password updated' %} {{ user.date_password_last_updated|date:"Y-m-d H:i:s" }} + {% endif %} {% trans 'Date expired' %} {{ user.date_expired|date:"Y-m-d H:i:s" }} @@ -189,6 +193,7 @@ {% endif %} + {% if request.user.can_update_ssh_key %} {% trans 'Update SSH public key' %}: @@ -205,6 +210,7 @@ + {% endif %}
    diff --git a/apps/users/templates/users/user_profile_update.html b/apps/users/templates/users/user_profile_update.html index 15ba795f5..e59edeccc 100644 --- a/apps/users/templates/users/user_profile_update.html +++ b/apps/users/templates/users/user_profile_update.html @@ -36,12 +36,16 @@
  • {% trans 'Profile' %}
  • + {% if request.user.can_update_password %}
  • {% trans 'Password' %}
  • + {% endif %} + {% if request.user.can_update_ssh_key %}
  • {% trans 'Public key' %}
  • + {% endif %}
    diff --git a/apps/users/templates/users/user_pubkey_update.html b/apps/users/templates/users/user_pubkey_update.html index e90e51659..4ab03f01c 100644 --- a/apps/users/templates/users/user_pubkey_update.html +++ b/apps/users/templates/users/user_pubkey_update.html @@ -36,12 +36,16 @@
  • {% trans 'Profile' %}
  • + {% if request.user.can_update_password %}
  • {% trans 'Password' %}
  • + {% endif %} + {% if request.user.can_update_ssh_key %}
  • {% trans 'Public key' %}
  • + {% endif %}
    diff --git a/apps/users/templates/users/user_update.html b/apps/users/templates/users/user_update.html index 67c7c155c..182ec88aa 100644 --- a/apps/users/templates/users/user_update.html +++ b/apps/users/templates/users/user_update.html @@ -23,7 +23,16 @@
    {% endif %} + {% if object.can_update_ssh_key %} {% bootstrap_field form.public_key layout="horizontal" %} + {% else %} +
    + +
    + {% trans 'User auth from {}, ssh key login is not supported' %} +
    +
    + {% endif %} {% endblock %} {% block custom_foot_js %} @@ -77,9 +86,13 @@ function passwordCheck() { $(document).ready(function(){ passwordCheck(); - var origin_text = $("#password_help_text").text(); - var new_text = origin_text.replace('{}', "{{ object.source_display }}"); - $("#password_help_text").html(new_text); + var origin_password_text = $("#password_help_text").text(); + var new_password_text = origin_password_text.replace('{}', "{{ object.source_display }}"); + $("#password_help_text").html(new_password_text); + + var origin_ssh_key_text = $("#ssh_key_help_text").text(); + var new_ssh_key_text = origin_ssh_key_text.replace('{}', "{{ object.source_display }}"); + $("#ssh_key_help_text").html(new_ssh_key_text) }) .on("submit", "form", function (evt) { diff --git a/apps/users/utils.py b/apps/users/utils.py index 60f6dfbee..662ddedec 100644 --- a/apps/users/utils.py +++ b/apps/users/utils.py @@ -198,7 +198,7 @@ def check_user_valid(**kwargs): if password and authenticate(username=username, password=password): return user, '' - if public_key and user.public_key: + if public_key and user.public_key and user.is_local: public_key_saved = user.public_key.split() if len(public_key_saved) == 1: if public_key == public_key_saved[0]: diff --git a/apps/users/views/user.py b/apps/users/views/user.py index ea599225e..1a8c25f2e 100644 --- a/apps/users/views/user.py +++ b/apps/users/views/user.py @@ -2,40 +2,32 @@ from __future__ import unicode_literals -import json -import uuid -import csv -import codecs -import chardet -from io import StringIO from django.contrib import messages -from django.contrib.auth import authenticate, login as auth_login +from django.contrib.auth import authenticate from django.contrib.messages.views import SuccessMessageMixin from django.core.cache import cache from django.conf import settings -from django.http import HttpResponse, JsonResponse +from django.http import HttpResponse from django.shortcuts import redirect from django.urls import reverse_lazy, reverse -from django.utils import timezone from django.utils.translation import ugettext as _ -from django.utils.decorators import method_decorator from django.views import View from django.views.generic.base import TemplateView -from django.db import transaction from django.views.generic.edit import ( CreateView, UpdateView, FormView ) from django.views.generic.detail import DetailView -from django.views.decorators.csrf import csrf_exempt from django.contrib.auth import logout as auth_logout from common.const import ( create_success_msg, update_success_msg, KEY_CACHE_RESOURCES_ID ) -from common.mixins import JSONResponseMixin -from common.utils import get_logger, get_object_or_none, is_uuid, ssh_key_gen -from common.permissions import PermissionsMixin, IsOrgAdmin, IsValidUser +from common.utils import get_logger, ssh_key_gen +from common.permissions import ( + PermissionsMixin, IsOrgAdmin, IsValidUser, + UserCanUpdatePassword, UserCanUpdateSSHKey, +) from orgs.utils import current_org from .. import forms from ..models import User, UserGroup @@ -260,6 +252,7 @@ class UserPasswordUpdateView(PermissionsMixin, UpdateView): model = User form_class = forms.UserPasswordForm success_url = reverse_lazy('users:user-profile') + permission_classes = [IsValidUser, UserCanUpdatePassword] def get_object(self, queryset=None): return self.request.user @@ -279,12 +272,6 @@ class UserPasswordUpdateView(PermissionsMixin, UpdateView): return super().get_success_url() def form_valid(self, form): - if not self.request.user.can_update_password(): - error = _("User auth from {}, go there change password").format( - self.request.source_display - ) - form.add_error("password", error) - return self.form_invalid(form) password = form.cleaned_data.get('new_password') is_ok = check_password_rules(password) if not is_ok: @@ -300,7 +287,7 @@ class UserPublicKeyUpdateView(PermissionsMixin, UpdateView): template_name = 'users/user_pubkey_update.html' model = User form_class = forms.UserPublicKeyForm - permission_classes = [IsValidUser] + permission_classes = [IsValidUser, UserCanUpdateSSHKey] success_url = reverse_lazy('users:user-profile') def get_object(self, queryset=None):