From d92cf2f469f25e1c02922e71d2bffe01951cf1f4 Mon Sep 17 00:00:00 2001 From: Apex Liu Date: Fri, 27 May 2022 19:16:57 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E9=9B=86=E6=88=90=E6=89=80=E9=9C=80=E5=AF=86=E9=92=A5=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=8A=9F=E8=83=BD=E5=AE=8C=E6=88=90=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/builder/build-external.py | 1 + external/version.ini | 4 +- server/tp_core/core/ts_web_rpc.cpp | 477 +++++++++--------- server/tp_core/protocol/ssh/ssh_session.cpp | 2 +- .../www/teleport/static/js/system/config.js | 9 + .../www/teleport/webroot/app/base/extsrv.py | 82 --- .../teleport/webroot/app/base/integration.py | 102 ++++ .../www/teleport/webroot/app/base/webapp.py | 10 +- .../teleport/webroot/app/controller/api_v1.py | 11 +- .../teleport/webroot/app/controller/api_v2.py | 13 +- .../teleport/webroot/app/controller/ops.py | 22 +- .../teleport/webroot/app/controller/system.py | 19 +- .../www/teleport/webroot/app/model/system.py | 28 +- 13 files changed, 429 insertions(+), 351 deletions(-) delete mode 100644 server/www/teleport/webroot/app/base/extsrv.py create mode 100644 server/www/teleport/webroot/app/base/integration.py diff --git a/build/builder/build-external.py b/build/builder/build-external.py index bd719c5..6e413ea 100644 --- a/build/builder/build-external.py +++ b/build/builder/build-external.py @@ -942,6 +942,7 @@ def main(): if command == 'ext-client': builder.build_jsoncpp() builder.build_mongoose() + builder.build_zlib() builder.build_openssl() elif command == 'ext-server': builder.prepare_python() diff --git a/external/version.ini b/external/version.ini index e54507a..d288fb3 100644 --- a/external/version.ini +++ b/external/version.ini @@ -10,7 +10,7 @@ mbedtls = 2.16.3 jsoncpp = 1.9.2 ; https://github.com/cesanta/mongoose/releases mongoose = 6.16 -; https://www.zlib.net/zlib1211.zip -zlib = 1.2.11,1211 +; https://www.zlib.net/zlib1212.zip +zlib = 1.2.12,1212 ; https://git.libssh.org/projects/libssh.git/ libssh = 0.8.9 diff --git a/server/tp_core/core/ts_web_rpc.cpp b/server/tp_core/core/ts_web_rpc.cpp index 8785290..55197f8 100644 --- a/server/tp_core/core/ts_web_rpc.cpp +++ b/server/tp_core/core/ts_web_rpc.cpp @@ -8,350 +8,355 @@ bool ts_web_rpc_register_core() { - //Json::FastWriter json_writer; - Json::Value jreq; - jreq["method"] = "register_core"; - jreq["param"]["rpc"] = g_env.core_server_rpc; + //Json::FastWriter json_writer; + Json::Value jreq; + jreq["method"] = "register_core"; + jreq["param"]["rpc"] = g_env.core_server_rpc; - ex_astr json_param; - //json_param = json_writer.write(jreq); + ex_astr json_param; + //json_param = json_writer.write(jreq); Json::StreamWriterBuilder jwb; std::unique_ptr jwriter(jwb.newStreamWriter()); ex_aoss os; jwriter->write(jreq, &os); json_param = os.str(); - ex_astr param; - ts_url_encode(json_param.c_str(), param); + ex_astr param; + ts_url_encode(json_param.c_str(), param); - ex_astr url = g_env.web_server_rpc; - url += "?"; - url += param; + ex_astr url = g_env.web_server_rpc; + url += "?"; + url += param; - ex_astr body; - return ts_http_get(url, body); + ex_astr body; + return ts_http_get(url, body); } int ts_web_rpc_get_conn_info(int conn_id, TS_CONNECT_INFO& info) { - //Json::FastWriter json_writer; - Json::Value jreq; - jreq["method"] = "get_conn_info"; - jreq["param"]["conn_id"] = conn_id; + //Json::FastWriter json_writer; + Json::Value jreq; + jreq["method"] = "get_conn_info"; + jreq["param"]["conn_id"] = conn_id; - ex_astr json_param; - //json_param = json_writer.write(jreq); + ex_astr json_param; + //json_param = json_writer.write(jreq); Json::StreamWriterBuilder jwb; std::unique_ptr jwriter(jwb.newStreamWriter()); ex_aoss os; jwriter->write(jreq, &os); json_param = os.str(); - ex_astr param; - ts_url_encode(json_param.c_str(), param); + ex_astr param; + ts_url_encode(json_param.c_str(), param); - ex_astr url = g_env.web_server_rpc; - url += "?"; - url += param; + ex_astr url = g_env.web_server_rpc; + url += "?"; + url += param; - ex_astr body; - if (!ts_http_get(url, body)) - { - EXLOGE("[core] get conn info from web-server failed: can not connect to web-server.\n"); - return TPE_NETWORK; - } - if (body.length() == 0) { - EXLOGE("[core] get conn info from web-server failed: got nothing.\n"); - return TPE_NETWORK; - } + ex_astr body; + if (!ts_http_get(url, body)) + { + EXLOGE("[core] get conn info from web-server failed: can not connect to web-server.\n"); + return TPE_NETWORK; + } + if (body.length() == 0) + { + EXLOGE("[core] get conn info from web-server failed: got nothing.\n"); + return TPE_NETWORK; + } - //Json::Reader jreader; - Json::Value jret; + //Json::Reader jreader; + Json::Value jret; - //if (!jreader.parse(body.c_str(), jret)) + //if (!jreader.parse(body.c_str(), jret)) Json::CharReaderBuilder jcrb; std::unique_ptr const jreader(jcrb.newCharReader()); - const char *str_json_begin = body.c_str(); + const char* str_json_begin = body.c_str(); ex_astr err; //if (!jreader.parse(func_args.c_str(), jsRoot)) { if (!jreader->parse(str_json_begin, str_json_begin + body.length(), &jret, &err)) - return TPE_PARAM; - if (!jret.isObject()) - return TPE_PARAM; - if (!jret["data"].isObject()) - return TPE_PARAM; + return TPE_PARAM; + if (!jret.isObject()) + return TPE_PARAM; + if (!jret["data"].isObject()) + return TPE_PARAM; - Json::Value& _jret = jret["data"]; + Json::Value& _jret = jret["data"]; - if(!_jret["user_id"].isInt()) + if (!_jret["user_id"].isInt()) EXLOGE("connection info: need `user_id`.\n"); - if(!_jret["host_id"].isInt()) + if (!_jret["host_id"].isInt()) EXLOGE("connection info: need `host_id`.\n"); - if(!_jret["acc_id"].isInt()) + if (!_jret["acc_id"].isInt()) EXLOGE("connection info: need `acc_id`.\n"); - if(!_jret["conn_port"].isInt()) + if (!_jret["conn_port"].isInt()) EXLOGE("connection info: need `conn_port`.\n"); - if(!_jret["protocol_type"].isInt()) + if (!_jret["protocol_type"].isInt()) EXLOGE("connection info: need `protocol_type`.\n"); - if(!_jret["protocol_sub_type"].isInt()) + if (!_jret["protocol_sub_type"].isInt()) EXLOGE("connection info: need `protocol_sub_type`.\n"); - if(!_jret["auth_type"].isInt()) + if (!_jret["auth_type"].isInt()) EXLOGE("connection info: need `auth_type`.\n"); - if (!_jret["protocol_flag"].isUInt()) - EXLOGE("connection info: need `protocol_flag`.\n"); - if (!_jret["record_flag"].isUInt()) - EXLOGE("connection info: need `record_flag`.\n"); - if (!_jret["_enc"].isInt()) + if (!_jret["protocol_flag"].isUInt()) + EXLOGE("connection info: need `protocol_flag`.\n"); + if (!_jret["record_flag"].isUInt()) + EXLOGE("connection info: need `record_flag`.\n"); + if (!_jret["_enc"].isInt()) EXLOGE("connection info: need `_enc`.\n"); - if(!_jret["user_username"].isString()) + if (!_jret["user_username"].isString()) EXLOGE("connection info: need `user_username`.\n"); - if(!_jret["host_ip"].isString()) + if (!_jret["host_ip"].isString()) EXLOGE("connection info: need `host_ip`.\n"); - if(!_jret["conn_ip"].isString()) + if (!_jret["conn_ip"].isString()) EXLOGE("connection info: need `conn_ip`.\n"); - if(!_jret["client_ip"].isString()) + if (!_jret["client_ip"].isString()) EXLOGE("connection info: need `client_ip`.\n"); - if(!_jret["acc_username"].isString()) + if (!_jret["acc_username"].isString()) EXLOGE("connection info: need `acc_username`.\n"); - if(!_jret["acc_secret"].isString()) + if (!_jret["acc_secret"].isString()) EXLOGE("connection info: need `acc_secret`.\n"); - if(!_jret["username_prompt"].isString()) + if (!_jret["username_prompt"].isString()) EXLOGE("connection info: need `username_prompt`.\n"); - if(!_jret["password_prompt"].isString()) + if (!_jret["password_prompt"].isString()) EXLOGE("connection info: need `password_prompt`.\n"); - if ( - !_jret["user_id"].isInt() - || !_jret["host_id"].isInt() - || !_jret["acc_id"].isInt() - || !_jret["conn_port"].isInt() - || !_jret["protocol_type"].isInt() - || !_jret["protocol_sub_type"].isInt() - || !_jret["auth_type"].isInt() - || !_jret["protocol_flag"].isUInt() - || !_jret["record_flag"].isUInt() - || !_jret["_enc"].isInt() + if ( + !_jret["user_id"].isInt() + || !_jret["host_id"].isInt() + || !_jret["acc_id"].isInt() + || !_jret["conn_port"].isInt() + || !_jret["protocol_type"].isInt() + || !_jret["protocol_sub_type"].isInt() + || !_jret["auth_type"].isInt() + || !_jret["protocol_flag"].isUInt() + || !_jret["record_flag"].isUInt() + || !_jret["_enc"].isInt() - || !_jret["user_username"].isString() - || !_jret["host_ip"].isString() - || !_jret["conn_ip"].isString() - || !_jret["client_ip"].isString() - || !_jret["acc_username"].isString() - || !_jret["acc_secret"].isString() - || !_jret["username_prompt"].isString() - || !_jret["password_prompt"].isString() - ) - { - EXLOGE("got connection info from web-server, but not all info valid.\n"); - return TPE_PARAM; - } + || !_jret["user_username"].isString() + || !_jret["host_ip"].isString() + || !_jret["conn_ip"].isString() + || !_jret["client_ip"].isString() + || !_jret["acc_username"].isString() + || !_jret["acc_secret"].isString() + || !_jret["username_prompt"].isString() + || !_jret["password_prompt"].isString() + ) + { + EXLOGE("got connection info from web-server, but not all info valid.\n"); + return TPE_PARAM; + } - int user_id; - int host_id; - int acc_id; - ex_astr user_username;// 申请本次连接的用户名 - ex_astr host_ip;// 真正的远程主机IP(如果是直接连接模式,则与remote_host_ip相同) - ex_astr conn_ip;// 要连接的远程主机的IP(如果是端口映射模式,则为路由主机的IP) - int conn_port;// 要连接的远程主机的端口(如果是端口映射模式,则为路由主机的端口) - ex_astr client_ip; - ex_astr acc_username; // 远程主机的账号 - ex_astr acc_secret;// 远程主机账号的密码(或者私钥) - ex_astr username_prompt; - ex_astr password_prompt; - int protocol_type = 0; - int protocol_sub_type = 0; - int auth_type = 0; - int protocol_flag = 0; - int record_flag = 0; - bool _enc; + int user_id; + int host_id; + int acc_id; + ex_astr user_username;// 申请本次连接的用户名 + ex_astr host_ip;// 真正的远程主机IP(如果是直接连接模式,则与remote_host_ip相同) + ex_astr conn_ip;// 要连接的远程主机的IP(如果是端口映射模式,则为路由主机的IP) + int conn_port;// 要连接的远程主机的端口(如果是端口映射模式,则为路由主机的端口) + ex_astr client_ip; + ex_astr acc_username; // 远程主机的账号 + ex_astr acc_secret;// 远程主机账号的密码(或者私钥) + ex_astr username_prompt; + ex_astr password_prompt; + int protocol_type = 0; + int protocol_sub_type = 0; + int auth_type = 0; + int protocol_flag = 0; + int record_flag = 0; + bool _enc; - user_id = _jret["user_id"].asInt(); - host_id = _jret["host_id"].asInt(); - acc_id = _jret["acc_id"].asInt(); - user_username = _jret["user_username"].asString(); - host_ip = _jret["host_ip"].asString(); - conn_ip = _jret["conn_ip"].asString(); - conn_port = _jret["conn_port"].asInt(); - client_ip = _jret["client_ip"].asString(); - acc_username = _jret["acc_username"].asString(); - acc_secret = _jret["acc_secret"].asString(); - username_prompt = _jret["username_prompt"].asString(); - password_prompt = _jret["password_prompt"].asString(); - protocol_type = _jret["protocol_type"].asInt(); - protocol_sub_type = _jret["protocol_sub_type"].asInt(); - protocol_flag = _jret["protocol_flag"].asUInt(); - record_flag = _jret["record_flag"].asUInt(); - auth_type = _jret["auth_type"].asInt(); - _enc = _jret["_enc"].asBool(); + user_id = _jret["user_id"].asInt(); + host_id = _jret["host_id"].asInt(); + acc_id = _jret["acc_id"].asInt(); + user_username = _jret["user_username"].asString(); + host_ip = _jret["host_ip"].asString(); + conn_ip = _jret["conn_ip"].asString(); + conn_port = _jret["conn_port"].asInt(); + client_ip = _jret["client_ip"].asString(); + acc_username = _jret["acc_username"].asString(); + acc_secret = _jret["acc_secret"].asString(); + username_prompt = _jret["username_prompt"].asString(); + password_prompt = _jret["password_prompt"].asString(); + protocol_type = _jret["protocol_type"].asInt(); + protocol_sub_type = _jret["protocol_sub_type"].asInt(); + protocol_flag = _jret["protocol_flag"].asUInt(); + record_flag = _jret["record_flag"].asUInt(); + auth_type = _jret["auth_type"].asInt(); + _enc = _jret["_enc"].asBool(); - // 进一步判断参数是否合法 - // 注意,account_id可以为-1,表示这是一次测试连接。 - if (user_id <= 0 || host_id <= 0 - || user_username.length() == 0 - || host_ip.length() == 0 || conn_ip.length() == 0 || client_ip.length() == 0 - || conn_port <= 0 || conn_port >= 65535 - || acc_username.length() == 0 - || !(protocol_type == TP_PROTOCOL_TYPE_RDP || protocol_type == TP_PROTOCOL_TYPE_SSH || protocol_type == TP_PROTOCOL_TYPE_TELNET) - || !(auth_type == TP_AUTH_TYPE_NONE || auth_type == TP_AUTH_TYPE_PASSWORD || auth_type == TP_AUTH_TYPE_PRIVATE_KEY) - ) - { - return TPE_PARAM; - } + // 进一步判断参数是否合法 + // 注意,account_id可以为-1,表示这是一次测试连接。 + // if (user_id <= 0 || host_id <= 0 + // || + if (user_username.length() == 0 + || host_ip.length() == 0 || conn_ip.length() == 0 || client_ip.length() == 0 + || conn_port <= 0 || conn_port >= 65535 + || acc_username.length() == 0 + || !(protocol_type == TP_PROTOCOL_TYPE_RDP || protocol_type == TP_PROTOCOL_TYPE_SSH || protocol_type == TP_PROTOCOL_TYPE_TELNET) + || !(auth_type == TP_AUTH_TYPE_NONE || auth_type == TP_AUTH_TYPE_PASSWORD || auth_type == TP_AUTH_TYPE_PRIVATE_KEY) + ) + { + return TPE_PARAM; + } - if(auth_type != TP_AUTH_TYPE_NONE && acc_secret.length() == 0) { - return TPE_PARAM; - } + if (auth_type != TP_AUTH_TYPE_NONE && acc_secret.length() == 0) + { + return TPE_PARAM; + } - if (_enc && !acc_secret.empty()) { - ex_astr _auth; - if (!ts_db_field_decrypt(acc_secret, _auth)) - return TPE_FAILED; + if (_enc && !acc_secret.empty()) + { + ex_astr _auth; + if (!ts_db_field_decrypt(acc_secret, _auth)) + return TPE_FAILED; - acc_secret = _auth; - } + acc_secret = _auth; + } - info.user_id = user_id; - info.host_id = host_id; - info.acc_id = acc_id; - info.user_username = user_username; - info.host_ip = host_ip; - info.conn_ip = conn_ip; - info.conn_port = conn_port; - info.client_ip = client_ip; - info.acc_username = acc_username; - info.acc_secret = acc_secret; - info.username_prompt = username_prompt; - info.password_prompt = password_prompt; - info.protocol_type = protocol_type; - info.protocol_sub_type = protocol_sub_type; - info.auth_type = auth_type; - info.protocol_flag = protocol_flag; - info.record_flag = record_flag; + info.user_id = user_id; + info.host_id = host_id; + info.acc_id = acc_id; + info.user_username = user_username; + info.host_ip = host_ip; + info.conn_ip = conn_ip; + info.conn_port = conn_port; + info.client_ip = client_ip; + info.acc_username = acc_username; + info.acc_secret = acc_secret; + info.username_prompt = username_prompt; + info.password_prompt = password_prompt; + info.protocol_type = protocol_type; + info.protocol_sub_type = protocol_sub_type; + info.auth_type = auth_type; + info.protocol_flag = protocol_flag; + info.record_flag = record_flag; - return TPE_OK; + return TPE_OK; } bool ts_web_rpc_session_begin(TS_CONNECT_INFO& info, int& record_id) { - //Json::FastWriter json_writer; - Json::Value jreq; + //Json::FastWriter json_writer; + Json::Value jreq; - jreq["method"] = "session_begin"; - jreq["param"]["sid"] = info.sid.c_str(); - jreq["param"]["user_id"] = info.user_id; - jreq["param"]["host_id"] = info.host_id; - jreq["param"]["acc_id"] = info.acc_id; - jreq["param"]["user_username"] = info.user_username.c_str(); - jreq["param"]["acc_username"] = info.acc_username.c_str(); - jreq["param"]["host_ip"] = info.host_ip.c_str(); - jreq["param"]["conn_ip"] = info.conn_ip.c_str(); - jreq["param"]["client_ip"] = info.client_ip.c_str(); - //jreq["param"]["sys_type"] = info.sys_type; - jreq["param"]["conn_port"] = info.conn_port; - jreq["param"]["auth_type"] = info.auth_type; - jreq["param"]["protocol_type"] = info.protocol_type; - jreq["param"]["protocol_sub_type"] = info.protocol_sub_type; + jreq["method"] = "session_begin"; + jreq["param"]["sid"] = info.sid.c_str(); + jreq["param"]["user_id"] = info.user_id; + jreq["param"]["host_id"] = info.host_id; + jreq["param"]["acc_id"] = info.acc_id; + jreq["param"]["user_username"] = info.user_username.c_str(); + jreq["param"]["acc_username"] = info.acc_username.c_str(); + jreq["param"]["host_ip"] = info.host_ip.c_str(); + jreq["param"]["conn_ip"] = info.conn_ip.c_str(); + jreq["param"]["client_ip"] = info.client_ip.c_str(); + //jreq["param"]["sys_type"] = info.sys_type; + jreq["param"]["conn_port"] = info.conn_port; + jreq["param"]["auth_type"] = info.auth_type; + jreq["param"]["protocol_type"] = info.protocol_type; + jreq["param"]["protocol_sub_type"] = info.protocol_sub_type; - ex_astr json_param; + ex_astr json_param; Json::StreamWriterBuilder jwb; std::unique_ptr jwriter(jwb.newStreamWriter()); ex_aoss os; jwriter->write(jreq, &os); json_param = os.str(); - ex_astr param; - ts_url_encode(json_param.c_str(), param); + ex_astr param; + ts_url_encode(json_param.c_str(), param); - ex_astr url = g_env.web_server_rpc; - url += "?"; - url += param; + ex_astr url = g_env.web_server_rpc; + url += "?"; + url += param; - ex_astr body; - if (!ts_http_get(url, body)) - { - // EXLOGV("request `rpc::session_begin` from web return: "); - // EXLOGV(body.c_str()); - // EXLOGV("\n"); - return false; - } + ex_astr body; + if (!ts_http_get(url, body)) + { + // EXLOGV("request `rpc::session_begin` from web return: "); + // EXLOGV(body.c_str()); + // EXLOGV("\n"); + return false; + } - Json::Value jret; + Json::Value jret; Json::CharReaderBuilder jcrb; std::unique_ptr const jreader(jcrb.newCharReader()); - const char *str_json_begin = body.c_str(); + const char* str_json_begin = body.c_str(); ex_astr err; if (!jreader->parse(str_json_begin, str_json_begin + body.length(), &jret, &err)) return false; - if (!jret.isObject()) - return false; - if (!jret["data"].isObject()) - return false; - if (!jret["data"]["rid"].isUInt()) - return false; + if (!jret.isObject()) + return false; + if (!jret["data"].isObject()) + return false; + if (!jret["data"]["rid"].isUInt()) + return false; - record_id = jret["data"]["rid"].asUInt(); + record_id = jret["data"]["rid"].asUInt(); - return true; + return true; } -bool ts_web_rpc_session_update(int record_id, int protocol_sub_type, int state) { - //Json::FastWriter json_writer; - Json::Value jreq; - jreq["method"] = "session_update"; - jreq["param"]["rid"] = record_id; - jreq["param"]["protocol_sub_type"] = protocol_sub_type; - jreq["param"]["code"] = state; +bool ts_web_rpc_session_update(int record_id, int protocol_sub_type, int state) +{ + //Json::FastWriter json_writer; + Json::Value jreq; + jreq["method"] = "session_update"; + jreq["param"]["rid"] = record_id; + jreq["param"]["protocol_sub_type"] = protocol_sub_type; + jreq["param"]["code"] = state; - ex_astr json_param; - //json_param = json_writer.write(jreq); + ex_astr json_param; + //json_param = json_writer.write(jreq); Json::StreamWriterBuilder jwb; std::unique_ptr jwriter(jwb.newStreamWriter()); ex_aoss os; jwriter->write(jreq, &os); json_param = os.str(); - ex_astr param; - ts_url_encode(json_param.c_str(), param); + ex_astr param; + ts_url_encode(json_param.c_str(), param); - ex_astr url = g_env.web_server_rpc; - url += "?"; - url += param; + ex_astr url = g_env.web_server_rpc; + url += "?"; + url += param; - ex_astr body; - return ts_http_get(url, body); + ex_astr body; + return ts_http_get(url, body); } //session 结束 bool ts_web_rpc_session_end(const char* sid, int record_id, int ret_code) { - // TODO: 对指定的sid相关的会话的引用计数减一(但减到0时销毁) + // TODO: 对指定的sid相关的会话的引用计数减一(但减到0时销毁) - //Json::FastWriter json_writer; - Json::Value jreq; - jreq["method"] = "session_end"; - jreq["param"]["rid"] = record_id; - jreq["param"]["code"] = ret_code; + //Json::FastWriter json_writer; + Json::Value jreq; + jreq["method"] = "session_end"; + jreq["param"]["rid"] = record_id; + jreq["param"]["code"] = ret_code; - ex_astr json_param; - //json_param = json_writer.write(jreq); + ex_astr json_param; + //json_param = json_writer.write(jreq); Json::StreamWriterBuilder jwb; std::unique_ptr jwriter(jwb.newStreamWriter()); ex_aoss os; jwriter->write(jreq, &os); json_param = os.str(); - ex_astr param; - ts_url_encode(json_param.c_str(), param); + ex_astr param; + ts_url_encode(json_param.c_str(), param); - ex_astr url = g_env.web_server_rpc; - url += "?"; - url += param; + ex_astr url = g_env.web_server_rpc; + url += "?"; + url += param; - ex_astr body; - return ts_http_get(url, body); + ex_astr body; + return ts_http_get(url, body); } diff --git a/server/tp_core/protocol/ssh/ssh_session.cpp b/server/tp_core/protocol/ssh/ssh_session.cpp index 73d5bc2..778baf9 100644 --- a/server/tp_core/protocol/ssh/ssh_session.cpp +++ b/server/tp_core/protocol/ssh/ssh_session.cpp @@ -297,7 +297,7 @@ void SshSession::_thread_loop() if (t_now - t_last_send_keepalive >= 60) { t_last_send_keepalive = t_now; - EXLOGD("[%s] send keepalive.\n", m_dbg_name.c_str()); + // EXLOGD("[%s] send keepalive.\n", m_dbg_name.c_str()); ssh_send_ignore(m_rs_tp2cli, "keepalive@openssh.com"); ssh_send_ignore(m_rs_tp2srv, "keepalive@openssh.com"); } diff --git a/server/www/teleport/static/js/system/config.js b/server/www/teleport/static/js/system/config.js index 7d2f16d..da3179e 100644 --- a/server/www/teleport/static/js/system/config.js +++ b/server/www/teleport/static/js/system/config.js @@ -841,6 +841,8 @@ $app.create_config_integration = function () { title: '权限角色', key: 'role_name', width: 120, + render: 'role_name', + fields: {role_name: 'role_name'} }, { title: '', @@ -907,6 +909,13 @@ $app.create_config_integration = function () { return '' + fields.acc_key + ''; }; + render.role_name = function(row_id, fields) { + if(!_.isNull(fields.role_name) && fields.role_name.length > 0) + return fields.role_name; + else + return '尚未设置'; + }; + render.make_action_btn = function (row_id, fields) { let ret = []; ret.push('
'); diff --git a/server/www/teleport/webroot/app/base/extsrv.py b/server/www/teleport/webroot/app/base/extsrv.py deleted file mode 100644 index 9d9f84c..0000000 --- a/server/www/teleport/webroot/app/base/extsrv.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import json -from app.base.configs import tp_cfg -from app.base.logger import log - - -class ExtSrvCfg(object): - - def __init__(self): - super().__init__() - - import builtins - if '__ext_srv_cfg__' in builtins.__dict__: - raise RuntimeError('ExtSrvCfg object exists, you can not create more than one instance.') - - # session表,session_id为索引,每个项为一个字典,包括 v(value), t(last access), e(expire seconds) - self._cfg = dict() - - 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_secret_info(self, key): - if key not in self._cfg: - return None - return self._cfg[key] - - -def tp_ext_srv_cfg(): - """ - :rtype : ExtSrvCfg - """ - - import builtins - if '__ext_srv_cfg__' not in builtins.__dict__: - builtins.__dict__['__ext_srv_cfg__'] = ExtSrvCfg() - return builtins.__dict__['__ext_srv_cfg__'] diff --git a/server/www/teleport/webroot/app/base/integration.py b/server/www/teleport/webroot/app/base/integration.py new file mode 100644 index 0000000..2925bb3 --- /dev/null +++ b/server/www/teleport/webroot/app/base/integration.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- + +import datetime +import threading + +from app.const import * +from app.base.configs import tp_cfg +from app.base.cron import tp_cron +import app.model.system as system_model + + +class IntegrationManager(object): + """ + 第三方系统集成密钥-内存缓存管理 + """ + + def __init__(self): + super().__init__() + + import builtins + if '__integration_manager__' in builtins.__dict__: + raise RuntimeError('IntegrationManager object exists, you can not create more than one instance.') + + # 密钥表,access-key为索引,每个项为一个字典,包括 n(name), s(access-secret), i(id), r(role_id), p(privilege) + self._keys = dict() + + self._lock = threading.RLock() + + def init(self): + # load from database. + err, _, _, recorder = system_model.get_integration(with_acc_sec=True) + if err != TPE_OK: + return False + # print(recorder) + # [{'id': 8, 'acc_key': 'TPRTn6c7xMW7ci7f', 'name': 'test-audit', 'comment': '日常审计操作', 'acc_sec': 'y3NcQZPdy76kPQmNz7nTik72S8JrTmnp', 'role_id': 3, 'role_name': '审计员', 'privilege': 32769}, ...] + for i in recorder: + self._keys[i['acc_key']] = { + 'name': i['name'], + 'secret': i['acc_sec'], + 'id': i['id'], + 'role_id': i['role_id'], + 'privilege': i['privilege'] + } + + # tp_cron().add_job('session_expire', self._check_expire, first_interval_seconds=None, interval_seconds=60) + return True + + def get_secret(self, acc_key): + with self._lock: + return None if acc_key not in self._keys else self._keys[acc_key] + + def update_by_id(self, _id, acc_key, acc_sec, name, role_id, privilege): + with self._lock: + if acc_key in self._keys: + self._keys[acc_key]['id'] = _id + self._keys[acc_key]['name'] = name + self._keys[acc_key]['role_id'] = role_id + self._keys[acc_key]['privilege'] = privilege + else: + self._keys[acc_key] = { + 'id': _id, + 'secret': '', + 'name': name, + 'role_id': role_id, + 'privilege': privilege + } + if acc_sec is not None: + self._keys[acc_key]['secret'] = acc_sec + + print(self._keys) + + def update_by_role_id(self, role_id, privilege): + with self._lock: + for i in self._keys: + if self._keys[i]['role_id'] == role_id: + self._keys[i]['privilege'] = privilege + + print(self._keys) + + def remove_by_id(self, ids): + with self._lock: + key_to_remove = list() + for i in self._keys: + if self._keys[i]['id'] in ids: + key_to_remove.append(i) + for k in key_to_remove: + del self._keys[k] + + print(self._keys) + + +def tp_integration(): + """ + 取得第三方服务集成密钥管理器的唯一实例 + + :rtype : IntegrationManager + """ + + import builtins + if '__integration_manager__' not in builtins.__dict__: + builtins.__dict__['__integration_manager__'] = IntegrationManager() + return builtins.__dict__['__integration_manager__'] diff --git a/server/www/teleport/webroot/app/base/webapp.py b/server/www/teleport/webroot/app/base/webapp.py index 637e138..fa438ab 100644 --- a/server/www/teleport/webroot/app/base/webapp.py +++ b/server/www/teleport/webroot/app/base/webapp.py @@ -16,7 +16,6 @@ import tornado.web import tornado.platform.asyncio from app.const import * from app.base.configs import tp_cfg -from app.base.extsrv import tp_ext_srv_cfg from app.base.db import get_db from app.base.logger import log from app.base.session import tp_session @@ -26,6 +25,7 @@ from app.base.host_alive import tp_host_alive from app.base.utils import tp_generate_random from app.app_ver import TP_SERVER_VER from app.base.assist_bridge import tp_assist_bridge +from app.base.integration import tp_integration class WebApp: @@ -100,10 +100,6 @@ class WebApp: return 0 def _run_loop(self): - ext_srv_cfg = tp_ext_srv_cfg() - if not ext_srv_cfg.init(): - return 0 - log.i('Teleport Web Server starting ...\n') tp_cron().init() @@ -157,6 +153,10 @@ class WebApp: log.e('can not initialize system status collector.\n') return 0 + if not tp_integration().init(): + log.e('can not load integration config.\n') + return 0 + if cfg.common.check_host_alive: if not tp_host_alive().init(): log.e('can not initialize host state inspector.\n') diff --git a/server/www/teleport/webroot/app/controller/api_v1.py b/server/www/teleport/webroot/app/controller/api_v1.py index d48e836..b5a1477 100644 --- a/server/www/teleport/webroot/app/controller/api_v1.py +++ b/server/www/teleport/webroot/app/controller/api_v1.py @@ -11,7 +11,8 @@ from app.model import host from app.base.logger import * from app.base.controller import TPBaseJsonHandler from app.base.utils import tp_bin, tp_str, tp_timestamp_sec -from app.base.extsrv import tp_ext_srv_cfg +# from app.base.extsrv import tp_ext_srv_cfg +from app.base.integration import tp_integration from .ops import api_request_session_id @@ -43,7 +44,8 @@ def _parse_api_args(handler): return False, handler.write_json(TPE_PARAM) # 从数据库中根据access-key查找access-secret - sec_info = tp_ext_srv_cfg().get_secret_info(req_access_key) + # sec_info = tp_ext_srv_cfg().get_secret_info(req_access_key) + sec_info = tp_integration().get_secret(req_access_key) if sec_info is None: return False, handler.write_json(TPE_INVALID_API_KEY) access_secret = sec_info['secret'] @@ -67,6 +69,7 @@ def _parse_api_args(handler): return False, handler.write_json(TPE_JSON_FORMAT) args['_srv_name_'] = sec_info['name'] + args['_privilege_'] = sec_info['privilege'] # log.d('api:get_host, param=', args, '\n') @@ -106,6 +109,7 @@ class RequestSessionHandler(TPBaseJsonHandler): acc_id = args['account_id'] operator = args['operator'] protocol_sub_type = args['protocol_sub_type'] + privilege = args['_privilege_'] except: return self.write_json(TPE_PARAM) @@ -115,7 +119,8 @@ class RequestSessionHandler(TPBaseJsonHandler): acc_id, protocol_sub_type, self.request.remote_ip, - operator + operator, + privilege ) if ret['code'] != TPE_OK: diff --git a/server/www/teleport/webroot/app/controller/api_v2.py b/server/www/teleport/webroot/app/controller/api_v2.py index 70df3ed..924d975 100644 --- a/server/www/teleport/webroot/app/controller/api_v2.py +++ b/server/www/teleport/webroot/app/controller/api_v2.py @@ -12,7 +12,8 @@ from app.model import host from app.base.logger import * from app.base.controller import TPBaseJsonHandler from app.base.utils import tp_bin, tp_str, tp_timestamp_sec -from app.base.extsrv import tp_ext_srv_cfg +# from app.base.extsrv import tp_ext_srv_cfg +from app.base.integration import tp_integration from .ops import api_v2_request_session_id @@ -53,7 +54,8 @@ def _parse_api_args(handler): return False, handler.write_json(TPE_PARAM) # 从数据库中根据access-key查找access-secret - sec_info = tp_ext_srv_cfg().get_secret_info(req_access_key) + # sec_info = tp_ext_srv_cfg().get_secret_info(req_access_key) + sec_info = tp_integration().get_secret(req_access_key) if sec_info is None: return False, handler.write_json(TPE_INVALID_API_KEY) access_secret = sec_info['secret'] @@ -93,7 +95,7 @@ def _parse_api_args(handler): return False, handler.write_json(TPE_JSON_FORMAT) args['_srv_name_'] = sec_info['name'] - args['_privilege'] = sec_info['privilege'] + args['_privilege_'] = sec_info['privilege'] return True, args @@ -115,6 +117,7 @@ class RequestSessionHandler(TPBaseJsonHandler): remote_secret = args['remote_secret'] protocol_type = args['protocol_type'] protocol_sub_type = args['protocol_sub_type'] + privilege = args['_privilege_'] except: return self.write_json(TPE_PARAM) @@ -122,7 +125,7 @@ class RequestSessionHandler(TPBaseJsonHandler): ret = yield api_v2_request_session_id( remote_ip, remote_port, remote_auth_type, remote_user, remote_secret, - protocol_type, protocol_sub_type, self.request.remote_ip, operator + protocol_type, protocol_sub_type, self.request.remote_ip, operator, privilege ) if ret['code'] != TPE_OK: @@ -141,7 +144,7 @@ class RequestAccessTokenHandler(TPBaseJsonHandler): try: operator = args['operator'] - privilege = args['_privilege'] + privilege = args['_privilege_'] except: return self.write_json(TPE_PARAM) diff --git a/server/www/teleport/webroot/app/controller/ops.py b/server/www/teleport/webroot/app/controller/ops.py index ee2e39e..ac0dfeb 100644 --- a/server/www/teleport/webroot/app/controller/ops.py +++ b/server/www/teleport/webroot/app/controller/ops.py @@ -92,13 +92,19 @@ class SessionListsHandler(TPBaseHandler): @tornado.gen.coroutine -def api_request_session_id(acc_id, protocol_sub_type, client_ip, operator): +def api_request_session_id(acc_id, protocol_sub_type, client_ip, operator, privilege): ret = { 'code': TPE_OK, 'message': '', 'data': {} } + # 检查权限 + if (privilege & TP_PRIVILEGE_OPS) == 0: + ret['code'] = TPE_PRIVILEGE + ret['message'] = '权限不足' + return ret + conn_info = dict() conn_info['_enc'] = 1 conn_info['host_id'] = 0 @@ -106,7 +112,6 @@ def api_request_session_id(acc_id, protocol_sub_type, client_ip, operator): conn_info['user_id'] = 1 conn_info['user_username'] = operator - # 直接连接(无需授权,第三方服务操作,已经经过授权检查了) err, acc_info = account.get_account_info(acc_id) if err != TPE_OK: ret['code'] = err @@ -198,19 +203,24 @@ def api_request_session_id(acc_id, protocol_sub_type, client_ip, operator): @tornado.gen.coroutine def api_v2_request_session_id( remote_ip, remote_port, remote_auth_type, remote_user, remote_secret, - protocol_type, protocol_sub_type, client_ip, operator): + protocol_type, protocol_sub_type, client_ip, operator, privilege): ret = { 'code': TPE_OK, 'message': '', 'data': {} } - # 直接连接(无需授权,第三方服务操作,已经经过授权检查了) + # 检查权限 + if (privilege & TP_PRIVILEGE_OPS) == 0: + ret['code'] = TPE_PRIVILEGE + ret['message'] = '权限不足' + return ret + conn_info = dict() conn_info['_enc'] = 0 - conn_info['host_id'] = 1 + conn_info['host_id'] = 0 conn_info['client_ip'] = client_ip - conn_info['user_id'] = 1 + conn_info['user_id'] = 0 conn_info['user_username'] = operator conn_info['host_ip'] = remote_ip diff --git a/server/www/teleport/webroot/app/controller/system.py b/server/www/teleport/webroot/app/controller/system.py index 6df8c15..8110ee6 100644 --- a/server/www/teleport/webroot/app/controller/system.py +++ b/server/www/teleport/webroot/app/controller/system.py @@ -13,6 +13,7 @@ from app.base import mail from app.base.configs import tp_cfg from app.base.controller import TPBaseHandler, TPBaseJsonHandler from app.base.logger import * +from app.base.integration import tp_integration from app.const import * from app.base.db import get_db from app.model import syslog @@ -132,6 +133,9 @@ class DoRoleUpdateHandler(TPBaseJsonHandler): return self.write_json(TPE_FAILED, '禁止修改系统管理员角色!') err = system_model.update_role(self, role_id, role_name, privilege) + if err == TPE_OK: + tp_integration().update_by_role_id(role_id, privilege) + return self.write_json(err, data=role_id) @@ -160,6 +164,9 @@ class DoRoleRemoveHandler(TPBaseJsonHandler): return self.write_json(TPE_FAILED, '禁止删除系统管理员角色!') err = system_model.remove_role(self, role_id) + if err == TPE_OK: + tp_integration().update_by_role_id(role_id, 0) + return self.write_json(err) @@ -806,19 +813,19 @@ class DoUpdateIntegrationHandler(TPBaseJsonHandler): _role_id = int(args['role_id']) _name = args['name'] _comment = args['comment'] - if _id != -1: - _acc_key = args['acc_key'] - _regenerate = args['regenerate'] + _acc_key = None if _id == -1 else args['acc_key'] + _regenerate = False if _id == -1 else args['regenerate'] except: return self.write_json(TPE_PARAM) ret = dict() if _id == -1: - err, acc_key, acc_sec = system_model.create_integration(self, _role_id, _name, _comment) + err, _id, acc_key, acc_sec, privilege = system_model.create_integration(self, _role_id, _name, _comment) else: - err, acc_key, acc_sec = system_model.update_integration(self, _id, _role_id, _name, _comment, _acc_key, _regenerate) + err, acc_key, acc_sec, privilege = system_model.update_integration(self, _id, _role_id, _name, _comment, _acc_key, _regenerate) if err == TPE_OK: + tp_integration().update_by_id(_id, acc_key, acc_sec, _name, _role_id, privilege) ret['acc_key'] = acc_key ret['acc_sec'] = acc_sec self.write_json(TPE_OK, data=ret) @@ -847,5 +854,7 @@ class DoRemoveIntegrationHandler(TPBaseJsonHandler): return self.write_json(TPE_PARAM) err = system_model.remove_integration(self, items) + if err == TPE_OK: + tp_integration().remove_by_id(items) self.write_json(err) diff --git a/server/www/teleport/webroot/app/model/system.py b/server/www/teleport/webroot/app/model/system.py index a93734b..b80aab6 100644 --- a/server/www/teleport/webroot/app/model/system.py +++ b/server/www/teleport/webroot/app/model/system.py @@ -134,24 +134,33 @@ def create_integration(handler, role_id, name, comment): acc_sec = tp_gen_password(32) for i in range(20): _acc_key = 'TP{}'.format(tp_gen_password(14)) - sql = 'SELECT `id` FROM {dbtp}integration_auth WHERE `acc_key`="{acc_key}";'.format(dbtp=db.table_prefix, acc_key=_acc_key) - db_ret = db.query(sql) + sql = 'SELECT `id` FROM {dbtp}integration_auth WHERE `acc_key`={ph};'.format(dbtp=db.table_prefix, ph=db.place_holder) + db_ret = db.query(sql, (_acc_key, )) if db_ret is not None and len(db_ret) > 0: continue acc_key = _acc_key break if len(acc_key) == 0: - return TPE_FAILED, None, None + return TPE_FAILED + + # 查询对应的角色的权限 + sql = 'SELECT `privilege` FROM {tp}role WHERE `id`={ph}'.format(tp=db.table_prefix, ph=db.place_holder) + db_ret = db.query(sql, (role_id, )) + if db_ret is None or len(db_ret) != 1: + return TPE_DATABASE + privilege = db_ret[0][0] sql = 'INSERT INTO `{dbtp}integration_auth` (`acc_key`, `acc_sec`, `role_id`, `name`, `comment`, `creator_id`, `create_time`) VALUES ' \ '("{acc_key}", "{acc_sec}", {role_id}, "{name}", "{comment}", {creator_id}, {create_time});' \ ''.format(dbtp=db.table_prefix, acc_key=acc_key, acc_sec=acc_sec, role_id=role_id, name=name, comment=comment, creator_id=operator['id'], create_time=_time_now) db_ret = db.exec(sql) if not db_ret: - return TPE_DATABASE, None, None + return TPE_DATABASE + + _id = db.last_insert_id() syslog.sys_log(operator, handler.request.remote_ip, TPE_OK, "创建外部密钥 {}".format(name)) - return TPE_OK, acc_key, acc_sec + return TPE_OK, _id, acc_key, acc_sec, privilege def update_integration(handler, _id, role_id, name, comment, acc_key, regenerate): @@ -167,6 +176,13 @@ def update_integration(handler, _id, role_id, name, comment, acc_key, regenerate if db_ret is None or len(db_ret) == 0: return TPE_NOT_EXISTS, None, None + # 查询对应的角色的权限 + sql = 'SELECT `privilege` FROM {tp}role WHERE `id`={ph}'.format(tp=db.table_prefix, ph=db.place_holder) + db_ret = db.query(sql, (role_id, )) + if db_ret is None or len(db_ret) != 1: + return TPE_DATABASE + privilege = db_ret[0][0] + if regenerate: acc_sec = tp_gen_password(32) sql = 'UPDATE `{dbtp}integration_auth` SET `name`={ph}, `comment`={ph}, `role_id`={ph}, `acc_sec`={ph} WHERE `id`={ph};' \ @@ -181,7 +197,7 @@ def update_integration(handler, _id, role_id, name, comment, acc_key, regenerate return TPE_DATABASE, None, None syslog.sys_log(operator, handler.request.remote_ip, TPE_OK, "更新外部密钥 {}{}".format(name, ',重新生成access-secret。' if regenerate else '')) - return TPE_OK, acc_key, acc_sec + return TPE_OK, acc_key, acc_sec, privilege def remove_integration(handler, items):