The branch, master has been updated via 3258eb19640dcf041d58da25c7c016788136cecf (commit) from dd0bb5c56aab629a2476e7d3890382da462f25d7 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 3258eb19640dcf041d58da25c7c016788136cecf Author: Oleksandr Shneyder <oleksandr.shneyder@obviously-nice.de> Date: Fri Sep 28 11:34:15 2012 +0200 support for SSH broker. --broker-user removed, use username in broker url instead ----------------------------------------------------------------------- Summary of changes: debian/changelog | 1 + httpbrokerclient.cpp | 458 +++++++++++++++++++++++++++++++++++++++----------- httpbrokerclient.h | 18 +- onmainwindow.cpp | 14 +- onmainwindow.h | 3 + 5 files changed, 394 insertions(+), 100 deletions(-) The diff of changes is: diff --git a/debian/changelog b/debian/changelog index 3193042..cefa5ac 100644 --- a/debian/changelog +++ b/debian/changelog @@ -67,6 +67,7 @@ x2goclient (3.99.3.0-0~x2go1) UNRELEASED; urgency=low - improve brocker code add support for "usebrockerpass" config variable to use brocker pass for ssh auth on X2Go server - commandline options --broker-user and --broker-noauth + - support for SSH broker. --broker-user removed, use username in broker url instead [ Ricardo Diaz ] * New upstream version (3.99.3.0): diff --git a/httpbrokerclient.cpp b/httpbrokerclient.cpp index 36d3e1b..f84f95e 100644 --- a/httpbrokerclient.cpp +++ b/httpbrokerclient.cpp @@ -25,25 +25,42 @@ #include "SVGFrame.h" #include "onmainwindow.h" #include <QTemporaryFile> +#include <QInputDialog> +#include <sshprocess.h> HttpBrokerClient::HttpBrokerClient ( ONMainWindow* wnd, ConfigFile* cfg ) { config=cfg; mainWindow=wnd; + sshConnection=0; QUrl lurl ( config->brokerurl ); - http=new QHttp ( this ); - - if ( config->brokerurl.indexOf ( "https://" ) !=-1 ) - http->setHost ( lurl.host(),QHttp::ConnectionModeHttps, - lurl.port ( 443 ) ); + if(lurl.userName().length()>0) + config->brokerUser=lurl.userName(); + if(config->brokerurl.indexOf("ssh://")==0) + { + sshBroker=true; + x2goDebug<<"host:"<<lurl.host(); + x2goDebug<<"port:"<<lurl.port(22); + x2goDebug<<"uname:"<<lurl.userName(); + x2goDebug<<"path:"<<lurl.path(); + config->sshBrokerBin=lurl.path(); + } else - http->setHost ( lurl.host(),QHttp::ConnectionModeHttp, - lurl.port ( 80 ) ); - - connect ( http,SIGNAL ( requestFinished ( int,bool ) ),this, - SLOT ( slotRequestFinished ( int,bool ) ) ); - connect ( http,SIGNAL ( sslErrors ( const QList<QSslError>& ) ),this, - SLOT ( slotSslErrors ( const QList<QSslError>& ) ) ); + { + sshBroker=false; + http=new QHttp ( this ); + if ( config->brokerurl.indexOf ( "https://" ) ==0 ) + http->setHost ( lurl.host(),QHttp::ConnectionModeHttps, + lurl.port ( 443 ) ); + else + http->setHost ( lurl.host(),QHttp::ConnectionModeHttp, + lurl.port ( 80 ) ); + + connect ( http,SIGNAL ( requestFinished ( int,bool ) ),this, + SLOT ( slotRequestFinished ( int,bool ) ) ); + connect ( http,SIGNAL ( sslErrors ( const QList<QSslError>& ) ),this, + SLOT ( slotSslErrors ( const QList<QSslError>& ) ) ); + } } @@ -51,67 +68,254 @@ HttpBrokerClient::~HttpBrokerClient() { } -void HttpBrokerClient::getUserSessions() +void HttpBrokerClient::createSshConnection() { - QString req; - QTextStream ( &req ) << - "task=listsessions&"<< - "user="<<config->brokerUser<<"&"<< - "password="<<config->brokerPass<<"&"<< - "authid="<<config->brokerUserId; QUrl lurl ( config->brokerurl ); - httpSessionAnswer.close(); - httpSessionAnswer.setData ( 0,0 ); - sessionsRequest=http->post ( lurl.path(),req.toUtf8(),&httpSessionAnswer ); - config->sessiondata=QString::null; + sshConnection=new SshMasterConnection (this, lurl.host(), lurl.port(22),false, + config->brokerUser, config->brokerPass,config->brokerSshKey,config->brokerAutologin, false,false); + + connect ( sshConnection, SIGNAL ( connectionOk(QString)), this, SLOT ( slotSshConnectionOk() ) ); + connect ( sshConnection, SIGNAL ( serverAuthError ( int,QString, SshMasterConnection* ) ),this, + SLOT ( slotSshServerAuthError ( int,QString, SshMasterConnection* ) ) ); + connect ( sshConnection, SIGNAL ( needPassPhrase(SshMasterConnection*)),this, + SLOT ( slotSshServerAuthPassphrase(SshMasterConnection*)) ); + connect ( sshConnection, SIGNAL ( userAuthError ( QString ) ),this,SLOT ( slotSshUserAuthError ( QString ) ) ); + connect ( sshConnection, SIGNAL ( connectionError(QString,QString)), this, + SLOT ( slotSshConnectionError ( QString,QString ) ) ); + sshConnection->start(); + +} + +void HttpBrokerClient::slotSshConnectionError(QString message, QString lastSessionError) +{ + if ( sshConnection ) + { + sshConnection->wait(); + delete sshConnection; + sshConnection=0l; + } + + QMessageBox::critical ( 0l,message,lastSessionError, + QMessageBox::Ok, + QMessageBox::NoButton ); +} + +void HttpBrokerClient::slotSshConnectionOk() +{ + getUserSessions(); +} + +void HttpBrokerClient::slotSshServerAuthError(int error, QString sshMessage, SshMasterConnection* connection) +{ + QString errMsg; + switch ( error ) + { + case SSH_SERVER_KNOWN_CHANGED: + errMsg=tr ( "Host key for server changed.\nIt is now: " ) +sshMessage+"\n"+ + tr ( "For security reasons, connection will be stopped" ); + connection->writeKnownHosts(false); + connection->wait(); + if(sshConnection && sshConnection !=connection) + { + sshConnection->wait(); + delete sshConnection; + } + sshConnection=0; + slotSshUserAuthError ( errMsg ); + return; + + case SSH_SERVER_FOUND_OTHER: + errMsg=tr ( "The host key for this server was not found but an other" + "type of key exists.An attacker might change the default server key to" + "confuse your client into thinking the key does not exist" ); + connection->writeKnownHosts(false); + connection->wait(); + if(sshConnection && sshConnection !=connection) + { + sshConnection->wait(); + delete sshConnection; + } + sshConnection=0; + slotSshUserAuthError ( errMsg ); + return ; + + case SSH_SERVER_ERROR: + connection->writeKnownHosts(false); + connection->wait(); + if(sshConnection && sshConnection !=connection) + { + sshConnection->wait(); + delete sshConnection; + } + sshConnection=0; + slotSshUserAuthError ( sshMessage ); + return ; + case SSH_SERVER_FILE_NOT_FOUND: + errMsg=tr ( "Could not find known host file." + "If you accept the host key here, the file will be automatically created" ); + break; + + case SSH_SERVER_NOT_KNOWN: + errMsg=tr ( "The server is unknown. Do you trust the host key?\nPublic key hash: " ) +sshMessage; + break; + } + + if ( QMessageBox::warning ( 0, tr ( "Host key verification failed" ),errMsg,tr ( "Yes" ), tr ( "No" ) ) !=0 ) + { + connection->writeKnownHosts(false); + connection->wait(); + if(sshConnection && sshConnection !=connection) + { + sshConnection->wait(); + delete sshConnection; + } + sshConnection=0; + slotSshUserAuthError ( tr ( "Host key verification failed" ) ); + return; + } + connection->writeKnownHosts(true); + connection->wait(); + connection->start(); } +void HttpBrokerClient::slotSshServerAuthPassphrase(SshMasterConnection* connection) +{ + bool ok; + QString phrase=QInputDialog::getText(0,connection->getUser()+"@"+connection->getHost()+":"+QString::number(connection->getPort()), + tr("Enter passphrase to decrypt a key"),QLineEdit::Password,QString::null, &ok); + if(!ok) + { + phrase=QString::null; + } + else + { + if(phrase==QString::null) + phrase=""; + } + connection->setKeyPhrase(phrase); + +} + +void HttpBrokerClient::slotSshUserAuthError(QString error) +{ + if ( sshConnection ) + { + sshConnection->wait(); + delete sshConnection; + sshConnection=0l; + } + + QMessageBox::critical ( 0l,tr ( "Authentication failed" ),error, + QMessageBox::Ok, + QMessageBox::NoButton ); + emit authFailed(); + return; +} + +void HttpBrokerClient::getUserSessions() +{ + config->sessiondata=QString::null; + if(!sshBroker) + { + QString req; + QTextStream ( &req ) << + "task=listsessions&"<< + "user="<<config->brokerUser<<"&"<< + "password="<<config->brokerPass<<"&"<< + "authid="<<config->brokerUserId; + QUrl lurl ( config->brokerurl ); + httpSessionAnswer.close(); + httpSessionAnswer.setData ( 0,0 ); + sessionsRequest=http->post ( lurl.path(),req.toUtf8(),&httpSessionAnswer ); + } + else + { + if(!sshConnection) + { + createSshConnection(); + return; + } + SshProcess* proc=new SshProcess ( sshConnection, this ); + connect ( proc,SIGNAL ( sshFinished ( bool,QString,SshProcess* ) ), + this,SLOT ( slotListSessions ( bool, QString, + SshProcess* ) ) ); + proc->startNormal ( config->sshBrokerBin+" --authid "+config->brokerUserId+ " --task listsessions" ); + } +} + void HttpBrokerClient::selectUserSession(const QString& session) { -// x2goDebug<<"selected sid: "<<session; - QString req; - QTextStream ( &req ) << - "task=selectsession&"<< - "sid="<<session<<"&"<< - "user="<<config->brokerUser<<"&"<< - "password="<<config->brokerPass<<"&"<< - "authid="<<config->brokerUserId; - QUrl lurl ( config->brokerurl ); - httpSessionAnswer.close(); - httpSessionAnswer.setData ( 0,0 ); - selSessRequest=http->post ( lurl.path(),req.toUtf8(),&httpSessionAnswer ); + if(!sshBroker) + { + QString req; + QTextStream ( &req ) << + "task=selectsession&"<< + "sid="<<session<<"&"<< + "user="<<config->brokerUser<<"&"<< + "password="<<config->brokerPass<<"&"<< + "authid="<<config->brokerUserId; + QUrl lurl ( config->brokerurl ); + httpSessionAnswer.close(); + httpSessionAnswer.setData ( 0,0 ); + selSessRequest=http->post ( lurl.path(),req.toUtf8(),&httpSessionAnswer ); + } + else + { + SshProcess* proc=new SshProcess ( sshConnection, this ); + connect ( proc,SIGNAL ( sshFinished ( bool,QString,SshProcess* ) ), + this,SLOT ( slotSelectSession(bool,QString,SshProcess*))); + proc->startNormal ( config->sshBrokerBin+" --authid "+config->brokerUserId+ " --task selectsession --sid "+session ); + } } void HttpBrokerClient::changePassword(QString newPass) { newBrokerPass=newPass; - QString req; - QTextStream ( &req ) << - "task=setpass&"<< - "newpass="<<newPass<<"&"<< - "user="<<config->brokerUser<<"&"<< - "password="<<config->brokerPass<<"&"<< - "authid="<<config->brokerUserId; - QUrl lurl ( config->brokerurl ); - httpSessionAnswer.close(); - httpSessionAnswer.setData ( 0,0 ); - chPassRequest=http->post ( lurl.path(),req.toUtf8(),&httpSessionAnswer ); - + if(!sshBroker) + { + QString req; + QTextStream ( &req ) << + "task=setpass&"<< + "newpass="<<newPass<<"&"<< + "user="<<config->brokerUser<<"&"<< + "password="<<config->brokerPass<<"&"<< + "authid="<<config->brokerUserId; + QUrl lurl ( config->brokerurl ); + httpSessionAnswer.close(); + httpSessionAnswer.setData ( 0,0 ); + chPassRequest=http->post ( lurl.path(),req.toUtf8(),&httpSessionAnswer ); + } + else + { + SshProcess* proc=new SshProcess ( sshConnection, this ); + connect ( proc,SIGNAL ( sshFinished ( bool,QString,SshProcess* ) ), + this,SLOT ( slotPassChanged(bool,QString,SshProcess*))); + proc->startNormal ( config->sshBrokerBin+" --authid "+config->brokerUserId+ " --task setpass --newpass "+newPass ); + } } void HttpBrokerClient::testConnection() { - QString req; - QTextStream ( &req ) << - "task=testcon"; - - QUrl lurl ( config->brokerurl ); - httpSessionAnswer.close(); - httpSessionAnswer.setData ( 0,0 ); - requestTime.start(); - testConRequest=http->post ( lurl.path(),req.toUtf8(),&httpSessionAnswer ); + if(!sshBroker) + { + QString req; + QTextStream ( &req ) << + "task=testcon"; + QUrl lurl ( config->brokerurl ); + httpSessionAnswer.close(); + httpSessionAnswer.setData ( 0,0 ); + requestTime.start(); + testConRequest=http->post ( lurl.path(),req.toUtf8(),&httpSessionAnswer ); + } + else + { + SshProcess* proc=new SshProcess ( sshConnection, this ); + connect ( proc,SIGNAL ( sshFinished ( bool,QString,SshProcess* ) ), + this,SLOT ( slotSelectSession(bool,QString,SshProcess*))); + proc->startNormal ( config->sshBrokerBin+" --authid "+config->brokerUserId+ " --task testcon" ); + } } @@ -130,6 +334,95 @@ void HttpBrokerClient::createIniFile(const QString& content) } +bool HttpBrokerClient::checkAccess(QString answer ) +{ + if (answer.indexOf("Access granted")==-1) + { + QMessageBox::critical ( + 0,tr ( "Error" ), + tr ( "Login failed!<br>" + "Please try again" ) ); + emit authFailed(); + return false; + } + config->brokerAuthenticated=true; + return true; +} + + +void HttpBrokerClient::slotConnectionTest(bool success, QString answer, SshProcess* proc) +{ + if(proc) + delete proc; + if(!success) + { + x2goDebug<<answer; + QMessageBox::critical(0,tr("Error"),answer); + emit fatalHttpError(); + return; + } + if(!checkAccess(answer)) + return; + if(!sshBroker) + { + x2goDebug<<"elapsed: "<<requestTime.elapsed()<<"received:"<<httpSessionAnswer.size()<<endl; + emit connectionTime(requestTime.elapsed(),httpSessionAnswer.size()); + } + return; + +} + +void HttpBrokerClient::slotListSessions(bool success, QString answer, SshProcess* proc) +{ + if(proc) + delete proc; + if(!success) + { + x2goDebug<<answer; + QMessageBox::critical(0,tr("Error"),answer); + emit fatalHttpError(); + return; + } + if(!checkAccess(answer)) + return; + createIniFile(answer); + emit sessionsLoaded(); +} + +void HttpBrokerClient::slotPassChanged(bool success, QString answer, SshProcess* proc) +{ + if(proc) + delete proc; + if(!success) + { + x2goDebug<<answer; + QMessageBox::critical(0,tr("Error"),answer); + emit fatalHttpError(); + return; + } + if(!checkAccess(answer)) + return; + +} + +void HttpBrokerClient::slotSelectSession(bool success, QString answer, SshProcess* proc) +{ + if(proc) + delete proc; + if(!success) + { + x2goDebug<<answer; + QMessageBox::critical(0,tr("Error"),answer); + emit fatalHttpError(); + return; + } + if(!checkAccess(answer)) + return; + x2goDebug<<"parsing "<<answer; + parseSession(answer); +} + + void HttpBrokerClient::slotRequestFinished ( int id, bool error ) { // x2goDebug<<"http request "<<id<<", finished with: "<<error; @@ -142,50 +435,23 @@ void HttpBrokerClient::slotRequestFinished ( int id, bool error ) return; } + QString answer ( httpSessionAnswer.data() ); + x2goDebug<<"cmd request answer: "<<answer; if (id==testConRequest) { - - //x2goDebug<<"cmd request answer: "<<answer; - x2goDebug<<"elapsed: "<<requestTime.elapsed()<<"received:"<<httpSessionAnswer.size()<<endl; - emit connectionTime(requestTime.elapsed(),httpSessionAnswer.size()); - return; + slotConnectionTest(true,answer,0); } - if ( id== sessionsRequest || id == selSessRequest || id==chPassRequest) + if (id == sessionsRequest) { - QString answer ( httpSessionAnswer.data() ); - x2goDebug<<"cmd request answer: "<<answer; - if (answer.indexOf("Access granted")==-1) - { - QMessageBox::critical ( - 0,tr ( "Error" ), - tr ( "Login failed!<br>" - "Please try again" ) ); - emit authFailed(); - return; - } - config->brokerAuthenticated=true; - if (id == sessionsRequest) - { - createIniFile(answer); - emit sessionsLoaded(); - } - if (id == selSessRequest) - { - parseSession(answer); - - } - if ( id == chPassRequest) - { - if (answer.indexOf("CHANGING PASS OK")!=-1) - { - emit passwordChanged(newBrokerPass); - } - else - { - emit passwordChanged(QString::null); - } - - } + slotListSessions(true, answer,0); + } + if (id == selSessRequest) + { + slotSelectSession(true,answer,0); + } + if ( id == chPassRequest) + { + slotPassChanged(true,answer,0); } } diff --git a/httpbrokerclient.h b/httpbrokerclient.h index e7b3b57..02f5d3d 100644 --- a/httpbrokerclient.h +++ b/httpbrokerclient.h @@ -16,6 +16,7 @@ #include <QBuffer> #include <QObject> #include <QDateTime> +#include "sshmasterconnection.h" /** @author Oleksandr Shneyder <oleksandr.shneyder@obviously-nice.de> */ @@ -43,14 +44,29 @@ private: QString newBrokerPass; ConfigFile* config; ONMainWindow* mainWindow; + QTime requestTime; + bool sshBroker; + SshMasterConnection* sshConnection; +private: void createIniFile(const QString& content); void parseSession(QString sInfo); - QTime requestTime; + void createSshConnection(); + bool checkAccess(QString answer); private slots: void slotRequestFinished ( int id, bool error ); void slotSslErrors ( const QList<QSslError> & errors ) ; QString getHexVal ( const QByteArray& ba ); + void slotSshConnectionError ( QString message, QString lastSessionError ); + void slotSshServerAuthError ( int error, QString sshMessage, SshMasterConnection* connection ); + void slotSshServerAuthPassphrase ( SshMasterConnection* connection ); + void slotSshUserAuthError ( QString error ); + void slotSshConnectionOk(); + void slotListSessions ( bool success, QString answer, SshProcess* proc); + void slotSelectSession ( bool success, QString answer, SshProcess* proc); + void slotPassChanged ( bool success, QString answer, SshProcess* proc); + void slotConnectionTest( bool success, QString answer, SshProcess* proc); + public slots: void getUserSessions(); diff --git a/onmainwindow.cpp b/onmainwindow.cpp index 2825e38..89e2964 100644 --- a/onmainwindow.cpp +++ b/onmainwindow.cpp @@ -969,13 +969,15 @@ void ONMainWindow::slotGetBrokerAuth() nameLabel->setText ( text ); slotShowPassForm(); config.brokerAuthenticated=false; - if(config.brokerUser.length()>=0) + if(config.brokerUser.length()>0) { login->setText(config.brokerUser); pass->setFocus(); } if(config.brokerNoAuth) slotSessEnter(); + if(config.brokerurl.indexOf("ssh://")==0 && (config.brokerAutologin || config.brokerSshKey.length()>0)) + slotSessEnter(); } @@ -6210,6 +6212,12 @@ bool ONMainWindow::parseParameter ( QString param ) return true; } + if ( param == "--broker-autologin") + { + config.brokerAutologin=true; + return true; + } + if ( param == "--broker-noauth") { config.brokerNoAuth=true; @@ -6339,9 +6347,9 @@ bool ONMainWindow::parseParameter ( QString param ) config.brokerurl=value; return true; } - if ( setting == "--broker-user") + if ( setting == "--broker-ssh-key") { - config.brokerUser=value; + config.brokerSshKey=value; return true; } if ( setting == "--ssh-key") diff --git a/onmainwindow.h b/onmainwindow.h index 831599a..5e8ec6e 100644 --- a/onmainwindow.h +++ b/onmainwindow.h @@ -165,8 +165,11 @@ struct ConfigFile QString brokerPass; QString brokerUserId; QString brokerName; + QString sshBrokerBin; bool brokerAuthenticated; bool brokerNoAuth; + bool brokerAutologin; + QString brokerSshKey; QString iniFile; QString server; QString serverIp;//Can be different from server (use for loadballancing) hooks/post-receive -- x2goclient.git (X2Go Client) This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "x2goclient.git" (X2Go Client).