Merge branch 'debian-packaging' into 'master'
add debian packaging See merge request !2
This commit is contained in:
commit
a9e79bde97
1
.gitignore
vendored
1
.gitignore
vendored
@ -72,3 +72,4 @@ Thumbs.db
|
||||
*.exe
|
||||
|
||||
coverage-html
|
||||
client/nymea-remoteproxy-client
|
||||
|
||||
275
README.md
275
README.md
@ -1,275 +0,0 @@
|
||||
# nymea remote proxy server
|
||||
----------------------------------------------
|
||||
|
||||
The nymea remote proxy server is the meeting point of nymea servers and nymea clients in order to establishing a secure remote connection.
|
||||
|
||||
# Build
|
||||
|
||||
In order to build the proxy server you need to install the qt default package.
|
||||
|
||||
apt install qt5-default
|
||||
|
||||
Change into the source directory and run following commands
|
||||
|
||||
cd nymea-remoteproxy
|
||||
mkdir build
|
||||
cd build
|
||||
qmake ../
|
||||
make -j$(nproc)
|
||||
|
||||
In the build directory you can find the resulting library and binary files.
|
||||
|
||||
If you want to start the proxy server from the build directory, you need to export the library path before starting the application:
|
||||
|
||||
|
||||
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)/libnymea-remoteproxy:$(pwd)/libnymea-remoteproxyclient
|
||||
$ ./server/nymea-remoteproxy -c ../nymea-remoteproxy/tests/test-certificate.crt -k ../nymea-remoteproxy/tests/test-certificate.key
|
||||
|
||||
|
||||
# Install
|
||||
|
||||
|
||||
|
||||
# Configure
|
||||
|
||||
|
||||
|
||||
# Test
|
||||
|
||||
In order to run the test, you can call `make check` in the build directory or run the resulting executable:
|
||||
|
||||
$ nymea-remoteproxy-tests
|
||||
|
||||
|
||||
## Test coverage report
|
||||
|
||||
If you want to create a line coverage report from the tests simply run following command in the source directory:
|
||||
|
||||
|
||||
$ apt install lcov gcovr
|
||||
$ ./create-coverage-html.sh
|
||||
|
||||
The resulting coverage report will be place in the `coverage-html` directory.
|
||||
|
||||
# Usage
|
||||
|
||||
In order to get information about the server you can start the command with the `--help` parameter.
|
||||
|
||||
$ nymea-remoteproxy --help
|
||||
|
||||
Usage: nymea-remoteproxy [options]
|
||||
|
||||
The nymea remote proxy server. This server allowes nymea-cloud users and registered nymea deamons to establish a tunnel connection.
|
||||
|
||||
Server version: 0.0.1
|
||||
API version: 0.1
|
||||
|
||||
Copyright © 2018 Simon Stürz <simon.stuerz@guh.io>
|
||||
|
||||
|
||||
Options:
|
||||
-h, --help Displays this help.
|
||||
-v, --version Displays version information.
|
||||
-l, --logging <logfile> Write log file to the given logfile.
|
||||
-s, --server <hostaddress> The server address this proxy will
|
||||
listen on. Default is 127.0.0.1
|
||||
-p, --port <port> The proxy server port. Default is
|
||||
1212
|
||||
-c, --certificate <certificate> The path to the SSL certificate used
|
||||
for this proxy server.
|
||||
-k, --certificate-key <certificate-key> The path to the SSL certificate key
|
||||
used for this proxy server.
|
||||
-a, --authentication-server <url> The server url of the AWS
|
||||
authentication server.
|
||||
|
||||
|
||||
# Server API
|
||||
|
||||
Once a client connects to the proxy server, he must authenticate him self by passing the token received from the nymea-cloud mqtt connection request.
|
||||
|
||||
## Message format
|
||||
|
||||
#### Request
|
||||
|
||||
{
|
||||
"id": integer,
|
||||
"method": "Namespace.Method",
|
||||
"o:params" { }
|
||||
}
|
||||
|
||||
#### Response
|
||||
|
||||
{
|
||||
"id": integer,
|
||||
"status": "string",
|
||||
"o:params" { },
|
||||
"o:error": "string"
|
||||
}
|
||||
|
||||
#### Notification
|
||||
|
||||
{
|
||||
"id": integer,
|
||||
"notification": "Namespace.Notification",
|
||||
"o:params" { }
|
||||
}
|
||||
|
||||
## Say Hello
|
||||
|
||||
#### Request
|
||||
|
||||
{
|
||||
"id": 0,
|
||||
"method": "RemoteProxy.Hello"
|
||||
}
|
||||
|
||||
|
||||
#### Response
|
||||
|
||||
{
|
||||
"id": 0,
|
||||
"params": {
|
||||
"apiVersion": "0.1",
|
||||
"name": "nymea-remoteproxy-testserver",
|
||||
"server": "nymea-remoteproxy",
|
||||
"version": "0.0.1"
|
||||
},
|
||||
"status": "success"
|
||||
}
|
||||
|
||||
## Authenticate the connection
|
||||
|
||||
The first data a client **must** send to the proxy server is the authentication request. This request contains the token which will be verified agains the nymea-cloud infrastructure.
|
||||
|
||||
#### Request
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"method": "Authentication.Authenticate",
|
||||
"params": {
|
||||
"id": "string",
|
||||
"name": "string",
|
||||
"token": "tokenstring"
|
||||
}
|
||||
}
|
||||
|
||||
#### Response
|
||||
|
||||
* **On Success**: If the token was authenticated successfully, the response will look like this:
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"status": "success"
|
||||
}
|
||||
|
||||
* **On Failure** If the token was invalid, the response will look like this and the server will close the connection immediatly:
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"status": "error",
|
||||
"error": "Invalid token. You are not allowed to use this server."
|
||||
}
|
||||
|
||||
#### Tunnel established
|
||||
|
||||
Once the other client is here and ready, the server will send a notification to the clients indicating that the tunnel has been established successfully. This message is the last data comming from the proxy server.
|
||||
|
||||
> **Important:** Any data traffic following after this notification comes from the tunnel endpoint, __not__ from the __proxy server__ any more.
|
||||
|
||||
{
|
||||
"id": "0",
|
||||
"notification": "RemoteProxy.TunnelEstablished",
|
||||
"params": {
|
||||
"name": "String",
|
||||
"uuid": "String"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
## Introspect the API
|
||||
|
||||
|
||||
#### Request
|
||||
|
||||
{
|
||||
"id": 0,
|
||||
"method": "RemoteProxy.Introspect"
|
||||
}
|
||||
|
||||
#### Response
|
||||
|
||||
|
||||
{
|
||||
"id": 0,
|
||||
"params": {
|
||||
"methods": {
|
||||
"Authentication.Authenticate": {
|
||||
"description": "Authenticate this connection. The returned AuthenticationError informs about the result. If the authentication was not successfull, the server will close the connection immediatly after sending the error response. The given id should be a unique id the other tunnel client can understand. Once the authentication was successfull, you can wait for the RemoteProxy.TunnelEstablished notification. If you send any data before getting this notification, the server will close the connection. If the tunnel client does not show up within 10 seconds, the server will close the connection.",
|
||||
"params": {
|
||||
"name": "String",
|
||||
"token": "String",
|
||||
"uuid": "String"
|
||||
},
|
||||
"returns": {
|
||||
"authenticationError": "$ref:AuthenticationError"
|
||||
}
|
||||
},
|
||||
"RemoteProxy.Hello": {
|
||||
"description": "Once connected to this server, a client can get information about the server by saying Hello. The response informs the client about this proxy server.",
|
||||
"params": {
|
||||
},
|
||||
"returns": {
|
||||
"apiVersion": "String",
|
||||
"name": "String",
|
||||
"server": "String",
|
||||
"version": "String"
|
||||
}
|
||||
},
|
||||
"RemoteProxy.Introspect": {
|
||||
"description": "Introspect this API.",
|
||||
"params": {
|
||||
},
|
||||
"returns": {
|
||||
"methods": "Object",
|
||||
"notifications": "Object",
|
||||
"types": "Object"
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"RemoteProxy.TunnelEstablished": {
|
||||
"description": "Emitted whenever the tunnel has been established successfully. This is the last message from the remote proxy server! Any following data will be from the other tunnel client until the connection will be closed. The parameter contain some information about the other tunnel client.",
|
||||
"params": {
|
||||
"name": "String",
|
||||
"uuid": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types": {
|
||||
"AuthenticationError": [
|
||||
"AuthenticationErrorNoError",
|
||||
"AuthenticationErrorUnknown",
|
||||
"AuthenticationErrorTimeout",
|
||||
"AuthenticationErrorAborted",
|
||||
"AuthenticationErrorAuthenticationFailed",
|
||||
"AuthenticationErrorAuthenticationServerNotResponding"
|
||||
],
|
||||
"BasicType": [
|
||||
"Uuid",
|
||||
"String",
|
||||
"Int",
|
||||
"UInt",
|
||||
"Double",
|
||||
"Bool",
|
||||
"Variant",
|
||||
"Object"
|
||||
]
|
||||
}
|
||||
},
|
||||
"status": "success"
|
||||
}
|
||||
|
||||
|
||||
# License
|
||||
|
||||
This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3 of the License.
|
||||
18
client/client.pro
Normal file
18
client/client.pro
Normal file
@ -0,0 +1,18 @@
|
||||
include(../nymea-remoteproxy.pri)
|
||||
include(../libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri)
|
||||
|
||||
TARGET = nymea-remoteproxy-client
|
||||
TEMPLATE = app
|
||||
|
||||
INCLUDEPATH += ../libnymea-remoteproxy
|
||||
|
||||
LIBS += -L$$top_builddir/libnymea-remoteproxyclient/ -lnymea-remoteproxyclient
|
||||
|
||||
SOURCES += main.cpp \
|
||||
proxyclient.cpp
|
||||
|
||||
target.path = /usr/bin
|
||||
INSTALLS += target
|
||||
|
||||
HEADERS += \
|
||||
proxyclient.h
|
||||
44
client/main.cpp
Normal file
44
client/main.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <QUrl>
|
||||
#include <QCoreApplication>
|
||||
#include <QLoggingCategory>
|
||||
#include <QCommandLineParser>
|
||||
#include <QCommandLineOption>
|
||||
|
||||
#include "proxyclient.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
QCoreApplication application(argc, argv);
|
||||
application.setApplicationName(SERVER_NAME_STRING);
|
||||
application.setOrganizationName("guh");
|
||||
application.setApplicationVersion(SERVER_VERSION_STRING);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
parser.setApplicationDescription(QString("\nThe nymea remote proxy server. This server allowes nymea-cloud users and "
|
||||
"registered nymea deamons to establish a tunnel connection.\n\n"
|
||||
"Server version: %1\n"
|
||||
"API version: %2\n\n"
|
||||
"Copyright %3 2018 Simon Stürz <simon.stuerz@guh.io>\n")
|
||||
.arg(SERVER_VERSION_STRING)
|
||||
.arg(API_VERSION_STRING)
|
||||
.arg(QChar(0xA9)));
|
||||
|
||||
|
||||
QCommandLineOption tokenOption(QStringList() << "t" << "token", "The AWS token for authentication.", "token");
|
||||
parser.addOption(tokenOption);
|
||||
|
||||
parser.process(application);
|
||||
|
||||
if (!parser.isSet(tokenOption)) {
|
||||
qWarning() << "Please specify the token for authentication." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
ProxyClient client;
|
||||
client.start(parser.value(tokenOption));
|
||||
|
||||
return application.exec();
|
||||
}
|
||||
34
client/proxyclient.cpp
Normal file
34
client/proxyclient.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "proxyclient.h"
|
||||
|
||||
|
||||
ProxyClient::ProxyClient(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
m_connection = new RemoteProxyConnection(QUuid::createUuid(), "nymea-remoteproxy-client", RemoteProxyConnection::ConnectionTypeWebSocket, this);
|
||||
m_connection->setInsecureConnection(true);
|
||||
connect(m_connection, &RemoteProxyConnection::ready, this, &ProxyClient::onClientReady);
|
||||
connect(m_connection, &RemoteProxyConnection::authenticated, this, &ProxyClient::onAuthenticationFinished);
|
||||
connect(m_connection, &RemoteProxyConnection::errorOccured, this, &ProxyClient::onErrorOccured);
|
||||
|
||||
}
|
||||
|
||||
void ProxyClient::onErrorOccured(RemoteProxyConnection::Error error)
|
||||
{
|
||||
qDebug() << "Error occured" << error << m_connection->errorString();
|
||||
}
|
||||
|
||||
void ProxyClient::onClientReady()
|
||||
{
|
||||
m_connection->authenticate(m_token);
|
||||
}
|
||||
|
||||
void ProxyClient::onAuthenticationFinished()
|
||||
{
|
||||
qDebug() << "Authentication finished.";
|
||||
}
|
||||
|
||||
void ProxyClient::start(const QString &token)
|
||||
{
|
||||
m_token = token;
|
||||
m_connection->connectServer(m_hostAddress, static_cast<quint16>(m_port));
|
||||
}
|
||||
39
client/proxyclient.h
Normal file
39
client/proxyclient.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef PROXYCLIENT_H
|
||||
#define PROXYCLIENT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "remoteproxyconnection.h"
|
||||
|
||||
using namespace remoteproxyclient;
|
||||
|
||||
class ProxyClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ProxyClient(QObject *parent = nullptr);
|
||||
|
||||
void setHostAddress(const QHostAddress &hostAddress);
|
||||
void setPort(const int &port);
|
||||
|
||||
private:
|
||||
QString m_token;
|
||||
QHostAddress m_hostAddress = QHostAddress::LocalHost;
|
||||
int m_port = 1212;
|
||||
|
||||
RemoteProxyConnection *m_connection = nullptr;
|
||||
|
||||
signals:
|
||||
|
||||
|
||||
private slots:
|
||||
void onErrorOccured(RemoteProxyConnection::Error error);
|
||||
void onClientReady();
|
||||
void onAuthenticationFinished();
|
||||
|
||||
public slots:
|
||||
void start(const QString &token);
|
||||
|
||||
};
|
||||
|
||||
#endif // PROXYCLIENT_H
|
||||
24
copyright
Normal file
24
copyright
Normal file
@ -0,0 +1,24 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: nymea-remoteproxy
|
||||
Upstream-Contact: Simon Stürz <simon.stuerz@guh.io>
|
||||
Copyright: 2018, guh GmbH
|
||||
Download: http://www.github.com/guh/nymea-remoteproxy
|
||||
Source: https://github.com/guh/nymea-remoteproxy.git
|
||||
|
||||
|
||||
License: GPL-2+
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License can be found in `/usr/share/common-licenses/GPL-2'.
|
||||
|
||||
License: LGPL-2.1
|
||||
On Debian systems, the complete text of the GNU Lesser General
|
||||
Public License can be found in `/usr/share/common-licenses/LGPL-2.1'.
|
||||
|
||||
License: LGPL-3
|
||||
On Debian systems, the complete text of the GNU Lesser General
|
||||
Public License can be found in `/usr/share/common-licenses/LGPL-3'.
|
||||
|
||||
|
||||
Files: *
|
||||
License: GPL-2+
|
||||
Copyright: 2018, Simon Stürz <simon.stuerz@guh.io>
|
||||
5
debian/changelog
vendored
Normal file
5
debian/changelog
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
nymea-remoteproxy (0.0.1) xenial; urgency=medium
|
||||
|
||||
* Initial release.
|
||||
|
||||
-- Michael Zanetti <michael.zanetti@guh.io> Thu, 13 Aug 2018 21:33:51 +0200
|
||||
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@ -0,0 +1 @@
|
||||
9
|
||||
42
debian/control
vendored
Normal file
42
debian/control
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
Source: nymea-remoteproxy
|
||||
Section: utils
|
||||
Priority: options
|
||||
Maintainer: Simon Stürz <simon.stürz@guh.io>
|
||||
Build-depends: debhelper (>= 0.0.0),
|
||||
libqt5websockets5-dev,
|
||||
Standards-Version: 3.9.3
|
||||
|
||||
Package: nymea-remoteproxy
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
Description: The nymea remote proxy server
|
||||
The nymea remote proxy server
|
||||
|
||||
Package: nymea-remoteproxy-client
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
Description: The nymea remote proxy client for testing
|
||||
The nymea remote proxy client for testing
|
||||
|
||||
Package: libnymea-remoteproxyclient
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
Description: The nymea remote proxy server client lib
|
||||
The nymea remote proxy server client lib
|
||||
|
||||
Package: libnymea-remoteproxyclient-dev
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
Description: The nymea remote proxy server client lib, development files
|
||||
The nymea remote proxy server client lib, development files
|
||||
|
||||
Package: nymea-remoteproxy-tests
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
Description: The nymea remote proxy server tests
|
||||
The nymea remote proxy server tests
|
||||
1
debian/libnymea-remoteproxyclient.install.in
vendored
Normal file
1
debian/libnymea-remoteproxyclient.install.in
vendored
Normal file
@ -0,0 +1 @@
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-remoteproxyclient.so.*
|
||||
1
debian/nymea-remoteproxy-client.install.in
vendored
Normal file
1
debian/nymea-remoteproxy-client.install.in
vendored
Normal file
@ -0,0 +1 @@
|
||||
usr/bin/nymea-remoteproxy-client
|
||||
1
debian/nymea-remoteproxy-tests.install
vendored
Normal file
1
debian/nymea-remoteproxy-tests.install
vendored
Normal file
@ -0,0 +1 @@
|
||||
usr/bin/nymea-remoteproxy-tests
|
||||
2
debian/nymea-remoteproxy.install.in
vendored
Normal file
2
debian/nymea-remoteproxy.install.in
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-remoteproxy.so*
|
||||
usr/bin/nymea-remoteproxy
|
||||
15
debian/rules
vendored
Executable file
15
debian/rules
vendored
Executable file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
|
||||
|
||||
|
||||
PREPROCESS_FILES := $(wildcard debian/*.in)
|
||||
|
||||
$(PREPROCESS_FILES:.in=): %: %.in
|
||||
sed 's,/@DEB_HOST_MULTIARCH@,$(DEB_HOST_MULTIARCH:%=/%),g' $< > $@
|
||||
|
||||
override_dh_install: $(PREPROCESS_FILES:.in=)
|
||||
dh_install
|
||||
|
||||
%:
|
||||
dh $@
|
||||
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@ -0,0 +1 @@
|
||||
3.0 (native)
|
||||
171
libnymea-remoteproxy/authentication/authenticationprocess.cpp
Normal file
171
libnymea-remoteproxy/authentication/authenticationprocess.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
#include "authenticationprocess.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
#include <QUrl>
|
||||
#include <QFile>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
AuthenticationProcess::AuthenticationProcess(QNetworkAccessManager *manager, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_manager(manager)
|
||||
{
|
||||
m_process = new QProcess(this);
|
||||
m_process->setProcessChannelMode(QProcess::MergedChannels);
|
||||
connect(m_process, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &AuthenticationProcess::onProcessFinished);
|
||||
}
|
||||
|
||||
void AuthenticationProcess::useDynamicCredentials(bool dynamicCredentials)
|
||||
{
|
||||
m_dynamicCredentials = dynamicCredentials;
|
||||
}
|
||||
|
||||
void AuthenticationProcess::requestDynamicCredentials()
|
||||
{
|
||||
QNetworkReply *reply = m_manager->get(QNetworkRequest(QUrl("http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-Remote-Connection-Proxy-Role")));
|
||||
connect(reply, &QNetworkReply::finished, this, &AuthenticationProcess::onDynamicCredentialsReady);
|
||||
}
|
||||
|
||||
void AuthenticationProcess::startVerificationProcess()
|
||||
{
|
||||
if (m_process->state() != QProcess::NotRunning) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Authentication process already running. Killing the running process and restart.";
|
||||
m_process->kill();
|
||||
}
|
||||
|
||||
// Create request map
|
||||
QVariantMap request;
|
||||
request.insert("token", m_token);
|
||||
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
env.insert("AWS_DEFAULT_REGION", "eu-west-1");
|
||||
|
||||
if (m_dynamicCredentials) {
|
||||
env.insert("AWS_ACCESS_KEY_ID", m_awsAccessKeyId);
|
||||
env.insert("AWS_SECRET_ACCESS_KEY", m_awsSecretAccessKey);
|
||||
env.insert("AWS_SESSION_TOKEN", m_awsSessionToken);
|
||||
}
|
||||
|
||||
// FIXME: check how to clean this up properly
|
||||
m_resultFileName = "/tmp/" + QUuid::createUuid().toString().remove("{").remove("}").remove("-") + ".json";
|
||||
|
||||
qCDebug(dcAuthentication()) << "Start authenticator process and store result in" << m_resultFileName;
|
||||
|
||||
m_process->start("aws", { "lambda", "invoke",
|
||||
"--function-name", "system-services-authorizer-dev-checkToken",
|
||||
"--invocation-type", "RequestResponse",
|
||||
"--payload", QString::fromUtf8(QJsonDocument::fromVariant(request).toJson()),
|
||||
m_resultFileName });
|
||||
|
||||
}
|
||||
|
||||
void AuthenticationProcess::onDynamicCredentialsReady()
|
||||
{
|
||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
||||
reply->deleteLater();
|
||||
|
||||
if (reply->error()) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Dynamic credentials reply error: " << reply->errorString();
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||
|
||||
if(error.error != QJsonParseError::NoError) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Failed to parse dynamic credentials reply data" << data << ":" << error.errorString();
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap response = jsonDoc.toVariant().toMap();
|
||||
qCDebug(dcAuthentication()) << "-->" << response;
|
||||
|
||||
m_awsAccessKeyId = response.value("AccessKeyId").toString();
|
||||
m_awsSecretAccessKey = response.value("SecretAccessKey").toString();
|
||||
m_awsSessionToken = response.value("Token").toString();
|
||||
|
||||
startVerificationProcess();
|
||||
}
|
||||
|
||||
void AuthenticationProcess::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
|
||||
if (exitStatus == QProcess::CrashExit) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Authentication process crashed:" << endl << qUtf8Printable(m_process->readAll());
|
||||
}
|
||||
|
||||
if (exitCode != 0) {
|
||||
qCWarning(dcAuthenticationProcess()) << "The authentication process finished with error" << exitCode << endl << qUtf8Printable(m_process->readAll());
|
||||
}
|
||||
|
||||
qCDebug(dcAuthenticationProcess()) << "Finished successfully";
|
||||
QFile resultFile(m_resultFileName);
|
||||
|
||||
if (!resultFile.exists()) {
|
||||
qCWarning(dcAuthenticationProcess()) << "The process output file does not exist.";
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!resultFile.open(QIODevice::ReadWrite)) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Could not open result file from process:" << resultFile.errorString();
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray resultData = resultFile.readAll();
|
||||
|
||||
resultFile.close();
|
||||
if (!resultFile.remove()) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Could not clean up result file from process:" << resultFile.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonParseError error;
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(resultData, &error);
|
||||
|
||||
if(error.error != QJsonParseError::NoError) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Failed to parse lambda invoke result data" << resultData << ":" << error.errorString();
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap response = jsonDoc.toVariant().toMap();
|
||||
qCDebug(dcAuthenticationProcess()) << "-->" << response;
|
||||
if (response.isEmpty()) {
|
||||
qCWarning(dcAuthenticationProcess()) << "Received empty lambda result.";
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorProxyError);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isValid = response.value("isValid").toBool();
|
||||
|
||||
if (isValid) {
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorNoError);
|
||||
} else {
|
||||
emit authenticationFinished(Authenticator::AuthenticationErrorAuthenticationFailed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AuthenticationProcess::authenticate(const QString &token)
|
||||
{
|
||||
qCDebug(dcAuthenticationProcess()) << "Start authentication process for token" << token;
|
||||
m_token = token;
|
||||
|
||||
if (m_dynamicCredentials) {
|
||||
// Request the access information
|
||||
requestDynamicCredentials();
|
||||
} else {
|
||||
// Direct call aws cli and assume the credentials will be provided static
|
||||
startVerificationProcess();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
50
libnymea-remoteproxy/authentication/authenticationprocess.h
Normal file
50
libnymea-remoteproxy/authentication/authenticationprocess.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef AUTHENTICATIONPROCESS_H
|
||||
#define AUTHENTICATIONPROCESS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
#include "authenticator.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class AuthenticationProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AuthenticationProcess(QNetworkAccessManager *manager, QObject *parent = nullptr);
|
||||
|
||||
void useDynamicCredentials(bool dynamicCredentials);
|
||||
|
||||
private:
|
||||
QString m_token;
|
||||
QString m_resultFileName;
|
||||
|
||||
bool m_dynamicCredentials = true;
|
||||
QString m_awsAccessKeyId;
|
||||
QString m_awsSecretAccessKey;
|
||||
QString m_awsSessionToken;
|
||||
|
||||
QNetworkAccessManager *m_manager = nullptr;
|
||||
QProcess *m_process = nullptr;
|
||||
|
||||
void requestDynamicCredentials();
|
||||
void startVerificationProcess();
|
||||
void cleanUp();
|
||||
|
||||
signals:
|
||||
void authenticationFinished(Authenticator::AuthenticationError error);
|
||||
|
||||
private slots:
|
||||
void onDynamicCredentialsReady();
|
||||
void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
||||
public slots:
|
||||
void authenticate(const QString &token);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AUTHENTICATIONPROCESS_H
|
||||
@ -7,7 +7,11 @@ AuthenticationReply::AuthenticationReply(ProxyClient *proxyClient, QObject *pare
|
||||
QObject(parent),
|
||||
m_proxyClient(proxyClient)
|
||||
{
|
||||
m_timer = new QTimer(this);
|
||||
m_timer->setInterval(10000);
|
||||
m_timer->setSingleShot(true);
|
||||
|
||||
m_process = new QProcess(this);
|
||||
}
|
||||
|
||||
ProxyClient *AuthenticationReply::proxyClient() const
|
||||
@ -37,19 +41,25 @@ void AuthenticationReply::setError(Authenticator::AuthenticationError error)
|
||||
|
||||
void AuthenticationReply::setFinished()
|
||||
{
|
||||
emit finished();
|
||||
m_timer->stop();
|
||||
// emit in next event loop
|
||||
QTimer::singleShot(0, this, &AuthenticationReply::finished);
|
||||
}
|
||||
|
||||
void AuthenticationReply::onTimeout()
|
||||
{
|
||||
m_timedOut = true;
|
||||
m_error = Authenticator::AuthenticationErrorTimeout;
|
||||
m_timer->stop();
|
||||
m_process->kill();
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void AuthenticationReply::abort()
|
||||
{
|
||||
m_error = Authenticator::AuthenticationErrorAborted;
|
||||
m_timer->stop();
|
||||
m_process->kill();
|
||||
emit finished();
|
||||
}
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <QUuid>
|
||||
#include <QTimer>
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "authenticator.h"
|
||||
@ -25,9 +26,9 @@ public:
|
||||
|
||||
private:
|
||||
explicit AuthenticationReply(ProxyClient *proxyClient, QObject *parent = nullptr);
|
||||
|
||||
ProxyClient *m_proxyClient = nullptr;
|
||||
QTimer m_timer;
|
||||
QTimer *m_timer = nullptr;
|
||||
QProcess *m_process = nullptr;
|
||||
|
||||
bool m_timedOut = false;
|
||||
bool m_finished = false;
|
||||
|
||||
@ -19,7 +19,7 @@ public:
|
||||
AuthenticationErrorTimeout,
|
||||
AuthenticationErrorAborted,
|
||||
AuthenticationErrorAuthenticationFailed,
|
||||
AuthenticationErrorAuthenticationServerNotResponding
|
||||
AuthenticationErrorProxyError
|
||||
};
|
||||
Q_ENUM(AuthenticationError)
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
#include "engine.h"
|
||||
#include "proxyclient.h"
|
||||
#include "awsauthenticator.h"
|
||||
#include "loggingcategories.h"
|
||||
@ -5,20 +6,47 @@
|
||||
namespace remoteproxy {
|
||||
|
||||
AwsAuthenticator::AwsAuthenticator(QObject *parent) :
|
||||
Authenticator(parent)
|
||||
Authenticator(parent),
|
||||
m_manager(new QNetworkAccessManager(this))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AwsAuthenticator::~AwsAuthenticator()
|
||||
{
|
||||
qCDebug(dcAuthentication()) << "Shutting down" << name();
|
||||
}
|
||||
|
||||
QString AwsAuthenticator::name() const
|
||||
{
|
||||
return "AWS authenticator";
|
||||
}
|
||||
|
||||
void AwsAuthenticator::onAuthenticationProcessFinished(Authenticator::AuthenticationError error)
|
||||
{
|
||||
AuthenticationProcess *process = static_cast<AuthenticationProcess *>(sender());
|
||||
AuthenticationReply *reply = m_runningProcesses.take(process);
|
||||
|
||||
setReplyError(reply, error);
|
||||
setReplyFinished(reply);
|
||||
|
||||
qCDebug(dcAuthentication()) << "" << error;
|
||||
}
|
||||
|
||||
AuthenticationReply *AwsAuthenticator::authenticate(ProxyClient *proxyClient)
|
||||
{
|
||||
qCDebug(dcAuthenticator()) << name() << "Start authenticating" << proxyClient << "using token" << proxyClient->token();
|
||||
qCDebug(dcAuthentication()) << name() << "Start authenticating" << proxyClient << "using token" << proxyClient->token();
|
||||
AuthenticationReply *reply = createAuthenticationReply(proxyClient, this);
|
||||
|
||||
AuthenticationProcess *process = new AuthenticationProcess(m_manager, this);
|
||||
process->useDynamicCredentials(!Engine::instance()->developerMode());
|
||||
connect(process, &AuthenticationProcess::authenticationFinished, this, &AwsAuthenticator::onAuthenticationProcessFinished);
|
||||
|
||||
// Configure process
|
||||
m_runningProcesses.insert(process, reply);
|
||||
|
||||
// Start authentication process
|
||||
process->authenticate(proxyClient->token());
|
||||
return reply;
|
||||
}
|
||||
|
||||
|
||||
@ -2,9 +2,11 @@
|
||||
#define AWSAUTHENTICATOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
#include "authenticator.h"
|
||||
#include "authenticationreply.h"
|
||||
#include "authenticationprocess.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
@ -13,10 +15,17 @@ class AwsAuthenticator : public Authenticator
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AwsAuthenticator(QObject *parent = nullptr);
|
||||
~AwsAuthenticator() override = default;
|
||||
~AwsAuthenticator() override;
|
||||
|
||||
QString name() const override;
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *m_manager = nullptr;
|
||||
QHash<AuthenticationProcess *, AuthenticationReply *> m_runningProcesses;
|
||||
|
||||
private slots:
|
||||
void onAuthenticationProcessFinished(Authenticator::AuthenticationError error);
|
||||
|
||||
public slots:
|
||||
AuthenticationReply *authenticate(ProxyClient *proxyClient) override;
|
||||
|
||||
|
||||
30
libnymea-remoteproxy/authentication/dummyauthenticator.cpp
Normal file
30
libnymea-remoteproxy/authentication/dummyauthenticator.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include "dummyauthenticator.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
DummyAuthenticator::DummyAuthenticator(QObject *parent) :
|
||||
Authenticator(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString DummyAuthenticator::name() const
|
||||
{
|
||||
return "Dummy authenticator";
|
||||
}
|
||||
|
||||
AuthenticationReply *DummyAuthenticator::authenticate(ProxyClient *proxyClient)
|
||||
{
|
||||
qCDebug(dcAuthentication()) << name() << "validate" << proxyClient;
|
||||
qCWarning(dcAuthentication()) << "Attention: This authenticator will always succeed! This is a security risk and was enabled explitly!";
|
||||
AuthenticationReply *reply = createAuthenticationReply(proxyClient, this);
|
||||
|
||||
setReplyError(reply, AuthenticationErrorNoError);
|
||||
setReplyFinished(reply);
|
||||
return reply;
|
||||
}
|
||||
|
||||
}
|
||||
27
libnymea-remoteproxy/authentication/dummyauthenticator.h
Normal file
27
libnymea-remoteproxy/authentication/dummyauthenticator.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef DUMMYAUTHENTICATOR_H
|
||||
#define DUMMYAUTHENTICATOR_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "proxyclient.h"
|
||||
#include "authenticator.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
class DummyAuthenticator : public Authenticator
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DummyAuthenticator(QObject *parent = nullptr);
|
||||
~DummyAuthenticator() override = default;
|
||||
|
||||
QString name() const override;
|
||||
|
||||
public slots:
|
||||
AuthenticationReply *authenticate(ProxyClient *proxyClient) override;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DUMMYAUTHENTICATOR_H
|
||||
@ -32,6 +32,10 @@ bool Engine::exists()
|
||||
|
||||
void Engine::start()
|
||||
{
|
||||
// Make sure an authenticator was registered
|
||||
Q_ASSERT_X(m_authenticator != nullptr, "Engine", "There is no authenticator registerd.");
|
||||
Q_ASSERT_X(m_configuration != nullptr, "Engine", "There is no configuration set.");
|
||||
|
||||
if (!m_running)
|
||||
qCDebug(dcEngine()) << "Start server engine";
|
||||
|
||||
@ -44,15 +48,12 @@ void Engine::start()
|
||||
|
||||
QUrl websocketServerUrl;
|
||||
websocketServerUrl.setScheme("wss");
|
||||
websocketServerUrl.setHost(m_webSocketServerHostAddress.toString());
|
||||
websocketServerUrl.setPort(m_webSocketServerPort);
|
||||
websocketServerUrl.setHost(m_configuration->webSocketServerHost().toString());
|
||||
websocketServerUrl.setPort(m_configuration->webSocketServerPort());
|
||||
m_webSocketServer->setServerUrl(websocketServerUrl);
|
||||
|
||||
m_proxyServer->registerTransportInterface(m_webSocketServer);
|
||||
|
||||
// Make sure an authenticator was registered
|
||||
Q_ASSERT_X(m_authenticator != nullptr, "Engine", "There is no authenticator registerd.");
|
||||
|
||||
qCDebug(dcEngine()) << "Starting proxy server";
|
||||
m_proxyServer->startServer();
|
||||
|
||||
@ -74,6 +75,11 @@ bool Engine::running() const
|
||||
return m_running;
|
||||
}
|
||||
|
||||
bool Engine::developerMode() const
|
||||
{
|
||||
return m_developerMode;
|
||||
}
|
||||
|
||||
QString Engine::serverName() const
|
||||
{
|
||||
return m_serverName;
|
||||
@ -84,36 +90,24 @@ void Engine::setServerName(const QString &serverName)
|
||||
m_serverName = serverName;
|
||||
}
|
||||
|
||||
void Engine::setWebSocketServerHostAddress(const QHostAddress &hostAddress)
|
||||
void Engine::setConfiguration(ProxyConfiguration *configuration)
|
||||
{
|
||||
qCDebug(dcEngine()) << "Websocket server host address:" << hostAddress;
|
||||
m_webSocketServerHostAddress = hostAddress;
|
||||
}
|
||||
|
||||
void Engine::setWebSocketServerPort(const quint16 &port)
|
||||
{
|
||||
qCDebug(dcEngine()) << "Websocket server port:" << port;
|
||||
m_webSocketServerPort = port;
|
||||
m_configuration = configuration;
|
||||
qCDebug(dcApplication()) << "Set configuration" << m_configuration;
|
||||
}
|
||||
|
||||
void Engine::setSslConfiguration(const QSslConfiguration &configuration)
|
||||
{
|
||||
qCDebug(dcEngine()) << "SSL certificate information:";
|
||||
qCDebug(dcEngine()) << " Common name:" << configuration.localCertificate().issuerInfo(QSslCertificate::CommonName);
|
||||
qCDebug(dcEngine()) << " Organisation:" << configuration.localCertificate().issuerInfo(QSslCertificate::Organization);
|
||||
qCDebug(dcEngine()) << " Organisation unit name:" << configuration.localCertificate().issuerInfo(QSslCertificate::OrganizationalUnitName);
|
||||
qCDebug(dcEngine()) << " Country name:" << configuration.localCertificate().issuerInfo(QSslCertificate::CountryName);
|
||||
qCDebug(dcEngine()) << " Locality name:" << configuration.localCertificate().issuerInfo(QSslCertificate::LocalityName);
|
||||
qCDebug(dcEngine()) << " State/Province:" << configuration.localCertificate().issuerInfo(QSslCertificate::StateOrProvinceName);
|
||||
qCDebug(dcEngine()) << " Email address:" << configuration.localCertificate().issuerInfo(QSslCertificate::EmailAddress);
|
||||
|
||||
m_sslConfiguration = configuration;
|
||||
}
|
||||
|
||||
void Engine::setAuthenticationServerUrl(const QUrl &url)
|
||||
{
|
||||
qCDebug(dcEngine()) << "Authentication server URL" << url.toString();
|
||||
m_authenticationServerUrl = url;
|
||||
qCDebug(dcEngine()) << "SSL certificate information:";
|
||||
qCDebug(dcEngine()) << " Common name:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::CommonName);
|
||||
qCDebug(dcEngine()) << " Organisation:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::Organization);
|
||||
qCDebug(dcEngine()) << " Organisation unit name:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::OrganizationalUnitName);
|
||||
qCDebug(dcEngine()) << " Country name:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::CountryName);
|
||||
qCDebug(dcEngine()) << " Locality name:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::LocalityName);
|
||||
qCDebug(dcEngine()) << " State/Province:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::StateOrProvinceName);
|
||||
qCDebug(dcEngine()) << " Email address:" << m_sslConfiguration.localCertificate().issuerInfo(QSslCertificate::EmailAddress);
|
||||
}
|
||||
|
||||
void Engine::setAuthenticator(Authenticator *authenticator)
|
||||
@ -132,6 +126,11 @@ void Engine::setAuthenticator(Authenticator *authenticator)
|
||||
// FIXME: connect
|
||||
}
|
||||
|
||||
void Engine::setDeveloperModeEnabled(bool enabled)
|
||||
{
|
||||
m_developerMode = enabled;
|
||||
}
|
||||
|
||||
Authenticator *Engine::authenticator() const
|
||||
{
|
||||
return m_authenticator;
|
||||
@ -172,7 +171,6 @@ void Engine::clean()
|
||||
}
|
||||
|
||||
if (m_configuration) {
|
||||
delete m_configuration;
|
||||
m_configuration = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,17 +26,17 @@ public:
|
||||
void stop();
|
||||
|
||||
bool running() const;
|
||||
bool developerMode() const;
|
||||
|
||||
QString serverName() const;
|
||||
void setServerName(const QString &serverName);
|
||||
|
||||
void setWebSocketServerHostAddress(const QHostAddress &hostAddress);
|
||||
void setWebSocketServerPort(const quint16 &port);
|
||||
void setConfiguration(ProxyConfiguration *configuration);
|
||||
void setSslConfiguration(const QSslConfiguration &configuration);
|
||||
void setAuthenticationServerUrl(const QUrl &url);
|
||||
|
||||
void setAuthenticator(Authenticator *authenticator);
|
||||
|
||||
void setDeveloperModeEnabled(bool enabled);
|
||||
|
||||
Authenticator *authenticator() const;
|
||||
ProxyServer *proxyServer() const;
|
||||
WebSocketServer *webSocketServer() const;
|
||||
@ -47,13 +47,10 @@ private:
|
||||
static Engine *s_instance;
|
||||
|
||||
bool m_running = false;
|
||||
bool m_developerMode = false;
|
||||
QString m_serverName;
|
||||
|
||||
quint16 m_webSocketServerPort = 1212;
|
||||
QHostAddress m_webSocketServerHostAddress = QHostAddress::LocalHost;
|
||||
QSslConfiguration m_sslConfiguration;
|
||||
QUrl m_authenticationServerUrl;
|
||||
|
||||
ProxyConfiguration *m_configuration = nullptr;
|
||||
Authenticator *m_authenticator = nullptr;
|
||||
ProxyServer *m_proxyServer = nullptr;
|
||||
|
||||
@ -3,6 +3,12 @@ include(../nymea-remoteproxy.pri)
|
||||
TEMPLATE = lib
|
||||
TARGET = nymea-remoteproxy
|
||||
|
||||
# -L/home/timon/guh/development/cloud/aws-sdk-cpp/build/install/lib
|
||||
# -laws-cpp-sdk-access-management \
|
||||
# -laws-cpp-sdk-cognito-identity \
|
||||
# -laws-cpp-sdk-iam \
|
||||
# -laws-cpp-sdk-kinesis\
|
||||
|
||||
HEADERS += \
|
||||
engine.h \
|
||||
loggingcategories.h \
|
||||
@ -19,7 +25,9 @@ HEADERS += \
|
||||
authentication/awsauthenticator.h \
|
||||
authentication/authenticationreply.h \
|
||||
proxyconfiguration.h \
|
||||
tunnelconnection.h
|
||||
tunnelconnection.h \
|
||||
authentication/authenticationprocess.h \
|
||||
authentication/dummyauthenticator.h
|
||||
|
||||
SOURCES += \
|
||||
engine.cpp \
|
||||
@ -37,7 +45,9 @@ SOURCES += \
|
||||
authentication/awsauthenticator.cpp \
|
||||
authentication/authenticationreply.cpp \
|
||||
proxyconfiguration.cpp \
|
||||
tunnelconnection.cpp
|
||||
tunnelconnection.cpp \
|
||||
authentication/authenticationprocess.cpp \
|
||||
authentication/dummyauthenticator.cpp
|
||||
|
||||
|
||||
# install header file with relative subdirectory
|
||||
@ -47,3 +57,6 @@ for(header, HEADERS) {
|
||||
eval(headers_$${path}.path = $${path})
|
||||
eval(INSTALLS *= headers_$${path})
|
||||
}
|
||||
|
||||
target.path = /usr/lib/$$system('dpkg-architecture -q DEB_HOST_MULTIARCH')
|
||||
INSTALLS += target
|
||||
|
||||
@ -6,7 +6,8 @@ Q_LOGGING_CATEGORY(dcJsonRpc, "JsonRpc")
|
||||
Q_LOGGING_CATEGORY(dcJsonRpcTraffic, "JsonRpcTraffic")
|
||||
Q_LOGGING_CATEGORY(dcWebSocketServer, "WebSocketServer")
|
||||
Q_LOGGING_CATEGORY(dcWebSocketServerTraffic, "WebSocketServerTraffic")
|
||||
Q_LOGGING_CATEGORY(dcAuthenticator, "Authenticator")
|
||||
Q_LOGGING_CATEGORY(dcAuthentication, "Authentication")
|
||||
Q_LOGGING_CATEGORY(dcAuthenticationProcess, "AuthenticationProcess")
|
||||
Q_LOGGING_CATEGORY(dcProxyServer, "ProxyServer")
|
||||
Q_LOGGING_CATEGORY(dcProxyServerTraffic, "ProxyServerTraffic")
|
||||
|
||||
|
||||
@ -10,7 +10,8 @@ Q_DECLARE_LOGGING_CATEGORY(dcJsonRpc)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcJsonRpcTraffic)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcWebSocketServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcWebSocketServerTraffic)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcAuthenticator)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcAuthentication)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcAuthenticationProcess)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcProxyServer)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcProxyServerTraffic)
|
||||
|
||||
|
||||
@ -1,10 +1,151 @@
|
||||
#include "loggingcategories.h"
|
||||
#include "proxyconfiguration.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
ProxyConfiguration::ProxyConfiguration(QObject *parent) : QObject(parent)
|
||||
ProxyConfiguration::ProxyConfiguration(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool ProxyConfiguration::loadConfiguration(const QString &fileName)
|
||||
{
|
||||
QFileInfo fileInfo(fileName);
|
||||
if (!fileInfo.exists()) {
|
||||
qCWarning(dcApplication()) << "Configuration: Could not find configuration file" << fileName;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fileInfo.isReadable()) {
|
||||
qCWarning(dcApplication()) << "Configuration: Cannot read configuration file" << fileName;
|
||||
return false;
|
||||
}
|
||||
|
||||
QSettings settings(fileName, QSettings::IniFormat);
|
||||
qCDebug(dcApplication()) << settings.childGroups();
|
||||
|
||||
settings.beginGroup("General");
|
||||
setWriteLogFile(settings.value("writeLogs", false).toBool());
|
||||
setLogFileName(settings.value("logFile", "/var/log/nymea-remoteproxy.log").toString());
|
||||
setSslCertificateFileName(settings.value("certificate", "/etc/ssl/certs/ssl-cert-snakeoil.pem").toString());
|
||||
setSslCertificateKeyFileName(settings.value("certificateKey", "/etc/ssl/private/ssl-cert-snakeoil.key").toString());
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup("WebSocketServer");
|
||||
setWebSocketServerHost(QHostAddress(settings.value("host", "127.0.0.1").toString()));
|
||||
setWebSocketServerPort(static_cast<quint16>(settings.value("port", 1212).toInt()));
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup("TcpServer");
|
||||
setWebSocketServerHost(QHostAddress(settings.value("host", "127.0.0.1").toString()));
|
||||
setWebSocketServerPort(static_cast<quint16>(settings.value("port", 1213).toInt()));
|
||||
settings.endGroup();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProxyConfiguration::writeLogFile() const
|
||||
{
|
||||
return m_writeLogFile;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setWriteLogFile(bool enabled)
|
||||
{
|
||||
m_writeLogFile = enabled;
|
||||
}
|
||||
|
||||
QString ProxyConfiguration::logFileName() const
|
||||
{
|
||||
return m_logFileName;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setLogFileName(const QString &logFileName)
|
||||
{
|
||||
m_logFileName = logFileName;
|
||||
}
|
||||
|
||||
QString ProxyConfiguration::sslCertificateFileName() const
|
||||
{
|
||||
return m_sslCertificateFileName;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setSslCertificateFileName(const QString &fileName)
|
||||
{
|
||||
m_logFileName = fileName;
|
||||
}
|
||||
|
||||
QString ProxyConfiguration::sslCertificateKeyFileName() const
|
||||
{
|
||||
return m_sslCertificateKeyFileName;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setSslCertificateKeyFileName(const QString &fileName)
|
||||
{
|
||||
m_sslCertificateKeyFileName = fileName;
|
||||
}
|
||||
|
||||
QHostAddress ProxyConfiguration::webSocketServerHost() const
|
||||
{
|
||||
return m_webSocketServerHost;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setWebSocketServerHost(const QHostAddress &address)
|
||||
{
|
||||
m_webSocketServerHost = address;
|
||||
}
|
||||
|
||||
quint16 ProxyConfiguration::webSocketServerPort() const
|
||||
{
|
||||
return m_webSocketServerPort;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setWebSocketServerPort(quint16 port)
|
||||
{
|
||||
m_webSocketServerPort = port;
|
||||
}
|
||||
|
||||
QHostAddress ProxyConfiguration::tcpServerHost() const
|
||||
{
|
||||
return m_tcpServerHost;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setTcpServerHost(const QHostAddress &address)
|
||||
{
|
||||
m_tcpServerHost = address;
|
||||
}
|
||||
|
||||
quint16 ProxyConfiguration::tcpServerPort() const
|
||||
{
|
||||
return m_tcpServerPort;
|
||||
}
|
||||
|
||||
void ProxyConfiguration::setTcpServerPort(quint16 port)
|
||||
{
|
||||
m_tcpServerPort = port;
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, ProxyConfiguration *configuration)
|
||||
{
|
||||
debug.nospace() << endl << "========== ProxyConfiguration ==========" << endl;
|
||||
debug.nospace() << "General" << endl;
|
||||
debug.nospace() << " - write logfile:" << configuration->writeLogFile() << endl;
|
||||
debug.nospace() << " - logfile:" << configuration->logFileName() << endl;
|
||||
debug.nospace() << " - certificate:" << configuration->sslCertificateFileName() << endl;
|
||||
debug.nospace() << " - certificate key:" << configuration->sslCertificateKeyFileName() << endl;
|
||||
debug.nospace() << "WebSocketServer" << endl;
|
||||
debug.nospace() << " - host:" << configuration->webSocketServerHost().toString() << endl;
|
||||
debug.nospace() << " - port:" << configuration->webSocketServerPort() << endl;
|
||||
debug.nospace() << "TcpServer" << endl;
|
||||
debug.nospace() << " - host:" << configuration->tcpServerHost().toString() << endl;
|
||||
debug.nospace() << " - port:" << configuration->tcpServerPort() << endl;
|
||||
debug.nospace() << "========== ProxyConfiguration ==========" << endl;
|
||||
|
||||
return debug; return debug;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
#define PROXYCONFIGURATION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
#include <QHostAddress>
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
@ -11,12 +13,54 @@ class ProxyConfiguration : public QObject
|
||||
public:
|
||||
explicit ProxyConfiguration(QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
bool loadConfiguration(const QString &fileName);
|
||||
|
||||
public slots:
|
||||
// General
|
||||
bool writeLogFile() const;
|
||||
void setWriteLogFile(bool enabled);
|
||||
|
||||
QString logFileName() const;
|
||||
void setLogFileName(const QString &logFileName);
|
||||
|
||||
QString sslCertificateFileName() const;
|
||||
void setSslCertificateFileName(const QString &fileName);
|
||||
|
||||
QString sslCertificateKeyFileName() const;
|
||||
void setSslCertificateKeyFileName(const QString &fileName);
|
||||
|
||||
// WebSocketServer
|
||||
QHostAddress webSocketServerHost() const;
|
||||
void setWebSocketServerHost(const QHostAddress &address);
|
||||
|
||||
quint16 webSocketServerPort() const;
|
||||
void setWebSocketServerPort(quint16 port);
|
||||
|
||||
// TcpServer
|
||||
QHostAddress tcpServerHost() const;
|
||||
void setTcpServerHost(const QHostAddress &address);
|
||||
|
||||
quint16 tcpServerPort() const;
|
||||
void setTcpServerPort(quint16 port);
|
||||
|
||||
private:
|
||||
// General
|
||||
bool m_writeLogFile = false;
|
||||
QString m_logFileName = "/var/log/nymea-remoteproxy.log";
|
||||
QString m_sslCertificateFileName = "/etc/ssl/certs/ssl-cert-snakeoil.pem";
|
||||
QString m_sslCertificateKeyFileName = "/etc/ssl/private/ssl-cert-snakeoil.key";
|
||||
|
||||
// WebSocketServer
|
||||
QHostAddress m_webSocketServerHost = QHostAddress::LocalHost;
|
||||
quint16 m_webSocketServerPort = 1212;
|
||||
|
||||
// TcpServer
|
||||
QHostAddress m_tcpServerHost = QHostAddress::LocalHost;
|
||||
quint16 m_tcpServerPort = 1213;
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<< (QDebug debug, ProxyConfiguration *configuration);
|
||||
|
||||
}
|
||||
|
||||
#endif // PROXYCONFIGURATION_H
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
INCLUDEPATH += $${PWD}
|
||||
|
||||
HEADERS += \
|
||||
$${PWD}/jsonrpcclient.h \
|
||||
$${PWD}/proxyjsonrpcclient.h \
|
||||
$${PWD}/jsonreply.h \
|
||||
$${PWD}/remoteproxyconnection.h \
|
||||
$${PWD}/proxyconnection.h \
|
||||
$${PWD}/websocketconnection.h
|
||||
|
||||
SOURCES += \
|
||||
$${PWD}/jsonrpcclient.cpp \
|
||||
$${PWD}/proxyjsonrpcclient.cpp \
|
||||
$${PWD}/jsonreply.cpp \
|
||||
$${PWD}/remoteproxyconnection.cpp \
|
||||
$${PWD}/proxyconnection.cpp \
|
||||
|
||||
@ -2,13 +2,11 @@ include(../nymea-remoteproxy.pri)
|
||||
|
||||
TEMPLATE = lib
|
||||
TARGET = nymea-remoteproxyclient
|
||||
target.path = /usr/lib/$$system('dpkg-architecture -q DEB_HOST_MULTIARCH')
|
||||
|
||||
include(libnymea-remoteproxyclient.pri)
|
||||
|
||||
# install header file with relative subdirectory
|
||||
for(header, HEADERS) {
|
||||
path = /usr/include/nymea-remoteproxyclient/$${dirname(header)}
|
||||
eval(headers_$${path}.files += $${header})
|
||||
eval(headers_$${path}.path = $${path})
|
||||
eval(INSTALLS *= headers_$${path})
|
||||
}
|
||||
installheaders.files = remoteproxyconnection.h
|
||||
installheaders.path = /usr/include/nymea-remoteproxyclient/
|
||||
|
||||
INSTALLS += target installheaders
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#include "jsonrpcclient.h"
|
||||
#include "proxyjsonrpcclient.h"
|
||||
#include "proxyconnection.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
@ -1,5 +1,7 @@
|
||||
#include "remoteproxyconnection.h"
|
||||
#include "websocketconnection.h"
|
||||
#include "proxyjsonrpcclient.h"
|
||||
#include "proxyconnection.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(dcRemoteProxyClientConnection, "RemoteProxyClientConnection")
|
||||
Q_LOGGING_CATEGORY(dcRemoteProxyClientConnectionTraffic, "RemoteProxyClientConnectionTraffic")
|
||||
|
||||
@ -8,14 +8,14 @@
|
||||
#include <QHostAddress>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#include "jsonrpcclient.h"
|
||||
#include "proxyconnection.h"
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcRemoteProxyClientConnection)
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcRemoteProxyClientConnectionTraffic)
|
||||
|
||||
namespace remoteproxyclient {
|
||||
|
||||
class JsonRpcClient;
|
||||
class ProxyConnection;
|
||||
|
||||
class RemoteProxyConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
13
nymea-remoteproxy.conf
Normal file
13
nymea-remoteproxy.conf
Normal file
@ -0,0 +1,13 @@
|
||||
[General]
|
||||
writeLogs=false
|
||||
logFile=/var/log/nymea-remoteproxy.log
|
||||
certificate=/etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||
certificateKey=/etc/ssl/private/ssl-cert-snakeoil.key
|
||||
|
||||
[WebSocketServer]
|
||||
host=0.0.0.0
|
||||
port=443
|
||||
|
||||
[TcpServer]
|
||||
host=0.0.0.0
|
||||
port=80
|
||||
@ -16,6 +16,9 @@ CONFIG += c++11 console
|
||||
QMAKE_CXXFLAGS *= -Werror -std=c++11 -g
|
||||
QMAKE_LFLAGS *= -std=c++11
|
||||
|
||||
INCLUDEPATH += /home/timon/guh/development/cloud/aws-sdk-cpp/build/install/include
|
||||
LIBS += -L/home/timon/guh/development/cloud/aws-sdk-cpp/build/install/lib -laws-cpp-sdk-core -laws-cpp-sdk-lambda
|
||||
|
||||
top_srcdir=$$PWD
|
||||
top_builddir=$$shadowed($$PWD)
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
include(nymea-remoteproxy.pri)
|
||||
|
||||
TEMPLATE=subdirs
|
||||
SUBDIRS += server libnymea-remoteproxy libnymea-remoteproxyclient tests
|
||||
SUBDIRS += server client libnymea-remoteproxy libnymea-remoteproxyclient tests
|
||||
|
||||
server.depends = libnymea-remoteproxy
|
||||
tests.depends = libnymea-remoteproxy libnymea-remoteproxyclient
|
||||
|
||||
client.depends = libnymea-remoteproxyclient
|
||||
|
||||
message("----------------------------------------------------------")
|
||||
message("Building nymea-remoteproxy $${SERVER_VERSION}")
|
||||
|
||||
159
server/main.cpp
159
server/main.cpp
@ -19,7 +19,9 @@
|
||||
|
||||
#include "engine.h"
|
||||
#include "loggingcategories.h"
|
||||
#include "proxyconfiguration.h"
|
||||
#include "authentication/awsauthenticator.h"
|
||||
#include "authentication/dummyauthenticator.h"
|
||||
|
||||
using namespace remoteproxy;
|
||||
|
||||
@ -95,7 +97,7 @@ int main(int argc, char *argv[])
|
||||
s_loggingFilters.insert("JsonRpcTraffic", true);
|
||||
s_loggingFilters.insert("WebSocketServer", true);
|
||||
s_loggingFilters.insert("WebSocketServerTraffic", false);
|
||||
s_loggingFilters.insert("Authenticator", true);
|
||||
s_loggingFilters.insert("Authentication", true);
|
||||
s_loggingFilters.insert("ProxyServer", true);
|
||||
|
||||
// command line parser
|
||||
@ -115,30 +117,33 @@ int main(int argc, char *argv[])
|
||||
"logfile", "/var/log/nymea-remoteproxy.log");
|
||||
parser.addOption(logfileOption);
|
||||
|
||||
QCommandLineOption serverOption(QStringList() << "s" << "server", "The server address this proxy will listen on. "
|
||||
"Default is 127.0.0.1", "hostaddress", "127.0.0.1");
|
||||
parser.addOption(serverOption);
|
||||
QCommandLineOption developmentOption(QStringList() << "d" << "development", "Enable the development mode. This enabled the server "
|
||||
"assumes there are static AWS credentials provided to aws-cli.");
|
||||
parser.addOption(developmentOption);
|
||||
|
||||
QCommandLineOption portOption(QStringList() << "p" << "port", "The proxy server port. Default is 1212", "port", "1212");
|
||||
parser.addOption(portOption);
|
||||
QCommandLineOption mockAuthenticatorOption(QStringList() << "m" << "mock-authenticator", "Start the server using a mock authenticator which returns always true.");
|
||||
parser.addOption(mockAuthenticatorOption);
|
||||
|
||||
QCommandLineOption certOption(QStringList() << "c" <<"certificate", "The path to the SSL certificate used for "
|
||||
"this proxy server.", "certificate");
|
||||
parser.addOption(certOption);
|
||||
|
||||
QCommandLineOption certKeyOption(QStringList() << "k" << "certificate-key", "The path to the SSL certificate key "
|
||||
"used for this proxy server.", "certificate-key");
|
||||
parser.addOption(certKeyOption);
|
||||
|
||||
QCommandLineOption authenticationUrlOption(QStringList() << "a" << "authentication-server",
|
||||
"The server url of the AWS authentication server.", "url", "https://127.0.0.1");
|
||||
parser.addOption(authenticationUrlOption);
|
||||
QCommandLineOption configOption(QStringList() << "c" <<"configuration", "The path to the proxy server configuration file. The default is /etc/nymea-remoteproxy/nymea-remoteproxy.conf", "configuration");
|
||||
configOption.setDefaultValue("/etc/nymea-remoteproxy/nymea-remoteproxy.conf");
|
||||
parser.addOption(configOption);
|
||||
|
||||
QCommandLineOption verboseOption(QStringList() << "v" << "verbose", "Print more verbose.");
|
||||
parser.addOption(verboseOption);
|
||||
|
||||
parser.process(application);
|
||||
|
||||
// Create a default configuration
|
||||
ProxyConfiguration *configuration = new ProxyConfiguration(nullptr);
|
||||
if (parser.isSet(configOption)) {
|
||||
qCDebug(dcApplication()) << "Loading configuration file from" << parser.value(configOption);
|
||||
if (!configuration->loadConfiguration(parser.value(configOption))) {
|
||||
qCCritical(dcApplication()) << "Invalid configuration file passed" << parser.value(configOption);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (parser.isSet(verboseOption)) {
|
||||
s_loggingFilters["Debug"] = true;
|
||||
s_loggingFilters["WebSocketServerTraffic"] = true;
|
||||
@ -146,104 +151,80 @@ int main(int argc, char *argv[])
|
||||
|
||||
QLoggingCategory::installFilter(loggingCategoryFilter);
|
||||
|
||||
// Open the logfile, if any specified
|
||||
if (parser.isSet(logfileOption)) {
|
||||
QFileInfo fi(parser.value(logfileOption));
|
||||
QDir logDir(fi.absolutePath());
|
||||
if (!logDir.exists() && !logDir.mkpath(logDir.absolutePath())) {
|
||||
qCCritical(dcApplication()) << "Error opening log file" << parser.value(logfileOption);
|
||||
return 1;
|
||||
}
|
||||
s_logFile.setFileName(parser.value(logfileOption));
|
||||
if (!s_logFile.open(QFile::WriteOnly | QFile::Append)) {
|
||||
qCCritical(dcApplication()) << "Error opening log file" << parser.value(logfileOption);
|
||||
return 1;
|
||||
}
|
||||
s_loggingEnabled = true;
|
||||
}
|
||||
|
||||
// Proxy server host address
|
||||
QHostAddress serverHostAddress = QHostAddress(parser.value(serverOption));
|
||||
if (serverHostAddress.isNull()) {
|
||||
qCCritical(dcApplication()) << "Invalid hostaddress for the proxy server:" << parser.value(serverOption);
|
||||
// Verify webserver configuration
|
||||
if (configuration->webSocketServerHost().isNull()) {
|
||||
qCCritical(dcApplication()) << "Invalid web socket host address passed.";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Port
|
||||
bool ok = false;
|
||||
uint port = parser.value(portOption).toUInt(&ok);
|
||||
if (!ok) {
|
||||
qCCritical(dcApplication()) << "Invalid port value:" << parser.value(portOption);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (port > 65535) {
|
||||
qCCritical(dcApplication()) << "Port value is out of range:" << parser.value(portOption);
|
||||
// Verify tcp server configuration
|
||||
if (configuration->tcpServerHost().isNull()) {
|
||||
qCCritical(dcApplication()) << "Invalid TCP server host address passed.";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// SSL certificate
|
||||
QSslConfiguration sslConfiguration;
|
||||
if (parser.isSet(certOption)) {
|
||||
// Load certificate
|
||||
QFile certFile(parser.value(certOption));
|
||||
if (!certFile.open(QIODevice::ReadOnly)) {
|
||||
qCCritical(dcApplication()) << "Could not open certificate file:" << parser.value(certOption) << certFile.errorString();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
QSslCertificate certificate(&certFile, QSsl::Pem);
|
||||
qCDebug(dcApplication()) << "Loaded successfully certificate" << parser.value(certOption);
|
||||
certFile.close();
|
||||
|
||||
// Create SSL configuration
|
||||
sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||
sslConfiguration.setLocalCertificate(certificate);
|
||||
sslConfiguration.setProtocol(QSsl::TlsV1_2OrLater);
|
||||
// Load certificate
|
||||
QFile certFile(configuration->sslCertificateFileName());
|
||||
if (!certFile.open(QIODevice::ReadOnly)) {
|
||||
qCCritical(dcApplication()) << "Could not open certificate file" << configuration->sslCertificateFileName() << certFile.errorString();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
QSslCertificate certificate(&certFile, QSsl::Pem);
|
||||
qCDebug(dcApplication()) << "Loaded successfully certificate" << configuration->sslCertificateFileName();
|
||||
certFile.close();
|
||||
|
||||
// Create SSL configuration
|
||||
sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||
sslConfiguration.setLocalCertificate(certificate);
|
||||
sslConfiguration.setProtocol(QSsl::TlsV1_2OrLater);
|
||||
|
||||
// SSL key
|
||||
if (parser.isSet(certKeyOption)) {
|
||||
QFile certKeyFile(parser.value(certKeyOption));
|
||||
if (!certKeyFile.open(QIODevice::ReadOnly)) {
|
||||
qCCritical(dcApplication()) << "Could not open certificate key file:" << parser.value(certKeyOption) << certKeyFile.errorString();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
QSslKey sslKey(&certKeyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
|
||||
qCDebug(dcApplication()) << "Loaded successfully certificate key" << parser.value(certKeyOption);
|
||||
certKeyFile.close();
|
||||
sslConfiguration.setPrivateKey(sslKey);
|
||||
QFile certKeyFile(configuration->sslCertificateKeyFileName());
|
||||
if (!certKeyFile.open(QIODevice::ReadOnly)) {
|
||||
qCCritical(dcApplication()) << "Could not open certificate key file:" << configuration->sslCertificateKeyFileName() << certKeyFile.errorString();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
QSslKey sslKey(&certKeyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
|
||||
qCDebug(dcApplication()) << "Loaded successfully certificate key" << configuration->sslCertificateKeyFileName();
|
||||
certKeyFile.close();
|
||||
sslConfiguration.setPrivateKey(sslKey);
|
||||
|
||||
if (sslConfiguration.isNull()) {
|
||||
qCCritical(dcApplication()) << "No SSL configuration specified. The server does not suppoert insecure connections.";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Authentication server url
|
||||
QUrl authenticationServerUrl(parser.value(authenticationUrlOption));
|
||||
if (!authenticationServerUrl.isValid()) {
|
||||
qCCritical(dcApplication()) << "Invalid authentication server url:" << parser.value(authenticationUrlOption);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
qCDebug(dcApplication()) << "==============================================";
|
||||
qCDebug(dcApplication()) << "==========================================================";
|
||||
qCDebug(dcApplication()) << "Starting" << application.applicationName() << application.applicationVersion();
|
||||
qCDebug(dcApplication()) << "==============================================";
|
||||
qCDebug(dcApplication()) << "==========================================================";
|
||||
|
||||
if (parser.isSet(developmentOption)) {
|
||||
qCWarning(dcApplication()) << "##########################################################";
|
||||
qCWarning(dcApplication()) << "# DEVELOPMENT MODE #";
|
||||
qCWarning(dcApplication()) << "##########################################################";
|
||||
}
|
||||
|
||||
if (s_loggingEnabled)
|
||||
qCDebug(dcApplication()) << "Logging enabled. Writing logs to" << s_logFile.fileName();
|
||||
|
||||
// Create default authenticator
|
||||
AwsAuthenticator *authenticator = new AwsAuthenticator(nullptr);
|
||||
Authenticator *authenticator = nullptr;
|
||||
if (parser.isSet(mockAuthenticatorOption)) {
|
||||
authenticator = qobject_cast<Authenticator *>(new DummyAuthenticator(nullptr));
|
||||
} else {
|
||||
// Create default authenticator
|
||||
authenticator = qobject_cast<Authenticator *>(new AwsAuthenticator(nullptr));
|
||||
}
|
||||
|
||||
// Configure and start the engines
|
||||
Engine::instance()->setAuthenticator(authenticator);
|
||||
Engine::instance()->setWebSocketServerHostAddress(serverHostAddress);
|
||||
Engine::instance()->setWebSocketServerPort(static_cast<quint16>(port));
|
||||
Engine::instance()->setConfiguration(configuration);
|
||||
Engine::instance()->setDeveloperModeEnabled(parser.isSet(developmentOption));
|
||||
Engine::instance()->setSslConfiguration(sslConfiguration);
|
||||
Engine::instance()->setAuthenticationServerUrl(authenticationServerUrl);
|
||||
Engine::instance()->setAuthenticator(authenticator);
|
||||
|
||||
Engine::instance()->start();
|
||||
|
||||
return application.exec();
|
||||
|
||||
@ -29,7 +29,7 @@ void MockAuthenticator::replyFinished()
|
||||
MockAuthenticationReply *reply = static_cast<MockAuthenticationReply *>(sender());
|
||||
reply->deleteLater();
|
||||
|
||||
qCDebug(dcAuthenticator()) << name() << "Authentication finished.";
|
||||
qCDebug(dcAuthentication()) << name() << "Authentication finished.";
|
||||
|
||||
setReplyError(reply->authenticationReply(), reply->error());
|
||||
setReplyFinished(reply->authenticationReply());
|
||||
@ -37,7 +37,7 @@ void MockAuthenticator::replyFinished()
|
||||
|
||||
AuthenticationReply *MockAuthenticator::authenticate(ProxyClient *proxyClient)
|
||||
{
|
||||
qCDebug(dcAuthenticator()) << name() << "Start authentication for" << proxyClient << "using token" << proxyClient->token();
|
||||
qCDebug(dcAuthentication()) << name() << "Start authentication for" << proxyClient << "using token" << proxyClient->token();
|
||||
|
||||
AuthenticationReply *authenticationReply = createAuthenticationReply(proxyClient, this);
|
||||
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
RemoteProxyTests::RemoteProxyTests(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
m_configuration = new ProxyConfiguration(this);
|
||||
|
||||
QFile certificateFile(":/test-certificate.crt");
|
||||
if (!certificateFile.open(QIODevice::ReadOnly)) {
|
||||
qWarning() << "Could not open resource file" << certificateFile.fileName();
|
||||
@ -72,11 +74,10 @@ void RemoteProxyTests::startEngine()
|
||||
if (!Engine::exists()) {
|
||||
QString serverName = "nymea-remoteproxy-testserver";
|
||||
Engine::instance()->setAuthenticator(m_authenticator);
|
||||
Engine::instance()->setAuthenticationServerUrl(QUrl("https://localhost"));
|
||||
Engine::instance()->setServerName(serverName);
|
||||
Engine::instance()->setWebSocketServerPort(m_port);
|
||||
Engine::instance()->setWebSocketServerHostAddress(QHostAddress::LocalHost);
|
||||
Engine::instance()->setConfiguration(m_configuration);
|
||||
Engine::instance()->setSslConfiguration(m_sslConfiguration);
|
||||
Engine::instance()->setDeveloperModeEnabled(true);
|
||||
|
||||
QVERIFY(Engine::exists());
|
||||
QVERIFY(Engine::instance()->serverName() == serverName);
|
||||
@ -89,6 +90,8 @@ void RemoteProxyTests::startServer()
|
||||
|
||||
if (!Engine::instance()->running()) {
|
||||
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
||||
Engine::instance()->setConfiguration(m_configuration);
|
||||
Engine::instance()->setDeveloperModeEnabled(true);
|
||||
Engine::instance()->start();
|
||||
runningSpy.wait();
|
||||
QVERIFY(runningSpy.count() == 1);
|
||||
@ -217,9 +220,8 @@ void RemoteProxyTests::webserverConnectionBlocked()
|
||||
dummyServer.listen(QHostAddress::LocalHost, m_port);
|
||||
|
||||
// Start proxy webserver
|
||||
Engine::instance()->setWebSocketServerPort(m_port);
|
||||
Engine::instance()->setConfiguration(m_configuration);
|
||||
Engine::instance()->setAuthenticator(m_authenticator);
|
||||
Engine::instance()->setWebSocketServerHostAddress(QHostAddress::LocalHost);
|
||||
Engine::instance()->setSslConfiguration(m_sslConfiguration);
|
||||
|
||||
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
||||
@ -324,7 +326,7 @@ void RemoteProxyTests::authenticate_data()
|
||||
<< 100 << Authenticator::AuthenticationErrorAuthenticationFailed;
|
||||
|
||||
QTest::newRow("not responding") << QUuid::createUuid().toString() << "Testclient, hello form the test!" << m_testToken
|
||||
<< 200 << Authenticator::AuthenticationErrorAuthenticationServerNotResponding;
|
||||
<< 200 << Authenticator::AuthenticationErrorProxyError;
|
||||
|
||||
QTest::newRow("aborted") << QUuid::createUuid().toString() << "Testclient, hello form the test!" << m_testToken
|
||||
<< 100 << Authenticator::AuthenticationErrorAborted;
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
#include "jsonrpc/jsontypes.h"
|
||||
#include "mockauthenticator.h"
|
||||
#include "proxyconfiguration.h"
|
||||
#include "remoteproxyconnection.h"
|
||||
|
||||
using namespace remoteproxy;
|
||||
@ -24,8 +25,11 @@ public:
|
||||
explicit RemoteProxyTests(QObject *parent = nullptr);
|
||||
|
||||
private:
|
||||
ProxyConfiguration *m_configuration = nullptr;
|
||||
|
||||
quint16 m_port = 1212;
|
||||
QHostAddress m_serverAddress = QHostAddress::LocalHost;
|
||||
|
||||
QSslConfiguration m_sslConfiguration;
|
||||
MockAuthenticator *m_authenticator = nullptr;
|
||||
QString m_testToken;
|
||||
|
||||
Reference in New Issue
Block a user