make auth config work

This commit is contained in:
Michael Zanetti 2017-08-31 23:30:06 +02:00
parent a4658332ff
commit 63ffc163ba
7 changed files with 72 additions and 114 deletions

View File

@ -238,16 +238,17 @@ QHash<QString, JsonHandler *> 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 &params)
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());
}
}

View File

@ -58,7 +58,7 @@ public:
QHash<QString, JsonHandler *> 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 &params = QVariantMap());
@ -78,7 +78,7 @@ private slots:
void asyncReplyFinished();
private:
QList<TransportInterface *> m_interfaces;
QMap<TransportInterface*, bool> m_interfaces;
QHash<QString, JsonHandler *> m_handlers;
QHash<JsonReply *, TransportInterface *> m_asyncReplies;

View File

@ -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);

View File

@ -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<QTcpSocket*>(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<QSslError> &errors)
{
qCWarning(dcTcpServer) << "SSL errors:" << errors;
}
void TcpServer::onClientDisconnected()
{
QPointer<QTcpSocket> client = qobject_cast<QTcpSocket *>(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<QSslSocket*>(sender());
emit clientDisconnected(socket);
socket->deleteLater();
}
void SslServer::onSocketReadyRead()
{
QSslSocket *socket = static_cast<QSslSocket*>(sender());
QByteArray data = socket->readAll();
emit dataAvailable(socket, data);
}
}

View File

@ -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<QSslError> &errors);
void onClientDisconnected(QSslSocket *socket);
void onDataAvailable(QSslSocket *socket, const QByteArray &data);
void onError(QAbstractSocket::SocketError error);
void onEncrypted();

View File

@ -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<QHostAddress> WebServer::serverAddressList()
{
QList<QHostAddress> 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

View File

@ -76,9 +76,6 @@ public:
~WebServer();
void sendHttpReply(HttpReply *reply);
int port() const;
QList<QHostAddress> serverAddressList();
private:
QHash<QUuid, QSslSocket *> 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;