diff --git a/apps/authentication/api/mfa.py b/apps/authentication/api/mfa.py index 52795c630..183fb113c 100644 --- a/apps/authentication/api/mfa.py +++ b/apps/authentication/api/mfa.py @@ -12,6 +12,7 @@ from rest_framework.response import Response from common.permissions import IsValidUser, NeedMFAVerify from common.utils import get_logger +from common.exceptions import UnexpectError from users.models.user import User from ..serializers import OtpVerifySerializer from .. import serializers @@ -35,30 +36,36 @@ class MFASendCodeApi(AuthMixin, CreateAPIView): """ permission_classes = (AllowAny,) serializer_class = serializers.MFASelectTypeSerializer + username = '' + ip = '' + + def get_user_from_db(self, username): + try: + user = get_object_or_404(User, username=username) + return user + except Exception as e: + self.incr_mfa_failed_time(username, self.ip) + raise e def perform_create(self, serializer): username = serializer.validated_data.get('username', '') mfa_type = serializer.validated_data['type'] + + self.ip = self.get_request_ip() + self.check_mfa_is_block(username, self.ip) if not username: user = self.get_user_from_session() else: - user = get_object_or_404(User, username=username) + user = self.get_user_from_db(username) mfa_backend = user.get_active_mfa_backend_by_type(mfa_type) if not mfa_backend or not mfa_backend.challenge_required: - raise ValidationError('MFA type not support: {} {}'.format(mfa_type, mfa_backend)) - mfa_backend.send_challenge() - - def create(self, request, *args, **kwargs): - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) - + error = _('Current user not support mfa type: {}').format(mfa_type) + raise ValidationError({'error': error}) try: - self.perform_create(serializer) - return Response(serializer.data, status=201) + mfa_backend.send_challenge() except Exception as e: - logger.exception(e) - return Response({'error': str(e)}, status=400) + raise UnexpectError(str(e)) class MFAChallengeVerifyApi(AuthMixin, CreateAPIView): diff --git a/apps/authentication/mixins.py b/apps/authentication/mixins.py index 2167ab198..dd3653c6e 100644 --- a/apps/authentication/mixins.py +++ b/apps/authentication/mixins.py @@ -335,6 +335,11 @@ class MFAMixin: mfa_backends = User.get_user_mfa_backends(user) return {'mfa_backends': mfa_backends} + @staticmethod + def incr_mfa_failed_time(username, ip): + util = MFABlockUtils(username, ip) + util.incr_failed_count() + class AuthPostCheckMixin: @classmethod diff --git a/apps/authentication/templates/authentication/login.html b/apps/authentication/templates/authentication/login.html index 6e053b877..b74217cee 100644 --- a/apps/authentication/templates/authentication/login.html +++ b/apps/authentication/templates/authentication/login.html @@ -109,7 +109,7 @@ } .select-con { - width: 30%; + width: 35%; } .mfa-div { diff --git a/apps/common/exceptions.py b/apps/common/exceptions.py index 9d3008c50..067750ec6 100644 --- a/apps/common/exceptions.py +++ b/apps/common/exceptions.py @@ -45,3 +45,9 @@ class MFAVerifyRequired(JMSException): status_code = status.HTTP_400_BAD_REQUEST default_code = 'mfa_verify_required' default_detail = _('This action require verify your MFA') + + +class UnexpectError(JMSException): + status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + default_code = 'unexpect_error' + default_detail = _('Unexpect error occur') diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index e14978a33..63dee9b87 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:504b910235e3d0103d9bf2654bb542b7c4cba7ff1836c24fae4587b065c30fa0 -size 96229 +oid sha256:65ae747dcbddab2bbf9238b0ee589037805c9cf04a6c3a2e312d4c6c5e486b2d +size 96320 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index ee3cac7d5..4aaec0cae 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: 2022-01-13 14:05+0800\n" +"POT-Creation-Date: 2022-01-13 16:57+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -1622,7 +1622,11 @@ msgstr "{ApplicationPermission} 移除 {SystemUser}" msgid "Invalid token" msgstr "无效的令牌" -#: authentication/api/mfa.py:103 +#: authentication/api/mfa.py:50 +msgid "Current user not support mfa type: {}" +msgstr "当前用户不支持 MFA 类型: {}" + +#: authentication/api/mfa.py:97 msgid "Code is invalid, {}" msgstr "验证码无效: {}" @@ -2347,6 +2351,10 @@ msgstr "被其他对象关联,不能删除" msgid "This action require verify your MFA" msgstr "这个操作需要验证 MFA" +#: common/exceptions.py:53 +msgid "Unexpect error occur" +msgstr "" + #: common/fields/model.py:80 msgid "Marshal dict data to char field" msgstr "编码 dict 为 char" @@ -2892,7 +2900,7 @@ msgstr "获取 LDAP 用户为 None" msgid "Imported {} users successfully (Organization: {})" msgstr "成功导入 {} 个用户 ( 组织: {} )" -#: settings/models.py:196 users/templates/users/reset_password.html:29 +#: settings/models.py:195 users/templates/users/reset_password.html:29 msgid "Setting" msgstr "设置" @@ -6308,6 +6316,9 @@ msgstr "旗舰版" msgid "Community edition" msgstr "社区版" +#~ msgid "MFA type not support: {}" +#~ msgstr "MFA 类型不支持:{}" + #~ msgid "Push system users to asset: {}({}) => {}" #~ msgstr "推送系统用户到入资产: {}({}) => {}" diff --git a/apps/settings/models.py b/apps/settings/models.py index f92e09f34..0690590b6 100644 --- a/apps/settings/models.py +++ b/apps/settings/models.py @@ -79,7 +79,6 @@ class Setting(models.Model): item.refresh_setting() def refresh_setting(self): - logger.debug(f"Refresh setting: {self.name}") if hasattr(self.__class__, f'refresh_{self.name}'): getattr(self.__class__, f'refresh_{self.name}')() else: diff --git a/apps/templates/_mfa_login_field.html b/apps/templates/_mfa_login_field.html index 8aa3cbdd6..d73df5499 100644 --- a/apps/templates/_mfa_login_field.html +++ b/apps/templates/_mfa_login_field.html @@ -121,11 +121,7 @@ url: url, method: "POST", body: JSON.stringify(data), - success: onSuccess, - error: function (text, data) { - toastr.error(data.error) - }, - flash_message: false + success: onSuccess }) }