Merge PR #707: Disable insecure interfaces if configured using env
This commit is contained in:
commit
cc164e50f7
@ -71,6 +71,7 @@
|
|||||||
#include "configurationhandler.h"
|
#include "configurationhandler.h"
|
||||||
#include "nymeacore.h"
|
#include "nymeacore.h"
|
||||||
#include "nymeaconfiguration.h"
|
#include "nymeaconfiguration.h"
|
||||||
|
#include "loggingcategories.h"
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "platform/platformsystemcontroller.h"
|
#include "platform/platformsystemcontroller.h"
|
||||||
|
|
||||||
@ -448,9 +449,9 @@ JsonReply *ConfigurationHandler::SetLocation(const QVariantMap ¶ms) const
|
|||||||
JsonReply *ConfigurationHandler::SetTcpServerConfiguration(const QVariantMap ¶ms) const
|
JsonReply *ConfigurationHandler::SetTcpServerConfiguration(const QVariantMap ¶ms) const
|
||||||
{
|
{
|
||||||
ServerConfiguration config = unpack<ServerConfiguration>(params.value("configuration").toMap());
|
ServerConfiguration config = unpack<ServerConfiguration>(params.value("configuration").toMap());
|
||||||
if (config.id.isEmpty()) {
|
if (config.id.isEmpty())
|
||||||
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId));
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId));
|
||||||
}
|
|
||||||
if (config.address.isNull())
|
if (config.address.isNull())
|
||||||
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidHostAddress));
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidHostAddress));
|
||||||
|
|
||||||
@ -459,8 +460,17 @@ JsonReply *ConfigurationHandler::SetTcpServerConfiguration(const QVariantMap &pa
|
|||||||
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidPort));
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidPort));
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcJsonRpc()) << QString("Configure TCP server %1:%2").arg(config.address).arg(config.port);
|
// To be compliant with the EN18031 we have to make sure the user cannot configure an insecure interface to the server.
|
||||||
|
if (qEnvironmentVariable("NYMEA_INSECURE_INTERFACES_DISABLED", "0") != "0") {
|
||||||
|
bool isLocalhost = config.address == "localhost" || config.address == "127.0.0.1";
|
||||||
|
bool isSecured = config.sslEnabled && config.authenticationEnabled;
|
||||||
|
if (!isLocalhost && !isSecured) {
|
||||||
|
qCWarning(dcJsonRpc()) << "Cannot add insecure TCP server configuration" << config << "because insecure interfaces to the core are explicit disabled.";
|
||||||
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorUnsupported));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(dcJsonRpc()) << QString("Configure TCP server %1:%2").arg(config.address).arg(config.port);
|
||||||
NymeaCore::instance()->configuration()->setTcpServerConfiguration(config);
|
NymeaCore::instance()->configuration()->setTcpServerConfiguration(config);
|
||||||
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorNoError));
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorNoError));
|
||||||
}
|
}
|
||||||
@ -509,9 +519,9 @@ JsonReply *ConfigurationHandler::DeleteWebServerConfiguration(const QVariantMap
|
|||||||
JsonReply *ConfigurationHandler::SetWebSocketServerConfiguration(const QVariantMap ¶ms) const
|
JsonReply *ConfigurationHandler::SetWebSocketServerConfiguration(const QVariantMap ¶ms) const
|
||||||
{
|
{
|
||||||
ServerConfiguration config = unpack<ServerConfiguration>(params.value("configuration").toMap());
|
ServerConfiguration config = unpack<ServerConfiguration>(params.value("configuration").toMap());
|
||||||
if (config.id.isEmpty()) {
|
if (config.id.isEmpty())
|
||||||
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId));
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId));
|
||||||
}
|
|
||||||
if (config.address.isNull())
|
if (config.address.isNull())
|
||||||
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidHostAddress));
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidHostAddress));
|
||||||
|
|
||||||
@ -520,6 +530,16 @@ JsonReply *ConfigurationHandler::SetWebSocketServerConfiguration(const QVariantM
|
|||||||
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidPort));
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidPort));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To be compliant with the EN18031 we have to make sure the user cannot configure an insecure interface to the server.
|
||||||
|
if (qEnvironmentVariable("NYMEA_INSECURE_INTERFACES_DISABLED", "0") != "0") {
|
||||||
|
bool isLocalhost = config.address == "localhost" || config.address == "127.0.0.1";
|
||||||
|
bool isSecured = config.sslEnabled && config.authenticationEnabled;
|
||||||
|
if (!isLocalhost && !isSecured) {
|
||||||
|
qCWarning(dcJsonRpc()) << "Cannot add insecure WebSocket server configuration" << config << "because insecure interfaces to the core are explicit disabled.";
|
||||||
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorUnsupported));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qCDebug(dcJsonRpc()) << QString("Configuring web socket server %1:%2").arg(config.address).arg(config.port);
|
qCDebug(dcJsonRpc()) << QString("Configuring web socket server %1:%2").arg(config.address).arg(config.port);
|
||||||
|
|
||||||
NymeaCore::instance()->configuration()->setWebSocketServerConfiguration(config);
|
NymeaCore::instance()->configuration()->setWebSocketServerConfiguration(config);
|
||||||
@ -540,9 +560,9 @@ JsonReply *ConfigurationHandler::DeleteWebSocketServerConfiguration(const QVaria
|
|||||||
JsonReply *ConfigurationHandler::SetTunnelProxyServerConfiguration(const QVariantMap ¶ms) const
|
JsonReply *ConfigurationHandler::SetTunnelProxyServerConfiguration(const QVariantMap ¶ms) const
|
||||||
{
|
{
|
||||||
TunnelProxyServerConfiguration config = unpack<TunnelProxyServerConfiguration>(params.value("configuration").toMap());
|
TunnelProxyServerConfiguration config = unpack<TunnelProxyServerConfiguration>(params.value("configuration").toMap());
|
||||||
if (config.id.isEmpty()) {
|
if (config.id.isEmpty())
|
||||||
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId));
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId));
|
||||||
}
|
|
||||||
if (config.address.isNull())
|
if (config.address.isNull())
|
||||||
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidHostAddress));
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidHostAddress));
|
||||||
|
|
||||||
@ -551,6 +571,14 @@ JsonReply *ConfigurationHandler::SetTunnelProxyServerConfiguration(const QVarian
|
|||||||
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidPort));
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidPort));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To be compliant with the EN18031 we have to make sure the user cannot configure an insecure interface to the server.
|
||||||
|
if (qEnvironmentVariable("NYMEA_INSECURE_INTERFACES_DISABLED", "0") != "0") {
|
||||||
|
if (!config.sslEnabled || !config.authenticationEnabled || config.ignoreSslErrors) {
|
||||||
|
qCWarning(dcJsonRpc()) << "Cannot add insecure tunnelproxy server configuration" << config << "because insecure interfaces to the core are explicit disabled.";
|
||||||
|
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorUnsupported));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qCDebug(dcJsonRpc()) << QString("Configuring tunnel proxy server %1:%2").arg(config.address).arg(config.port);
|
qCDebug(dcJsonRpc()) << QString("Configuring tunnel proxy server %1:%2").arg(config.address).arg(config.port);
|
||||||
|
|
||||||
NymeaCore::instance()->configuration()->setTunnelProxyServerConfiguration(config);
|
NymeaCore::instance()->configuration()->setTunnelProxyServerConfiguration(config);
|
||||||
@ -757,10 +785,10 @@ QVariantMap ConfigurationHandler::packBasicConfiguration()
|
|||||||
basicConfiguration.insert("timeZone", QTimeZone::systemTimeZoneId());
|
basicConfiguration.insert("timeZone", QTimeZone::systemTimeZoneId());
|
||||||
basicConfiguration.insert("language", NymeaCore::instance()->configuration()->locale().name());
|
basicConfiguration.insert("language", NymeaCore::instance()->configuration()->locale().name());
|
||||||
basicConfiguration.insert("location", QVariantMap{
|
basicConfiguration.insert("location", QVariantMap{
|
||||||
{"latitude", NymeaCore::instance()->configuration()->locationLatitude()},
|
{"latitude", NymeaCore::instance()->configuration()->locationLatitude()},
|
||||||
{"longitude", NymeaCore::instance()->configuration()->locationLongitude()},
|
{"longitude", NymeaCore::instance()->configuration()->locationLongitude()},
|
||||||
{"name", NymeaCore::instance()->configuration()->locationName()}
|
{"name", NymeaCore::instance()->configuration()->locationName()}
|
||||||
});
|
});
|
||||||
basicConfiguration.insert("debugServerEnabled", NymeaCore::instance()->configuration()->debugServerEnabled());
|
basicConfiguration.insert("debugServerEnabled", NymeaCore::instance()->configuration()->debugServerEnabled());
|
||||||
return basicConfiguration;
|
return basicConfiguration;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -576,7 +576,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac
|
|||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||||
|
|
||||||
if(error.error != QJsonParseError::NoError) {
|
if(error.error != QJsonParseError::NoError) {
|
||||||
qCWarning(dcJsonRpc) << "Failed to parse JSON data" << data << ":" << error.errorString();
|
qCWarning(dcJsonRpc()) << "Failed to parse JSON data" << data << ":" << error.errorString();
|
||||||
sendErrorResponse(interface, clientId, -1, QString("Failed to parse JSON data: %1").arg(error.errorString()));
|
sendErrorResponse(interface, clientId, -1, QString("Failed to parse JSON data: %1").arg(error.errorString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -586,7 +586,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac
|
|||||||
bool success;
|
bool success;
|
||||||
int commandId = message.value("id").toInt(&success);
|
int commandId = message.value("id").toInt(&success);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
qCWarning(dcJsonRpc) << "Error parsing command. Missing \"id\":" << message;
|
qCWarning(dcJsonRpc()) << "Error parsing command. Missing \"id\":" << message;
|
||||||
sendErrorResponse(interface, clientId, commandId, "Error parsing command. Missing 'id'");
|
sendErrorResponse(interface, clientId, commandId, "Error parsing command. Missing 'id'");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -594,7 +594,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac
|
|||||||
QString methodString = message.value("method").toString();
|
QString methodString = message.value("method").toString();
|
||||||
QStringList commandList = methodString.split('.');
|
QStringList commandList = methodString.split('.');
|
||||||
if (commandList.count() != 2) {
|
if (commandList.count() != 2) {
|
||||||
qCWarning(dcJsonRpc) << "Error parsing method.\nGot:" << message.value("method").toString() << "\nExpected: \"Namespace.method\"";
|
qCWarning(dcJsonRpc()) << "Error parsing method.\nGot:" << message.value("method").toString() << "\nExpected: \"Namespace.method\"";
|
||||||
sendErrorResponse(interface, clientId, commandId, QString("Error parsing method. Got: '%1'', Expected: 'Namespace.method'").arg(message.value("method").toString()));
|
sendErrorResponse(interface, clientId, commandId, QString("Error parsing method. Got: '%1'', Expected: 'Namespace.method'").arg(message.value("method").toString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -607,7 +607,7 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac
|
|||||||
token = message.value("token").toByteArray();
|
token = message.value("token").toByteArray();
|
||||||
} else if (message.value("token").toByteArray() != token) {
|
} else if (message.value("token").toByteArray() != token) {
|
||||||
qCWarning(dcJsonRpc()) << "Client changed token without redoing the handshake.";
|
qCWarning(dcJsonRpc()) << "Client changed token without redoing the handshake.";
|
||||||
qCDebug(dcJsonRpc) << "Old token:" << token << "new token:" << message.value("token").toByteArray();
|
qCDebug(dcJsonRpc()) << "Old token:" << token << "new token:" << message.value("token").toByteArray();
|
||||||
sendUnauthorizedResponse(interface, clientId, commandId, "Changing the user (token) requires a new handshake. Call JSONRPC.Hello.");
|
sendUnauthorizedResponse(interface, clientId, commandId, "Changing the user (token) requires a new handshake. Call JSONRPC.Hello.");
|
||||||
interface->terminateClientConnection(clientId);
|
interface->terminateClientConnection(clientId);
|
||||||
qCWarning(dcJsonRpc()) << "Staring connection lockdown timer";
|
qCWarning(dcJsonRpc()) << "Staring connection lockdown timer";
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "tagshandler.h"
|
#include "tagshandler.h"
|
||||||
|
|
||||||
|
#include "loggingcategories.h"
|
||||||
#include "nymeacore.h"
|
#include "nymeacore.h"
|
||||||
#include "tagging/tagsstorage.h"
|
#include "tagging/tagsstorage.h"
|
||||||
|
|
||||||
@ -142,7 +143,7 @@ JsonReply *TagsHandler::RemoveTag(const QVariantMap ¶ms) const
|
|||||||
|
|
||||||
void TagsHandler::onTagAdded(const Tag &tag)
|
void TagsHandler::onTagAdded(const Tag &tag)
|
||||||
{
|
{
|
||||||
qCDebug(dcJsonRpc) << "Notify \"Tags.TagAdded\"";
|
qCDebug(dcJsonRpc()) << "Notify \"Tags.TagAdded\"";
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
params.insert("tag", pack(tag));
|
params.insert("tag", pack(tag));
|
||||||
emit TagAdded(params);
|
emit TagAdded(params);
|
||||||
@ -150,7 +151,7 @@ void TagsHandler::onTagAdded(const Tag &tag)
|
|||||||
|
|
||||||
void TagsHandler::onTagRemoved(const Tag &tag)
|
void TagsHandler::onTagRemoved(const Tag &tag)
|
||||||
{
|
{
|
||||||
qCDebug(dcJsonRpc) << "Notify \"Tags.TagRemoved\"";
|
qCDebug(dcJsonRpc()) << "Notify \"Tags.TagRemoved\"";
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
params.insert("tag", pack(tag));
|
params.insert("tag", pack(tag));
|
||||||
emit TagRemoved(params);
|
emit TagRemoved(params);
|
||||||
@ -158,7 +159,7 @@ void TagsHandler::onTagRemoved(const Tag &tag)
|
|||||||
|
|
||||||
void TagsHandler::onTagValueChanged(const Tag &tag)
|
void TagsHandler::onTagValueChanged(const Tag &tag)
|
||||||
{
|
{
|
||||||
qCDebug(dcJsonRpc) << "Notify \"Tags.TagValueChanged\"";
|
qCDebug(dcJsonRpc()) << "Notify \"Tags.TagValueChanged\"";
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
params.insert("tag", pack(tag));
|
params.insert("tag", pack(tag));
|
||||||
emit TagValueChanged(params);
|
emit TagValueChanged(params);
|
||||||
|
|||||||
@ -325,8 +325,12 @@ QLocale NymeaConfiguration::locale() const
|
|||||||
|
|
||||||
void NymeaConfiguration::setLocale(const QLocale &locale)
|
void NymeaConfiguration::setLocale(const QLocale &locale)
|
||||||
{
|
{
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
qCDebug(dcConfiguration()) << "Configuration: Set system locale:" << locale.name() << locale.nativeCountryName() << locale.nativeLanguageName();
|
qCDebug(dcConfiguration()) << "Configuration: Set system locale:" << locale.name() << locale.nativeCountryName() << locale.nativeLanguageName();
|
||||||
|
#else
|
||||||
|
qCDebug(dcConfiguration()) << "Configuration: Set system locale:" << locale.name() << locale.nativeTerritoryName() << locale.nativeLanguageName();
|
||||||
|
|
||||||
|
#endif
|
||||||
NymeaSettings settings(NymeaSettings::SettingsRoleGlobal);
|
NymeaSettings settings(NymeaSettings::SettingsRoleGlobal);
|
||||||
settings.beginGroup("nymead");
|
settings.beginGroup("nymead");
|
||||||
if (settings.value("language").toString() == locale.name()) {
|
if (settings.value("language").toString() == locale.name()) {
|
||||||
|
|||||||
@ -129,7 +129,8 @@ public:
|
|||||||
ConfigurationErrorInvalidPort,
|
ConfigurationErrorInvalidPort,
|
||||||
ConfigurationErrorInvalidHostAddress,
|
ConfigurationErrorInvalidHostAddress,
|
||||||
ConfigurationErrorBluetoothHardwareNotAvailable,
|
ConfigurationErrorBluetoothHardwareNotAvailable,
|
||||||
ConfigurationErrorInvalidCertificate
|
ConfigurationErrorInvalidCertificate,
|
||||||
|
ConfigurationErrorUnsupported
|
||||||
};
|
};
|
||||||
Q_ENUM(ConfigurationError)
|
Q_ENUM(ConfigurationError)
|
||||||
|
|
||||||
|
|||||||
@ -49,6 +49,7 @@
|
|||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "platform/platformzeroconfcontroller.h"
|
#include "platform/platformzeroconfcontroller.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
#include "jsonrpc/jsonrpcserverimplementation.h"
|
#include "jsonrpc/jsonrpcserverimplementation.h"
|
||||||
#include "servers/mocktcpserver.h"
|
#include "servers/mocktcpserver.h"
|
||||||
@ -73,6 +74,12 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati
|
|||||||
m_nymeaConfiguration(configuration),
|
m_nymeaConfiguration(configuration),
|
||||||
m_sslConfiguration(QSslConfiguration())
|
m_sslConfiguration(QSslConfiguration())
|
||||||
{
|
{
|
||||||
|
// To be compliant with the EN18031 we have to make sure the user cannot configure an insecure interface to the server.
|
||||||
|
if (qEnvironmentVariable("NYMEA_INSECURE_INTERFACES_DISABLED", "0") != "0") {
|
||||||
|
qCInfo(dcServerManager()) << "Insecure interfaces to the core are explicit disabled. Not starting any unauthenticated or unencrypted interfaces.";
|
||||||
|
m_disableInsecureInterfaces = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!QSslSocket::supportsSsl()) {
|
if (!QSslSocket::supportsSsl()) {
|
||||||
qCWarning(dcServerManager()) << "SSL is not supported/installed on this platform.";
|
qCWarning(dcServerManager()) << "SSL is not supported/installed on this platform.";
|
||||||
} else {
|
} else {
|
||||||
@ -102,8 +109,7 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (certsLoaded) {
|
if (certsLoaded) {
|
||||||
// Update this to 1.3 when minimum required Qt is 5.12 (and known client apps can deal with it)
|
m_sslConfiguration.setProtocol(QSsl::TlsV1_3OrLater);
|
||||||
m_sslConfiguration.setProtocol(QSsl::TlsV1_2OrLater);
|
|
||||||
m_sslConfiguration.setPrivateKey(m_certificateKey);
|
m_sslConfiguration.setPrivateKey(m_certificateKey);
|
||||||
m_sslConfiguration.setLocalCertificate(m_certificate);
|
m_sslConfiguration.setLocalCertificate(m_certificate);
|
||||||
}
|
}
|
||||||
@ -149,6 +155,11 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (const ServerConfiguration &config, configuration->tcpServerConfigurations()) {
|
foreach (const ServerConfiguration &config, configuration->tcpServerConfigurations()) {
|
||||||
|
if (m_disableInsecureInterfaces && (!config.sslEnabled || !config.authenticationEnabled)) {
|
||||||
|
qCWarning(dcServerManager()) << "Loaded insecure TCP server configuration" << config << "but insecure interfaces to the core are explicit disabled. This interface will not be started.";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
TcpServer *tcpServer = new TcpServer(config, m_sslConfiguration, this);
|
TcpServer *tcpServer = new TcpServer(config, m_sslConfiguration, this);
|
||||||
m_jsonServer->registerTransportInterface(tcpServer);
|
m_jsonServer->registerTransportInterface(tcpServer);
|
||||||
m_tcpServers.insert(config.id, tcpServer);
|
m_tcpServers.insert(config.id, tcpServer);
|
||||||
@ -158,6 +169,11 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (const ServerConfiguration &config, configuration->webSocketServerConfigurations()) {
|
foreach (const ServerConfiguration &config, configuration->webSocketServerConfigurations()) {
|
||||||
|
if (m_disableInsecureInterfaces && (!config.sslEnabled || !config.authenticationEnabled)) {
|
||||||
|
qCWarning(dcServerManager()) << "Loaded insecure WebSocket server configuration" << config << "but insecure interfaces to the core are explicit disabled. This interface will not be started.";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
WebSocketServer *webSocketServer = new WebSocketServer(config, m_sslConfiguration, this);
|
WebSocketServer *webSocketServer = new WebSocketServer(config, m_sslConfiguration, this);
|
||||||
m_jsonServer->registerTransportInterface(webSocketServer);
|
m_jsonServer->registerTransportInterface(webSocketServer);
|
||||||
m_webSocketServers.insert(config.id, webSocketServer);
|
m_webSocketServers.insert(config.id, webSocketServer);
|
||||||
@ -170,10 +186,19 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati
|
|||||||
m_bluetoothServer = new BluetoothServer(this);
|
m_bluetoothServer = new BluetoothServer(this);
|
||||||
m_jsonServer->registerTransportInterface(m_bluetoothServer);
|
m_jsonServer->registerTransportInterface(m_bluetoothServer);
|
||||||
if (configuration->bluetoothServerEnabled()) {
|
if (configuration->bluetoothServerEnabled()) {
|
||||||
m_bluetoothServer->startServer();
|
if (m_disableInsecureInterfaces) {
|
||||||
|
qCWarning(dcServerManager()) << "The bluetooth RFCOM server is enabled, but insecure server interfaces have been disabled explicitly. Not starting the bluetooth server.";
|
||||||
|
} else {
|
||||||
|
m_bluetoothServer->startServer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (const TunnelProxyServerConfiguration &config, configuration->tunnelProxyServerConfigurations()) {
|
foreach (const TunnelProxyServerConfiguration &config, configuration->tunnelProxyServerConfigurations()) {
|
||||||
|
if (m_disableInsecureInterfaces && (!config.sslEnabled || !config.authenticationEnabled || config.ignoreSslErrors)) {
|
||||||
|
qCWarning(dcServerManager()) << "Loaded insecure tunnelproxy server configuration" << config << "but insecure interfaces to the core are explicit disabled. This interface will not be started.";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
TunnelProxyServer *tunnelProxyServer = new TunnelProxyServer(configuration->serverName(), configuration->serverUuid(), config, this);
|
TunnelProxyServer *tunnelProxyServer = new TunnelProxyServer(configuration->serverName(), configuration->serverUuid(), config, this);
|
||||||
qCDebug(dcServerManager()) << "Creating tunnel proxy server using" << config;
|
qCDebug(dcServerManager()) << "Creating tunnel proxy server using" << config;
|
||||||
m_tunnelProxyServers.insert(config.id, tunnelProxyServer);
|
m_tunnelProxyServers.insert(config.id, tunnelProxyServer);
|
||||||
@ -209,14 +234,18 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati
|
|||||||
|
|
||||||
connect(configuration, &NymeaConfiguration::tcpServerConfigurationChanged, this, &ServerManager::tcpServerConfigurationChanged);
|
connect(configuration, &NymeaConfiguration::tcpServerConfigurationChanged, this, &ServerManager::tcpServerConfigurationChanged);
|
||||||
connect(configuration, &NymeaConfiguration::tcpServerConfigurationRemoved, this, &ServerManager::tcpServerConfigurationRemoved);
|
connect(configuration, &NymeaConfiguration::tcpServerConfigurationRemoved, this, &ServerManager::tcpServerConfigurationRemoved);
|
||||||
|
|
||||||
connect(configuration, &NymeaConfiguration::webSocketServerConfigurationChanged, this, &ServerManager::webSocketServerConfigurationChanged);
|
connect(configuration, &NymeaConfiguration::webSocketServerConfigurationChanged, this, &ServerManager::webSocketServerConfigurationChanged);
|
||||||
connect(configuration, &NymeaConfiguration::webSocketServerConfigurationRemoved, this, &ServerManager::webSocketServerConfigurationRemoved);
|
connect(configuration, &NymeaConfiguration::webSocketServerConfigurationRemoved, this, &ServerManager::webSocketServerConfigurationRemoved);
|
||||||
|
|
||||||
connect(configuration, &NymeaConfiguration::webServerConfigurationChanged, this, &ServerManager::webServerConfigurationChanged);
|
connect(configuration, &NymeaConfiguration::webServerConfigurationChanged, this, &ServerManager::webServerConfigurationChanged);
|
||||||
connect(configuration, &NymeaConfiguration::webServerConfigurationRemoved, this, &ServerManager::webServerConfigurationRemoved);
|
connect(configuration, &NymeaConfiguration::webServerConfigurationRemoved, this, &ServerManager::webServerConfigurationRemoved);
|
||||||
|
|
||||||
connect(configuration, &NymeaConfiguration::mqttServerConfigurationChanged, this, &ServerManager::mqttServerConfigurationChanged);
|
connect(configuration, &NymeaConfiguration::mqttServerConfigurationChanged, this, &ServerManager::mqttServerConfigurationChanged);
|
||||||
connect(configuration, &NymeaConfiguration::mqttServerConfigurationRemoved, this, &ServerManager::mqttServerConfigurationRemoved);
|
connect(configuration, &NymeaConfiguration::mqttServerConfigurationRemoved, this, &ServerManager::mqttServerConfigurationRemoved);
|
||||||
connect(configuration, &NymeaConfiguration::mqttPolicyChanged, this, &ServerManager::mqttPolicyChanged);
|
connect(configuration, &NymeaConfiguration::mqttPolicyChanged, this, &ServerManager::mqttPolicyChanged);
|
||||||
connect(configuration, &NymeaConfiguration::mqttPolicyRemoved, this, &ServerManager::mqttPolicyRemoved);
|
connect(configuration, &NymeaConfiguration::mqttPolicyRemoved, this, &ServerManager::mqttPolicyRemoved);
|
||||||
|
|
||||||
connect(configuration, &NymeaConfiguration::tunnelProxyServerConfigurationChanged, this, &ServerManager::tunnelProxyServerConfigurationChanged);
|
connect(configuration, &NymeaConfiguration::tunnelProxyServerConfigurationChanged, this, &ServerManager::tunnelProxyServerConfigurationChanged);
|
||||||
connect(configuration, &NymeaConfiguration::tunnelProxyServerConfigurationRemoved, this, &ServerManager::tunnelProxyServerConfigurationRemoved);
|
connect(configuration, &NymeaConfiguration::tunnelProxyServerConfigurationRemoved, this, &ServerManager::tunnelProxyServerConfigurationRemoved);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,6 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include "loggingcategories.h"
|
|
||||||
#include "nymeaconfiguration.h"
|
#include "nymeaconfiguration.h"
|
||||||
|
|
||||||
#include <QSslConfiguration>
|
#include <QSslConfiguration>
|
||||||
@ -72,7 +71,6 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void setServerName(const QString &serverName);
|
void setServerName(const QString &serverName);
|
||||||
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void tcpServerConfigurationChanged(const QString &id);
|
void tcpServerConfigurationChanged(const QString &id);
|
||||||
void tcpServerConfigurationRemoved(const QString &id);
|
void tcpServerConfigurationRemoved(const QString &id);
|
||||||
@ -95,6 +93,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Platform *m_platform = nullptr;
|
Platform *m_platform = nullptr;
|
||||||
|
bool m_disableInsecureInterfaces = false;
|
||||||
NymeaConfiguration *m_nymeaConfiguration = nullptr;
|
NymeaConfiguration *m_nymeaConfiguration = nullptr;
|
||||||
|
|
||||||
// Interfaces
|
// Interfaces
|
||||||
|
|||||||
@ -11,7 +11,7 @@ isEmpty(NYMEA_VERSION) {
|
|||||||
|
|
||||||
# define protocol versions
|
# define protocol versions
|
||||||
JSON_PROTOCOL_VERSION_MAJOR=8
|
JSON_PROTOCOL_VERSION_MAJOR=8
|
||||||
JSON_PROTOCOL_VERSION_MINOR=2
|
JSON_PROTOCOL_VERSION_MINOR=3
|
||||||
JSON_PROTOCOL_VERSION="$${JSON_PROTOCOL_VERSION_MAJOR}.$${JSON_PROTOCOL_VERSION_MINOR}"
|
JSON_PROTOCOL_VERSION="$${JSON_PROTOCOL_VERSION_MAJOR}.$${JSON_PROTOCOL_VERSION_MINOR}"
|
||||||
LIBNYMEA_API_VERSION_MAJOR=9
|
LIBNYMEA_API_VERSION_MAJOR=9
|
||||||
LIBNYMEA_API_VERSION_MINOR=0
|
LIBNYMEA_API_VERSION_MINOR=0
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
8.2
|
8.3
|
||||||
{
|
{
|
||||||
"enums": {
|
"enums": {
|
||||||
"BasicType": [
|
"BasicType": [
|
||||||
@ -34,7 +34,8 @@
|
|||||||
"ConfigurationErrorInvalidPort",
|
"ConfigurationErrorInvalidPort",
|
||||||
"ConfigurationErrorInvalidHostAddress",
|
"ConfigurationErrorInvalidHostAddress",
|
||||||
"ConfigurationErrorBluetoothHardwareNotAvailable",
|
"ConfigurationErrorBluetoothHardwareNotAvailable",
|
||||||
"ConfigurationErrorInvalidCertificate"
|
"ConfigurationErrorInvalidCertificate",
|
||||||
|
"ConfigurationErrorUnsupported"
|
||||||
],
|
],
|
||||||
"CreateMethod": [
|
"CreateMethod": [
|
||||||
"CreateMethodUser",
|
"CreateMethodUser",
|
||||||
|
|||||||
@ -56,6 +56,8 @@ private slots:
|
|||||||
|
|
||||||
void testDebugServerConfiguration();
|
void testDebugServerConfiguration();
|
||||||
|
|
||||||
|
void testDisableInsecureInterfacesEnv();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVariantMap loadBasicConfiguration();
|
QVariantMap loadBasicConfiguration();
|
||||||
|
|
||||||
@ -295,7 +297,7 @@ void TestConfigurations::testDebugServerConfiguration()
|
|||||||
|
|
||||||
// Webserver request
|
// Webserver request
|
||||||
QNetworkAccessManager nam;
|
QNetworkAccessManager nam;
|
||||||
connect(&nam, &QNetworkAccessManager::sslErrors, [](QNetworkReply* reply, const QList<QSslError> &) {
|
connect(&nam, &QNetworkAccessManager::sslErrors, this, [](QNetworkReply* reply, const QList<QSslError> &) {
|
||||||
reply->ignoreSslErrors();
|
reply->ignoreSslErrors();
|
||||||
});
|
});
|
||||||
QSignalSpy namSpy(&nam, &QNetworkAccessManager::finished);
|
QSignalSpy namSpy(&nam, &QNetworkAccessManager::finished);
|
||||||
@ -329,7 +331,7 @@ void TestConfigurations::testDebugServerConfiguration()
|
|||||||
|
|
||||||
ok = false;
|
ok = false;
|
||||||
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(&ok);
|
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(&ok);
|
||||||
QVERIFY2(ok, "Could not convert statuscode from response to int");
|
QVERIFY2(ok, "Could not convert status code from response to int");
|
||||||
QCOMPARE(statusCode, 404);
|
QCOMPARE(statusCode, 404);
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
|
||||||
@ -338,6 +340,90 @@ void TestConfigurations::testDebugServerConfiguration()
|
|||||||
disableNotifications();
|
disableNotifications();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestConfigurations::testDisableInsecureInterfacesEnv()
|
||||||
|
{
|
||||||
|
QString id = "insecure";
|
||||||
|
|
||||||
|
// Create a insecure interface
|
||||||
|
QVariantMap insecureTcpConfig;
|
||||||
|
insecureTcpConfig.insert("id", id);
|
||||||
|
insecureTcpConfig.insert("address", "0.0.0.0");
|
||||||
|
insecureTcpConfig.insert("port", 23456);
|
||||||
|
insecureTcpConfig.insert("sslEnabled", false);
|
||||||
|
insecureTcpConfig.insert("authenticationEnabled", false);
|
||||||
|
|
||||||
|
// Create a insecure interface
|
||||||
|
QVariantMap insecureWebSocketConfig;
|
||||||
|
insecureWebSocketConfig.insert("id", id);
|
||||||
|
insecureWebSocketConfig.insert("address", "0.0.0.0");
|
||||||
|
insecureWebSocketConfig.insert("port", 23457);
|
||||||
|
insecureWebSocketConfig.insert("sslEnabled", false);
|
||||||
|
insecureWebSocketConfig.insert("authenticationEnabled", false);
|
||||||
|
|
||||||
|
// Create a insecure interface
|
||||||
|
QVariantMap insecureTunnelProxyConfig;
|
||||||
|
insecureTunnelProxyConfig.insert("id", id);
|
||||||
|
insecureTunnelProxyConfig.insert("address", "example.nymea.io");
|
||||||
|
insecureTunnelProxyConfig.insert("port", 2213);
|
||||||
|
insecureTunnelProxyConfig.insert("sslEnabled", false);
|
||||||
|
insecureTunnelProxyConfig.insert("authenticationEnabled", false);
|
||||||
|
insecureTunnelProxyConfig.insert("ignoreSslErrors", true);
|
||||||
|
|
||||||
|
QVariantMap params; QVariant response;
|
||||||
|
|
||||||
|
params.insert("configuration", insecureTcpConfig);
|
||||||
|
response = injectAndWait("Configuration.SetTcpServerConfiguration", params);
|
||||||
|
verifyConfigurationError(response);
|
||||||
|
|
||||||
|
params.insert("configuration", insecureWebSocketConfig);
|
||||||
|
response = injectAndWait("Configuration.SetWebSocketServerConfiguration", params);
|
||||||
|
verifyConfigurationError(response);
|
||||||
|
|
||||||
|
params.insert("configuration", insecureTunnelProxyConfig);
|
||||||
|
response = injectAndWait("Configuration.SetTunnelProxyServerConfiguration", params);
|
||||||
|
verifyConfigurationError(response);
|
||||||
|
|
||||||
|
// Restart with disabled insecure interfaces
|
||||||
|
qputenv("NYMEA_INSECURE_INTERFACES_DISABLED", "1");
|
||||||
|
restartServer();
|
||||||
|
|
||||||
|
// FIXME: make sure the insecure servers are not running
|
||||||
|
|
||||||
|
// Remove the insecure configs and try to add them again and expect them to fail
|
||||||
|
params.clear(); response.clear();
|
||||||
|
params.insert("id", id);
|
||||||
|
response = injectAndWait("Configuration.DeleteTcpServerConfiguration", params);
|
||||||
|
verifyConfigurationError(response);
|
||||||
|
|
||||||
|
params.clear(); response.clear();
|
||||||
|
params.insert("id", id);
|
||||||
|
response = injectAndWait("Configuration.DeleteWebSocketServerConfiguration", params);
|
||||||
|
verifyConfigurationError(response);
|
||||||
|
|
||||||
|
params.clear(); response.clear();
|
||||||
|
params.insert("id", id);
|
||||||
|
response = injectAndWait("Configuration.DeleteTunnelProxyServerConfiguration", params);
|
||||||
|
verifyConfigurationError(response);
|
||||||
|
|
||||||
|
// Make sure we cannot add insecure interfaces beside localhost
|
||||||
|
params.clear(); response.clear();
|
||||||
|
params.insert("configuration", insecureTcpConfig);
|
||||||
|
response = injectAndWait("Configuration.SetTcpServerConfiguration", params);
|
||||||
|
verifyConfigurationError(response, NymeaConfiguration::ConfigurationErrorUnsupported);
|
||||||
|
|
||||||
|
params.clear(); response.clear();
|
||||||
|
params.insert("configuration", insecureWebSocketConfig);
|
||||||
|
response = injectAndWait("Configuration.SetWebSocketServerConfiguration", params);
|
||||||
|
verifyConfigurationError(response, NymeaConfiguration::ConfigurationErrorUnsupported);
|
||||||
|
|
||||||
|
params.clear(); response.clear();
|
||||||
|
params.insert("configuration", insecureTunnelProxyConfig);
|
||||||
|
response = injectAndWait("Configuration.SetTunnelProxyServerConfiguration", params);
|
||||||
|
verifyConfigurationError(response, NymeaConfiguration::ConfigurationErrorUnsupported);
|
||||||
|
|
||||||
|
qunsetenv("NYMEA_INSECURE_INTERFACES_DISABLED");
|
||||||
|
}
|
||||||
|
|
||||||
QVariantMap TestConfigurations::loadBasicConfiguration()
|
QVariantMap TestConfigurations::loadBasicConfiguration()
|
||||||
{
|
{
|
||||||
QVariant response = injectAndWait("Configuration.GetConfigurations");
|
QVariant response = injectAndWait("Configuration.GetConfigurations");
|
||||||
|
|||||||
@ -32,6 +32,7 @@
|
|||||||
#include "nymeacore.h"
|
#include "nymeacore.h"
|
||||||
#include "servers/mqttbroker.h"
|
#include "servers/mqttbroker.h"
|
||||||
#include "servers/mocktcpserver.h"
|
#include "servers/mocktcpserver.h"
|
||||||
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
#include <mqttclient.h>
|
#include <mqttclient.h>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user