151 lines
6.3 KiB
C++
151 lines
6.3 KiB
C++
#include "eetca.h"
|
|
|
|
#include <QFile>
|
|
#include <QProcess>
|
|
#include <QRegularExpression>
|
|
#include <QSslCertificate>
|
|
#include <QSslKey>
|
|
#include <QSslServer>
|
|
#include <QTemporaryDir>
|
|
#include <QtTest>
|
|
|
|
namespace
|
|
{
|
|
class MockCaServer : public QSslServer
|
|
{
|
|
public:
|
|
explicit MockCaServer(const QByteArray &pkcs12)
|
|
: m_pkcs12(pkcs12)
|
|
{
|
|
connect(this, &QSslServer::pendingConnectionAvailable, this, [this] {
|
|
QSslSocket *socket = qobject_cast<QSslSocket *>(nextPendingConnection());
|
|
if (socket == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
connect(socket, &QSslSocket::readyRead, this, [this, socket] {
|
|
const QByteArray request = socket->readAll();
|
|
const QByteArray firstLine = request.left(request.indexOf("\r\n"));
|
|
const QList<QByteArray> parts = firstLine.split(' ');
|
|
if (parts.size() < 2 || !request.contains("Authorization: Bearer "))
|
|
{
|
|
socket->disconnectFromHost();
|
|
return;
|
|
}
|
|
QByteArray body;
|
|
int status = 200;
|
|
if (parts.at(1) == "/api/request/renew")
|
|
{
|
|
body = "{\"reqId\":\"123e4567-e89b-42d3-a456-426614174000\"}";
|
|
status = 201;
|
|
}
|
|
else if (parts.at(1) == "/api/request/123e4567-e89b-42d3-a456-426614174000/status")
|
|
{
|
|
body = "{\"reqId\":\"123e4567-e89b-42d3-a456-426614174000\","
|
|
"\"state\":\"ISSUED\"}";
|
|
}
|
|
else if (parts.at(1) == "/api/request/not-finished")
|
|
{
|
|
body = "{\"count\":1,\"data\":[\"123e4567-e89b-42d3-a456-426614174000\"]}";
|
|
}
|
|
else if (parts.at(1) == "/api/request/123e4567-e89b-42d3-a456-426614174000/claim-download")
|
|
{
|
|
body = "{\"pkcs12\":\"" + m_pkcs12.toBase64() +
|
|
"\",\"password\":\"ABcd1234\",\"certificate\":{"
|
|
"\"sn\":\"12345\",\"validFrom\":\"2026-01-01T00:00:00+00:00\","
|
|
"\"validTo\":\"2027-01-01T00:00:00+00:00\",\"state\":\"VALID\"}}";
|
|
}
|
|
else if (parts.at(1) == "/api/request/123e4567-e89b-42d3-a456-426614174000/ack-download")
|
|
{
|
|
status = 204;
|
|
}
|
|
else
|
|
{
|
|
status = 404;
|
|
body = "{\"code\":4,\"message\":\"Unknown object.\"}";
|
|
}
|
|
const QByteArray response =
|
|
"HTTP/1.1 " + QByteArray::number(status) + " OK\r\n"
|
|
"Content-Type: application/json\r\nContent-Length: " +
|
|
QByteArray::number(body.size()) + "\r\nConnection: close\r\n\r\n" + body;
|
|
socket->write(response);
|
|
socket->disconnectFromHost();
|
|
});
|
|
});
|
|
}
|
|
|
|
private:
|
|
QByteArray m_pkcs12;
|
|
};
|
|
}
|
|
|
|
class EetCaIntegrationTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private slots:
|
|
void runsCertificateWorkflow();
|
|
};
|
|
|
|
void EetCaIntegrationTest::runsCertificateWorkflow()
|
|
{
|
|
QTemporaryDir directory;
|
|
QVERIFY(directory.isValid());
|
|
const QString keyPath = directory.filePath(QStringLiteral("key.pem"));
|
|
const QString certPath = directory.filePath(QStringLiteral("certificate.pem"));
|
|
const QString p12Path = directory.filePath(QStringLiteral("certificate.p12"));
|
|
auto runOpenSsl = [](const QStringList &arguments) {
|
|
QProcess process;
|
|
process.start(QStringLiteral("openssl"), arguments);
|
|
QVERIFY2(process.waitForFinished(30000), qPrintable(process.errorString()));
|
|
QVERIFY2(process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0,
|
|
process.readAllStandardError().constData());
|
|
};
|
|
runOpenSsl({QStringLiteral("req"), QStringLiteral("-x509"), QStringLiteral("-newkey"),
|
|
QStringLiteral("rsa:2048"), QStringLiteral("-nodes"), QStringLiteral("-subj"),
|
|
QStringLiteral("/CN=localhost"), QStringLiteral("-keyout"), keyPath,
|
|
QStringLiteral("-out"), certPath, QStringLiteral("-days"), QStringLiteral("1")});
|
|
runOpenSsl({QStringLiteral("pkcs12"), QStringLiteral("-export"), QStringLiteral("-out"),
|
|
p12Path, QStringLiteral("-inkey"), keyPath, QStringLiteral("-in"), certPath,
|
|
QStringLiteral("-passout"), QStringLiteral("pass:test")});
|
|
QFile p12File(p12Path);
|
|
QVERIFY(p12File.open(QIODevice::ReadOnly));
|
|
const QByteArray p12 = p12File.readAll();
|
|
|
|
MockCaServer server(p12);
|
|
QSslConfiguration ssl = QSslConfiguration::defaultConfiguration();
|
|
QFile keyFile(keyPath);
|
|
QFile certificateFile(certPath);
|
|
QVERIFY(keyFile.open(QIODevice::ReadOnly));
|
|
QVERIFY(certificateFile.open(QIODevice::ReadOnly));
|
|
ssl.setPrivateKey(QSslKey(keyFile.readAll(), QSsl::Rsa, QSsl::Pem));
|
|
ssl.setLocalCertificate(QSslCertificate(certificateFile.readAll(), QSsl::Pem));
|
|
server.setSslConfiguration(ssl);
|
|
QVERIFY(server.listen(QHostAddress::LocalHost));
|
|
|
|
QSslConfiguration clientSsl = QSslConfiguration::defaultConfiguration();
|
|
clientSsl.setCaCertificates({ssl.localCertificate()});
|
|
EetCaClient client({
|
|
QUrl(QStringLiteral("https://localhost:%1/api").arg(server.serverPort())),
|
|
p12Path, QByteArrayLiteral("test"), 5000, clientSsl
|
|
});
|
|
QString error;
|
|
QUuid requestId;
|
|
QVERIFY2(client.requestRenewal(&requestId, &error), qPrintable(error));
|
|
QCOMPARE(requestId, QUuid(QStringLiteral("123e4567-e89b-42d3-a456-426614174000")));
|
|
EetCaRequestStatus status;
|
|
QVERIFY2(client.requestStatus(requestId, &status, &error), qPrintable(error));
|
|
QCOMPARE(status.state, QStringLiteral("ISSUED"));
|
|
QList<QUuid> unfinished;
|
|
QVERIFY2(client.listUnfinished(&unfinished, &error), qPrintable(error));
|
|
QCOMPARE(unfinished, QList<QUuid>{requestId});
|
|
EetCaPkcs12 package;
|
|
QVERIFY2(client.claimDownload(requestId, &package, &error), qPrintable(error));
|
|
QCOMPARE(package.pkcs12, p12);
|
|
QCOMPARE(package.password, QByteArrayLiteral("ABcd1234"));
|
|
QVERIFY2(client.acknowledgeDownload(requestId, &error), qPrintable(error));
|
|
}
|
|
|
|
QTEST_MAIN(EetCaIntegrationTest)
|
|
#include "eetca_integration_test.moc"
|