From 2f6c9671b08e834058254ee288be9a8b1556af1d Mon Sep 17 00:00:00 2001 From: Marius Dege <marius.dege@basyskom.com> Date: Wed, 18 Aug 2021 13:37:25 +0200 Subject: [PATCH 1/8] Oauth class with reply server for authorization flow --- docs/generators/cpp-qt-client.md | 2 +- .../codegen/languages/CppQtClientCodegen.java | 5 + .../resources/cpp-qt-client/Project.mustache | 6 +- .../resources/cpp-qt-client/api-body.mustache | 39 ++++- .../cpp-qt-client/api-header.mustache | 9 + .../cpp-qt-client/oauth.cpp.mustache | 158 ++++++++++++++++++ .../resources/cpp-qt-client/oauth.h.mustache | 113 +++++++++++++ .../petstore/cpp-qt/.openapi-generator/FILES | 2 + .../petstore/cpp-qt/client/PFXPetApi.cpp | 12 ++ .../client/petstore/cpp-qt/client/PFXPetApi.h | 9 + .../petstore/cpp-qt/client/PFXStoreApi.cpp | 12 ++ .../petstore/cpp-qt/client/PFXStoreApi.h | 9 + .../petstore/cpp-qt/client/PFXUserApi.cpp | 12 ++ .../petstore/cpp-qt/client/PFXUserApi.h | 9 + .../petstore/cpp-qt/client/PFXclient.pri | 6 +- .../client/petstore/cpp-qt/client/oauth.cpp | 158 ++++++++++++++++++ samples/client/petstore/cpp-qt/client/oauth.h | 119 +++++++++++++ 17 files changed, 674 insertions(+), 6 deletions(-) create mode 100644 modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache create mode 100644 modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache create mode 100644 samples/client/petstore/cpp-qt/client/oauth.cpp create mode 100644 samples/client/petstore/cpp-qt/client/oauth.h diff --git a/docs/generators/cpp-qt-client.md b/docs/generators/cpp-qt-client.md index 0dcbd968233..9103af0d835 100644 --- a/docs/generators/cpp-qt-client.md +++ b/docs/generators/cpp-qt-client.md @@ -239,7 +239,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |OAuth2_Implicit|✗|OAS2,OAS3 |OAuth2_Password|✗|OAS2,OAS3 |OAuth2_ClientCredentials|✗|OAS2,OAS3 -|OAuth2_AuthorizationCode|✗|OAS2,OAS3 +|OAuth2_AuthorizationCode|✓|OAS2,OAS3 ### Wire Format Feature | Name | Supported | Defined By | diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java index e93ae32541a..029a74a2589 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java @@ -46,6 +46,7 @@ public class CppQtClientCodegen extends CppQtAbstractCodegen implements CodegenC .includeSecurityFeatures(SecurityFeature.BasicAuth) .includeSecurityFeatures(SecurityFeature.ApiKey) .includeSecurityFeatures(SecurityFeature.BearerToken) + .includeSecurityFeatures(SecurityFeature.OAuth2_AuthorizationCode) .includeGlobalFeatures(GlobalFeature.ParameterStyling) ); @@ -96,6 +97,8 @@ public class CppQtClientCodegen extends CppQtAbstractCodegen implements CodegenC supportingFiles.add(new SupportingFile("enum.mustache", sourceFolder, PREFIX + "Enum.h")); supportingFiles.add(new SupportingFile("ServerConfiguration.mustache", sourceFolder, PREFIX + "ServerConfiguration.h")); supportingFiles.add(new SupportingFile("ServerVariable.mustache", sourceFolder, PREFIX + "ServerVariable.h")); + supportingFiles.add(new SupportingFile("oauth.cpp.mustache", sourceFolder, "oauth.cpp")); + supportingFiles.add(new SupportingFile("oauth.h.mustache", sourceFolder, "oauth.h")); supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("CMakeLists.txt.mustache", sourceFolder, "CMakeLists.txt")); if (optionalProjectFileFlag) { @@ -127,6 +130,8 @@ public class CppQtClientCodegen extends CppQtAbstractCodegen implements CodegenC supportingFiles.add(new SupportingFile("enum.mustache", sourceFolder, modelNamePrefix + "Enum.h")); supportingFiles.add(new SupportingFile("ServerConfiguration.mustache", sourceFolder, modelNamePrefix + "ServerConfiguration.h")); supportingFiles.add(new SupportingFile("ServerVariable.mustache", sourceFolder, modelNamePrefix + "ServerVariable.h")); + supportingFiles.add(new SupportingFile("oauth.cpp.mustache", sourceFolder, "oauth.cpp")); + supportingFiles.add(new SupportingFile("oauth.h.mustache", sourceFolder, "oauth.h")); supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("CMakeLists.txt.mustache", sourceFolder, "CMakeLists.txt")); diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/Project.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/Project.mustache index c48c32708b9..69a42e8d576 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/Project.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/Project.mustache @@ -22,7 +22,8 @@ HEADERS += \ $${PWD}/{{prefix}}Enum.h \ $${PWD}/{{prefix}}HttpFileElement.h \ $${PWD}/{{prefix}}ServerConfiguration.h \ - $${PWD}/{{prefix}}ServerVariable.h + $${PWD}/{{prefix}}ServerVariable.h \ + $${PWD}/oauth.h SOURCES += \ # Models @@ -42,4 +43,5 @@ SOURCES += \ # Others $${PWD}/{{prefix}}Helpers.cpp \ $${PWD}/{{prefix}}HttpRequest.cpp \ - $${PWD}/{{prefix}}HttpFileElement.cpp + $${PWD}/{{prefix}}HttpFileElement.cpp \ + $${PWD}/oauth.cpp diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache index 39c55843a74..4f8538466b6 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache @@ -661,8 +661,28 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} if(findChildren<{{prefix}}HttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } + });{{#authMethods}}{{#isOAuth}}{{#isCode}}QString scope("{{#scopes}}{{scope}}{{/scopes}}"); + auto token = auth.getToken(scope); + if(token.isValid()) + input.headers.insert("Authorization", "Bearer " + token.getToken()); + + latestWorker = new {{prefix}}HttpRequestWorker(this, _manager); + latestWorker->setTimeOut(_timeOut); + latestWorker->setWorkingDirectory(_workingDirectory);{{#contentCompression}} + latestWorker->setResponseCompressionEnabled(isResponseCompressionEnabled); + latestWorker->setRequestCompressionEnabled(isRequestCompressionEnabled);{{/contentCompression}} + + connect(latestWorker, &{{prefix}}HttpRequestWorker::on_execution_finished, this, &{{classname}}::{{nickname}}Callback); + connect(this, &{{classname}}::abortRequestsSignal, latestWorker, &QObject::deleteLater); + connect(latestWorker, &QObject::destroyed, [this](){ + if(findChildren<{{prefix}}HttpRequestWorker*>().count() == 0){ + emit allPendingRequestsCompleted(); + } }); + latestInput = input; + latestScope = scope;{{/isCode}}{{/isOAuth}}{{/authMethods}} + worker->execute(&input); } @@ -720,7 +740,12 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { if (worker->error_type == QNetworkReply::NoError) { emit {{nickname}}Signal({{#returnType}}output{{/returnType}}); - emit {{nickname}}SignalFull(worker{{#returnType}}, output{{/returnType}}); + emit {{nickname}}SignalFull(worker{{#returnType}}, output{{/returnType}});{{#authMethods}}{{#isOAuth}}{{#isCode}} + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + connect(&auth, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + //TODO get clientID and Secret in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like + auth.setVariables(); + emit auth.authenticationNeeded();{{/isCode}}{{/isOAuth}}{{/authMethods}} } else { emit {{nickname}}SignalE({{#returnType}}output, {{/returnType}}error_type, error_str); emit {{nickname}}SignalEFull(worker, error_type, error_str); @@ -729,6 +754,18 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { {{/operation}} {{/operations}} +void {{classname}}::tokenAvailable(){ + + auto token = auth.getToken(latestScope); + //Only inject header when token is valid. If not we run the auth process again and remove the token + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + }else{ + auth.removeToken(latestScope); + } + + latestWorker->execute(&latestInput); +} {{#cppNamespaceDeclarations}} } // namespace {{this}} {{/cppNamespaceDeclarations}} diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache index 09449281ecd..28481ba7ec0 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache @@ -5,6 +5,7 @@ #include "{{prefix}}Helpers.h" #include "{{prefix}}HttpRequest.h" #include "{{prefix}}ServerConfiguration.h" +#include "oauth.h" {{#imports}}{{{import}}} {{/imports}} @@ -73,6 +74,10 @@ private: QMap<QString, QString> defaultHeaders; bool isResponseCompressionEnabled; bool isRequestCompressionEnabled; + {{prefix}}HttpRequestInput latestInput; + {{prefix}}HttpRequestWorker *latestWorker; + QString latestScope; + OauthCode auth; {{#operations}}{{#operation}} void {{nickname}}Callback({{prefix}}HttpRequestWorker *worker);{{/operation}}{{/operations}} @@ -88,6 +93,10 @@ signals: void abortRequestsSignal(); void allPendingRequestsCompleted(); + +public slots: + void tokenAvailable(); + }; {{#cppNamespaceDeclarations}} diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache new file mode 100644 index 00000000000..8f37f426f78 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache @@ -0,0 +1,158 @@ +#include "oauth.h" + +namespace OpenAPI { + +OauthCode::OauthCode(QObject *parent) : OauthBase(parent) +{ + connect(&m_server, SIGNAL(dataReceived(QMap<QString,QString>)), this, SLOT(onVerificationReceived(QMap<QString,QString>))); + connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); + connect(this, SIGNAL(tokenReceived()), &m_server, SLOT(stop())); + +} + +void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, QString accessType, QString state, QString redirectUri, QString clientId, QString clientSecret ){ + + m_authUrl = QUrl(authUrl); + m_tokenUrl = QUrl(tokenUrl); + m_scope = scope; + m_accessType = accessType; + m_state = state; + m_redirectUri = redirectUri; + m_clientId = clientId; + m_clientSecret = clientSecret; + +} + +void OauthCode::authenticationNeededCallback() +{ + QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + "&access_type=" + m_accessType + "&response_type=code" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); + m_server.start(); +} + +void OauthCode::onVerificationReceived(const QMap<QString, QString> response) { + + // Save access code + QString state(response.value("state")); + QString scope(response.value("scope")); + QString code(response.value("code")); + + //create query with the required fields + QUrlQuery postData; + postData.addQueryItem("grant_type", "authorization_code"); + postData.addQueryItem("client_id", m_clientId); + postData.addQueryItem("client_secret", m_clientSecret); + postData.addQueryItem("code", code); + postData.addQueryItem("redirect_uri", m_redirectUri); + QNetworkAccessManager * manager = new QNetworkAccessManager(this); + + QNetworkRequest request(m_tokenUrl); + + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + + connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinish(QNetworkReply *))); + + manager->post(request, postData.query().toUtf8()); +} + +void OauthCode::onFinish(QNetworkReply *rep) +{ + //TODO emit error signal when token is wrong + QJsonDocument document = QJsonDocument::fromJson(rep->readAll()); + QJsonObject rootObj = document.object(); + QString token = rootObj.find("access_token").value().toString(); + QString scope = rootObj.find("scope").value().toString(); + QString type = rootObj.find("token_type").value().toString(); + int expiresIn = rootObj.find("expires_in").value().toInt(); + + this->m_oauthTokenMap.insert(scope,oauthToken(token, expiresIn, scope, type)); + emit tokenReceived(); +} + +oauthToken OauthBase::getToken(QString scope) +{ + auto tokenIt = m_oauthTokenMap.find(scope); + return tokenIt != m_oauthTokenMap.end() ? tokenIt.value() : oauthToken(); +} + +void OauthBase::removeToken(QString scope) +{ + m_oauthTokenMap.remove(scope); +} + +ReplyServer::ReplyServer(QObject *parent) : QTcpServer(parent) +{ + connect(this, SIGNAL(newConnection()), this, SLOT(onConnected())); + m_reply = "You can close this window now!"; + +} + +void ReplyServer::start() +{ + if(!listen(QHostAddress::Any, 9999)) + { + qDebug() << "Server could not start"; + } + else + { + qDebug() << "Server started!"; + } + +} + +void ReplyServer::stop() +{ + qDebug() << "Stopping the Server..."; + QTcpServer::close(); +} + +void ReplyServer::onConnected() +{ + // need to grab the socket + QTcpSocket *socket = nextPendingConnection(); + connect(socket, SIGNAL(readyRead()), this, SLOT(read()), Qt::UniqueConnection); + connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater())); + +} + +void ReplyServer::read() +{ + QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender()); + if (!socket) { + qDebug() << "No socket available"; + return; + } + qDebug() << "Socket connected"; + + socket->write(m_reply); + + QByteArray data = socket->readLine(); + QString splitGetLine = QString(data); + splitGetLine.remove("GET"); + splitGetLine.remove("HTTP/1.1"); + splitGetLine.remove("\r\n"); + splitGetLine.remove(" "); + //prefix is needed to extract query params + QUrl getTokenUrl("http://" + splitGetLine); + QList< QPair<QString, QString> > tokens; + + QUrlQuery query(getTokenUrl); + tokens = query.queryItems(); + + + QMap<QString, QString> queryParams; + QPair<QString, QString> tokenPair; + foreach (tokenPair, tokens) { + QString key = QUrl::fromPercentEncoding(QByteArray().append(tokenPair.first.trimmed().toLatin1())); + QString value = QUrl::fromPercentEncoding(QByteArray().append(tokenPair.second.trimmed().toLatin1())); + queryParams.insert(key, value); + } + if (!queryParams.contains("state")) { + socket->write(m_reply); + socket->close(); + return; + } + socket->close(); + + emit dataReceived(queryParams); +} +} diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache new file mode 100644 index 00000000000..5e5804c6677 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache @@ -0,0 +1,113 @@ +{{>licenseInfo}} +/** + * Providing a Oauth2 Class and a ReplyServer for the Oauth2 authorization code flow. + */ +#ifndef {{prefix}}_OAUTH2_H +#define {{prefix}}_OAUTH2_H + +#include <QObject> +#include <QtCore> +#include <QtNetwork> +#include <QDesktopServices> +#include <QNetworkRequest> +#include <QNetworkReply> +#include <QNetworkAccessManager> +#include <QtDebug> +#include <QTcpServer> +#include <QTcpSocket> +#include <QByteArray> +#include <QString> +#include <QMap> +#include <QUrl> +#include <QUrlQuery> +#include <QDateTime> + + + +{{#cppNamespaceDeclarations}} +namespace {{this}} { +{{/cppNamespaceDeclarations}} + +class oauthToken +{ +public: + oauthToken(QString token, int expiresIn, QString scope, QString tokenType) : m_token(token), m_scope(scope), m_type(tokenType){ + m_validUntil = QDateTime::fromSecsSinceEpoch(QDateTime::currentSecsSinceEpoch() + expiresIn); + } + oauthToken(){ + m_validUntil = QDateTime::fromSecsSinceEpoch(QDateTime::currentSecsSinceEpoch() -1); + } + QString getToken(){return m_token;}; + QString getScope(){return m_scope;}; + QString getType(){return m_type;}; + + bool isValid(){return QDateTime::currentDateTime() < m_validUntil;}; +private: + QString m_token; + QDateTime m_validUntil; + QString m_scope; + QString m_type; +}; + +class ReplyServer : public QTcpServer +{ + Q_OBJECT +public: + explicit ReplyServer(QObject *parent = nullptr); + + void run(); +private: + QByteArray m_reply; + +signals: + void dataReceived(QMap<QString, QString>); + +public slots: + void onConnected(); + void read(); + void start(); + void stop(); +}; + +class OauthBase : public QObject +{ + Q_OBJECT + +public: + OauthBase(QObject* parent = nullptr) : QObject(parent) {}; + oauthToken getToken(QString scope); + void removeToken(QString scope); + +protected: + QMap<QString, oauthToken> m_oauthTokenMap; + +signals: + void authenticationNeeded(); + void tokenReceived(); +}; + +class OauthCode : public OauthBase +{ + Q_OBJECT +public: + OauthCode(QObject *parent = nullptr); + void setVariables( QString authUrl, QString tokenUrl, QString scope, QString accessType, QString state, QString redirectUri, QString clientId, QString clientSecret); +private: + ReplyServer m_server; + QUrl m_authUrl; + QUrl m_tokenUrl; + QString m_scope, m_accessType, m_state, m_redirectUri, m_clientId, m_clientSecret; + + +public slots: + void authenticationNeededCallback(); + void onVerificationReceived(const QMap<QString, QString> response); + void onFinish(QNetworkReply *rep); + + +}; + +{{#cppNamespaceDeclarations}} +} // namespace {{this}} +{{/cppNamespaceDeclarations}} +#endif // {{prefix}}_OAUTH2_H diff --git a/samples/client/petstore/cpp-qt/.openapi-generator/FILES b/samples/client/petstore/cpp-qt/.openapi-generator/FILES index 3b14ec399c5..ac2a7a56629 100644 --- a/samples/client/petstore/cpp-qt/.openapi-generator/FILES +++ b/samples/client/petstore/cpp-qt/.openapi-generator/FILES @@ -29,3 +29,5 @@ client/PFXUser.h client/PFXUserApi.cpp client/PFXUserApi.h client/PFXclient.pri +client/oauth.cpp +client/oauth.h diff --git a/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp b/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp index 136f71708ba..16f8e90a9d9 100644 --- a/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp @@ -856,4 +856,16 @@ void PFXPetApi::uploadFileCallback(PFXHttpRequestWorker *worker) { } } +void PFXPetApi::tokenAvailable(){ + + auto token = auth.getToken(latestScope); + //Only inject header when token is valid. If not we run the auth process again and remove the token + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + }else{ + auth.removeToken(latestScope); + } + + latestWorker->execute(&latestInput); +} } // namespace test_namespace diff --git a/samples/client/petstore/cpp-qt/client/PFXPetApi.h b/samples/client/petstore/cpp-qt/client/PFXPetApi.h index 2c4d472306b..1d507e8de01 100644 --- a/samples/client/petstore/cpp-qt/client/PFXPetApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXPetApi.h @@ -15,6 +15,7 @@ #include "PFXHelpers.h" #include "PFXHttpRequest.h" #include "PFXServerConfiguration.h" +#include "oauth.h" #include "PFXApiResponse.h" #include "PFXHttpFileElement.h" @@ -116,6 +117,10 @@ private: QMap<QString, QString> defaultHeaders; bool isResponseCompressionEnabled; bool isRequestCompressionEnabled; + PFXHttpRequestInput latestInput; + PFXHttpRequestWorker *latestWorker; + QString latestScope; + OauthCode auth; void addPetCallback(PFXHttpRequestWorker *worker); void deletePetCallback(PFXHttpRequestWorker *worker); @@ -166,6 +171,10 @@ signals: void abortRequestsSignal(); void allPendingRequestsCompleted(); + +public slots: + void tokenAvailable(); + }; } // namespace test_namespace diff --git a/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp b/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp index 723af6e80c2..d4c66920d62 100644 --- a/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp @@ -436,4 +436,16 @@ void PFXStoreApi::placeOrderCallback(PFXHttpRequestWorker *worker) { } } +void PFXStoreApi::tokenAvailable(){ + + auto token = auth.getToken(latestScope); + //Only inject header when token is valid. If not we run the auth process again and remove the token + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + }else{ + auth.removeToken(latestScope); + } + + latestWorker->execute(&latestInput); +} } // namespace test_namespace diff --git a/samples/client/petstore/cpp-qt/client/PFXStoreApi.h b/samples/client/petstore/cpp-qt/client/PFXStoreApi.h index 7f0fa92b27b..1e4c671ab38 100644 --- a/samples/client/petstore/cpp-qt/client/PFXStoreApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXStoreApi.h @@ -15,6 +15,7 @@ #include "PFXHelpers.h" #include "PFXHttpRequest.h" #include "PFXServerConfiguration.h" +#include "oauth.h" #include "PFXOrder.h" #include <QMap> @@ -88,6 +89,10 @@ private: QMap<QString, QString> defaultHeaders; bool isResponseCompressionEnabled; bool isRequestCompressionEnabled; + PFXHttpRequestInput latestInput; + PFXHttpRequestWorker *latestWorker; + QString latestScope; + OauthCode auth; void deleteOrderCallback(PFXHttpRequestWorker *worker); void getInventoryCallback(PFXHttpRequestWorker *worker); @@ -118,6 +123,10 @@ signals: void abortRequestsSignal(); void allPendingRequestsCompleted(); + +public slots: + void tokenAvailable(); + }; } // namespace test_namespace diff --git a/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp b/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp index 1ea5c6e602d..752d2d88b0e 100644 --- a/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp @@ -664,4 +664,16 @@ void PFXUserApi::updateUserCallback(PFXHttpRequestWorker *worker) { } } +void PFXUserApi::tokenAvailable(){ + + auto token = auth.getToken(latestScope); + //Only inject header when token is valid. If not we run the auth process again and remove the token + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + }else{ + auth.removeToken(latestScope); + } + + latestWorker->execute(&latestInput); +} } // namespace test_namespace diff --git a/samples/client/petstore/cpp-qt/client/PFXUserApi.h b/samples/client/petstore/cpp-qt/client/PFXUserApi.h index ab974de0622..889de01970b 100644 --- a/samples/client/petstore/cpp-qt/client/PFXUserApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXUserApi.h @@ -15,6 +15,7 @@ #include "PFXHelpers.h" #include "PFXHttpRequest.h" #include "PFXServerConfiguration.h" +#include "oauth.h" #include "PFXUser.h" #include <QList> @@ -110,6 +111,10 @@ private: QMap<QString, QString> defaultHeaders; bool isResponseCompressionEnabled; bool isRequestCompressionEnabled; + PFXHttpRequestInput latestInput; + PFXHttpRequestWorker *latestWorker; + QString latestScope; + OauthCode auth; void createUserCallback(PFXHttpRequestWorker *worker); void createUsersWithArrayInputCallback(PFXHttpRequestWorker *worker); @@ -160,6 +165,10 @@ signals: void abortRequestsSignal(); void allPendingRequestsCompleted(); + +public slots: + void tokenAvailable(); + }; } // namespace test_namespace diff --git a/samples/client/petstore/cpp-qt/client/PFXclient.pri b/samples/client/petstore/cpp-qt/client/PFXclient.pri index b28c7479d90..4e7c0a35495 100644 --- a/samples/client/petstore/cpp-qt/client/PFXclient.pri +++ b/samples/client/petstore/cpp-qt/client/PFXclient.pri @@ -19,7 +19,8 @@ HEADERS += \ $${PWD}/PFXEnum.h \ $${PWD}/PFXHttpFileElement.h \ $${PWD}/PFXServerConfiguration.h \ - $${PWD}/PFXServerVariable.h + $${PWD}/PFXServerVariable.h \ + $${PWD}/oauth.h SOURCES += \ # Models @@ -36,4 +37,5 @@ SOURCES += \ # Others $${PWD}/PFXHelpers.cpp \ $${PWD}/PFXHttpRequest.cpp \ - $${PWD}/PFXHttpFileElement.cpp + $${PWD}/PFXHttpFileElement.cpp \ + $${PWD}/oauth.cpp diff --git a/samples/client/petstore/cpp-qt/client/oauth.cpp b/samples/client/petstore/cpp-qt/client/oauth.cpp new file mode 100644 index 00000000000..8f37f426f78 --- /dev/null +++ b/samples/client/petstore/cpp-qt/client/oauth.cpp @@ -0,0 +1,158 @@ +#include "oauth.h" + +namespace OpenAPI { + +OauthCode::OauthCode(QObject *parent) : OauthBase(parent) +{ + connect(&m_server, SIGNAL(dataReceived(QMap<QString,QString>)), this, SLOT(onVerificationReceived(QMap<QString,QString>))); + connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); + connect(this, SIGNAL(tokenReceived()), &m_server, SLOT(stop())); + +} + +void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, QString accessType, QString state, QString redirectUri, QString clientId, QString clientSecret ){ + + m_authUrl = QUrl(authUrl); + m_tokenUrl = QUrl(tokenUrl); + m_scope = scope; + m_accessType = accessType; + m_state = state; + m_redirectUri = redirectUri; + m_clientId = clientId; + m_clientSecret = clientSecret; + +} + +void OauthCode::authenticationNeededCallback() +{ + QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + "&access_type=" + m_accessType + "&response_type=code" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); + m_server.start(); +} + +void OauthCode::onVerificationReceived(const QMap<QString, QString> response) { + + // Save access code + QString state(response.value("state")); + QString scope(response.value("scope")); + QString code(response.value("code")); + + //create query with the required fields + QUrlQuery postData; + postData.addQueryItem("grant_type", "authorization_code"); + postData.addQueryItem("client_id", m_clientId); + postData.addQueryItem("client_secret", m_clientSecret); + postData.addQueryItem("code", code); + postData.addQueryItem("redirect_uri", m_redirectUri); + QNetworkAccessManager * manager = new QNetworkAccessManager(this); + + QNetworkRequest request(m_tokenUrl); + + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + + connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinish(QNetworkReply *))); + + manager->post(request, postData.query().toUtf8()); +} + +void OauthCode::onFinish(QNetworkReply *rep) +{ + //TODO emit error signal when token is wrong + QJsonDocument document = QJsonDocument::fromJson(rep->readAll()); + QJsonObject rootObj = document.object(); + QString token = rootObj.find("access_token").value().toString(); + QString scope = rootObj.find("scope").value().toString(); + QString type = rootObj.find("token_type").value().toString(); + int expiresIn = rootObj.find("expires_in").value().toInt(); + + this->m_oauthTokenMap.insert(scope,oauthToken(token, expiresIn, scope, type)); + emit tokenReceived(); +} + +oauthToken OauthBase::getToken(QString scope) +{ + auto tokenIt = m_oauthTokenMap.find(scope); + return tokenIt != m_oauthTokenMap.end() ? tokenIt.value() : oauthToken(); +} + +void OauthBase::removeToken(QString scope) +{ + m_oauthTokenMap.remove(scope); +} + +ReplyServer::ReplyServer(QObject *parent) : QTcpServer(parent) +{ + connect(this, SIGNAL(newConnection()), this, SLOT(onConnected())); + m_reply = "You can close this window now!"; + +} + +void ReplyServer::start() +{ + if(!listen(QHostAddress::Any, 9999)) + { + qDebug() << "Server could not start"; + } + else + { + qDebug() << "Server started!"; + } + +} + +void ReplyServer::stop() +{ + qDebug() << "Stopping the Server..."; + QTcpServer::close(); +} + +void ReplyServer::onConnected() +{ + // need to grab the socket + QTcpSocket *socket = nextPendingConnection(); + connect(socket, SIGNAL(readyRead()), this, SLOT(read()), Qt::UniqueConnection); + connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater())); + +} + +void ReplyServer::read() +{ + QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender()); + if (!socket) { + qDebug() << "No socket available"; + return; + } + qDebug() << "Socket connected"; + + socket->write(m_reply); + + QByteArray data = socket->readLine(); + QString splitGetLine = QString(data); + splitGetLine.remove("GET"); + splitGetLine.remove("HTTP/1.1"); + splitGetLine.remove("\r\n"); + splitGetLine.remove(" "); + //prefix is needed to extract query params + QUrl getTokenUrl("http://" + splitGetLine); + QList< QPair<QString, QString> > tokens; + + QUrlQuery query(getTokenUrl); + tokens = query.queryItems(); + + + QMap<QString, QString> queryParams; + QPair<QString, QString> tokenPair; + foreach (tokenPair, tokens) { + QString key = QUrl::fromPercentEncoding(QByteArray().append(tokenPair.first.trimmed().toLatin1())); + QString value = QUrl::fromPercentEncoding(QByteArray().append(tokenPair.second.trimmed().toLatin1())); + queryParams.insert(key, value); + } + if (!queryParams.contains("state")) { + socket->write(m_reply); + socket->close(); + return; + } + socket->close(); + + emit dataReceived(queryParams); +} +} diff --git a/samples/client/petstore/cpp-qt/client/oauth.h b/samples/client/petstore/cpp-qt/client/oauth.h new file mode 100644 index 00000000000..6053dd79273 --- /dev/null +++ b/samples/client/petstore/cpp-qt/client/oauth.h @@ -0,0 +1,119 @@ +/** + * OpenAPI Petstore + * This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters. + * + * The version of the OpenAPI document: 1.0.0 + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * Providing a Oauth2 Class and a ReplyServer for the Oauth2 authorization code flow. + */ +#ifndef PFX_OAUTH2_H +#define PFX_OAUTH2_H + +#include <QObject> +#include <QtCore> +#include <QtNetwork> +#include <QDesktopServices> +#include <QNetworkRequest> +#include <QNetworkReply> +#include <QNetworkAccessManager> +#include <QtDebug> +#include <QTcpServer> +#include <QTcpSocket> +#include <QByteArray> +#include <QString> +#include <QMap> +#include <QUrl> +#include <QUrlQuery> +#include <QDateTime> + + + +namespace test_namespace { + +class oauthToken +{ +public: + oauthToken(QString token, int expiresIn, QString scope, QString tokenType) : m_token(token), m_scope(scope), m_type(tokenType){ + m_validUntil = QDateTime::fromSecsSinceEpoch(QDateTime::currentSecsSinceEpoch() + expiresIn); + } + oauthToken(){ + m_validUntil = QDateTime::fromSecsSinceEpoch(QDateTime::currentSecsSinceEpoch() -1); + } + QString getToken(){return m_token;}; + QString getScope(){return m_scope;}; + QString getType(){return m_type;}; + + bool isValid(){return QDateTime::currentDateTime() < m_validUntil;}; +private: + QString m_token; + QDateTime m_validUntil; + QString m_scope; + QString m_type; +}; + +class ReplyServer : public QTcpServer +{ + Q_OBJECT +public: + explicit ReplyServer(QObject *parent = nullptr); + + void run(); +private: + QByteArray m_reply; + +signals: + void dataReceived(QMap<QString, QString>); + +public slots: + void onConnected(); + void read(); + void start(); + void stop(); +}; + +class OauthBase : public QObject +{ + Q_OBJECT + +public: + OauthBase(QObject* parent = nullptr) : QObject(parent) {}; + oauthToken getToken(QString scope); + void removeToken(QString scope); + +protected: + QMap<QString, oauthToken> m_oauthTokenMap; + +signals: + void authenticationNeeded(); + void tokenReceived(); +}; + +class OauthCode : public OauthBase +{ + Q_OBJECT +public: + OauthCode(QObject *parent = nullptr); + void setVariables( QString authUrl, QString tokenUrl, QString scope, QString accessType, QString state, QString redirectUri, QString clientId, QString clientSecret); +private: + ReplyServer m_server; + QUrl m_authUrl; + QUrl m_tokenUrl; + QString m_scope, m_accessType, m_state, m_redirectUri, m_clientId, m_clientSecret; + + +public slots: + void authenticationNeededCallback(); + void onVerificationReceived(const QMap<QString, QString> response); + void onFinish(QNetworkReply *rep); + + +}; + +} // namespace test_namespace +#endif // PFX_OAUTH2_H -- GitLab From 9bd5a519119325db120c6ae9ba3179711d064bec Mon Sep 17 00:00:00 2001 From: Marius Dege <marius.dege@basyskom.com> Date: Wed, 25 Aug 2021 15:49:55 +0200 Subject: [PATCH 2/8] multiple scopes. Joined with space seperator --- .../resources/cpp-qt-client/api-body.mustache | 15 ++++++++++++--- .../resources/cpp-qt-client/api-header.mustache | 2 +- samples/client/petstore/cpp-qt/client/PFXPetApi.h | 2 +- .../client/petstore/cpp-qt/client/PFXStoreApi.h | 2 +- .../client/petstore/cpp-qt/client/PFXUserApi.h | 2 +- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache index 4f8538466b6..444d9061c13 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache @@ -661,8 +661,12 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} if(findChildren<{{prefix}}HttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } - });{{#authMethods}}{{#isOAuth}}{{#isCode}}QString scope("{{#scopes}}{{scope}}{{/scopes}}"); - auto token = auth.getToken(scope); + });{{#authMethods}}{{#isOAuth}}{{#isCode}} + QStringList scope; + {{#scopes}} + scope.append("{{scope}}"); + {{/scopes}} + auto token = auth.getToken(scope.join(" ")); if(token.isValid()) input.headers.insert("Authorization", "Bearer " + token.getToken()); @@ -743,8 +747,13 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { emit {{nickname}}SignalFull(worker{{#returnType}}, output{{/returnType}});{{#authMethods}}{{#isOAuth}}{{#isCode}} } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ connect(&auth, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + QStringList scope; + {{#scopes}} + scope.append("{{scope}}"); + {{/scopes}} + QString scopeStr = scope.join(" "); //TODO get clientID and Secret in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - auth.setVariables(); + //auth.setVariables(); emit auth.authenticationNeeded();{{/isCode}}{{/isOAuth}}{{/authMethods}} } else { emit {{nickname}}SignalE({{#returnType}}output, {{/returnType}}error_type, error_str); diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache index 28481ba7ec0..71ee289bf54 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache @@ -76,7 +76,7 @@ private: bool isRequestCompressionEnabled; {{prefix}}HttpRequestInput latestInput; {{prefix}}HttpRequestWorker *latestWorker; - QString latestScope; + QStringList latestScope; OauthCode auth; {{#operations}}{{#operation}} void {{nickname}}Callback({{prefix}}HttpRequestWorker *worker);{{/operation}}{{/operations}} diff --git a/samples/client/petstore/cpp-qt/client/PFXPetApi.h b/samples/client/petstore/cpp-qt/client/PFXPetApi.h index 1d507e8de01..87cef175635 100644 --- a/samples/client/petstore/cpp-qt/client/PFXPetApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXPetApi.h @@ -119,7 +119,7 @@ private: bool isRequestCompressionEnabled; PFXHttpRequestInput latestInput; PFXHttpRequestWorker *latestWorker; - QString latestScope; + QStringList latestScope; OauthCode auth; void addPetCallback(PFXHttpRequestWorker *worker); diff --git a/samples/client/petstore/cpp-qt/client/PFXStoreApi.h b/samples/client/petstore/cpp-qt/client/PFXStoreApi.h index 1e4c671ab38..c970745a72a 100644 --- a/samples/client/petstore/cpp-qt/client/PFXStoreApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXStoreApi.h @@ -91,7 +91,7 @@ private: bool isRequestCompressionEnabled; PFXHttpRequestInput latestInput; PFXHttpRequestWorker *latestWorker; - QString latestScope; + QStringList latestScope; OauthCode auth; void deleteOrderCallback(PFXHttpRequestWorker *worker); diff --git a/samples/client/petstore/cpp-qt/client/PFXUserApi.h b/samples/client/petstore/cpp-qt/client/PFXUserApi.h index 889de01970b..b8a2c13fcdf 100644 --- a/samples/client/petstore/cpp-qt/client/PFXUserApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXUserApi.h @@ -113,7 +113,7 @@ private: bool isRequestCompressionEnabled; PFXHttpRequestInput latestInput; PFXHttpRequestWorker *latestWorker; - QString latestScope; + QStringList latestScope; OauthCode auth; void createUserCallback(PFXHttpRequestWorker *worker); -- GitLab From 30cd73e2a4404d09bac71e85eb435d4693a16b2d Mon Sep 17 00:00:00 2001 From: Marius Dege <marius.dege@basyskom.com> Date: Thu, 26 Aug 2021 13:46:11 +0200 Subject: [PATCH 3/8] some refactoring, using urls from the spec --- .../main/resources/cpp-qt-client/api-body.mustache | 14 ++++++++------ .../resources/cpp-qt-client/oauth.cpp.mustache | 4 ++-- .../main/resources/cpp-qt-client/oauth.h.mustache | 2 +- .../client/petstore/cpp-qt/client/PFXPetApi.cpp | 8 ++++---- .../client/petstore/cpp-qt/client/PFXStoreApi.cpp | 8 ++++---- .../client/petstore/cpp-qt/client/PFXUserApi.cpp | 8 ++++---- samples/client/petstore/cpp-qt/client/oauth.cpp | 4 ++-- samples/client/petstore/cpp-qt/client/oauth.h | 2 +- 8 files changed, 26 insertions(+), 24 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache index 444d9061c13..d6a32ebcf2e 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache @@ -752,8 +752,10 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { scope.append("{{scope}}"); {{/scopes}} QString scopeStr = scope.join(" "); - //TODO get clientID and Secret in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - //auth.setVariables(); + QString authorizationUrl("{{authorizationUrl}}"); + QString tokenUrl("{{tokenUrl}}"); + //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like + auth.setVariables(authorizationUrl, tokenUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); emit auth.authenticationNeeded();{{/isCode}}{{/isOAuth}}{{/authMethods}} } else { emit {{nickname}}SignalE({{#returnType}}output, {{/returnType}}error_type, error_str); @@ -765,15 +767,15 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { {{/operations}} void {{classname}}::tokenAvailable(){ - auto token = auth.getToken(latestScope); + auto token = auth.getToken(latestScope.join(" ")); //Only inject header when token is valid. If not we run the auth process again and remove the token if(token.isValid()){ latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); }else{ - auth.removeToken(latestScope); + auth.removeToken(latestScope.join(" ")); + qDebug() << "Could not retrieve a valid token"; } - - latestWorker->execute(&latestInput); } {{#cppNamespaceDeclarations}} } // namespace {{this}} diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache index 8f37f426f78..46f5fdc5403 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache @@ -10,7 +10,7 @@ OauthCode::OauthCode(QObject *parent) : OauthBase(parent) } -void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, QString accessType, QString state, QString redirectUri, QString clientId, QString clientSecret ){ +void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType){ m_authUrl = QUrl(authUrl); m_tokenUrl = QUrl(tokenUrl); @@ -25,7 +25,7 @@ void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, Q void OauthCode::authenticationNeededCallback() { - QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + "&access_type=" + m_accessType + "&response_type=code" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); + QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + (m_accessType=="" ? "" : "&access_type=" + m_accessType) + "&response_type=code" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); m_server.start(); } diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache index 5e5804c6677..4c94a7aad8d 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache @@ -91,7 +91,7 @@ class OauthCode : public OauthBase Q_OBJECT public: OauthCode(QObject *parent = nullptr); - void setVariables( QString authUrl, QString tokenUrl, QString scope, QString accessType, QString state, QString redirectUri, QString clientId, QString clientSecret); + void setVariables( QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType = ""); private: ReplyServer m_server; QUrl m_authUrl; diff --git a/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp b/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp index 16f8e90a9d9..2ee6f1b90cb 100644 --- a/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp @@ -858,14 +858,14 @@ void PFXPetApi::uploadFileCallback(PFXHttpRequestWorker *worker) { void PFXPetApi::tokenAvailable(){ - auto token = auth.getToken(latestScope); + auto token = auth.getToken(latestScope.join(" ")); //Only inject header when token is valid. If not we run the auth process again and remove the token if(token.isValid()){ latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); }else{ - auth.removeToken(latestScope); + auth.removeToken(latestScope.join(" ")); + qDebug() << "Could not retrieve a valid token"; } - - latestWorker->execute(&latestInput); } } // namespace test_namespace diff --git a/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp b/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp index d4c66920d62..949428637e2 100644 --- a/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp @@ -438,14 +438,14 @@ void PFXStoreApi::placeOrderCallback(PFXHttpRequestWorker *worker) { void PFXStoreApi::tokenAvailable(){ - auto token = auth.getToken(latestScope); + auto token = auth.getToken(latestScope.join(" ")); //Only inject header when token is valid. If not we run the auth process again and remove the token if(token.isValid()){ latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); }else{ - auth.removeToken(latestScope); + auth.removeToken(latestScope.join(" ")); + qDebug() << "Could not retrieve a valid token"; } - - latestWorker->execute(&latestInput); } } // namespace test_namespace diff --git a/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp b/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp index 752d2d88b0e..ad3a55d9f5b 100644 --- a/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp @@ -666,14 +666,14 @@ void PFXUserApi::updateUserCallback(PFXHttpRequestWorker *worker) { void PFXUserApi::tokenAvailable(){ - auto token = auth.getToken(latestScope); + auto token = auth.getToken(latestScope.join(" ")); //Only inject header when token is valid. If not we run the auth process again and remove the token if(token.isValid()){ latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); }else{ - auth.removeToken(latestScope); + auth.removeToken(latestScope.join(" ")); + qDebug() << "Could not retrieve a valid token"; } - - latestWorker->execute(&latestInput); } } // namespace test_namespace diff --git a/samples/client/petstore/cpp-qt/client/oauth.cpp b/samples/client/petstore/cpp-qt/client/oauth.cpp index 8f37f426f78..46f5fdc5403 100644 --- a/samples/client/petstore/cpp-qt/client/oauth.cpp +++ b/samples/client/petstore/cpp-qt/client/oauth.cpp @@ -10,7 +10,7 @@ OauthCode::OauthCode(QObject *parent) : OauthBase(parent) } -void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, QString accessType, QString state, QString redirectUri, QString clientId, QString clientSecret ){ +void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType){ m_authUrl = QUrl(authUrl); m_tokenUrl = QUrl(tokenUrl); @@ -25,7 +25,7 @@ void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, Q void OauthCode::authenticationNeededCallback() { - QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + "&access_type=" + m_accessType + "&response_type=code" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); + QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + (m_accessType=="" ? "" : "&access_type=" + m_accessType) + "&response_type=code" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); m_server.start(); } diff --git a/samples/client/petstore/cpp-qt/client/oauth.h b/samples/client/petstore/cpp-qt/client/oauth.h index 6053dd79273..5ff4038170e 100644 --- a/samples/client/petstore/cpp-qt/client/oauth.h +++ b/samples/client/petstore/cpp-qt/client/oauth.h @@ -99,7 +99,7 @@ class OauthCode : public OauthBase Q_OBJECT public: OauthCode(QObject *parent = nullptr); - void setVariables( QString authUrl, QString tokenUrl, QString scope, QString accessType, QString state, QString redirectUri, QString clientId, QString clientSecret); + void setVariables( QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType = ""); private: ReplyServer m_server; QUrl m_authUrl; -- GitLab From 0a1c6fd7b280e1233e7f2518597aebb08872d976 Mon Sep 17 00:00:00 2001 From: Marius Dege <marius.dege@basyskom.com> Date: Fri, 27 Aug 2021 13:18:31 +0200 Subject: [PATCH 4/8] added implicit flow. Refactored oauth classes. --- docs/generators/cpp-qt-client.md | 2 +- .../codegen/languages/CppQtClientCodegen.java | 1 + .../resources/cpp-qt-client/api-body.mustache | 84 ++++- .../cpp-qt-client/api-header.mustache | 3 + .../cpp-qt-client/oauth.cpp.mustache | 147 +++++++-- .../resources/cpp-qt-client/oauth.h.mustache | 47 ++- .../petstore/cpp-qt/client/PFXPetApi.cpp | 287 +++++++++++++++++- .../client/petstore/cpp-qt/client/PFXPetApi.h | 3 + .../petstore/cpp-qt/client/PFXStoreApi.cpp | 35 ++- .../petstore/cpp-qt/client/PFXStoreApi.h | 3 + .../petstore/cpp-qt/client/PFXUserApi.cpp | 35 ++- .../petstore/cpp-qt/client/PFXUserApi.h | 3 + .../client/petstore/cpp-qt/client/oauth.cpp | 147 +++++++-- samples/client/petstore/cpp-qt/client/oauth.h | 47 ++- 14 files changed, 723 insertions(+), 121 deletions(-) diff --git a/docs/generators/cpp-qt-client.md b/docs/generators/cpp-qt-client.md index 9103af0d835..480ebfbfc41 100644 --- a/docs/generators/cpp-qt-client.md +++ b/docs/generators/cpp-qt-client.md @@ -236,7 +236,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |ApiKey|✓|OAS2,OAS3 |OpenIDConnect|✗|OAS3 |BearerToken|✓|OAS3 -|OAuth2_Implicit|✗|OAS2,OAS3 +|OAuth2_Implicit|✓|OAS2,OAS3 |OAuth2_Password|✗|OAS2,OAS3 |OAuth2_ClientCredentials|✗|OAS2,OAS3 |OAuth2_AuthorizationCode|✓|OAS2,OAS3 diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java index 029a74a2589..1d72e6c16c5 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java @@ -47,6 +47,7 @@ public class CppQtClientCodegen extends CppQtAbstractCodegen implements CodegenC .includeSecurityFeatures(SecurityFeature.ApiKey) .includeSecurityFeatures(SecurityFeature.BearerToken) .includeSecurityFeatures(SecurityFeature.OAuth2_AuthorizationCode) + .includeSecurityFeatures(SecurityFeature.OAuth2_Implicit) .includeGlobalFeatures(GlobalFeature.ParameterStyling) ); diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache index d6a32ebcf2e..a90bed1f397 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache @@ -662,6 +662,9 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} emit allPendingRequestsCompleted(); } });{{#authMethods}}{{#isOAuth}}{{#isCode}} + OauthMethod = 2; + implicit.unlink(); + auth.link(); QStringList scope; {{#scopes}} scope.append("{{scope}}"); @@ -685,7 +688,36 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} }); latestInput = input; - latestScope = scope;{{/isCode}}{{/isOAuth}}{{/authMethods}} + latestScope = scope;{{/isCode}} + {{#isImplicit}} + OauthMethod = 1; + auth.unlink(); + implicit.link(); + QStringList scope; + {{#scopes}} + scope.append("{{scope}}"); + {{/scopes}} + auto token = implicit.getToken(scope.join(" ")); + if(token.isValid()) + input.headers.insert("Authorization", "Bearer " + token.getToken()); + + latestWorker = new {{prefix}}HttpRequestWorker(this, _manager); + latestWorker->setTimeOut(_timeOut); + latestWorker->setWorkingDirectory(_workingDirectory);{{#contentCompression}} + latestWorker->setResponseCompressionEnabled(isResponseCompressionEnabled); + latestWorker->setRequestCompressionEnabled(isRequestCompressionEnabled);{{/contentCompression}} + + connect(latestWorker, &{{prefix}}HttpRequestWorker::on_execution_finished, this, &{{classname}}::{{nickname}}Callback); + connect(this, &{{classname}}::abortRequestsSignal, latestWorker, &QObject::deleteLater); + connect(latestWorker, &QObject::destroyed, [this](){ + if(findChildren<{{prefix}}HttpRequestWorker*>().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + latestInput = input; + latestScope = scope; + {{/isImplicit}}{{/isOAuth}}{{/authMethods}} worker->execute(&input); } @@ -756,7 +788,20 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { QString tokenUrl("{{tokenUrl}}"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like auth.setVariables(authorizationUrl, tokenUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); - emit auth.authenticationNeeded();{{/isCode}}{{/isOAuth}}{{/authMethods}} + emit auth.authenticationNeeded();{{/isCode}} + {{#isImplicit}} + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + QStringList scope; + {{#scopes}} + scope.append("{{scope}}"); + {{/scopes}} + QString scopeStr = scope.join(" "); + QString authorizationUrl("{{authorizationUrl}}"); + //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like + implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); + emit implicit.authenticationNeeded(); + {{/isImplicit}}{{/isOAuth}}{{/authMethods}} } else { emit {{nickname}}SignalE({{#returnType}}output, {{/returnType}}error_type, error_str); emit {{nickname}}SignalEFull(worker, error_type, error_str); @@ -766,15 +811,32 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { {{/operation}} {{/operations}} void {{classname}}::tokenAvailable(){ - - auto token = auth.getToken(latestScope.join(" ")); - //Only inject header when token is valid. If not we run the auth process again and remove the token - if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); - }else{ - auth.removeToken(latestScope.join(" ")); - qDebug() << "Could not retrieve a valid token"; + + oauthToken token; + switch (OauthMethod) { + case 1: //implicit flow + token = implicit.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + implicit.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 2: //authorization flow + token = auth.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + auth.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + default: + qDebug() << "No Oauth method set!"; + break; } } {{#cppNamespaceDeclarations}} diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache index 71ee289bf54..feb25cf88e7 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache @@ -78,6 +78,9 @@ private: {{prefix}}HttpRequestWorker *latestWorker; QStringList latestScope; OauthCode auth; + OauthImplicit implicit; + int OauthMethod = 0; + {{#operations}}{{#operation}} void {{nickname}}Callback({{prefix}}HttpRequestWorker *worker);{{/operation}}{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache index 46f5fdc5403..1653b96c0ee 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache @@ -2,15 +2,12 @@ namespace OpenAPI { -OauthCode::OauthCode(QObject *parent) : OauthBase(parent) -{ - connect(&m_server, SIGNAL(dataReceived(QMap<QString,QString>)), this, SLOT(onVerificationReceived(QMap<QString,QString>))); - connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); - connect(this, SIGNAL(tokenReceived()), &m_server, SLOT(stop())); +/* + * Base class to perform oauth2 flows + * + */ -} - -void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType){ +void OauthBase::setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType){ m_authUrl = QUrl(authUrl); m_tokenUrl = QUrl(tokenUrl); @@ -18,9 +15,57 @@ void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, Q m_accessType = accessType; m_state = state; m_redirectUri = redirectUri; - m_clientId = clientId; - m_clientSecret = clientSecret; + m_clientId = clientId; m_clientSecret = clientSecret; + +} + +void OauthBase::onFinish(QNetworkReply *rep) +{ + //TODO emit error signal when token is wrong + QJsonDocument document = QJsonDocument::fromJson(rep->readAll()); + QJsonObject rootObj = document.object(); + QString token = rootObj.find("access_token").value().toString(); + QString scope = rootObj.find("scope").value().toString(); + QString type = rootObj.find("token_type").value().toString(); + int expiresIn = rootObj.find("expires_in").value().toInt(); + addToken(oauthToken(token, expiresIn, scope, type)); +} + +oauthToken OauthBase::getToken(QString scope) +{ + auto tokenIt = m_oauthTokenMap.find(scope); + return tokenIt != m_oauthTokenMap.end() ? tokenIt.value() : oauthToken(); +} + +void OauthBase::addToken(oauthToken token) +{ + m_oauthTokenMap.insert(token.getScope(),token); + emit tokenReceived(); + +} + +void OauthBase::removeToken(QString scope) +{ + m_oauthTokenMap.remove(scope); +} +/* + * Class to perform the authorization code flow + * + */ + +OauthCode::OauthCode(QObject *parent) : OauthBase(parent){} + +void OauthCode::link(){ + connect(&m_server, SIGNAL(dataReceived(QMap<QString,QString>)), this, SLOT(onVerificationReceived(QMap<QString,QString>))); + connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); + connect(this, SIGNAL(tokenReceived()), &m_server, SLOT(stop())); +} + +void OauthCode::unlink() +{ + disconnect(this,0,0,0); + disconnect(&m_server,0,0,0); } void OauthCode::authenticationNeededCallback() @@ -54,36 +99,53 @@ void OauthCode::onVerificationReceived(const QMap<QString, QString> response) { manager->post(request, postData.query().toUtf8()); } -void OauthCode::onFinish(QNetworkReply *rep) +/* + * Class to perform the implicit flow + * + */ + +OauthImplicit::OauthImplicit(QObject *parent) : OauthBase(parent){} + +void OauthImplicit::link() { - //TODO emit error signal when token is wrong - QJsonDocument document = QJsonDocument::fromJson(rep->readAll()); - QJsonObject rootObj = document.object(); - QString token = rootObj.find("access_token").value().toString(); - QString scope = rootObj.find("scope").value().toString(); - QString type = rootObj.find("token_type").value().toString(); - int expiresIn = rootObj.find("expires_in").value().toInt(); + //TODO correct linking + connect(&m_server, SIGNAL(dataReceived(QMap<QString,QString>)), this, SLOT(ImplicitTokenReceived(QMap<QString,QString>))); + connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); + connect(this, SIGNAL(tokenReceived()), &m_server, SLOT(stop())); + m_linked = true; +} - this->m_oauthTokenMap.insert(scope,oauthToken(token, expiresIn, scope, type)); - emit tokenReceived(); +void OauthImplicit::unlink() +{ + disconnect(this,0,0,0); + disconnect(&m_server,0,0,0); + m_linked = false; } -oauthToken OauthBase::getToken(QString scope) +void OauthImplicit::authenticationNeededCallback() { - auto tokenIt = m_oauthTokenMap.find(scope); - return tokenIt != m_oauthTokenMap.end() ? tokenIt.value() : oauthToken(); + QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + (m_accessType=="" ? "" : "&access_type=" + m_accessType) + "&response_type=token" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); + m_server.start(); } -void OauthBase::removeToken(QString scope) +void OauthImplicit::ImplicitTokenReceived(const QMap<QString, QString> response) { - m_oauthTokenMap.remove(scope); + QString token = response.find("access_token").value(); + QString scope = response.find("scope").value(); + QString type = response.find("token_type").value(); + int expiresIn = response.find("expires_in").value().toInt(); + addToken(oauthToken(token, expiresIn, scope, type)); } +/* + * Class that provides a simple reply server + * + */ + ReplyServer::ReplyServer(QObject *parent) : QTcpServer(parent) { connect(this, SIGNAL(newConnection()), this, SLOT(onConnected())); - m_reply = "You can close this window now!"; - + m_reply ="you can close this window now!"; } void ReplyServer::start() @@ -96,7 +158,6 @@ void ReplyServer::start() { qDebug() << "Server started!"; } - } void ReplyServer::stop() @@ -123,7 +184,29 @@ void ReplyServer::read() } qDebug() << "Socket connected"; - socket->write(m_reply); + QTextStream os(socket); + os.setAutoDetectUnicode(true); + os << "HTTP/1.0 200 Ok\r\n" + "Content-Type: text/html; charset=\"utf-8\"\r\n" + "\r\n" + <<"<!DOCTYPE html>\ + <html>\ + <head>\ + <script>\ + window.onload = function hashFunction() {\ + var query = location.hash.substr(1);\ + if (query != \"\") {\ + var xhttp = new XMLHttpRequest();\ + xhttp.open(\"GET\", \"/?\" + query, true);\ + xhttp.send();\ + }\ + }\ + </script>\ + </head>\ + <body>\ + <h2>You can close this window now!</h2>\ + </body>\ + </html>"; QByteArray data = socket->readLine(); QString splitGetLine = QString(data); @@ -147,7 +230,7 @@ void ReplyServer::read() queryParams.insert(key, value); } if (!queryParams.contains("state")) { - socket->write(m_reply); + socket->close(); return; } @@ -155,4 +238,6 @@ void ReplyServer::read() emit dataReceived(queryParams); } -} + + +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache index 4c94a7aad8d..35fb922b542 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache @@ -40,8 +40,8 @@ public: QString getToken(){return m_token;}; QString getScope(){return m_scope;}; QString getType(){return m_type;}; - bool isValid(){return QDateTime::currentDateTime() < m_validUntil;}; + private: QString m_token; QDateTime m_validUntil; @@ -54,7 +54,7 @@ class ReplyServer : public QTcpServer Q_OBJECT public: explicit ReplyServer(QObject *parent = nullptr); - + void setReply(QByteArray reply){m_reply = reply;}; void run(); private: QByteArray m_reply; @@ -69,42 +69,69 @@ public slots: void stop(); }; +//Base class class OauthBase : public QObject { Q_OBJECT - public: OauthBase(QObject* parent = nullptr) : QObject(parent) {}; oauthToken getToken(QString scope); + void addToken(oauthToken token); void removeToken(QString scope); + void setVariables( QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType = ""); + bool linked(){return m_linked;}; + virtual void link()=0; + virtual void unlink()=0; protected: QMap<QString, oauthToken> m_oauthTokenMap; + QUrl m_authUrl; + QUrl m_tokenUrl; + QString m_scope, m_accessType, m_state, m_redirectUri, m_clientId, m_clientSecret; + bool m_linked; + +public slots: + virtual void authenticationNeededCallback()=0; + void onFinish(QNetworkReply *rep); signals: void authenticationNeeded(); void tokenReceived(); }; +// Authorization code flow class OauthCode : public OauthBase { Q_OBJECT public: OauthCode(QObject *parent = nullptr); - void setVariables( QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType = ""); + void link() override; + void unlink() override; + private: ReplyServer m_server; - QUrl m_authUrl; - QUrl m_tokenUrl; - QString m_scope, m_accessType, m_state, m_redirectUri, m_clientId, m_clientSecret; - public slots: - void authenticationNeededCallback(); + void authenticationNeededCallback() override; void onVerificationReceived(const QMap<QString, QString> response); - void onFinish(QNetworkReply *rep); +}; +// Implicit flow +class OauthImplicit : public OauthBase +{ + Q_OBJECT +public: + OauthImplicit(QObject *parent = nullptr); + void link() override; + void unlink() override; + +private: + ReplyServer m_server; + +public slots: + void authenticationNeededCallback() override; + void ImplicitTokenReceived(const QMap<QString, QString> response); }; {{#cppNamespaceDeclarations}} diff --git a/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp b/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp index 2ee6f1b90cb..ed2b99a0a88 100644 --- a/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp @@ -242,6 +242,31 @@ void PFXPetApi::addPet(const PFXPet &body) { emit allPendingRequestsCompleted(); } }); + OauthMethod = 1; + auth.unlink(); + implicit.link(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + auto token = implicit.getToken(scope.join(" ")); + if(token.isValid()) + input.headers.insert("Authorization", "Bearer " + token.getToken()); + + latestWorker = new PFXHttpRequestWorker(this, _manager); + latestWorker->setTimeOut(_timeOut); + latestWorker->setWorkingDirectory(_workingDirectory); + + connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::addPetCallback); + connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); + connect(latestWorker, &QObject::destroyed, [this](){ + if(findChildren<PFXHttpRequestWorker*>().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + latestInput = input; + latestScope = scope; + worker->execute(&input); } @@ -262,6 +287,17 @@ void PFXPetApi::addPetCallback(PFXHttpRequestWorker *worker) { if (worker->error_type == QNetworkReply::NoError) { emit addPetSignal(); emit addPetSignalFull(worker); + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + QString scopeStr = scope.join(" "); + QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); + //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like + implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); + emit implicit.authenticationNeeded(); + } else { emit addPetSignalE(error_type, error_str); emit addPetSignalEFull(worker, error_type, error_str); @@ -306,6 +342,31 @@ void PFXPetApi::deletePet(const qint64 &pet_id, const ::test_namespace::Optional emit allPendingRequestsCompleted(); } }); + OauthMethod = 1; + auth.unlink(); + implicit.link(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + auto token = implicit.getToken(scope.join(" ")); + if(token.isValid()) + input.headers.insert("Authorization", "Bearer " + token.getToken()); + + latestWorker = new PFXHttpRequestWorker(this, _manager); + latestWorker->setTimeOut(_timeOut); + latestWorker->setWorkingDirectory(_workingDirectory); + + connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::deletePetCallback); + connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); + connect(latestWorker, &QObject::destroyed, [this](){ + if(findChildren<PFXHttpRequestWorker*>().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + latestInput = input; + latestScope = scope; + worker->execute(&input); } @@ -326,6 +387,17 @@ void PFXPetApi::deletePetCallback(PFXHttpRequestWorker *worker) { if (worker->error_type == QNetworkReply::NoError) { emit deletePetSignal(); emit deletePetSignalFull(worker); + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + QString scopeStr = scope.join(" "); + QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); + //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like + implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); + emit implicit.authenticationNeeded(); + } else { emit deletePetSignalE(error_type, error_str); emit deletePetSignalEFull(worker, error_type, error_str); @@ -436,6 +508,31 @@ void PFXPetApi::findPetsByStatus(const QList<QString> &status) { emit allPendingRequestsCompleted(); } }); + OauthMethod = 1; + auth.unlink(); + implicit.link(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + auto token = implicit.getToken(scope.join(" ")); + if(token.isValid()) + input.headers.insert("Authorization", "Bearer " + token.getToken()); + + latestWorker = new PFXHttpRequestWorker(this, _manager); + latestWorker->setTimeOut(_timeOut); + latestWorker->setWorkingDirectory(_workingDirectory); + + connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::findPetsByStatusCallback); + connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); + connect(latestWorker, &QObject::destroyed, [this](){ + if(findChildren<PFXHttpRequestWorker*>().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + latestInput = input; + latestScope = scope; + worker->execute(&input); } @@ -466,6 +563,17 @@ void PFXPetApi::findPetsByStatusCallback(PFXHttpRequestWorker *worker) { if (worker->error_type == QNetworkReply::NoError) { emit findPetsByStatusSignal(output); emit findPetsByStatusSignalFull(worker, output); + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + QString scopeStr = scope.join(" "); + QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); + //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like + implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); + emit implicit.authenticationNeeded(); + } else { emit findPetsByStatusSignalE(output, error_type, error_str); emit findPetsByStatusSignalEFull(worker, error_type, error_str); @@ -576,6 +684,31 @@ void PFXPetApi::findPetsByTags(const QList<QString> &tags) { emit allPendingRequestsCompleted(); } }); + OauthMethod = 1; + auth.unlink(); + implicit.link(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + auto token = implicit.getToken(scope.join(" ")); + if(token.isValid()) + input.headers.insert("Authorization", "Bearer " + token.getToken()); + + latestWorker = new PFXHttpRequestWorker(this, _manager); + latestWorker->setTimeOut(_timeOut); + latestWorker->setWorkingDirectory(_workingDirectory); + + connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::findPetsByTagsCallback); + connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); + connect(latestWorker, &QObject::destroyed, [this](){ + if(findChildren<PFXHttpRequestWorker*>().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + latestInput = input; + latestScope = scope; + worker->execute(&input); } @@ -606,6 +739,17 @@ void PFXPetApi::findPetsByTagsCallback(PFXHttpRequestWorker *worker) { if (worker->error_type == QNetworkReply::NoError) { emit findPetsByTagsSignal(output); emit findPetsByTagsSignalFull(worker, output); + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + QString scopeStr = scope.join(" "); + QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); + //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like + implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); + emit implicit.authenticationNeeded(); + } else { emit findPetsByTagsSignalE(output, error_type, error_str); emit findPetsByTagsSignalEFull(worker, error_type, error_str); @@ -697,6 +841,31 @@ void PFXPetApi::updatePet(const PFXPet &body) { emit allPendingRequestsCompleted(); } }); + OauthMethod = 1; + auth.unlink(); + implicit.link(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + auto token = implicit.getToken(scope.join(" ")); + if(token.isValid()) + input.headers.insert("Authorization", "Bearer " + token.getToken()); + + latestWorker = new PFXHttpRequestWorker(this, _manager); + latestWorker->setTimeOut(_timeOut); + latestWorker->setWorkingDirectory(_workingDirectory); + + connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::updatePetCallback); + connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); + connect(latestWorker, &QObject::destroyed, [this](){ + if(findChildren<PFXHttpRequestWorker*>().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + latestInput = input; + latestScope = scope; + worker->execute(&input); } @@ -717,6 +886,17 @@ void PFXPetApi::updatePetCallback(PFXHttpRequestWorker *worker) { if (worker->error_type == QNetworkReply::NoError) { emit updatePetSignal(); emit updatePetSignalFull(worker); + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + QString scopeStr = scope.join(" "); + QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); + //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like + implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); + emit implicit.authenticationNeeded(); + } else { emit updatePetSignalE(error_type, error_str); emit updatePetSignalEFull(worker, error_type, error_str); @@ -763,6 +943,31 @@ void PFXPetApi::updatePetWithForm(const qint64 &pet_id, const ::test_namespace:: emit allPendingRequestsCompleted(); } }); + OauthMethod = 1; + auth.unlink(); + implicit.link(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + auto token = implicit.getToken(scope.join(" ")); + if(token.isValid()) + input.headers.insert("Authorization", "Bearer " + token.getToken()); + + latestWorker = new PFXHttpRequestWorker(this, _manager); + latestWorker->setTimeOut(_timeOut); + latestWorker->setWorkingDirectory(_workingDirectory); + + connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::updatePetWithFormCallback); + connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); + connect(latestWorker, &QObject::destroyed, [this](){ + if(findChildren<PFXHttpRequestWorker*>().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + latestInput = input; + latestScope = scope; + worker->execute(&input); } @@ -783,6 +988,17 @@ void PFXPetApi::updatePetWithFormCallback(PFXHttpRequestWorker *worker) { if (worker->error_type == QNetworkReply::NoError) { emit updatePetWithFormSignal(); emit updatePetWithFormSignalFull(worker); + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + QString scopeStr = scope.join(" "); + QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); + //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like + implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); + emit implicit.authenticationNeeded(); + } else { emit updatePetWithFormSignalE(error_type, error_str); emit updatePetWithFormSignalEFull(worker, error_type, error_str); @@ -829,6 +1045,31 @@ void PFXPetApi::uploadFile(const qint64 &pet_id, const ::test_namespace::Optiona emit allPendingRequestsCompleted(); } }); + OauthMethod = 1; + auth.unlink(); + implicit.link(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + auto token = implicit.getToken(scope.join(" ")); + if(token.isValid()) + input.headers.insert("Authorization", "Bearer " + token.getToken()); + + latestWorker = new PFXHttpRequestWorker(this, _manager); + latestWorker->setTimeOut(_timeOut); + latestWorker->setWorkingDirectory(_workingDirectory); + + connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::uploadFileCallback); + connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); + connect(latestWorker, &QObject::destroyed, [this](){ + if(findChildren<PFXHttpRequestWorker*>().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + latestInput = input; + latestScope = scope; + worker->execute(&input); } @@ -850,6 +1091,17 @@ void PFXPetApi::uploadFileCallback(PFXHttpRequestWorker *worker) { if (worker->error_type == QNetworkReply::NoError) { emit uploadFileSignal(output); emit uploadFileSignalFull(worker, output); + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + QString scopeStr = scope.join(" "); + QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); + //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like + implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); + emit implicit.authenticationNeeded(); + } else { emit uploadFileSignalE(output, error_type, error_str); emit uploadFileSignalEFull(worker, error_type, error_str); @@ -857,15 +1109,32 @@ void PFXPetApi::uploadFileCallback(PFXHttpRequestWorker *worker) { } void PFXPetApi::tokenAvailable(){ - - auto token = auth.getToken(latestScope.join(" ")); - //Only inject header when token is valid. If not we run the auth process again and remove the token - if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); - }else{ - auth.removeToken(latestScope.join(" ")); - qDebug() << "Could not retrieve a valid token"; + + oauthToken token; + switch (OauthMethod) { + case 1: //implicit flow + token = implicit.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + implicit.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 2: //authorization flow + token = auth.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + auth.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + default: + qDebug() << "No Oauth method set!"; + break; } } } // namespace test_namespace diff --git a/samples/client/petstore/cpp-qt/client/PFXPetApi.h b/samples/client/petstore/cpp-qt/client/PFXPetApi.h index 87cef175635..0adf5fb3468 100644 --- a/samples/client/petstore/cpp-qt/client/PFXPetApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXPetApi.h @@ -121,6 +121,9 @@ private: PFXHttpRequestWorker *latestWorker; QStringList latestScope; OauthCode auth; + OauthImplicit implicit; + int OauthMethod = 0; + void addPetCallback(PFXHttpRequestWorker *worker); void deletePetCallback(PFXHttpRequestWorker *worker); diff --git a/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp b/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp index 949428637e2..d1557126104 100644 --- a/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp @@ -437,15 +437,32 @@ void PFXStoreApi::placeOrderCallback(PFXHttpRequestWorker *worker) { } void PFXStoreApi::tokenAvailable(){ - - auto token = auth.getToken(latestScope.join(" ")); - //Only inject header when token is valid. If not we run the auth process again and remove the token - if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); - }else{ - auth.removeToken(latestScope.join(" ")); - qDebug() << "Could not retrieve a valid token"; + + oauthToken token; + switch (OauthMethod) { + case 1: //implicit flow + token = implicit.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + implicit.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 2: //authorization flow + token = auth.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + auth.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + default: + qDebug() << "No Oauth method set!"; + break; } } } // namespace test_namespace diff --git a/samples/client/petstore/cpp-qt/client/PFXStoreApi.h b/samples/client/petstore/cpp-qt/client/PFXStoreApi.h index c970745a72a..3c97ccf4213 100644 --- a/samples/client/petstore/cpp-qt/client/PFXStoreApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXStoreApi.h @@ -93,6 +93,9 @@ private: PFXHttpRequestWorker *latestWorker; QStringList latestScope; OauthCode auth; + OauthImplicit implicit; + int OauthMethod = 0; + void deleteOrderCallback(PFXHttpRequestWorker *worker); void getInventoryCallback(PFXHttpRequestWorker *worker); diff --git a/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp b/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp index ad3a55d9f5b..18630328462 100644 --- a/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp @@ -665,15 +665,32 @@ void PFXUserApi::updateUserCallback(PFXHttpRequestWorker *worker) { } void PFXUserApi::tokenAvailable(){ - - auto token = auth.getToken(latestScope.join(" ")); - //Only inject header when token is valid. If not we run the auth process again and remove the token - if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); - }else{ - auth.removeToken(latestScope.join(" ")); - qDebug() << "Could not retrieve a valid token"; + + oauthToken token; + switch (OauthMethod) { + case 1: //implicit flow + token = implicit.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + implicit.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 2: //authorization flow + token = auth.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + auth.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + default: + qDebug() << "No Oauth method set!"; + break; } } } // namespace test_namespace diff --git a/samples/client/petstore/cpp-qt/client/PFXUserApi.h b/samples/client/petstore/cpp-qt/client/PFXUserApi.h index b8a2c13fcdf..85d52f38e1d 100644 --- a/samples/client/petstore/cpp-qt/client/PFXUserApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXUserApi.h @@ -115,6 +115,9 @@ private: PFXHttpRequestWorker *latestWorker; QStringList latestScope; OauthCode auth; + OauthImplicit implicit; + int OauthMethod = 0; + void createUserCallback(PFXHttpRequestWorker *worker); void createUsersWithArrayInputCallback(PFXHttpRequestWorker *worker); diff --git a/samples/client/petstore/cpp-qt/client/oauth.cpp b/samples/client/petstore/cpp-qt/client/oauth.cpp index 46f5fdc5403..1653b96c0ee 100644 --- a/samples/client/petstore/cpp-qt/client/oauth.cpp +++ b/samples/client/petstore/cpp-qt/client/oauth.cpp @@ -2,15 +2,12 @@ namespace OpenAPI { -OauthCode::OauthCode(QObject *parent) : OauthBase(parent) -{ - connect(&m_server, SIGNAL(dataReceived(QMap<QString,QString>)), this, SLOT(onVerificationReceived(QMap<QString,QString>))); - connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); - connect(this, SIGNAL(tokenReceived()), &m_server, SLOT(stop())); +/* + * Base class to perform oauth2 flows + * + */ -} - -void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType){ +void OauthBase::setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType){ m_authUrl = QUrl(authUrl); m_tokenUrl = QUrl(tokenUrl); @@ -18,9 +15,57 @@ void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, Q m_accessType = accessType; m_state = state; m_redirectUri = redirectUri; - m_clientId = clientId; - m_clientSecret = clientSecret; + m_clientId = clientId; m_clientSecret = clientSecret; + +} + +void OauthBase::onFinish(QNetworkReply *rep) +{ + //TODO emit error signal when token is wrong + QJsonDocument document = QJsonDocument::fromJson(rep->readAll()); + QJsonObject rootObj = document.object(); + QString token = rootObj.find("access_token").value().toString(); + QString scope = rootObj.find("scope").value().toString(); + QString type = rootObj.find("token_type").value().toString(); + int expiresIn = rootObj.find("expires_in").value().toInt(); + addToken(oauthToken(token, expiresIn, scope, type)); +} + +oauthToken OauthBase::getToken(QString scope) +{ + auto tokenIt = m_oauthTokenMap.find(scope); + return tokenIt != m_oauthTokenMap.end() ? tokenIt.value() : oauthToken(); +} + +void OauthBase::addToken(oauthToken token) +{ + m_oauthTokenMap.insert(token.getScope(),token); + emit tokenReceived(); + +} + +void OauthBase::removeToken(QString scope) +{ + m_oauthTokenMap.remove(scope); +} +/* + * Class to perform the authorization code flow + * + */ + +OauthCode::OauthCode(QObject *parent) : OauthBase(parent){} + +void OauthCode::link(){ + connect(&m_server, SIGNAL(dataReceived(QMap<QString,QString>)), this, SLOT(onVerificationReceived(QMap<QString,QString>))); + connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); + connect(this, SIGNAL(tokenReceived()), &m_server, SLOT(stop())); +} + +void OauthCode::unlink() +{ + disconnect(this,0,0,0); + disconnect(&m_server,0,0,0); } void OauthCode::authenticationNeededCallback() @@ -54,36 +99,53 @@ void OauthCode::onVerificationReceived(const QMap<QString, QString> response) { manager->post(request, postData.query().toUtf8()); } -void OauthCode::onFinish(QNetworkReply *rep) +/* + * Class to perform the implicit flow + * + */ + +OauthImplicit::OauthImplicit(QObject *parent) : OauthBase(parent){} + +void OauthImplicit::link() { - //TODO emit error signal when token is wrong - QJsonDocument document = QJsonDocument::fromJson(rep->readAll()); - QJsonObject rootObj = document.object(); - QString token = rootObj.find("access_token").value().toString(); - QString scope = rootObj.find("scope").value().toString(); - QString type = rootObj.find("token_type").value().toString(); - int expiresIn = rootObj.find("expires_in").value().toInt(); + //TODO correct linking + connect(&m_server, SIGNAL(dataReceived(QMap<QString,QString>)), this, SLOT(ImplicitTokenReceived(QMap<QString,QString>))); + connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); + connect(this, SIGNAL(tokenReceived()), &m_server, SLOT(stop())); + m_linked = true; +} - this->m_oauthTokenMap.insert(scope,oauthToken(token, expiresIn, scope, type)); - emit tokenReceived(); +void OauthImplicit::unlink() +{ + disconnect(this,0,0,0); + disconnect(&m_server,0,0,0); + m_linked = false; } -oauthToken OauthBase::getToken(QString scope) +void OauthImplicit::authenticationNeededCallback() { - auto tokenIt = m_oauthTokenMap.find(scope); - return tokenIt != m_oauthTokenMap.end() ? tokenIt.value() : oauthToken(); + QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + (m_accessType=="" ? "" : "&access_type=" + m_accessType) + "&response_type=token" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); + m_server.start(); } -void OauthBase::removeToken(QString scope) +void OauthImplicit::ImplicitTokenReceived(const QMap<QString, QString> response) { - m_oauthTokenMap.remove(scope); + QString token = response.find("access_token").value(); + QString scope = response.find("scope").value(); + QString type = response.find("token_type").value(); + int expiresIn = response.find("expires_in").value().toInt(); + addToken(oauthToken(token, expiresIn, scope, type)); } +/* + * Class that provides a simple reply server + * + */ + ReplyServer::ReplyServer(QObject *parent) : QTcpServer(parent) { connect(this, SIGNAL(newConnection()), this, SLOT(onConnected())); - m_reply = "You can close this window now!"; - + m_reply ="you can close this window now!"; } void ReplyServer::start() @@ -96,7 +158,6 @@ void ReplyServer::start() { qDebug() << "Server started!"; } - } void ReplyServer::stop() @@ -123,7 +184,29 @@ void ReplyServer::read() } qDebug() << "Socket connected"; - socket->write(m_reply); + QTextStream os(socket); + os.setAutoDetectUnicode(true); + os << "HTTP/1.0 200 Ok\r\n" + "Content-Type: text/html; charset=\"utf-8\"\r\n" + "\r\n" + <<"<!DOCTYPE html>\ + <html>\ + <head>\ + <script>\ + window.onload = function hashFunction() {\ + var query = location.hash.substr(1);\ + if (query != \"\") {\ + var xhttp = new XMLHttpRequest();\ + xhttp.open(\"GET\", \"/?\" + query, true);\ + xhttp.send();\ + }\ + }\ + </script>\ + </head>\ + <body>\ + <h2>You can close this window now!</h2>\ + </body>\ + </html>"; QByteArray data = socket->readLine(); QString splitGetLine = QString(data); @@ -147,7 +230,7 @@ void ReplyServer::read() queryParams.insert(key, value); } if (!queryParams.contains("state")) { - socket->write(m_reply); + socket->close(); return; } @@ -155,4 +238,6 @@ void ReplyServer::read() emit dataReceived(queryParams); } -} + + +} \ No newline at end of file diff --git a/samples/client/petstore/cpp-qt/client/oauth.h b/samples/client/petstore/cpp-qt/client/oauth.h index 5ff4038170e..e5e21c376fe 100644 --- a/samples/client/petstore/cpp-qt/client/oauth.h +++ b/samples/client/petstore/cpp-qt/client/oauth.h @@ -48,8 +48,8 @@ public: QString getToken(){return m_token;}; QString getScope(){return m_scope;}; QString getType(){return m_type;}; - bool isValid(){return QDateTime::currentDateTime() < m_validUntil;}; + private: QString m_token; QDateTime m_validUntil; @@ -62,7 +62,7 @@ class ReplyServer : public QTcpServer Q_OBJECT public: explicit ReplyServer(QObject *parent = nullptr); - + void setReply(QByteArray reply){m_reply = reply;}; void run(); private: QByteArray m_reply; @@ -77,42 +77,69 @@ public slots: void stop(); }; +//Base class class OauthBase : public QObject { Q_OBJECT - public: OauthBase(QObject* parent = nullptr) : QObject(parent) {}; oauthToken getToken(QString scope); + void addToken(oauthToken token); void removeToken(QString scope); + void setVariables( QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType = ""); + bool linked(){return m_linked;}; + virtual void link()=0; + virtual void unlink()=0; protected: QMap<QString, oauthToken> m_oauthTokenMap; + QUrl m_authUrl; + QUrl m_tokenUrl; + QString m_scope, m_accessType, m_state, m_redirectUri, m_clientId, m_clientSecret; + bool m_linked; + +public slots: + virtual void authenticationNeededCallback()=0; + void onFinish(QNetworkReply *rep); signals: void authenticationNeeded(); void tokenReceived(); }; +// Authorization code flow class OauthCode : public OauthBase { Q_OBJECT public: OauthCode(QObject *parent = nullptr); - void setVariables( QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType = ""); + void link() override; + void unlink() override; + private: ReplyServer m_server; - QUrl m_authUrl; - QUrl m_tokenUrl; - QString m_scope, m_accessType, m_state, m_redirectUri, m_clientId, m_clientSecret; - public slots: - void authenticationNeededCallback(); + void authenticationNeededCallback() override; void onVerificationReceived(const QMap<QString, QString> response); - void onFinish(QNetworkReply *rep); +}; +// Implicit flow +class OauthImplicit : public OauthBase +{ + Q_OBJECT +public: + OauthImplicit(QObject *parent = nullptr); + void link() override; + void unlink() override; + +private: + ReplyServer m_server; + +public slots: + void authenticationNeededCallback() override; + void ImplicitTokenReceived(const QMap<QString, QString> response); }; } // namespace test_namespace -- GitLab From 1295a222296c67c02f2e8ebaf82a64f8c975ade1 Mon Sep 17 00:00:00 2001 From: Marius Dege <marius.dege@basyskom.com> Date: Mon, 6 Sep 2021 11:07:59 +0200 Subject: [PATCH 5/8] added missing {{prefix}} to Oauth class --- .../codegen/languages/CppQtClientCodegen.java | 8 ++++---- .../src/main/resources/cpp-qt-client/Project.mustache | 4 ++-- .../src/main/resources/cpp-qt-client/api-header.mustache | 2 +- .../src/main/resources/cpp-qt-client/oauth.cpp.mustache | 2 +- samples/client/petstore/cpp-qt/.openapi-generator/FILES | 4 ++-- .../petstore/cpp-qt/client/{oauth.cpp => PFXOauth.cpp} | 2 +- .../client/petstore/cpp-qt/client/{oauth.h => PFXOauth.h} | 0 samples/client/petstore/cpp-qt/client/PFXPetApi.h | 2 +- samples/client/petstore/cpp-qt/client/PFXStoreApi.h | 2 +- samples/client/petstore/cpp-qt/client/PFXUserApi.h | 2 +- samples/client/petstore/cpp-qt/client/PFXclient.pri | 4 ++-- 11 files changed, 16 insertions(+), 16 deletions(-) rename samples/client/petstore/cpp-qt/client/{oauth.cpp => PFXOauth.cpp} (99%) rename samples/client/petstore/cpp-qt/client/{oauth.h => PFXOauth.h} (100%) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java index 1d72e6c16c5..259d5a2f18e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java @@ -98,8 +98,8 @@ public class CppQtClientCodegen extends CppQtAbstractCodegen implements CodegenC supportingFiles.add(new SupportingFile("enum.mustache", sourceFolder, PREFIX + "Enum.h")); supportingFiles.add(new SupportingFile("ServerConfiguration.mustache", sourceFolder, PREFIX + "ServerConfiguration.h")); supportingFiles.add(new SupportingFile("ServerVariable.mustache", sourceFolder, PREFIX + "ServerVariable.h")); - supportingFiles.add(new SupportingFile("oauth.cpp.mustache", sourceFolder, "oauth.cpp")); - supportingFiles.add(new SupportingFile("oauth.h.mustache", sourceFolder, "oauth.h")); + supportingFiles.add(new SupportingFile("oauth.cpp.mustache", sourceFolder, PREFIX + "Oauth.cpp")); + supportingFiles.add(new SupportingFile("oauth.h.mustache", sourceFolder, PREFIX + "Oauth.h")); supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("CMakeLists.txt.mustache", sourceFolder, "CMakeLists.txt")); if (optionalProjectFileFlag) { @@ -131,8 +131,8 @@ public class CppQtClientCodegen extends CppQtAbstractCodegen implements CodegenC supportingFiles.add(new SupportingFile("enum.mustache", sourceFolder, modelNamePrefix + "Enum.h")); supportingFiles.add(new SupportingFile("ServerConfiguration.mustache", sourceFolder, modelNamePrefix + "ServerConfiguration.h")); supportingFiles.add(new SupportingFile("ServerVariable.mustache", sourceFolder, modelNamePrefix + "ServerVariable.h")); - supportingFiles.add(new SupportingFile("oauth.cpp.mustache", sourceFolder, "oauth.cpp")); - supportingFiles.add(new SupportingFile("oauth.h.mustache", sourceFolder, "oauth.h")); + supportingFiles.add(new SupportingFile("oauth.cpp.mustache", sourceFolder, modelNamePrefix + "Oauth.cpp")); + supportingFiles.add(new SupportingFile("oauth.h.mustache", sourceFolder, modelNamePrefix + "Oauth.h")); supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("CMakeLists.txt.mustache", sourceFolder, "CMakeLists.txt")); diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/Project.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/Project.mustache index 69a42e8d576..86d8cb029c3 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/Project.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/Project.mustache @@ -23,7 +23,7 @@ HEADERS += \ $${PWD}/{{prefix}}HttpFileElement.h \ $${PWD}/{{prefix}}ServerConfiguration.h \ $${PWD}/{{prefix}}ServerVariable.h \ - $${PWD}/oauth.h + $${PWD}/{{prefix}}Oauth.h SOURCES += \ # Models @@ -44,4 +44,4 @@ SOURCES += \ $${PWD}/{{prefix}}Helpers.cpp \ $${PWD}/{{prefix}}HttpRequest.cpp \ $${PWD}/{{prefix}}HttpFileElement.cpp \ - $${PWD}/oauth.cpp + $${PWD}/{{prefix}}Oauth.cpp diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache index feb25cf88e7..492bf2cb95e 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache @@ -5,7 +5,7 @@ #include "{{prefix}}Helpers.h" #include "{{prefix}}HttpRequest.h" #include "{{prefix}}ServerConfiguration.h" -#include "oauth.h" +#include "{{prefix}}Oauth.h" {{#imports}}{{{import}}} {{/imports}} diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache index 1653b96c0ee..c6f60a5737a 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache @@ -1,4 +1,4 @@ -#include "oauth.h" +#include "{{prefix}}Oauth.h" namespace OpenAPI { diff --git a/samples/client/petstore/cpp-qt/.openapi-generator/FILES b/samples/client/petstore/cpp-qt/.openapi-generator/FILES index ac2a7a56629..8676f752a6c 100644 --- a/samples/client/petstore/cpp-qt/.openapi-generator/FILES +++ b/samples/client/petstore/cpp-qt/.openapi-generator/FILES @@ -11,6 +11,8 @@ client/PFXHttpFileElement.cpp client/PFXHttpFileElement.h client/PFXHttpRequest.cpp client/PFXHttpRequest.h +client/PFXOauth.cpp +client/PFXOauth.h client/PFXObject.h client/PFXOrder.cpp client/PFXOrder.h @@ -29,5 +31,3 @@ client/PFXUser.h client/PFXUserApi.cpp client/PFXUserApi.h client/PFXclient.pri -client/oauth.cpp -client/oauth.h diff --git a/samples/client/petstore/cpp-qt/client/oauth.cpp b/samples/client/petstore/cpp-qt/client/PFXOauth.cpp similarity index 99% rename from samples/client/petstore/cpp-qt/client/oauth.cpp rename to samples/client/petstore/cpp-qt/client/PFXOauth.cpp index 1653b96c0ee..94462308f9d 100644 --- a/samples/client/petstore/cpp-qt/client/oauth.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXOauth.cpp @@ -1,4 +1,4 @@ -#include "oauth.h" +#include "PFXOauth.h" namespace OpenAPI { diff --git a/samples/client/petstore/cpp-qt/client/oauth.h b/samples/client/petstore/cpp-qt/client/PFXOauth.h similarity index 100% rename from samples/client/petstore/cpp-qt/client/oauth.h rename to samples/client/petstore/cpp-qt/client/PFXOauth.h diff --git a/samples/client/petstore/cpp-qt/client/PFXPetApi.h b/samples/client/petstore/cpp-qt/client/PFXPetApi.h index 0adf5fb3468..f38f67ed3e3 100644 --- a/samples/client/petstore/cpp-qt/client/PFXPetApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXPetApi.h @@ -15,7 +15,7 @@ #include "PFXHelpers.h" #include "PFXHttpRequest.h" #include "PFXServerConfiguration.h" -#include "oauth.h" +#include "PFXOauth.h" #include "PFXApiResponse.h" #include "PFXHttpFileElement.h" diff --git a/samples/client/petstore/cpp-qt/client/PFXStoreApi.h b/samples/client/petstore/cpp-qt/client/PFXStoreApi.h index 3c97ccf4213..d47e0c5287b 100644 --- a/samples/client/petstore/cpp-qt/client/PFXStoreApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXStoreApi.h @@ -15,7 +15,7 @@ #include "PFXHelpers.h" #include "PFXHttpRequest.h" #include "PFXServerConfiguration.h" -#include "oauth.h" +#include "PFXOauth.h" #include "PFXOrder.h" #include <QMap> diff --git a/samples/client/petstore/cpp-qt/client/PFXUserApi.h b/samples/client/petstore/cpp-qt/client/PFXUserApi.h index 85d52f38e1d..0908c23a86e 100644 --- a/samples/client/petstore/cpp-qt/client/PFXUserApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXUserApi.h @@ -15,7 +15,7 @@ #include "PFXHelpers.h" #include "PFXHttpRequest.h" #include "PFXServerConfiguration.h" -#include "oauth.h" +#include "PFXOauth.h" #include "PFXUser.h" #include <QList> diff --git a/samples/client/petstore/cpp-qt/client/PFXclient.pri b/samples/client/petstore/cpp-qt/client/PFXclient.pri index 4e7c0a35495..7271d7055c6 100644 --- a/samples/client/petstore/cpp-qt/client/PFXclient.pri +++ b/samples/client/petstore/cpp-qt/client/PFXclient.pri @@ -20,7 +20,7 @@ HEADERS += \ $${PWD}/PFXHttpFileElement.h \ $${PWD}/PFXServerConfiguration.h \ $${PWD}/PFXServerVariable.h \ - $${PWD}/oauth.h + $${PWD}/PFXOauth.h SOURCES += \ # Models @@ -38,4 +38,4 @@ SOURCES += \ $${PWD}/PFXHelpers.cpp \ $${PWD}/PFXHttpRequest.cpp \ $${PWD}/PFXHttpFileElement.cpp \ - $${PWD}/oauth.cpp + $${PWD}/PFXOauth.cpp -- GitLab From 6b3d1f76cdc1ff4a4d5998da6fd615f8f03f440e Mon Sep 17 00:00:00 2001 From: Marius Dege <marius.dege@basyskom.com> Date: Fri, 29 Oct 2021 13:27:29 +0200 Subject: [PATCH 6/8] added client credentials flow --- docs/generators/cpp-qt-client.md | 2 +- .../codegen/languages/CppQtClientCodegen.java | 1 + .../resources/cpp-qt-client/api-body.mustache | 59 ++++++++++++++++++- .../cpp-qt-client/api-header.mustache | 1 + .../cpp-qt-client/oauth.cpp.mustache | 36 +++++++++++ .../resources/cpp-qt-client/oauth.h.mustache | 14 +++++ .../petstore/cpp-qt/client/PFXOauth.cpp | 36 +++++++++++ .../client/petstore/cpp-qt/client/PFXOauth.h | 14 +++++ .../petstore/cpp-qt/client/PFXPetApi.cpp | 45 +++++++++----- .../client/petstore/cpp-qt/client/PFXPetApi.h | 1 + .../petstore/cpp-qt/client/PFXStoreApi.cpp | 10 ++++ .../petstore/cpp-qt/client/PFXStoreApi.h | 1 + .../petstore/cpp-qt/client/PFXUserApi.cpp | 10 ++++ .../petstore/cpp-qt/client/PFXUserApi.h | 1 + 14 files changed, 213 insertions(+), 18 deletions(-) diff --git a/docs/generators/cpp-qt-client.md b/docs/generators/cpp-qt-client.md index 480ebfbfc41..28c5f874c26 100644 --- a/docs/generators/cpp-qt-client.md +++ b/docs/generators/cpp-qt-client.md @@ -238,7 +238,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |BearerToken|✓|OAS3 |OAuth2_Implicit|✓|OAS2,OAS3 |OAuth2_Password|✗|OAS2,OAS3 -|OAuth2_ClientCredentials|✗|OAS2,OAS3 +|OAuth2_ClientCredentials|✓|OAS2,OAS3 |OAuth2_AuthorizationCode|✓|OAS2,OAS3 ### Wire Format Feature diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java index 259d5a2f18e..91daa7828ed 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java @@ -48,6 +48,7 @@ public class CppQtClientCodegen extends CppQtAbstractCodegen implements CodegenC .includeSecurityFeatures(SecurityFeature.BearerToken) .includeSecurityFeatures(SecurityFeature.OAuth2_AuthorizationCode) .includeSecurityFeatures(SecurityFeature.OAuth2_Implicit) + .includeSecurityFeatures(SecurityFeature.OAuth2_ClientCredentials) .includeGlobalFeatures(GlobalFeature.ParameterStyling) ); diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache index a90bed1f397..6750c6c46e3 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache @@ -664,6 +664,7 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} });{{#authMethods}}{{#isOAuth}}{{#isCode}} OauthMethod = 2; implicit.unlink(); + credential.unlink(); auth.link(); QStringList scope; {{#scopes}} @@ -692,6 +693,7 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} {{#isImplicit}} OauthMethod = 1; auth.unlink(); + credential.unlink(); implicit.link(); QStringList scope; {{#scopes}} @@ -715,9 +717,38 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} } }); + latestInput = input; + latestScope = scope;{{/isImplicit}} + {{#isApplication}} + OauthMethod = 1; + auth.unlink(); + implicit.unlink(); + credential.link(); + QStringList scope; + {{#scopes}} + scope.append("{{scope}}"); + {{/scopes}} + auto token = credential.getToken(scope.join(" ")); + if(token.isValid()) + input.headers.insert("Authorization", "Bearer " + token.getToken()); + + latestWorker = new {{prefix}}HttpRequestWorker(this, _manager); + latestWorker->setTimeOut(_timeOut); + latestWorker->setWorkingDirectory(_workingDirectory);{{#contentCompression}} + latestWorker->setResponseCompressionEnabled(isResponseCompressionEnabled); + latestWorker->setRequestCompressionEnabled(isRequestCompressionEnabled);{{/contentCompression}} + + connect(latestWorker, &{{prefix}}HttpRequestWorker::on_execution_finished, this, &{{classname}}::{{nickname}}Callback); + connect(this, &{{classname}}::abortRequestsSignal, latestWorker, &QObject::deleteLater); + connect(latestWorker, &QObject::destroyed, [this](){ + if(findChildren<{{prefix}}HttpRequestWorker*>().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + latestInput = input; latestScope = scope; - {{/isImplicit}}{{/isOAuth}}{{/authMethods}} + {{/isApplication}}{{/isOAuth}}{{/authMethods}} worker->execute(&input); } @@ -800,8 +831,20 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { QString authorizationUrl("{{authorizationUrl}}"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); - emit implicit.authenticationNeeded(); - {{/isImplicit}}{{/isOAuth}}{{/authMethods}} + emit implicit.authenticationNeeded();{{/isImplicit}} + {{#isApplication}} + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + connect(&credential, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + QStringList scope; + {{#scopes}} + scope.append("{{scope}}"); + {{/scopes}} + QString scopeStr = scope.join(" "); + QString tokenUrl("{{tokenUrl}}"); + //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like + credential.setVariables("", tokenUrl , scopeStr, "state" , "", "clientId", "clientSecret"); + emit credential.authenticationNeeded(); + {{/isApplication}}{{/isOAuth}}{{/authMethods}} } else { emit {{nickname}}SignalE({{#returnType}}output, {{/returnType}}error_type, error_str); emit {{nickname}}SignalEFull(worker, error_type, error_str); @@ -834,6 +877,16 @@ void {{classname}}::tokenAvailable(){ qDebug() << "Could not retreive a valid token"; } break; + case 3: //client credentials flow + token = credential.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + credential.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; default: qDebug() << "No Oauth method set!"; break; diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache index 492bf2cb95e..0b962b2632b 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache @@ -79,6 +79,7 @@ private: QStringList latestScope; OauthCode auth; OauthImplicit implicit; + OauthCredentials credential; int OauthMethod = 0; {{#operations}}{{#operation}} diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache index c6f60a5737a..0b90ad1eab8 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache @@ -137,6 +137,42 @@ void OauthImplicit::ImplicitTokenReceived(const QMap<QString, QString> response) addToken(oauthToken(token, expiresIn, scope, type)); } + +/* + * Class to perform the client credentials flow + * + */ +OauthCredentials::OauthCredentials(QObject *parent) : OauthBase(parent){} +void OauthCredentials::link() +{ + connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); +} + +void OauthCredentials::unlink() +{ + disconnect(this,0,0,0); +} + +void OauthCredentials::authenticationNeededCallback() +{ + //create query with the required fields + QUrlQuery postData; + postData.addQueryItem("grant_type", "client_credentials"); + postData.addQueryItem("client_id", m_clientId); + postData.addQueryItem("client_secret", m_clientSecret); + postData.addQueryItem("scope", m_scope); + QNetworkAccessManager * manager = new QNetworkAccessManager(this); + + QNetworkRequest request(m_tokenUrl); + + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + + connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinish(QNetworkReply *))); + + manager->post(request, postData.query().toUtf8()); +} + + /* * Class that provides a simple reply server * diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache index 35fb922b542..2fb30ba1f7d 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache @@ -134,6 +134,20 @@ public slots: void ImplicitTokenReceived(const QMap<QString, QString> response); }; +//client credentials flow +class OauthCredentials : public OauthBase +{ + Q_OBJECT +public: + OauthCredentials(QObject *parent = nullptr); + void link() override; + void unlink() override; + +public slots: + void authenticationNeededCallback() override; + +}; + {{#cppNamespaceDeclarations}} } // namespace {{this}} {{/cppNamespaceDeclarations}} diff --git a/samples/client/petstore/cpp-qt/client/PFXOauth.cpp b/samples/client/petstore/cpp-qt/client/PFXOauth.cpp index 94462308f9d..535d9681577 100644 --- a/samples/client/petstore/cpp-qt/client/PFXOauth.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXOauth.cpp @@ -137,6 +137,42 @@ void OauthImplicit::ImplicitTokenReceived(const QMap<QString, QString> response) addToken(oauthToken(token, expiresIn, scope, type)); } + +/* + * Class to perform the client credentials flow + * + */ +OauthCredentials::OauthCredentials(QObject *parent) : OauthBase(parent){} +void OauthCredentials::link() +{ + connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); +} + +void OauthCredentials::unlink() +{ + disconnect(this,0,0,0); +} + +void OauthCredentials::authenticationNeededCallback() +{ + //create query with the required fields + QUrlQuery postData; + postData.addQueryItem("grant_type", "client_credentials"); + postData.addQueryItem("client_id", m_clientId); + postData.addQueryItem("client_secret", m_clientSecret); + postData.addQueryItem("scope", m_scope); + QNetworkAccessManager * manager = new QNetworkAccessManager(this); + + QNetworkRequest request(m_tokenUrl); + + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + + connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinish(QNetworkReply *))); + + manager->post(request, postData.query().toUtf8()); +} + + /* * Class that provides a simple reply server * diff --git a/samples/client/petstore/cpp-qt/client/PFXOauth.h b/samples/client/petstore/cpp-qt/client/PFXOauth.h index e5e21c376fe..4dd3bb23c01 100644 --- a/samples/client/petstore/cpp-qt/client/PFXOauth.h +++ b/samples/client/petstore/cpp-qt/client/PFXOauth.h @@ -142,5 +142,19 @@ public slots: void ImplicitTokenReceived(const QMap<QString, QString> response); }; +//client credentials flow +class OauthCredentials : public OauthBase +{ + Q_OBJECT +public: + OauthCredentials(QObject *parent = nullptr); + void link() override; + void unlink() override; + +public slots: + void authenticationNeededCallback() override; + +}; + } // namespace test_namespace #endif // PFX_OAUTH2_H diff --git a/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp b/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp index ed2b99a0a88..9f5dec44305 100644 --- a/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp @@ -244,6 +244,7 @@ void PFXPetApi::addPet(const PFXPet &body) { }); OauthMethod = 1; auth.unlink(); + credential.unlink(); implicit.link(); QStringList scope; scope.append("write:pets"); @@ -266,7 +267,7 @@ void PFXPetApi::addPet(const PFXPet &body) { latestInput = input; latestScope = scope; - + worker->execute(&input); } @@ -297,7 +298,7 @@ void PFXPetApi::addPetCallback(PFXHttpRequestWorker *worker) { //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); emit implicit.authenticationNeeded(); - + } else { emit addPetSignalE(error_type, error_str); emit addPetSignalEFull(worker, error_type, error_str); @@ -344,6 +345,7 @@ void PFXPetApi::deletePet(const qint64 &pet_id, const ::test_namespace::Optional }); OauthMethod = 1; auth.unlink(); + credential.unlink(); implicit.link(); QStringList scope; scope.append("write:pets"); @@ -366,7 +368,7 @@ void PFXPetApi::deletePet(const qint64 &pet_id, const ::test_namespace::Optional latestInput = input; latestScope = scope; - + worker->execute(&input); } @@ -397,7 +399,7 @@ void PFXPetApi::deletePetCallback(PFXHttpRequestWorker *worker) { //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); emit implicit.authenticationNeeded(); - + } else { emit deletePetSignalE(error_type, error_str); emit deletePetSignalEFull(worker, error_type, error_str); @@ -510,6 +512,7 @@ void PFXPetApi::findPetsByStatus(const QList<QString> &status) { }); OauthMethod = 1; auth.unlink(); + credential.unlink(); implicit.link(); QStringList scope; scope.append("write:pets"); @@ -532,7 +535,7 @@ void PFXPetApi::findPetsByStatus(const QList<QString> &status) { latestInput = input; latestScope = scope; - + worker->execute(&input); } @@ -573,7 +576,7 @@ void PFXPetApi::findPetsByStatusCallback(PFXHttpRequestWorker *worker) { //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); emit implicit.authenticationNeeded(); - + } else { emit findPetsByStatusSignalE(output, error_type, error_str); emit findPetsByStatusSignalEFull(worker, error_type, error_str); @@ -686,6 +689,7 @@ void PFXPetApi::findPetsByTags(const QList<QString> &tags) { }); OauthMethod = 1; auth.unlink(); + credential.unlink(); implicit.link(); QStringList scope; scope.append("write:pets"); @@ -708,7 +712,7 @@ void PFXPetApi::findPetsByTags(const QList<QString> &tags) { latestInput = input; latestScope = scope; - + worker->execute(&input); } @@ -749,7 +753,7 @@ void PFXPetApi::findPetsByTagsCallback(PFXHttpRequestWorker *worker) { //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); emit implicit.authenticationNeeded(); - + } else { emit findPetsByTagsSignalE(output, error_type, error_str); emit findPetsByTagsSignalEFull(worker, error_type, error_str); @@ -843,6 +847,7 @@ void PFXPetApi::updatePet(const PFXPet &body) { }); OauthMethod = 1; auth.unlink(); + credential.unlink(); implicit.link(); QStringList scope; scope.append("write:pets"); @@ -865,7 +870,7 @@ void PFXPetApi::updatePet(const PFXPet &body) { latestInput = input; latestScope = scope; - + worker->execute(&input); } @@ -896,7 +901,7 @@ void PFXPetApi::updatePetCallback(PFXHttpRequestWorker *worker) { //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); emit implicit.authenticationNeeded(); - + } else { emit updatePetSignalE(error_type, error_str); emit updatePetSignalEFull(worker, error_type, error_str); @@ -945,6 +950,7 @@ void PFXPetApi::updatePetWithForm(const qint64 &pet_id, const ::test_namespace:: }); OauthMethod = 1; auth.unlink(); + credential.unlink(); implicit.link(); QStringList scope; scope.append("write:pets"); @@ -967,7 +973,7 @@ void PFXPetApi::updatePetWithForm(const qint64 &pet_id, const ::test_namespace:: latestInput = input; latestScope = scope; - + worker->execute(&input); } @@ -998,7 +1004,7 @@ void PFXPetApi::updatePetWithFormCallback(PFXHttpRequestWorker *worker) { //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); emit implicit.authenticationNeeded(); - + } else { emit updatePetWithFormSignalE(error_type, error_str); emit updatePetWithFormSignalEFull(worker, error_type, error_str); @@ -1047,6 +1053,7 @@ void PFXPetApi::uploadFile(const qint64 &pet_id, const ::test_namespace::Optiona }); OauthMethod = 1; auth.unlink(); + credential.unlink(); implicit.link(); QStringList scope; scope.append("write:pets"); @@ -1069,7 +1076,7 @@ void PFXPetApi::uploadFile(const qint64 &pet_id, const ::test_namespace::Optiona latestInput = input; latestScope = scope; - + worker->execute(&input); } @@ -1101,7 +1108,7 @@ void PFXPetApi::uploadFileCallback(PFXHttpRequestWorker *worker) { //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); emit implicit.authenticationNeeded(); - + } else { emit uploadFileSignalE(output, error_type, error_str); emit uploadFileSignalEFull(worker, error_type, error_str); @@ -1132,6 +1139,16 @@ void PFXPetApi::tokenAvailable(){ qDebug() << "Could not retreive a valid token"; } break; + case 3: //client credentials flow + token = credential.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + credential.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; default: qDebug() << "No Oauth method set!"; break; diff --git a/samples/client/petstore/cpp-qt/client/PFXPetApi.h b/samples/client/petstore/cpp-qt/client/PFXPetApi.h index f38f67ed3e3..2aa185a77a7 100644 --- a/samples/client/petstore/cpp-qt/client/PFXPetApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXPetApi.h @@ -122,6 +122,7 @@ private: QStringList latestScope; OauthCode auth; OauthImplicit implicit; + OauthCredentials credential; int OauthMethod = 0; diff --git a/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp b/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp index d1557126104..f306471cbf3 100644 --- a/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp @@ -460,6 +460,16 @@ void PFXStoreApi::tokenAvailable(){ qDebug() << "Could not retreive a valid token"; } break; + case 3: //client credentials flow + token = credential.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + credential.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; default: qDebug() << "No Oauth method set!"; break; diff --git a/samples/client/petstore/cpp-qt/client/PFXStoreApi.h b/samples/client/petstore/cpp-qt/client/PFXStoreApi.h index d47e0c5287b..0b27cbc1ecb 100644 --- a/samples/client/petstore/cpp-qt/client/PFXStoreApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXStoreApi.h @@ -94,6 +94,7 @@ private: QStringList latestScope; OauthCode auth; OauthImplicit implicit; + OauthCredentials credential; int OauthMethod = 0; diff --git a/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp b/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp index 18630328462..72250911c82 100644 --- a/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp @@ -688,6 +688,16 @@ void PFXUserApi::tokenAvailable(){ qDebug() << "Could not retreive a valid token"; } break; + case 3: //client credentials flow + token = credential.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + credential.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; default: qDebug() << "No Oauth method set!"; break; diff --git a/samples/client/petstore/cpp-qt/client/PFXUserApi.h b/samples/client/petstore/cpp-qt/client/PFXUserApi.h index 0908c23a86e..0d964be6b33 100644 --- a/samples/client/petstore/cpp-qt/client/PFXUserApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXUserApi.h @@ -116,6 +116,7 @@ private: QStringList latestScope; OauthCode auth; OauthImplicit implicit; + OauthCredentials credential; int OauthMethod = 0; -- GitLab From f9b6c33578b81752accbd2fbe775106d2f5b9d75 Mon Sep 17 00:00:00 2001 From: Marius Dege <marius.dege@basyskom.com> Date: Mon, 1 Nov 2021 17:00:39 +0100 Subject: [PATCH 7/8] added password flow. setVariables for each class --- docs/generators/cpp-qt-client.md | 2 +- .../codegen/languages/CppQtClientCodegen.java | 1 + .../resources/cpp-qt-client/api-body.mustache | 67 ++++++++++++-- .../cpp-qt-client/api-header.mustache | 1 + .../cpp-qt-client/oauth.cpp.mustache | 90 ++++++++++++++++--- .../resources/cpp-qt-client/oauth.h.mustache | 23 ++++- 6 files changed, 165 insertions(+), 19 deletions(-) diff --git a/docs/generators/cpp-qt-client.md b/docs/generators/cpp-qt-client.md index 28c5f874c26..96be28abb0a 100644 --- a/docs/generators/cpp-qt-client.md +++ b/docs/generators/cpp-qt-client.md @@ -237,7 +237,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |OpenIDConnect|✗|OAS3 |BearerToken|✓|OAS3 |OAuth2_Implicit|✓|OAS2,OAS3 -|OAuth2_Password|✗|OAS2,OAS3 +|OAuth2_Password|✓|OAS2,OAS3 |OAuth2_ClientCredentials|✓|OAS2,OAS3 |OAuth2_AuthorizationCode|✓|OAS2,OAS3 diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java index 91daa7828ed..5aa46278a9c 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppQtClientCodegen.java @@ -49,6 +49,7 @@ public class CppQtClientCodegen extends CppQtAbstractCodegen implements CodegenC .includeSecurityFeatures(SecurityFeature.OAuth2_AuthorizationCode) .includeSecurityFeatures(SecurityFeature.OAuth2_Implicit) .includeSecurityFeatures(SecurityFeature.OAuth2_ClientCredentials) + .includeSecurityFeatures(SecurityFeature.OAuth2_Password) .includeGlobalFeatures(GlobalFeature.ParameterStyling) ); diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache index 6750c6c46e3..68d191bc8ad 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache @@ -665,6 +665,7 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} OauthMethod = 2; implicit.unlink(); credential.unlink(); + passwordFlow.unlink(); auth.link(); QStringList scope; {{#scopes}} @@ -694,6 +695,7 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} OauthMethod = 1; auth.unlink(); credential.unlink(); + passwordFlow.unlink(); implicit.link(); QStringList scope; {{#scopes}} @@ -720,9 +722,10 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} latestInput = input; latestScope = scope;{{/isImplicit}} {{#isApplication}} - OauthMethod = 1; + OauthMethod = 3; auth.unlink(); implicit.unlink(); + passwordFlow.unlink(); credential.link(); QStringList scope; {{#scopes}} @@ -746,9 +749,39 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} } }); + latestInput = input; + latestScope = scope;{{/isApplication}} + {{#isPassword}} + OauthMethod = 4; + auth.unlink(); + implicit.unlink(); + credential.unlink(); + passwordFlow.link(); + QStringList scope; + {{#scopes}} + scope.append("{{scope}}"); + {{/scopes}} + auto token = passwordFlow.getToken(scope.join(" ")); + if(token.isValid()) + input.headers.insert("Authorization", "Bearer " + token.getToken()); + + latestWorker = new {{prefix}}HttpRequestWorker(this, _manager); + latestWorker->setTimeOut(_timeOut); + latestWorker->setWorkingDirectory(_workingDirectory);{{#contentCompression}} + latestWorker->setResponseCompressionEnabled(isResponseCompressionEnabled); + latestWorker->setRequestCompressionEnabled(isRequestCompressionEnabled);{{/contentCompression}} + + connect(latestWorker, &{{prefix}}HttpRequestWorker::on_execution_finished, this, &{{classname}}::{{nickname}}Callback); + connect(this, &{{classname}}::abortRequestsSignal, latestWorker, &QObject::deleteLater); + connect(latestWorker, &QObject::destroyed, [this](){ + if(findChildren<{{prefix}}HttpRequestWorker*>().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + latestInput = input; latestScope = scope; - {{/isApplication}}{{/isOAuth}}{{/authMethods}} + {{/isPassword}}{{/isOAuth}}{{/authMethods}} worker->execute(&input); } @@ -830,7 +863,7 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { QString scopeStr = scope.join(" "); QString authorizationUrl("{{authorizationUrl}}"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); + implicit.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); emit implicit.authenticationNeeded();{{/isImplicit}} {{#isApplication}} } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ @@ -842,9 +875,21 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { QString scopeStr = scope.join(" "); QString tokenUrl("{{tokenUrl}}"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - credential.setVariables("", tokenUrl , scopeStr, "state" , "", "clientId", "clientSecret"); - emit credential.authenticationNeeded(); - {{/isApplication}}{{/isOAuth}}{{/authMethods}} + credential.setVariables(tokenUrl , scopeStr, "clientId", "clientSecret"); + emit credential.authenticationNeeded();{{/isApplication}} + {{#isPassword}} + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + connect(&passwordFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + QStringList scope; + {{#scopes}} + scope.append("{{scope}}"); + {{/scopes}} + QString scopeStr = scope.join(" "); + QString tokenUrl("{{tokenUrl}}"); + //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like + passwordFlow.setVariables(tokenUrl , scopeStr ,"clientId", "clientSecret", "username", "password"); + emit passwordFlow.authenticationNeeded(); + {{/isPassword}}{{/isOAuth}}{{/authMethods}} } else { emit {{nickname}}SignalE({{#returnType}}output, {{/returnType}}error_type, error_str); emit {{nickname}}SignalEFull(worker, error_type, error_str); @@ -887,6 +932,16 @@ void {{classname}}::tokenAvailable(){ qDebug() << "Could not retreive a valid token"; } break; + case 4: //resource owner password flow + token = passwordFlow.getToken(latestScope.join(" ")); + if(token.isValid()){ + latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + latestWorker->execute(&latestInput); + }else{ + credential.removeToken(latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; default: qDebug() << "No Oauth method set!"; break; diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache index 0b962b2632b..f4ae1684d42 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache @@ -80,6 +80,7 @@ private: OauthCode auth; OauthImplicit implicit; OauthCredentials credential; + OauthPassword passwordFlow; int OauthMethod = 0; {{#operations}}{{#operation}} diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache index 0b90ad1eab8..ebe53654851 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache @@ -7,17 +7,6 @@ namespace OpenAPI { * */ -void OauthBase::setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType){ - - m_authUrl = QUrl(authUrl); - m_tokenUrl = QUrl(tokenUrl); - m_scope = scope; - m_accessType = accessType; - m_state = state; - m_redirectUri = redirectUri; - m_clientId = clientId; m_clientSecret = clientSecret; - -} void OauthBase::onFinish(QNetworkReply *rep) { @@ -68,6 +57,19 @@ void OauthCode::unlink() disconnect(&m_server,0,0,0); } +void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType){ + + m_authUrl = QUrl(authUrl); + m_tokenUrl = QUrl(tokenUrl); + m_scope = scope; + m_accessType = accessType; + m_state = state; + m_redirectUri = redirectUri; + m_clientId = clientId; + m_clientSecret = clientSecret; + +} + void OauthCode::authenticationNeededCallback() { QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + (m_accessType=="" ? "" : "&access_type=" + m_accessType) + "&response_type=code" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); @@ -122,6 +124,17 @@ void OauthImplicit::unlink() m_linked = false; } +void OauthImplicit::setVariables(QString authUrl, QString scope, QString state, QString redirectUri, QString clientId, QString accessType){ + + m_authUrl = QUrl(authUrl); + m_scope = scope; + m_accessType = accessType; + m_state = state; + m_redirectUri = redirectUri; + m_clientId = clientId; + +} + void OauthImplicit::authenticationNeededCallback() { QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + (m_accessType=="" ? "" : "&access_type=" + m_accessType) + "&response_type=token" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); @@ -153,6 +166,15 @@ void OauthCredentials::unlink() disconnect(this,0,0,0); } +void OauthCredentials::setVariables(QString tokenUrl, QString scope, QString clientId, QString clientSecret){ + + m_tokenUrl = QUrl(tokenUrl); + m_scope = scope; + m_clientId = clientId; + m_clientSecret = clientSecret; + +} + void OauthCredentials::authenticationNeededCallback() { //create query with the required fields @@ -172,6 +194,52 @@ void OauthCredentials::authenticationNeededCallback() manager->post(request, postData.query().toUtf8()); } +/* + * Class to perform the resource owner password flow + * + */ +OauthPassword::OauthPassword(QObject *parent) : OauthBase(parent){} +void OauthPassword::link() +{ + connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); +} + +void OauthPassword::unlink() +{ + disconnect(this,0,0,0); +} + +void OauthPassword::setVariables(QString tokenUrl, QString scope, QString clientId, QString clientSecret, QString username, QString password){ + + m_tokenUrl = QUrl(tokenUrl); + m_scope = scope; + m_clientId = clientId; + m_clientSecret = clientSecret; + m_username = username; + m_password = password; + +} +void OauthPassword::authenticationNeededCallback() +{ + //create query with the required fields + QUrlQuery postData; + postData.addQueryItem("grant_type", "password"); + postData.addQueryItem("username", m_username); + postData.addQueryItem("password", m_password); + postData.addQueryItem("client_id", m_clientId); + postData.addQueryItem("client_secret", m_clientSecret); + postData.addQueryItem("scope", m_scope); + QNetworkAccessManager * manager = new QNetworkAccessManager(this); + + QNetworkRequest request(m_tokenUrl); + + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + + connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinish(QNetworkReply *))); + + manager->post(request, postData.query().toUtf8()); +} + /* * Class that provides a simple reply server diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache index 2fb30ba1f7d..03aa0dde901 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache @@ -78,7 +78,6 @@ public: oauthToken getToken(QString scope); void addToken(oauthToken token); void removeToken(QString scope); - void setVariables( QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType = ""); bool linked(){return m_linked;}; virtual void link()=0; virtual void unlink()=0; @@ -107,6 +106,7 @@ public: OauthCode(QObject *parent = nullptr); void link() override; void unlink() override; + void setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType = ""); private: ReplyServer m_server; @@ -125,6 +125,7 @@ public: OauthImplicit(QObject *parent = nullptr); void link() override; void unlink() override; + void setVariables(QString authUrl, QString scope, QString state, QString redirectUri, QString clientId, QString accessType = ""); private: ReplyServer m_server; @@ -142,12 +143,32 @@ public: OauthCredentials(QObject *parent = nullptr); void link() override; void unlink() override; + void setVariables(QString tokenUrl, QString scope, QString clientId, QString clientSecret); public slots: void authenticationNeededCallback() override; }; +//resource owner password flow +class OauthPassword : public OauthBase +{ + Q_OBJECT +public: + OauthPassword(QObject *parent = nullptr); + void link() override; + void unlink() override; + void setVariables(QString tokenUrl, QString scope, QString clientId, QString clientSecret, QString username, QString password); + +private: + QString m_username, m_password; + +public slots: + void authenticationNeededCallback() override; + +}; + + {{#cppNamespaceDeclarations}} } // namespace {{this}} {{/cppNamespaceDeclarations}} -- GitLab From fe323aa90b666771da42129380e49bd4842babc8 Mon Sep 17 00:00:00 2001 From: Marius Dege <marius.dege@basyskom.com> Date: Tue, 2 Nov 2021 10:37:33 +0100 Subject: [PATCH 8/8] Refactored variables to fit style. Updated Samples --- .../resources/cpp-qt-client/api-body.mustache | 186 ++++++------ .../cpp-qt-client/api-header.mustache | 16 +- .../petstore/cpp-qt/client/PFXOauth.cpp | 90 +++++- .../client/petstore/cpp-qt/client/PFXOauth.h | 23 +- .../petstore/cpp-qt/client/PFXPetApi.cpp | 281 ++++++++++-------- .../client/petstore/cpp-qt/client/PFXPetApi.h | 15 +- .../petstore/cpp-qt/client/PFXStoreApi.cpp | 36 ++- .../petstore/cpp-qt/client/PFXStoreApi.h | 15 +- .../petstore/cpp-qt/client/PFXUserApi.cpp | 36 ++- .../petstore/cpp-qt/client/PFXUserApi.h | 15 +- 10 files changed, 428 insertions(+), 285 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache index a7b575a2267..23ce15ffe5e 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-body.mustache @@ -679,125 +679,125 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} emit allPendingRequestsCompleted(); } });{{#authMethods}}{{#isOAuth}}{{#isCode}} - OauthMethod = 2; - implicit.unlink(); - credential.unlink(); - passwordFlow.unlink(); - auth.link(); + _OauthMethod = 2; + _implicitFlow.unlink(); + _credentialFlow.unlink(); + _passwordFlow.unlink(); + _authFlow.link(); QStringList scope; {{#scopes}} scope.append("{{scope}}"); {{/scopes}} - auto token = auth.getToken(scope.join(" ")); + auto token = _authFlow.getToken(scope.join(" ")); if(token.isValid()) input.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker = new {{prefix}}HttpRequestWorker(this, _manager); - latestWorker->setTimeOut(_timeOut); - latestWorker->setWorkingDirectory(_workingDirectory);{{#contentCompression}} - latestWorker->setResponseCompressionEnabled(isResponseCompressionEnabled); - latestWorker->setRequestCompressionEnabled(isRequestCompressionEnabled);{{/contentCompression}} + _latestWorker = new {{prefix}}HttpRequestWorker(this, _manager); + _latestWorker->setTimeOut(_timeOut); + _latestWorker->setWorkingDirectory(_workingDirectory);{{#contentCompression}} + _latestWorker->setResponseCompressionEnabled(isResponseCompressionEnabled); + _latestWorker->setRequestCompressionEnabled(isRequestCompressionEnabled);{{/contentCompression}} - connect(latestWorker, &{{prefix}}HttpRequestWorker::on_execution_finished, this, &{{classname}}::{{nickname}}Callback); - connect(this, &{{classname}}::abortRequestsSignal, latestWorker, &QObject::deleteLater); - connect(latestWorker, &QObject::destroyed, [this](){ + connect(_latestWorker, &{{prefix}}HttpRequestWorker::on_execution_finished, this, &{{classname}}::{{nickname}}Callback); + connect(this, &{{classname}}::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ if(findChildren<{{prefix}}HttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } }); - latestInput = input; - latestScope = scope;{{/isCode}} + _latestInput = input; + _latestScope = scope;{{/isCode}} {{#isImplicit}} - OauthMethod = 1; - auth.unlink(); - credential.unlink(); - passwordFlow.unlink(); - implicit.link(); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); QStringList scope; {{#scopes}} scope.append("{{scope}}"); {{/scopes}} - auto token = implicit.getToken(scope.join(" ")); + auto token = _implicitFlow.getToken(scope.join(" ")); if(token.isValid()) input.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker = new {{prefix}}HttpRequestWorker(this, _manager); - latestWorker->setTimeOut(_timeOut); - latestWorker->setWorkingDirectory(_workingDirectory);{{#contentCompression}} - latestWorker->setResponseCompressionEnabled(isResponseCompressionEnabled); - latestWorker->setRequestCompressionEnabled(isRequestCompressionEnabled);{{/contentCompression}} + _latestWorker = new {{prefix}}HttpRequestWorker(this, _manager); + _latestWorker->setTimeOut(_timeOut); + _latestWorker->setWorkingDirectory(_workingDirectory);{{#contentCompression}} + _latestWorker->setResponseCompressionEnabled(isResponseCompressionEnabled); + _latestWorker->setRequestCompressionEnabled(isRequestCompressionEnabled);{{/contentCompression}} - connect(latestWorker, &{{prefix}}HttpRequestWorker::on_execution_finished, this, &{{classname}}::{{nickname}}Callback); - connect(this, &{{classname}}::abortRequestsSignal, latestWorker, &QObject::deleteLater); - connect(latestWorker, &QObject::destroyed, [this](){ + connect(_latestWorker, &{{prefix}}HttpRequestWorker::on_execution_finished, this, &{{classname}}::{{nickname}}Callback); + connect(this, &{{classname}}::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ if(findChildren<{{prefix}}HttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } }); - latestInput = input; - latestScope = scope;{{/isImplicit}} + _latestInput = input; + _latestScope = scope;{{/isImplicit}} {{#isApplication}} - OauthMethod = 3; - auth.unlink(); - implicit.unlink(); - passwordFlow.unlink(); - credential.link(); + _OauthMethod = 3; + _authFlow.unlink(); + _implicitFlow.unlink(); + _passwordFlow.unlink(); + _credentialFlow.link(); QStringList scope; {{#scopes}} scope.append("{{scope}}"); {{/scopes}} - auto token = credential.getToken(scope.join(" ")); + auto token = _credentialFlow.getToken(scope.join(" ")); if(token.isValid()) input.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker = new {{prefix}}HttpRequestWorker(this, _manager); - latestWorker->setTimeOut(_timeOut); - latestWorker->setWorkingDirectory(_workingDirectory);{{#contentCompression}} - latestWorker->setResponseCompressionEnabled(isResponseCompressionEnabled); - latestWorker->setRequestCompressionEnabled(isRequestCompressionEnabled);{{/contentCompression}} + _latestWorker = new {{prefix}}HttpRequestWorker(this, _manager); + _latestWorker->setTimeOut(_timeOut); + _latestWorker->setWorkingDirectory(_workingDirectory);{{#contentCompression}} + _latestWorker->setResponseCompressionEnabled(isResponseCompressionEnabled); + _latestWorker->setRequestCompressionEnabled(isRequestCompressionEnabled);{{/contentCompression}} - connect(latestWorker, &{{prefix}}HttpRequestWorker::on_execution_finished, this, &{{classname}}::{{nickname}}Callback); - connect(this, &{{classname}}::abortRequestsSignal, latestWorker, &QObject::deleteLater); - connect(latestWorker, &QObject::destroyed, [this](){ + connect(_latestWorker, &{{prefix}}HttpRequestWorker::on_execution_finished, this, &{{classname}}::{{nickname}}Callback); + connect(this, &{{classname}}::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ if(findChildren<{{prefix}}HttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } }); - latestInput = input; - latestScope = scope;{{/isApplication}} + _latestInput = input; + _latestScope = scope;{{/isApplication}} {{#isPassword}} - OauthMethod = 4; - auth.unlink(); - implicit.unlink(); - credential.unlink(); - passwordFlow.link(); + _OauthMethod = 4; + _passwordFlow.link(); + _authFlow.unlink(); + _implicitFlow.unlink(); + _credentialFlow.unlink(); QStringList scope; {{#scopes}} scope.append("{{scope}}"); {{/scopes}} - auto token = passwordFlow.getToken(scope.join(" ")); + auto token = _passwordFlow.getToken(scope.join(" ")); if(token.isValid()) input.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker = new {{prefix}}HttpRequestWorker(this, _manager); - latestWorker->setTimeOut(_timeOut); - latestWorker->setWorkingDirectory(_workingDirectory);{{#contentCompression}} - latestWorker->setResponseCompressionEnabled(isResponseCompressionEnabled); - latestWorker->setRequestCompressionEnabled(isRequestCompressionEnabled);{{/contentCompression}} + _latestWorker = new {{prefix}}HttpRequestWorker(this, _manager); + _latestWorker->setTimeOut(_timeOut); + _latestWorker->setWorkingDirectory(_workingDirectory);{{#contentCompression}} + _latestWorker->setResponseCompressionEnabled(isResponseCompressionEnabled); + _latestWorker->setRequestCompressionEnabled(isRequestCompressionEnabled);{{/contentCompression}} - connect(latestWorker, &{{prefix}}HttpRequestWorker::on_execution_finished, this, &{{classname}}::{{nickname}}Callback); - connect(this, &{{classname}}::abortRequestsSignal, latestWorker, &QObject::deleteLater); - connect(latestWorker, &QObject::destroyed, [this](){ + connect(_latestWorker, &{{prefix}}HttpRequestWorker::on_execution_finished, this, &{{classname}}::{{nickname}}Callback); + connect(this, &{{classname}}::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ if(findChildren<{{prefix}}HttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } }); - latestInput = input; - latestScope = scope; + _latestInput = input; + _latestScope = scope; {{/isPassword}}{{/isOAuth}}{{/authMethods}} worker->execute(&input); @@ -855,7 +855,7 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { emit {{nickname}}Signal({{#returnType}}output{{/returnType}}); emit {{nickname}}SignalFull(worker{{#returnType}}, output{{/returnType}});{{#authMethods}}{{#isOAuth}}{{#isCode}} } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ - connect(&auth, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + connect(&_authFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); QStringList scope; {{#scopes}} scope.append("{{scope}}"); @@ -864,11 +864,11 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { QString authorizationUrl("{{authorizationUrl}}"); QString tokenUrl("{{tokenUrl}}"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - auth.setVariables(authorizationUrl, tokenUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); - emit auth.authenticationNeeded();{{/isCode}} + _authFlow.setVariables(authorizationUrl, tokenUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); + emit _authFlow.authenticationNeeded();{{/isCode}} {{#isImplicit}} } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ - connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + connect(&_implicitFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); QStringList scope; {{#scopes}} scope.append("{{scope}}"); @@ -876,11 +876,11 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { QString scopeStr = scope.join(" "); QString authorizationUrl("{{authorizationUrl}}"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - implicit.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); - emit implicit.authenticationNeeded();{{/isImplicit}} + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded();{{/isImplicit}} {{#isApplication}} } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ - connect(&credential, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + connect(&_credentialFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); QStringList scope; {{#scopes}} scope.append("{{scope}}"); @@ -888,11 +888,11 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { QString scopeStr = scope.join(" "); QString tokenUrl("{{tokenUrl}}"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - credential.setVariables(tokenUrl , scopeStr, "clientId", "clientSecret"); - emit credential.authenticationNeeded();{{/isApplication}} + _credentialFlow.setVariables(tokenUrl , scopeStr, "clientId", "clientSecret"); + emit _credentialFlow.authenticationNeeded();{{/isApplication}} {{#isPassword}} } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ - connect(&passwordFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + connect(&_passwordFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); QStringList scope; {{#scopes}} scope.append("{{scope}}"); @@ -900,8 +900,8 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { QString scopeStr = scope.join(" "); QString tokenUrl("{{tokenUrl}}"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - passwordFlow.setVariables(tokenUrl , scopeStr ,"clientId", "clientSecret", "username", "password"); - emit passwordFlow.authenticationNeeded(); + _passwordFlow.setVariables(tokenUrl , scopeStr ,"clientId", "clientSecret", "username", "password"); + emit _passwordFlow.authenticationNeeded(); {{/isPassword}}{{/isOAuth}}{{/authMethods}} } else { emit {{nickname}}SignalE({{#returnType}}output, {{/returnType}}error_type, error_str); @@ -914,44 +914,44 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { void {{classname}}::tokenAvailable(){ oauthToken token; - switch (OauthMethod) { + switch (_OauthMethod) { case 1: //implicit flow - token = implicit.getToken(latestScope.join(" ")); + token = _implicitFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - implicit.removeToken(latestScope.join(" ")); + _implicitFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; case 2: //authorization flow - token = auth.getToken(latestScope.join(" ")); + token = _authFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - auth.removeToken(latestScope.join(" ")); + _authFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; case 3: //client credentials flow - token = credential.getToken(latestScope.join(" ")); + token = _credentialFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - credential.removeToken(latestScope.join(" ")); + _credentialFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; case 4: //resource owner password flow - token = passwordFlow.getToken(latestScope.join(" ")); + token = _passwordFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - credential.removeToken(latestScope.join(" ")); + _credentialFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; diff --git a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache index f55aa199254..6d1376d52c5 100644 --- a/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/api-header.mustache @@ -74,14 +74,14 @@ private: QMap<QString, QString> _defaultHeaders; bool _isResponseCompressionEnabled; bool _isRequestCompressionEnabled; - {{prefix}}HttpRequestInput latestInput; - {{prefix}}HttpRequestWorker *latestWorker; - QStringList latestScope; - OauthCode auth; - OauthImplicit implicit; - OauthCredentials credential; - OauthPassword passwordFlow; - int OauthMethod = 0; + {{prefix}}HttpRequestInput _latestInput; + {{prefix}}HttpRequestWorker *_latestWorker; + QStringList _latestScope; + OauthCode _authFlow; + OauthImplicit _implicitFlow; + OauthCredentials _credentialFlow; + OauthPassword _passwordFlow; + int _OauthMethod = 0; {{#operations}}{{#operation}} void {{nickname}}Callback({{prefix}}HttpRequestWorker *worker);{{/operation}}{{/operations}} diff --git a/samples/client/petstore/cpp-qt/client/PFXOauth.cpp b/samples/client/petstore/cpp-qt/client/PFXOauth.cpp index 535d9681577..a5cc0da2606 100644 --- a/samples/client/petstore/cpp-qt/client/PFXOauth.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXOauth.cpp @@ -7,17 +7,6 @@ namespace OpenAPI { * */ -void OauthBase::setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType){ - - m_authUrl = QUrl(authUrl); - m_tokenUrl = QUrl(tokenUrl); - m_scope = scope; - m_accessType = accessType; - m_state = state; - m_redirectUri = redirectUri; - m_clientId = clientId; m_clientSecret = clientSecret; - -} void OauthBase::onFinish(QNetworkReply *rep) { @@ -68,6 +57,19 @@ void OauthCode::unlink() disconnect(&m_server,0,0,0); } +void OauthCode::setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType){ + + m_authUrl = QUrl(authUrl); + m_tokenUrl = QUrl(tokenUrl); + m_scope = scope; + m_accessType = accessType; + m_state = state; + m_redirectUri = redirectUri; + m_clientId = clientId; + m_clientSecret = clientSecret; + +} + void OauthCode::authenticationNeededCallback() { QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + (m_accessType=="" ? "" : "&access_type=" + m_accessType) + "&response_type=code" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); @@ -122,6 +124,17 @@ void OauthImplicit::unlink() m_linked = false; } +void OauthImplicit::setVariables(QString authUrl, QString scope, QString state, QString redirectUri, QString clientId, QString accessType){ + + m_authUrl = QUrl(authUrl); + m_scope = scope; + m_accessType = accessType; + m_state = state; + m_redirectUri = redirectUri; + m_clientId = clientId; + +} + void OauthImplicit::authenticationNeededCallback() { QDesktopServices::openUrl(QUrl(m_authUrl.toString() + "?scope=" + m_scope + (m_accessType=="" ? "" : "&access_type=" + m_accessType) + "&response_type=token" + "&state=" + m_state + "&redirect_uri=" + m_redirectUri + "&client_id=" + m_clientId)); @@ -153,6 +166,15 @@ void OauthCredentials::unlink() disconnect(this,0,0,0); } +void OauthCredentials::setVariables(QString tokenUrl, QString scope, QString clientId, QString clientSecret){ + + m_tokenUrl = QUrl(tokenUrl); + m_scope = scope; + m_clientId = clientId; + m_clientSecret = clientSecret; + +} + void OauthCredentials::authenticationNeededCallback() { //create query with the required fields @@ -172,6 +194,52 @@ void OauthCredentials::authenticationNeededCallback() manager->post(request, postData.query().toUtf8()); } +/* + * Class to perform the resource owner password flow + * + */ +OauthPassword::OauthPassword(QObject *parent) : OauthBase(parent){} +void OauthPassword::link() +{ + connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); +} + +void OauthPassword::unlink() +{ + disconnect(this,0,0,0); +} + +void OauthPassword::setVariables(QString tokenUrl, QString scope, QString clientId, QString clientSecret, QString username, QString password){ + + m_tokenUrl = QUrl(tokenUrl); + m_scope = scope; + m_clientId = clientId; + m_clientSecret = clientSecret; + m_username = username; + m_password = password; + +} +void OauthPassword::authenticationNeededCallback() +{ + //create query with the required fields + QUrlQuery postData; + postData.addQueryItem("grant_type", "password"); + postData.addQueryItem("username", m_username); + postData.addQueryItem("password", m_password); + postData.addQueryItem("client_id", m_clientId); + postData.addQueryItem("client_secret", m_clientSecret); + postData.addQueryItem("scope", m_scope); + QNetworkAccessManager * manager = new QNetworkAccessManager(this); + + QNetworkRequest request(m_tokenUrl); + + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + + connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(onFinish(QNetworkReply *))); + + manager->post(request, postData.query().toUtf8()); +} + /* * Class that provides a simple reply server diff --git a/samples/client/petstore/cpp-qt/client/PFXOauth.h b/samples/client/petstore/cpp-qt/client/PFXOauth.h index 4dd3bb23c01..f86a29e944f 100644 --- a/samples/client/petstore/cpp-qt/client/PFXOauth.h +++ b/samples/client/petstore/cpp-qt/client/PFXOauth.h @@ -86,7 +86,6 @@ public: oauthToken getToken(QString scope); void addToken(oauthToken token); void removeToken(QString scope); - void setVariables( QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType = ""); bool linked(){return m_linked;}; virtual void link()=0; virtual void unlink()=0; @@ -115,6 +114,7 @@ public: OauthCode(QObject *parent = nullptr); void link() override; void unlink() override; + void setVariables(QString authUrl, QString tokenUrl, QString scope, QString state, QString redirectUri, QString clientId, QString clientSecret, QString accessType = ""); private: ReplyServer m_server; @@ -133,6 +133,7 @@ public: OauthImplicit(QObject *parent = nullptr); void link() override; void unlink() override; + void setVariables(QString authUrl, QString scope, QString state, QString redirectUri, QString clientId, QString accessType = ""); private: ReplyServer m_server; @@ -150,11 +151,31 @@ public: OauthCredentials(QObject *parent = nullptr); void link() override; void unlink() override; + void setVariables(QString tokenUrl, QString scope, QString clientId, QString clientSecret); public slots: void authenticationNeededCallback() override; }; +//resource owner password flow +class OauthPassword : public OauthBase +{ + Q_OBJECT +public: + OauthPassword(QObject *parent = nullptr); + void link() override; + void unlink() override; + void setVariables(QString tokenUrl, QString scope, QString clientId, QString clientSecret, QString username, QString password); + +private: + QString m_username, m_password; + +public slots: + void authenticationNeededCallback() override; + +}; + + } // namespace test_namespace #endif // PFX_OAUTH2_H diff --git a/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp b/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp index c3e81961d27..781e192159f 100644 --- a/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp @@ -256,31 +256,33 @@ void PFXPetApi::addPet(const PFXPet &body) { emit allPendingRequestsCompleted(); } }); - OauthMethod = 1; - auth.unlink(); - credential.unlink(); - implicit.link(); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); - auto token = implicit.getToken(scope.join(" ")); + auto token = _implicitFlow.getToken(scope.join(" ")); if(token.isValid()) input.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker = new PFXHttpRequestWorker(this, _manager); - latestWorker->setTimeOut(_timeOut); - latestWorker->setWorkingDirectory(_workingDirectory); + _latestWorker = new PFXHttpRequestWorker(this, _manager); + _latestWorker->setTimeOut(_timeOut); + _latestWorker->setWorkingDirectory(_workingDirectory); - connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::addPetCallback); - connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); - connect(latestWorker, &QObject::destroyed, [this](){ + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::addPetCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ if(findChildren<PFXHttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } }); - latestInput = input; - latestScope = scope; + _latestInput = input; + _latestScope = scope; + worker->execute(&input); @@ -299,15 +301,16 @@ void PFXPetApi::addPetCallback(PFXHttpRequestWorker *worker) { emit addPetSignal(); emit addPetSignalFull(worker); } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ - connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + connect(&_implicitFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); QString scopeStr = scope.join(" "); QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); - emit implicit.authenticationNeeded(); + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + } else { emit addPetSignalE(error_type, error_str); @@ -361,31 +364,33 @@ void PFXPetApi::deletePet(const qint64 &pet_id, const ::test_namespace::Optional emit allPendingRequestsCompleted(); } }); - OauthMethod = 1; - auth.unlink(); - credential.unlink(); - implicit.link(); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); - auto token = implicit.getToken(scope.join(" ")); + auto token = _implicitFlow.getToken(scope.join(" ")); if(token.isValid()) input.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker = new PFXHttpRequestWorker(this, _manager); - latestWorker->setTimeOut(_timeOut); - latestWorker->setWorkingDirectory(_workingDirectory); + _latestWorker = new PFXHttpRequestWorker(this, _manager); + _latestWorker->setTimeOut(_timeOut); + _latestWorker->setWorkingDirectory(_workingDirectory); - connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::deletePetCallback); - connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); - connect(latestWorker, &QObject::destroyed, [this](){ + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::deletePetCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ if(findChildren<PFXHttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } }); - latestInput = input; - latestScope = scope; + _latestInput = input; + _latestScope = scope; + worker->execute(&input); @@ -404,15 +409,16 @@ void PFXPetApi::deletePetCallback(PFXHttpRequestWorker *worker) { emit deletePetSignal(); emit deletePetSignalFull(worker); } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ - connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + connect(&_implicitFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); QString scopeStr = scope.join(" "); QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); - emit implicit.authenticationNeeded(); + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + } else { emit deletePetSignalE(error_type, error_str); @@ -532,31 +538,33 @@ void PFXPetApi::findPetsByStatus(const QList<QString> &status) { emit allPendingRequestsCompleted(); } }); - OauthMethod = 1; - auth.unlink(); - credential.unlink(); - implicit.link(); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); - auto token = implicit.getToken(scope.join(" ")); + auto token = _implicitFlow.getToken(scope.join(" ")); if(token.isValid()) input.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker = new PFXHttpRequestWorker(this, _manager); - latestWorker->setTimeOut(_timeOut); - latestWorker->setWorkingDirectory(_workingDirectory); + _latestWorker = new PFXHttpRequestWorker(this, _manager); + _latestWorker->setTimeOut(_timeOut); + _latestWorker->setWorkingDirectory(_workingDirectory); - connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::findPetsByStatusCallback); - connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); - connect(latestWorker, &QObject::destroyed, [this](){ + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::findPetsByStatusCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ if(findChildren<PFXHttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } }); - latestInput = input; - latestScope = scope; + _latestInput = input; + _latestScope = scope; + worker->execute(&input); @@ -585,15 +593,16 @@ void PFXPetApi::findPetsByStatusCallback(PFXHttpRequestWorker *worker) { emit findPetsByStatusSignal(output); emit findPetsByStatusSignalFull(worker, output); } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ - connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + connect(&_implicitFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); QString scopeStr = scope.join(" "); QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); - emit implicit.authenticationNeeded(); + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + } else { emit findPetsByStatusSignalE(output, error_type, error_str); @@ -713,31 +722,33 @@ void PFXPetApi::findPetsByTags(const QList<QString> &tags) { emit allPendingRequestsCompleted(); } }); - OauthMethod = 1; - auth.unlink(); - credential.unlink(); - implicit.link(); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); - auto token = implicit.getToken(scope.join(" ")); + auto token = _implicitFlow.getToken(scope.join(" ")); if(token.isValid()) input.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker = new PFXHttpRequestWorker(this, _manager); - latestWorker->setTimeOut(_timeOut); - latestWorker->setWorkingDirectory(_workingDirectory); + _latestWorker = new PFXHttpRequestWorker(this, _manager); + _latestWorker->setTimeOut(_timeOut); + _latestWorker->setWorkingDirectory(_workingDirectory); - connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::findPetsByTagsCallback); - connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); - connect(latestWorker, &QObject::destroyed, [this](){ + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::findPetsByTagsCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ if(findChildren<PFXHttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } }); - latestInput = input; - latestScope = scope; + _latestInput = input; + _latestScope = scope; + worker->execute(&input); @@ -766,15 +777,16 @@ void PFXPetApi::findPetsByTagsCallback(PFXHttpRequestWorker *worker) { emit findPetsByTagsSignal(output); emit findPetsByTagsSignalFull(worker, output); } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ - connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + connect(&_implicitFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); QString scopeStr = scope.join(" "); QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); - emit implicit.authenticationNeeded(); + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + } else { emit findPetsByTagsSignalE(output, error_type, error_str); @@ -879,31 +891,33 @@ void PFXPetApi::updatePet(const PFXPet &body) { emit allPendingRequestsCompleted(); } }); - OauthMethod = 1; - auth.unlink(); - credential.unlink(); - implicit.link(); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); - auto token = implicit.getToken(scope.join(" ")); + auto token = _implicitFlow.getToken(scope.join(" ")); if(token.isValid()) input.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker = new PFXHttpRequestWorker(this, _manager); - latestWorker->setTimeOut(_timeOut); - latestWorker->setWorkingDirectory(_workingDirectory); + _latestWorker = new PFXHttpRequestWorker(this, _manager); + _latestWorker->setTimeOut(_timeOut); + _latestWorker->setWorkingDirectory(_workingDirectory); - connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::updatePetCallback); - connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); - connect(latestWorker, &QObject::destroyed, [this](){ + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::updatePetCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ if(findChildren<PFXHttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } }); - latestInput = input; - latestScope = scope; + _latestInput = input; + _latestScope = scope; + worker->execute(&input); @@ -922,15 +936,16 @@ void PFXPetApi::updatePetCallback(PFXHttpRequestWorker *worker) { emit updatePetSignal(); emit updatePetSignalFull(worker); } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ - connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + connect(&_implicitFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); QString scopeStr = scope.join(" "); QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); - emit implicit.authenticationNeeded(); + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + } else { emit updatePetSignalE(error_type, error_str); @@ -986,31 +1001,33 @@ void PFXPetApi::updatePetWithForm(const qint64 &pet_id, const ::test_namespace:: emit allPendingRequestsCompleted(); } }); - OauthMethod = 1; - auth.unlink(); - credential.unlink(); - implicit.link(); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); - auto token = implicit.getToken(scope.join(" ")); + auto token = _implicitFlow.getToken(scope.join(" ")); if(token.isValid()) input.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker = new PFXHttpRequestWorker(this, _manager); - latestWorker->setTimeOut(_timeOut); - latestWorker->setWorkingDirectory(_workingDirectory); + _latestWorker = new PFXHttpRequestWorker(this, _manager); + _latestWorker->setTimeOut(_timeOut); + _latestWorker->setWorkingDirectory(_workingDirectory); - connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::updatePetWithFormCallback); - connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); - connect(latestWorker, &QObject::destroyed, [this](){ + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::updatePetWithFormCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ if(findChildren<PFXHttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } }); - latestInput = input; - latestScope = scope; + _latestInput = input; + _latestScope = scope; + worker->execute(&input); @@ -1029,15 +1046,16 @@ void PFXPetApi::updatePetWithFormCallback(PFXHttpRequestWorker *worker) { emit updatePetWithFormSignal(); emit updatePetWithFormSignalFull(worker); } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ - connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + connect(&_implicitFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); QString scopeStr = scope.join(" "); QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); - emit implicit.authenticationNeeded(); + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + } else { emit updatePetWithFormSignalE(error_type, error_str); @@ -1093,31 +1111,33 @@ void PFXPetApi::uploadFile(const qint64 &pet_id, const ::test_namespace::Optiona emit allPendingRequestsCompleted(); } }); - OauthMethod = 1; - auth.unlink(); - credential.unlink(); - implicit.link(); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); - auto token = implicit.getToken(scope.join(" ")); + auto token = _implicitFlow.getToken(scope.join(" ")); if(token.isValid()) input.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker = new PFXHttpRequestWorker(this, _manager); - latestWorker->setTimeOut(_timeOut); - latestWorker->setWorkingDirectory(_workingDirectory); + _latestWorker = new PFXHttpRequestWorker(this, _manager); + _latestWorker->setTimeOut(_timeOut); + _latestWorker->setWorkingDirectory(_workingDirectory); - connect(latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::uploadFileCallback); - connect(this, &PFXPetApi::abortRequestsSignal, latestWorker, &QObject::deleteLater); - connect(latestWorker, &QObject::destroyed, [this](){ + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::uploadFileCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ if(findChildren<PFXHttpRequestWorker*>().count() == 0){ emit allPendingRequestsCompleted(); } }); - latestInput = input; - latestScope = scope; + _latestInput = input; + _latestScope = scope; + worker->execute(&input); @@ -1137,15 +1157,16 @@ void PFXPetApi::uploadFileCallback(PFXHttpRequestWorker *worker) { emit uploadFileSignal(output); emit uploadFileSignalFull(worker, output); } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ - connect(&implicit, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + connect(&_implicitFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); QStringList scope; scope.append("write:pets"); scope.append("read:pets"); QString scopeStr = scope.join(" "); QString authorizationUrl("http://petstore.swagger.io/api/oauth/dialog"); //TODO get clientID and Secret and state in the config? https://swagger.io/docs/specification/authentication/oauth2/ states that you should do as you like - implicit.setVariables(authorizationUrl, "", scopeStr, "state" , "http://127.0.0.1:9999", "clientId", "clientSecret"); - emit implicit.authenticationNeeded(); + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + } else { emit uploadFileSignalE(output, error_type, error_str); @@ -1156,34 +1177,44 @@ void PFXPetApi::uploadFileCallback(PFXHttpRequestWorker *worker) { void PFXPetApi::tokenAvailable(){ oauthToken token; - switch (OauthMethod) { + switch (_OauthMethod) { case 1: //implicit flow - token = implicit.getToken(latestScope.join(" ")); + token = _implicitFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - implicit.removeToken(latestScope.join(" ")); + _implicitFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; case 2: //authorization flow - token = auth.getToken(latestScope.join(" ")); + token = _authFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - auth.removeToken(latestScope.join(" ")); + _authFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; case 3: //client credentials flow - token = credential.getToken(latestScope.join(" ")); + token = _credentialFlow.getToken(_latestScope.join(" ")); + if(token.isValid()){ + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); + }else{ + _credentialFlow.removeToken(_latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 4: //resource owner password flow + token = _passwordFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - credential.removeToken(latestScope.join(" ")); + _credentialFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; diff --git a/samples/client/petstore/cpp-qt/client/PFXPetApi.h b/samples/client/petstore/cpp-qt/client/PFXPetApi.h index 02fb6131118..9fc00dd6d3c 100644 --- a/samples/client/petstore/cpp-qt/client/PFXPetApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXPetApi.h @@ -117,13 +117,14 @@ private: QMap<QString, QString> _defaultHeaders; bool _isResponseCompressionEnabled; bool _isRequestCompressionEnabled; - PFXHttpRequestInput latestInput; - PFXHttpRequestWorker *latestWorker; - QStringList latestScope; - OauthCode auth; - OauthImplicit implicit; - OauthCredentials credential; - int OauthMethod = 0; + PFXHttpRequestInput _latestInput; + PFXHttpRequestWorker *_latestWorker; + QStringList _latestScope; + OauthCode _authFlow; + OauthImplicit _implicitFlow; + OauthCredentials _credentialFlow; + OauthPassword _passwordFlow; + int _OauthMethod = 0; void addPetCallback(PFXHttpRequestWorker *worker); void deletePetCallback(PFXHttpRequestWorker *worker); diff --git a/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp b/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp index 8d0e583c405..6090921ce42 100644 --- a/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp @@ -461,34 +461,44 @@ void PFXStoreApi::placeOrderCallback(PFXHttpRequestWorker *worker) { void PFXStoreApi::tokenAvailable(){ oauthToken token; - switch (OauthMethod) { + switch (_OauthMethod) { case 1: //implicit flow - token = implicit.getToken(latestScope.join(" ")); + token = _implicitFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - implicit.removeToken(latestScope.join(" ")); + _implicitFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; case 2: //authorization flow - token = auth.getToken(latestScope.join(" ")); + token = _authFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - auth.removeToken(latestScope.join(" ")); + _authFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; case 3: //client credentials flow - token = credential.getToken(latestScope.join(" ")); + token = _credentialFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - credential.removeToken(latestScope.join(" ")); + _credentialFlow.removeToken(_latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 4: //resource owner password flow + token = _passwordFlow.getToken(_latestScope.join(" ")); + if(token.isValid()){ + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); + }else{ + _credentialFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; diff --git a/samples/client/petstore/cpp-qt/client/PFXStoreApi.h b/samples/client/petstore/cpp-qt/client/PFXStoreApi.h index 7ed5c6eedfd..037ef2f4d2f 100644 --- a/samples/client/petstore/cpp-qt/client/PFXStoreApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXStoreApi.h @@ -89,13 +89,14 @@ private: QMap<QString, QString> _defaultHeaders; bool _isResponseCompressionEnabled; bool _isRequestCompressionEnabled; - PFXHttpRequestInput latestInput; - PFXHttpRequestWorker *latestWorker; - QStringList latestScope; - OauthCode auth; - OauthImplicit implicit; - OauthCredentials credential; - int OauthMethod = 0; + PFXHttpRequestInput _latestInput; + PFXHttpRequestWorker *_latestWorker; + QStringList _latestScope; + OauthCode _authFlow; + OauthImplicit _implicitFlow; + OauthCredentials _credentialFlow; + OauthPassword _passwordFlow; + int _OauthMethod = 0; void deleteOrderCallback(PFXHttpRequestWorker *worker); void getInventoryCallback(PFXHttpRequestWorker *worker); diff --git a/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp b/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp index 98a9da15b3d..0d206a0f837 100644 --- a/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp @@ -705,34 +705,44 @@ void PFXUserApi::updateUserCallback(PFXHttpRequestWorker *worker) { void PFXUserApi::tokenAvailable(){ oauthToken token; - switch (OauthMethod) { + switch (_OauthMethod) { case 1: //implicit flow - token = implicit.getToken(latestScope.join(" ")); + token = _implicitFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - implicit.removeToken(latestScope.join(" ")); + _implicitFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; case 2: //authorization flow - token = auth.getToken(latestScope.join(" ")); + token = _authFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - auth.removeToken(latestScope.join(" ")); + _authFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; case 3: //client credentials flow - token = credential.getToken(latestScope.join(" ")); + token = _credentialFlow.getToken(_latestScope.join(" ")); if(token.isValid()){ - latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); - latestWorker->execute(&latestInput); + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); }else{ - credential.removeToken(latestScope.join(" ")); + _credentialFlow.removeToken(_latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 4: //resource owner password flow + token = _passwordFlow.getToken(_latestScope.join(" ")); + if(token.isValid()){ + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); + }else{ + _credentialFlow.removeToken(_latestScope.join(" ")); qDebug() << "Could not retreive a valid token"; } break; diff --git a/samples/client/petstore/cpp-qt/client/PFXUserApi.h b/samples/client/petstore/cpp-qt/client/PFXUserApi.h index 4e794f2138f..0fc9a73266e 100644 --- a/samples/client/petstore/cpp-qt/client/PFXUserApi.h +++ b/samples/client/petstore/cpp-qt/client/PFXUserApi.h @@ -111,13 +111,14 @@ private: QMap<QString, QString> _defaultHeaders; bool _isResponseCompressionEnabled; bool _isRequestCompressionEnabled; - PFXHttpRequestInput latestInput; - PFXHttpRequestWorker *latestWorker; - QStringList latestScope; - OauthCode auth; - OauthImplicit implicit; - OauthCredentials credential; - int OauthMethod = 0; + PFXHttpRequestInput _latestInput; + PFXHttpRequestWorker *_latestWorker; + QStringList _latestScope; + OauthCode _authFlow; + OauthImplicit _implicitFlow; + OauthCredentials _credentialFlow; + OauthPassword _passwordFlow; + int _OauthMethod = 0; void createUserCallback(PFXHttpRequestWorker *worker); void createUsersWithArrayInputCallback(PFXHttpRequestWorker *worker); -- GitLab