diff --git a/apps/authentication/api/token.py b/apps/authentication/api/token.py index 6c6a34aa2..f7516496c 100644 --- a/apps/authentication/api/token.py +++ b/apps/authentication/api/token.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # - +from django.shortcuts import redirect from rest_framework.permissions import AllowAny from rest_framework.response import Response from rest_framework.generics import CreateAPIView @@ -40,3 +40,5 @@ class TokenCreateApi(AuthMixin, CreateAPIView): return Response(e.as_data(), status=400) except errors.NeedMoreInfoError as e: return Response(e.as_data(), status=200) + except errors.PasswdTooSimple as e: + return redirect(e.url) diff --git a/apps/authentication/errors.py b/apps/authentication/errors.py index 241881ba0..26363363e 100644 --- a/apps/authentication/errors.py +++ b/apps/authentication/errors.py @@ -211,3 +211,12 @@ class LoginConfirmOtherError(LoginConfirmBaseError): class SSOAuthClosed(JMSException): default_code = 'sso_auth_closed' default_detail = _('SSO auth closed') + + +class PasswdTooSimple(JMSException): + default_code = 'passwd_too_simple' + default_detail = _('Your password is too simple, please change it for security') + + def __init__(self, url, *args, **kwargs): + super(PasswdTooSimple, self).__init__(*args, **kwargs) + self.url = url diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index a450f610a..23ddac3cf 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -1,9 +1,12 @@ # -*- coding: utf-8 -*- # +from urllib.parse import urlencode from functools import partial import time + from django.conf import settings from django.contrib.auth import authenticate +from django.shortcuts import reverse from common.utils import get_object_or_none, get_request_ip, get_logger from users.models import User @@ -91,6 +94,8 @@ class AuthMixin: elif user.password_has_expired: raise CredentialError(error=errors.reason_password_expired) + self._check_passwd_is_too_simple(user, password) + clean_failed_count(username, ip) request.session['auth_password'] = 1 request.session['user_id'] = str(user.id) @@ -98,6 +103,22 @@ class AuthMixin: request.session['auth_backend'] = auth_backend return user + @classmethod + def _check_passwd_is_too_simple(cls, user, password): + if user.is_superuser and password == 'admin': + reset_passwd_url = reverse('authentication:reset-password') + query_str = urlencode({ + 'token': user.generate_reset_token() + }) + reset_passwd_url = f'{reset_passwd_url}?{query_str}' + + flash_page_url = reverse('authentication:passwd-too-simple-flash-msg') + query_str = urlencode({ + 'redirect_url': reset_passwd_url + }) + + raise errors.PasswdTooSimple(f'{flash_page_url}?{query_str}') + def check_user_auth_if_need(self): request = self.request if request.session.get('auth_password') and \ diff --git a/apps/authentication/urls/view_urls.py b/apps/authentication/urls/view_urls.py index 12e1fea84..467e32d0d 100644 --- a/apps/authentication/urls/view_urls.py +++ b/apps/authentication/urls/view_urls.py @@ -21,6 +21,7 @@ urlpatterns = [ path('password/forgot/sendmail-success/', users_view.UserForgotPasswordSendmailSuccessView.as_view(), name='forgot-password-sendmail-success'), path('password/reset/', users_view.UserResetPasswordView.as_view(), name='reset-password'), + path('password/too-simple-flash-msg/', views.FlashPasswdTooSimpleMsgView.as_view(), name='passwd-too-simple-flash-msg'), path('password/reset/success/', users_view.UserResetPasswordSuccessView.as_view(), name='reset-password-success'), path('password/verify/', users_view.UserVerifyPasswordView.as_view(), name='user-verify-password'), diff --git a/apps/authentication/views/login.py b/apps/authentication/views/login.py index a0b8804e1..d6331aa82 100644 --- a/apps/authentication/views/login.py +++ b/apps/authentication/views/login.py @@ -29,6 +29,7 @@ from ..forms import get_user_login_form_cls __all__ = [ 'UserLoginView', 'UserLogoutView', 'UserLoginGuardView', 'UserLoginWaitConfirmView', + 'FlashPasswdTooSimpleMsgView', ] @@ -91,6 +92,8 @@ class UserLoginView(mixins.AuthMixin, FormView): new_form._errors = form.errors context = self.get_context_data(form=new_form) return self.render_to_response(context) + except errors.PasswdTooSimple as e: + return redirect(e.url) return self.redirect_to_guard_view() def redirect_to_guard_view(self): @@ -151,6 +154,8 @@ class UserLoginGuardView(mixins.AuthMixin, RedirectView): return self.format_redirect_url(self.login_confirm_url) except errors.MFAUnsetError as e: return e.url + except errors.PasswdTooSimple as e: + return e.url else: auth_login(self.request, user) self.send_auth_signal(success=True, user=user) @@ -222,4 +227,16 @@ class UserLogoutView(TemplateView): return super().get_context_data(**kwargs) +@method_decorator(never_cache, name='dispatch') +class FlashPasswdTooSimpleMsgView(TemplateView): + template_name = 'flash_message_standalone.html' + def get(self, request, *args, **kwargs): + context = { + 'title': _('Please change your password'), + 'messages': _('Your password is too simple, please change it for security'), + 'interval': 5, + 'redirect_url': request.GET.get('redirect_url'), + 'auto_redirect': True, + } + return self.render_to_response(context) diff --git a/apps/common/utils/django.py b/apps/common/utils/django.py index 50c3f0ea1..b2a919401 100644 --- a/apps/common/utils/django.py +++ b/apps/common/utils/django.py @@ -2,7 +2,6 @@ # import re from django.shortcuts import reverse as dj_reverse -from django.db.models import Subquery, QuerySet from django.conf import settings from django.utils import timezone diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index cb2695eec..10950173d 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 fb3ab714f..2ab609743 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: 2020-08-04 15:33+0800\n" +"POT-Creation-Date: 2020-08-05 16:43+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -1359,11 +1359,11 @@ msgstr "复制成功" msgid "Welcome back, please enter username and password to login" msgstr "欢迎回来,请输入用户名和密码登录" -#: authentication/views/login.py:82 +#: authentication/views/login.py:83 msgid "Please enable cookies and try again." msgstr "设置你的浏览器支持cookie" -#: authentication/views/login.py:178 +#: authentication/views/login.py:183 msgid "" "Wait for {} confirm, You also can copy link to her/him
\n" " Don't close this page" @@ -1371,18 +1371,26 @@ msgstr "" "等待 {} 确认, 你也可以复制链接发给他/她
\n" " 不要关闭本页面" -#: authentication/views/login.py:183 +#: authentication/views/login.py:188 msgid "No ticket found" msgstr "没有发现工单" -#: authentication/views/login.py:215 +#: authentication/views/login.py:220 msgid "Logout success" msgstr "退出登录成功" -#: authentication/views/login.py:216 +#: authentication/views/login.py:221 msgid "Logout success, return login page" msgstr "退出登录成功,返回到登录页面" +#: authentication/views/login.py:236 +msgid "Please change your password" +msgstr "请修改密码" + +#: authentication/views/login.py:237 +msgid "Your password is too simple, please change it for security" +msgstr "你的密码过于简单,为了安全,请修改" + #: common/const/__init__.py:6 #, python-format msgid "%(name)s was created successfully" @@ -4222,9 +4230,6 @@ msgstr "旗舰版" #~ msgid "Update asset user auth" #~ msgstr "更新资产用户认证信息" -#~ msgid "Please input password" -#~ msgstr "请输入密码" - #~ msgid "Asset user auth" #~ msgstr "资产用户信息"