[ssh] fix not works with pub-key auth mode.

[web] support alive check with PING.
dev
Apex Liu 2021-05-19 01:02:22 +08:00
parent 9abde183f9
commit aee95b2cba
8 changed files with 118 additions and 59 deletions

View File

@ -3,11 +3,9 @@ project(teleport)
include(CMakeCfg.txt) include(CMakeCfg.txt)
#if (OS_LINUX) if (OS_LINUX)
# add_subdirectory(server/tp_web/src)
#endif()
add_subdirectory(server/tp_web/src) add_subdirectory(server/tp_web/src)
endif()
add_subdirectory(server/tp_core/core) add_subdirectory(server/tp_core/core)
add_subdirectory(server/tp_core/protocol/ssh) add_subdirectory(server/tp_core/protocol/ssh)

View File

@ -54,6 +54,7 @@ else:win32:CONFIG(debug, debug|release): {
macx: { macx: {
CONFIG+=sdk_no_version_check
INCLUDEPATH += $$PWD/../../external/macos/release/include INCLUDEPATH += $$PWD/../../external/macos/release/include
} }
macx:CONFIG(release, debug|release): { macx:CONFIG(release, debug|release): {

View File

@ -548,11 +548,11 @@ int SshSession::_do_auth(const char* user, const char* secret)
if (!m_conn_info) if (!m_conn_info)
{ {
EXLOGE("[%s] no such session id: %s\n", m_dbg_name.c_str(), m_sid.c_str());
_set_last_error(TP_SESS_STAT_ERR_SESSION); _set_last_error(TP_SESS_STAT_ERR_SESSION);
m_auth_err_msg = "invalid session id: '"; m_auth_err_msg = "invalid session id: '";
m_auth_err_msg += m_sid; m_auth_err_msg += m_sid;
m_auth_err_msg += "'."; m_auth_err_msg += "'.";
EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
@ -565,11 +565,11 @@ int SshSession::_do_auth(const char* user, const char* secret)
if (m_conn_info->protocol_type != TP_PROTOCOL_TYPE_SSH) if (m_conn_info->protocol_type != TP_PROTOCOL_TYPE_SSH)
{ {
EXLOGE("[ssh] session '%s' is not for SSH.\n", m_sid.c_str());
_set_last_error(TP_SESS_STAT_ERR_INTERNAL); _set_last_error(TP_SESS_STAT_ERR_INTERNAL);
m_auth_err_msg = "session "; m_auth_err_msg = "session ";
m_auth_err_msg += m_sid; m_auth_err_msg += m_sid;
m_auth_err_msg += " is not for SSH."; m_auth_err_msg += " is not for SSH.";
EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
@ -577,9 +577,9 @@ int SshSession::_do_auth(const char* user, const char* secret)
if ((m_acc_name.empty() && _name == "INTERACTIVE_USER") if ((m_acc_name.empty() && _name == "INTERACTIVE_USER")
|| (!m_acc_name.empty() && _name != "INTERACTIVE_USER")) || (!m_acc_name.empty() && _name != "INTERACTIVE_USER"))
{ {
EXLOGE("[%s] conflict account info.\n", m_dbg_name.c_str());
_set_last_error(TP_SESS_STAT_ERR_SESSION); _set_last_error(TP_SESS_STAT_ERR_SESSION);
m_auth_err_msg = "account name of remote host should not be 'INTERACTIVE_USER'."; m_auth_err_msg = "account name of remote host should not be 'INTERACTIVE_USER'.";
EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
@ -640,13 +640,13 @@ int SshSession::_do_auth(const char* user, const char* secret)
int rc = ssh_connect(m_rs_tp2srv); int rc = ssh_connect(m_rs_tp2srv);
if (rc != SSH_OK) if (rc != SSH_OK)
{ {
EXLOGE("[%s] can not connect to real SSH server %s. %s\n", m_dbg_name.c_str(), m_dbg_server.c_str(), ssh_get_error(m_rs_tp2srv));
_set_last_error(TP_SESS_STAT_ERR_CONNECT); _set_last_error(TP_SESS_STAT_ERR_CONNECT);
m_auth_err_msg = "can not connect to remote host "; m_auth_err_msg = "can not connect to remote host ";
m_auth_err_msg += m_dbg_server; m_auth_err_msg += m_dbg_server;
m_auth_err_msg += ", "; m_auth_err_msg += ", ";
m_auth_err_msg += ssh_get_error(m_rs_tp2srv); m_auth_err_msg += ssh_get_error(m_rs_tp2srv);
m_auth_err_msg += "."; m_auth_err_msg += ".";
EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
@ -693,11 +693,11 @@ int SshSession::_do_auth(const char* user, const char* secret)
{ {
if (!(((auth_methods & SSH_AUTH_METHOD_INTERACTIVE) == SSH_AUTH_METHOD_INTERACTIVE) || ((auth_methods & SSH_AUTH_METHOD_PASSWORD) == SSH_AUTH_METHOD_PASSWORD))) if (!(((auth_methods & SSH_AUTH_METHOD_INTERACTIVE) == SSH_AUTH_METHOD_INTERACTIVE) || ((auth_methods & SSH_AUTH_METHOD_PASSWORD) == SSH_AUTH_METHOD_PASSWORD)))
{ {
EXLOGE("[%s] configure to auth by password, but remote host not allow such auth mode.\n", m_dbg_name.c_str());
_set_last_error(TP_SESS_STAT_ERR_AUTH_TYPE); _set_last_error(TP_SESS_STAT_ERR_AUTH_TYPE);
m_auth_err_msg = "both password and interactive authorize methods are not allowed by remote host "; m_auth_err_msg = "both password and interactive authorize methods are not allowed by remote host ";
m_auth_err_msg += m_dbg_server; m_auth_err_msg += m_dbg_server;
m_auth_err_msg += "."; m_auth_err_msg += ".";
EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
@ -734,6 +734,7 @@ int SshSession::_do_auth(const char* user, const char* secret)
m_auth_err_msg += m_dbg_server; m_auth_err_msg += m_dbg_server;
m_auth_err_msg += " with interactive authorize method failed, "; m_auth_err_msg += " with interactive authorize method failed, ";
m_auth_err_msg += ssh_get_error(m_rs_tp2srv); m_auth_err_msg += ssh_get_error(m_rs_tp2srv);
EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
break; break;
} }
@ -760,7 +761,6 @@ int SshSession::_do_auth(const char* user, const char* secret)
rc = ssh_userauth_kbdint_setanswer(m_rs_tp2srv, i, m_acc_secret.c_str()); rc = ssh_userauth_kbdint_setanswer(m_rs_tp2srv, i, m_acc_secret.c_str());
if (rc < 0) if (rc < 0)
{ {
EXLOGE("[%s] invalid password for interactive mode to login to remote host %s.\n", m_dbg_name.c_str(), m_dbg_server.c_str());
_set_last_error(TP_SESS_STAT_ERR_AUTH_DENIED); _set_last_error(TP_SESS_STAT_ERR_AUTH_DENIED);
if (!m_auth_err_msg.empty()) if (!m_auth_err_msg.empty())
@ -770,9 +770,7 @@ int SshSession::_do_auth(const char* user, const char* secret)
m_auth_err_msg += " with interactive authorize method failed, "; m_auth_err_msg += " with interactive authorize method failed, ";
m_auth_err_msg += ssh_get_error(m_rs_tp2srv); m_auth_err_msg += ssh_get_error(m_rs_tp2srv);
// m_auth_err_msg = "failed to login remote host "; EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
// m_auth_err_msg += m_dbg_server;
// m_auth_err_msg += " with interactive authorize method, access denied.";
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
@ -819,77 +817,93 @@ int SshSession::_do_auth(const char* user, const char* secret)
} }
} }
EXLOGE("[%s] auth failed, mode=password/interactive, remote-host=%s.\n", m_dbg_name.c_str(), m_dbg_server.c_str());
_set_last_error(TP_SESS_STAT_ERR_AUTH_DENIED); _set_last_error(TP_SESS_STAT_ERR_AUTH_DENIED);
// if(!m_auth_err_msg.empty())
// m_auth_err_msg += "\r\n";
// m_auth_err_msg += "login remote host ";
// m_auth_err_msg += m_dbg_server;
// m_auth_err_msg += " failed, ";
// m_auth_err_msg += ssh_get_error(m_rs_tp2srv);
m_auth_err_msg += "failed to login remote host "; m_auth_err_msg += "failed to login remote host ";
m_auth_err_msg += m_dbg_server; m_auth_err_msg += m_dbg_server;
m_auth_err_msg += " with interactive and password authorize methods, access denied."; m_auth_err_msg += " with interactive and password authorize methods, access denied.";
EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
else if (m_auth_type == TP_AUTH_TYPE_PRIVATE_KEY) else if (m_auth_type == TP_AUTH_TYPE_PRIVATE_KEY)
{ {
if ((auth_methods & SSH_AUTH_METHOD_PUBLICKEY) != SSH_AUTH_METHOD_PUBLICKEY) if ((auth_methods & SSH_AUTH_METHOD_PUBLICKEY) != SSH_AUTH_METHOD_PUBLICKEY)
{ {
EXLOGE("[%s] configure to use public-key auth, but remote host not allow such auth mode.\n", m_dbg_name.c_str());
_set_last_error(TP_SESS_STAT_ERR_AUTH_TYPE); _set_last_error(TP_SESS_STAT_ERR_AUTH_TYPE);
m_auth_err_msg = "public-key-authorize method is not allowed by remote host "; m_auth_err_msg = "public-key-authorize method is not allowed by remote host ";
m_auth_err_msg += m_dbg_server; m_auth_err_msg += m_dbg_server;
m_auth_err_msg += "."; m_auth_err_msg += ".";
EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
ssh_key key = nullptr; ssh_key key = nullptr;
if (SSH_OK != ssh_pki_import_privkey_base64(m_acc_secret.c_str(), nullptr, nullptr, nullptr, &key)) if (SSH_OK != ssh_pki_import_privkey_base64(m_acc_secret.c_str(), nullptr, nullptr, nullptr, &key))
{ {
EXLOGE("[%s] can not import private-key for auth.\n", m_dbg_name.c_str());
_set_last_error(TP_SESS_STAT_ERR_BAD_SSH_KEY); _set_last_error(TP_SESS_STAT_ERR_BAD_SSH_KEY);
m_auth_err_msg = "can not load private key for login remote host "; m_auth_err_msg = "can not load private key for login remote host ";
m_auth_err_msg += m_dbg_server; m_auth_err_msg += m_dbg_server;
m_auth_err_msg += "."; m_auth_err_msg += ", ";
EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
int retry_count = 0;
rc = ssh_userauth_publickey(m_rs_tp2srv, nullptr, key); rc = ssh_userauth_publickey(m_rs_tp2srv, nullptr, key);
ssh_key_free(key); for (;;)
{
if (rc == SSH_AUTH_SUCCESS) if (rc == SSH_AUTH_SUCCESS)
{ {
EXLOGW("[%s] login with public-key mode succeeded.\n", m_dbg_name.c_str()); EXLOGW("[%s] login with public-key mode succeeded.\n", m_dbg_name.c_str());
m_auth_passed = true; m_auth_passed = true;
ssh_key_free(key);
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
else if (rc == SSH_AUTH_AGAIN)
{
retry_count += 1;
if (retry_count >= 5)
break;
ex_sleep_ms(100);
rc = ssh_userauth_publickey(m_rs_tp2srv, nullptr, key);
continue;
}
EXLOGE("[%s] failed to login with password mode, got %d.\n", m_dbg_name.c_str(), rc);
break;
}
ssh_key_free(key);
EXLOGE("[%s] auth failed, mode=public-key, remote-host=%s.\n", m_dbg_name.c_str(), m_dbg_server.c_str());
_set_last_error(TP_SESS_STAT_ERR_AUTH_DENIED); _set_last_error(TP_SESS_STAT_ERR_AUTH_DENIED);
m_auth_err_msg = "failed to login remote host ";
if (!m_auth_err_msg.empty())
m_auth_err_msg += "\r\n";
m_auth_err_msg += "login remote host ";
m_auth_err_msg += m_dbg_server; m_auth_err_msg += m_dbg_server;
m_auth_err_msg += " with public-key authorize method, access denied."; m_auth_err_msg += " with public-key authorize method failed. ";
m_auth_err_msg += ssh_get_error(m_rs_tp2srv);
EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
else if (m_auth_type == TP_AUTH_TYPE_NONE) else if (m_auth_type == TP_AUTH_TYPE_NONE)
{ {
EXLOGE("[%s] configure to login without auth, not allowed.\n", m_dbg_name.c_str());
_set_last_error(TP_SESS_STAT_ERR_AUTH_DENIED); _set_last_error(TP_SESS_STAT_ERR_AUTH_DENIED);
m_auth_err_msg = "no authorize method for login remote host "; m_auth_err_msg = "no authorize method for login remote host ";
m_auth_err_msg += m_dbg_server; m_auth_err_msg += m_dbg_server;
m_auth_err_msg += "."; m_auth_err_msg += ".";
EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
else else
{ {
EXLOGE("[%s] unknown auth mode: %d.\n", m_dbg_name.c_str(), m_auth_type);
_set_last_error(TP_SESS_STAT_ERR_AUTH_DENIED); _set_last_error(TP_SESS_STAT_ERR_AUTH_DENIED);
m_auth_err_msg = "unknown authorize method for login remote host "; m_auth_err_msg = "unknown authorize method for login remote host ";
m_auth_err_msg += m_dbg_server; m_auth_err_msg += m_dbg_server;
m_auth_err_msg += "."; m_auth_err_msg += ".";
EXLOGE("[%s] %s\n", m_dbg_name.c_str(), m_auth_err_msg.c_str());
return SSH_AUTH_SUCCESS; return SSH_AUTH_SUCCESS;
} }
} }

View File

@ -85,15 +85,15 @@ $app.create_controls = function (cb_stack) {
render: 'account', render: 'account',
fields: {count: 'acc_count'} fields: {count: 'acc_count'}
}, },
{ // {
title: "在线", // title: "在线",
key: "_alive", // key: "_alive",
sort: false, // sort: false,
width: 90, // width: 90,
align: 'center', // align: 'center',
render: 'host_alive', // render: 'host_alive',
fields: {id: 'id', alive: '_alive', alive_info: '_alive_info'} // fields: {id: 'id', alive: '_alive', alive_info: '_alive_info'}
}, // },
{ {
title: "状态", title: "状态",
key: "state", key: "state",
@ -121,6 +121,18 @@ $app.create_controls = function (cb_stack) {
on_cell_created: $app.on_table_host_cell_created on_cell_created: $app.on_table_host_cell_created
}; };
if ($app.options._check_host_alive) {
table_host_options.columns.splice(-2, 0, {
title: "在线",
key: "_alive",
sort: false,
width: 60,
align: 'center',
render: 'host_alive',
fields: {id: 'id', alive: '_alive', alive_info: '_alive_info'}
})
}
$app.table_host = $tp.create_table(table_host_options); $app.table_host = $tp.create_table(table_host_options);
cb_stack cb_stack
.add($app.table_host.load_data) .add($app.table_host.load_data)
@ -355,7 +367,10 @@ $app.on_table_host_render_created = function (render) {
render.host_alive = function (row_id, fields) { render.host_alive = function (row_id, fields) {
var _style, _alive; var _style, _alive;
if (fields.alive === 0) { if (fields.alive === -1) {
_style = 'alive-unknown';
_alive = '功能未启用';
} else if (fields.alive === 0) {
_style = 'alive-unknown'; _style = 'alive-unknown';
_alive = '正在检测,请稍后刷新页面'; _alive = '正在检测,请稍后刷新页面';
} else if (fields.alive === 1) { } else if (fields.alive === 1) {

View File

@ -298,6 +298,12 @@ class AppConfig(BaseAppConfig):
'DO NOT FORGET update this setting if you modified rpc::bind-port in core.ini.\n' 'DO NOT FORGET update this setting if you modified rpc::bind-port in core.ini.\n'
'core-server-rpc=http://127.0.0.1:52080/rpc' 'core-server-rpc=http://127.0.0.1:52080/rpc'
) )
# check_host_alive
self.set_default('common::check-host-alive', 0,
'0/1, default to 0.\n\n'
'when enable, tp-web will check alive state of remote host with ICMP(ping).\n'
'check-host-alive=0'
)
self.set_default('database::type', 'sqlite', self.set_default('database::type', 'sqlite',
'database in use, should be sqlite/mysql, default to sqlite.\n' 'database in use, should be sqlite/mysql, default to sqlite.\n'
'type=sqlite' 'type=sqlite'
@ -355,6 +361,9 @@ class AppConfig(BaseAppConfig):
if _tmp_str is not None: if _tmp_str is not None:
self.set_kv('common::core-server-rpc', _tmp_str) self.set_kv('common::core-server-rpc', _tmp_str)
_tmp_bool = _sec.getint('check-host-alive', False)
self.set_kv('common::check-host-alive', _tmp_bool)
_sec = cfg_parser['database'] _sec = cfg_parser['database']
_tmp_str = _sec.get('type', None) _tmp_str = _sec.get('type', None)

View File

@ -85,6 +85,9 @@ class HostAlive(object):
self._lock = threading.RLock() self._lock = threading.RLock()
def init(self): def init(self):
if not tp_cfg().common.check_host_alive:
return True
icmp_protocol = socket.getprotobyname('icmp') icmp_protocol = socket.getprotobyname('icmp')
try: try:
self._socket_ping = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp_protocol) self._socket_ping = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp_protocol)
@ -112,11 +115,17 @@ class HostAlive(object):
return True return True
def stop(self): def stop(self):
if not tp_cfg().common.check_host_alive:
return
self._need_stop = True self._need_stop = True
if self._thread_recv_ping_result is not None: if self._thread_recv_ping_result is not None:
self._thread_recv_ping_result.join() self._thread_recv_ping_result.join()
def add_host(self, host_ip, method=0, param=None, check_now=False): 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: if param is None:
param = {} param = {}
@ -139,12 +148,18 @@ class HostAlive(object):
log.w('Warning: check alive method not implement.\n') log.w('Warning: check alive method not implement.\n')
def remove_host(self, host_ip): def remove_host(self, host_ip):
if not tp_cfg().common.check_host_alive:
return
with self._lock: with self._lock:
if host_ip not in self._states: if host_ip not in self._states:
return return
del self._states[host_ip] del self._states[host_ip]
def get_states(self, host_ip_list): def get_states(self, host_ip_list):
if not tp_cfg().common.check_host_alive:
return {}
with self._lock: with self._lock:
ret = dict() ret = dict()
time_now = int(time.time()) time_now = int(time.time())

View File

@ -129,12 +129,15 @@ class WebApp:
if not tp_session().init(): if not tp_session().init():
log.e('can not initialize session manager.\n') log.e('can not initialize session manager.\n')
return 0 return 0
if not tp_stats().init(): if not tp_stats().init():
log.e('can not initialize system status collector.\n') log.e('can not initialize system status collector.\n')
return 0 return 0
# if not tp_host_alive().init():
# log.e('can not initialize host state inspector.\n') if cfg.common.check_host_alive:
# return 0 if not tp_host_alive().init():
log.e('can not initialize host state inspector.\n')
return 0
settings = { settings = {
# #
@ -189,7 +192,8 @@ class WebApp:
except: except:
log.e('\n') log.e('\n')
# tp_host_alive().stop() if tp_cfg().common.check_host_alive:
tp_host_alive().stop()
tp_cron().stop() tp_cron().stop()
return 0 return 0

View File

@ -28,7 +28,8 @@ class HostListHandler(TPBaseHandler):
err, groups = group.get_host_groups_for_user(self.current_user['id'], self.current_user['privilege']) err, groups = group.get_host_groups_for_user(self.current_user['id'], self.current_user['privilege'])
param = { param = {
'host_groups': groups 'host_groups': groups,
'_check_host_alive': tp_cfg().common.check_host_alive
} }
self.render('asset/host-list.mako', page_param=json.dumps(param)) self.render('asset/host-list.mako', page_param=json.dumps(param))
@ -111,6 +112,8 @@ class DoGetHostsHandler(TPBaseJsonHandler):
else: else:
ip_list.append(row_data[x]['ip']) ip_list.append(row_data[x]['ip'])
ip_list = list(set(ip_list)) ip_list = list(set(ip_list))
if tp_cfg().common.check_host_alive:
host_states = tp_host_alive().get_states(ip_list) host_states = tp_host_alive().get_states(ip_list)
for x in range(len(row_data)): for x in range(len(row_data)):
if row_data[x]['router_ip'] != '': if row_data[x]['router_ip'] != '':