// 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 #ifndef QT_NO_SSL #include #endif #include #include #include #include #include #include [[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 struct TestAuthorizationServer { std::unique_ptr server; QList receivedAuthorizationRequests; QList receivedTokenRequests; ServerResponses responses; QUrl authorizationEndpoint() { Q_ASSERT(server); return server->url(http://code.qt.io/QStringLiteral(%22authorizationEndpoint")); } QUrl tokenEndpoint() { Q_ASSERT(server); return server->url(http://code.qt.io/QStringLiteral(%22tokenEndpoint")); } }; // 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 std::unique_ptr> createAuthorizationServer( ServerResponses responses, Args&&... args) { auto result = std::make_unique>(); 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)...)); return result; } #endif // OAUTHTESTUTILS_H