From 9fd2a3440f17d8fca27bed4b92e7682918bfe459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 6 Jun 2019 15:39:00 +0200 Subject: [PATCH] Add insecure websocket support and start with tcp server support --- libnymea-remoteproxy/engine.cpp | 4 +- libnymea-remoteproxy/proxyconfiguration.cpp | 12 +++ libnymea-remoteproxy/proxyconfiguration.h | 4 + libnymea-remoteproxy/websocketserver.cpp | 11 ++- libnymea-remoteproxy/websocketserver.h | 3 +- .../libnymea-remoteproxyclient.pri | 2 + .../proxyconnection.cpp | 10 ++ libnymea-remoteproxyclient/proxyconnection.h | 5 +- .../remoteproxyconnection.cpp | 9 ++ .../remoteproxyconnection.h | 3 +- .../tcpsocketconnection.cpp | 95 +++++++++++++++++++ .../tcpsocketconnection.h | 46 +++++++++ .../websocketconnection.cpp | 11 +-- .../websocketconnection.h | 3 - nymea-remoteproxy.conf | 1 + server/main.cpp | 7 +- 16 files changed, 204 insertions(+), 22 deletions(-) create mode 100644 libnymea-remoteproxyclient/tcpsocketconnection.cpp create mode 100644 libnymea-remoteproxyclient/tcpsocketconnection.h diff --git a/libnymea-remoteproxy/engine.cpp b/libnymea-remoteproxy/engine.cpp index 887cd83..0baf9bd 100644 --- a/libnymea-remoteproxy/engine.cpp +++ b/libnymea-remoteproxy/engine.cpp @@ -72,10 +72,10 @@ void Engine::start(ProxyConfiguration *configuration) Q_ASSERT_X(m_authenticator != nullptr, "Engine", "There is no authenticator registerd."); m_proxyServer = new ProxyServer(this); - m_webSocketServer = new WebSocketServer(m_configuration->sslConfiguration(), this); + m_webSocketServer = new WebSocketServer(m_configuration->sslEnabled(), m_configuration->sslConfiguration(), this); QUrl websocketServerUrl; - websocketServerUrl.setScheme("wss"); + websocketServerUrl.setScheme(m_configuration->sslEnabled() ? "wss" : "ws"); websocketServerUrl.setHost(m_configuration->webSocketServerHost().toString()); websocketServerUrl.setPort(m_configuration->webSocketServerPort()); diff --git a/libnymea-remoteproxy/proxyconfiguration.cpp b/libnymea-remoteproxy/proxyconfiguration.cpp index 7d2f061..5d88dc0 100644 --- a/libnymea-remoteproxy/proxyconfiguration.cpp +++ b/libnymea-remoteproxy/proxyconfiguration.cpp @@ -71,6 +71,7 @@ bool ProxyConfiguration::loadConfiguration(const QString &fileName) settings.endGroup(); settings.beginGroup("SSL"); + setSslEnabled(settings.value("enabled", true).toBool()); setSslCertificateFileName(settings.value("certificate", "/etc/ssl/certs/ssl-cert-snakeoil.pem").toString()); setSslCertificateKeyFileName(settings.value("certificateKey", "/etc/ssl/private/ssl-cert-snakeoil.key").toString()); setSslCertificateChainFileName(settings.value("certificateChain", "").toString()); @@ -256,6 +257,16 @@ void ProxyConfiguration::setAwsCredentialsUrl(const QUrl &url) m_awsCredentialsUrl = url; } +bool ProxyConfiguration::sslEnabled() const +{ + return m_sslEnabled; +} + +void ProxyConfiguration::setSslEnabled(bool enabled) +{ + m_sslEnabled = enabled; +} + QString ProxyConfiguration::sslCertificateFileName() const { return m_sslCertificateFileName; @@ -349,6 +360,7 @@ QDebug operator<<(QDebug debug, ProxyConfiguration *configuration) debug.nospace() << " - Authorizer lambda function:" << configuration->awsAuthorizerLambdaFunctionName() << endl; debug.nospace() << " - Credentials URL:" << configuration->awsCredentialsUrl().toString() << endl; debug.nospace() << "SSL configuration" << endl; + debug.nospace() << " - Enabled:" << configuration->sslEnabled() << endl; debug.nospace() << " - Certificate:" << configuration->sslCertificateFileName() << endl; debug.nospace() << " - Certificate key:" << configuration->sslCertificateKeyFileName() << endl; debug.nospace() << " - Certificate chain:" << configuration->sslCertificateChainFileName() << endl; diff --git a/libnymea-remoteproxy/proxyconfiguration.h b/libnymea-remoteproxy/proxyconfiguration.h index 048c74a..2262761 100644 --- a/libnymea-remoteproxy/proxyconfiguration.h +++ b/libnymea-remoteproxy/proxyconfiguration.h @@ -85,6 +85,9 @@ public: void setAwsCredentialsUrl(const QUrl &url); // Ssl + bool sslEnabled() const; + void setSslEnabled(bool enabled); + QString sslCertificateFileName() const; void setSslCertificateFileName(const QString &fileName); @@ -130,6 +133,7 @@ private: QUrl m_awsCredentialsUrl; // Ssl + bool m_sslEnabled = true; QString m_sslCertificateFileName = "/etc/ssl/certs/ssl-cert-snakeoil.pem"; QString m_sslCertificateKeyFileName = "/etc/ssl/private/ssl-cert-snakeoil.key"; QString m_sslCertificateChainFileName; diff --git a/libnymea-remoteproxy/websocketserver.cpp b/libnymea-remoteproxy/websocketserver.cpp index 9e60d94..9a5386f 100644 --- a/libnymea-remoteproxy/websocketserver.cpp +++ b/libnymea-remoteproxy/websocketserver.cpp @@ -32,8 +32,9 @@ namespace remoteproxy { -WebSocketServer::WebSocketServer(const QSslConfiguration &sslConfiguration, QObject *parent) : +WebSocketServer::WebSocketServer(bool sslEnabled, const QSslConfiguration &sslConfiguration, QObject *parent) : TransportInterface(parent), + m_sslEnabled(sslEnabled), m_sslConfiguration(sslConfiguration) { m_serverName = "Websocket server"; @@ -181,8 +182,12 @@ void WebSocketServer::onServerError(QWebSocketProtocol::CloseCode closeCode) bool WebSocketServer::startServer() { - m_server = new QWebSocketServer(QCoreApplication::applicationName(), QWebSocketServer::SecureMode, this); - m_server->setSslConfiguration(sslConfiguration()); + if (m_sslEnabled) { + m_server = new QWebSocketServer(QCoreApplication::applicationName(), QWebSocketServer::SecureMode, this); + m_server->setSslConfiguration(sslConfiguration()); + } else { + m_server = new QWebSocketServer(QCoreApplication::applicationName(), QWebSocketServer::NonSecureMode, this); + } connect (m_server, &QWebSocketServer::newConnection, this, &WebSocketServer::onClientConnected); connect (m_server, &QWebSocketServer::acceptError, this, &WebSocketServer::onAcceptError); diff --git a/libnymea-remoteproxy/websocketserver.h b/libnymea-remoteproxy/websocketserver.h index f4641d2..27e4108 100644 --- a/libnymea-remoteproxy/websocketserver.h +++ b/libnymea-remoteproxy/websocketserver.h @@ -43,7 +43,7 @@ class WebSocketServer : public TransportInterface { Q_OBJECT public: - explicit WebSocketServer(const QSslConfiguration &sslConfiguration, QObject *parent = nullptr); + explicit WebSocketServer(bool sslEnabled, const QSslConfiguration &sslConfiguration, QObject *parent = nullptr); ~WebSocketServer() override; QUrl serverUrl() const; @@ -59,6 +59,7 @@ public: private: QUrl m_serverUrl; QWebSocketServer *m_server = nullptr; + bool m_sslEnabled; QSslConfiguration m_sslConfiguration; bool m_enabled = false; diff --git a/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri b/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri index 2a7edce..6ae9be7 100644 --- a/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri +++ b/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri @@ -1,6 +1,7 @@ INCLUDEPATH += $${PWD} HEADERS += \ + $$PWD/tcpsocketconnection.h \ $${PWD}/proxyjsonrpcclient.h \ $${PWD}/jsonreply.h \ $${PWD}/remoteproxyconnection.h \ @@ -8,6 +9,7 @@ HEADERS += \ $${PWD}/websocketconnection.h SOURCES += \ + $$PWD/tcpsocketconnection.cpp \ $${PWD}/proxyjsonrpcclient.cpp \ $${PWD}/jsonreply.cpp \ $${PWD}/remoteproxyconnection.cpp \ diff --git a/libnymea-remoteproxyclient/proxyconnection.cpp b/libnymea-remoteproxyclient/proxyconnection.cpp index 075e32f..2dcffd7 100644 --- a/libnymea-remoteproxyclient/proxyconnection.cpp +++ b/libnymea-remoteproxyclient/proxyconnection.cpp @@ -34,6 +34,11 @@ ProxyConnection::ProxyConnection(QObject *parent) : QObject(parent) } +QUrl ProxyConnection::serverUrl() const +{ + return m_serverUrl; +} + bool ProxyConnection::connected() { return m_connected; @@ -48,6 +53,11 @@ void ProxyConnection::setConnected(bool connected) emit connectedChanged(m_connected); } +void ProxyConnection::setServerUrl(const QUrl &serverUrl) +{ + m_serverUrl = serverUrl; +} + ProxyConnection::~ProxyConnection() { diff --git a/libnymea-remoteproxyclient/proxyconnection.h b/libnymea-remoteproxyclient/proxyconnection.h index e23dd83..178fab7 100644 --- a/libnymea-remoteproxyclient/proxyconnection.h +++ b/libnymea-remoteproxyclient/proxyconnection.h @@ -28,6 +28,7 @@ #ifndef SOCKETCONNECTOR_H #define SOCKETCONNECTOR_H +#include #include #include #include @@ -43,7 +44,7 @@ public: virtual void sendData(const QByteArray &data) = 0; - virtual QUrl serverUrl() const = 0; + QUrl serverUrl() const; virtual void ignoreSslErrors() = 0; virtual void ignoreSslErrors(const QList &errors) = 0; @@ -52,9 +53,11 @@ public: private: bool m_connected = false; + QUrl m_serverUrl; protected: void setConnected(bool connected); + void setServerUrl(const QUrl &serverUrl); signals: void connectedChanged(bool connected); diff --git a/libnymea-remoteproxyclient/remoteproxyconnection.cpp b/libnymea-remoteproxyclient/remoteproxyconnection.cpp index e636857..a56f6b6 100644 --- a/libnymea-remoteproxyclient/remoteproxyconnection.cpp +++ b/libnymea-remoteproxyclient/remoteproxyconnection.cpp @@ -43,6 +43,15 @@ RemoteProxyConnection::RemoteProxyConnection(const QUuid &clientUuid, const QStr } +RemoteProxyConnection::RemoteProxyConnection(const QUuid &clientUuid, const QString &clientName, RemoteProxyConnection::ConnectionType connectionType, QObject *parent) : + QObject(parent), + m_clientUuid(clientUuid), + m_clientName(clientName), + m_connectionType(connectionType) +{ + +} + RemoteProxyConnection::~RemoteProxyConnection() { diff --git a/libnymea-remoteproxyclient/remoteproxyconnection.h b/libnymea-remoteproxyclient/remoteproxyconnection.h index 28c92f6..372a114 100644 --- a/libnymea-remoteproxyclient/remoteproxyconnection.h +++ b/libnymea-remoteproxyclient/remoteproxyconnection.h @@ -69,6 +69,7 @@ public: Q_ENUM(State) explicit RemoteProxyConnection(const QUuid &clientUuid, const QString &clientName, QObject *parent = nullptr); + RemoteProxyConnection(const QUuid &clientUuid, const QString &clientName, ConnectionType connectionType, QObject *parent = nullptr); ~RemoteProxyConnection(); RemoteProxyConnection::State state() const; @@ -94,9 +95,9 @@ public: QString tunnelPartnerUuid() const; private: - ConnectionType m_connectionType = ConnectionTypeWebSocket; QUuid m_clientUuid; QString m_clientName; + ConnectionType m_connectionType = ConnectionTypeWebSocket; QUrl m_serverUrl; diff --git a/libnymea-remoteproxyclient/tcpsocketconnection.cpp b/libnymea-remoteproxyclient/tcpsocketconnection.cpp new file mode 100644 index 0000000..4e60266 --- /dev/null +++ b/libnymea-remoteproxyclient/tcpsocketconnection.cpp @@ -0,0 +1,95 @@ +#include "tcpsocketconnection.h" +Q_LOGGING_CATEGORY(dcRemoteProxyClientTcpSocket, "RemoteProxyClientTcpSocket") + +namespace remoteproxyclient { + +TcpSocketConnection::TcpSocketConnection(QObject *parent) : + ProxyConnection(parent) +{ + m_tcpSocket = new QSslSocket(this); + + connect(m_tcpSocket, &QSslSocket::disconnected, this, &TcpSocketConnection::onDisconnected); + connect(m_tcpSocket, &QSslSocket::encrypted, this, &TcpSocketConnection::onEncrypted); + connect(m_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError))); + connect(m_tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onStateChanged(QAbstractSocket::SocketState))); + connect(m_tcpSocket, SIGNAL(sslErrors(QList)), this, SIGNAL(sslErrors(QList))); +} + +TcpSocketConnection::~TcpSocketConnection() +{ + m_tcpSocket->close(); +} + +void TcpSocketConnection::sendData(const QByteArray &data) +{ + m_tcpSocket->write(data); +} + +void TcpSocketConnection::ignoreSslErrors() +{ + m_tcpSocket->ignoreSslErrors(); +} + +void TcpSocketConnection::ignoreSslErrors(const QList &errors) +{ + m_tcpSocket->ignoreSslErrors(errors); +} + +void TcpSocketConnection::onDisconnected() +{ + qCDebug(dcRemoteProxyClientTcpSocket()) << "Disconnected from" << serverUrl().toString(); + setConnected(false); +} + +void TcpSocketConnection::onEncrypted() +{ + qCDebug(dcRemoteProxyClientTcpSocket()) << "Connection encrypted"; +} + +void TcpSocketConnection::onError(QAbstractSocket::SocketError error) +{ + qCDebug(dcRemoteProxyClientTcpSocket()) << "Socket error occured" << error << m_tcpSocket->errorString(); + emit errorOccured(error); +} + +void TcpSocketConnection::onStateChanged(QAbstractSocket::SocketState state) +{ + qCDebug(dcRemoteProxyClientTcpSocket()) << "Socket state changed" << state; + + switch (state) { + case QAbstractSocket::ConnectedState: + qCDebug(dcRemoteProxyClientTcpSocket()) << "Connected with" << serverUrl().toString(); + setConnected(true); + break; + default: + setConnected(false); + break; + } + + emit stateChanged(state); +} + +void TcpSocketConnection::onReadyRead() +{ + emit dataReceived(m_tcpSocket->readAll()); +} + +void TcpSocketConnection::connectServer(const QUrl &serverUrl) +{ + qCDebug(dcRemoteProxyClientTcpSocket()) << "Connecting to" << this->serverUrl().toString(); + setServerUrl(serverUrl); + + if (serverUrl.scheme() == "tcp") { + m_tcpSocket->connectToHost(QHostAddress(this->serverUrl().host()), static_cast(this->serverUrl().port())); + } else { + m_tcpSocket->connectToHostEncrypted(this->serverUrl().host(), static_cast(this->serverUrl().port())); + } +} + +void TcpSocketConnection::disconnectServer() +{ + qCDebug(dcRemoteProxyClientTcpSocket()) << "Disconnecting from" << serverUrl().toString(); + m_tcpSocket->close(); +} + +} diff --git a/libnymea-remoteproxyclient/tcpsocketconnection.h b/libnymea-remoteproxyclient/tcpsocketconnection.h new file mode 100644 index 0000000..f9ea374 --- /dev/null +++ b/libnymea-remoteproxyclient/tcpsocketconnection.h @@ -0,0 +1,46 @@ +#ifndef TCPSOCKETCONNECTION_H +#define TCPSOCKETCONNECTION_H + +#include +#include +#include +#include + +#include "proxyconnection.h" + +Q_DECLARE_LOGGING_CATEGORY(dcRemoteProxyClienTcpSocket) + +namespace remoteproxyclient { + +class TcpSocketConnection : public ProxyConnection +{ + Q_OBJECT + +public: + explicit TcpSocketConnection(QObject *parent = nullptr); + ~TcpSocketConnection() override; + + void sendData(const QByteArray &data) override; + + void ignoreSslErrors() override; + void ignoreSslErrors(const QList &errors) override; + +private: + QSslSocket *m_tcpSocket = nullptr; + +private slots: + void onDisconnected(); + void onEncrypted(); + void onError(QAbstractSocket::SocketError error); + void onStateChanged(QAbstractSocket::SocketState state); + void onReadyRead(); + +public slots: + void connectServer(const QUrl &serverUrl) override; + void disconnectServer() override; + +}; + +} + +#endif // TCPSOCKETCONNECTION_H diff --git a/libnymea-remoteproxyclient/websocketconnection.cpp b/libnymea-remoteproxyclient/websocketconnection.cpp index 5177cad..2b4dace 100644 --- a/libnymea-remoteproxyclient/websocketconnection.cpp +++ b/libnymea-remoteproxyclient/websocketconnection.cpp @@ -49,11 +49,6 @@ WebSocketConnection::~WebSocketConnection() m_webSocket->close(); } -QUrl WebSocketConnection::serverUrl() const -{ - return m_serverUrl; -} - void WebSocketConnection::sendData(const QByteArray &data) { m_webSocket->sendTextMessage(QString::fromUtf8(data + '\n')); @@ -108,10 +103,10 @@ void WebSocketConnection::connectServer(const QUrl &serverUrl) if (connected()) { m_webSocket->close(); } + setServerUrl(serverUrl); - m_serverUrl = serverUrl; - qCDebug(dcRemoteProxyClientWebSocket()) << "Connecting to" << m_serverUrl.toString(); - m_webSocket->open(m_serverUrl); + qCDebug(dcRemoteProxyClientWebSocket()) << "Connecting to" << this->serverUrl().toString(); + m_webSocket->open(this->serverUrl()); } void WebSocketConnection::disconnectServer() diff --git a/libnymea-remoteproxyclient/websocketconnection.h b/libnymea-remoteproxyclient/websocketconnection.h index cf7e771..252d0d9 100644 --- a/libnymea-remoteproxyclient/websocketconnection.h +++ b/libnymea-remoteproxyclient/websocketconnection.h @@ -46,15 +46,12 @@ public: explicit WebSocketConnection(QObject *parent = nullptr); ~WebSocketConnection() override; - QUrl serverUrl() const override; - void sendData(const QByteArray &data) override; void ignoreSslErrors() override; void ignoreSslErrors(const QList &errors) override; private: - QUrl m_serverUrl; QWebSocket *m_webSocket = nullptr; private slots: diff --git a/nymea-remoteproxy.conf b/nymea-remoteproxy.conf index 9266c60..639f33c 100644 --- a/nymea-remoteproxy.conf +++ b/nymea-remoteproxy.conf @@ -15,6 +15,7 @@ authorizerLambdaFunction=system-services-authorizer-dev-checkToken awsCredentialsUrl=http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-Remote-Connection-Proxy-Role [SSL] +enabled=true certificate=/etc/ssl/certs/ssl-cert-snakeoil.pem certificateKey=/etc/ssl/private/ssl-cert-snakeoil.key certificateChain= diff --git a/server/main.cpp b/server/main.cpp index 9d9d80d..0a8a67a 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -186,9 +186,11 @@ int main(int argc, char *argv[]) } // Verify SSL configuration - if (configuration->sslConfiguration().isNull()) { - qCCritical(dcApplication()) << "No SSL configuration specified. The server does not suppoert insecure connections."; + if (configuration->sslEnabled() && configuration->sslConfiguration().isNull()) { + qCCritical(dcApplication()) << "SSL is enabled but no SSL configuration specified."; exit(-1); + } else { + qCDebug(dcApplication()) << "Using SSL version:" << QSslSocket::sslLibraryVersionString(); } qCDebug(dcApplication()) << "=========================================================="; @@ -203,7 +205,6 @@ int main(int argc, char *argv[]) if (s_loggingEnabled) qCDebug(dcApplication()) << "Logging enabled. Writing logs to" << s_logFile.fileName(); - qCDebug(dcApplication()) << "Using SSL version:" << QSslSocket::sslLibraryVersionString(); Authenticator *authenticator = nullptr; if (parser.isSet(mockAuthenticatorOption)) {