第三方服务集成所需密钥管理功能完成。

feature/assist-websocket
Apex Liu 2022-05-27 19:16:57 +08:00
parent 8b106a8be6
commit d92cf2f469
13 changed files with 429 additions and 351 deletions

View File

@ -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()

View File

@ -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

View File

@ -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<Json::StreamWriter> 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<Json::StreamWriter> 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<Json::CharReader> 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<Json::StreamWriter> 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<Json::CharReader> 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<Json::StreamWriter> 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<Json::StreamWriter> 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);
}

View File

@ -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");
}

View File

@ -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 '<span class="mono">' + fields.acc_key + '</span>';
};
render.role_name = function(row_id, fields) {
if(!_.isNull(fields.role_name) && fields.role_name.length > 0)
return fields.role_name;
else
return '<span class="label label-sm label-danger">尚未设置</span>';
};
render.make_action_btn = function (row_id, fields) {
let ret = [];
ret.push('<div class="btn-group btn-group-sm" role="group">');

View File

@ -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__']

View File

@ -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__']

View File

@ -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')

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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):