Add native lambda invoke code
This commit is contained in:
parent
c7dd9e72aa
commit
c5f031796b
8
debian/changelog
vendored
8
debian/changelog
vendored
@ -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 <simon.stuerz@guh.io> Mon, 27 Aug 2018 13:31:18 +0200
|
||||
|
||||
nymea-remoteproxy (0.1.2) bionic; urgency=medium
|
||||
|
||||
* Many bug fixes
|
||||
* Add more scurity mechanisms
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<void(QProcess::*)(int, QProcess::ExitStatus)>(&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': <botocore.config.Config object at 0x7f44560f3128>, '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<QNetworkReply *>(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<QNetworkReply *>(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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -27,8 +27,8 @@
|
||||
#include <QElapsedTimer>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
#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);
|
||||
|
||||
@ -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
|
||||
@ -25,9 +25,10 @@
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
#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<AuthenticationProcess *, AuthenticationReply *> m_runningProcesses;
|
||||
|
||||
private slots:
|
||||
@ -0,0 +1,148 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2018 Simon Stürz <simon.stuerz@guh.io> *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "loggingcategories.h"
|
||||
#include "awscredentialprovider.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonParseError>
|
||||
#include <QNetworkRequest>
|
||||
|
||||
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<QNetworkReply *>(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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2018 Simon Stürz <simon.stuerz@guh.io> *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef AWSCREDENTIALPROVIDER_H
|
||||
#define AWSCREDENTIALPROVIDER_H
|
||||
|
||||
#include <QUrl>
|
||||
#include <QTimer>
|
||||
#include <QObject>
|
||||
#include <QDateTime>
|
||||
#include <QElapsedTimer>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
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
|
||||
@ -1,5 +1,26 @@
|
||||
#include "sigv4utils.h"
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2018 Simon Stürz <simon.stuerz@guh.io> *
|
||||
* Copyright (C) 2018 Michael Zanetti <michael.zanetti@guh.io> *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "sigv4utils.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QCryptographicHash>
|
||||
@ -8,34 +29,37 @@
|
||||
#include <QUrlQuery>
|
||||
#include <QList>
|
||||
|
||||
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<QPair<QString, QString> > 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;
|
||||
}
|
||||
55
libnymea-remoteproxy/authentication/aws/sigv4utils.h
Normal file
55
libnymea-remoteproxy/authentication/aws/sigv4utils.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2018 Simon Stürz <simon.stuerz@guh.io> *
|
||||
* Copyright (C) 2018 Michael Zanetti <michael.zanetti@guh.io> *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef SIGV4UTILS_H
|
||||
#define SIGV4UTILS_H
|
||||
|
||||
#include <QString>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
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
|
||||
@ -25,7 +25,7 @@
|
||||
#include <QObject>
|
||||
|
||||
#include "proxyclient.h"
|
||||
#include "authenticator.h"
|
||||
#include "authentication/authenticator.h"
|
||||
|
||||
namespace remoteproxy {
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
#ifndef SIGV4UTILS_H
|
||||
#define SIGV4UTILS_H
|
||||
|
||||
#include <QString>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
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
|
||||
@ -78,8 +78,9 @@ JsonReply *AuthenticationHandler::Authenticate(const QVariantMap ¶ms, ProxyC
|
||||
void AuthenticationHandler::onAuthenticationFinished()
|
||||
{
|
||||
AuthenticationReply *authenticationReply = static_cast<AuthenticationReply *>(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();
|
||||
|
||||
@ -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<JsonHandler*>(this), data);
|
||||
return JsonReply::createReply(const_cast<JsonHandler*>(this), method, data);
|
||||
}
|
||||
|
||||
JsonReply *JsonHandler::createAsyncReply(const QString &method) const
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<bool, QString> 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<bool, QString> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#ifndef PROXYCONFIGURATION_H
|
||||
#define PROXYCONFIGURATION_H
|
||||
|
||||
#include <QUrl>
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
#include <QHostAddress>
|
||||
@ -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";
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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}\\\" \
|
||||
|
||||
@ -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<Authenticator *>(new DummyAuthenticator(nullptr));
|
||||
} else {
|
||||
// Create default authenticator
|
||||
authenticator = qobject_cast<Authenticator *>(new AwsAuthenticator(nullptr));
|
||||
authenticator = qobject_cast<Authenticator *>(new AwsAuthenticator(configuration->awsCredentialsUrl(), nullptr));
|
||||
}
|
||||
|
||||
// Configure and start the engines
|
||||
|
||||
@ -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<Authenticator *>(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<RemoteProxyConnection::State>();
|
||||
qRegisterMetaType<RemoteProxyConnection::ConnectionType>();
|
||||
|
||||
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<Authenticator *>(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();
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
Reference in New Issue
Block a user