diff --git a/src/bridge/BridgeConnection.cpp b/src/bridge/BridgeConnection.cpp index 9518db0..4c75ce0 100644 --- a/src/bridge/BridgeConnection.cpp +++ b/src/bridge/BridgeConnection.cpp @@ -18,7 +18,7 @@ BridgeConnection::BridgeConnection(QWebSocket *sock, QString ID){ qDebug() << "New Connection:" << SockPeerIP; idletimer = new QTimer(this); idletimer->setInterval(30000); //connection timout for idle sockets - idletimer->setSingleShot(true); + //idletimer->setSingleShot(true); connect(idletimer, SIGNAL(timeout()), this, SLOT(checkAuth()) ); connect(SOCKET, SIGNAL(textMessageReceived(const QString&)), this, SLOT(EvaluateMessage(const QString&)) ); connect(SOCKET, SIGNAL(binaryMessageReceived(const QByteArray&)), this, SLOT(EvaluateMessage(const QByteArray&)) ); @@ -87,6 +87,7 @@ QStringList BridgeConnection::JsonArrayToStringList(QJsonArray array){ void BridgeConnection::InjectMessage(QString msg){ //See if this message is directed to the bridge itself, or a client + qDebug() << "Got Message:" << msg; if(msg.startsWith("{") || !AUTHSYSTEM->checkAuth(SockAuthToken) ){ HandleAPIMessage(msg); }else{ @@ -95,7 +96,8 @@ void BridgeConnection::InjectMessage(QString msg){ QString toID = msg.left(lb); if(toID.contains(" ")){ //Return an error message to the calling socket - if(SOCKET->isValid()){ SOCKET->sendTextMessage("{\"namespace\":\"error\", \"name\":\"error\",\"id\":\"error\",\"args\":\"\" }"); } + qDebug() << "Invalid Destination ID:" << toID; + //if(SOCKET->isValid()){ SOCKET->sendTextMessage("{\"namespace\":\"error\", \"name\":\"error\",\"id\":\"error\",\"args\":\"\" }"); } }else{ //Add the "from" ID to the message msg = msg.replace(0,lb,SockID); //replace the "to" ID with the "from" ID @@ -109,10 +111,10 @@ void BridgeConnection::HandleAPIMessage(QString msg){ QJsonObject out; if(JM.isEmpty() || !JM.contains("namespace") || !JM.contains("name") || !JM.contains("args") || !JM.contains("id") ){ //invalid inputs - return - out.insert("namespace","error"); + /*out.insert("namespace","error"); out.insert("name","error"); out.insert("id", JM.contains("id") ? JM.value("id") : "error"); - out.insert("args", ""); + out.insert("args", "");*/ }else if( JM.value("name").toString()=="response" ){ // - Return messages first (check ID) QString id = JM.value("id").toString(); @@ -128,7 +130,7 @@ void BridgeConnection::HandleAPIMessage(QString msg){ } } //no response needed - }else{ + }else if(JM.value("name").toString()!="error"){ //API Call QString name, namesp, id; QJsonObject args = JM.value("args").toObject(); @@ -147,7 +149,7 @@ void BridgeConnection::HandleAPIMessage(QString msg){ }else if(namesp == "rpc" && name=="auth_ssl"){ if(!args.contains("encrypted_string")){ //Stage 1 - send a random string to encrypt - qDebug() << "Connection Auth Init:" << SockPeerIP; + qDebug() << "Connection Auth Init:" << SockID; QString key = AUTHSYSTEM->GenerateEncCheckString(); QJsonObject obj; obj.insert("test_string", key); outargs = obj; @@ -159,12 +161,12 @@ void BridgeConnection::HandleAPIMessage(QString msg){ array.append(SockAuthToken); array.append(AUTHSYSTEM->checkAuthTimeoutSecs(SockAuthToken)); outargs = array; - qDebug() << "Connection Authorized:" << SockPeerIP << "Type:" << (serverconn ? "server" : "client"); + qDebug() << "Connection Authorized:" << SockPeerIP << SockID << "Type:" << (serverconn ? "server" : "client"); QTimer::singleShot(10 ,this, SLOT(requestKeyList()) ); }else{ out.insert("name","error"); outargs = "unauthorized"; - qDebug() << "Connection Not Authorized:" << SockPeerIP; + qDebug() << "Connection Not Authorized:" << SockPeerIP << SockID; } } }else if(AUTHSYSTEM->checkAuth(SockAuthToken)){ @@ -182,21 +184,25 @@ void BridgeConnection::HandleAPIMessage(QString msg){ // PRIVATE SLOTS // ===================== void BridgeConnection::checkIdle(){ - if(SOCKET !=0 && SOCKET->isValid()){ - qDebug() << "Connection Idle: "<close(); //timeout - close the connection to make way for others - } + if(SOCKET !=0){ + if(SOCKET->isValid()){ + qDebug() << "Connection Idle: "<< SockID; + SOCKET->close(); //timeout - close the connection to make way for others + }else{ + emit SocketClosed(SockID); //disconnect signal did not get picked up for some reason + } + } } void BridgeConnection::checkAuth(){ - if(!AUTHSYSTEM->checkAuth(SockAuthToken)){ + if(!AUTHSYSTEM->checkAuth(SockAuthToken) || !SOCKET->isValid() ){ //Still not authorized - disconnect checkIdle(); } } void BridgeConnection::SocketClosing(){ - qDebug() << "Connection Closing: " << SockPeerIP; + qDebug() << "Connection Closing: " << SockID; if(idletimer->isActive()){ idletimer->stop(); } //Stop any current requests @@ -254,7 +260,7 @@ void BridgeConnection::requestKeyList(){ QJsonObject args; args.insert("action","list_ssl_checksums"); obj.insert("args",args); - + qDebug() << "Request Key List"; SOCKET->sendTextMessage( QJsonDocument(obj).toJson(QJsonDocument::Compact) ); } diff --git a/src/bridge/BridgeServer.cpp b/src/bridge/BridgeServer.cpp index cae44e3..1f750dc 100644 --- a/src/bridge/BridgeServer.cpp +++ b/src/bridge/BridgeServer.cpp @@ -190,7 +190,7 @@ void BridgeServer::SocketClosed(QString ID){ // Connection Keys Changed void BridgeServer::announceKeyChange(QString ID, bool isServer, QStringList keys){ - qDebug() << "Key Change:" << ID << isServer << keys; + //qDebug() << "Key Change:" << ID << isServer << keys; for(int c = 0; cisServer(); QStringList keys = OpenSockets[c]->validKeySums(); diff --git a/src/server/AuthorizationManager.cpp b/src/server/AuthorizationManager.cpp index edffeeb..02d5612 100644 --- a/src/server/AuthorizationManager.cpp +++ b/src/server/AuthorizationManager.cpp @@ -146,7 +146,7 @@ void AuthorizationManager::ListCertificateChecksums(QJsonObject *out){ chash.addData( keys[i].section("/",2,-1).toLocal8Bit() ); QByteArray res = chash.result(); chash.reset(); - arr << QString(res); + arr << QString(res.toBase64()); } out->insert("md5_keys", arr); } diff --git a/src/server/WebBackend.cpp b/src/server/WebBackend.cpp index 1ee9ddc..8a8f9fa 100644 --- a/src/server/WebBackend.cpp +++ b/src/server/WebBackend.cpp @@ -95,6 +95,7 @@ RestOutputStruct::ExitCode WebSocket::EvaluateBackendRequest(const RestInputStru "args" - JSON input arguments structure "out" - JSON output arguments structure */ + qDebug() << "Evaluate Backend Request:" << IN.namesp << IN.name << IN.id << IN.args << IN.fullaccess; QString namesp = IN.namesp.toLower(); QString name = IN.name.toLower(); //Get/Verify subsystems @@ -141,7 +142,7 @@ RestOutputStruct::ExitCode WebSocket::EvaluateBackendRequest(const RestInputStru // === SYSADM SSL SETTINGS === RestOutputStruct::ExitCode WebSocket::EvaluateSysadmSettingsRequest(const QJsonValue in_args, QJsonObject *out){ - //qDebug() << "sysadm/settings Request:" << in_args; + qDebug() << "sysadm/settings Request:" << in_args; if(!in_args.isObject()){ return RestOutputStruct::BADREQUEST; } QJsonObject argsO = in_args.toObject(); QStringList keys = argsO.keys(); diff --git a/src/server/WebSocket.cpp b/src/server/WebSocket.cpp index 41ba936..69db206 100644 --- a/src/server/WebSocket.cpp +++ b/src/server/WebSocket.cpp @@ -182,7 +182,8 @@ void WebSocket::EvaluateREST(QString msg){ } void WebSocket::EvaluateRequest(const RestInputStruct &REQ){ - //qDebug() << "Evaluate Request:" << REQ.namesp << REQ.name << REQ.args; + qDebug() << "Evaluate Request:" << REQ.namesp << REQ.name << REQ.args; + if(REQ.name=="response" && REQ.bridgeID.isEmpty() && isBridge){ qDebug() << "Unhandled Bridge Message:" << REQ.name << REQ.id << REQ.args; return; } //if a bridge reply gets this far - skip it (automated reply to some message we don't care about) RestOutputStruct out; out.in_struct = REQ; QHostAddress host; @@ -208,20 +209,21 @@ void WebSocket::EvaluateRequest(const RestInputStruct &REQ){ } //qDebug() << "Auth Token:" << cur_auth_tok; //Now check the body of the message and do what it needs -if(out.in_struct.namesp.toLower() == "rpc"){ - if(out.in_struct.name == "identify"){ - QJsonObject obj; + if(out.in_struct.namesp.toLower() == "rpc" && (out.in_struct.name=="identify" || out.in_struct.name.startsWith("auth")) ){ + //qDebug() << "Within rpc section"; + if(out.in_struct.name == "identify"){ + QJsonObject obj; obj.insert("type", "server"); - out.out_args = obj; - out.CODE = RestOutputStruct::OK; - }else if(out.in_struct.name.startsWith("auth")){ - //Now perform authentication based on type of auth given - //Note: This sets/changes the current SockAuthToken - AUTHSYSTEM->clearAuth(cur_auth_tok); //new auth requested - clear any old token + out.out_args = obj; + out.CODE = RestOutputStruct::OK; + }else if(out.in_struct.name.startsWith("auth")){ + //Now perform authentication based on type of auth given + //Note: This sets/changes the current SockAuthToken + AUTHSYSTEM->clearAuth(cur_auth_tok); //new auth requested - clear any old token - if(DEBUG){ qDebug() << "Authenticate Peer:" << host; } - //Now do the auth - if(out.in_struct.name=="auth" && out.in_struct.args.isObject() && !isBridge ){ + if(DEBUG){ qDebug() << "Authenticate Peer:" << host; } + //Now do the auth + if(out.in_struct.name=="auth" && out.in_struct.args.isObject() && !isBridge ){ //username/[password/cert] authentication QString user, pass; if(out.in_struct.args.toObject().contains("username")){ user = JsonValueToString(out.in_struct.args.toObject().value("username")); } @@ -331,7 +333,15 @@ if(out.in_struct.namesp.toLower() == "rpc"){ out.CODE = RestOutputStruct::UNAUTHORIZED; } //Other namespace - check whether auth has already been established before continuing -}else if( AUTHSYSTEM->checkAuth(cur_auth_tok) ){ //validate current Authentication token +}else if( isBridge && REQ.bridgeID.isEmpty() && !SockAuthToken.isEmpty() && REQ.namesp=="rpc" && REQ.name=="settings" && REQ.args.toObject().value("action").toString()=="list_ssl_checksums"){ + qDebug() << "Within special bridge section"; + out.in_struct.fullaccess = false; + //Pre-set any output fields + QJsonObject outargs; + out.CODE = EvaluateBackendRequest(out.in_struct, &outargs); + out.out_args = outargs; +}else if( AUTHSYSTEM->checkAuth(cur_auth_tok) ){ //validate current Authentication token + qDebug() << "Within auth section"; //Now provide access to the various subsystems // First get/set the permissions flag into the input structure out.in_struct.fullaccess = AUTHSYSTEM->hasFullAccess(cur_auth_tok); @@ -340,6 +350,7 @@ if(out.in_struct.namesp.toLower() == "rpc"){ out.CODE = EvaluateBackendRequest(out.in_struct, &outargs); out.out_args = outargs; }else{ + qDebug() << "Within fallback auth error section"; //Error in inputs - assemble the return error message out.CODE = RestOutputStruct::UNAUTHORIZED; } @@ -368,7 +379,7 @@ if(out.in_struct.namesp.toLower() == "rpc"){ } void WebSocket::EvaluateResponse(const RestInputStruct& IN){ - qDebug() << "Evaluate Response:" << IN.id << IN.name << IN.args; + //qDebug() << "Evaluate Response:" << IN.id << IN.name << IN.args; 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());