diff --git a/apps/authentication/forms.py b/apps/authentication/forms.py index 61b073e21..5316e0d79 100644 --- a/apps/authentication/forms.py +++ b/apps/authentication/forms.py @@ -5,6 +5,8 @@ from django import forms from django.contrib.auth.forms import AuthenticationForm from django.utils.translation import gettext_lazy as _ from captcha.fields import CaptchaField +from django.conf import settings +from users.utils import get_login_failed_count class UserLoginForm(AuthenticationForm): @@ -16,10 +18,18 @@ class UserLoginForm(AuthenticationForm): error_messages = { 'invalid_login': _( - "Please enter a correct username and password. Note that both " - "fields may be case-sensitive." + "The username or password you entered is incorrect, " + "please enter it again." ), 'inactive': _("This account is inactive."), + 'limit_login': _( + "You can also try {times_try} times " + "(The account will be temporarily locked for {block_time} minutes)" + ), + 'block_login': _( + "The account has been locked " + "(please contact admin to unlock it or try again after {} minutes)" + ) } def confirm_login_allowed(self, user): @@ -28,6 +38,25 @@ class UserLoginForm(AuthenticationForm): self.error_messages['inactive'], code='inactive',) + def get_limit_login_error_message(self, username, ip): + times_up = settings.SECURITY_LOGIN_LIMIT_COUNT + times_failed = get_login_failed_count(username, ip) + times_try = int(times_up) - int(times_failed) + block_time = settings.SECURITY_LOGIN_LIMIT_TIME + if times_try <= 0: + error_message = self.error_messages['block_login'] + error_message = error_message.format(block_time) + else: + error_message = self.error_messages['limit_login'] + error_message = error_message.format( + times_try=times_try, block_time=block_time, + ) + return error_message + + def add_limit_login_error(self, username, ip): + error = self.get_limit_login_error_message(username, ip) + self.add_error('password', error) + class UserLoginCaptchaForm(UserLoginForm): captcha = CaptchaField() diff --git a/apps/authentication/templates/authentication/login.html b/apps/authentication/templates/authentication/login.html index e565e209c..b31a716b8 100644 --- a/apps/authentication/templates/authentication/login.html +++ b/apps/authentication/templates/authentication/login.html @@ -58,6 +58,7 @@ {% else %}

{{ form.non_field_errors.as_text }}

{% endif %} +

{{ form.errors.password.as_text }}

{% endif %}
@@ -78,10 +79,11 @@ {% endif %}
-
- - {% trans 'Forgot password' %}? - +
+ + {% trans 'Forgot password' %}? + +
{% if AUTH_OPENID %} diff --git a/apps/authentication/templates/authentication/new_login.html b/apps/authentication/templates/authentication/new_login.html index c644e6fad..4a62dd6d0 100644 --- a/apps/authentication/templates/authentication/new_login.html +++ b/apps/authentication/templates/authentication/new_login.html @@ -72,9 +72,10 @@
{% csrf_token %} -
+
{% if block_login %}

{% trans 'Log in frequently and try again later' %}

+

{{ form.errors.password.as_text }}

{% elif password_expired %}

{% trans 'The user password has expired' %}

{% elif form.errors %} @@ -83,6 +84,7 @@ {% else %}

{{ form.non_field_errors.as_text }}

{% endif %} +

{{ form.errors.password.as_text }}

{% endif %}
diff --git a/apps/authentication/views/login.py b/apps/authentication/views/login.py index 53112fcac..0939370f1 100644 --- a/apps/authentication/views/login.py +++ b/apps/authentication/views/login.py @@ -100,6 +100,7 @@ class UserLoginView(FormView): # limit user login failed count ip = get_request_ip(self.request) increase_login_failed_count(username, ip) + form.add_limit_login_error(username, ip) # show captcha cache.set(self.key_prefix_captcha.format(ip), 1, 3600) self.send_auth_signal(success=False, username=username, reason=reason) diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 472399029..098558e3f 100644 Binary files a/apps/locale/zh/LC_MESSAGES/django.mo and b/apps/locale/zh/LC_MESSAGES/django.mo differ diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 2e9883d6a..a7dd721b8 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Jumpserver 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2019-07-29 18:24+0800\n" +"POT-Creation-Date: 2019-07-30 18:48+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -429,29 +429,29 @@ msgstr "详情" #: assets/templates/assets/system_user_list.html:33 #: assets/templates/assets/system_user_list.html:85 audits/models.py:33 #: perms/templates/perms/asset_permission_detail.html:30 -#: perms/templates/perms/asset_permission_list.html:177 +#: perms/templates/perms/asset_permission_list.html:178 #: perms/templates/perms/remote_app_permission_detail.html:30 #: perms/templates/perms/remote_app_permission_list.html:59 #: terminal/templates/terminal/terminal_detail.html:16 -#: terminal/templates/terminal/terminal_list.html:72 +#: terminal/templates/terminal/terminal_list.html:73 #: users/templates/users/user_detail.html:25 #: users/templates/users/user_group_detail.html:28 #: users/templates/users/user_group_list.html:20 -#: users/templates/users/user_group_list.html:70 +#: users/templates/users/user_group_list.html:71 #: 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_list.html:103 +#: users/templates/users/user_list.html:106 #: 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/change_auth_plan/templates/change_auth_plan/plan_list.html:56 #: xpack/plugins/cloud/templates/cloud/account_detail.html:23 -#: xpack/plugins/cloud/templates/cloud/account_list.html:39 +#: xpack/plugins/cloud/templates/cloud/account_list.html:40 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:29 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:56 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:57 #: xpack/plugins/orgs/templates/orgs/org_detail.html:25 -#: xpack/plugins/orgs/templates/orgs/org_list.html:87 +#: xpack/plugins/orgs/templates/orgs/org_list.html:88 msgid "Update" msgstr "更新" @@ -473,25 +473,25 @@ msgstr "更新" #: assets/templates/assets/system_user_list.html:86 audits/models.py:34 #: ops/templates/ops/task_list.html:64 #: perms/templates/perms/asset_permission_detail.html:34 -#: perms/templates/perms/asset_permission_list.html:178 +#: perms/templates/perms/asset_permission_list.html:179 #: perms/templates/perms/remote_app_permission_detail.html:34 #: perms/templates/perms/remote_app_permission_list.html:60 #: settings/templates/settings/terminal_setting.html:93 #: settings/templates/settings/terminal_setting.html:115 -#: terminal/templates/terminal/terminal_list.html:74 +#: terminal/templates/terminal/terminal_list.html:75 #: users/templates/users/user_detail.html:30 #: users/templates/users/user_group_detail.html:32 -#: users/templates/users/user_group_list.html:72 -#: users/templates/users/user_list.html:110 -#: users/templates/users/user_list.html:114 +#: users/templates/users/user_group_list.html:73 +#: users/templates/users/user_list.html:111 +#: users/templates/users/user_list.html:115 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:33 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:57 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:58 #: xpack/plugins/cloud/templates/cloud/account_detail.html:27 -#: xpack/plugins/cloud/templates/cloud/account_list.html:41 +#: xpack/plugins/cloud/templates/cloud/account_list.html:42 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:33 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:57 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:58 #: xpack/plugins/orgs/templates/orgs/org_detail.html:29 -#: xpack/plugins/orgs/templates/orgs/org_list.html:89 +#: xpack/plugins/orgs/templates/orgs/org_list.html:90 msgid "Delete" msgstr "删除" @@ -719,9 +719,9 @@ msgstr "SSH网关,支持代理SSH,RDP和VNC" #: assets/templates/assets/domain_gateway_list.html:71 #: assets/templates/assets/system_user_detail.html:62 #: assets/templates/assets/system_user_list.html:52 audits/models.py:94 -#: audits/templates/audits/login_log_list.html:51 authentication/forms.py:11 -#: authentication/templates/authentication/login.html:64 -#: authentication/templates/authentication/new_login.html:90 +#: audits/templates/audits/login_log_list.html:51 authentication/forms.py:13 +#: authentication/templates/authentication/login.html:65 +#: authentication/templates/authentication/new_login.html:91 #: ops/models/adhoc.py:164 perms/templates/perms/asset_permission_list.html:70 #: perms/templates/perms/asset_permission_user.html:55 #: perms/templates/perms/remote_app_permission_user.html:54 @@ -748,9 +748,9 @@ msgstr "密码或密钥密码" #: assets/serializers/asset_user.py:62 #: assets/templates/assets/_asset_user_auth_update_modal.html:21 #: assets/templates/assets/_asset_user_auth_view_modal.html:27 -#: authentication/forms.py:13 -#: authentication/templates/authentication/login.html:67 -#: authentication/templates/authentication/new_login.html:93 +#: authentication/forms.py:15 +#: authentication/templates/authentication/login.html:68 +#: authentication/templates/authentication/new_login.html:94 #: 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 @@ -1595,8 +1595,8 @@ msgstr "选择节点" #: users/templates/users/user_detail.html:441 #: users/templates/users/user_detail.html:486 #: users/templates/users/user_group_create_update.html:32 -#: users/templates/users/user_group_list.html:119 -#: users/templates/users/user_list.html:255 +#: users/templates/users/user_group_list.html:120 +#: users/templates/users/user_list.html:256 #: xpack/plugins/cloud/templates/cloud/account_create_update.html:34 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_create_update.html:54 #: xpack/plugins/interface/templates/interface/interface.html:103 @@ -1649,10 +1649,10 @@ msgstr "创建管理用户" #: 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 -#: users/templates/users/user_group_list.html:194 -#: users/templates/users/user_list.html:164 -#: users/templates/users/user_list.html:196 +#: users/templates/users/user_group_list.html:164 +#: users/templates/users/user_group_list.html:195 +#: users/templates/users/user_list.html:165 +#: users/templates/users/user_list.html:197 #: xpack/plugins/vault/templates/vault/vault.html:224 msgid "Please select file" msgstr "选择文件" @@ -1792,8 +1792,8 @@ msgstr "显示所有子节点资产" #: 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_group_list.html:113 -#: users/templates/users/user_list.html:249 +#: users/templates/users/user_group_list.html:114 +#: users/templates/users/user_list.html:250 #: xpack/plugins/interface/templates/interface/interface.html:97 msgid "Are you sure?" msgstr "你确认吗?" @@ -1809,8 +1809,8 @@ msgstr "删除选择资产" #: users/templates/users/user_detail.html:416 #: users/templates/users/user_detail.html:484 #: users/templates/users/user_group_create_update.html:31 -#: users/templates/users/user_group_list.html:117 -#: users/templates/users/user_list.html:253 +#: users/templates/users/user_group_list.html:118 +#: users/templates/users/user_list.html:254 #: xpack/plugins/interface/templates/interface/interface.html:101 #: xpack/plugins/orgs/templates/orgs/org_create_update.html:32 msgid "Cancel" @@ -2392,17 +2392,29 @@ msgstr "" msgid "Invalid token or cache refreshed." msgstr "" -#: authentication/forms.py:19 +#: authentication/forms.py:21 msgid "" -"Please enter a correct username and password. Note that both fields may be " -"case-sensitive." -msgstr "请输入正确的用户名和密码. 注意它们是区分大小写." +"The username or password you entered is incorrect, please enter it again." +msgstr "您输入的用户名或密码不正确,请重新输入。" -#: authentication/forms.py:22 +#: authentication/forms.py:24 msgid "This account is inactive." msgstr "此账户无效" -#: authentication/forms.py:37 users/forms.py:22 +#: authentication/forms.py:26 +#, python-brace-format +msgid "" +"You can also try {times_try} times (The account will be temporarily locked " +"for {block_time} minutes)" +msgstr "您还可以尝试 {times_try} 次(账号将被临时锁定 {block_time} 分钟)" + +#: authentication/forms.py:30 +msgid "" +"The account has been locked (please contact admin to unlock it or try again " +"after {} minutes)" +msgstr "账号已被锁定(请联系管理员解锁 或 {}分钟后重试)" + +#: authentication/forms.py:66 users/forms.py:22 msgid "MFA code" msgstr "MFA 验证码" @@ -2466,8 +2478,8 @@ msgid "Changes the world, starting with a little bit." msgstr "改变世界,从一点点开始。" #: authentication/templates/authentication/login.html:46 -#: authentication/templates/authentication/login.html:72 -#: authentication/templates/authentication/new_login.html:99 +#: authentication/templates/authentication/login.html:73 +#: authentication/templates/authentication/new_login.html:100 #: templates/_header_bar.html:101 msgid "Login" msgstr "登录" @@ -2482,18 +2494,18 @@ msgstr "用户密码已过期" msgid "Captcha invalid" msgstr "验证码错误" -#: authentication/templates/authentication/login.html:83 -#: authentication/templates/authentication/new_login.html:103 +#: authentication/templates/authentication/login.html:84 +#: authentication/templates/authentication/new_login.html:104 #: users/templates/users/forgot_password.html:10 #: users/templates/users/forgot_password.html:25 msgid "Forgot password" msgstr "忘记密码" -#: authentication/templates/authentication/login.html:89 +#: authentication/templates/authentication/login.html:91 msgid "More login options" msgstr "更多登录方式" -#: authentication/templates/authentication/login.html:93 +#: authentication/templates/authentication/login.html:95 msgid "Keycloak" msgstr "" @@ -2542,16 +2554,16 @@ msgstr "欢迎回来,请输入用户名和密码登录" msgid "Please enable cookies and try again." msgstr "设置你的浏览器支持cookie" -#: authentication/views/login.py:172 users/views/user.py:386 +#: authentication/views/login.py:173 users/views/user.py:386 #: users/views/user.py:411 msgid "MFA code invalid, or ntp sync server time" msgstr "MFA验证码不正确,或者服务器端时间不对" -#: authentication/views/login.py:203 +#: authentication/views/login.py:204 msgid "Logout success" msgstr "退出登录成功" -#: authentication/views/login.py:204 +#: authentication/views/login.py:205 msgid "Logout success, return login page" msgstr "退出登录成功,返回到登录页面" @@ -2955,9 +2967,9 @@ msgstr "版本" #: ops/templates/ops/task_list.html:63 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:137 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:53 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:54 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:141 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:54 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:55 msgid "Run" msgstr "执行" @@ -3167,7 +3179,7 @@ msgstr "刷新授权缓存" msgid "Validity" msgstr "有效" -#: perms/templates/perms/asset_permission_list.html:244 +#: perms/templates/perms/asset_permission_list.html:245 msgid "Refresh success" msgstr "刷新成功" @@ -4347,11 +4359,11 @@ msgstr "地址" msgid "Alive" msgstr "在线" -#: terminal/templates/terminal/terminal_list.html:77 +#: terminal/templates/terminal/terminal_list.html:78 msgid "Accept" msgstr "接受" -#: terminal/templates/terminal/terminal_list.html:79 +#: terminal/templates/terminal/terminal_list.html:80 msgid "Reject" msgstr "拒绝" @@ -4911,45 +4923,45 @@ msgstr "添加用户" msgid "Create user group" msgstr "创建用户组" -#: users/templates/users/user_group_list.html:114 +#: users/templates/users/user_group_list.html:115 msgid "This will delete the selected groups !!!" msgstr "删除选择组" -#: users/templates/users/user_group_list.html:123 +#: users/templates/users/user_group_list.html:124 msgid "UserGroups Deleted." msgstr "用户组删除" -#: users/templates/users/user_group_list.html:124 -#: users/templates/users/user_group_list.html:129 +#: users/templates/users/user_group_list.html:125 +#: users/templates/users/user_group_list.html:130 msgid "UserGroups Delete" msgstr "用户组删除" -#: users/templates/users/user_group_list.html:128 +#: users/templates/users/user_group_list.html:129 msgid "UserGroup Deleting failed." msgstr "用户组删除失败" -#: users/templates/users/user_list.html:250 +#: users/templates/users/user_list.html:251 msgid "This will delete the selected users !!!" msgstr "删除选中用户 !!!" -#: users/templates/users/user_list.html:266 +#: users/templates/users/user_list.html:267 msgid "User Deleted." msgstr "已被删除" -#: users/templates/users/user_list.html:267 -#: users/templates/users/user_list.html:271 +#: users/templates/users/user_list.html:268 +#: users/templates/users/user_list.html:272 msgid "User Delete" msgstr "删除" -#: users/templates/users/user_list.html:270 +#: users/templates/users/user_list.html:271 msgid "User Deleting failed." msgstr "用户删除失败" -#: users/templates/users/user_list.html:323 +#: users/templates/users/user_list.html:324 msgid "User is expired" msgstr "用户已失效" -#: users/templates/users/user_list.html:326 +#: users/templates/users/user_list.html:327 msgid "User is inactive" msgstr "用户已禁用" @@ -5484,7 +5496,7 @@ msgid "Run plan manually" msgstr "手动执行计划" #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:179 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:102 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:103 msgid "Execute failed" msgstr "执行失败" @@ -5708,7 +5720,7 @@ msgid "Run task manually" msgstr "手动执行任务" #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:181 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:98 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:99 msgid "Sync success" msgstr "同步成功" diff --git a/apps/users/utils.py b/apps/users/utils.py index 88564c2d3..3ccdc15b0 100644 --- a/apps/users/utils.py +++ b/apps/users/utils.py @@ -299,6 +299,12 @@ def increase_login_failed_count(username, ip): cache.set(key_limit, count, int(limit_time)*60) +def get_login_failed_count(username, ip): + key_limit = key_prefix_limit.format(username, ip) + count = cache.get(key_limit, 0) + return count + + def clean_failed_count(username, ip): key_limit = key_prefix_limit.format(username, ip) key_block = key_prefix_block.format(username) @@ -307,9 +313,8 @@ def clean_failed_count(username, ip): def is_block_login(username, ip): - key_limit = key_prefix_limit.format(username, ip) + count = get_login_failed_count(username, ip) key_block = key_prefix_block.format(username) - count = cache.get(key_limit, 0) limit_count = settings.SECURITY_LOGIN_LIMIT_COUNT limit_time = settings.SECURITY_LOGIN_LIMIT_TIME