[Update] 添加OTP认证功能

pull/1214/head^2
BaiJiangjie 2018-04-19 11:13:11 +08:00
parent 33bc73aba7
commit 12c8cf6b76
15 changed files with 347 additions and 215 deletions

Binary file not shown.

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Jumpserver 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-04-13 17:27+0800\n"
"POT-Creation-Date: 2018-04-18 20:14+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: Jumpserver team<ibuler@qq.com>\n"
@ -154,7 +154,7 @@ msgstr "名称"
#: assets/templates/assets/system_user_detail.html:62
#: assets/templates/assets/system_user_list.html:27
#: perms/templates/perms/asset_permission_user.html:55 users/forms.py:13
#: users/models/authentication.py:45 users/models/user.py:39
#: users/forms.py:22 users/models/authentication.py:45 users/models/user.py:39
#: users/templates/users/_select_user_modal.html:14
#: users/templates/users/login.html:56
#: users/templates/users/login_log_list.html:49
@ -169,9 +169,11 @@ msgid "Password or private key passphrase"
msgstr "密码或密钥密码"
#: assets/forms/user.py:25 assets/models/base.py:22 common/forms.py:113
#: users/forms.py:15 users/forms.py:24 users/templates/users/login.html:59
#: users/forms.py:15 users/forms.py:24 users/forms.py:36
#: users/templates/users/login.html:59
#: users/templates/users/reset_password.html:52
#: users/templates/users/user_create.html:11
#: users/templates/users/user_password_authentication.html:13
#: users/templates/users/user_password_update.html:40
#: users/templates/users/user_profile_update.html:40
#: users/templates/users/user_pubkey_update.html:40
@ -310,7 +312,7 @@ msgstr "标签管理"
#: assets/templates/assets/system_user_detail.html:96
#: ops/templates/ops/adhoc_detail.html:86 perms/models.py:28 perms/models.py:72
#: perms/templates/perms/asset_permission_detail.html:98
#: users/models/user.py:55 users/templates/users/user_detail.html:99
#: users/models/user.py:55 users/templates/users/user_detail.html:107
msgid "Created by"
msgstr "创建者"
@ -341,10 +343,10 @@ msgstr "创建日期"
#: ops/models/adhoc.py:42 perms/models.py:30 perms/models.py:74
#: perms/templates/perms/asset_permission_detail.html:102 terminal/models.py:26
#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15
#: users/models/user.py:52 users/templates/users/user_detail.html:111
#: users/models/user.py:52 users/templates/users/user_detail.html:119
#: users/templates/users/user_group_detail.html:67
#: users/templates/users/user_group_list.html:14
#: users/templates/users/user_profile.html:114
#: users/templates/users/user_profile.html:122
msgid "Comment"
msgstr "备注"
@ -390,7 +392,7 @@ msgid "Default"
msgstr "默认"
#: assets/models/cluster.py:36 assets/models/label.py:13
#: users/models/user.py:285
#: users/models/user.py:299
msgid "System"
msgstr "系统"
@ -428,10 +430,10 @@ msgstr "默认资产组"
#: terminal/templates/terminal/command_list.html:32
#: terminal/templates/terminal/command_list.html:72
#: terminal/templates/terminal/session_list.html:33
#: terminal/templates/terminal/session_list.html:71 users/forms.py:219
#: users/models/user.py:30 users/models/user.py:273
#: terminal/templates/terminal/session_list.html:71 users/forms.py:231
#: users/models/user.py:30 users/models/user.py:287
#: users/templates/users/user_group_detail.html:78
#: users/templates/users/user_group_list.html:13 users/views/user.py:335
#: users/templates/users/user_group_list.html:13 users/views/user.py:339
msgid "User"
msgstr "用户"
@ -536,34 +538,6 @@ msgstr ""
msgid "推送系统用户到入资产: {}"
msgstr ""
#: assets/templates/assets/_admin_user_setting_modal.html:4
#: users/templates/users/reset_password.html:57
#: users/templates/users/user_profile.html:20
msgid "Setting"
msgstr "设置"
#: assets/templates/assets/_admin_user_setting_modal.html:9
#: assets/templates/assets/_asset_import_modal.html:9
#: users/templates/users/_user_import_modal.html:10
msgid "Template"
msgstr "模板"
#: assets/templates/assets/_admin_user_setting_modal.html:10
#: assets/templates/assets/_asset_import_modal.html:10
#: users/templates/users/_user_import_modal.html:11
msgid "Download"
msgstr "下载"
#: assets/templates/assets/_admin_user_setting_modal.html:13
#: assets/templates/assets/_asset_import_modal.html:13
msgid "Asset csv file"
msgstr "资产csv文件"
#: assets/templates/assets/_admin_user_setting_modal.html:16
#: assets/templates/assets/_asset_import_modal.html:16
msgid "If set id, will use this id update asset existed"
msgstr "如果设置了id则会使用该行信息更新该id的资产"
#: assets/templates/assets/_asset_group_bulk_update_modal.html:5
msgid "Update asset group"
msgstr "更新用户组"
@ -594,6 +568,24 @@ msgstr "二次验证"
msgid "Import asset"
msgstr "导入资产"
#: assets/templates/assets/_asset_import_modal.html:9
#: users/templates/users/_user_import_modal.html:10
msgid "Template"
msgstr "模板"
#: assets/templates/assets/_asset_import_modal.html:10
#: users/templates/users/_user_import_modal.html:11
msgid "Download"
msgstr "下载"
#: assets/templates/assets/_asset_import_modal.html:13
msgid "Asset csv file"
msgstr "资产csv文件"
#: assets/templates/assets/_asset_import_modal.html:16
msgid "If set id, will use this id update asset existed"
msgstr "如果设置了id则会使用该行信息更新该id的资产"
#: assets/templates/assets/_asset_list_modal.html:7 assets/views/asset.py:50
#: templates/_nav.html:23
msgid "Asset list"
@ -637,7 +629,7 @@ msgstr "其它"
#: assets/templates/assets/asset_update.html:70
#: assets/templates/assets/domain_create_update.html:16
#: assets/templates/assets/gateway_create_update.html:58
#: assets/templates/assets/label_create_update.html:16
#: assets/templates/assets/label_create_update.html:18
#: common/templates/common/basic_setting.html:58
#: common/templates/common/email_setting.html:59
#: common/templates/common/ldap_setting.html:59
@ -647,7 +639,7 @@ msgstr "其它"
#: users/templates/users/_user.html:43
#: users/templates/users/user_bulk_update.html:23
#: users/templates/users/user_password_update.html:58
#: users/templates/users/user_profile.html:151
#: users/templates/users/user_profile.html:180
#: users/templates/users/user_profile_update.html:63
#: users/templates/users/user_pubkey_update.html:70
#: users/templates/users/user_pubkey_update.html:76
@ -662,7 +654,7 @@ msgstr "重置"
#: assets/templates/assets/asset_update.html:71
#: assets/templates/assets/domain_create_update.html:17
#: assets/templates/assets/gateway_create_update.html:59
#: assets/templates/assets/label_create_update.html:17
#: assets/templates/assets/label_create_update.html:19
#: common/templates/common/basic_setting.html:59
#: common/templates/common/email_setting.html:60
#: common/templates/common/ldap_setting.html:60
@ -740,7 +732,7 @@ msgstr "测试"
#: assets/templates/assets/asset_list.html:170
#: assets/templates/assets/domain_detail.html:24
#: assets/templates/assets/domain_detail.html:103
#: assets/templates/assets/domain_gateway_list.html:90
#: assets/templates/assets/domain_gateway_list.html:85
#: assets/templates/assets/domain_list.html:42
#: assets/templates/assets/label_list.html:38
#: assets/templates/assets/system_user_detail.html:26
@ -753,8 +745,8 @@ msgstr "测试"
#: users/templates/users/user_group_detail.html:28
#: users/templates/users/user_group_list.html:43
#: users/templates/users/user_list.html:76
#: users/templates/users/user_profile.html:135
#: users/templates/users/user_profile.html:143
#: users/templates/users/user_profile.html:172
msgid "Update"
msgstr "更新"
@ -764,7 +756,7 @@ msgstr "更新"
#: assets/templates/assets/asset_list.html:171
#: assets/templates/assets/domain_detail.html:28
#: assets/templates/assets/domain_detail.html:104
#: assets/templates/assets/domain_gateway_list.html:91
#: assets/templates/assets/domain_gateway_list.html:86
#: assets/templates/assets/domain_list.html:43
#: assets/templates/assets/label_list.html:39
#: assets/templates/assets/system_user_detail.html:30
@ -796,13 +788,13 @@ msgstr "选择节点"
#: assets/templates/assets/system_user_detail.html:183
#: assets/templates/assets/system_user_list.html:138 templates/_modal.html:22
#: terminal/templates/terminal/session_detail.html:108
#: users/templates/users/user_detail.html:339
#: users/templates/users/user_detail.html:364
#: users/templates/users/user_detail.html:387
#: users/templates/users/user_detail.html:357
#: users/templates/users/user_detail.html:382
#: users/templates/users/user_detail.html:405
#: users/templates/users/user_group_create_update.html:32
#: users/templates/users/user_group_list.html:86
#: users/templates/users/user_list.html:196
#: users/templates/users/user_profile.html:185
#: users/templates/users/user_profile.html:214
msgid "Confirm"
msgstr "确认"
@ -852,15 +844,15 @@ msgid "Disk"
msgstr "硬盘"
#: assets/templates/assets/asset_detail.html:121
#: users/templates/users/user_detail.html:103
#: users/templates/users/user_profile.html:88
#: users/templates/users/user_detail.html:111
#: users/templates/users/user_profile.html:96
msgid "Date joined"
msgstr "创建日期"
#: assets/templates/assets/asset_detail.html:137
#: terminal/templates/terminal/session_detail.html:81
#: users/templates/users/user_detail.html:122
#: users/templates/users/user_profile.html:126
#: users/templates/users/user_detail.html:130
#: users/templates/users/user_profile.html:134
msgid "Quick modify"
msgstr "快速修改"
@ -873,7 +865,7 @@ msgstr "快速修改"
#: perms/templates/perms/asset_permission_list.html:59
#: terminal/templates/terminal/terminal_list.html:34
#: users/templates/users/_select_user_modal.html:18
#: users/templates/users/user_detail.html:128
#: users/templates/users/user_detail.html:136
#: users/templates/users/user_granted_asset.html:46
#: users/templates/users/user_group_granted_asset.html:46
#: users/templates/users/user_list.html:27
@ -890,7 +882,8 @@ msgid "Refresh"
msgstr "刷新"
#: assets/templates/assets/asset_detail.html:300
#: users/templates/users/user_detail.html:273
#: users/templates/users/user_detail.html:282
#: users/templates/users/user_detail.html:304
msgid "Update successfully!"
msgstr "更新成功"
@ -978,8 +971,8 @@ msgstr "存在资产,不能删除"
#: assets/templates/assets/asset_list.html:595
#: assets/templates/assets/system_user_list.html:133
#: users/templates/users/user_detail.html:334
#: users/templates/users/user_detail.html:359
#: users/templates/users/user_detail.html:352
#: users/templates/users/user_detail.html:377
#: users/templates/users/user_group_list.html:81
#: users/templates/users/user_list.html:191
msgid "Are you sure?"
@ -1032,7 +1025,7 @@ msgstr "网关列表"
msgid "Create gateway"
msgstr "创建网关"
#: assets/templates/assets/domain_gateway_list.html:92
#: assets/templates/assets/domain_gateway_list.html:87
#: common/templates/common/email_setting.html:58
#: common/templates/common/ldap_setting.html:58
msgid "Test connection"
@ -1242,14 +1235,18 @@ msgstr "<b>%(name)s</b> 创建成功"
msgid "<b>%(name)s</b> was updated successfully"
msgstr "<b>%(name)s</b> 更新成功"
#: common/fields.py:26
#: common/fields.py:30
msgid "Not a valid json"
msgstr "不是合法json"
#: common/fields.py:28
#: common/fields.py:32
msgid "Not a string type"
msgstr "不是字符类型"
#: common/fields.py:69
msgid "Encrypt field using Secret Key"
msgstr ""
#: common/forms.py:70
msgid "Current SITE URL"
msgstr "当前站点URL"
@ -1389,7 +1386,7 @@ msgstr ""
msgid "discard time"
msgstr ""
#: common/models.py:29
#: common/models.py:29 users/templates/users/user_detail.html:96
msgid "Enabled"
msgstr "启用"
@ -1707,8 +1704,8 @@ msgstr "任务列表"
msgid "Task run history"
msgstr "执行历史"
#: perms/forms.py:18 users/forms.py:176 users/forms.py:181 users/forms.py:193
#: users/forms.py:223
#: perms/forms.py:18 users/forms.py:188 users/forms.py:193 users/forms.py:205
#: users/forms.py:235
msgid "Select users"
msgstr "选择用户"
@ -1717,7 +1714,7 @@ msgstr "选择用户"
#: perms/templates/perms/asset_permission_list.html:136 templates/_nav.html:14
#: users/models/group.py:25 users/models/user.py:42
#: users/templates/users/_select_user_modal.html:16
#: users/templates/users/user_detail.html:179
#: users/templates/users/user_detail.html:188
#: users/templates/users/user_list.html:26
msgid "User group"
msgstr "用户组"
@ -1732,8 +1729,8 @@ msgstr ""
#: perms/models.py:27 perms/models.py:71
#: perms/templates/perms/asset_permission_detail.html:90
#: users/models/user.py:54 users/templates/users/user_detail.html:95
#: users/templates/users/user_profile.html:96
#: users/models/user.py:54 users/templates/users/user_detail.html:103
#: users/templates/users/user_profile.html:104
msgid "Date expired"
msgstr "失效日期"
@ -1770,7 +1767,7 @@ msgid "Add node to this permission"
msgstr "添加节点"
#: perms/templates/perms/asset_permission_asset.html:125
#: users/templates/users/user_detail.html:196
#: users/templates/users/user_detail.html:205
msgid "Join"
msgstr "加入"
@ -1856,13 +1853,13 @@ msgstr "商业支持"
msgid "Docs"
msgstr "文档"
#: templates/_header_bar.html:37 templates/_nav_user.html:9 users/forms.py:93
#: templates/_header_bar.html:37 templates/_nav_user.html:9 users/forms.py:105
#: users/templates/users/_user.html:36
#: users/templates/users/user_password_update.html:37
#: 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:318
#: users/templates/users/user_pubkey_update.html:37 users/views/user.py:322
msgid "Profile"
msgstr "个人信息"
@ -1919,13 +1916,13 @@ msgstr "关闭"
#: templates/_nav.html:10 users/views/group.py:28 users/views/group.py:44
#: users/views/group.py:62 users/views/group.py:79 users/views/group.py:95
#: users/views/login.py:205 users/views/login.py:254 users/views/user.py:60
#: users/views/user.py:75 users/views/user.py:95 users/views/user.py:151
#: users/views/user.py:306 users/views/user.py:353 users/views/user.py:375
#: users/views/login.py:240 users/views/login.py:289 users/views/user.py:64
#: users/views/user.py:79 users/views/user.py:99 users/views/user.py:155
#: users/views/user.py:310 users/views/user.py:357 users/views/user.py:379
msgid "Users"
msgstr "用户管理"
#: templates/_nav.html:13 users/views/user.py:61
#: templates/_nav.html:13 users/views/user.py:65
msgid "User list"
msgstr "用户列表"
@ -2231,7 +2228,11 @@ msgstr ""
msgid "Invalid token or cache refreshed."
msgstr ""
#: users/forms.py:27 users/models/user.py:43
#: users/forms.py:30
msgid "Otp_code"
msgstr ""
#: users/forms.py:39 users/models/user.py:43
#: users/templates/users/_select_user_modal.html:15
#: users/templates/users/user_detail.html:87
#: users/templates/users/user_list.html:25
@ -2239,57 +2240,57 @@ msgstr ""
msgid "Role"
msgstr "角色"
#: users/forms.py:29 users/forms.py:139
#: users/forms.py:41 users/forms.py:151
msgid "ssh public key"
msgstr "ssh公钥"
#: users/forms.py:30 users/forms.py:140
#: users/forms.py:42 users/forms.py:152
msgid "ssh-rsa AAAA..."
msgstr ""
#: users/forms.py:31
#: users/forms.py:43
msgid "Paste user id_rsa.pub here."
msgstr "复制用户公钥到这里"
#: users/forms.py:49 users/templates/users/user_detail.html:187
#: users/forms.py:61 users/templates/users/user_detail.html:196
msgid "Join user groups"
msgstr "添加到用户组"
#: users/forms.py:59 users/forms.py:154
#: users/forms.py:71 users/forms.py:166
msgid "Public key should not be the same as your old one."
msgstr "不能和原来的密钥相同"
#: users/forms.py:63 users/forms.py:158 users/serializers.py:42
#: users/forms.py:75 users/forms.py:170 users/serializers.py:45
msgid "Not a valid ssh public key"
msgstr "ssh密钥不合法"
#: users/forms.py:99
#: users/forms.py:111
msgid "Old password"
msgstr "原来密码"
#: users/forms.py:104
#: users/forms.py:116
msgid "New password"
msgstr "新密码"
#: users/forms.py:109
#: users/forms.py:121
msgid "Confirm password"
msgstr "确认密码"
#: users/forms.py:119
#: users/forms.py:131
msgid "Old password error"
msgstr "原来密码错误"
#: users/forms.py:127
#: users/forms.py:139
msgid "Password does not match"
msgstr "密码不一致"
#: users/forms.py:141
#: users/forms.py:153
msgid "Paste your id_rsa.pub here."
msgstr "复制你的公钥到这里"
#: users/forms.py:169 users/models/user.py:51
#: users/forms.py:181 users/models/user.py:51
#: users/templates/users/user_password_update.html:43
#: users/templates/users/user_profile.html:71
#: users/templates/users/user_profile.html:79
#: users/templates/users/user_profile_update.html:43
#: users/templates/users/user_pubkey_update.html:43
msgid "Public key"
@ -2319,7 +2320,7 @@ msgstr "Agent"
msgid "Date login"
msgstr "登录日期"
#: users/models/user.py:29 users/models/user.py:281
#: users/models/user.py:29 users/models/user.py:295
msgid "Administrator"
msgstr "管理员"
@ -2327,15 +2328,18 @@ msgstr "管理员"
msgid "Application"
msgstr "应用程序"
#: users/models/user.py:34
#: users/models/user.py:34 users/templates/users/user_profile.html:74
#: users/templates/users/user_profile.html:155
#: users/templates/users/user_profile.html:158
msgid "Disable"
msgstr "禁用"
#: users/models/user.py:35
#: users/models/user.py:35 users/templates/users/user_profile.html:72
#: users/templates/users/user_profile.html:162
msgid "Enable"
msgstr "启用"
#: users/models/user.py:36
#: users/models/user.py:36 users/templates/users/user_profile.html:70
msgid "Force enable"
msgstr "强制启用"
@ -2352,11 +2356,11 @@ msgstr "头像"
msgid "Wechat"
msgstr "微信"
#: users/models/user.py:47
#: users/models/user.py:47 users/templates/users/user_detail.html:91
msgid "Enable OTP"
msgstr "二次验证"
#: users/models/user.py:284
#: users/models/user.py:298
msgid "Administrator is the super user of system"
msgstr "Administrator是初始的超级管理员"
@ -2408,11 +2412,16 @@ msgstr "Step"
#: users/templates/users/first_login.html:57
msgid "Previous"
msgstr ""
msgstr "上一步"
#: users/templates/users/first_login.html:60
#: users/templates/users/login_otp.html:66
#: users/templates/users/user_otp_authentication.html:22
#: users/templates/users/user_otp_enable_bind.html:25
#: users/templates/users/user_otp_enable_install_app.html:22
#: users/templates/users/user_password_authentication.html:21
msgid "Next"
msgstr ""
msgstr "下一步"
#: users/templates/users/first_login_done.html:30
msgid "Welcome to use jumpserver, visit "
@ -2447,8 +2456,22 @@ msgstr "Agent"
msgid "City"
msgstr "城市"
#: users/templates/users/login_otp.html:45
msgid "二次认证"
msgstr ""
#: users/templates/users/login_otp.html:64
#: users/templates/users/user_otp_authentication.html:19
#: users/templates/users/user_otp_enable_bind.html:18
msgid "Six figures"
msgstr "6位数字"
#: users/templates/users/login_otp.html:69
msgid "Can't provide security? Please contact the administrator"
msgstr "如果不能提供OTP码请联系管理员"
#: users/templates/users/reset_password.html:45
#: users/templates/users/user_detail.html:325 users/utils.py:71
#: users/templates/users/user_detail.html:343 users/utils.py:72
msgid "Reset password"
msgstr "重置密码"
@ -2456,8 +2479,13 @@ msgstr "重置密码"
msgid "Password again"
msgstr "再次输入密码"
#: users/templates/users/reset_password.html:57
#: users/templates/users/user_profile.html:20
msgid "Setting"
msgstr "设置"
#: users/templates/users/user_create.html:4
#: users/templates/users/user_list.html:16 users/views/user.py:75
#: users/templates/users/user_list.html:16 users/views/user.py:79
msgid "Create user"
msgstr "创建用户"
@ -2466,7 +2494,7 @@ msgid "Reset link will be generated and sent to the user. "
msgstr "生成重置密码连接,通过邮件发送给用户"
#: users/templates/users/user_detail.html:19
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:152
#: users/templates/users/user_granted_asset.html:18 users/views/user.py:156
msgid "User detail"
msgstr "用户详情"
@ -2477,55 +2505,67 @@ msgstr "用户详情"
msgid "Asset granted"
msgstr "授权的资产"
#: users/templates/users/user_detail.html:107
#: users/templates/users/user_profile.html:92
#: users/templates/users/user_detail.html:94
msgid "Force enabled"
msgstr "强制启用"
#: users/templates/users/user_detail.html:98
msgid "Disabled"
msgstr "禁用"
#: users/templates/users/user_detail.html:115
#: users/templates/users/user_profile.html:100
msgid "Last login"
msgstr "最后登录"
#: users/templates/users/user_detail.html:157
#: users/templates/users/user_detail.html:151
msgid "Force enabled OTP"
msgstr "强制启用OTP"
#: users/templates/users/user_detail.html:166
msgid "Send reset password mail"
msgstr "发送重置密码邮件"
#: users/templates/users/user_detail.html:160
#: users/templates/users/user_detail.html:168
#: users/templates/users/user_detail.html:169
#: users/templates/users/user_detail.html:177
msgid "Send"
msgstr "发送"
#: users/templates/users/user_detail.html:165
#: users/templates/users/user_detail.html:174
msgid "Send reset ssh key mail"
msgstr "发送重置密钥邮件"
#: users/templates/users/user_detail.html:324
#: users/templates/users/user_detail.html:342
msgid "An e-mail has been sent to the user`s mailbox."
msgstr "已发送邮件到用户邮箱"
#: users/templates/users/user_detail.html:335
#: users/templates/users/user_detail.html:353
msgid "This will reset the user password and send a reset mail"
msgstr "将失效用户当前密码,并发送重设密码邮件到用户邮箱"
#: users/templates/users/user_detail.html:349
#: users/templates/users/user_detail.html:367
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:350
#: users/templates/users/user_detail.html:368
msgid "Reset SSH public key"
msgstr "重置SSH密钥"
#: users/templates/users/user_detail.html:360
#: users/templates/users/user_detail.html:378
msgid "This will reset the user public key and send a reset mail"
msgstr "将会失效用户当前密钥,并发送重置邮件到用户邮箱"
#: users/templates/users/user_detail.html:377
#: users/templates/users/user_profile.html:174
#: users/templates/users/user_detail.html:395
#: users/templates/users/user_profile.html:203
msgid "Successfully updated the SSH public key."
msgstr "更新ssh密钥成功"
#: users/templates/users/user_detail.html:378
#: users/templates/users/user_detail.html:382
#: users/templates/users/user_profile.html:175
#: users/templates/users/user_profile.html:180
#: users/templates/users/user_detail.html:396
#: users/templates/users/user_detail.html:400
#: users/templates/users/user_profile.html:204
#: users/templates/users/user_profile.html:209
msgid "User SSH public key update"
msgstr "ssh密钥"
@ -2585,24 +2625,28 @@ msgstr "用户删除失败"
msgid "OTP"
msgstr ""
#: users/templates/users/user_profile.html:100 users/views/user.py:181
#: users/views/user.py:235
#: users/templates/users/user_profile.html:108 users/views/user.py:185
#: users/views/user.py:239
msgid "User groups"
msgstr "用户组"
#: users/templates/users/user_profile.html:132
#: users/templates/users/user_profile.html:140
msgid "Update password"
msgstr "更改密码"
#: users/templates/users/user_profile.html:140
#: users/templates/users/user_profile.html:148
msgid "Update otp"
msgstr "更改OTP设置"
#: users/templates/users/user_profile.html:169
msgid "Update SSH public key"
msgstr "更改SSH密钥"
#: users/templates/users/user_profile.html:148
#: users/templates/users/user_profile.html:177
msgid "Reset public key and download"
msgstr "重置并下载SSH密钥"
#: users/templates/users/user_profile.html:178
#: users/templates/users/user_profile.html:207
msgid "Failed to update SSH public key."
msgstr "更新密钥失败"
@ -2622,15 +2666,15 @@ msgstr "更新密钥"
msgid "Or reset by server"
msgstr "或者重置并下载密钥"
#: users/templates/users/user_update.html:4 users/views/user.py:95
#: users/templates/users/user_update.html:4 users/views/user.py:99
msgid "Update user"
msgstr "更新用户"
#: users/utils.py:35
#: users/utils.py:36
msgid "Create account successfully"
msgstr "创建账户成功"
#: users/utils.py:37
#: users/utils.py:38
#, python-format
msgid ""
"\n"
@ -2671,7 +2715,7 @@ msgstr ""
" </br>\n"
" "
#: users/utils.py:73
#: users/utils.py:74
#, python-format
msgid ""
"\n"
@ -2715,11 +2759,11 @@ msgstr ""
" </br>\n"
" "
#: users/utils.py:104
#: users/utils.py:105
msgid "SSH Key Reset"
msgstr "重置ssh密钥"
#: users/utils.py:106
#: users/utils.py:107
#, python-format
msgid ""
"\n"
@ -2744,15 +2788,15 @@ msgstr ""
" </br>\n"
" "
#: users/utils.py:139
#: users/utils.py:140
msgid "User not exist"
msgstr "用户不存在"
#: users/utils.py:141
#: users/utils.py:142
msgid "Disabled or expired"
msgstr "禁用或失效"
#: users/utils.py:154
#: users/utils.py:155
msgid "Password or SSH public key invalid"
msgstr "密码或密钥不合法"
@ -2768,78 +2812,102 @@ msgstr "更新用户组"
msgid "User group granted asset"
msgstr "用户组授权资产"
#: users/views/login.py:55
#: users/views/login.py:56
msgid "Please enable cookies and try again."
msgstr "设置你的浏览器支持cookie"
#: users/views/login.py:97
#: users/views/login.py:106 users/views/user.py:460 users/views/user.py:485
msgid "Otp code invalid"
msgstr "otp码认证失败"
#: users/views/login.py:132
msgid "Logout success"
msgstr "退出登录成功"
#: users/views/login.py:98
#: users/views/login.py:133
msgid "Logout success, return login page"
msgstr "退出登录成功,返回到登录页面"
#: users/views/login.py:114
#: users/views/login.py:149
msgid "Email address invalid, please input again"
msgstr "邮箱地址错误,重新输入"
#: users/views/login.py:127
#: users/views/login.py:162
msgid "Send reset password message"
msgstr "发送重置密码邮件"
#: users/views/login.py:128
#: users/views/login.py:163
msgid "Send reset password mail success, login your mail box and follow it "
msgstr ""
"发送重置邮件成功, 请登录邮箱查看, 按照提示操作 (如果没收到,请等待3-5分钟)"
#: users/views/login.py:142
#: users/views/login.py:177
msgid "Reset password success"
msgstr "重置密码成功"
#: users/views/login.py:143
#: users/views/login.py:178
msgid "Reset password success, return to login page"
msgstr "重置密码成功,返回到登录页面"
#: users/views/login.py:160 users/views/login.py:173
#: users/views/login.py:195 users/views/login.py:208
msgid "Token invalid or expired"
msgstr "Token错误或失效"
#: users/views/login.py:169
#: users/views/login.py:204
msgid "Password not same"
msgstr "密码不一致"
#: users/views/login.py:205
#: users/views/login.py:240
msgid "First login"
msgstr "首次登陆"
#: users/views/login.py:255
#: users/views/login.py:290
msgid "Login log list"
msgstr "登录日志"
#: users/views/user.py:105
#: users/views/user.py:109
msgid "Bulk update user success"
msgstr "批量更新用户成功"
#: users/views/user.py:210
#: users/views/user.py:214
msgid "Invalid file."
msgstr "文件不合法"
#: users/views/user.py:307
#: users/views/user.py:311
msgid "User granted assets"
msgstr "用户授权资产"
#: users/views/user.py:336
#: users/views/user.py:340
msgid "Profile setting"
msgstr "个人信息设置"
#: users/views/user.py:354
#: users/views/user.py:358
msgid "Password update"
msgstr "密码更新"
#: users/views/user.py:376
#: users/views/user.py:380
msgid "Public key update"
msgstr "密钥更新"
#: users/views/user.py:419
msgid "Password invalid"
msgstr "用户名或密码无效"
#: users/views/user.py:512
msgid "OTP enable success"
msgstr "OTP 绑定成功"
#: users/views/user.py:513
msgid "OTP enable success, return login page"
msgstr "OTP 绑定成功,返回到登录页面"
#: users/views/user.py:515
msgid "OTP disable success"
msgstr "OTP 解绑成功"
#: users/views/user.py:516
msgid "OTP disable success, return login page"
msgstr "OTP 解绑成功,返回登录页面"
#~ msgid "Add asset"
#~ msgstr "添加资产到节点"

View File

@ -2,6 +2,7 @@
import uuid
from django.core.cache import cache
from django.urls import reverse
from rest_framework import generics
from rest_framework.permissions import AllowAny, IsAuthenticated
@ -139,40 +140,75 @@ class UserProfile(APIView):
return Response(self.serializer_class(request.user).data)
class UserOtpAuthApi(APIView):
permission_classes = (AllowAny,)
serializer_class = UserSerializer
def post(self, request):
otp_code = request.data.get('otp_code', '')
seed = request.data.get('seed', '')
user = cache.get(seed, None)
if not user:
return Response({'msg': '请先进行用户名和密码验证'}, status=401)
if not check_otp_code(user.otp_secret_key, otp_code):
return Response({'msg': 'otp认证失败'}, status=401)
token = generate_token(request, user)
self.write_login_log(request, user)
return Response(
{
'token': token,
'user': self.serializer_class(user).data
}
)
@staticmethod
def write_login_log(request, user):
login_ip = request.data.get('remote_addr', None)
login_type = request.data.get('login_type', '')
user_agent = request.data.get('HTTP_USER_AGENT', '')
if not login_ip:
login_ip = get_login_ip(request)
write_login_log_async.delay(
user.username, ip=login_ip,
type=login_type, user_agent=user_agent,
)
class UserAuthApi(APIView):
permission_classes = (AllowAny,)
serializer_class = UserSerializer
def post(self, request):
otp_check = request.data.get('otp_check', None)
if otp_check:
# otp验证
return self.check_auth_otp(request)
else:
# password验证
return self.check_auth_password(request)
def check_auth_password(self, request):
user, msg = self.check_user_valid(request)
if user:
token = generate_token(request, user)
if not user.otp_enabled:
self.write_login_log(request, user)
return Response({'token': token, 'user': self.serializer_class(user).data})
else:
if not user:
return Response({'msg': msg}, status=401)
def check_auth_otp(self, request):
otp_code = request.data.get('otp_code', '')
user, msg = self.check_user_valid(request)
if user:
if not user.otp_enabled:
token = generate_token(request, user)
if check_otp_code(user.otp_secret_key, otp_code):
self.write_login_log(request, user)
return Response({'token': token, 'user': self.serializer_class(user).data})
return Response({'msg': msg}, status=401)
self.write_login_log(request, user)
return Response(
{
'token': token,
'user': self.serializer_class(user).data
}
)
seed = uuid.uuid4().hex
cache.set(seed, user, 300)
return Response(
{
'code': 101,
'msg': '请携带seed值,进行OTP二次认证',
'otp_url': reverse('api-users:user-otp-auth'),
'seed': seed,
'user': self.serializer_class(user).data
}, status=300)
@staticmethod
def check_user_valid(request):

View File

@ -232,7 +232,7 @@ class User(AbstractUser):
def disable_otp(self):
self.otp_level = 0
self.otp_secret_key = ''
self.otp_secret_key = None
def to_json(self):
return OrderedDict({

View File

@ -21,7 +21,7 @@ class UserSerializer(BulkSerializerMixin, serializers.ModelSerializer):
list_serializer_class = BulkListSerializer
exclude = [
'first_name', 'last_name', 'password', '_private_key',
'_public_key', 'otp_secret_key', 'user_permissions'
'_public_key', '_otp_secret_key', 'user_permissions'
]
def get_field_names(self, declared_fields, info):

View File

@ -25,7 +25,7 @@
<div>
<a href="{% url 'index' %}">首页</a>
<b></b>
<a href="#">帮助中心</a>
<a href="http://docs.jumpserver.org/zh/docs/">文档</a>
<b></b>
<a href="https://www.github.com/jumpserver/">GitHub</a>
</div>

View File

@ -66,7 +66,7 @@
<button type="submit" class="btn btn-primary block full-width m-b">{% trans 'Next' %}</button>
<a href="#">
<small>{% trans "Can't provide security? Please contact the administrator" %}</small>
<small>{% trans "Can't provide otp code? Please contact the administrator" %}</small>
</a>
</form>

View File

@ -7,10 +7,8 @@
<div class="verify">
<p style="margin:20px auto;"><strong style="color: #000000">使用手机 Google Authenticator 应用扫描以下二维码获取6位验证码</strong></p>
<div id="qr_code"></div>
<form class="" role="form" method="post" action="">
{% csrf_token %}
@ -18,12 +16,13 @@
<input type="text" class="" name="otp_code" placeholder="{% trans 'Six figures' %}" required="">
</div>
<button type="submit" class="next">{% trans 'Next' %}</button>
{% if 'otp_code' in form.errors %}
<p style="color: #ed5565">{{ form.otp_code.errors.as_text }}</p>
{% endif %}
<button type="submit" class="next">{% trans 'Next' %}</button>
</form>
</div>

View File

@ -5,6 +5,7 @@
{% block content %}
<form class="" role="form" method="post" action="">
{% csrf_token %}
<div class="form-input">
<input type="text" class="" name="{{ form.username.html_name }}" value="{{ form.username.value }}" readonly="readonly" required="">
</div>
@ -13,13 +14,12 @@
<input type="password" class="" name="{{ form.password.html_name }}" placeholder="{% trans 'Password' %}" required="">
</div>
<button type="submit" class="next">{% trans 'Next' %}</button>
{% if 'password' in form.errors %}
<p class="red-fonts">{{ form.password.errors.as_text }}</p>
{% endif %}
<button type="submit" class="next">{% trans 'Next' %}</button>
</form>
{% endblock %}

View File

@ -152,8 +152,7 @@
href="
{% if request.user.otp_enabled and request.user.otp_secret_key %}
{% if request.user.otp_force_enabled %}
javascript:void(0)
"><span style="color:#ed5565">{% trans 'Disable' %}</span>
" disabled >{% trans 'Disable' %}
{% else %}
{% url 'users:user-otp-disable-authentication' %}
">{% trans 'Disable' %}

View File

@ -20,6 +20,7 @@ urlpatterns = [
url(r'^v1/connection-token/$', api.UserConnectionTokenApi.as_view(), name='connection-token'),
url(r'^v1/profile/$', api.UserProfile.as_view(), name='user-profile'),
url(r'^v1/auth/$', api.UserAuthApi.as_view(), name='user-auth'),
url(r'^v1/otp/auth/$', api.UserOtpAuthApi.as_view(), name='user-otp-auth'),
url(r'^v1/users/(?P<pk>[0-9a-zA-Z\-]{36})/password/$',
api.ChangeUserPasswordApi.as_view(), name='change-user-password'),
url(r'^v1/users/(?P<pk>[0-9a-zA-Z\-]{36})/password/reset/$',

View File

@ -224,16 +224,14 @@ def get_ip_city(ip, timeout=10):
return city
def get_user(request):
if is_login(request):
user = request.user
else:
user = cache.get(request.session.session_key)
def get_tmp_user_from_session(request):
user_id = request.session.get('tmp_user_id')
user = get_object_or_none(User, pk=user_id)
return user
def is_login(request):
return isinstance(request.user, User)
def set_tmp_user_to_session(request, user):
request.session['tmp_user_id'] = str(user.id)
def redirect_user_first_login_or_index(request, redirect_field_name):
@ -244,9 +242,15 @@ def redirect_user_first_login_or_index(request, redirect_field_name):
request.GET.get(redirect_field_name, reverse('index')))
def generate_otp_uri(user, issuer="Jumpserver"):
otp_secret_key = base64.b32encode(os.urandom(10)).decode('utf-8')
cache.set('otp_secret_key', otp_secret_key, 300)
def generate_otp_uri(request, issuer="Jumpserver"):
if request.user.is_authenticated:
user = request.user
else:
user = get_tmp_user_from_session(request)
otp_secret_key = cache.get(request.session.session_key+'otp_key', '')
if not otp_secret_key:
otp_secret_key = base64.b32encode(os.urandom(10)).decode('utf-8')
cache.set(request.session.session_key+'otp_key', otp_secret_key, 600)
totp = pyotp.TOTP(otp_secret_key)
return totp.provisioning_uri(name=user.username, issuer_name=issuer)

View File

@ -19,12 +19,12 @@ from django.views.generic.base import TemplateView
from django.views.generic.edit import FormView
from formtools.wizard.views import SessionWizardView
from django.conf import settings
from django.core.cache import cache
from common.utils import get_object_or_none
from common.mixins import DatetimeSearchMixin, AdminUserRequiredMixin
from ..models import User, LoginLog
from ..utils import send_reset_password_mail, check_otp_code , get_login_ip, redirect_user_first_login_or_index
from ..utils import send_reset_password_mail, check_otp_code, get_login_ip, redirect_user_first_login_or_index, \
get_tmp_user_from_session, set_tmp_user_to_session
from ..tasks import write_login_log_async
from .. import forms
@ -54,11 +54,12 @@ class UserLoginView(FormView):
def form_valid(self, form):
if not self.request.session.test_cookie_worked():
return HttpResponse(_("Please enable cookies and try again."))
cache.set(self.request.session.session_key, form.get_user(), 600)
set_tmp_user_to_session(self.request, form.get_user())
return redirect(self.get_success_url())
def get_success_url(self):
user = cache.get(self.request.session.session_key)
user = get_tmp_user_from_session(self.request)
if user.otp_enabled and user.otp_secret_key:
# 1,2 & T
@ -94,7 +95,7 @@ class UserLoginOtpView(FormView):
redirect_field_name = 'next'
def form_valid(self, form):
user = cache.get(self.request.session.session_key)
user = get_tmp_user_from_session(self.request)
otp_code = form.cleaned_data.get('otp_code')
otp_secret_key = user.otp_secret_key

View File

@ -35,7 +35,7 @@ from common.mixins import JSONResponseMixin
from common.utils import get_logger, get_object_or_none, is_uuid, ssh_key_gen
from .. import forms
from ..models import User, UserGroup
from ..utils import AdminUserRequiredMixin, generate_otp_uri, check_otp_code, get_user, is_login
from ..utils import AdminUserRequiredMixin, generate_otp_uri, check_otp_code, get_tmp_user_from_session
from ..signals import post_user_create
from ..tasks import write_login_log_async
@ -400,20 +400,31 @@ class UserOtpEnableAuthenticationView(FormView):
form_class = forms.UserCheckPasswordForm
def get_form(self, form_class=None):
if self.request.user.is_authenticated:
user = self.request.user
else:
user = get_tmp_user_from_session(self.request)
form = super().get_form(form_class=form_class)
form['username'].initial = get_user(self.request).username
form['username'].initial = user.username
return form
def get_context_data(self, **kwargs):
if self.request.user.is_authenticated:
user = self.request.user
else:
user = get_tmp_user_from_session(self.request)
context = {
'user': get_user(self.request)
'user': user
}
kwargs.update(context)
return super().get_context_data(**kwargs)
def form_valid(self, form):
if self.request.user.is_authenticated:
user = self.request.user
else:
user = get_tmp_user_from_session(self.request)
password = form.cleaned_data.get('password')
user = get_user(self.request)
user = authenticate(username=user.username, password=password)
if not user:
form.add_error("password", _("Password invalid"))
@ -428,8 +439,12 @@ class UserOtpEnableInstallAppView(TemplateView):
template_name = 'users/user_otp_enable_install_app.html'
def get_context_data(self, **kwargs):
if self.request.user.is_authenticated:
user = self.request.user
else:
user = get_tmp_user_from_session(self.request)
context = {
'user': get_user(self.request)
'user': user
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@ -441,16 +456,20 @@ class UserOtpEnableBindView(TemplateView, FormView):
success_url = reverse_lazy('users:user-otp-settings-success')
def get_context_data(self, **kwargs):
if self.request.user.is_authenticated:
user = self.request.user
else:
user = get_tmp_user_from_session(self.request)
context = {
'otp_uri': generate_otp_uri(user=get_user(self.request)),
'user': get_user(self.request)
'otp_uri': generate_otp_uri(self.request),
'user': user
}
kwargs.update(context)
return super().get_context_data(**kwargs)
def form_valid(self, form):
otp_code = form.cleaned_data.get('otp_code')
otp_secret_key = cache.get('otp_secret_key')
otp_secret_key = cache.get(self.request.session.session_key+'otp_key', '')
if check_otp_code(otp_secret_key, otp_code):
self.save_otp(otp_secret_key)
@ -461,7 +480,10 @@ class UserOtpEnableBindView(TemplateView, FormView):
return self.form_invalid(form)
def save_otp(self, otp_secret_key):
user = get_user(self.request)
if self.request.user.is_authenticated:
user = self.request.user
else:
user = get_tmp_user_from_session(self.request)
user.enable_otp()
user.otp_secret_key = otp_secret_key
user.save()
@ -489,11 +511,8 @@ class UserOtpDisableAuthenticationView(FormView):
class UserOtpSettingsSuccessView(TemplateView):
template_name = 'flash_message_standalone.html'
def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs)
if is_login(request):
auth_logout(request)
return response
# def get(self, request, *args, **kwargs):
# return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
title, describe = self.get_title_describe()
@ -508,7 +527,11 @@ class UserOtpSettingsSuccessView(TemplateView):
return super().get_context_data(**kwargs)
def get_title_describe(self):
user = get_user(self.request)
if self.request.user.is_authenticated:
user = self.request.user
auth_logout(self.request)
else:
user = get_tmp_user_from_session(self.request)
title = _('OTP enable success')
describe = _('OTP enable success, return login page')
if not user.otp_enabled:

View File

@ -54,6 +54,7 @@ pyasn1==0.4.2
pycparser==2.18
pycrypto==2.6.1
pyldap==2.4.45
pyotp==2.2.6
PyNaCl==1.2.1
python-dateutil==2.6.1
python-gssapi==0.6.4