From 67f6b1080e6c728e84d5279caa0885512f9e8389 Mon Sep 17 00:00:00 2001 From: fit2bot <68588906+fit2bot@users.noreply.github.com> Date: Fri, 30 Jul 2021 15:19:00 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=AE=A1=E7=90=86=E5=91=98=E5=92=8C?= =?UTF-8?q?=E6=99=AE=E9=80=9A=E7=94=A8=E6=88=B7=E6=94=AF=E6=8C=81=E5=8D=95?= =?UTF-8?q?=E7=8B=AC=E8=AE=BE=E7=BD=AEMFA=E5=92=8C=E5=AF=86=E7=A0=81?= =?UTF-8?q?=E9=95=BF=E5=BA=A6=20(#6562)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 支持配置系统管理员强制MFA和独立密码长度限制 * feat: 支持配置系统管理员强制MFA和独立密码长度限制 * feat: 支持配置系统管理员强制MFA和独立密码长度限制, 翻译文件 * fix: 设置界面可设置管理员用户开启MFA,当在设置开启全局的时候,不改变用户的mfa字段状态 * fix: 修改管理员最小密码长度变量名称 * perf: 优化不同的配置 * perf: 修改check password rule * perf: 添加配置文件 * perf: 修改profile * perf: 优化代码 * fix: 修复bug Co-authored-by: fit2cloud-jiangweidong Co-authored-by: ibuler --- apps/assets/models/asset.py | 2 +- apps/assets/models/node.py | 2 +- apps/jumpserver/conf.py | 5 +- apps/jumpserver/settings/custom.py | 1 + apps/locale/zh/LC_MESSAGES/django.mo | Bin 79785 -> 80516 bytes apps/locale/zh/LC_MESSAGES/django.po | 136 ++++++++++-------- apps/settings/api/common.py | 4 +- .../migrations/0002_auto_20210729_1546.py | 29 ++++ apps/settings/serializers/settings.py | 14 +- apps/users/models/user.py | 9 +- apps/users/serializers/profile.py | 5 +- apps/users/serializers/user.py | 2 +- apps/users/utils.py | 12 +- apps/users/views/profile/otp.py | 17 ++- apps/users/views/profile/password.py | 52 +------ apps/users/views/profile/reset.py | 7 +- 16 files changed, 168 insertions(+), 129 deletions(-) create mode 100644 apps/settings/migrations/0002_auto_20210729_1546.py diff --git a/apps/assets/models/asset.py b/apps/assets/models/asset.py index 829c13f75..91acd3d34 100644 --- a/apps/assets/models/asset.py +++ b/apps/assets/models/asset.py @@ -333,7 +333,7 @@ class Asset(AbsConnectivity, ProtocolsMixin, NodesRelationMixin, OrgModelMixin): 'iconSkin': icon_skin, 'meta': { 'type': 'asset', - 'asset': { + 'data': { 'id': self.id, 'hostname': self.hostname, 'ip': self.ip, diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index 2e3b890a5..77614276a 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -608,7 +608,7 @@ class Node(OrgModelMixin, SomeNodesMixin, FamilyMixin, NodeAssetsMixin): 'isParent': True, 'open': self.is_org_root(), 'meta': { - 'node': { + 'data': { "id": self.id, "name": self.name, "value": self.value, diff --git a/apps/jumpserver/conf.py b/apps/jumpserver/conf.py index e1d6ead47..495ff5d50 100644 --- a/apps/jumpserver/conf.py +++ b/apps/jumpserver/conf.py @@ -16,9 +16,7 @@ import json import yaml from importlib import import_module from django.urls import reverse_lazy -from django.templatetags.static import static from urllib.parse import urljoin, urlparse -from django.utils.translation import ugettext_lazy as _ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) PROJECT_DIR = os.path.dirname(BASE_DIR) @@ -244,7 +242,7 @@ class Config(dict): 'TERMINAL_TELNET_REGEX': '', 'TERMINAL_COMMAND_STORAGE': {}, - 'SECURITY_MFA_AUTH': False, + 'SECURITY_MFA_AUTH': 0, # 0 不开启 1 全局开启 2 管理员开启 'SECURITY_COMMAND_EXECUTION': True, 'SECURITY_SERVICE_ACCOUNT_REGISTRATION': True, 'SECURITY_VIEW_AUTH_NEED_MFA': True, @@ -253,6 +251,7 @@ class Config(dict): 'SECURITY_MAX_IDLE_TIME': 30, 'SECURITY_PASSWORD_EXPIRATION_TIME': 9999, 'SECURITY_PASSWORD_MIN_LENGTH': 6, + 'SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH': 6, 'SECURITY_PASSWORD_UPPER_CASE': False, 'SECURITY_PASSWORD_LOWER_CASE': False, 'SECURITY_PASSWORD_NUMBER': False, diff --git a/apps/jumpserver/settings/custom.py b/apps/jumpserver/settings/custom.py index 226aedc62..cc6875083 100644 --- a/apps/jumpserver/settings/custom.py +++ b/apps/jumpserver/settings/custom.py @@ -38,6 +38,7 @@ SECURITY_LOGIN_LIMIT_TIME = CONFIG.SECURITY_LOGIN_LIMIT_TIME # Unit: minute SECURITY_MAX_IDLE_TIME = CONFIG.SECURITY_MAX_IDLE_TIME # Unit: minute SECURITY_PASSWORD_EXPIRATION_TIME = CONFIG.SECURITY_PASSWORD_EXPIRATION_TIME # Unit: day SECURITY_PASSWORD_MIN_LENGTH = CONFIG.SECURITY_PASSWORD_MIN_LENGTH # Unit: bit +SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH = CONFIG.SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH # Unit: bit OLD_PASSWORD_HISTORY_LIMIT_COUNT = CONFIG.OLD_PASSWORD_HISTORY_LIMIT_COUNT SECURITY_PASSWORD_UPPER_CASE = CONFIG.SECURITY_PASSWORD_UPPER_CASE SECURITY_PASSWORD_LOWER_CASE = CONFIG.SECURITY_PASSWORD_LOWER_CASE diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index f85dee23ae796b98671c1d164c999f343b46a3bd..0133308889c136f77eb3e0bd7882a8b61fe755d2 100644 GIT binary patch delta 24715 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 Z=>Poy&COrdQ$E1$p*?I@*3;7e{{iBr3fcew delta 23953 zcmYk^2YgQF-^cND6O!0Fwpg+E-m7SxF?{S>pTRYA^+|t%@NI5;*JI*vbhC{G%2ghkf|I;{`IBzG% z8HwBQ3YO^XIHwq&Jj`)o9mnfj>Ebx)7%-=+{P+m-VY>eA!Yd<>meUZMW3&G3zwXTz5<0<6 zOpT9GD|N!%I0Q3EETR=xuDR%}Hr_!#OQUchvC4fXmyM?DiM2f8QDj#_vbRKG^3`MY3x z^hQ$Agwrgs7`32ii;r7;4fQ%b!;JXK+Eae*IGKs_qE1j9)!r1-V;{?pMcw=P7=TNW zTkdt%QPI8Kg?aEW>I&jf592E=f}TkCnJ9+ZkqW3Qse^j&o1@-}NYt}50@ZISYTo&% z^Bh1uTPHEK-v9Gd`22D1p(c2MI`LD?fd8OYoMwO>n+0}r8Y#ZT6L7K4bdqfYb+ zHBagxt{G9!N)F71`A|Dj8@(FX!x~1T?%^`bj5{qpi#lN(Y5@;XC-@6B{vXuSoOY;d zUbCF}8S0s8je0BkqAqCkQ1)M2JCB4WUT$tQcbW%L{Z62E<`;{vS$xlYhFZuwtbi$o zxzEU_s0Fvg{MZ4tBa?=)|C)HFbzFd&V57zRF*EUL%!Ch6D^EDwU2rDUM7dFKQ6aMu z79*~Q+M%JS@lmLUdoyaM_j##k;5pRmaSOH5c+|arjCzXSp-vPy!rg(?sBu|Q`NEhB zOIyA<>O#7rPB<8K3np6oBGbExie96AsGT^4n(!j(UR_7MHqTHK{%h?i**Q%dgc=`$ z8dnZ8Vl~vb7N`s8Z0-Hgw;(t6Iuohr-hYGYxB&I~tVQj_70iOSQT^VdwlZL(YcA9+ zsf>CyzQT^!7S->2)P-F}&36a2a}P1O-v75$bT0x%xhKeG=EGp}B~TN5g}S2FsIBaZ z`WzUFdOK#JE?_RI|0;_&qi$s^>cl^ycHj~w;rvcK6+L9nmB8eq-GyXCO_&QcK{3?C zRZv@92Q^^>)PmYs9FDru(Wnzm!a_I?3*%ALf}f#R6TYINjvuf*rWoUHU0u}HhN2c2 zi8}Et)WQ~+YfQf zb9K~}w?s`CYWBcf!~;+h&OyC3YfumE9t^Ko3Cuddy(JC2RJ3J7Py?r<7O)&O z;diK8bJ#qG>UR_U@rC98K`l7RL^q!m6BFk_Ex3^7OIyA&W+U&dMJ1R@s3k^Y0P!-^ zJzj6|F4TkvQ78Vv;?vfC0d>o+qweuT)c9nR+zZKsy3hisTU7;{>HB{ql{F-O!@W3S zvOA#S6!(^Vj+&@F>LKcdT1X^nAtO*bG#+(=Z&5qA9@Re<^{gC2_5T(1xo`zD=>305 zMO&S0s(Y`qVglkam=w!nAbx_Hr~&Hpq7CZA{m~Ccn&VLYCZitCd6wUankUxcqnK3h z{|PF|@B#+oZ4AJK)7%pzL$zl?-Q)bIr@10(;nguYHbnJnhgx7y)P;;R$DkhO@u>Ni zqE{2HqmmqBQ5}9nJ=M2Nzvz)md1nD{ugQiAFvPx z%yP$-#@xi!Fd=rr?AX;yMO!`IT#q`z�}vgj(1Q)R)bls4MY{az9{_VH)E6sCg=( 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 diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 64901bb1d..ba3f42c3b 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-27 15:57+0800\n" +"POT-Creation-Date: 2021-07-28 18:36+0800\n" "PO-Revision-Date: 2021-05-20 10:54+0800\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -25,7 +25,7 @@ msgstr "" #: orgs/models.py:24 perms/models/base.py:49 settings/models.py:29 #: terminal/models/storage.py:23 terminal/models/task.py:16 #: terminal/models/terminal.py:100 users/forms/profile.py:32 -#: users/models/group.py:15 users/models/user.py:551 +#: users/models/group.py:15 users/models/user.py:555 #: users/templates/users/_select_user_modal.html:13 #: users/templates/users/user_asset_permission.html:37 #: users/templates/users/user_asset_permission.html:154 @@ -61,7 +61,7 @@ msgstr "激活中" #: orgs/models.py:27 perms/models/base.py:57 settings/models.py:34 #: terminal/models/storage.py:26 terminal/models/terminal.py:114 #: tickets/models/ticket.py:73 users/models/group.py:16 -#: users/models/user.py:584 xpack/plugins/change_auth_plan/models.py:77 +#: users/models/user.py:588 xpack/plugins/change_auth_plan/models.py:77 #: xpack/plugins/cloud/models.py:35 xpack/plugins/cloud/models.py:98 #: xpack/plugins/gathered_user/models.py:26 msgid "Comment" @@ -99,7 +99,7 @@ msgstr "动作" #: terminal/backends/command/models.py:18 #: terminal/backends/command/serializers.py:12 terminal/models/session.py:38 #: tickets/models/comment.py:17 users/models/user.py:176 -#: users/models/user.py:747 users/models/user.py:773 +#: users/models/user.py:751 users/models/user.py:777 #: users/serializers/group.py:19 #: users/templates/users/user_asset_permission.html:38 #: users/templates/users/user_asset_permission.html:64 @@ -179,7 +179,7 @@ msgstr "格式为逗号分隔的字符串, * 表示匹配所有. " #: applications/serializers/attrs/application_type/vmware_client.py:26 #: assets/models/base.py:176 assets/models/gathered_user.py:15 #: audits/models.py:100 authentication/forms.py:15 authentication/forms.py:17 -#: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:549 +#: ops/models/adhoc.py:148 users/forms/profile.py:31 users/models/user.py:553 #: users/templates/users/_select_user_modal.html:14 #: xpack/plugins/change_auth_plan/models.py:47 #: xpack/plugins/change_auth_plan/models.py:278 @@ -515,7 +515,7 @@ msgstr "标签管理" #: assets/models/cluster.py:28 assets/models/cmd_filter.py:26 #: assets/models/cmd_filter.py:67 assets/models/group.py:21 #: common/db/models.py:70 common/mixins/models.py:49 orgs/models.py:25 -#: orgs/models.py:437 perms/models/base.py:55 users/models/user.py:592 +#: orgs/models.py:437 perms/models/base.py:55 users/models/user.py:596 #: users/serializers/group.py:33 xpack/plugins/change_auth_plan/models.py:81 #: xpack/plugins/cloud/models.py:104 xpack/plugins/gathered_user/models.py:30 msgid "Created by" @@ -529,7 +529,7 @@ msgstr "创建者" #: assets/models/label.py:25 common/db/models.py:72 common/mixins/models.py:50 #: ops/models/adhoc.py:38 ops/models/command.py:29 orgs/models.py:26 #: orgs/models.py:435 perms/models/base.py:56 users/models/group.py:18 -#: users/models/user.py:774 xpack/plugins/cloud/models.py:107 +#: users/models/user.py:778 xpack/plugins/cloud/models.py:107 msgid "Date created" msgstr "创建日期" @@ -587,7 +587,7 @@ msgstr "带宽" msgid "Contact" msgstr "联系人" -#: assets/models/cluster.py:22 users/models/user.py:570 +#: assets/models/cluster.py:22 users/models/user.py:574 msgid "Phone" msgstr "手机" @@ -613,7 +613,7 @@ msgid "Default" msgstr "默认" #: assets/models/cluster.py:36 assets/models/label.py:14 -#: users/models/user.py:759 +#: users/models/user.py:763 msgid "System" msgstr "系统" @@ -1151,7 +1151,7 @@ msgstr "用户代理" #: audits/models.py:105 #: authentication/templates/authentication/_mfa_confirm_modal.html:14 #: authentication/templates/authentication/login_otp.html:6 -#: users/forms/profile.py:64 users/models/user.py:573 +#: users/forms/profile.py:64 users/models/user.py:577 #: users/serializers/profile.py:102 msgid "MFA" msgstr "多因子认证" @@ -1641,7 +1641,8 @@ msgid "Show" msgstr "显示" #: authentication/templates/authentication/_access_key_modal.html:66 -#: users/models/user.py:463 users/serializers/profile.py:99 +#: settings/serializers/settings.py:148 users/models/user.py:463 +#: users/serializers/profile.py:99 #: users/templates/users/user_verify_mfa.html:32 msgid "Disable" msgstr "禁用" @@ -2020,7 +2021,7 @@ msgstr "" "div>" #: notifications/backends/__init__.py:11 users/forms/profile.py:101 -#: users/models/user.py:553 +#: users/models/user.py:557 msgid "Email" msgstr "邮件" @@ -2213,7 +2214,7 @@ msgstr "组织审计员" msgid "GLOBAL" msgstr "全局组织" -#: orgs/models.py:434 users/models/user.py:561 +#: orgs/models.py:434 users/models/user.py:565 #: users/templates/users/_select_user_modal.html:15 msgid "Role" msgstr "角色" @@ -2276,7 +2277,7 @@ msgid "Favorite" msgstr "收藏夹" #: perms/models/base.py:51 templates/_nav.html:21 users/models/group.py:31 -#: users/models/user.py:557 users/templates/users/_select_user_modal.html:16 +#: users/models/user.py:561 users/templates/users/_select_user_modal.html:16 #: users/templates/users/user_asset_permission.html:39 #: users/templates/users/user_asset_permission.html:67 #: users/templates/users/user_database_app_permission.html:38 @@ -2289,7 +2290,7 @@ msgstr "用户组" #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:77 #: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:43 #: tickets/serializers/ticket/meta/ticket_type/apply_asset.py:81 -#: users/models/user.py:589 +#: users/models/user.py:593 msgid "Date expired" msgstr "失效日期" @@ -2585,60 +2586,72 @@ msgstr "RDP 地址" msgid "RDP visit address, eg: dev.jumpserver.org:3389" msgstr "RDP 访问地址, 如: dev.jumpserver.org:3389" -#: settings/serializers/settings.py:147 +#: settings/serializers/settings.py:149 +msgid "All users" +msgstr "所有用户" + +#: settings/serializers/settings.py:150 +msgid "Only admin users" +msgstr "仅管理员" + +#: settings/serializers/settings.py:152 msgid "Global MFA auth" msgstr "全局启用 MFA 认证" -#: settings/serializers/settings.py:148 -msgid "All user enable MFA" -msgstr "强制所有用户启用多因子认证" +#: settings/serializers/settings.py:155 +msgid "Admin user MFA auth" +msgstr "所有管理员启用 MFA" -#: settings/serializers/settings.py:151 +#: settings/serializers/settings.py:156 +msgid "Admin user enable MFA" +msgstr "强制管理员启用 MFA" + +#: settings/serializers/settings.py:159 msgid "Batch command execution" msgstr "批量命令执行" -#: settings/serializers/settings.py:152 +#: settings/serializers/settings.py:160 msgid "Allow user run batch command or not using ansible" msgstr "是否允许用户使用 ansible 执行批量命令" -#: settings/serializers/settings.py:155 +#: settings/serializers/settings.py:163 msgid "Enable terminal register" msgstr "终端注册" -#: settings/serializers/settings.py:156 +#: settings/serializers/settings.py:164 msgid "" "Allow terminal register, after all terminal setup, you should disable this " "for security" msgstr "是否允许终端注册,当所有终端启动后,为了安全应该关闭" -#: settings/serializers/settings.py:160 +#: settings/serializers/settings.py:168 msgid "Limit the number of login failures" msgstr "限制登录失败次数" -#: settings/serializers/settings.py:164 +#: settings/serializers/settings.py:172 msgid "Block logon interval" msgstr "禁止登录时间间隔" -#: settings/serializers/settings.py:165 +#: settings/serializers/settings.py:173 msgid "" "Tip: (unit/minute) if the user has failed to log in for a limited number of " "times, no login is allowed during this time interval." msgstr "" "提示:(单位:分)当用户登录失败次数达到限制后,那么在此时间间隔内禁止登录" -#: settings/serializers/settings.py:169 +#: settings/serializers/settings.py:177 msgid "Connection max idle time" msgstr "连接最大空闲时间" -#: settings/serializers/settings.py:170 +#: settings/serializers/settings.py:178 msgid "If idle time more than it, disconnect connection Unit: minute" msgstr "提示:如果超过该配置没有操作,连接会被断开 (单位:分)" -#: settings/serializers/settings.py:174 +#: settings/serializers/settings.py:182 msgid "User password expiration" msgstr "用户密码过期时间" -#: settings/serializers/settings.py:175 +#: settings/serializers/settings.py:183 msgid "" "Tip: (unit: day) If the user does not update the password during the time, " "the user password will expire failure;The password expiration reminder mail " @@ -2648,53 +2661,57 @@ msgstr "" "提示:(单位:天)如果用户在此期间没有更新密码,用户密码将过期失效; 密码过期" "提醒邮件将在密码过期前5天内由系统(每天)自动发送给用户" -#: settings/serializers/settings.py:179 +#: settings/serializers/settings.py:187 msgid "Number of repeated historical passwords" msgstr "不能设置近几次密码" -#: settings/serializers/settings.py:180 +#: settings/serializers/settings.py:188 msgid "" "Tip: When the user resets the password, it cannot be the previous n " "historical passwords of the user" msgstr "提示:用户重置密码时,不能为该用户前几次使用过的密码" -#: settings/serializers/settings.py:184 +#: settings/serializers/settings.py:192 msgid "Password minimum length" msgstr "密码最小长度" -#: settings/serializers/settings.py:187 +#: settings/serializers/settings.py:196 +msgid "Admin user password minimum length" +msgstr "管理员密码最小长度" + +#: settings/serializers/settings.py:199 msgid "Must contain capital" msgstr "必须包含大写字符" -#: settings/serializers/settings.py:189 +#: settings/serializers/settings.py:201 msgid "Must contain lowercase" msgstr "必须包含小写字符" -#: settings/serializers/settings.py:190 +#: settings/serializers/settings.py:202 msgid "Must contain numeric" msgstr "必须包含数字" -#: settings/serializers/settings.py:191 +#: settings/serializers/settings.py:203 msgid "Must contain special" msgstr "必须包含特殊字符" -#: settings/serializers/settings.py:192 +#: settings/serializers/settings.py:204 msgid "Insecure command alert" msgstr "危险命令告警" -#: settings/serializers/settings.py:194 +#: settings/serializers/settings.py:206 msgid "Email recipient" msgstr "邮件收件人" -#: settings/serializers/settings.py:195 +#: settings/serializers/settings.py:207 msgid "Multiple user using , split" msgstr "多个用户,使用 , 分割" -#: settings/serializers/settings.py:203 +#: settings/serializers/settings.py:215 msgid "Enable WeCom Auth" msgstr "启用企业微信认证" -#: settings/serializers/settings.py:210 +#: settings/serializers/settings.py:222 msgid "Enable DingTalk Auth" msgstr "启用钉钉认证" @@ -4069,7 +4086,7 @@ msgstr "不能和原来的密钥相同" msgid "Not a valid ssh public key" msgstr "SSH密钥不合法" -#: users/forms/profile.py:160 users/models/user.py:581 +#: users/forms/profile.py:160 users/models/user.py:585 #: users/templates/users/user_password_update.html:48 msgid "Public key" msgstr "SSH公钥" @@ -4086,39 +4103,39 @@ msgstr "系统审计员" msgid "Force enable" msgstr "强制启用" -#: users/models/user.py:530 +#: users/models/user.py:534 msgid "Local" msgstr "数据库" -#: users/models/user.py:564 +#: users/models/user.py:568 msgid "Avatar" msgstr "头像" -#: users/models/user.py:567 +#: users/models/user.py:571 msgid "Wechat" msgstr "微信" -#: users/models/user.py:578 +#: users/models/user.py:582 msgid "Private key" msgstr "ssh私钥" -#: users/models/user.py:597 +#: users/models/user.py:601 msgid "Source" msgstr "来源" -#: users/models/user.py:601 +#: users/models/user.py:605 msgid "Date password last updated" msgstr "最后更新密码日期" -#: users/models/user.py:604 +#: users/models/user.py:608 msgid "Need update password" msgstr "需要更新密码" -#: users/models/user.py:755 +#: users/models/user.py:759 msgid "Administrator" msgstr "管理员" -#: users/models/user.py:758 +#: users/models/user.py:762 msgid "Administrator is the super user of system" msgstr "Administrator是初始的超级管理员" @@ -4709,24 +4726,24 @@ msgstr "" "
\n" " " -#: users/views/profile/otp.py:107 users/views/profile/otp.py:146 -#: users/views/profile/otp.py:166 +#: users/views/profile/otp.py:107 users/views/profile/otp.py:147 +#: users/views/profile/otp.py:167 msgid "MFA code invalid, or ntp sync server time" msgstr "MFA验证码不正确,或者服务器端时间不对" -#: users/views/profile/otp.py:190 +#: users/views/profile/otp.py:191 msgid "MFA enable success" msgstr "多因子认证启用成功" -#: users/views/profile/otp.py:191 +#: users/views/profile/otp.py:192 msgid "MFA enable success, return login page" msgstr "多因子认证启用成功,返回到登录页面" -#: users/views/profile/otp.py:193 +#: users/views/profile/otp.py:194 msgid "MFA disable success" msgstr "多因子认证禁用成功" -#: users/views/profile/otp.py:194 +#: users/views/profile/otp.py:195 msgid "MFA disable success, return login page" msgstr "多因子认证禁用成功,返回登录页面" @@ -5277,6 +5294,9 @@ msgstr "旗舰版" msgid "Community edition" msgstr "社区版" +#~ msgid "All user enable MFA" +#~ msgstr "强制所有用户启用 MFA" + #~ msgid "Application category" #~ msgstr "应用类别" diff --git a/apps/settings/api/common.py b/apps/settings/api/common.py index 85e1c941f..27e3eff54 100644 --- a/apps/settings/api/common.py +++ b/apps/settings/api/common.py @@ -122,6 +122,7 @@ class PublicSettingApi(generics.RetrieveAPIView): "TICKETS_ENABLED": settings.TICKETS_ENABLED, "PASSWORD_RULE": { 'SECURITY_PASSWORD_MIN_LENGTH': settings.SECURITY_PASSWORD_MIN_LENGTH, + 'SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH': settings.SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH, 'SECURITY_PASSWORD_UPPER_CASE': settings.SECURITY_PASSWORD_UPPER_CASE, 'SECURITY_PASSWORD_LOWER_CASE': settings.SECURITY_PASSWORD_LOWER_CASE, 'SECURITY_PASSWORD_NUMBER': settings.SECURITY_PASSWORD_NUMBER, @@ -160,7 +161,8 @@ class SettingsApi(generics.RetrieveUpdateAPIView): def get_object(self): items = self.get_fields().keys() - return {item: getattr(settings, item) for item in items} + obj = {item: getattr(settings, item) for item in items} + return obj def parse_serializer_data(self, serializer): data = [] diff --git a/apps/settings/migrations/0002_auto_20210729_1546.py b/apps/settings/migrations/0002_auto_20210729_1546.py new file mode 100644 index 000000000..986818cd4 --- /dev/null +++ b/apps/settings/migrations/0002_auto_20210729_1546.py @@ -0,0 +1,29 @@ +# Generated by Django 3.1 on 2021-07-29 07:46 + +from django.db import migrations + + +def migrate_security_mfa_auth(apps, schema_editor): + setting_model = apps.get_model("settings", "Setting") + db_alias = schema_editor.connection.alias + + mfa_setting = setting_model.objects.using(db_alias).filter(name='SECURITY_MFA_AUTH').first() + if not mfa_setting: + return + + if mfa_setting.value: + mfa_setting.value = 1 + else: + mfa_setting.value = 0 + mfa_setting.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('settings', '0001_initial'), + ] + + operations = [ + migrations.RunPython(migrate_security_mfa_auth) + ] diff --git a/apps/settings/serializers/settings.py b/apps/settings/serializers/settings.py index f2e11c17f..1039fd557 100644 --- a/apps/settings/serializers/settings.py +++ b/apps/settings/serializers/settings.py @@ -143,9 +143,13 @@ class TerminalSettingSerializer(serializers.Serializer): class SecuritySettingSerializer(serializers.Serializer): - SECURITY_MFA_AUTH = serializers.BooleanField( - required=False, label=_("Global MFA auth"), - help_text=_('All user enable MFA') + SECURITY_MFA_AUTH = serializers.ChoiceField( + choices=( + [0, _('Disable')], + [1, _('All users')], + [2, _('Only admin users')], + ), + required=False, label=_("Global MFA auth") ) SECURITY_COMMAND_EXECUTION = serializers.BooleanField( required=False, label=_('Batch command execution'), @@ -183,6 +187,10 @@ class SecuritySettingSerializer(serializers.Serializer): min_value=6, max_value=30, required=True, label=_('Password minimum length') ) + SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH = serializers.IntegerField( + min_value=6, max_value=30, required=True, + label=_('Admin user password minimum length') + ) SECURITY_PASSWORD_UPPER_CASE = serializers.BooleanField( required=False, label=_('Must contain capital') ) diff --git a/apps/users/models/user.py b/apps/users/models/user.py index a8a60f44a..f921058fa 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -464,14 +464,19 @@ class MFAMixin: (1, _('Enable')), (2, _("Force enable")), ) + is_org_admin: bool @property def mfa_enabled(self): - return self.mfa_force_enabled or self.mfa_level > 0 + if self.mfa_force_enabled: + return True + return self.mfa_level > 0 @property def mfa_force_enabled(self): - if settings.SECURITY_MFA_AUTH: + if settings.SECURITY_MFA_AUTH in [True, 1]: + return True + if settings.SECURITY_MFA_AUTH == 2 and self.is_org_admin: return True return self.mfa_level == 2 diff --git a/apps/users/serializers/profile.py b/apps/users/serializers/profile.py index c1caf1f99..3ba22ac7b 100644 --- a/apps/users/serializers/profile.py +++ b/apps/users/serializers/profile.py @@ -32,7 +32,7 @@ class UserUpdatePasswordSerializer(serializers.ModelSerializer): def validate_new_password(self, value): from ..utils import check_password_rules - if not check_password_rules(value): + if not check_password_rules(value, user=self.instance): msg = _('Password does not match security rules') raise serializers.ValidationError(msg) if self.instance.is_history_password(value): @@ -106,7 +106,8 @@ class UserProfileSerializer(UserSerializer): fields = UserSerializer.Meta.fields + [ 'public_key_comment', 'public_key_hash_md5', 'admin_or_audit_orgs', 'current_org_roles', - 'guide_url', 'user_all_orgs' + 'guide_url', 'user_all_orgs', 'is_org_admin', + 'is_superuser' ] read_only_fields = [ 'date_joined', 'last_login', 'created_by', 'source' diff --git a/apps/users/serializers/user.py b/apps/users/serializers/user.py index f9b2c46ee..c718f29ec 100644 --- a/apps/users/serializers/user.py +++ b/apps/users/serializers/user.py @@ -122,7 +122,7 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer): if self.instance and not password: # 更新用户, 未设置密码 return - if not check_password_rules(password): + if not check_password_rules(password, user=self.instance): msg = _('Password does not match security rules') raise serializers.ValidationError(msg) return password diff --git a/apps/users/utils.py b/apps/users/utils.py index 374ead56f..9d4d3e32d 100644 --- a/apps/users/utils.py +++ b/apps/users/utils.py @@ -295,10 +295,12 @@ def check_otp_code(otp_secret_key, otp_code): return totp.verify(otp=otp_code, valid_window=otp_valid_window) -def get_password_check_rules(): +def get_password_check_rules(user): check_rules = [] for rule in settings.SECURITY_PASSWORD_RULES: key = "id_{}".format(rule.lower()) + if user.is_org_admin and rule == 'SECURITY_PASSWORD_MIN_LENGTH': + rule = 'SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH' value = getattr(settings, rule) if not value: continue @@ -306,7 +308,7 @@ def get_password_check_rules(): return check_rules -def check_password_rules(password): +def check_password_rules(password, user): pattern = r"^" if settings.SECURITY_PASSWORD_UPPER_CASE: pattern += '(?=.*[A-Z])' @@ -317,7 +319,11 @@ def check_password_rules(password): if settings.SECURITY_PASSWORD_SPECIAL_CHAR: pattern += '(?=.*[`~!@#\$%\^&\*\(\)-=_\+\[\]\{\}\|;:\'\",\.<>\/\?])' pattern += '[a-zA-Z\d`~!@#\$%\^&\*\(\)-=_\+\[\]\{\}\|;:\'\",\.<>\/\?]' - pattern += '.{' + str(settings.SECURITY_PASSWORD_MIN_LENGTH-1) + ',}$' + if user.is_org_admin: + min_length = settings.SECURITY_ADMIN_USER_PASSWORD_MIN_LENGTH + else: + min_length = settings.SECURITY_PASSWORD_MIN_LEN + pattern += '.{' + str(min_length-1) + ',}$' match_obj = re.match(pattern, password) return bool(match_obj) diff --git a/apps/users/views/profile/otp.py b/apps/users/views/profile/otp.py index caed50532..7966dda8e 100644 --- a/apps/users/views/profile/otp.py +++ b/apps/users/views/profile/otp.py @@ -2,6 +2,7 @@ import time from django.urls import reverse_lazy, reverse +from django.shortcuts import get_object_or_404 from django.utils.translation import ugettext as _ from django.views.generic.base import TemplateView from django.views.generic.edit import FormView @@ -33,6 +34,16 @@ logger = get_logger(__name__) class UserOtpEnableStartView(UserVerifyPasswordView): template_name = 'users/user_otp_check_password.html' + def form_valid(self, form): + # 开启了 OTP IN RADIUS 就不用绑定了 + resp = super().form_valid(form) + if settings.OTP_IN_RADIUS: + user_id = self.request.session.get('user_id') + user = get_object_or_404(User, id=user_id) + user.enable_mfa() + user.save() + return resp + def get_success_url(self): if settings.OTP_IN_RADIUS: success_url = reverse_lazy('authentication:user-otp-settings-success') @@ -85,7 +96,11 @@ class UserOtpEnableBindView(AuthMixin, TemplateView, FormView): session_user = get_object_or_none(User, pk=user_id) if session_user: - if all((is_auth_password_time_valid(self.request.session), session_user.mfa_enabled, not session_user.otp_secret_key)): + if all(( + is_auth_password_time_valid(self.request.session), + session_user.mfa_enabled, + not session_user.otp_secret_key + )): return True return False diff --git a/apps/users/views/profile/password.py b/apps/users/views/profile/password.py index e2cd8f8e2..e2dde8e92 100644 --- a/apps/users/views/profile/password.py +++ b/apps/users/views/profile/password.py @@ -4,65 +4,20 @@ import time from django.conf import settings from django.contrib.auth import authenticate from django.shortcuts import redirect -from django.urls import reverse_lazy from django.utils.translation import ugettext as _ -from django.views.generic.edit import UpdateView, FormView -from django.contrib.auth import logout as auth_logout +from django.views.generic.edit import FormView from common.utils import get_logger -from common.permissions import ( - IsValidUser, - UserCanUpdatePassword -) -from common.mixins.views import PermissionsMixin from ... import forms -from ...models import User from ...utils import ( get_user_or_pre_auth_user, - check_password_rules, get_password_check_rules, ) -__all__ = ['UserPasswordUpdateView', 'UserVerifyPasswordView'] +__all__ = ['UserVerifyPasswordView'] logger = get_logger(__name__) -class UserPasswordUpdateView(PermissionsMixin, UpdateView): - template_name = 'users/user_password_update.html' - 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 - - def get_context_data(self, **kwargs): - check_rules = get_password_check_rules() - context = { - 'app': _('Users'), - 'action': _('Password update'), - 'password_check_rules': check_rules, - } - kwargs.update(context) - return super().get_context_data(**kwargs) - - def get_success_url(self): - auth_logout(self.request) - return super().get_success_url() - - def form_valid(self, form): - password = form.cleaned_data.get('new_password') - is_ok = check_password_rules(password) - if not is_ok: - form.add_error( - "new_password", - _("* Your password does not meet the requirements") - ) - return self.form_invalid(form) - return super().form_valid(form) - - class UserVerifyPasswordView(FormView): template_name = 'users/user_password_verify.html' form_class = forms.UserCheckPasswordForm @@ -74,9 +29,6 @@ class UserVerifyPasswordView(FormView): if not user: form.add_error("password", _("Password invalid")) return self.form_invalid(form) - if not user.mfa_is_otp(): - user.enable_mfa() - user.save() self.request.session['user_id'] = str(user.id) self.request.session['auth_password'] = 1 self.request.session['auth_password_expired_at'] = time.time() + settings.AUTH_EXPIRED_SECONDS diff --git a/apps/users/views/profile/reset.py b/apps/users/views/profile/reset.py index ba9cfd9b7..46d09ab7e 100644 --- a/apps/users/views/profile/reset.py +++ b/apps/users/views/profile/reset.py @@ -82,8 +82,9 @@ class UserResetPasswordView(FormView): if not user: context['errors'] = _('Token invalid or expired') context['token_invalid'] = True - check_rules = get_password_check_rules() - context['password_check_rules'] = check_rules + else: + check_rules = get_password_check_rules(user) + context['password_check_rules'] = check_rules return context def form_valid(self, form): @@ -100,7 +101,7 @@ class UserResetPasswordView(FormView): return self.form_invalid(form) password = form.cleaned_data['new_password'] - is_ok = check_password_rules(password) + is_ok = check_password_rules(password, user) if not is_ok: error = _('* Your password does not meet the requirements') form.add_error('new_password', error)