Add support for the server to become the initiator in a client->bridge connection. The bridge setting to use are still not implemented yet, and the new bridge-specific SSL key pair still needs to be created on first run.

This commit is contained in:
Ken Moore
2016-05-11 15:29:37 -04:00
parent 9012c7cb57
commit 916069ce69
6 changed files with 118 additions and 8 deletions

View File

@@ -231,6 +231,35 @@ QString AuthorizationManager::GenerateEncCheckString(){
return key;
}
QString AuthorizationManager::GenerateEncString_bridge(QString str){
//Get the private key
return str; //NOT IMPLEMENTED YET
QByteArray privkey = "";//SSL_cfg.privateKey().toPem();
//Now use this private key to encode the given string
unsigned char encode[4098] = {};
RSA *rsa= NULL;
BIO *keybio = NULL;
keybio = BIO_new_mem_buf(privkey.data(), -1);
if(keybio==NULL){ return ""; }
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa,NULL, NULL);
if(rsa==NULL){ return ""; }
int len = RSA_private_encrypt(str.length(), (unsigned char*)(str.toLatin1().data()), encode, rsa, RSA_PKCS1_PADDING);
if(len <0){ return ""; }
else{
//Now return this as a base64 encoded string
QByteArray str_encode( (char*)(encode), len);
/*qDebug() << "Encoded String Info";
qDebug() << " - Raw string:" << str << "Length:" << str.length();
qDebug() << " - Encoded string:" << str_encode << "Length:" << str_encode.length();*/
str_encode = str_encode.toBase64();
/*qDebug() << " - Enc string (base64):" << str_encode << "Length:" << str_encode.length();
qDebug() << " - Enc string (QString):" << QString(str_encode);*/
return QString( str_encode );
}
}
//Stage 2 SSL Login Check: Verify that the returned/encrypted string can be decoded and matches the initial random string
QString AuthorizationManager::LoginUC(QHostAddress host, QString encstring){
//Login w/ SSL certificate
@@ -294,11 +323,12 @@ QString AuthorizationManager::LoginUC(QHostAddress host, QString encstring){
}
QString AuthorizationManager::encryptString(QString msg, QString key){
//do nothing yet
return msg;
}
QString AuthorizationManager::decryptString(QString msg, QString key){
return msg; //do nothing yet
}
// =========================

View File

@@ -32,7 +32,9 @@ public:
QString LoginService(QHostAddress host, QString service); //Login a particular automated service
//Stage 1 SSL Login Check: Generation of random string for this user
QString GenerateEncCheckString();
QString GenerateEncCheckString(); //generate random string (server is receiver w/ pub key)
QString GenerateEncString_bridge(QString str); //encrypt random string (server is initiator w/ private key)
//Stage 2 SSL Login Check: Verify that the returned/encrypted string can be decoded and matches the initial random string
QString LoginUC(QHostAddress host, QString encstring);

View File

@@ -15,6 +15,9 @@ WebServer::WebServer(){
//Setup all the various settings
WSServer = 0;
TCPServer = 0;
bridgeTimer = new QTimer(this);
bridgeTimer->setInterval(5*60*1000); //5 minutes
connect(bridgeTimer, SIGNAL(timeout()), this, SLOT(checkBridges()) );
AUTH = new AuthorizationManager();
connect(AUTH, SIGNAL(BlockHost(QHostAddress)), this, SLOT(BlackListConnection(QHostAddress)) );
}
@@ -30,7 +33,7 @@ bool WebServer::startServer(quint16 port, bool websocket){
qDebug() << " - Version:" << QSslSocket::sslLibraryVersionString();
}
bool ok = false;
if(websocket){ ok = setupWebSocket(port); }
if(websocket){ ok = setupWebSocket(port); }
else{ ok = setupTcp(port); }
if(ok){
@@ -41,11 +44,15 @@ bool WebServer::startServer(quint16 port, bool websocket){
}else{
qCritical() << "Could not start server - exiting...";
}
if(ok && websocket){
bridgeTimer->start();
QTimer::singleShot(5, this, SLOT(checkBridges()));
}
return ok;
}
void WebServer::stopServer(){
if(bridgeTimer->isActive()){ bridgeTimer->stop(); }
if(WSServer!=0){ WSServer->close(); } //note - this will throw the "closed()" signal when done
else if(TCPServer!=0){ TCPServer->close(); QCoreApplication::exit(0);} //no corresponding signal
}
@@ -206,3 +213,8 @@ void WebServer::SocketClosed(QString ID){
}
QTimer::singleShot(0,this, SLOT(NewSocketConnection()) ); //check for a new connection
}
// BRIDGE Connection checks
void WebServer::checkBridges(){
}

View File

@@ -28,7 +28,8 @@ private:
SslServer *TCPServer;
QList<WebSocket*> OpenSockets;
AuthorizationManager *AUTH;
QTimer *bridgeTimer;
//Server Setup functions
bool setupWebSocket(quint16 port);
bool setupTcp(quint16 port);
@@ -56,9 +57,12 @@ private slots:
void SslErrors(const QList<QSslError>&); //sslErrors() signal
void SocketClosed(QString ID);
// BRIDGE Connection checks
void checkBridges();
signals:
//void DispatchStatusUpdate(QString);
};
#endif
#endif

View File

@@ -59,6 +59,31 @@ WebSocket::WebSocket(QSslSocket *sock, QString ID, AuthorizationManager *auth){
QTimer::singleShot(30000, this, SLOT(checkAuth()));
}
WebSocket::WebSocket(QUrl url, QString ID, AuthorizationManager *auth){
//sets up a bridge connection (websocket only)
SockID = ID;
isBridge = true;
SockAuthToken.clear(); //nothing set initially
SOCKET = new QWebSocket("sysadm-server", QWebSocketProtocol::VersionLatest, this);
TSOCKET = 0;
AUTHSYSTEM = auth;
SockPeerIP = SOCKET->peerAddress().toString();
LogManager::log(LogManager::HOST,"New Connection: "+SockPeerIP);
idletimer = new QTimer(this);
idletimer->setInterval(IDLETIMEOUTMINS*60000); //connection timout for idle sockets
idletimer->setSingleShot(true);
connect(idletimer, SIGNAL(timeout()), this, SLOT(checkIdle()) );
connect(SOCKET, SIGNAL(textMessageReceived(const QString&)), this, SLOT(EvaluateMessage(const QString&)) );
connect(SOCKET, SIGNAL(binaryMessageReceived(const QByteArray&)), this, SLOT(EvaluateMessage(const QByteArray&)) );
connect(SOCKET, SIGNAL(aboutToClose()), this, SLOT(SocketClosing()) );
connect(EVENTS, SIGNAL(NewEvent(EventWatcher::EVENT_TYPE, QJsonValue)), this, SLOT(EventUpdate(EventWatcher::EVENT_TYPE, QJsonValue)) );
connect(this, SIGNAL(SendMessage(QString)), this, SLOT(sendReply(QString)) );
connect(SOCKET, SIGNAL(connected()), this, SLOT(startBridgeAuth()) );
//idletimer->start(); //do not idle out on a bridge connection
/*QTimer::singleShot(30000, this, SLOT(checkAuth()));*/
SOCKET->open(url);
}
WebSocket::~WebSocket(){
//qDebug() << "SOCKET Destroyed";
if(SOCKET!=0 && SOCKET->isValid()){
@@ -143,7 +168,7 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){
if(SOCKET!=0 && SOCKET->isValid()){ host = SOCKET->peerAddress(); }
else if(TSOCKET!=0 && TSOCKET->isValid()){ host = TSOCKET->peerAddress(); }
QString cur_auth_tok = SockAuthToken;
if(!REQ.bridgeID.isEmpty()){
if(!REQ.bridgeID.isEmpty() || isBridge){ //never clear/check the SockAuthToken itself on a bridge - this was assigned by the bridge and not created here
cur_auth_tok.clear();
if(BRIDGE.contains(REQ.bridgeID)){ cur_auth_tok = BRIDGE[REQ.bridgeID].auth_tok; }
}
@@ -317,6 +342,7 @@ if(out.in_struct.namesp.toLower() == "rpc"){
}
void WebSocket::EvaluateResponse(const RestInputStruct& IN){
if(!isBridge){ return; } //this is only valid for bridge connections
if(IN.namesp=="events" && IN.name=="bridge"){
QStringList bids = JsonArrayToStringList(IN.args.toObject().value("available_connections").toArray());
QStringList keys = BRIDGE.keys();
@@ -328,6 +354,28 @@ void WebSocket::EvaluateResponse(const RestInputStruct& IN){
for(int i=0; i<bids.length(); i++){
BRIDGE.insert(bids[i], bridge_data());
}
}else if(IN.namesp=="rpc" && IN.id=="server_to_bridge_auth"){
if(IN.args.isArray()){
//Auth Successful - save auth token
QStringList arr = JsonArrayToStringList(IN.args.toArray());
if(arr.length()==2){
SockAuthToken = arr.first();
}
}else if(IN.args.isObject()){
//Stage 2 auth - encrypt string and return it
//Get the test string and encode it
QString test = IN.args.toObject().value("test_string").toString();
QString enc_test = AUTHSYSTEM->GenerateEncString_bridge(test);
//Now send the string back
QJsonObject obj, args;
obj.insert("id","server_to_bridge_auth");
obj.insert("namespace","rpc");
obj.insert("name","auth_ssl");
args.insert("encrypted_string", enc_test);
obj.insert("args", args);
this->sendReply( QJsonDocument(obj).toJson(QJsonDocument::Compact) );
}
}
}
// === GENERAL PURPOSE UTILITY FUNCTIONS ===
@@ -477,6 +525,16 @@ void WebSocket::SslError(const QList<QSslError> &err){ //sslErrors() signal
LogManager::log(LogManager::HOST,"Connection SSL Errors ["+SockPeerIP+"]: "+err.length());
}
void WebSocket::startBridgeAuth(){
QJsonObject obj;
obj.insert("id", "server_to_bridge_auth");
obj.insert("namespace","rpc");
obj.insert("name","auth_ssl");
obj.insert("args","");
this->sendReply( QJsonDocument(obj).toJson(QJsonDocument::Compact) );
}
// ======================
// PUBLIC SLOTS
// ======================

View File

@@ -20,6 +20,7 @@ class WebSocket : public QObject{
public:
WebSocket(QWebSocket*, QString ID, AuthorizationManager *auth);
WebSocket(QSslSocket*, QString ID, AuthorizationManager *auth);
WebSocket(QUrl, QString ID, AuthorizationManager *auth); //sets up a bridge connection (websocket only)
~WebSocket();
QString ID();
@@ -105,6 +106,9 @@ private slots:
void slotIohyveFetchDone(QString, int, QString);
void slotIohyveFetchProcessOutput(QString);
//Bridge Connection Handling
void startBridgeAuth();
public slots:
void EventUpdate(EventWatcher::EVENT_TYPE, QJsonValue = QJsonValue() );