1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef OAUTHTESTUTILS_H
#define OAUTHTESTUTILS_H
#include "tlswebserver.h"
#include "webserver.h"
#include <QtNetworkAuth/qoauthglobal.h>
#ifndef QT_NO_SSL
#include <QtNetwork/qsslconfiguration.h>
#endif
#include <QtNetwork/qtcpsocket.h>
#include <QtCore/qcontainerfwd.h>
#include <QtCore/qscopeguard.h>
#include <QtCore/qstring.h>
#include <QtCore/qtenvironmentvariables.h>
#include <memory>
[[nodiscard]] inline auto useTemporaryKeychain()
{
#ifndef QT_NO_SSL
// Set the same environment value as CI uses, so that it's possible
// to run autotests locally without macOS asking for permission to use
// a private key in keychain (with TLS sockets)
auto value = qEnvironmentVariable("QT_SSL_USE_TEMPORARY_KEYCHAIN");
qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1");
auto envRollback = qScopeGuard([value](){
if (value.isEmpty())
qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN");
else
qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", value.toUtf8());
});
return envRollback;
#else
// avoid maybe-unused warnings from callers
return qScopeGuard([]{});
#endif // QT_NO_SSL
}
QString createSignedJWT(const QVariantMap &header = {}, const QVariantMap &payload = {});
#ifndef QT_NO_SSL
QSslConfiguration createSslConfiguration(const QString &keyFileName,
const QString &certificateFileName);
#endif // QT_NO_SSL
struct ServerResponses
{
QByteArray authBody;
QByteArray authHttpStatus;
QByteArray tokenBody;
QByteArray tokenHttpStatus;
};
template<typename ServerType>
struct TestAuthorizationServer
{
std::unique_ptr<ServerType> server;
QList<WebServer::HttpRequest> receivedAuthorizationRequests;
QList<WebServer::HttpRequest> receivedTokenRequests;
ServerResponses responses;
QUrl authorizationEndpoint()
{
Q_ASSERT(server);
return server->url(QStringLiteral("authorizationEndpoint"));
}
QUrl tokenEndpoint()
{
Q_ASSERT(server);
return server->url(QStringLiteral("tokenEndpoint"));
}
};
// Creates a local http authorization server.
// The provided ServerResponses are used as the initial values. The testcase
// can modify individual response members during the testcase by modifying the returned
// instance's TestAuthorizationServer::responses contents.
// The template is used so that the function can return either WebServer* or TlsWebServer*
template<typename ServerType, typename... Args>
std::unique_ptr<TestAuthorizationServer<ServerType>> createAuthorizationServer(
ServerResponses responses, Args&&... args)
{
auto result = std::make_unique<TestAuthorizationServer<ServerType>>();
result->responses = std::move(responses);
auto handler = [raw = result.get()]
(const WebServer::HttpRequest &request, QTcpSocket *socket) {
QByteArray replyMessage;
if (request.url.path() == QLatin1StringView("/authorizationEndpoint")) {
// Set received request for test cases to check
raw->receivedAuthorizationRequests.append(request);
replyMessage =
"HTTP/1.0 " + raw->responses.authHttpStatus + "\r\n"
"Content-Type: application/json; charset=\"utf-8\"\r\n"
"Content-Length: " + QByteArray::number(raw->responses.authBody.size())
+ "\r\n\r\n" + raw->responses.authBody;
} else if (request.url.path() == QLatin1StringView("/tokenEndpoint")) {
// Set received request for test cases to check
raw->receivedTokenRequests.append(request);
replyMessage =
"HTTP/1.0 " + raw->responses.tokenHttpStatus + "\r\n"
"Content-Type: application/json; charset=\"utf-8\"\r\n"
"Content-Length: " + QByteArray::number(raw->responses.tokenBody.size())
+ "\r\n\r\n" + raw->responses.tokenBody;
} else {
qFatal() << "Unsupported URL:" << request.url;
}
socket->write(replyMessage);
};
result->server.reset(new ServerType(handler, std::forward<Args>(args)...));
return result;
}
#endif // OAUTHTESTUTILS_H
|