def get(self): param = { 'mode': 0, # mode=0, unknown mode. 'token': '', 'code': TPE_OK } _token = self.get_argument('token', None) if _token is None: # 如果尚未设置SMTP或者系统限制,不允许发送密码重置邮件 if len(tp_cfg().sys.smtp.server) == 0: param['mode'] = 2 # mode=2, show 'error' page param['code'] = TPE_NETWORK elif not tp_cfg().sys.password.allow_reset: param['mode'] = 2 # mode=2, show 'error' page param['code'] = TPE_PRIVILEGE else: param['mode'] = 1 # mode=1, show 'find-my-password' page. else: err, _ = user.check_reset_token(_token) param['code'] = err param['token'] = _token if err != TPE_OK: param['mode'] = 2 # mode=2, show 'error' page else: param['mode'] = 3 # mode=3, show 'set-new-password' page param['force_strong'] = tp_cfg().sys.password.force_strong self.render('user/reset-password.mako', page_param=json.dumps(param))
def post(self): ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if ret != TPE_OK: return args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: if len(tp_cfg().sys_ldap_password) == 0: return self.write_json(TPE_PARAM, message='LDAP未能正确配置,需要管理员密码') else: _password = tp_cfg().sys_ldap_password _server = tp_cfg().sys.ldap.server _port = tp_cfg().sys.ldap.port _admin = tp_cfg().sys.ldap.admin _base_dn = tp_cfg().sys.ldap.base_dn _filter = tp_cfg().sys.ldap.filter _attr_username = tp_cfg().sys.ldap.attr_username _attr_surname = tp_cfg().sys.ldap.attr_surname _attr_email = tp_cfg().sys.ldap.attr_email except: return self.write_json(TPE_PARAM) try: ldap = Ldap(_server, _port, _base_dn) ret, data, err_msg = ldap.list_users(_admin, _password, _filter, _attr_username, _attr_surname, _attr_email) if ret != TPE_OK: return self.write_json(ret, message=err_msg) exists_users = user.get_users_by_type(TP_USER_TYPE_LDAP) bound_users = [] if exists_users is not None: for u in exists_users: h = hashlib.sha1() h.update(u['ldap_dn'].encode()) bound_users.append(h.hexdigest()) ret_data = [] for u in data: h = hashlib.sha1() h.update(u.encode()) _id = h.hexdigest() if _id in bound_users: continue _user = data[u] _user['id'] = h.hexdigest() ret_data.append(_user) return self.write_json(ret, data=ret_data) except: log.e('') return self.write_json(TPE_PARAM)
def post(self): ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if ret != TPE_OK: return args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: dn_hash_list = args['ldap_users'] if len(tp_cfg().sys_ldap_password) == 0: return self.write_json(TPE_PARAM, message='LDAP未能正确配置,需要管理员密码') else: _password = tp_cfg().sys_ldap_password _server = tp_cfg().sys.ldap.server _port = tp_cfg().sys.ldap.port _admin = tp_cfg().sys.ldap.admin _base_dn = tp_cfg().sys.ldap.base_dn _filter = tp_cfg().sys.ldap.filter _attr_username = tp_cfg().sys.ldap.attr_username _attr_surname = tp_cfg().sys.ldap.attr_surname _attr_email = tp_cfg().sys.ldap.attr_email except: return self.write_json(TPE_PARAM) try: ldap = Ldap(_server, _port, _base_dn) ret, data, err_msg = ldap.list_users(_admin, _password, _filter, _attr_username, _attr_surname, _attr_email) if ret != TPE_OK: return self.write_json(ret, message=err_msg) need_import = [] for u in data: h = hashlib.sha1() h.update(u.encode()) dn_hash = h.hexdigest() for x in dn_hash_list: if x == dn_hash: _user = data[u] _user['dn'] = u need_import.append(_user) break if len(need_import) == 0: return self.write_json(ret, message='没有可以导入的LDAP用户') return self._do_import(need_import) except: log.e('') return self.write_json(TPE_PARAM)
def get(self): param = { 'mode': 0, # mode=0, unknown mode. 'token': '', 'code': TPE_OK } _token = self.get_argument('token', None) if _token is None: # 如果尚未设置SMTP或者系统限制,不允许发送密码重置邮件 if len(tp_cfg().sys.smtp.server) == 0: param['mode'] = 2 # mode=2, show 'error' page param['code'] = TPE_NETWORK elif not tp_cfg().sys.password.allow_reset: param['mode'] = 2 # mode=2, show 'error' page param['code'] = TPE_PRIVILEGE else: param['mode'] = 1 # mode=1, show 'find-my-password' page. else: err, _ = user.check_reset_token(_token) param['code'] = err param['token'] = _token if err != TPE_OK: param['mode'] = 2 # mode=2, show 'error' page else: param['mode'] = 3 # mode=3, show 'set-new-password' page param['force_strong'] = tp_cfg().sys.password.force_strong self.render('user/reset-password.mako', page_param=json.dumps(param))
def delete_log(log_list): try: where = list() for item in log_list: where.append(' `id`={}'.format(item)) db = get_db() sql = 'DELETE FROM `{}log` WHERE{};'.format(db.table_prefix, ' OR'.join(where)) ret = db.exec(sql) if not ret: return False # TODO: 此处应该通过json-rpc接口通知core服务来删除重放文件。 for item in log_list: log_id = int(item) try: record_path = os.path.join(tp_cfg().core.replay_path, 'ssh', '{:06d}'.format(log_id)) if os.path.exists(record_path): shutil.rmtree(record_path) record_path = os.path.join(tp_cfg().core.replay_path, 'rdp', '{:06d}'.format(log_id)) if os.path.exists(record_path): shutil.rmtree(record_path) except Exception: pass return True except: return False
def _register_core(self, param): # 因为core服务启动了(之前可能非正常终止了),做一下数据库中会话状态的修复操作 record.session_fix() if 'rpc' not in param: return self.write_json(TPE_PARAM, 'invalid param.') tp_cfg().common.core_server_rpc = param['rpc'] # 获取core服务的配置信息 req = {'method': 'get_config', 'param': []} _yr = core_service_async_post_http(req) code, ret_data = yield _yr if code != TPE_OK: return self.write_json(code, 'get config from core-service failed.') log.d('update base server config info.\n') tp_cfg().update_core(ret_data) # 将运行时配置发送给核心服务 req = {'method': 'set_config', 'param': {'noop_timeout': tp_cfg().sys.session.noop_timeout}} _yr = core_service_async_post_http(req) code, ret_data = yield _yr if code != TPE_OK: return self.write_json(code, 'set runtime-config to core-service failed.') return self.write_json(TPE_OK)
def post(self): ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if ret != TPE_OK: return args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: cfg = args['ldap'] cfg['port'] = int(cfg['port']) if len(cfg['password']) == 0: if len(tp_cfg().sys_ldap_password) == 0: return self.write_json(TPE_PARAM, message='需要设置LDAP管理员密码') else: cfg['password'] = tp_cfg().sys_ldap_password except: return self.write_json(TPE_PARAM) try: ldap = Ldap(cfg['server'], cfg['port'], cfg['base_dn']) ret, data, err_msg = ldap.get_all_attr(cfg['admin'], cfg['password'], cfg['filter']) if ret != TPE_OK: return self.write_json(ret, message=err_msg) else: return self.write_json(ret, data=data) except: log.e('') return self.write_json(TPE_PARAM)
def delete_log(log_list): try: where = list() for item in log_list: where.append(' `id`={}'.format(item)) db = get_db() sql = 'DELETE FROM `{}log` WHERE{};'.format(db.table_prefix, ' OR'.join(where)) ret = db.exec(sql) if not ret: return False # TODO: 此处应该通过json-rpc接口通知core服务来删除重放文件。 for item in log_list: log_id = int(item) try: record_path = os.path.join(tp_cfg().core.replay_path, 'ssh', '{:06d}'.format(log_id)) if os.path.exists(record_path): shutil.rmtree(record_path) record_path = os.path.join(tp_cfg().core.replay_path, 'rdp', '{:06d}'.format(log_id)) if os.path.exists(record_path): shutil.rmtree(record_path) except Exception: pass return True except: return False
def load_system_config(self): sys_cfg = dict() db_ret = self.query('SELECT `name`, `value` FROM `{}config`;'.format(self._table_prefix)) for item in db_ret: sys_cfg[item[0]] = item[1] if len(sys_cfg) > 0: tp_cfg().update_sys(sys_cfg)
def load_system_config(self): sys_cfg = dict() db_ret = self.query('SELECT `name`, `value` FROM `{}config`;'.format(self._table_prefix)) for item in db_ret: sys_cfg[item[0]] = item[1] if len(sys_cfg) > 0: tp_cfg().update_sys(sys_cfg)
def post(self): ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if ret != TPE_OK: return args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: dn_hash_list = args['ldap_users'] if len(tp_cfg().sys_ldap_password) == 0: return self.write_json(TPE_PARAM, message='LDAP未能正确配置,需要管理员密码') else: _password = tp_cfg().sys_ldap_password _server = tp_cfg().sys.ldap.server _port = tp_cfg().sys.ldap.port _admin = tp_cfg().sys.ldap.admin _base_dn = tp_cfg().sys.ldap.base_dn _filter = tp_cfg().sys.ldap.filter _attr_username = tp_cfg().sys.ldap.attr_username _attr_surname = tp_cfg().sys.ldap.attr_surname _attr_email = tp_cfg().sys.ldap.attr_email except: return self.write_json(TPE_PARAM) try: ldap = Ldap(_server, _port, _base_dn) ret, data, err_msg = ldap.list_users(_admin, _password, _filter, _attr_username, _attr_surname, _attr_email) if ret != TPE_OK: return self.write_json(ret, message=err_msg) need_import = [] for u in data: h = hashlib.sha1() h.update(u.encode()) dn_hash = h.hexdigest() for x in dn_hash_list: if x == dn_hash: _user = data[u] _user['dn'] = u need_import.append(_user) break if len(need_import) == 0: return self.write_json(ret, message='没有可以导入的LDAP用户') return self._do_import(need_import) except: log.e('') return self.write_json(TPE_PARAM)
def post(self): ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if ret != TPE_OK: return args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: if len(tp_cfg().sys_ldap_password) == 0: return self.write_json(TPE_PARAM, message='LDAP未能正确配置,需要管理员密码') else: _password = tp_cfg().sys_ldap_password _server = tp_cfg().sys.ldap.server _port = tp_cfg().sys.ldap.port _admin = tp_cfg().sys.ldap.admin _base_dn = tp_cfg().sys.ldap.base_dn _filter = tp_cfg().sys.ldap.filter _attr_username = tp_cfg().sys.ldap.attr_username _attr_surname = tp_cfg().sys.ldap.attr_surname _attr_email = tp_cfg().sys.ldap.attr_email except: return self.write_json(TPE_PARAM) try: ldap = Ldap(_server, _port, _base_dn) ret, data, err_msg = ldap.list_users(_admin, _password, _filter, _attr_username, _attr_surname, _attr_email) if ret != TPE_OK: return self.write_json(ret, message=err_msg) exits_users = user.get_users_by_type(TP_USER_TYPE_LDAP) bound_users = [] for u in exits_users: h = hashlib.sha1() h.update(u['ldap_dn'].encode()) bound_users.append(h.hexdigest()) ret_data = [] for u in data: h = hashlib.sha1() h.update(u.encode()) _id = h.hexdigest() if _id in bound_users: continue _user = data[u] _user['id'] = h.hexdigest() ret_data.append(_user) return self.write_json(ret, data=ret_data) except: log.e('') return self.write_json(TPE_PARAM)
def tp_captcha_generate_image(h): if h >= 32: captcha_image_t = captcha( width=136, height=36, drawings=[ background(color='#eeeeee'), curve(color='#bbbbbb', width=6, number=12), curve(color=_random_color_line, width=2, number=30), curve(color='#cccccc', width=7, number=13), curve(color='#dddddd', width=8, number=14), text(fonts=[ os.path.join(tp_cfg().res_path, 'fonts', '001.ttf') ], font_sizes=(h-5, h-2, h, h+2), color=_random_color_font, squeeze_factor=1.05, drawings=[ warp(dx_factor=0.03, dy_factor=0.03), rotate(angle=20), offset() ]), smooth(), ]) else: captcha_image_t = captcha( width=int(h*3)+8, height=h, drawings=[ background(color='#eeeeee'), noise(number=40, color='#dddddd', level=3), smooth(), text(fonts=[ os.path.join(tp_cfg().res_path, 'fonts', '001.ttf') ], font_sizes=(h-3, h-2, h-1, h), color=_random_color_font, squeeze_factor=0.95, drawings=[ warp(dx_factor=0.03, dy_factor=0.03), rotate(angle=15), offset() ]), smooth(), ]) chars_t = random.sample(_captcha_chars, 4) image = captcha_image_t(chars_t) out = io.BytesIO() image.save(out, "jpeg", quality=80) return ''.join(chars_t), out.getvalue()
def get(self): from app.base.db import get_db if tp_cfg().app_mode == APP_MODE_MAINTENANCE and get_db().need_create: _user = { 'id': 0, 'username': '******', 'surname': '系统维护-安装', 'role_id': 0, 'role': '', 'privilege': TP_PRIVILEGE_SYS_CONFIG, '_is_login': True } self.set_session('user', _user) self.redirect('/maintenance/install') return if tp_cfg().app_mode == APP_MODE_MAINTENANCE and get_db().need_upgrade: _user = { 'id': 0, 'username': '******', 'surname': '系统维护-升级', 'role_id': 0, 'role': '', 'privilege': TP_PRIVILEGE_SYS_CONFIG, '_is_login': True } self.set_session('user', _user) self.redirect('/maintenance/upgrade') return _user = self.get_current_user() _ref = quote(self.get_argument('ref', '/')) if _user['_is_login']: self.redirect(_ref) return if _user['id'] == 0: username = self.get_cookie('username') if username is None: username = '' else: username = _user['username'] default_auth_type = tp_cfg().sys.login.auth param = { 'ref': _ref, 'username': username, 'default_auth': default_auth_type } self.render('auth/login.mako', page_param=json.dumps(param))
def get(self): ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if ret != TPE_OK: return is_sys_smtp = False if tp_cfg().sys.loaded: smtp = tp_cfg().sys.smtp if len(smtp.server) > 0: is_sys_smtp = True param = {'sys_smtp': is_sys_smtp, 'sys_cfg': tp_cfg().sys} self.render('user/user-list.mako', page_param=json.dumps(param))
def init(self): if not tp_cfg().common.check_host_alive: return True icmp_protocol = socket.getprotobyname('icmp') try: self._socket_ping = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp_protocol) except PermissionError: print('To use PING to check host state, must run as root.') log.e('To use PING to check host state, must run as root.\n') return False # 加载所有主机IP hosts = host.get_all_hosts_for_check_state() for h in hosts: if h['router_ip'] != '': self.add_host(h['router_ip'], HostAlive.METHOD_PING) else: self.add_host(h['ip'], HostAlive.METHOD_PING) self._thread_recv_ping_result = threading.Thread( target=self._thread_func_recv_ping_result) self._thread_recv_ping_result.start() tp_cron().add_job('host_check_alive', self._check_alive, first_interval_seconds=10, interval_seconds=HostAlive.PING_INTERVAL) # for test: # tp_cron().add_job('host_show_alive', self._show_alive, first_interval_seconds=20, interval_seconds=HostAlive.PING_INTERVAL) return True
def stop(self): if not tp_cfg().common.check_host_alive: return self._need_stop = True if self._thread_recv_ping_result is not None: self._thread_recv_ping_result.join()
def add_host(self, host_ip, method=0, param=None, check_now=False): if not tp_cfg().common.check_host_alive: return True if param is None: param = {} # now we support PING only if method != HostAlive.METHOD_PING: log.e('Unknown method for check host state: {}\n'.format(method)) return False with self._lock: if host_ip not in self._states: self._states[host_ip] = { 'last_online': 0, 'last_check': 0, 'method': method, 'param': param } else: self._states[host_ip]['method'] = method self._states[host_ip]['param'] = param if check_now: if method == HostAlive.METHOD_PING: self._ping(host_ip) else: log.w('Warning: check alive method not implement.\n')
def get(self): if self.request.uri == tp_cfg().random_exit_uri: tornado.ioloop.IOLoop.instance().stop() self.write('EXIT') return log.w('catch all, GET: {}\n'.format(self.request.uri)) self.show_error_page(TPE_HTTP_404_NOT_FOUND)
def remove_host(self, host_ip): if not tp_cfg().common.check_host_alive: return with self._lock: if host_ip not in self._states: return del self._states[host_ip]
def get(self): ret = self.check_privilege(TP_PRIVILEGE_OPS_AUZ | TP_PRIVILEGE_AUDIT_AUZ | TP_PRIVILEGE_AUDIT) if ret != TPE_OK: return if not tp_cfg().core.detected: total_size = 0 free_size = 0 else: total_size, free_size = get_free_space_bytes(tp_cfg().core.replay_path) param = { 'total_size': total_size, 'free_size': free_size, } self.render('audit/record.mako', page_param=json.dumps(param))
def get(self): ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if ret != TPE_OK: return is_sys_smtp = False if tp_cfg().sys.loaded: smtp = tp_cfg().sys.smtp if len(smtp.server) > 0: is_sys_smtp = True param = { 'sys_smtp': is_sys_smtp, 'sys_cfg': tp_cfg().sys } self.render('user/user-list.mako', page_param=json.dumps(param))
def stop(self): if self._need_stop: return self._need_stop = True cfg = tp_cfg() try: c = urllib.request.urlopen('http://127.0.0.1:{}{}'.format(cfg.common.port, cfg.random_exit_uri)) c.read() except: log.e('\n')
def get(self): _username = urllib.unquote(self.get_argument('username', None)) if _username is None: return self.redirect('/') param = { 'username': _username, 'force_strong': tp_cfg().sys.password.force_strong } self.render('user/change-expired-password.mako', page_param=json.dumps(param))
def get(self): ret = self.check_privilege(TP_PRIVILEGE_OPS | TP_PRIVILEGE_OPS_AUZ | TP_PRIVILEGE_AUDIT_AUZ | TP_PRIVILEGE_AUDIT) if ret != TPE_OK: return if not tp_cfg().core.detected: total_size = 0 free_size = 0 else: total_size, free_size = get_free_space_bytes( tp_cfg().core.replay_path) param = { 'total_size': total_size, 'free_size': free_size, } self.render('audit/record.mako', page_param=json.dumps(param))
def update_temp_locked_user_state(): sys_cfg = tp_cfg().sys if sys_cfg.login.lock_timeout == 0: return _lock_time = tp_timestamp_utc_now() - (sys_cfg.login.lock_timeout * 60) db = get_db() if db.need_create or db.need_upgrade: return sql = 'UPDATE `{}user` SET state={new_state}, lock_time=0, fail_count=0 WHERE (state={old_state} AND lock_time<{lock_time});' \ ''.format(db.table_prefix, new_state=TP_STATE_NORMAL, old_state=TP_STATE_LOCKED, lock_time=_lock_time) db.exec(sql)
def update_temp_locked_user_state(): sys_cfg = tp_cfg().sys if sys_cfg.login.lock_timeout == 0: return _lock_time = tp_timestamp_utc_now() - (sys_cfg.login.lock_timeout * 60) db = get_db() if db.need_create or db.need_upgrade: return sql = 'UPDATE `{}user` SET state={new_state}, lock_time=0, fail_count=0 WHERE (state={old_state} AND lock_time<{lock_time});' \ ''.format(db.table_prefix, new_state=TP_STATE_NORMAL, old_state=TP_STATE_LOCKED, lock_time=_lock_time) db.exec(sql)
def get(self): ret = self.check_privilege(TP_PRIVILEGE_OPS) if ret != TPE_OK: return err, groups = group.get_host_groups_for_user( self.current_user['id'], self.current_user['privilege']) param = {'host_groups': groups, 'core_cfg': tp_cfg().core} # param = { # 'core_cfg': tp_cfg().core # } self.render('ops/remote-list.mako', page_param=json.dumps(param))
def get(self): from app.base.db import get_db if tp_cfg().app_mode == APP_MODE_MAINTENANCE and get_db().need_create: _user = { 'id': 0, 'username': '******', 'surname': '安装程序', 'role_id': 0, 'role': '', 'privilege': TP_PRIVILEGE_SYS_CONFIG, '_is_login': True } self.set_session('user', _user) self.redirect('/maintenance/install') return _user = self.get_current_user() _ref = quote(self.get_argument('ref', '/')) if _user['_is_login']: self.redirect(_ref) return if _user['id'] == 0: username = self.get_cookie('username') if username is None: username = '' else: username = _user['username'] default_auth_type = tp_cfg().sys.login.auth param = { 'ref': _ref, 'username': username, 'default_auth': default_auth_type } self.render('auth/login.mako', page_param=json.dumps(param))
def get(self): ret = self.check_privilege(TP_PRIVILEGE_ASSET_CREATE | TP_PRIVILEGE_ASSET_DELETE | TP_PRIVILEGE_ASSET_GROUP) if ret != TPE_OK: return err, groups = group.get_host_groups_for_user( self.current_user['id'], self.current_user['privilege']) param = { 'host_groups': groups, '_check_host_alive': tp_cfg().common.check_host_alive } self.render('asset/host-list.mako', page_param=json.dumps(param))
def init(self): cfg = tp_cfg() cfg_file = os.path.join(cfg.cfg_path, 'extsrv.json') # 如果配置文件不存在,则不支持第三方服务调用TP-API if not os.path.exists(cfg_file): return True log.i('Loading external server configuration...\n') with open(cfg_file, encoding='utf_8') as f: c = f.read() try: sc = json.loads(c) except: return False if 'version' not in sc: return False if 'ext_srv' not in sc: return False srv = sc['ext_srv'] try: for i in range(len(srv)): srv_name = srv[i]['name'] srv_desc = srv[i]['desc'] for j in range(len(srv[i]['access'])): key = srv[i]['access'][j]['key'] secret = srv[i]['access'][j]['secret'] privilege = int(srv[i]['access'][j]['privilege']) if key in self._cfg: log.e( 'Invalid extsrv.json, duplicated key: {}\n'.format( key)) return False self._cfg[key] = { 'name': srv_name, 'desc': srv_desc, 'secret': secret, 'privilege': privilege } except: log.e('Invalid extsrv.json\n') return False return True
def _get_core_server_config(self): cfg = tp_cfg() try: req = {'method': 'get_config', 'param': []} req_data = json.dumps(req) data = urllib.parse.quote(req_data).encode('utf-8') req = urllib.request.Request(url=cfg.common.core_server_rpc, data=data) rep = urllib.request.urlopen(req, timeout=3) body = rep.read().decode() x = json.loads(body) if 'code' not in x or x['code'] != 0: log.e('connect core-server for get config info failed.\n') else: cfg.update_core(x['data']) log.d('get config info of core-server succeeded.\n') except: log.w('can not connect to core-server to get config, maybe it not start yet, ignore.\n')
def _get_core_server_config(self): cfg = tp_cfg() try: req = {'method': 'get_config', 'param': []} req_data = json.dumps(req) data = urllib.parse.quote(req_data).encode('utf-8') req = urllib.request.Request(url=cfg.common.core_server_rpc, data=data) rep = urllib.request.urlopen(req, timeout=3) body = rep.read().decode() x = json.loads(body) if 'code' not in x or x['code'] != 0: log.e('connect core-server for get config info failed.\n') else: cfg.update_core(x['data']) log.d('get config info of core-server succeeded.\n') except: log.w('can not connect to core-server to get config, maybe it not start yet, ignore.\n')
def init(self, path_app_root, path_data): log.initialize() cfg = tp_cfg() cfg.app_path = path_app_root cfg.static_path = os.path.join(path_app_root, 'static') cfg.template_path = os.path.join(path_app_root, 'view') cfg.res_path = os.path.join(path_app_root, 'res') cfg.data_path = path_data cfg.cfg_path = os.path.join(path_data, 'etc') cfg.log_path = os.path.join(path_data, 'log') self._cfg_file = os.path.join(cfg.cfg_path, 'web.ini') if not cfg.load(self._cfg_file): return False return True
def get(self): ret = self.check_privilege(TP_PRIVILEGE_OPS) if ret != TPE_OK: return err, groups = group.get_host_groups_for_user(self.current_user['id'], self.current_user['privilege']) _cfg = tp_cfg() param = { 'host_groups': groups, 'core_cfg': _cfg.core, 'url_proto': _cfg.sys.glob.url_proto } # param = { # 'core_cfg': tp_cfg().core # } self.render('ops/remote-list.mako', page_param=json.dumps(param))
def set(self, s_id, value, expire=None): """ 设置一个会话数据,如果expire为负数,则立即删除已经存在的名为s_id的会话,如果expire为0,则此会话数据永不过期。expire的单位为秒。 @param s_id: string @param value: string @param expire: integer @return: None """ if expire is None: expire = tp_cfg().sys.login.session_timeout * 60 if expire < 0: with self._lock: if s_id in self._session_dict: del self._session_dict[s_id] else: self._session_dict[s_id] = {'v': value, 't': int(datetime.datetime.utcnow().timestamp()), 'e': expire}
def init(self): cfg = tp_cfg() if 'sqlite' == cfg.database.type: if cfg.database.sqlite_file is None: cfg.set_default('database::sqlite-file', os.path.join(cfg.data_path, 'db', 'teleport.db')) if not self._init_sqlite(cfg.database.sqlite_file): return False if self.need_create: return True elif 'mysql' == cfg.database.type: if not self._init_mysql(cfg.database.mysql_host, cfg.database.mysql_port, cfg.database.mysql_db, cfg.database.mysql_prefix, cfg.database.mysql_user, cfg.database.mysql_password): return False else: log.e('unknown database type `{}`, support sqlite/mysql now.\n'.format(cfg.database.type)) return False return True
def init(self): cfg = tp_cfg() if 'sqlite' == cfg.database.type: if cfg.database.sqlite_file is None: cfg.set_default('database::sqlite-file', os.path.join(cfg.data_path, 'db', 'teleport.db')) if not self._init_sqlite(cfg.database.sqlite_file): return False if self.need_create: return True elif 'mysql' == cfg.database.type: if not self._init_mysql(cfg.database.mysql_host, cfg.database.mysql_port, cfg.database.mysql_db, cfg.database.mysql_prefix, cfg.database.mysql_user, cfg.database.mysql_password): return False else: log.e('unknown database type `{}`, support sqlite/mysql now.\n'.format(cfg.database.type)) return False return True
def get_states(self, host_ip_list): if not tp_cfg().common.check_host_alive: return {} with self._lock: ret = dict() time_now = int(time.time()) for k in host_ip_list: if k not in self._states: ret[k] = { 'state': HostAlive.STATE_UNKNOWN, 'last_online': 0, 'last_check': 0 } continue if self._states[k]['last_check'] == 0: ret[k] = { 'state': HostAlive.STATE_UNKNOWN, 'last_online': 0, 'last_check': time_now - self._states[k]['last_check'] } continue if self._states[k]['last_online'] == 0: ret[k] = { 'state': HostAlive.STATE_WARNING, 'last_online': 0, 'last_check': time_now - self._states[k]['last_check'] } if time_now - self._states[k]['last_online'] > 2 * 60: _state = HostAlive.STATE_OFFLINE elif time_now - self._states[k]['last_online'] > 60: _state = HostAlive.STATE_WARNING else: _state = HostAlive.STATE_ONLINE ret[k] = { 'state': _state, 'last_online': self._states[k]['last_online'], 'last_check': time_now - self._states[k]['last_check'] } return ret
def _init_sqlite(self, db_file): self.db_type = self.DB_TYPE_SQLITE self.auto_increment = 'AUTOINCREMENT' self.place_holder = '?' self.sqlite_file = db_file self._table_prefix = tp_cfg().database.mysql_prefix self._conn_pool = TPSqlitePool(db_file) if not os.path.exists(db_file): p = os.path.dirname(os.path.abspath(db_file)) if not os.path.exists(p): os.makedirs(p) log.w('database need create.\n') self.need_create = True return True return True
def init(self, path_app_root, path_data): log.initialize() asyncio.set_event_loop_policy(tornado.platform.asyncio.AnyThreadEventLoopPolicy()) cfg = tp_cfg() cfg.app_path = path_app_root cfg.static_path = os.path.join(path_app_root, 'static') cfg.template_path = os.path.join(path_app_root, 'view') cfg.res_path = os.path.join(path_app_root, 'res') cfg.data_path = path_data cfg.cfg_path = os.path.join(path_data, 'etc') cfg.log_path = os.path.join(path_data, 'log') self._cfg_file = os.path.join(cfg.cfg_path, 'web.ini') if not cfg.load(self._cfg_file): return False return True
def init(self, path_app_root, path_data): log.initialize() asyncio.set_event_loop_policy(tornado.platform.asyncio.AnyThreadEventLoopPolicy()) cfg = tp_cfg() cfg.app_path = path_app_root cfg.static_path = os.path.join(path_app_root, 'static') cfg.template_path = os.path.join(path_app_root, 'view') cfg.res_path = os.path.join(path_app_root, 'res') cfg.data_path = path_data cfg.cfg_path = os.path.join(path_data, 'etc') cfg.log_path = os.path.join(path_data, 'log') self._cfg_file = os.path.join(cfg.cfg_path, 'web.ini') if not cfg.load(self._cfg_file): return False return True
def update_fail_count(handler, user_info): db = get_db() sys_cfg = tp_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 update_fail_count(handler, user_info): db = get_db() sys_cfg = tp_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 get(self): ret = self.check_privilege(TP_PRIVILEGE_SYS_CONFIG) if ret != TPE_OK: return cfg = tp_cfg() # core_detected = False req = {'method': 'get_config', 'param': []} _yr = core_service_async_post_http(req) code, ret_data = yield _yr if code != TPE_OK: cfg.update_core(None) else: cfg.update_core(ret_data) if not tp_cfg().core.detected: total_size = 0 free_size = 0 else: total_size, _, free_size = shutil.disk_usage( tp_cfg().core.replay_path) _db = get_db() db = {'type': _db.db_type} if _db.db_type == _db.DB_TYPE_SQLITE: db['sqlite_file'] = _db.sqlite_file elif _db.db_type == _db.DB_TYPE_MYSQL: db['mysql_host'] = _db.mysql_host db['mysql_port'] = _db.mysql_port db['mysql_db'] = _db.mysql_db db['mysql_user'] = _db.mysql_user param = { 'total_size': total_size, 'free_size': free_size, 'core_cfg': tp_cfg().core, 'sys_cfg': tp_cfg().sys, 'web_cfg': { 'version': TP_SERVER_VER, 'core_server_rpc': tp_cfg().common.core_server_rpc, 'db': db } } self.render('system/config.mako', page_param=json.dumps(param))
def get(self): ret = self.check_privilege(TP_PRIVILEGE_SYS_CONFIG) if ret != TPE_OK: return cfg = tp_cfg() # core_detected = False req = {'method': 'get_config', 'param': []} _yr = core_service_async_post_http(req) code, ret_data = yield _yr if code != TPE_OK: cfg.update_core(None) else: cfg.update_core(ret_data) if not tp_cfg().core.detected: total_size = 0 free_size = 0 else: total_size, _, free_size = shutil.disk_usage(tp_cfg().core.replay_path) _db = get_db() db = {'type': _db.db_type} if _db.db_type == _db.DB_TYPE_SQLITE: db['sqlite_file'] = _db.sqlite_file elif _db.db_type == _db.DB_TYPE_MYSQL: db['mysql_host'] = _db.mysql_host db['mysql_port'] = _db.mysql_port db['mysql_db'] = _db.mysql_db db['mysql_user'] = _db.mysql_user param = { 'total_size': total_size, 'free_size': free_size, 'core_cfg': tp_cfg().core, 'sys_cfg': tp_cfg().sys, 'web_cfg': { 'version': TP_SERVER_VER, 'core_server_rpc': tp_cfg().common.core_server_rpc, 'db': db } } self.render('system/config.mako', page_param=json.dumps(param))
# -*- coding: utf-8 -*- import json import threading from app.const import * from app.base.configs import tp_cfg from app.base.controller import TPBaseHandler, TPBaseJsonHandler from app.base.db import get_db cfg = tp_cfg() class IndexHandler(TPBaseHandler): def get(self): self.render('maintenance/index.mako') class InstallHandler(TPBaseHandler): def get(self): ret = self.check_privilege(TP_PRIVILEGE_SYS_CONFIG) if ret != TPE_OK: return if get_db().need_create: cfg.reload() _db = get_db() _db.init() db = {'type': _db.db_type}
def login(handler, username, password=None, oath_code=None, check_bind_oath=False): sys_cfg = tp_cfg().sys err, user_info = get_by_username(username) if err != TPE_OK: # if err == TPE_NOT_EXISTS: # syslog.sys_log({'username': username, 'surname': username}, handler.request.remote_ip, TPE_NOT_EXISTS, # '用户身份验证失败,用户`{}`不存在'.format(username)) return err, None if user_info.privilege == 0: # 尚未为此用户设置角色 return TPE_PRIVILEGE, None if check_bind_oath and len(user_info['oath_secret']) != 0: return TPE_OATH_ALREADY_BIND, None 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, handler.request.remote_ip, TPE_USER_LOCKED, '登录失败,用户已被临时锁定') return TPE_USER_LOCKED, None elif user_info['state'] == TP_STATE_DISABLED: syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_DISABLED, '登录失败,用户已被禁用') return TPE_USER_DISABLED, None elif user_info['state'] != TP_STATE_NORMAL: syslog.sys_log(user_info, handler.request.remote_ip, TPE_FAILED, '登录失败,用户状态异常') return TPE_FAILED, None err_msg = '' if password is not None: if user_info['type'] == TP_USER_TYPE_LOCAL: # 如果系统配置了密码有效期,则检查用户的密码是否失效 if sys_cfg.password.timeout != 0: _time_now = tp_timestamp_utc_now() if user_info['last_chpass'] + (sys_cfg.password.timeout * 60 * 60 * 24) < _time_now: syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, '登录失败,用户密码已过期') return TPE_USER_AUTH, None if not tp_password_verify(password, user_info['password']): err, is_locked = update_fail_count(handler, user_info) if is_locked: err_msg = ',用户已被临时锁定' syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, '登录失败,密码错误{}'.format(err_msg)) return TPE_USER_AUTH, None elif user_info['type'] == TP_USER_TYPE_LDAP: try: if len(tp_cfg().sys_ldap_password) == 0: syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, 'LDAP未能正确配置,需要管理员密码') return TPE_USER_AUTH, None else: _ldap_password = tp_cfg().sys_ldap_password _ldap_server = tp_cfg().sys.ldap.server _ldap_port = tp_cfg().sys.ldap.port _ldap_base_dn = tp_cfg().sys.ldap.base_dn except: syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, 'LDAP未能正确配置') return TPE_USER_AUTH, None try: ldap = Ldap(_ldap_server, _ldap_port, _ldap_base_dn) ret, err_msg = ldap.valid_user(user_info['ldap_dn'], password) if ret != TPE_OK: if ret == TPE_USER_AUTH: err, is_locked = update_fail_count(handler, user_info) if is_locked: err_msg = ',用户已被临时锁定' syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, 'LDAP用户登录失败,密码错误{}'.format(err_msg)) return TPE_USER_AUTH, None else: syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, 'LDAP用户登录失败,{}'.format(err_msg)) return TPE_USER_AUTH, None except: syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, 'LDAP用户登录失败,发生内部错误') return TPE_USER_AUTH, None else: syslog.sys_log(user_info, handler.request.remote_ip, TPE_USER_AUTH, '登录失败,系统内部错误') return TPE_USER_AUTH, None if oath_code is not None: # use oath if len(user_info['oath_secret']) == 0: return TPE_OATH_MISMATCH, None if not tp_oath_verify_code(user_info['oath_secret'], oath_code): err, is_locked = update_fail_count(handler, user_info) if is_locked: err_msg = ',用户已被临时锁定!' syslog.sys_log(user_info, handler.request.remote_ip, TPE_OATH_MISMATCH, "登录失败,身份验证器动态验证码错误{}".format(err_msg)) return TPE_OATH_MISMATCH, None del user_info['password'] del user_info['oath_secret'] if len(user_info['surname']) == 0: user_info['surname'] = user_info['username'] return TPE_OK, user_info
def post(self): """ csv导入规则: 每一行的数据格式: 用户账号,用户姓名,登录认证方式,email地址,Mobile,QQ,WeChat,所属组,描述 在导入时: 0. 以“#”作为行注释。 1. 用户账号是必须填写的,其他均为可选。 2. 一个用户属于多个组,可以用“|”将组分隔,如果某个组并不存在,则会创建这个组。 3. 空行跳过,数据格式不正确的跳过。 """ ret = dict() ret['code'] = TPE_OK ret['message'] = '' rv = self.check_privilege(TP_PRIVILEGE_USER_CREATE | TP_PRIVILEGE_USER_GROUP, need_process=False) if rv != TPE_OK: ret['code'] = rv ret['code'] = rv if rv == TPE_NEED_LOGIN: ret['message'] = '需要登录!' elif rv == TPE_PRIVILEGE: ret['message'] = '权限不足!' else: ret['message'] = '未知错误!' return self.write(json.dumps(ret).encode('utf8')) success = list() failed = list() group_failed = list() csv_filename = '' try: upload_path = os.path.join(tp_cfg().data_path, 'tmp') # 文件的暂存路径 if not os.path.exists(upload_path): os.mkdir(upload_path) file_metas = self.request.files['csvfile'] # 提取表单中‘name’为‘file’的文件元数据 for meta in file_metas: now = time.localtime(time.time()) tmp_name = 'upload-{:04d}{:02d}{:02d}{:02d}{:02d}{:02d}.csv'.format(now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec) csv_filename = os.path.join(upload_path, tmp_name) with open(csv_filename, 'wb') as f: f.write(meta['body']) # file encode maybe utf8 or gbk... check it out. file_encode = None with open(csv_filename, encoding='gbk') as f: try: f.readlines() file_encode = 'gbk' except: pass if file_encode is None: log.v('file `{}` is not gbk, try utf8\n'.format(csv_filename)) with open(csv_filename, encoding='utf_8_sig') as f: try: f.readlines() file_encode = 'utf_8_sig' except: pass if file_encode is None: os.remove(csv_filename) log.e('file `{}` unknown encode, neither GBK nor UTF8.\n'.format(csv_filename)) ret['code'] = TPE_FAILED ret['message'] = '文件无法解码:不是GBK编码或者UTF8编码!' return self.write(json.dumps(ret).encode('utf8')) group_list = dict() user_list = list() # 解析csv文件 with open(csv_filename, encoding=file_encode) as f: username_list = [] # 用于检查是否有重复的用户被添加 csv_reader = csv.reader(f) line = 0 for csv_recorder in csv_reader: line += 1 # 跳过空行和注释 if len(csv_recorder) == 0 or csv_recorder[0].strip().startswith('#'): continue # 格式错误则记录在案,然后继续 if len(csv_recorder) != 8: failed.append({'line': line, 'error': '格式错误,字段数量不匹配。'}) continue # check _username = csv_recorder[self.IDX_USERNAME].strip() if len(_username) == 0: failed.append({'line': line, 'error': '格式错误,用户账号必须填写。'}) continue _email = csv_recorder[self.IDX_EMAIL].strip() _group = csv_recorder[self.IDX_GROUP].split('|') u = dict() u['_line'] = line u['_id'] = 0 u['username'] = _username u['surname'] = csv_recorder[self.IDX_SURNAME].strip() # u['auth'] = _auth u['email'] = _email u['mobile'] = csv_recorder[self.IDX_MOBILE].strip() u['qq'] = csv_recorder[self.IDX_QQ].strip() u['wechat'] = csv_recorder[self.IDX_WECHAT].strip() u['desc'] = csv_recorder[self.IDX_DESC].strip() u['password'] = tp_gen_password(8) # fix if len(u['surname']) == 0: u['surname'] = _username u['username'] = _username.lower() if u['username'] in username_list: failed.append({'line': line, 'error': '上传文件中用户 `{}` 重复。'.format(u['username'])}) continue else: username_list.append(u['username']) u['_group'] = list() for i in range(len(_group)): x = _group[i].strip() if len(x) > 0: u['_group'].append(x) # 更新一下组列表,以备后续为用户与所在组创建映射 for i in range(len(u['_group'])): if u['_group'][i] not in group_list: group_list[u['_group'][i]] = 0 user_list.append(u) if os.path.exists(csv_filename): os.remove(csv_filename) # 检查一下 if len(user_list) == 0: ret['code'] = TPE_FAILED ret['message'] = '上传的 csv 文件中没有可用于导入的用户!' ret['data'] = failed return self.write(json.dumps(ret).encode('utf8')) # 已经有了用户组列表,查询组数据库,有则更新用户组列表中组对应的id,无则创建组 if len(group_list) > 0: err = group.make_groups(self, TP_GROUP_USER, group_list, group_failed) if len(group_failed) > 0: ret['code'] = TPE_FAILED ret['message'] += '无法创建用户组 {}。'.format(','.join(group_failed)) return self.write(json.dumps(ret).encode('utf8')) # 对用户列表中的每一项,创建用户 user.create_users(self, user_list, success, failed) # 对创建成功的用户,在用户组映射表中设定其对应关系 gm = list() for u in user_list: if u['_id'] == 0: continue for ug in u['_group']: for g in group_list: if group_list[g] == 0 or ug != g: continue gm.append({'type': TP_GROUP_USER, 'gid': group_list[g], 'mid': u['_id']}) group.make_group_map(TP_GROUP_USER, gm) # 对于创建成功的用户,发送密码邮件函 sys_smtp_password = tp_cfg().sys_smtp_password if len(sys_smtp_password) > 0: web_url = '{}://{}'.format(self.request.protocol, self.request.host) for u in user_list: if u['_id'] == 0 or len(u['email']) == 0: continue err, msg = yield mail.tp_send_mail( u['email'], '{surname} 您好!\n\n已为您创建teleport系统用户账号,现在可以使用以下信息登录teleport系统:\n\n' '登录用户名:{username}\n' '密码:{password}\n' '地址:{web_url}\n\n\n\n' '[本邮件由teleport系统自动发出,请勿回复]' '\n\n' ''.format(surname=u['surname'], username=u['username'], password=u['password'], web_url=web_url), subject='用户密码函' ) if err != TPE_OK: failed.append({'line': u['_line'], 'error': '无法发送密码函到邮箱 {},错误:{}。'.format(u['email'], msg)}) # 统计结果 total_success = 0 total_failed = 0 for u in user_list: if u['_id'] == 0: total_failed += 1 else: total_success += 1 # 生成最终结果信息 if len(failed) == 0: ret['code'] = TPE_OK ret['message'] = '共导入 {} 个用户账号!'.format(total_success) return self.write(json.dumps(ret).encode('utf8')) else: ret['code'] = TPE_FAILED if total_success > 0: ret['message'] = '{} 个用户账号导入成功,'.format(total_success) if total_failed > 0: ret['message'] += '{} 个用户账号未能导入!'.format(total_failed) ret['data'] = failed return self.write(json.dumps(ret).encode('utf8')) except: log.e('got exception when import user.\n') ret['code'] = TPE_FAILED if len(success) > 0: ret['message'] += '{} 个用户账号导入后发生异常!'.format(len(success)) else: ret['message'] = '发生异常!' ret['data'] = failed return self.write(json.dumps(ret).encode('utf8'))
def post(self): ret = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if ret != TPE_OK: return args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: args['id'] = int(args['id']) args['role'] = int(args['role']) args['auth_type'] = int(args['auth_type']) args['username'] = args['username'].strip().lower() args['surname'] = args['surname'].strip() args['email'] = args['email'].strip() args['mobile'] = args['mobile'].strip() args['qq'] = args['qq'].strip() args['wechat'] = args['wechat'].strip() args['desc'] = args['desc'].strip() except: return self.write_json(TPE_PARAM) if len(args['username']) == 0: return self.write_json(TPE_PARAM) if args['id'] == -1: args['password'] = tp_gen_password(8) err, _ = user.create_user(self, args) if err == TPE_OK: if len(args['email']) == 0: return self.write_json(TPE_OK) # 对于创建成功的用户,发送密码邮件函 sys_smtp_password = tp_cfg().sys_smtp_password if len(sys_smtp_password) > 0: web_url = '{}://{}'.format(self.request.protocol, self.request.host) err, msg = yield mail.tp_send_mail( args['email'], '{surname} 您好!\n\n已为您创建teleport系统用户账号,现在可以使用以下信息登录teleport系统:\n\n' '登录用户名:{username}\n' '密码:{password}\n' '地址:{web_url}\n\n\n\n' '[本邮件由teleport系统自动发出,请勿回复]' '\n\n' ''.format(surname=args['surname'], username=args['username'], password=args['password'], web_url=web_url), subject='用户密码函' ) if err != TPE_OK: return self.write_json(TPE_OK, '用户账号创建成功,但发送密码函失败:{}'.format(msg)) else: return self.write_json(TPE_OK) else: return self.write_json(err) else: err = user.update_user(self, args) self.write_json(err)
def post(self): args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: mode = int(args['mode']) except: return self.write_json(TPE_PARAM) password = '' if mode == 1: # 管理员直接在后台给用户发送密码重置邮件 err = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if err != TPE_OK: return self.write_json(err) try: user_id = int(args['id']) except: return self.write_json(TPE_PARAM) elif mode == 2: # 管理员直接在后台为用户重置密码 err = self.check_privilege(TP_PRIVILEGE_USER_CREATE) if err != TPE_OK: return self.write_json(err) try: user_id = int(args['id']) password = args['password'] except: return self.write_json(TPE_PARAM) elif mode == 3: # 用户自行找回密码,需要填写用户名、邮箱、验证码 try: username = args['username'] email = args['email'] captcha = args['captcha'] except: return self.write_json(TPE_PARAM) code = self.get_session('captcha') if code is None: return self.write_json(TPE_CAPTCHA_EXPIRED, '验证码已失效') if code.lower() != captcha.lower(): return self.write_json(TPE_CAPTCHA_MISMATCH, '验证码错误') self.del_session('captcha') err, user_info = user.get_by_username(username) if err != TPE_OK: return self.write_json(err) if user_info.email != email: return self.write_json(TPE_NOT_EXISTS) user_id = user_info.id elif mode == 4: # 用户通过密码重置邮件中的链接(有token验证),在页面上设置新密码,需要提供token、新密码 try: token = args['token'] password = args['password'] except: return self.write_json(TPE_PARAM) err, user_id = user.check_reset_token(token) if err != TPE_OK: return self.write_json(err) elif mode == 5: # 用户输入当前密码和新密码进行设置 try: current_password = args['current_password'] password = args['password'] except: return self.write_json(TPE_PARAM) err, user_info = user.get_by_username(self.get_current_user()['username']) if err != TPE_OK: return self.write_json(err) if not tp_password_verify(current_password, user_info['password']): return self.write_json(TPE_USER_AUTH) user_id = user_info['id'] else: return self.write_json(TPE_PARAM) if user_id == 0: return self.write_json(TPE_PARAM) if mode == 1 or mode == 3: err, email, token = user.generate_reset_password_token(self, user_id) # generate an URL for reset password, valid in 24hr. reset_url = '{}://{}/user/reset-password?token={}'.format(self.request.protocol, self.request.host, token) err, msg = yield mail.tp_send_mail( email, 'Teleport用户,您好!\n\n请访问以下链接以重设您的teleport登录密码。此链接将于本邮件寄出24小时之后失效。\n' '访问此链接,将会为您打开密码重置页面,然后您可以设定新密码。\n\n' '如果您并没有做重设密码的操作,请忽略本邮件,请及时联系您的系统管理员!\n\n' '{reset_url}\n\n\n\n' '[本邮件由teleport系统自动发出,请勿回复]' '\n\n' ''.format(reset_url=reset_url), subject='密码重置确认函' ) return self.write_json(err, msg) elif mode == 2 or mode == 4 or mode == 5: if len(password) == 0: return self.write_json(TPE_PARAM) # 根据需要进行弱密码检测 if tp_cfg().sys.password.force_strong: if not tp_check_strong_password(password): return self.write_json(TPE_FAILED, '密码强度太弱!强密码需要至少8个英文字符,必须包含大写字母、小写字母和数字。') password = tp_password_generate_secret(password) err = user.set_password(self, user_id, password) if mode == 4 and err == TPE_OK: user.remove_reset_token(token) # 非用户自行修改密码的情况,都默认重置身份认证 if mode != 5 and err == TPE_OK: print("reset oath secret") user.update_oath_secret(self, user_id, '') self.write_json(err) else: self.write_json(TPE_PARAM)
def cleanup_storage(handler): # storage config sto = tp_cfg().sys.storage db = get_db() _now = tp_timestamp_utc_now() msg = [] have_error = False s = SQL(db) chk_time = _now - sto.keep_log * 24 * 60 * 60 if sto.keep_log > 0: # find out all sys-log to be remove s.select_from('syslog', ['id'], alt_name='s') s.where('s.log_time<{chk_time}'.format(chk_time=chk_time)) err = s.query() if err != TPE_OK: have_error = True msg.append('清理系统日志时发生错误:无法获取系统日志信息!') # return err, msg else: removed_log = len(s.recorder) if 0 == removed_log: msg.append('没有满足条件的系统日志需要清除!') else: s.reset().delete_from('syslog').where('log_time<{chk_time}'.format(chk_time=chk_time)) err = s.exec() if err != TPE_OK: have_error = True msg.append('清理系统日志时发生错误:无法清除指定的系统日志!') else: msg.append('{} 条系统日志已清除!'.format(removed_log)) if sto.keep_record > 0: core_cfg = tp_cfg().core if not core_cfg.detected: have_error = True msg.append('清除指定会话录像失败:未能检测到核心服务!') else: replay_path = core_cfg.replay_path if not os.path.exists(replay_path): have_error = True msg.append('清除指定会话录像失败:会话录像路径不存在({})!'.format(replay_path)) else: # find out all record to be remove s.reset().select_from('record', ['id', 'protocol_type'], alt_name='r') s.where('r.time_begin<{chk_time}'.format(chk_time=chk_time)) err = s.query() if err != TPE_OK: have_error = True msg.append('清除指定会话录像失败:无法获取会话录像信息!') elif len(s.recorder) == 0: msg.append('没有满足条件的会话录像需要清除!') else: record_removed = 0 for r in s.recorder: if r.protocol_type == TP_PROTOCOL_TYPE_RDP: path_remove = os.path.join(replay_path, 'rdp', '{:09d}'.format(r.id)) elif r.protocol_type == TP_PROTOCOL_TYPE_SSH: path_remove = os.path.join(replay_path, 'ssh', '{:09d}'.format(r.id)) elif r.protocol_type == TP_PROTOCOL_TYPE_TELNET: path_remove = os.path.join(replay_path, 'telnet', '{:09d}'.format(r.id)) else: have_error = True msg.append('会话录像记录编号 {},未知远程访问协议!'.format(r.id)) continue if os.path.exists(path_remove): # print('remove path', path_remove) try: shutil.rmtree(path_remove) except: have_error = True msg.append('会话录像记录 {} 清除失败,无法删除目录 {}!'.format(r.id, path_remove)) ss = SQL(db) ss.delete_from('record').where('id={rid}'.format(rid=r.id)) ss.exec() record_removed += 1 msg.append('{} 条会话录像数据已清除!'.format(record_removed)) if have_error: return TPE_FAILED, msg else: return TPE_OK, msg
def read_telnet_record_data(record_id, offset): if not tp_cfg().core.detected: return None, TPE_NO_CORE_SERVER record_path = os.path.join(tp_cfg().core.replay_path, 'telnet', '{:09d}'.format(int(record_id))) file_data = os.path.join(record_path, 'tp-telnet.dat') if not os.path.exists(file_data): return None, 0, TPE_NOT_EXISTS data_list = list() data_size = 0 file = None try: file_size = os.path.getsize(file_data) if offset >= file_size: return None, 0, TPE_FAILED file = open(file_data, 'rb') if offset > 0: file.seek(offset, io.SEEK_SET) # read 1000 packages one time from offset. for i in range(1000): """ // 一个数据包的头 typedef struct TS_RECORD_PKG { ex_u8 type; // 包的数据类型 ex_u32 size; // 这个包的总大小(不含包头) ex_u32 time_ms; // 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天) ex_u8 _reserve[3]; // 保留 }TS_RECORD_PKG; """ _data = file.read(12) data_size += 12 _action, _size, _time, = struct.unpack_from('=BII', _data) if offset + data_size + _size > file_size: return None, 0, TPE_FAILED _data = file.read(_size) data_size += _size temp = dict() temp['a'] = _action temp['t'] = _time if _action == 1: # this is window size changed. w, h = struct.unpack_from('HH', _data) temp['w'] = w temp['h'] = h elif _action == 2: try: _d = _data.decode() temp['d'] = _d except: _data = base64.b64encode(_data) temp['a'] = 3 temp['d'] = _data.decode() else: return None, 0, TPE_FAILED data_list.append(temp) if offset + data_size == file_size: break except Exception: log.e('failed to read record file: {}\n'.format(file_data)) return None, 0, TPE_FAILED finally: if file is not None: file.close() return data_list, data_size, TPE_OK
def read_record_head(protocol_type, record_id): if not tp_cfg().core.detected: return None, TPE_NO_CORE_SERVER if protocol_type == TP_PROTOCOL_TYPE_RDP: path_name = 'rdp' elif protocol_type == TP_PROTOCOL_TYPE_SSH: path_name = 'ssh' elif protocol_type == TP_PROTOCOL_TYPE_TELNET: path_name = 'telnet' record_path = os.path.join(tp_cfg().core.replay_path, path_name, '{:09d}'.format(int(record_id))) header_file_path = os.path.join(record_path, 'tp-{}.tpr'.format(path_name)) if not os.path.exists(header_file_path): return None, TPE_NOT_EXISTS file = None try: file = open(header_file_path, 'rb') data = file.read() offset = 0 magic, = struct.unpack_from('I', data, offset) # magic must be 1381126228, 'TPPR' offset += 4 ver, = struct.unpack_from('H', data, offset) offset += 2 pkg_count, = struct.unpack_from('I', data, offset) offset += 4 time_used, = struct.unpack_from('I', data, offset) offset += 4 protocol_type, = struct.unpack_from('H', data, offset) offset += 2 protocol_sub_type, = struct.unpack_from('H', data, offset) offset += 2 time_start, = struct.unpack_from('Q', data, offset) offset += 8 width, = struct.unpack_from('H', data, offset) offset += 2 height, = struct.unpack_from('H', data, offset) offset += 2 # file_count, = struct.unpack_from('H', data, offset) # offset += 2 # total_size, = struct.unpack_from('I', data, offset) # offset += 4 user_name, = struct.unpack_from('64s', data, offset) user_name = _remove_padding_space(user_name).decode() offset += 64 account, = struct.unpack_from('64s', data, offset) account = _remove_padding_space(account).decode() offset += 64 host_ip, = struct.unpack_from('40s', data, offset) host_ip = _remove_padding_space(host_ip).decode() offset += 40 conn_ip, = struct.unpack_from('40s', data, offset) conn_ip = _remove_padding_space(conn_ip).decode() offset += 40 conn_port, = struct.unpack_from('H', data, offset) offset += 2 client_ip, = struct.unpack_from('40s', data, offset) client_ip = _remove_padding_space(client_ip).decode() offset += 40 except Exception as e: log.e(e) return None, TPE_FAILED finally: if file is not None: file.close() header = dict() header['start'] = time_start header['pkg_count'] = pkg_count header['time_used'] = time_used header['width'] = width header['height'] = height header['account'] = account header['user_name'] = user_name header['host_ip'] = host_ip header['conn_ip'] = conn_ip header['conn_port'] = conn_port header['client_ip'] = client_ip return header, TPE_OK
def post(self): # ret = self.check_privilege(TP_PRIVILEGE_ASSET_CREATE | TP_PRIVILEGE_ASSET_DELETE | TP_PRIVILEGE_OPS | TP_PRIVILEGE_OPS_AUZ) # if ret != TPE_OK: # return args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) # 有三种方式获取会话ID: # 1. 给定一个远程连接授权ID(普通用户进行远程连接) # 2. 给定要连接的主机ID和账号ID(管理员进行远程连接) # 3. 给定要连接的主机ID和账号信息(管理员测试远程连接是否可用) # # WEB服务根据上述信息产生临时的远程连接ID,核心服务通过此远程连接ID来获取远程连接所需数据,生成会话ID。 try: _mode = int(args['mode']) _protocol_type = int(args['protocol_type']) _protocol_sub_type = int(args['protocol_sub_type']) except: return self.write_json(TPE_PARAM) conn_info = dict() conn_info['_enc'] = 1 conn_info['host_id'] = 0 conn_info['client_ip'] = self.request.remote_ip conn_info['user_id'] = self.get_current_user()['id'] conn_info['user_username'] = self.get_current_user()['username'] # mode = 0: test connect # mode = 1: user connect # mode = 2: admin connect if _mode == 1: # 通过指定的auth_id连接(需要授权),必须具有远程运维的权限方可进行 ret = self.check_privilege(TP_PRIVILEGE_OPS) if ret != TPE_OK: return if 'auth_id' not in args or 'protocol_sub_type' not in args: return self.write_json(TPE_PARAM) # 根据auth_id从数据库中取得此授权相关的用户、主机、账号三者详细信息 auth_id = args['auth_id'] ops_auth, err = ops.get_auth(auth_id) if err != TPE_OK: return self.write_json(err) policy_id = ops_auth['p_id'] acc_id = ops_auth['a_id'] host_id = ops_auth['h_id'] err, policy_info = ops.get_by_id(policy_id) if err != TPE_OK: return self.write_json(err) err, acc_info = account.get_account_info(acc_id) if err != TPE_OK: return self.write_json(err) # log.v(acc_info) if acc_info['protocol_type'] == TP_PROTOCOL_TYPE_RDP: acc_info['protocol_flag'] = policy_info['flag_rdp'] elif acc_info['protocol_type'] == TP_PROTOCOL_TYPE_SSH: acc_info['protocol_flag'] = policy_info['flag_ssh'] elif acc_info['protocol_type'] == TP_PROTOCOL_TYPE_TELNET: acc_info['protocol_flag'] = policy_info['flag_telnet'] else: acc_info['protocol_flag'] = 0 acc_info['record_flag'] = policy_info['flag_record'] elif _mode == 2: # 直接连接(无需授权),必须具有运维授权管理的权限方可进行 ret = self.check_privilege(TP_PRIVILEGE_OPS_AUZ) if ret != TPE_OK: return acc_id = args['acc_id'] host_id = args['host_id'] err, acc_info = account.get_account_info(acc_id) if err != TPE_OK: return self.write_json(err) acc_info['protocol_flag'] = TP_FLAG_ALL acc_info['record_flag'] = TP_FLAG_ALL elif _mode == 0: # 测试连接,必须具有主机信息创建、编辑的权限方可进行 ret = self.check_privilege(TP_PRIVILEGE_ASSET_CREATE) if ret != TPE_OK: return conn_info['_test'] = 1 try: acc_id = int(args['acc_id']) host_id = int(args['host_id']) auth_type = int(args['auth_type']) username = args['username'] password = args['password'] pri_key = args['pri_key'] protocol_port = int(args['protocol_port']) username_prompt = args['username_prompt'] password_prompt = args['password_prompt'] except: return self.write_json(TPE_PARAM) if len(username) == 0: return self.write_json(TPE_PARAM) acc_info = dict() acc_info['auth_type'] = auth_type acc_info['protocol_type'] = _protocol_type acc_info['protocol_port'] = protocol_port acc_info['protocol_flag'] = TP_FLAG_ALL acc_info['record_flag'] = TP_FLAG_ALL acc_info['username'] = username acc_info['password'] = password acc_info['pri_key'] = pri_key acc_info['username_prompt'] = username_prompt acc_info['password_prompt'] = password_prompt conn_info['_enc'] = 0 if acc_id == -1: if auth_type == TP_AUTH_TYPE_PASSWORD and len(password) == 0: return self.write_json(TPE_PARAM) elif auth_type == TP_AUTH_TYPE_PRIVATE_KEY and len(pri_key) == 0: return self.write_json(TPE_PARAM) else: if (auth_type == TP_AUTH_TYPE_PASSWORD and len(password) == 0) or (auth_type == TP_AUTH_TYPE_PRIVATE_KEY and len(pri_key) == 0): err, _acc_info = account.get_account_info(acc_id) if err != TPE_OK: return self.write_json(err) acc_info['password'] = _acc_info['password'] acc_info['pri_key'] = _acc_info['pri_key'] conn_info['_enc'] = 1 else: return self.write_json(TPE_PARAM) # 获取要远程连接的主机信息(要访问的IP地址,如果是路由模式,则是路由主机的IP+端口) err, host_info = host.get_host_info(host_id) if err != TPE_OK: return self.write_json(err) conn_info['host_id'] = host_id conn_info['host_ip'] = host_info['ip'] if len(host_info['router_ip']) > 0: conn_info['conn_ip'] = host_info['router_ip'] conn_info['conn_port'] = host_info['router_port'] else: conn_info['conn_ip'] = host_info['ip'] conn_info['conn_port'] = acc_info['protocol_port'] conn_info['acc_id'] = acc_id conn_info['acc_username'] = acc_info['username'] conn_info['username_prompt'] = acc_info['username_prompt'] conn_info['password_prompt'] = acc_info['password_prompt'] conn_info['protocol_flag'] = acc_info['protocol_flag'] conn_info['record_flag'] = acc_info['record_flag'] conn_info['protocol_type'] = acc_info['protocol_type'] conn_info['protocol_sub_type'] = _protocol_sub_type conn_info['auth_type'] = acc_info['auth_type'] if acc_info['auth_type'] == TP_AUTH_TYPE_PASSWORD: conn_info['acc_secret'] = acc_info['password'] elif acc_info['auth_type'] == TP_AUTH_TYPE_PRIVATE_KEY: conn_info['acc_secret'] = acc_info['pri_key'] else: conn_info['acc_secret'] = '' with tmp_conn_id_lock: global tmp_conn_id_base tmp_conn_id_base += 1 conn_id = tmp_conn_id_base # log.v('CONN-INFO:', conn_info) tp_session().set('tmp-conn-info-{}'.format(conn_id), conn_info, 10) req = {'method': 'request_session', 'param': {'conn_id': conn_id}} _yr = core_service_async_post_http(req) _code, ret_data = yield _yr if _code != TPE_OK: return self.write_json(_code) if ret_data is None: return self.write_json(TPE_FAILED, '调用核心服务获取会话ID失败') if 'sid' not in ret_data: return self.write_json(TPE_FAILED, '核心服务获取会话ID时返回错误数据') data = dict() data['session_id'] = ret_data['sid'] data['host_ip'] = host_info['ip'] data['protocol_flag'] = acc_info['protocol_flag'] if conn_info['protocol_type'] == TP_PROTOCOL_TYPE_RDP: data['teleport_port'] = tp_cfg().core.rdp.port elif conn_info['protocol_type'] == TP_PROTOCOL_TYPE_SSH: data['teleport_port'] = tp_cfg().core.ssh.port elif conn_info['protocol_type'] == TP_PROTOCOL_TYPE_TELNET: data['teleport_port'] = tp_cfg().core.telnet.port return self.write_json(0, data=data)
def post(self): ret = self.check_privilege(TP_PRIVILEGE_SYS_CONFIG) if ret != TPE_OK: return args = self.get_argument('args', None) if args is None: return self.write_json(TPE_PARAM) try: args = json.loads(args) except: return self.write_json(TPE_JSON_FORMAT) try: processed = False if 'smtp' in args: processed = True _cfg = args['smtp'] _server = _cfg['server'] _port = _cfg['port'] _ssl = _cfg['ssl'] _sender = _cfg['sender'] _password = _cfg['password'] # TODO: encrypt the password before save by core-service. # TODO: if not send password, use pre-saved password. err = system_model.save_config(self, '更新SMTP设置', 'smtp', _cfg) if err == TPE_OK: # 同时更新内存缓存 tp_cfg().sys.smtp.server = _server tp_cfg().sys.smtp.port = _port tp_cfg().sys.smtp.ssl = _ssl tp_cfg().sys.smtp.sender = _sender # 特殊处理,防止前端拿到密码 tp_cfg().sys_smtp_password = _password else: return self.write_json(err) #增加urlprotocol的配置 if 'global' in args: processed = True _cfg = args['global'] _url_proto = _cfg['url_proto'] err = system_model.save_config(self, '更新全局设置', 'global', _cfg) if err == TPE_OK: tp_cfg().sys.glob.url_proto = _url_proto else: return self.write_json(err) if 'password' in args: processed = True _cfg = args['password'] _allow_reset = _cfg['allow_reset'] _force_strong = _cfg['force_strong'] _timeout = _cfg['timeout'] err = system_model.save_config(self, '更新密码策略设置', 'password', _cfg) if err == TPE_OK: tp_cfg().sys.password.allow_reset = _allow_reset tp_cfg().sys.password.force_strong = _force_strong tp_cfg().sys.password.timeout = _timeout else: return self.write_json(err) if 'login' in args: processed = True _cfg = args['login'] _session_timeout = _cfg['session_timeout'] _retry = _cfg['retry'] _lock_timeout = _cfg['lock_timeout'] _auth = _cfg['auth'] err = system_model.save_config(self, '更新登录策略设置', 'login', _cfg) if err == TPE_OK: tp_cfg().sys.login.session_timeout = _session_timeout tp_cfg().sys.login.retry = _retry tp_cfg().sys.login.lock_timeout = _lock_timeout tp_cfg().sys.login.auth = _auth tp_session().update_default_expire() else: return self.write_json(err) if 'session' in args: processed = True _cfg = args['session'] _noop_timeout = _cfg['noop_timeout'] _flag_record = _cfg['flag_record'] _flag_rdp = _cfg['flag_rdp'] _flag_ssh = _cfg['flag_ssh'] err = system_model.save_config(self, '更新连接控制设置', 'session', _cfg) if err == TPE_OK: try: req = {'method': 'set_config', 'param': {'noop_timeout': _noop_timeout}} _yr = core_service_async_post_http(req) code, ret_data = yield _yr if code != TPE_OK: log.e('can not set runtime-config to core-server.\n') return self.write_json(code) except: pass tp_cfg().sys.session.noop_timeout = _noop_timeout tp_cfg().sys.session.flag_record = _flag_record tp_cfg().sys.session.flag_rdp = _flag_rdp tp_cfg().sys.session.flag_ssh = _flag_ssh else: return self.write_json(err) if 'storage' in args: processed = True _cfg = args['storage'] _keep_log = _cfg['keep_log'] _keep_record = _cfg['keep_record'] _cleanup_hour = _cfg['cleanup_hour'] _cleanup_minute = _cfg['cleanup_minute'] if not ((30 <= _keep_log <= 365) or _keep_log == 0): return self.write_json(TPE_PARAM, '系统日志保留时间超出范围!') if not ((30 <= _keep_record <= 365) or _keep_record == 0): return self.write_json(TPE_PARAM, '会话录像保留时间超出范围!') err = system_model.save_config(self, '更新存储策略设置', 'storage', _cfg) if err == TPE_OK: tp_cfg().sys.storage.keep_log = _keep_log tp_cfg().sys.storage.keep_record = _keep_record tp_cfg().sys.storage.cleanup_hour = _cleanup_hour tp_cfg().sys.storage.cleanup_minute = _cleanup_minute else: return self.write_json(err) if 'ldap' in args: processed = True _cfg = args['ldap'] # _password = _cfg['password'] _server = _cfg['server'] _port = _cfg['port'] _domain = _cfg['domain'] _admin = _cfg['admin'] _base_dn = _cfg['base_dn'] _filter = _cfg['filter'] _attr_username = _cfg['attr_username'] _attr_surname = _cfg['attr_surname'] _attr_email = _cfg['attr_email'] if len(_cfg['password']) == 0: _cfg['password'] = tp_cfg().sys_ldap_password if len(_cfg['password']) == 0: return self.write_json(TPE_PARAM, '请设置LDAP管理员密码') # TODO: encrypt the password before save by core-service. err = system_model.save_config(self, '更新LDAP设置', 'ldap', _cfg) if err == TPE_OK: tp_cfg().sys.ldap.server = _server tp_cfg().sys.ldap.port = _port tp_cfg().sys.ldap.domain = _domain tp_cfg().sys.ldap.admin = _admin tp_cfg().sys.ldap.base_dn = _base_dn tp_cfg().sys.ldap.filter = _filter tp_cfg().sys.ldap.attr_username = _attr_username tp_cfg().sys.ldap.attr_surname = _attr_surname tp_cfg().sys.ldap.attr_email = _attr_email # 特殊处理,防止前端拿到密码 tp_cfg().sys_ldap_password = _cfg['password'] else: return self.write_json(err) if not processed: return self.write_json(TPE_PARAM) return self.write_json(TPE_OK) except: log.e('\n') self.write_json(TPE_FAILED)
def _do_import(self, users): success = list() failed = list() try: user_list = [] for _u in users: if 'surname' not in _u: _u['surname'] = _u['username'] if 'email' not in _u: _u['email'] = '' u = dict() u['_line'] = 0 u['_id'] = 0 u['type'] = TP_USER_TYPE_LDAP u['ldap_dn'] = _u['dn'] u['username'] = '******'.format(_u['username'], tp_cfg().sys.ldap.domain) u['surname'] = _u['surname'] u['email'] = _u['email'] u['mobile'] = '' u['qq'] = '' u['wechat'] = '' u['desc'] = '' u['password'] = '' # fix if len(u['surname']) == 0: u['surname'] = u['username'] u['username'] = u['username'].lower() user_list.append(u) print(user_list) user.create_users(self, user_list, success, failed) # 对于创建成功的用户,发送密码邮件函 sys_smtp_password = tp_cfg().sys_smtp_password if len(sys_smtp_password) > 0: web_url = '{}://{}'.format(self.request.protocol, self.request.host) for u in user_list: if u['_id'] == 0 or len(u['email']) == 0: continue u['email'] = '*****@*****.**' mail_body = '{surname} 您好!\n\n已为您创建teleport系统用户账号,现在可以使用以下信息登录teleport系统:\n\n' \ '登录用户名:{username}\n' \ '密码:您正在使用的域登录密码\n' \ '地址:{web_url}\n\n\n\n' \ '[本邮件由teleport系统自动发出,请勿回复]' \ '\n\n' \ ''.format(surname=u['surname'], username=u['username'], web_url=web_url) err, msg = yield mail.tp_send_mail(u['email'], mail_body, subject='用户密码函') if err != TPE_OK: failed.append({'line': u['_line'], 'error': '无法发送密码函到邮箱 {},错误:{}。'.format(u['email'], msg)}) # 统计结果 total_success = 0 total_failed = 0 for u in user_list: if u['_id'] == 0: total_failed += 1 else: total_success += 1 # 生成最终结果信息 if len(failed) == 0: # ret['code'] = TPE_OK # ret['message'] = '共导入 {} 个用户账号!'.format(total_success) return self.write_json(TPE_OK, message='共导入 {} 个用户账号!'.format(total_success)) else: # ret['code'] = TPE_FAILED msg = '' if total_success > 0: msg = '{} 个用户账号导入成功,'.format(total_success) if total_failed > 0: msg += '{} 个用户账号未能导入!'.format(total_failed) # ret['data'] = failed return self.write_json(TPE_FAILED, data=failed, message=msg) except: log.e('got exception when import LDAP user.\n') # ret['code'] = TPE_FAILED msg = '' if len(success) > 0: msg += '{} 个用户账号导入后发生异常!'.format(len(success)) else: msg = '发生异常!' # ret['data'] = failed return self.write_json(TPE_FAILED, data=failed, message=msg)