mirror of
https://github.com/outbackdingo/sysadm.git
synced 2026-01-27 02:20:17 +00:00
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:
@@ -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
|
||||
}
|
||||
|
||||
// =========================
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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(){
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
// ======================
|
||||
|
||||
@@ -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() );
|
||||
|
||||
|
||||
Reference in New Issue
Block a user