From c5f031796b1263f8ecaf8db9837b2a78b73c0a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 27 Aug 2018 13:32:07 +0200 Subject: [PATCH] Add native lambda invoke code --- debian/changelog | 8 +- .../authentication/authenticationreply.cpp | 19 +-- .../authentication/authenticationreply.h | 3 +- .../{ => aws}/authenticationprocess.cpp | 161 ++++++++---------- .../{ => aws}/authenticationprocess.h | 22 +-- .../{ => aws}/awsauthenticator.cpp | 20 ++- .../{ => aws}/awsauthenticator.h | 8 +- .../aws/awscredentialprovider.cpp | 148 ++++++++++++++++ .../aws/awscredentialprovider.h | 82 +++++++++ .../authentication/{ => aws}/sigv4utils.cpp | 48 ++++-- .../authentication/aws/sigv4utils.h | 55 ++++++ .../{ => aws}/userinformation.cpp | 0 .../{ => aws}/userinformation.h | 0 .../{ => dummy}/dummyauthenticator.cpp | 0 .../{ => dummy}/dummyauthenticator.h | 2 +- .../authentication/sigv4utils.h | 33 ---- .../jsonrpc/authenticationhandler.cpp | 4 +- libnymea-remoteproxy/jsonrpc/jsonhandler.cpp | 4 +- libnymea-remoteproxy/jsonrpc/jsonhandler.h | 2 +- libnymea-remoteproxy/jsonrpc/jsonreply.cpp | 4 +- libnymea-remoteproxy/jsonrpc/jsonreply.h | 3 +- libnymea-remoteproxy/jsonrpcserver.cpp | 23 ++- libnymea-remoteproxy/libnymea-remoteproxy.pro | 22 +-- libnymea-remoteproxy/loggingcategories.cpp | 3 +- libnymea-remoteproxy/loggingcategories.h | 2 + libnymea-remoteproxy/proxyconfiguration.cpp | 13 +- libnymea-remoteproxy/proxyconfiguration.h | 12 +- .../proxyjsonrpcclient.cpp | 6 +- monitor/terminalwindow.cpp | 26 +-- nymea-remoteproxy.conf | 1 + nymea-remoteproxy.pri | 2 +- server/main.cpp | 11 +- tests/testbase/basetest.cpp | 62 ++++--- tests/testbase/basetest.h | 4 +- 34 files changed, 572 insertions(+), 241 deletions(-) rename libnymea-remoteproxy/authentication/{ => aws}/authenticationprocess.cpp (71%) rename libnymea-remoteproxy/authentication/{ => aws}/authenticationprocess.h (83%) rename libnymea-remoteproxy/authentication/{ => aws}/awsauthenticator.cpp (78%) rename libnymea-remoteproxy/authentication/{ => aws}/awsauthenticator.h (89%) create mode 100644 libnymea-remoteproxy/authentication/aws/awscredentialprovider.cpp create mode 100644 libnymea-remoteproxy/authentication/aws/awscredentialprovider.h rename libnymea-remoteproxy/authentication/{ => aws}/sigv4utils.cpp (71%) create mode 100644 libnymea-remoteproxy/authentication/aws/sigv4utils.h rename libnymea-remoteproxy/authentication/{ => aws}/userinformation.cpp (100%) rename libnymea-remoteproxy/authentication/{ => aws}/userinformation.h (100%) rename libnymea-remoteproxy/authentication/{ => dummy}/dummyauthenticator.cpp (100%) rename libnymea-remoteproxy/authentication/{ => dummy}/dummyauthenticator.h (98%) delete mode 100644 libnymea-remoteproxy/authentication/sigv4utils.h diff --git a/debian/changelog b/debian/changelog index fe65d1f..cef6e5d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,10 @@ -nymea-remoteproxy (0.1.2) UNRELEASED; urgency=medium +nymea-remoteproxy (0.1.3) bionic; urgency=medium + + * Add native AWS lambda invoke code + + -- Simon Stürz Mon, 27 Aug 2018 13:31:18 +0200 + +nymea-remoteproxy (0.1.2) bionic; urgency=medium * Many bug fixes * Add more scurity mechanisms diff --git a/libnymea-remoteproxy/authentication/authenticationreply.cpp b/libnymea-remoteproxy/authentication/authenticationreply.cpp index 7d18e64..7abcf61 100644 --- a/libnymea-remoteproxy/authentication/authenticationreply.cpp +++ b/libnymea-remoteproxy/authentication/authenticationreply.cpp @@ -29,12 +29,11 @@ AuthenticationReply::AuthenticationReply(ProxyClient *proxyClient, QObject *pare QObject(parent), m_proxyClient(proxyClient) { - m_timer.setSingleShot(true); - connect(&m_timer, &QTimer::timeout, this, &AuthenticationReply::onTimeout); + m_timer = new QTimer(this); + m_timer->setSingleShot(true); + connect(m_timer, &QTimer::timeout, this, &AuthenticationReply::onTimeout); - m_process = new QProcess(this); - - m_timer.start(Engine::instance()->configuration()->authenticationTimeout()); + m_timer->start(Engine::instance()->configuration()->authenticationTimeout()); } ProxyClient *AuthenticationReply::proxyClient() const @@ -64,7 +63,7 @@ void AuthenticationReply::setError(Authenticator::AuthenticationError error) void AuthenticationReply::setFinished() { - m_timer.stop(); + m_timer->stop(); // emit in next event loop QTimer::singleShot(0, this, &AuthenticationReply::finished); } @@ -73,17 +72,13 @@ void AuthenticationReply::onTimeout() { m_timedOut = true; m_error = Authenticator::AuthenticationErrorTimeout; - m_timer.stop(); - m_process->kill(); - QTimer::singleShot(0, this, &AuthenticationReply::finished); + setFinished(); } void AuthenticationReply::abort() { m_error = Authenticator::AuthenticationErrorAborted; - m_timer.stop(); - m_process->kill(); - QTimer::singleShot(0, this, &AuthenticationReply::finished); + setFinished(); } } diff --git a/libnymea-remoteproxy/authentication/authenticationreply.h b/libnymea-remoteproxy/authentication/authenticationreply.h index 82b724b..3eb830f 100644 --- a/libnymea-remoteproxy/authentication/authenticationreply.h +++ b/libnymea-remoteproxy/authentication/authenticationreply.h @@ -48,8 +48,7 @@ public: private: explicit AuthenticationReply(ProxyClient *proxyClient, QObject *parent = nullptr); ProxyClient *m_proxyClient = nullptr; - QTimer m_timer; - QProcess *m_process = nullptr; + QTimer *m_timer = nullptr; bool m_timedOut = false; bool m_finished = false; diff --git a/libnymea-remoteproxy/authentication/authenticationprocess.cpp b/libnymea-remoteproxy/authentication/aws/authenticationprocess.cpp similarity index 71% rename from libnymea-remoteproxy/authentication/authenticationprocess.cpp rename to libnymea-remoteproxy/authentication/aws/authenticationprocess.cpp index dfb612b..92d9954 100644 --- a/libnymea-remoteproxy/authentication/authenticationprocess.cpp +++ b/libnymea-remoteproxy/authentication/aws/authenticationprocess.cpp @@ -32,28 +32,19 @@ namespace remoteproxy { -AuthenticationProcess::AuthenticationProcess(QNetworkAccessManager *manager, QObject *parent) : +AuthenticationProcess::AuthenticationProcess(QNetworkAccessManager *manager, const QString &accessKey, const QString &secretAccessKey, const QString &sessionToken, QObject *parent) : QObject(parent), - m_manager(manager) + m_manager(manager), + m_accessKey(accessKey), + m_secretAccessKey(secretAccessKey), + m_sessionToken(sessionToken) { m_process = new QProcess(this); m_process->setProcessChannelMode(QProcess::MergedChannels); connect(m_process, static_cast(&QProcess::finished), this, &AuthenticationProcess::onProcessFinished); } -void AuthenticationProcess::useDynamicCredentials(bool dynamicCredentials) -{ - m_dynamicCredentials = dynamicCredentials; -} - -void AuthenticationProcess::requestDynamicCredentials() -{ - m_requestTimer.start(); - 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::invokeLambdaFunction(const QString accessKey, const QString &secretAccessKey, const QString &sessionToken) +void AuthenticationProcess::invokeLambdaFunction() { // Known configurations QString region = "eu-west-1"; @@ -63,23 +54,21 @@ void AuthenticationProcess::invokeLambdaFunction(const QString accessKey, const // {'url_path': '/2015-03-31/functions/system-services-authorizer-dev-checkToken/invocations', 'query_string': {}, 'method': 'POST', 'headers': {'X-Amz-Invocation-Type': 'RequestResponse', 'User-Agent': 'aws-cli/1.14.44 Python/3.6.5 Linux/4.15.0-1019-aws botocore/1.8.48'}, 'body': b'{"token": "...."}', 'url': 'https://lambda.eu-west-1.amazonaws.com/2015-03-31/functions/system-services-authorizer-dev-checkToken/invocations', 'context': {'client_region': 'eu-west-1', 'client_config': , 'has_streaming_input': True, 'auth_type': None}} - // Create request map - QVariantMap requestMap; - requestMap.insert("token", m_token); - QByteArray payload = QJsonDocument::fromVariant(requestMap).toJson(QJsonDocument::Compact); - QUrl requestUrl; requestUrl.setScheme("https"); requestUrl.setHost(QString("lambda.%1.amazonaws.com").arg(region)); requestUrl.setPath(QString("/2015-03-31/functions/%1/invocations").arg(lambdaFunctionName)); - QNetworkRequest request(requestUrl); - request.setRawHeader("User-Agent", QString("%1/%2 JSON-RPC/%3").arg(SERVER_NAME_STRING).arg(SERVER_VERSION_STRING).arg(API_VERSION_STRING).toUtf8()); - request.setRawHeader("Content-Type", "application/json"); - request.setRawHeader("host", requestUrl.host().toUtf8()); - request.setRawHeader("x-amz-invocation-type", invocationType.toUtf8()); + // Create request map + QVariantMap requestMap; + requestMap.insert("token", m_token); + QByteArray payload = QJsonDocument::fromVariant(requestMap).toJson(QJsonDocument::Compact); - SigV4Utils::signRequest(QNetworkAccessManager::PostOperation, request, region, service, accessKey.toUtf8(), secretAccessKey.toUtf8(), sessionToken.toUtf8(), payload); + QNetworkRequest request(requestUrl); + //request.setRawHeader("User-Agent", QString("%1/%2 JSON-RPC/%3").arg(SERVER_NAME_STRING).arg(SERVER_VERSION_STRING).arg(API_VERSION_STRING).toUtf8()); + //request.setRawHeader("Content-Type", "application/json"); + request.setRawHeader("host", requestUrl.host().toUtf8()); + SigV4Utils::signRequest(QNetworkAccessManager::PostOperation, request, region, service, invocationType, m_accessKey.toUtf8(), m_secretAccessKey.toUtf8(), m_sessionToken.toUtf8(), payload); qCDebug(dcAuthenticationProcess()) << "Invoke lambda function" << lambdaFunctionName; @@ -87,19 +76,19 @@ void AuthenticationProcess::invokeLambdaFunction(const QString accessKey, const qCDebug(dcAuthenticationProcess()) << request.url().toString(); foreach (const QByteArray &rawHeader, request.rawHeaderList()) { - qDebug(dcAuthenticationProcess()) << request.rawHeader(rawHeader); + qDebug(dcAuthenticationProcess()) << rawHeader << request.rawHeader(rawHeader); } qCDebug(dcAuthenticationProcess()) << payload; qCDebug(dcAuthenticationProcess()) << "--------------------------------------------"; m_lambdaTimer.start(); - QNetworkReply *reply = m_manager->get(request); + QNetworkReply *reply = m_manager->post(request, payload); connect(reply, &QNetworkReply::finished, this, &AuthenticationProcess::onLambdaInvokeFunctionFinished); } -void AuthenticationProcess::startVerificationProcess(const QString accessKey, const QString &secretAccessKey, const QString &sessionToken) +void AuthenticationProcess::startVerificationProcess() { if (m_process->state() != QProcess::NotRunning) { qCWarning(dcAuthenticationProcess()) << "Authentication process already running. Killing the running process and restart."; @@ -113,56 +102,31 @@ void AuthenticationProcess::startVerificationProcess(const QString accessKey, co // Set environment QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert("AWS_DEFAULT_REGION", "eu-west-1"); - if (m_dynamicCredentials) { - qCDebug(dcAuthenticationProcess()) << "Using dynamic credentials" << accessKey << secretAccessKey << sessionToken; - env.insert("AWS_ACCESS_KEY_ID", accessKey); - env.insert("AWS_SECRET_ACCESS_KEY", secretAccessKey); - env.insert("AWS_SESSION_TOKEN", sessionToken); + if (m_fallback) { + qCDebug(dcAuthenticationProcess()) << "Using dynamic credentials" << m_accessKey << m_secretAccessKey << m_sessionToken; + env.insert("AWS_ACCESS_KEY_ID", m_accessKey); + env.insert("AWS_SECRET_ACCESS_KEY", m_secretAccessKey); + env.insert("AWS_SESSION_TOKEN", m_sessionToken); } + m_process->setProcessEnvironment(env); // FIXME: check how to clean this up properly m_resultFileName = "/tmp/" + QUuid::createUuid().toString().remove("{").remove("}").remove("-") + ".json"; + QStringList processParams = { "lambda", "invoke", + "--function-name", "system-services-authorizer-dev-checkToken", + "--invocation-type", "RequestResponse", + "--payload", QString::fromUtf8(QJsonDocument::fromVariant(request).toJson()), + m_resultFileName }; + + qCDebug(dcAuthenticationProcess()) << "Process environment" << env.toStringList(); + qCDebug(dcAuthenticationProcess()) << "Process params" << processParams; + + qCDebug(dcAuthentication()) << "Start authenticator process and store result in" << m_resultFileName; m_processTimer.start(); - 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(sender()); - reply->deleteLater(); - - qCDebug(dcAuthenticationProcess()) << "Dynamic credentials request finished (" << m_requestTimer.elapsed() << "[ms] )"; - 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; - - startVerificationProcess(response.value("AccessKeyId").toString(), - response.value("SecretAccessKey").toString(), - response.value("Token").toString()); + m_process->start("aws", processParams); } void AuthenticationProcess::onLambdaInvokeFunctionFinished() @@ -170,39 +134,58 @@ void AuthenticationProcess::onLambdaInvokeFunctionFinished() QNetworkReply *reply = static_cast(sender()); reply->deleteLater(); - qCDebug(dcAuthenticationProcess()) << "Lambda invoke request finished (" << m_lambdaTimer.elapsed() << "[ms] )"; - if (reply->error()) { - qCWarning(dcAuthenticationProcess()) << "Dynamic credentials reply error: " << reply->errorString(); - emit authenticationFinished(Authenticator::AuthenticationErrorProxyError); - return; - } + qCDebug(dcAuthenticationProcess()) << "Lambda invoke request finished (" << m_lambdaTimer.elapsed() << "[ms] )"; QByteArray data = reply->readAll(); - qCDebug(dcAuthenticationProcess()) << "Invoke lambda function response ready"; - qCDebug(dcAuthenticationProcess()) << "--------------------------------------------"; qCDebug(dcAuthenticationProcess()) << reply->request().url().toString(); foreach (const QByteArray &rawHeader, reply->rawHeaderList()) { - qDebug(dcAuthenticationProcess()) << reply->rawHeader(rawHeader); + qDebug(dcAuthenticationProcess()) << rawHeader << reply->rawHeader(rawHeader); } - qCDebug(dcAuthenticationProcess()) << data; + qCDebug(dcAuthenticationProcess()) << qUtf8Printable(data); qCDebug(dcAuthenticationProcess()) << "--------------------------------------------"; + if (reply->error()) { + qCWarning(dcAuthenticationProcess()) << "Lambda invoke reply error: " << reply->errorString(); + m_fallback = true; + return; + } + + qCDebug(dcAuthenticationProcess()) << "Lambda function result ready" << qUtf8Printable(data); 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(); + qCWarning(dcAuthenticationProcess()) << "Failed to parse lambda invoke result data" << data << ":" << error.errorString(); emit authenticationFinished(Authenticator::AuthenticationErrorProxyError); return; } QVariantMap response = jsonDoc.toVariant().toMap(); - qCDebug(dcAuthentication()) << "-->" << response; + 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) { + QVariantMap verifiedDataMap = response.value("verifiedData").toMap(); + QString vendorId = verifiedDataMap.value("vendorId").toString(); + QString userPoolId = verifiedDataMap.value("userPoolId").toString(); + QVariantMap verifiedParsedTokenMap = verifiedDataMap.value("verifiedParsedToken").toMap(); + QString email = verifiedParsedTokenMap.value("email").toString(); + QString cognitoUsername = verifiedParsedTokenMap.value("cognito:username").toString(); + + UserInformation userInformation(email, cognitoUsername, vendorId, userPoolId); + + emit authenticationFinished(Authenticator::AuthenticationErrorNoError, userInformation); + } else { + emit authenticationFinished(Authenticator::AuthenticationErrorAuthenticationFailed); + } } void AuthenticationProcess::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) @@ -281,15 +264,7 @@ 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 { - // FIXME: - // Direct call aws cli and assume the credentials will be provided static - // startVerificationProcess(); - } + invokeLambdaFunction(); } } diff --git a/libnymea-remoteproxy/authentication/authenticationprocess.h b/libnymea-remoteproxy/authentication/aws/authenticationprocess.h similarity index 83% rename from libnymea-remoteproxy/authentication/authenticationprocess.h rename to libnymea-remoteproxy/authentication/aws/authenticationprocess.h index 67421d7..759e24f 100644 --- a/libnymea-remoteproxy/authentication/authenticationprocess.h +++ b/libnymea-remoteproxy/authentication/aws/authenticationprocess.h @@ -27,8 +27,8 @@ #include #include -#include "authenticator.h" #include "userinformation.h" +#include "authentication/authenticator.h" namespace remoteproxy { @@ -36,32 +36,32 @@ class AuthenticationProcess : public QObject { Q_OBJECT public: - explicit AuthenticationProcess(QNetworkAccessManager *manager, QObject *parent = nullptr); - - void useDynamicCredentials(bool dynamicCredentials); + explicit AuthenticationProcess(QNetworkAccessManager *manager, const QString &accessKey, const QString &secretAccessKey, const QString &sessionToken, QObject *parent = nullptr); private: + QNetworkAccessManager *m_manager = nullptr; + QString m_accessKey; + QString m_secretAccessKey; + QString m_sessionToken; + QString m_token; QString m_resultFileName; - bool m_dynamicCredentials = true; + bool m_fallback = false; - QNetworkAccessManager *m_manager = nullptr; QProcess *m_process = nullptr; - QElapsedTimer m_requestTimer; QElapsedTimer m_lambdaTimer; QElapsedTimer m_processTimer; - void requestDynamicCredentials(); - void invokeLambdaFunction(const QString accessKey, const QString &secretAccessKey, const QString &sessionToken); - void startVerificationProcess(const QString accessKey, const QString &secretAccessKey, const QString &sessionToken); + void invokeLambdaFunction(); + void startVerificationProcess(); + void cleanUp(); signals: void authenticationFinished(Authenticator::AuthenticationError error, const UserInformation &userInformation = UserInformation()); private slots: - void onDynamicCredentialsReady(); void onLambdaInvokeFunctionFinished(); void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); diff --git a/libnymea-remoteproxy/authentication/awsauthenticator.cpp b/libnymea-remoteproxy/authentication/aws/awsauthenticator.cpp similarity index 78% rename from libnymea-remoteproxy/authentication/awsauthenticator.cpp rename to libnymea-remoteproxy/authentication/aws/awsauthenticator.cpp index 68ced91..eb737db 100644 --- a/libnymea-remoteproxy/authentication/awsauthenticator.cpp +++ b/libnymea-remoteproxy/authentication/aws/awsauthenticator.cpp @@ -26,16 +26,18 @@ namespace remoteproxy { -AwsAuthenticator::AwsAuthenticator(QObject *parent) : +AwsAuthenticator::AwsAuthenticator(const QUrl &awsCredentialsUrl, QObject *parent) : Authenticator(parent), m_manager(new QNetworkAccessManager(this)) { - // TODO: verify if aws command is installed + m_credentialsProvider = new AwsCredentialProvider(m_manager, awsCredentialsUrl, this); + QMetaObject::invokeMethod(m_credentialsProvider, QString("enable").toLatin1().data(), Qt::QueuedConnection); } AwsAuthenticator::~AwsAuthenticator() { qCDebug(dcAuthentication()) << "Shutting down" << name(); + m_credentialsProvider->disable(); } QString AwsAuthenticator::name() const @@ -63,8 +65,18 @@ AuthenticationReply *AwsAuthenticator::authenticate(ProxyClient *proxyClient) qCDebug(dcAuthentication()) << name() << "Start authenticating" << proxyClient; AuthenticationReply *reply = createAuthenticationReply(proxyClient, this); - AuthenticationProcess *process = new AuthenticationProcess(m_manager, this); - process->useDynamicCredentials(!Engine::instance()->developerMode()); + if (!m_credentialsProvider->isValid()) { + qCWarning(dcAuthentication()) << name() << "There are no credentials for authenticating."; + setReplyError(reply, AuthenticationErrorProxyError); + setReplyFinished(reply); + return reply; + } + + AuthenticationProcess *process = new AuthenticationProcess(m_manager, + m_credentialsProvider->accessKey(), + m_credentialsProvider->secretAccessKey(), + m_credentialsProvider->sessionToken(), this); + connect(process, &AuthenticationProcess::authenticationFinished, this, &AwsAuthenticator::onAuthenticationProcessFinished); // Configure process diff --git a/libnymea-remoteproxy/authentication/awsauthenticator.h b/libnymea-remoteproxy/authentication/aws/awsauthenticator.h similarity index 89% rename from libnymea-remoteproxy/authentication/awsauthenticator.h rename to libnymea-remoteproxy/authentication/aws/awsauthenticator.h index 4524cbc..57a5489 100644 --- a/libnymea-remoteproxy/authentication/awsauthenticator.h +++ b/libnymea-remoteproxy/authentication/aws/awsauthenticator.h @@ -25,9 +25,10 @@ #include #include -#include "authenticator.h" -#include "authenticationreply.h" +#include "awscredentialprovider.h" #include "authenticationprocess.h" +#include "authentication/authenticator.h" +#include "authentication/authenticationreply.h" namespace remoteproxy { @@ -35,13 +36,14 @@ class AwsAuthenticator : public Authenticator { Q_OBJECT public: - explicit AwsAuthenticator(QObject *parent = nullptr); + explicit AwsAuthenticator(const QUrl &awsCredentialsUrl, QObject *parent = nullptr); ~AwsAuthenticator() override; QString name() const override; private: QNetworkAccessManager *m_manager = nullptr; + AwsCredentialProvider *m_credentialsProvider = nullptr; QHash m_runningProcesses; private slots: diff --git a/libnymea-remoteproxy/authentication/aws/awscredentialprovider.cpp b/libnymea-remoteproxy/authentication/aws/awscredentialprovider.cpp new file mode 100644 index 0000000..530a6a9 --- /dev/null +++ b/libnymea-remoteproxy/authentication/aws/awscredentialprovider.cpp @@ -0,0 +1,148 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2018 Simon Stürz * + * * + * This file is part of nymea-remoteproxy. * + * * + * This program 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, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "loggingcategories.h" +#include "awscredentialprovider.h" + +#include +#include +#include +#include + +namespace remoteproxy { + +AwsCredentialProvider::AwsCredentialProvider(QNetworkAccessManager *networkManager, const QUrl &awsCredentialsUrl, QObject *parent) : + QObject(parent), + m_networkManager(networkManager), + m_requestUrl(awsCredentialsUrl) +{ + m_timer = new QTimer(this); + m_timer->setSingleShot(false); + m_timer->setInterval(90000); + + connect(m_timer, &QTimer::timeout, this, &AwsCredentialProvider::onTimeout); +} + +QString AwsCredentialProvider::accessKey() const +{ + return m_accessKey; +} + +QString AwsCredentialProvider::secretAccessKey() const +{ + return m_secretAccessKey; +} + +QString AwsCredentialProvider::sessionToken() const +{ + return m_sessionToken; +} + +bool AwsCredentialProvider::isValid() const +{ + return !m_accessKey.isEmpty() && !m_secretAccessKey.isEmpty() && !m_sessionToken.isEmpty(); +} + +bool AwsCredentialProvider::enabled() const +{ + return m_enabled; +} + +void AwsCredentialProvider::refreshCredentials() +{ + qCDebug(dcAwsCredentialsProvider()) << "Update dynamic credentials form" << m_requestUrl.toString(); + + m_requestTimer.start(); + QNetworkReply *reply = m_networkManager->get(QNetworkRequest(m_requestUrl)); + connect(reply, &QNetworkReply::finished, this, &AwsCredentialProvider::onReplyFinished); +} + +void AwsCredentialProvider::clear() +{ + m_accessKey.clear(); + m_secretAccessKey.clear(); + m_sessionToken.clear(); +} + + +void AwsCredentialProvider::onTimeout() +{ + // TODO: check if we need to refresh + refreshCredentials(); +} + +void AwsCredentialProvider::onReplyFinished() +{ + QNetworkReply *reply = static_cast(sender()); + reply->deleteLater(); + + qCDebug(dcAwsCredentialsProvider()) << "Dynamic credentials request finished (" << m_requestTimer.elapsed() << "[ms] )"; + if (reply->error()) { + qCWarning(dcAwsCredentialsProvider()) << "Dynamic credentials reply error: " << reply->errorString(); + return; + } + + QByteArray data = reply->readAll(); + + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + + if(error.error != QJsonParseError::NoError) { + qCWarning(dcAwsCredentialsProviderTraffic()) << "Failed to parse dynamic credentials reply data" << data << ":" << error.errorString(); + return; + } + + QVariantMap response = jsonDoc.toVariant().toMap(); + + m_accessKey = response.value("AccessKeyId").toString(); + m_secretAccessKey = response.value("SecretAccessKey").toString(); + m_sessionToken = response.value("Token").toString(); + + qCDebug(dcAwsCredentialsProviderTraffic()) << "Dynamic credentials updated:" << response; + + QDateTime expirationTime = QDateTime::fromString(response.value("Expiration").toString(), "yyyy-MM-ddThh:mm:ssZ"); + QDateTime lastUpdateTime = QDateTime::fromString(response.value("LastUpdated").toString(), "yyyy-MM-ddThh:mm:ssZ"); + qCDebug(dcAwsCredentialsProviderTraffic()) << "Exipration time" << expirationTime.toString("dd.MM.yyyy hh:mm:ss"); + qCDebug(dcAwsCredentialsProviderTraffic()) << "Last update time" << lastUpdateTime.toString("dd.MM.yyyy hh:mm:ss"); +} + +void AwsCredentialProvider::enable() +{ + if (!m_enabled) { + clear(); + m_enabled = true; + } + + qCDebug(dcAwsCredentialsProvider()) << "Enable AWS dynamic credentials provider"; + m_timer->start(); + refreshCredentials(); +} + +void AwsCredentialProvider::disable() +{ + qCDebug(dcAwsCredentialsProvider()) << "Disable AWS dynamic credentials provider"; + m_enabled = false; + m_timer->stop(); + + clear(); +} + +} diff --git a/libnymea-remoteproxy/authentication/aws/awscredentialprovider.h b/libnymea-remoteproxy/authentication/aws/awscredentialprovider.h new file mode 100644 index 0000000..0c6b518 --- /dev/null +++ b/libnymea-remoteproxy/authentication/aws/awscredentialprovider.h @@ -0,0 +1,82 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2018 Simon Stürz * + * * + * This file is part of nymea-remoteproxy. * + * * + * This program 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, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef AWSCREDENTIALPROVIDER_H +#define AWSCREDENTIALPROVIDER_H + +#include +#include +#include +#include +#include +#include + +namespace remoteproxy { + +class AwsCredentialProvider : public QObject +{ + Q_OBJECT +public: + explicit AwsCredentialProvider(QNetworkAccessManager *networkManager, const QUrl &awsCredentialsUrl, QObject *parent = nullptr); + + QString accessKey() const; + QString secretAccessKey() const; + QString sessionToken() const; + + bool isValid() const; + bool enabled() const; + +private: + QNetworkAccessManager *m_networkManager = nullptr; + QTimer *m_timer = nullptr; + + QElapsedTimer m_requestTimer; + + bool m_enabled = false; + + QUrl m_requestUrl; + + QString m_accessKey; + QString m_secretAccessKey; + QString m_sessionToken; + + QDateTime m_expirationTime; + QDateTime m_lastUpdateTime; + + void refreshCredentials(); + void clear(); + +private slots: + void onTimeout(); + void onReplyFinished(); + +signals: + void credentialsChanged(); + +public slots: + void enable(); + void disable(); + +}; + +} + +#endif // AWSCREDENTIALPROVIDER_H diff --git a/libnymea-remoteproxy/authentication/sigv4utils.cpp b/libnymea-remoteproxy/authentication/aws/sigv4utils.cpp similarity index 71% rename from libnymea-remoteproxy/authentication/sigv4utils.cpp rename to libnymea-remoteproxy/authentication/aws/sigv4utils.cpp index 539a3fe..7184016 100644 --- a/libnymea-remoteproxy/authentication/sigv4utils.cpp +++ b/libnymea-remoteproxy/authentication/aws/sigv4utils.cpp @@ -1,5 +1,26 @@ -#include "sigv4utils.h" +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2018 Simon Stürz * + * Copyright (C) 2018 Michael Zanetti * + * * + * This file is part of nymea-remoteproxy. * + * * + * This program 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, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#include "sigv4utils.h" #include #include @@ -8,34 +29,37 @@ #include #include -namespace remoteproxy { +#include "loggingcategories.h" +namespace remoteproxy { SigV4Utils::SigV4Utils() { } -void SigV4Utils::signRequest(QNetworkAccessManager::Operation operation, QNetworkRequest &request, const QString ®ion, const QString &service, const QByteArray &accessKeyId, const QByteArray &secretAccessKey, const QByteArray &sessionToken, const QByteArray &payload) +void SigV4Utils::signRequest(QNetworkAccessManager::Operation operation, QNetworkRequest &request, const QString ®ion, const QString &service, const QString &invocationType, const QByteArray &accessKeyId, const QByteArray &secretAccessKey, const QByteArray &sessionToken, const QByteArray &payload) { QByteArray dateTime; - if (request.rawHeaderList().contains("X-Amz-Date")) { - dateTime = request.rawHeader("X-AMZ-Date"); + if (request.rawHeaderList().contains("x-amz-date")) { + dateTime = request.rawHeader("x-amz-date"); } else { dateTime = SigV4Utils::getCurrentDateTime(); - request.setRawHeader("X-Amz-Date", dateTime); + request.setRawHeader("x-amz-date", dateTime); } + request.setRawHeader("x-amz-invocation-type", invocationType.toUtf8()); + if (!sessionToken.isEmpty()) { request.setRawHeader("x-amz-security-token", sessionToken); } QByteArray canonicalRequest = SigV4Utils::getCanonicalRequest(operation, request, payload); -// qDebug() << "canonical request:" << qUtf8Printable(canonicalRequest); + qCDebug(dcAuthenticationProcess()) << "canonical request:" << endl << qUtf8Printable(canonicalRequest); QByteArray stringToSign = SigV4Utils::getStringToSign(canonicalRequest, dateTime, region.toUtf8(), service.toUtf8()); -// qDebug() << "string to sign:" << stringToSign; + qCDebug(dcAuthenticationProcess()) << "string to sign:" << endl << qUtf8Printable(stringToSign); QByteArray signature = SigV4Utils::getSignature(stringToSign, secretAccessKey, dateTime, region, service); -// qDebug() << "signature:" << signature; + qCDebug(dcAuthenticationProcess()) << "signature:" << signature; QByteArray authorizeHeader = SigV4Utils::getAuthorizationHeader(accessKeyId, dateTime, region, service, request, signature); request.setRawHeader("Authorization", authorizeHeader); @@ -80,7 +104,7 @@ QByteArray SigV4Utils::getSignatureKey(const QByteArray &key, const QByteArray & return QMessageAuthenticationCode::hash("aws4_request", QMessageAuthenticationCode::hash(service, QMessageAuthenticationCode::hash(region, - QMessageAuthenticationCode::hash(date, "AWS4"+key, + QMessageAuthenticationCode::hash(date, "AWS4" + key, hashAlgorithm), hashAlgorithm), hashAlgorithm), hashAlgorithm); } @@ -100,6 +124,7 @@ QByteArray SigV4Utils::getCanonicalRequest(QNetworkAccessManager::Operation oper Q_ASSERT_X(false, "Network operation not implemented", "SigV4Utils"); } QByteArray uri = request.url().path(QUrl::FullyEncoded).toUtf8(); + QUrlQuery query(request.url()); QList > queryItems = query.queryItems(); QStringList queryItemStrings; @@ -118,7 +143,7 @@ QByteArray SigV4Utils::getCanonicalRequest(QNetworkAccessManager::Operation oper QByteArray payloadHash = QCryptographicHash::hash(payload, QCryptographicHash::Sha256).toHex(); - canonicalRequest = method + '\n' + uri + '\n' + canonicalQueryString + '\n' + canonicalHeaders + '\n' + request.rawHeaderList().join(';').toLower() + '\n' + payloadHash; + canonicalRequest = method + '\n' + uri + '\n' + canonicalQueryString + '\n' + canonicalHeaders + '\n' + request.rawHeaderList().join(';').toLower() + '\n' + payloadHash.toLower(); return canonicalRequest; } @@ -133,7 +158,6 @@ QByteArray SigV4Utils::getStringToSign(const QByteArray &canonicalRequest, const { QByteArray algorithm = "AWS4-HMAC-SHA256"; QByteArray credentialScope = getCredentialScope(algorithm, dateTime, region, service); - QByteArray stringToSign = algorithm + '\n' + dateTime + '\n' + credentialScope + '\n' + QCryptographicHash::hash(canonicalRequest, QCryptographicHash::Sha256).toHex(); return stringToSign; } diff --git a/libnymea-remoteproxy/authentication/aws/sigv4utils.h b/libnymea-remoteproxy/authentication/aws/sigv4utils.h new file mode 100644 index 0000000..60a6810 --- /dev/null +++ b/libnymea-remoteproxy/authentication/aws/sigv4utils.h @@ -0,0 +1,55 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2018 Simon Stürz * + * Copyright (C) 2018 Michael Zanetti * + * * + * This file is part of nymea-remoteproxy. * + * * + * This program 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, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef SIGV4UTILS_H +#define SIGV4UTILS_H + +#include +#include +#include + +namespace remoteproxy { + +class SigV4Utils +{ +public: + SigV4Utils(); + + // Signes a request by adding the "X-AMZ-Date" (if not present) and "X-AMZ-Signature" headers + static void signRequest(QNetworkAccessManager::Operation operation, QNetworkRequest &request, const QString ®ion, const QString &service, const QString &invocationType, const QByteArray &accessKeyId, const QByteArray &secretAccessKey, const QByteArray &sessionToken = QByteArray(), const QByteArray &payload = QByteArray()); + + static QByteArray getCurrentDateTime(); + + static QByteArray getCanonicalQueryString(const QNetworkRequest &request, const QByteArray &accessKeyId, const QByteArray &secretAccessKey, const QByteArray &sessionToken, const QByteArray ®ion, const QByteArray &service, const QByteArray &payload); + static QByteArray getCanonicalRequest(QNetworkAccessManager::Operation operation, const QNetworkRequest &request, const QByteArray &payload); + static QByteArray getCanonicalHeaders(const QNetworkRequest &request); + static QByteArray getCredentialScope(const QByteArray &algorithm, const QByteArray &dateTime, const QByteArray ®ion, const QByteArray &service); + static QByteArray getStringToSign(const QByteArray &canonicalRequest, const QByteArray &dateTime, const QByteArray ®ion, const QByteArray &service); + static QByteArray getSignatureKey(const QByteArray &key, const QByteArray &date, const QByteArray ®ion, const QByteArray &service); + static QByteArray getSignature(const QByteArray &stringToSign, const QByteArray &secretAccessKey, const QByteArray &dateTime, const QString ®ion, const QString &service); + static QByteArray getAuthorizationHeader(const QByteArray &accessKeyId, const QByteArray &dateTime, const QString ®ion, const QString &service, const QNetworkRequest &request, const QByteArray &signature); + +}; + +} + +#endif // SIGV4UTILS_H diff --git a/libnymea-remoteproxy/authentication/userinformation.cpp b/libnymea-remoteproxy/authentication/aws/userinformation.cpp similarity index 100% rename from libnymea-remoteproxy/authentication/userinformation.cpp rename to libnymea-remoteproxy/authentication/aws/userinformation.cpp diff --git a/libnymea-remoteproxy/authentication/userinformation.h b/libnymea-remoteproxy/authentication/aws/userinformation.h similarity index 100% rename from libnymea-remoteproxy/authentication/userinformation.h rename to libnymea-remoteproxy/authentication/aws/userinformation.h diff --git a/libnymea-remoteproxy/authentication/dummyauthenticator.cpp b/libnymea-remoteproxy/authentication/dummy/dummyauthenticator.cpp similarity index 100% rename from libnymea-remoteproxy/authentication/dummyauthenticator.cpp rename to libnymea-remoteproxy/authentication/dummy/dummyauthenticator.cpp diff --git a/libnymea-remoteproxy/authentication/dummyauthenticator.h b/libnymea-remoteproxy/authentication/dummy/dummyauthenticator.h similarity index 98% rename from libnymea-remoteproxy/authentication/dummyauthenticator.h rename to libnymea-remoteproxy/authentication/dummy/dummyauthenticator.h index 74e4b83..aad28b4 100644 --- a/libnymea-remoteproxy/authentication/dummyauthenticator.h +++ b/libnymea-remoteproxy/authentication/dummy/dummyauthenticator.h @@ -25,7 +25,7 @@ #include #include "proxyclient.h" -#include "authenticator.h" +#include "authentication/authenticator.h" namespace remoteproxy { diff --git a/libnymea-remoteproxy/authentication/sigv4utils.h b/libnymea-remoteproxy/authentication/sigv4utils.h deleted file mode 100644 index 1e46063..0000000 --- a/libnymea-remoteproxy/authentication/sigv4utils.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef SIGV4UTILS_H -#define SIGV4UTILS_H - -#include -#include -#include - -namespace remoteproxy { - -class SigV4Utils -{ -public: - SigV4Utils(); - - // Signes a request by adding the "X-AMZ-Date" (if not present) and "X-AMZ-Signature" headers - static void signRequest(QNetworkAccessManager::Operation operation, QNetworkRequest &request, const QString ®ion, const QString &service, const QByteArray &accessKeyId, const QByteArray &secretAccessKey, const QByteArray &sessionToken = QByteArray(), const QByteArray &payload = QByteArray()); - - static QByteArray getCurrentDateTime(); - - static QByteArray getCanonicalQueryString(const QNetworkRequest &request, const QByteArray &accessKeyId, const QByteArray &secretAccessKey, const QByteArray &sessionToken, const QByteArray ®ion, const QByteArray &service, const QByteArray &payload); - static QByteArray getCanonicalRequest(QNetworkAccessManager::Operation operation, const QNetworkRequest &request, const QByteArray &payload); - static QByteArray getCanonicalHeaders(const QNetworkRequest &request); - static QByteArray getCredentialScope(const QByteArray &algorithm, const QByteArray &dateTime, const QByteArray ®ion, const QByteArray &service); - static QByteArray getStringToSign(const QByteArray &canonicalRequest, const QByteArray &dateTime, const QByteArray ®ion, const QByteArray &service); - static QByteArray getSignatureKey(const QByteArray &key, const QByteArray &date, const QByteArray ®ion, const QByteArray &service); - static QByteArray getSignature(const QByteArray &stringToSign, const QByteArray &secretAccessKey, const QByteArray &dateTime, const QString ®ion, const QString &service); - static QByteArray getAuthorizationHeader(const QByteArray &accessKeyId, const QByteArray &dateTime, const QString ®ion, const QString &service, const QNetworkRequest &request, const QByteArray &signature); - -}; - -} - -#endif // SIGV4UTILS_H diff --git a/libnymea-remoteproxy/jsonrpc/authenticationhandler.cpp b/libnymea-remoteproxy/jsonrpc/authenticationhandler.cpp index 1d53af3..3fc1d85 100644 --- a/libnymea-remoteproxy/jsonrpc/authenticationhandler.cpp +++ b/libnymea-remoteproxy/jsonrpc/authenticationhandler.cpp @@ -78,8 +78,9 @@ JsonReply *AuthenticationHandler::Authenticate(const QVariantMap ¶ms, ProxyC void AuthenticationHandler::onAuthenticationFinished() { AuthenticationReply *authenticationReply = static_cast(sender()); + authenticationReply->deleteLater(); - qCDebug(dcJsonRpc()) << "Authentication respons ready for" << authenticationReply->proxyClient() << authenticationReply->error(); + qCDebug(dcJsonRpc()) << "Authentication response ready for" << authenticationReply->proxyClient() << authenticationReply->error(); JsonReply *jsonReply = m_runningAuthentications.take(authenticationReply); if (authenticationReply->error() != Authenticator::AuthenticationErrorNoError) { @@ -92,7 +93,6 @@ void AuthenticationHandler::onAuthenticationFinished() // Set client authenticated authenticationReply->proxyClient()->setAuthenticated(authenticationReply->error() == Authenticator::AuthenticationErrorNoError); - authenticationReply->deleteLater(); jsonReply->setData(errorToReply(authenticationReply->error())); jsonReply->finished(); diff --git a/libnymea-remoteproxy/jsonrpc/jsonhandler.cpp b/libnymea-remoteproxy/jsonrpc/jsonhandler.cpp index 14beada..0643b0e 100644 --- a/libnymea-remoteproxy/jsonrpc/jsonhandler.cpp +++ b/libnymea-remoteproxy/jsonrpc/jsonhandler.cpp @@ -136,9 +136,9 @@ QVariantMap JsonHandler::errorToReply(Authenticator::AuthenticationError error) return returns; } -JsonReply *JsonHandler::createReply(const QVariantMap &data) const +JsonReply *JsonHandler::createReply(const QString &method, const QVariantMap &data) const { - return JsonReply::createReply(const_cast(this), data); + return JsonReply::createReply(const_cast(this), method, data); } JsonReply *JsonHandler::createAsyncReply(const QString &method) const diff --git a/libnymea-remoteproxy/jsonrpc/jsonhandler.h b/libnymea-remoteproxy/jsonrpc/jsonhandler.h index 327cd49..3daa29e 100644 --- a/libnymea-remoteproxy/jsonrpc/jsonhandler.h +++ b/libnymea-remoteproxy/jsonrpc/jsonhandler.h @@ -63,7 +63,7 @@ protected: QVariantMap errorToReply(Authenticator::AuthenticationError error) const; - JsonReply *createReply(const QVariantMap &data) const; + JsonReply *createReply(const QString &method, const QVariantMap &data) const; JsonReply *createAsyncReply(const QString &method) const; }; diff --git a/libnymea-remoteproxy/jsonrpc/jsonreply.cpp b/libnymea-remoteproxy/jsonrpc/jsonreply.cpp index 4b1222d..379afe6 100644 --- a/libnymea-remoteproxy/jsonrpc/jsonreply.cpp +++ b/libnymea-remoteproxy/jsonrpc/jsonreply.cpp @@ -24,9 +24,9 @@ namespace remoteproxy { -JsonReply *JsonReply::createReply(JsonHandler *handler, const QVariantMap &data) +JsonReply *JsonReply::createReply(JsonHandler *handler, const QString &method, const QVariantMap &data) { - return new JsonReply(TypeSync, handler, QString(), data); + return new JsonReply(TypeSync, handler, method, data); } JsonReply *JsonReply::createAsyncReply(JsonHandler *handler, const QString &method) diff --git a/libnymea-remoteproxy/jsonrpc/jsonreply.h b/libnymea-remoteproxy/jsonrpc/jsonreply.h index 853d596..615d173 100644 --- a/libnymea-remoteproxy/jsonrpc/jsonreply.h +++ b/libnymea-remoteproxy/jsonrpc/jsonreply.h @@ -41,7 +41,7 @@ public: friend class JsonRpcServer; - static JsonReply *createReply(JsonHandler *handler, const QVariantMap &data); + static JsonReply *createReply(JsonHandler *handler, const QString &method, const QVariantMap &data); static JsonReply *createAsyncReply(JsonHandler *handler, const QString &method); Type type() const; @@ -50,7 +50,6 @@ public: void setData(const QVariantMap &data); JsonHandler *handler() const; - QString method() const; QUuid clientId() const; diff --git a/libnymea-remoteproxy/jsonrpcserver.cpp b/libnymea-remoteproxy/jsonrpcserver.cpp index 2d8d33f..eccca76 100644 --- a/libnymea-remoteproxy/jsonrpcserver.cpp +++ b/libnymea-remoteproxy/jsonrpcserver.cpp @@ -91,7 +91,7 @@ JsonReply *JsonRpcServer::Hello(const QVariantMap ¶ms, ProxyClient *proxyCli data.insert("version", SERVER_VERSION_STRING); data.insert("apiVersion", API_VERSION_STRING); - return createReply(data); + return createReply("Hello", data); } JsonReply *JsonRpcServer::Introspect(const QVariantMap ¶ms, ProxyClient *proxyClient) const @@ -118,7 +118,7 @@ JsonReply *JsonRpcServer::Introspect(const QVariantMap ¶ms, ProxyClient *pro data.insert("notifications", signalsMap); - return createReply(data); + return createReply("Introspect", data); } void JsonRpcServer::sendResponse(ProxyClient *client, int commandId, const QVariantMap ¶ms) @@ -142,7 +142,7 @@ void JsonRpcServer::sendErrorResponse(ProxyClient *client, int commandId, const QByteArray data = QJsonDocument::fromVariant(errorResponse).toJson(QJsonDocument::Compact); qCDebug(dcJsonRpcTraffic()) << "Sending data:" << data; - client->interface()->sendData(client->clientId(), data); + client->sendData(data); } QString JsonRpcServer::formatAssertion(const QString &targetNamespace, const QString &method, JsonHandler *handler, const QVariantMap &data) const @@ -190,11 +190,19 @@ void JsonRpcServer::asyncReplyFinished() Q_ASSERT_X(reply->handler()->validateReturns(reply->method(), reply->data()).first ,"validating return value", formatAssertion(reply->handler()->name(), reply->method(), reply->handler(), reply->data()).toLatin1().data()); + + QPair returnValidation = reply->handler()->validateReturns(reply->method(), reply->data()); + if (!returnValidation.first) { + qCWarning(dcJsonRpc()) << "Return value validation failed. This should never happen. Please check the source code."; + } + sendResponse(proxyClient, reply->commandId(), reply->data()); + if (!reply->success()) { // Disconnect this client since the request was not successfully proxyClient->interface()->killClientConnection(proxyClient->clientId(), "API call was not successfully."); } + } else { sendErrorResponse(proxyClient, reply->commandId(), "Command timed out"); // Disconnect this client since he requested something that created a timeout @@ -289,11 +297,18 @@ void JsonRpcServer::processData(ProxyClient *proxyClient, const QByteArray &data m_asyncReplies.insert(reply, proxyClient); reply->setClientId(proxyClient->clientId()); reply->setCommandId(commandId); + connect(reply, &JsonReply::finished, this, &JsonRpcServer::asyncReplyFinished); reply->startWait(); } else { Q_ASSERT_X((targetNamespace == "RemoteProxy" && method == "Introspect") || handler->validateReturns(method, reply->data()).first ,"validating return value", formatAssertion(targetNamespace, method, handler, reply->data()).toLatin1().data()); + +// QPair returnValidation = reply->handler()->validateReturns(reply->method(), reply->data()); +// if (!returnValidation.first) { +// qCWarning(dcJsonRpc()) << "Return value validation failed of sync reply. This should never happen. Please check the source code."; +// } + reply->setClientId(proxyClient->clientId()); reply->setCommandId(commandId); sendResponse(proxyClient, commandId, reply->data()); @@ -310,7 +325,7 @@ void JsonRpcServer::sendNotification(const QString &nameSpace, const QString &me QByteArray data = QJsonDocument::fromVariant(notification).toJson(QJsonDocument::Compact); qCDebug(dcJsonRpcTraffic()) << "Sending notification:" << data; - proxyClient->interface()->sendData(proxyClient->clientId(), data); + proxyClient->sendData(data); } } diff --git a/libnymea-remoteproxy/libnymea-remoteproxy.pro b/libnymea-remoteproxy/libnymea-remoteproxy.pro index 76c18ad..ccb3913 100644 --- a/libnymea-remoteproxy/libnymea-remoteproxy.pro +++ b/libnymea-remoteproxy/libnymea-remoteproxy.pro @@ -19,12 +19,13 @@ HEADERS += \ jsonrpc/jsontypes.h \ jsonrpc/authenticationhandler.h \ authentication/authenticator.h \ - authentication/awsauthenticator.h \ authentication/authenticationreply.h \ - authentication/userinformation.h \ - authentication/authenticationprocess.h \ - authentication/dummyauthenticator.h \ - authentication/sigv4utils.h + authentication/dummy/dummyauthenticator.h \ + authentication/aws/awsauthenticator.h \ + authentication/aws/userinformation.h \ + authentication/aws/authenticationprocess.h \ + authentication/aws/sigv4utils.h \ + authentication/aws/awscredentialprovider.h SOURCES += \ engine.cpp \ @@ -42,12 +43,13 @@ SOURCES += \ jsonrpc/jsontypes.cpp \ jsonrpc/authenticationhandler.cpp \ authentication/authenticator.cpp \ - authentication/awsauthenticator.cpp \ authentication/authenticationreply.cpp \ - authentication/userinformation.cpp \ - authentication/authenticationprocess.cpp \ - authentication/dummyauthenticator.cpp \ - authentication/sigv4utils.cpp + authentication/dummy/dummyauthenticator.cpp \ + authentication/aws/awsauthenticator.cpp \ + authentication/aws/userinformation.cpp \ + authentication/aws/authenticationprocess.cpp \ + authentication/aws/sigv4utils.cpp \ + authentication/aws/awscredentialprovider.cpp # install header file with relative subdirectory diff --git a/libnymea-remoteproxy/loggingcategories.cpp b/libnymea-remoteproxy/loggingcategories.cpp index 6a72fd1..ab5ce1e 100644 --- a/libnymea-remoteproxy/loggingcategories.cpp +++ b/libnymea-remoteproxy/loggingcategories.cpp @@ -32,4 +32,5 @@ Q_LOGGING_CATEGORY(dcAuthenticationProcess, "AuthenticationProcess") Q_LOGGING_CATEGORY(dcProxyServer, "ProxyServer") Q_LOGGING_CATEGORY(dcProxyServerTraffic, "ProxyServerTraffic") Q_LOGGING_CATEGORY(dcMonitorServer, "MonitorServer") - +Q_LOGGING_CATEGORY(dcAwsCredentialsProvider, "AwsCredentialsProvider") +Q_LOGGING_CATEGORY(dcAwsCredentialsProviderTraffic, "AwsCredentialsProviderTraffic") diff --git a/libnymea-remoteproxy/loggingcategories.h b/libnymea-remoteproxy/loggingcategories.h index cc7d49b..4149807 100644 --- a/libnymea-remoteproxy/loggingcategories.h +++ b/libnymea-remoteproxy/loggingcategories.h @@ -36,5 +36,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcAuthenticationProcess) Q_DECLARE_LOGGING_CATEGORY(dcProxyServer) Q_DECLARE_LOGGING_CATEGORY(dcProxyServerTraffic) Q_DECLARE_LOGGING_CATEGORY(dcMonitorServer) +Q_DECLARE_LOGGING_CATEGORY(dcAwsCredentialsProvider) +Q_DECLARE_LOGGING_CATEGORY(dcAwsCredentialsProviderTraffic) #endif // LOGGINGCATEGORIES_H diff --git a/libnymea-remoteproxy/proxyconfiguration.cpp b/libnymea-remoteproxy/proxyconfiguration.cpp index 1286178..dbc300f 100644 --- a/libnymea-remoteproxy/proxyconfiguration.cpp +++ b/libnymea-remoteproxy/proxyconfiguration.cpp @@ -56,7 +56,7 @@ bool ProxyConfiguration::loadConfiguration(const QString &fileName) setAuthenticationTimeout(settings.value("authenticationTimeout", 8000).toInt()); setInactiveTimeout(settings.value("inactiveTimeout", 8000).toInt()); setAloneTimeout(settings.value("aloneTimeout", 8000).toInt()); - + setAwsCredentialsUrl(QUrl(settings.value("awsCredentialsUrl", "http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-Remote-Connection-Proxy-Role").toString())); settings.endGroup(); settings.beginGroup("SSL"); @@ -205,6 +205,16 @@ void ProxyConfiguration::setAloneTimeout(int timeout) m_aloneTimeout = timeout; } +QUrl ProxyConfiguration::awsCredentialsUrl() const +{ + return m_awsCredentialsUrl; +} + +void ProxyConfiguration::setAwsCredentialsUrl(const QUrl &url) +{ + m_awsCredentialsUrl = url; +} + QString ProxyConfiguration::sslCertificateFileName() const { return m_sslCertificateFileName; @@ -292,6 +302,7 @@ QDebug operator<<(QDebug debug, ProxyConfiguration *configuration) debug.nospace() << " - Authentication timeout:" << configuration->authenticationTimeout() << " [ms]" << endl; debug.nospace() << " - Inactive timeout:" << configuration->inactiveTimeout() << " [ms]" << endl; debug.nospace() << " - Alone timeout:" << configuration->aloneTimeout() << " [ms]" << endl; + debug.nospace() << " - AWS credentials URL:" << configuration->awsCredentialsUrl().toString() << endl; debug.nospace() << "SSL configuration" << endl; debug.nospace() << " - Certificate:" << configuration->sslCertificateFileName() << endl; debug.nospace() << " - Certificate key:" << configuration->sslCertificateKeyFileName() << endl; diff --git a/libnymea-remoteproxy/proxyconfiguration.h b/libnymea-remoteproxy/proxyconfiguration.h index 4b7b9a0..c1a8225 100644 --- a/libnymea-remoteproxy/proxyconfiguration.h +++ b/libnymea-remoteproxy/proxyconfiguration.h @@ -22,6 +22,7 @@ #ifndef PROXYCONFIGURATION_H #define PROXYCONFIGURATION_H +#include #include #include #include @@ -64,6 +65,9 @@ public: int aloneTimeout() const; void setAloneTimeout(int timeout); + QUrl awsCredentialsUrl() const; + void setAwsCredentialsUrl(const QUrl &url); + // Ssl QString sslCertificateFileName() const; void setSslCertificateFileName(const QString &fileName); @@ -99,9 +103,11 @@ private: QString m_monitorSocketFileName; int m_jsonRpcTimeout = 10000; - int m_authenticationTimeout = 5000; - int m_inactiveTimeout = 5000; - int m_aloneTimeout = 5000; + int m_authenticationTimeout = 8000; + int m_inactiveTimeout = 8000; + int m_aloneTimeout = 8000; + + QUrl m_awsCredentialsUrl; // Ssl QString m_sslCertificateFileName = "/etc/ssl/certs/ssl-cert-snakeoil.pem"; diff --git a/libnymea-remoteproxyclient/proxyjsonrpcclient.cpp b/libnymea-remoteproxyclient/proxyjsonrpcclient.cpp index 3f3e0fc..dacacaf 100644 --- a/libnymea-remoteproxyclient/proxyjsonrpcclient.cpp +++ b/libnymea-remoteproxyclient/proxyjsonrpcclient.cpp @@ -61,14 +61,14 @@ JsonReply *JsonRpcClient::callAuthenticate(const QUuid &clientUuid, const QStrin void JsonRpcClient::sendRequest(const QVariantMap &request) { - QByteArray data = QJsonDocument::fromVariant(request).toJson(QJsonDocument::Compact) + '\n'; - qCDebug(dcRemoteProxyClientJsonRpcTraffic()) << "Sending" << qUtf8Printable(data); + QByteArray data = QJsonDocument::fromVariant(request).toJson(QJsonDocument::Compact); + qCDebug(dcRemoteProxyClientJsonRpcTraffic()) << "Sending" << data; m_connection->sendData(data); } void JsonRpcClient::processData(const QByteArray &data) { - qCDebug(dcRemoteProxyClientJsonRpcTraffic()) << "Received data:" << qUtf8Printable(data); + qCDebug(dcRemoteProxyClientJsonRpcTraffic()) << "Received data:" << data; QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); diff --git a/monitor/terminalwindow.cpp b/monitor/terminalwindow.cpp index c7e1601..1ffa011 100644 --- a/monitor/terminalwindow.cpp +++ b/monitor/terminalwindow.cpp @@ -57,9 +57,13 @@ TerminalWindow::TerminalWindow(QObject *parent) : m_headerWindow = newwin(m_headerHeight, m_terminalSizeX, 0, 0); m_contentWindow = newwin(m_terminalSizeY - m_headerHeight, m_terminalSizeX, m_headerHeight, 0); - // Draw borders + nodelay(m_headerWindow, TRUE); + nodelay(m_contentWindow, TRUE); + werase(m_headerWindow); werase(m_contentWindow); + + // Draw borders drawWindowBorder(m_headerWindow); drawWindowBorder(m_contentWindow); @@ -106,6 +110,8 @@ void TerminalWindow::resizeWindow() int terminalSizeX; int terminalSizeY; getmaxyx(stdscr, terminalSizeY, terminalSizeX); + + // Resize the window if size has changed if (m_terminalSizeX != terminalSizeX || m_terminalSizeY != terminalSizeY) { m_terminalSizeX = terminalSizeX; m_terminalSizeY = terminalSizeY; @@ -155,12 +161,10 @@ void TerminalWindow::paintHeader() headerString.append(" "); - wclear(m_headerWindow); wattron(m_headerWindow, A_BOLD | COLOR_PAIR(1)); mvwprintw(m_headerWindow, 1, 2, convertString(headerString)); wattroff(m_headerWindow, A_BOLD | COLOR_PAIR(1)); drawWindowBorder(m_headerWindow); - wrefresh(m_headerWindow); } void TerminalWindow::paintContentClients() @@ -169,7 +173,6 @@ void TerminalWindow::paintContentClients() return; int i = 1; - wclear(m_contentWindow); foreach (const QVariant &clientVariant, m_clientHash.values()) { QVariantMap clientMap = clientVariant.toMap(); @@ -191,14 +194,12 @@ void TerminalWindow::paintContentClients() // Draw borders drawWindowBorder(m_contentWindow); - wrefresh(m_contentWindow); } void TerminalWindow::paintContentTunnels() { int i = 1; - wclear(m_contentWindow); foreach (const QVariant &tunnelVaiant, m_dataMap.value("proxyStatistic").toMap().value("tunnels").toList()) { QVariantMap tunnelMap = tunnelVaiant.toMap(); QVariantMap clientOne = m_clientHash.value(tunnelMap.value("clientOne").toString()); @@ -223,12 +224,15 @@ void TerminalWindow::paintContentTunnels() // Draw borders drawWindowBorder(m_contentWindow); - wrefresh(m_contentWindow); } void TerminalWindow::eventLoop() { - resizeWindow(); + + werase(m_headerWindow); + werase(m_contentWindow); + + resizeWindow(); int keyInteger = getch(); switch (keyInteger) { @@ -264,11 +268,13 @@ void TerminalWindow::eventLoop() break; } - refresh(); + wrefresh(m_headerWindow); + wrefresh(m_contentWindow); + //refresh(); // Reinvoke the method for the next event loop run //QMetaObject::invokeMethod(this, "eventLoop", Qt::QueuedConnection); - QTimer::singleShot(50, this, &TerminalWindow::eventLoop); + QTimer::singleShot(100, this, &TerminalWindow::eventLoop); } void TerminalWindow::refreshWindow(const QVariantMap &dataMap) diff --git a/nymea-remoteproxy.conf b/nymea-remoteproxy.conf index 463fcaa..2cc38f3 100644 --- a/nymea-remoteproxy.conf +++ b/nymea-remoteproxy.conf @@ -7,6 +7,7 @@ jsonRpcTimeout=10000 authenticationTimeout=8000 inactiveTimeout=8000 aloneTimeout=8000 +awsCredentialsUrl=http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-Remote-Connection-Proxy-Role [SSL] certificate=/etc/ssl/certs/ssl-cert-snakeoil.pem diff --git a/nymea-remoteproxy.pri b/nymea-remoteproxy.pri index 5cc0877..92f544e 100644 --- a/nymea-remoteproxy.pri +++ b/nymea-remoteproxy.pri @@ -5,7 +5,7 @@ QT -= gui SERVER_NAME=nymea-remoteproxy API_VERSION_MAJOR=0 API_VERSION_MINOR=2 -SERVER_VERSION=0.1.2 +SERVER_VERSION=0.1.3 DEFINES += SERVER_NAME_STRING=\\\"$${SERVER_NAME}\\\" \ SERVER_VERSION_STRING=\\\"$${SERVER_VERSION}\\\" \ diff --git a/server/main.cpp b/server/main.cpp index 3bc31c9..7243623 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -42,8 +42,8 @@ #include "loggingcategories.h" #include "proxyconfiguration.h" #include "remoteproxyserverapplication.h" -#include "authentication/awsauthenticator.h" -#include "authentication/dummyauthenticator.h" +#include "authentication/aws/awsauthenticator.h" +#include "authentication/dummy/dummyauthenticator.h" using namespace remoteproxy; @@ -120,12 +120,14 @@ int main(int argc, char *argv[]) s_loggingFilters.insert("Authentication", true); s_loggingFilters.insert("ProxyServer", true); s_loggingFilters.insert("MonitorServer", true); + s_loggingFilters.insert("AwsCredentialsProvider", true); // Only with verbose enabled s_loggingFilters.insert("JsonRpcTraffic", false); s_loggingFilters.insert("ProxyServerTraffic", false); s_loggingFilters.insert("AuthenticationProcess", false); s_loggingFilters.insert("WebSocketServerTraffic", false); + s_loggingFilters.insert("AwsCredentialsProviderTraffic", false); QString configFile = "/etc/nymea/nymea-remoteproxy.conf"; @@ -183,6 +185,7 @@ int main(int argc, char *argv[]) s_loggingFilters["ProxyServerTraffic"] = true; s_loggingFilters["AuthenticationProcess"] = true; s_loggingFilters["WebSocketServerTraffic"] = true; + s_loggingFilters["AwsCredentialsProviderTraffic"] = true; } QLoggingCategory::installFilter(loggingCategoryFilter); @@ -232,14 +235,14 @@ int main(int argc, char *argv[]) if (s_loggingEnabled) qCDebug(dcApplication()) << "Logging enabled. Writing logs to" << s_logFile.fileName(); - qCDebug(dcApplication()) << "Using ssl version:" << QSslSocket::sslLibraryVersionString(); + qCDebug(dcApplication()) << "Using SSL version:" << QSslSocket::sslLibraryVersionString(); Authenticator *authenticator = nullptr; if (parser.isSet(mockAuthenticatorOption)) { authenticator = qobject_cast(new DummyAuthenticator(nullptr)); } else { // Create default authenticator - authenticator = qobject_cast(new AwsAuthenticator(nullptr)); + authenticator = qobject_cast(new AwsAuthenticator(configuration->awsCredentialsUrl(), nullptr)); } // Configure and start the engines diff --git a/tests/testbase/basetest.cpp b/tests/testbase/basetest.cpp index d4d250a..e73bb15 100644 --- a/tests/testbase/basetest.cpp +++ b/tests/testbase/basetest.cpp @@ -34,27 +34,6 @@ BaseTest::BaseTest(QObject *parent) : QObject(parent) { - m_configuration = new ProxyConfiguration(this); - m_configuration->loadConfiguration(":/test-configuration.conf"); - - m_mockAuthenticator = new MockAuthenticator(this); - m_dummyAuthenticator = new DummyAuthenticator(this); - m_awsAuthenticator = new AwsAuthenticator(this); - - m_authenticator = qobject_cast(m_mockAuthenticator); - - m_testToken = "eyJraWQiOiJXdnFFT3prVVh5VDlINzFyRUpoNWdxRnkxNFhnR2l3SFAzVEIzUFQ1V3ZrPSIsImFsZyI6IlJT" - "MjU2In0.eyJzdWIiOiJmZTJmZDNlNC1hMGJhLTQ1OTUtOWRiZS00ZDkxYjRiMjFlMzUiLCJhdWQiOiI4cmpoZ" - "mRsZjlqZjFzdW9rMmpjcmx0ZDZ2IiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImV2ZW50X2lkIjoiN2Y5NTRiNm" - "ItOTYyZi0xMWU4LWI0ZjItMzU5NWRiZmRiODVmIiwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE1MzM" - "xOTkxMzgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5ldS13ZXN0LTEuYW1hem9uYXdzLmNvbVwvZXUt" - "d2VzdC0xXzZlWDZZam1YciIsImNvZ25pdG86dXNlcm5hbWUiOiIyYzE3YzUwZC0xZDFlLTRhM2UtYmFjOS0zZ" - "DI0YjQ1MTFiYWEiLCJleHAiOjE1MzMyMDI3MzgsImlhdCI6MTUzMzE5OTEzOCwiZW1haWwiOiJqZW5raW5zQG" - "d1aC5pbyJ9.hMMSvZMx7pMvV70PaUmTZOZgdez5WGX5yagRFPZojBm8jNWZND1lUmi0RFkybeD4HonDiKHxTF" - "_psyJoBVndgHbxYBBl3Np4gn0MxECWjvLxYzGxVBBkN24SqNUyAGkr0uFcZKkBecdtJlqNQnZN8Uk49twmODf" - "raRaRmGmKmRBAK1qDITpUgP6AWqH9xoJWaoDzt0kwJ3EtPxS7vL1PHqOaN8ggXA8Eq4iTCSfXU1HAXhIWJH9Y" - "pQbj58v1vktaAEATdmKmlzmcix-HJK9wWHRSuv3TsNa8DGxvcPOoeTu8Vql7krZ-y7Zu-s2WsgeP4VxyT80VE" - "T_xh6pMkOhE6g"; } @@ -142,6 +121,12 @@ QVariant BaseTest::invokeApiCall(const QString &method, const QVariantMap params socket->deleteLater(); for (int i = 0; i < dataSpy.count(); i++) { + // Make sure the response ends with '}\n' + if (!dataSpy.at(i).last().toByteArray().endsWith("}\n")) { + qWarning() << "JSON data does not end with \"}\n\""; + return QVariant(); + } + // Make sure the response it a valid JSON string QJsonParseError error; jsonDoc = QJsonDocument::fromJson(dataSpy.at(i).last().toByteArray(), &error); @@ -184,6 +169,12 @@ QVariant BaseTest::injectSocketData(const QByteArray &data) socket->deleteLater(); for (int i = 0; i < spy.count(); i++) { + // Make sure the response ends with '}\n' + if (!spy.at(i).last().toByteArray().endsWith("}\n")) { + qWarning() << "JSON data does not end with \"}\n\""; + return QVariant(); + } + // Make sure the response it a valid JSON string QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(spy.at(i).last().toByteArray(), &error); @@ -202,6 +193,28 @@ void BaseTest::initTestCase() qRegisterMetaType(); qRegisterMetaType(); + m_configuration = new ProxyConfiguration(this); + m_configuration->loadConfiguration(":/test-configuration.conf"); + + m_mockAuthenticator = new MockAuthenticator(this); + m_dummyAuthenticator = new DummyAuthenticator(this); + m_awsAuthenticator = new AwsAuthenticator(m_configuration->awsCredentialsUrl(), this); + + m_authenticator = qobject_cast(m_mockAuthenticator); + + m_testToken = "eyJraWQiOiJXdnFFT3prVVh5VDlINzFyRUpoNWdxRnkxNFhnR2l3SFAzVEIzUFQ1V3ZrPSIsImFsZyI6IlJT" + "MjU2In0.eyJzdWIiOiJmZTJmZDNlNC1hMGJhLTQ1OTUtOWRiZS00ZDkxYjRiMjFlMzUiLCJhdWQiOiI4cmpoZ" + "mRsZjlqZjFzdW9rMmpjcmx0ZDZ2IiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImV2ZW50X2lkIjoiN2Y5NTRiNm" + "ItOTYyZi0xMWU4LWI0ZjItMzU5NWRiZmRiODVmIiwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE1MzM" + "xOTkxMzgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5ldS13ZXN0LTEuYW1hem9uYXdzLmNvbVwvZXUt" + "d2VzdC0xXzZlWDZZam1YciIsImNvZ25pdG86dXNlcm5hbWUiOiIyYzE3YzUwZC0xZDFlLTRhM2UtYmFjOS0zZ" + "DI0YjQ1MTFiYWEiLCJleHAiOjE1MzMyMDI3MzgsImlhdCI6MTUzMzE5OTEzOCwiZW1haWwiOiJqZW5raW5zQG" + "d1aC5pbyJ9.hMMSvZMx7pMvV70PaUmTZOZgdez5WGX5yagRFPZojBm8jNWZND1lUmi0RFkybeD4HonDiKHxTF" + "_psyJoBVndgHbxYBBl3Np4gn0MxECWjvLxYzGxVBBkN24SqNUyAGkr0uFcZKkBecdtJlqNQnZN8Uk49twmODf" + "raRaRmGmKmRBAK1qDITpUgP6AWqH9xoJWaoDzt0kwJ3EtPxS7vL1PHqOaN8ggXA8Eq4iTCSfXU1HAXhIWJH9Y" + "pQbj58v1vktaAEATdmKmlzmcix-HJK9wWHRSuv3TsNa8DGxvcPOoeTu8Vql7krZ-y7Zu-s2WsgeP4VxyT80VE" + "T_xh6pMkOhE6g"; + qCDebug(dcApplication()) << "Init test case."; restartEngine(); } @@ -209,6 +222,13 @@ void BaseTest::initTestCase() void BaseTest::cleanupTestCase() { qCDebug(dcApplication()) << "Clean up test case."; + delete m_configuration; + delete m_mockAuthenticator; + delete m_dummyAuthenticator; + delete m_awsAuthenticator; + + m_authenticator = nullptr; + cleanUpEngine(); } diff --git a/tests/testbase/basetest.h b/tests/testbase/basetest.h index e2ff7ea..b0aa1ed 100644 --- a/tests/testbase/basetest.h +++ b/tests/testbase/basetest.h @@ -35,8 +35,8 @@ #include "mockauthenticator.h" #include "proxyconfiguration.h" #include "remoteproxyconnection.h" -#include "authentication/awsauthenticator.h" -#include "authentication/dummyauthenticator.h" +#include "authentication/aws/awsauthenticator.h" +#include "authentication/dummy/dummyauthenticator.h" using namespace remoteproxy; using namespace remoteproxyclient;