From 63ffc163baf668159a560a905b3f780a65ce501b Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Thu, 31 Aug 2017 23:30:06 +0200 Subject: [PATCH] make auth config work --- server/jsonrpc/jsonrpcserver.cpp | 38 +++++++++------- server/jsonrpc/jsonrpcserver.h | 4 +- server/servermanager.cpp | 8 ++-- server/tcpserver.cpp | 76 ++++++++++++++------------------ server/tcpserver.h | 11 +++-- server/webserver.cpp | 45 +++---------------- server/webserver.h | 4 -- 7 files changed, 72 insertions(+), 114 deletions(-) diff --git a/server/jsonrpc/jsonrpcserver.cpp b/server/jsonrpc/jsonrpcserver.cpp index dbcfc459..aea6d594 100644 --- a/server/jsonrpc/jsonrpcserver.cpp +++ b/server/jsonrpc/jsonrpcserver.cpp @@ -238,16 +238,17 @@ QHash JsonRPCServer::handlers() const } /*! Register a new \l{TransportInterface} to the JSON server. The \a enabled flag indivates if the given \a interface sould be enebeld on startup. */ -void JsonRPCServer::registerTransportInterface(TransportInterface *interface, const bool &enabled) +void JsonRPCServer::registerTransportInterface(TransportInterface *interface, bool enabled, bool authenticationRequired) { connect(interface, &TransportInterface::clientConnected, this, &JsonRPCServer::clientConnected); connect(interface, &TransportInterface::clientDisconnected, this, &JsonRPCServer::clientDisconnected); connect(interface, &TransportInterface::dataAvailable, this, &JsonRPCServer::processData); - if (enabled) - QMetaObject::invokeMethod(interface, "startServer", Qt::QueuedConnection); + m_interfaces.insert(interface, authenticationRequired); - m_interfaces.append(interface); + if (enabled) { + QMetaObject::invokeMethod(interface, "startServer", Qt::QueuedConnection); + } } /*! Send a JSON success response to the client with the given \a clientId, @@ -330,18 +331,21 @@ void JsonRPCServer::processData(const QUuid &clientId, const QByteArray &data) QString targetNamespace = commandList.first(); QString method = commandList.last(); - // if there is no user in the system yet, let's fail unless this is a CreateUser or Introspect call - if (GuhCore::instance()->userManager()->users().isEmpty()) { - if (!(targetNamespace == "JSONRPC" && (method == "CreateUser" || method == "Introspect"))) { - sendUnauthorizedResponse(interface, clientId, commandId, "Initial setup required. Call CreateUser first."); - return; - } - } else { - // ok, we have a user. if there isn't a valid token, let's fail unless this is a Authenticate or Introspect call - QByteArray token = message.value("token").toByteArray(); - if (!(targetNamespace == "JSONRPC" && (method == "Authenticate" || method == "Introspect")) && !GuhCore::instance()->userManager()->verifyToken(token)) { - sendUnauthorizedResponse(interface, clientId, commandId, "Forbidden: Invalid token."); - return; + // check if authentication is required for this transport + if (m_interfaces.value(interface)) { + // if there is no user in the system yet, let's fail unless this is a CreateUser or Introspect call + if (GuhCore::instance()->userManager()->users().isEmpty()) { + if (!(targetNamespace == "JSONRPC" && (method == "CreateUser" || method == "Introspect"))) { + sendUnauthorizedResponse(interface, clientId, commandId, "Initial setup required. Call CreateUser first."); + return; + } + } else { + // ok, we have a user. if there isn't a valid token, let's fail unless this is a Authenticate or Introspect call + QByteArray token = message.value("token").toByteArray(); + if (!(targetNamespace == "JSONRPC" && (method == "Authenticate" || method == "Introspect")) && !GuhCore::instance()->userManager()->verifyToken(token)) { + sendUnauthorizedResponse(interface, clientId, commandId, "Forbidden: Invalid token."); + return; + } } } // At this point we can assume all the calls are authorized @@ -404,7 +408,7 @@ void JsonRPCServer::sendNotification(const QVariantMap ¶ms) notification.insert("notification", handler->name() + "." + method.name()); notification.insert("params", params); - foreach (TransportInterface *interface, m_interfaces) { + foreach (TransportInterface *interface, m_interfaces.keys()) { interface->sendData(m_clients.keys(true), QJsonDocument::fromVariant(notification).toJson()); } } diff --git a/server/jsonrpc/jsonrpcserver.h b/server/jsonrpc/jsonrpcserver.h index 212fbb1f..574d9671 100644 --- a/server/jsonrpc/jsonrpcserver.h +++ b/server/jsonrpc/jsonrpcserver.h @@ -58,7 +58,7 @@ public: QHash handlers() const; - void registerTransportInterface(TransportInterface *interface, const bool &enabled = true); + void registerTransportInterface(TransportInterface *interface, bool enabled, bool authenticationRequired); private: void sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms = QVariantMap()); @@ -78,7 +78,7 @@ private slots: void asyncReplyFinished(); private: - QList m_interfaces; + QMap m_interfaces; QHash m_handlers; QHash m_asyncReplies; diff --git a/server/servermanager.cpp b/server/servermanager.cpp index 0e22a3d7..0e566adb 100644 --- a/server/servermanager.cpp +++ b/server/servermanager.cpp @@ -94,22 +94,22 @@ ServerManager::ServerManager(GuhConfiguration* configuration, QObject *parent) : // Transports #ifdef TESTING_ENABLED MockTcpServer *tcpServer = new MockTcpServer(this); - m_jsonServer->registerTransportInterface(tcpServer); + m_jsonServer->registerTransportInterface(tcpServer, true, true); #else foreach (const ServerConfiguration &config, configuration->tcpServerConfigurations()) { TcpServer *tcpServer = new TcpServer(config.address, config.port, config.sslEnabled, m_sslConfiguration, this); - m_jsonServer->registerTransportInterface(tcpServer); + m_jsonServer->registerTransportInterface(tcpServer, true, config.authenticationEnabled); } #endif foreach (const ServerConfiguration &config, configuration->webSocketServerConfigurations()) { qWarning() << "Have websockeserver config" << config.id; WebSocketServer *webSocketServer = new WebSocketServer(config.address, config.port, config.sslEnabled, m_sslConfiguration, this); - m_jsonServer->registerTransportInterface(webSocketServer); + m_jsonServer->registerTransportInterface(webSocketServer, true, config.authenticationEnabled); } m_bluetoothServer = new BluetoothServer(this); - m_jsonServer->registerTransportInterface(m_bluetoothServer, configuration->bluetoothServerEnabled()); + m_jsonServer->registerTransportInterface(m_bluetoothServer, configuration->bluetoothServerEnabled(), true); foreach (const WebServerConfiguration &config, configuration->webServerConfigurations()) { WebServer *webServer = new WebServer(config.address, config.port, config.publicFolder, config.sslEnabled, m_sslConfiguration, this); diff --git a/server/tcpserver.cpp b/server/tcpserver.cpp index 0722f05e..32c9d428 100644 --- a/server/tcpserver.cpp +++ b/server/tcpserver.cpp @@ -80,53 +80,25 @@ void TcpServer::sendData(const QUuid &clientId, const QByteArray &data) QTcpSocket *client = 0; client = m_clientList.value(clientId); if (client) { + qWarning() << "send data:" << data; client->write(data); } } void TcpServer::onClientConnected(QSslSocket *socket) { - // got a new client connected qCDebug(dcConnection) << "Tcp server: new client connected:" << socket->peerAddress().toString(); - QUuid clientId = QUuid::createUuid(); - - // append the new client to the client list m_clientList.insert(clientId, socket); - emit clientConnected(clientId); } -void TcpServer::readPackage() +void TcpServer::onClientDisconnected(QSslSocket *socket) { - QTcpSocket *client = qobject_cast(sender()); - qCDebug(dcTcpServer) << "Data coming from" << client->peerAddress().toString(); - QByteArray message; - while (client->canReadLine()) { - QByteArray dataLine = client->readLine(); - qCDebug(dcTcpServer) << "Line in:" << dataLine; - message.append(dataLine); - if (dataLine.endsWith('\n')) { - emit dataAvailable(m_clientList.key(client), message); - message.clear(); - } - } -} - -void TcpServer::onSslErrors(const QList &errors) -{ - qCWarning(dcTcpServer) << "SSL errors:" << errors; -} - -void TcpServer::onClientDisconnected() -{ - QPointer client = qobject_cast(sender()); - if (client.isNull()) - return; - - qCDebug(dcConnection) << "Tcp server: client disconnected:" << client->peerAddress().toString(); - QUuid clientId = m_clientList.key(client); - m_clientList.take(clientId)->deleteLater(); + qCDebug(dcConnection) << "Tcp server: client disconnected:" << socket->peerAddress().toString(); + QUuid clientId = m_clientList.key(socket); + m_clientList.take(clientId); + emit clientDisconnected(clientId); } void TcpServer::onError(QAbstractSocket::SocketError error) @@ -141,6 +113,12 @@ void TcpServer::onEncrypted() qCDebug(dcTcpServer) << "TCP Server connection encrypted"; } +void TcpServer::onDataAvailable(QSslSocket * socket, const QByteArray &data) +{ + QUuid clientId = m_clientList.key(socket); + emit dataAvailable(clientId, data); +} + void TcpServer::onAvahiServiceStateChanged(const QtAvahiService::QtAvahiServiceState &state) { if (state == QtAvahiService::QtAvahiServiceStateEstablished) { @@ -204,6 +182,8 @@ bool TcpServer::startServer() qCDebug(dcConnection) << "Started Tcp server on" << m_server->serverAddress().toString() << m_server->serverPort(); connect(m_server, SIGNAL(clientConnected(QSslSocket *)), SLOT(onClientConnected(QSslSocket *))); + connect(m_server, SIGNAL(clientDisconnected(QSslSocket *)), SLOT(onClientDisconnected(QSslSocket *))); + connect(m_server, &SslServer::dataAvailable, this, &TcpServer::onDataAvailable); return true; } @@ -231,23 +211,17 @@ void SslServer::incomingConnection(qintptr socketDescriptor) { qWarning() << "incoming"; QSslSocket *sslSocket = new QSslSocket(this); - connect(sslSocket, &QSslSocket::encrypted, [this, sslSocket](){ - qWarning() << "encrypted"; - emit clientConnected(sslSocket); - }); - connect(sslSocket, &QSslSocket::readyRead, [this, sslSocket]() { - qWarning() << "readyRead:" << sslSocket->readAll(); -// sslSocket->startServerEncryption(); - }); + connect(sslSocket, &QSslSocket::encrypted, [this, sslSocket](){ emit clientConnected(sslSocket); }); + connect(sslSocket, &QSslSocket::readyRead, this, &SslServer::onSocketReadyRead); + connect(sslSocket, &QSslSocket::disconnected, this, &SslServer::onClientDisconnected); if (!sslSocket->setSocketDescriptor(socketDescriptor)) { - qCWarning(dcConnection) << "Failed to set SSL socket"; + qCWarning(dcConnection) << "Failed to set SSL socket descriptor."; delete sslSocket; return; } if (m_sslEnabled) { - qWarning() << "starting encryption"; sslSocket->setSslConfiguration(m_config); sslSocket->startServerEncryption(); } else { @@ -255,4 +229,18 @@ void SslServer::incomingConnection(qintptr socketDescriptor) } } +void SslServer::onClientDisconnected() +{ + QSslSocket *socket = static_cast(sender()); + emit clientDisconnected(socket); + socket->deleteLater(); +} + +void SslServer::onSocketReadyRead() +{ + QSslSocket *socket = static_cast(sender()); + QByteArray data = socket->readAll(); + emit dataAvailable(socket, data); +} + } diff --git a/server/tcpserver.h b/server/tcpserver.h index 1fd65bdb..f1cdbd3b 100644 --- a/server/tcpserver.h +++ b/server/tcpserver.h @@ -52,10 +52,16 @@ public: signals: void clientConnected(QSslSocket *socket); + void clientDisconnected(QSslSocket *socket); + void dataAvailable(QSslSocket *socket, const QByteArray &data); protected: void incomingConnection(qintptr socketDescriptor) override; +private slots: + void onClientDisconnected(); + void onSocketReadyRead(); + private: bool m_sslEnabled = false; QSslConfiguration m_config; @@ -87,9 +93,8 @@ private: private slots: void onClientConnected(QSslSocket *socket); - void onClientDisconnected(); - void readPackage(); - void onSslErrors(const QList &errors); + void onClientDisconnected(QSslSocket *socket); + void onDataAvailable(QSslSocket *socket, const QByteArray &data); void onError(QAbstractSocket::SocketError error); void onEncrypted(); diff --git a/server/webserver.cpp b/server/webserver.cpp index 0dfc3655..745504c1 100644 --- a/server/webserver.cpp +++ b/server/webserver.cpp @@ -143,27 +143,6 @@ void WebServer::sendHttpReply(HttpReply *reply) socket->write(reply->data()); } -/*! Returns the port on which the webserver is listening. */ -int WebServer::port() const -{ - return m_port; -} - -/*! Returns the list of addresses on which the webserver is listening. */ -QList WebServer::serverAddressList() -{ - QList addresses; - foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) { - // listen only on IPv4 - foreach (QNetworkAddressEntry entry, interface.addressEntries()) { - if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) { - addresses.append(entry.ip()); - } - } - } - return addresses; -} - bool WebServer::verifyFile(QSslSocket *socket, const QString &fileName) { QFileInfo file(fileName); @@ -235,17 +214,6 @@ HttpReply *WebServer::processIconRequest(const QString &fileName) return RestResource::createErrorReply(HttpReply::NotFound); } -QHostAddress WebServer::getServerAddress(QHostAddress clientAddress) -{ - foreach (QHostAddress address, serverAddressList()) { - if (clientAddress.isInSubnet(QHostAddress::parseSubnet(address.toString() + "/24"))) { - qCDebug(dcWebServer) << "server for" << clientAddress.toString() << " ->" << address.toString(); - return address; - } - } - return QHostAddress(); -} - void WebServer::incomingConnection(qintptr socketDescriptor) { if (!m_enabled) @@ -397,8 +365,7 @@ void WebServer::readClient() qCDebug(dcWebServer) << "server XML request call"; HttpReply *reply = RestResource::createSuccessReply(); reply->setHeader(HttpReply::ContentTypeHeader, "text/xml"); - QHostAddress serverAddress = getServerAddress(socket->peerAddress()); - reply->setPayload(createServerXmlDocument(serverAddress)); + reply->setPayload(createServerXmlDocument(m_host)); reply->setClientId(clientId); sendHttpReply(reply); reply->deleteLater(); @@ -553,12 +520,10 @@ bool WebServer::startServer() return false; } - foreach (QHostAddress address, serverAddressList()) { - if (m_useSsl) { - qCDebug(dcConnection) << "Started webserver on" << QString("https://%1:%2").arg(address.toString()).arg(m_port); - } else { - qCDebug(dcConnection) << "Started webserver on" << QString("http://%1:%2").arg(address.toString()).arg(m_port); - } + if (m_useSsl) { + qCDebug(dcConnection) << "Started webserver on" << QString("https://%1:%2").arg(m_host.toString()).arg(m_port); + } else { + qCDebug(dcConnection) << "Started webserver on" << QString("http://%1:%2").arg(m_host.toString()).arg(m_port); } #ifndef TESTING_ENABLED diff --git a/server/webserver.h b/server/webserver.h index d480fb44..1c2cd374 100644 --- a/server/webserver.h +++ b/server/webserver.h @@ -76,9 +76,6 @@ public: ~WebServer(); void sendHttpReply(HttpReply *reply); - int port() const; - QList serverAddressList(); - private: QHash m_clientList; @@ -101,7 +98,6 @@ private: QByteArray createServerXmlDocument(QHostAddress address); HttpReply *processIconRequest(const QString &fileName); - QHostAddress getServerAddress(QHostAddress clientAddress); protected: void incomingConnection(qintptr socketDescriptor) override;