From 1db8db69c6b71898236f97708ac2307e857d459f Mon Sep 17 00:00:00 2001 From: Apex Liu Date: Wed, 8 Nov 2017 18:54:22 +0800 Subject: [PATCH] temp. --- .../www/teleport/static/js/asset/host-list.js | 83 +---------------- .../www/teleport/webroot/app/base/configs.py | 2 +- .../www/teleport/webroot/app/base/session.py | 4 +- server/www/teleport/webroot/app/const.py | 7 -- .../teleport/webroot/app/controller/auth.py | 92 +++++++++++-------- server/www/teleport/webroot/app/model/user.py | 40 ++++++-- 6 files changed, 89 insertions(+), 139 deletions(-) diff --git a/server/www/teleport/static/js/asset/host-list.js b/server/www/teleport/static/js/asset/host-list.js index 4a9ce98..96729fe 100644 --- a/server/www/teleport/static/js/asset/host-list.js +++ b/server/www/teleport/static/js/asset/host-list.js @@ -829,6 +829,7 @@ $app.create_dlg_edit_host = function () { dlg.dom.edit_router_port.val('' + dlg.field_router_port); } } else { + dlg.field_router_ip = ''; dlg.field_router_port = 0; } @@ -878,88 +879,6 @@ $app.create_dlg_edit_host = function () { return dlg; }; -$app.create_dlg_host_info = function () { - var dlg = {}; - dlg.dom_id = 'dlg-user-info'; - dlg.row_id = -1; - dlg.need_edit = false; - - dlg.dom = { - dialog: $('#' + dlg.dom_id), - dlg_title: $('#' + dlg.dom_id + ' [data-field="dlg-title"]'), - info: $('#' + dlg.dom_id + ' [data-field="user-info"]'), - btn_edit: $('#' + dlg.dom_id + ' [data-field="btn-edit"]') - }; - - dlg.init = function (cb_stack) { - dlg.dom.dialog.on('hidden.bs.modal', function () { - if (!dlg.need_edit) - return; - $app.dlg_edit_user.show_edit(dlg.row_id); - }); - - dlg.dom.btn_edit.click(function () { - dlg.need_edit = true; - dlg.dom.dialog.modal('hide'); - }); - - cb_stack.exec(); - }; - - dlg.show = function (row_id) { - dlg.row_id = row_id; - dlg.need_edit = false; - - var _row_data = $app.table_host.get_row(dlg.row_id); - - // 表格加载时,是不会读取用户的 desc 字段的,因此可以判断此用户是否已经读取过详细信息了 - if (_.isUndefined(_row_data.desc)) { - // 尚未读取,则向服务器要求获取此用户账号的完整信息 - $tp.ajax_post_json('/user/get-user/' + _row_data.id, {}, - function (ret) { - if (ret.code === TPE_OK) { - $app.table_host.update_row(dlg.row_id, ret.data); - dlg.show_info(ret.data); - } else { - $tp.notify_error('无法获取用户详细信息:' + tp_error_msg(ret.code, ret.message)); - } - }, - function () { - $tp.notify_error('网络故障,无法获取用户详细信息!'); - } - ); - } else { - dlg.show_info(_row_data); - } - }; - - dlg.show_info = function (user) { - // 更新对话框中显示的信息 - dlg.dom.dlg_title.html(' ' + user.surname); - - var info = []; - - var not_set = '未设置'; - var mobile = (user.mobile.length === 0) ? not_set : user.mobile; - var qq = (user.qq.length === 0) ? not_set : user.qq; - var wechat = (user.wechat.length === 0) ? not_set : user.wechat; - var desc = (user.desc.length === 0) ? not_set : user.desc; - info.push('账号:' + user.username + ''); - info.push('姓名:' + user.surname + ''); - info.push('邮箱:' + user.email + ''); - info.push('电话:' + mobile + ''); - info.push('QQ:' + qq + ''); - info.push('微信:' + wechat + ''); - info.push('描述:
' + desc + '
'); - - dlg.dom.info.html($(info.join(''))); - - dlg.dom.dialog.modal(); - }; - - return dlg; -}; - $app.create_dlg_accounts = function () { var dlg = {}; dlg.dom_id = 'dlg-accounts'; diff --git a/server/www/teleport/webroot/app/base/configs.py b/server/www/teleport/webroot/app/base/configs.py index aab246a..5f3b3e4 100644 --- a/server/www/teleport/webroot/app/base/configs.py +++ b/server/www/teleport/webroot/app/base/configs.py @@ -486,7 +486,7 @@ class AppConfig(BaseAppConfig): self.sys.login = tp_convert_to_attr_dict(_login) if not self.sys.login.is_exists('session_timeout'): - self.sys.login.session_timeout = 30 + self.sys.login.session_timeout = 60 # 1 hour if not self.sys.login.is_exists('retry'): self.sys.login.retry = 0 if not self.sys.login.is_exists('lock_timeout'): diff --git a/server/www/teleport/webroot/app/base/session.py b/server/www/teleport/webroot/app/base/session.py index de66470..e5bc039 100644 --- a/server/www/teleport/webroot/app/base/session.py +++ b/server/www/teleport/webroot/app/base/session.py @@ -4,6 +4,7 @@ import datetime import threading from app.base.logger import log +from app.base.configs import get_cfg class SessionManager(threading.Thread): @@ -62,7 +63,8 @@ class SessionManager(threading.Thread): """ if expire is None: - expire = self.SESSION_EXPIRE + # expire = self.SESSION_EXPIRE + expire = get_cfg().sys.login.session_timeout * 60 if expire < 0: with self._lock: diff --git a/server/www/teleport/webroot/app/const.py b/server/www/teleport/webroot/app/const.py index 2ed30d9..8e67f20 100644 --- a/server/www/teleport/webroot/app/const.py +++ b/server/www/teleport/webroot/app/const.py @@ -9,13 +9,6 @@ TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH = 0x0008 # 用户名+密码+OATH APP_MODE_NORMAL = 1 APP_MODE_MAINTENANCE = 2 -# ========================================================================== -# 用户账号状态 -# ========================================================================== -USER_STATE_NORMAL = 1 # 正常状态 -USER_STATE_LOCKED = 2 # 锁定(例如密码连错n次) -USER_STATE_DISABLED = 3 # 禁用 - # ========================================================================== # 远程主机账号认证方式 # ========================================================================== diff --git a/server/www/teleport/webroot/app/controller/auth.py b/server/www/teleport/webroot/app/controller/auth.py index f095da7..cdb2815 100644 --- a/server/www/teleport/webroot/app/controller/auth.py +++ b/server/www/teleport/webroot/app/controller/auth.py @@ -11,6 +11,7 @@ from app.logic.auth.captcha import tp_captcha_generate_image from app.model import user from app.model import syslog from app.logic.auth.password import tp_password_verify +from app.base.utils import tp_timestamp_utc_now class LoginHandler(TPBaseHandler): @@ -53,68 +54,86 @@ class LoginHandler(TPBaseHandler): class DoLoginHandler(TPBaseJsonHandler): def post(self): + sys_cfg = get_cfg().sys + args = self.get_argument('args', None) - if args is not None: - try: - args = json.loads(args) - except: - return self.write_json(TPE_JSON_FORMAT, '参数错误') + if args is None: + return self.write_json(TPE_PARAM) - try: - login_type = args['type'] - captcha = args['captcha'].strip() - username = args['username'].strip() - password = args['password'] - oath = args['oath'].strip() - remember = args['remember'] - except: - return self.write_json(TPE_PARAM, '参数错误') - else: - return self.write_json(TPE_PARAM, '参数错误') + try: + args = json.loads(args) + except: + return self.write_json(TPE_JSON_FORMAT, '参数错误') - _tmp = {'username': username, 'surname': username} + try: + login_type = args['type'] + captcha = args['captcha'].strip() + username = args['username'].strip().lower() + password = args['password'] + oath = args['oath'].strip() + remember = args['remember'] + except: + return self.write_json(TPE_PARAM) + + if login_type not in [TP_LOGIN_AUTH_USERNAME_PASSWORD, + TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA, + TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH, + TP_LOGIN_AUTH_USERNAME_OATH + ]: + return self.write_json(TPE_PARAM, '未知的认证方式') if login_type == TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA: oath = None code = self.get_session('captcha') if code is None: return self.write_json(TPE_CAPTCHA_EXPIRED, '验证码已失效') - self.del_session('captcha') if code.lower() != captcha.lower(): return self.write_json(TPE_CAPTCHA_MISMATCH, '验证码错误') - elif login_type == TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH: + elif login_type in [TP_LOGIN_AUTH_USERNAME_OATH, TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH]: if len(oath) == 0: return self.write_json(TPE_OATH_MISMATCH, '未提供身份验证器动态验证码') - else: - return self.write_json(TPE_PARAM, '参数错误') self.del_session('captcha') + if len(username) == 0: + return self.write_json(TPE_PARAM, '未提供登录用户名') + err, user_info = user.get_by_username(username) - # if user_info is None: - # return self.write_json(TPE_USER_AUTH) if err != TPE_OK: if err == TPE_NOT_EXISTS: - syslog.sys_log(_tmp, self.request.remote_ip, TPE_NOT_EXISTS, '登录失败,用户`{}`不存在'.format(username)) + syslog.sys_log({'username': username, 'surname': username}, self.request.remote_ip, TPE_NOT_EXISTS, '登录失败,用户`{}`不存在'.format(username)) return self.write_json(err) - if user_info['state'] == USER_STATE_LOCKED: - syslog.sys_log(_tmp, self.request.remote_ip, TPE_USER_LOCKED, '登录失败,用户已被锁定') - return self.write_json(TPE_USER_LOCKED) - elif user_info['state'] == USER_STATE_DISABLED: - syslog.sys_log(_tmp, self.request.remote_ip, TPE_USER_DISABLED, '登录失败,用户已被禁用') + if user_info['state'] == TP_STATE_LOCKED: + # 用户已经被锁定,如果系统配置为一定时间后自动解锁,则更新一下用户信息 + if sys_cfg.login.lock_timeout != 0: + if tp_timestamp_utc_now() - user_info.lock_time > sys_cfg.login.lock_timeout * 60: + user_info.fail_count = 0 + user_info.state = TP_STATE_NORMAL + if user_info['state'] == TP_STATE_LOCKED: + syslog.sys_log(user_info, self.request.remote_ip, TPE_USER_LOCKED, '登录失败,用户已被锁定') + return self.write_json(TPE_USER_LOCKED) + elif user_info['state'] == TP_STATE_DISABLED: + syslog.sys_log(user_info, self.request.remote_ip, TPE_USER_DISABLED, '登录失败,用户已被禁用') return self.write_json(TPE_USER_DISABLED) - elif user_info['state'] != USER_STATE_NORMAL: - syslog.sys_log(_tmp, self.request.remote_ip, TPE_FAILED, '登录失败,系统内部错误') + elif user_info['state'] != TP_STATE_NORMAL: + syslog.sys_log(user_info, self.request.remote_ip, TPE_FAILED, '登录失败,系统内部错误') return self.write_json(TPE_FAILED) - if login_type == TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA: + err_msg = '' + if login_type in [TP_LOGIN_AUTH_USERNAME_PASSWORD, TP_LOGIN_AUTH_USERNAME_PASSWORD_CAPTCHA, TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH]: if not tp_password_verify(password, user_info['password']): - syslog.sys_log(_tmp, self.request.remote_ip, TPE_USER_AUTH, '登录失败,密码错误!') + err, is_locked = user.update_fail_count(self, user_info) + if is_locked: + err_msg = '用户被临时锁定!' + syslog.sys_log(user_info, self.request.remote_ip, TPE_USER_AUTH, '登录失败,密码错误!{}'.format(err_msg)) return self.write_json(TPE_USER_AUTH) - elif login_type == TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH: + elif login_type in [TP_LOGIN_AUTH_USERNAME_OATH, TP_LOGIN_AUTH_USERNAME_PASSWORD_OATH]: if not tp_oath_verify_code(user_info['oath_secret'], oath): - syslog.sys_log(_tmp, self.request.remote_ip, TPE_OATH_MISMATCH, "登录失败,身份验证器动态验证码错误!") + err, is_locked = user.update_fail_count(self, user_info) + if is_locked: + err_msg = '用户被临时锁定!' + syslog.sys_log(user_info, self.request.remote_ip, TPE_OATH_MISMATCH, "登录失败,身份验证器动态验证码错误!{}".format(err_msg)) return self.write_json(TPE_OATH_MISMATCH) self._user = user_info @@ -122,12 +141,9 @@ class DoLoginHandler(TPBaseJsonHandler): del self._user['password'] del self._user['oath_secret'] - print('00000', self._user) - if remember: self.set_session('user', self._user, 12 * 60 * 60) else: - # TODO: 使用系统配置项中的默认会话超时 self.set_session('user', self._user) user.update_login_info(self, user_info['id']) diff --git a/server/www/teleport/webroot/app/model/user.py b/server/www/teleport/webroot/app/model/user.py index b5c13e0..cc4dafb 100644 --- a/server/www/teleport/webroot/app/model/user.py +++ b/server/www/teleport/webroot/app/model/user.py @@ -2,14 +2,12 @@ # import hashlib -from app.const import * -from app.base.logger import log -# from app.base.configs import get_cfg +from app.base.configs import get_cfg from app.base.db import get_db, SQL -from app.model import syslog -# from app.logic.auth.oath import tp_oath_verify_code -# from app.logic.auth.password import tp_password_generate_secret, tp_password_verify +from app.base.logger import log from app.base.utils import tp_timestamp_utc_now +from app.const import * +from app.model import syslog def get_user_info(user_id): @@ -32,7 +30,7 @@ def get_user_info(user_id): def get_by_username(username): s = SQL(get_db()) - s.select_from('user', ['id', 'type', 'auth_type', 'username', 'surname', 'password', 'oath_secret', 'role_id', 'state', 'email', 'create_time', 'last_login', 'last_ip', 'last_chpass', 'mobile', 'qq', 'wechat', 'desc'], alt_name='u') + s.select_from('user', ['id', 'type', 'auth_type', 'username', 'surname', 'password', 'oath_secret', 'role_id', 'state', 'fail_count', 'lock_time', 'email', 'create_time', 'last_login', 'last_ip', 'last_chpass', 'mobile', 'qq', 'wechat', 'desc'], alt_name='u') s.left_join('role', ['name', 'privilege'], join_on='r.id=u.role_id', alt_name='r', out_map={'name': 'role'}) s.where('u.username="{}"'.format(username)) err = s.query() @@ -249,11 +247,10 @@ def set_password(handler, user_id, password): def update_login_info(handler, user_id): - db = get_db() _time_now = tp_timestamp_utc_now() - sql = 'UPDATE `{}user` SET last_login=login_time, last_ip=login_ip, login_time={login_time}, login_ip="{ip}" WHERE id={user_id};' \ + sql = 'UPDATE `{}user` SET fail_count=0, last_login=login_time, last_ip=login_ip, login_time={login_time}, login_ip="{ip}" WHERE id={user_id};' \ ''.format(db.table_prefix, login_time=_time_now, ip=handler.request.remote_ip, user_id=user_id ) @@ -285,6 +282,29 @@ def update_users_state(handler, user_ids, state): return TPE_DATABASE +def update_fail_count(handler, user_info): + db = get_db() + sys_cfg = get_cfg().sys + sql_list = [] + is_locked = False + fail_count = user_info.fail_count + 1 + + sql = 'UPDATE `{}user` SET fail_count={count} WHERE id={uid};' \ + ''.format(db.table_prefix, count=fail_count, uid=user_info.id) + sql_list.append(sql) + + if sys_cfg.login.retry != 0 and fail_count >= sys_cfg.login.retry: + is_locked = True + sql = 'UPDATE `{}user` SET state={state}, lock_time={lock_time} WHERE id={uid};' \ + ''.format(db.table_prefix, state=TP_STATE_LOCKED, lock_time=tp_timestamp_utc_now(), uid=user_info.id) + sql_list.append(sql) + + if db.transaction(sql_list): + return TPE_OK, is_locked + else: + return TPE_DATABASE, is_locked + + def remove_users(handler, users): s = SQL(get_db()) @@ -587,7 +607,7 @@ def get_group_with_member(sql_filter, sql_order, sql_limit): for g in sg.recorder: g['member_count'] = 0 g['members'] = [] - g['_mid'] = [] # 临时使用,构建此组的前5个成员的id + g['_mid'] = [] # 临时使用,构建此组的前5个成员的id # 对于本次要返回的用户组,取其中每一个组内成员的基本信息(id/用户名/真实名称等) groups = [g['id'] for g in sg.recorder]