From f596b32316aea8486ceaa822647185621fae652a Mon Sep 17 00:00:00 2001 From: basyskom-dege <72982549+basyskom-dege@users.noreply.github.com> Date: Sun, 14 Nov 2021 16:16:29 +0100 Subject: [PATCH] [Qt][C++] Oauth2 Authorization Code Flow and Implicit Flow Support. (#10183) * Oauth class with reply server for authorization flow * multiple scopes. Joined with space seperator * some refactoring, using urls from the spec * added implicit flow. Refactored oauth classes. * added missing {{prefix}} to Oauth class * added client credentials flow * added password flow. setVariables for each class * Refactored variables to fit style. Updated Samples --- docs/generators/cpp-qt-client.md | 8 +- .../codegen/languages/CppQtClientCodegen.java | 8 + .../resources/cpp-qt-client/Project.mustache | 6 +- .../resources/cpp-qt-client/api-body.mustache | 220 ++++++++++- .../cpp-qt-client/api-header.mustache | 13 + .../cpp-qt-client/oauth.cpp.mustache | 347 ++++++++++++++++++ .../resources/cpp-qt-client/oauth.h.mustache | 175 +++++++++ .../petstore/cpp-qt/.openapi-generator/FILES | 2 + .../petstore/cpp-qt/client/PFXOauth.cpp | 347 ++++++++++++++++++ .../client/petstore/cpp-qt/client/PFXOauth.h | 181 +++++++++ .../petstore/cpp-qt/client/PFXPetApi.cpp | 329 +++++++++++++++++ .../client/petstore/cpp-qt/client/PFXPetApi.h | 13 + .../petstore/cpp-qt/client/PFXStoreApi.cpp | 49 +++ .../petstore/cpp-qt/client/PFXStoreApi.h | 13 + .../petstore/cpp-qt/client/PFXUserApi.cpp | 49 +++ .../petstore/cpp-qt/client/PFXUserApi.h | 13 + .../petstore/cpp-qt/client/PFXclient.pri | 6 +- 17 files changed, 1770 insertions(+), 9 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/PFXOauth.cpp create mode 100644 samples/client/petstore/cpp-qt/client/PFXOauth.h diff --git a/docs/generators/cpp-qt-client.md b/docs/generators/cpp-qt-client.md index 0dcbd968233..96be28abb0a 100644 --- a/docs/generators/cpp-qt-client.md +++ b/docs/generators/cpp-qt-client.md @@ -236,10 +236,10 @@ These options may be applied as additional-properties (cli) or configOptions (pl |ApiKey|✓|OAS2,OAS3 |OpenIDConnect|✗|OAS3 |BearerToken|✓|OAS3 -|OAuth2_Implicit|✗|OAS2,OAS3 -|OAuth2_Password|✗|OAS2,OAS3 -|OAuth2_ClientCredentials|✗|OAS2,OAS3 -|OAuth2_AuthorizationCode|✗|OAS2,OAS3 +|OAuth2_Implicit|✓|OAS2,OAS3 +|OAuth2_Password|✓|OAS2,OAS3 +|OAuth2_ClientCredentials|✓|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..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 @@ -46,6 +46,10 @@ public class CppQtClientCodegen extends CppQtAbstractCodegen implements CodegenC .includeSecurityFeatures(SecurityFeature.BasicAuth) .includeSecurityFeatures(SecurityFeature.ApiKey) .includeSecurityFeatures(SecurityFeature.BearerToken) + .includeSecurityFeatures(SecurityFeature.OAuth2_AuthorizationCode) + .includeSecurityFeatures(SecurityFeature.OAuth2_Implicit) + .includeSecurityFeatures(SecurityFeature.OAuth2_ClientCredentials) + .includeSecurityFeatures(SecurityFeature.OAuth2_Password) .includeGlobalFeatures(GlobalFeature.ParameterStyling) ); @@ -96,6 +100,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, 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) { @@ -127,6 +133,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, 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 c48c32708b9..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 @@ -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}/{{prefix}}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}/{{prefix}}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 3f7e5035d79..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 @@ -678,8 +678,128 @@ void {{classname}}::{{nickname}}({{#allParams}}{{#required}}const {{{dataType}}} if (findChildren<{{prefix}}HttpRequestWorker*>().count() == 0) { emit allPendingRequestsCompleted(); } + });{{#authMethods}}{{#isOAuth}}{{#isCode}} + _OauthMethod = 2; + _implicitFlow.unlink(); + _credentialFlow.unlink(); + _passwordFlow.unlink(); + _authFlow.link(); + QStringList scope; + {{#scopes}} + scope.append("{{scope}}"); + {{/scopes}} + 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}} + + 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}} + {{#isImplicit}} + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); + QStringList scope; + {{#scopes}} + scope.append("{{scope}}"); + {{/scopes}} + 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}} + + 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}} + {{#isApplication}} + _OauthMethod = 3; + _authFlow.unlink(); + _implicitFlow.unlink(); + _passwordFlow.unlink(); + _credentialFlow.link(); + QStringList scope; + {{#scopes}} + scope.append("{{scope}}"); + {{/scopes}} + 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}} + + 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}} + {{#isPassword}} + _OauthMethod = 4; + _passwordFlow.link(); + _authFlow.unlink(); + _implicitFlow.unlink(); + _credentialFlow.unlink(); + 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; + {{/isPassword}}{{/isOAuth}}{{/authMethods}} + worker->execute(&input); } @@ -733,7 +853,56 @@ 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(&_authFlow, SIGNAL(tokenReceived()), this, SLOT(tokenAvailable())); + QStringList scope; + {{#scopes}} + scope.append("{{scope}}"); + {{/scopes}} + QString scopeStr = scope.join(" "); + 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 + _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(&_implicitFlow, 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 + _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(&_credentialFlow, 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 + _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())); + 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); @@ -742,6 +911,55 @@ void {{classname}}::{{nickname}}Callback({{prefix}}HttpRequestWorker *worker) { {{/operation}} {{/operations}} +void {{classname}}::tokenAvailable(){ + + oauthToken token; + switch (_OauthMethod) { + case 1: //implicit flow + token = _implicitFlow.getToken(_latestScope.join(" ")); + if(token.isValid()){ + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); + }else{ + _implicitFlow.removeToken(_latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 2: //authorization flow + token = _authFlow.getToken(_latestScope.join(" ")); + if(token.isValid()){ + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); + }else{ + _authFlow.removeToken(_latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 3: //client credentials flow + 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); + }else{ + _credentialFlow.removeToken(_latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + default: + qDebug() << "No Oauth method set!"; + break; + } +} {{#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 6823ab05ec5..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 @@ -5,6 +5,7 @@ #include "{{prefix}}Helpers.h" #include "{{prefix}}HttpRequest.h" #include "{{prefix}}ServerConfiguration.h" +#include "{{prefix}}Oauth.h" {{#imports}}{{{import}}} {{/imports}} @@ -73,6 +74,14 @@ private: QMap _defaultHeaders; bool _isResponseCompressionEnabled; bool _isRequestCompressionEnabled; + {{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}} @@ -88,6 +97,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..ebe53654851 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.cpp.mustache @@ -0,0 +1,347 @@ +#include "{{prefix}}Oauth.h" + +namespace OpenAPI { + +/* + * Base class to perform oauth2 flows + * + */ + + +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)), this, SLOT(onVerificationReceived(QMap))); + 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::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)); + m_server.start(); +} + +void OauthCode::onVerificationReceived(const QMap 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()); +} + +/* + * Class to perform the implicit flow + * + */ + +OauthImplicit::OauthImplicit(QObject *parent) : OauthBase(parent){} + +void OauthImplicit::link() +{ + //TODO correct linking + connect(&m_server, SIGNAL(dataReceived(QMap)), this, SLOT(ImplicitTokenReceived(QMap))); + connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); + connect(this, SIGNAL(tokenReceived()), &m_server, SLOT(stop())); + m_linked = true; +} + +void OauthImplicit::unlink() +{ + disconnect(this,0,0,0); + disconnect(&m_server,0,0,0); + 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)); + m_server.start(); +} + +void OauthImplicit::ImplicitTokenReceived(const QMap response) +{ + 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 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::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 + 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 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 + * + */ + +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(sender()); + if (!socket) { + qDebug() << "No socket available"; + return; + } + qDebug() << "Socket connected"; + + 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" + <<"\ + \ + \ + \ + \ + \ +

You can close this window now!

\ + \ + "; + + 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 > tokens; + + QUrlQuery query(getTokenUrl); + tokens = query.queryItems(); + + + QMap queryParams; + QPair 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->close(); + return; + } + socket->close(); + + 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 new file mode 100644 index 00000000000..03aa0dde901 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/cpp-qt-client/oauth.h.mustache @@ -0,0 +1,175 @@ +{{>licenseInfo}} +/** + * Providing a Oauth2 Class and a ReplyServer for the Oauth2 authorization code flow. + */ +#ifndef {{prefix}}_OAUTH2_H +#define {{prefix}}_OAUTH2_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +{{#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 setReply(QByteArray reply){m_reply = reply;}; + void run(); +private: + QByteArray m_reply; + +signals: + void dataReceived(QMap); + +public slots: + void onConnected(); + void read(); + void start(); + 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); + bool linked(){return m_linked;}; + virtual void link()=0; + virtual void unlink()=0; + +protected: + QMap 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 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; + +public slots: + void authenticationNeededCallback() override; + void onVerificationReceived(const QMap response); + +}; + +// Implicit flow +class OauthImplicit : public OauthBase +{ + Q_OBJECT +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; + +public slots: + void authenticationNeededCallback() override; + void ImplicitTokenReceived(const QMap response); +}; + +//client credentials flow +class OauthCredentials : public OauthBase +{ + Q_OBJECT +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}} +#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..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 diff --git a/samples/client/petstore/cpp-qt/client/PFXOauth.cpp b/samples/client/petstore/cpp-qt/client/PFXOauth.cpp new file mode 100644 index 00000000000..a5cc0da2606 --- /dev/null +++ b/samples/client/petstore/cpp-qt/client/PFXOauth.cpp @@ -0,0 +1,347 @@ +#include "PFXOauth.h" + +namespace OpenAPI { + +/* + * Base class to perform oauth2 flows + * + */ + + +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)), this, SLOT(onVerificationReceived(QMap))); + 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::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)); + m_server.start(); +} + +void OauthCode::onVerificationReceived(const QMap 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()); +} + +/* + * Class to perform the implicit flow + * + */ + +OauthImplicit::OauthImplicit(QObject *parent) : OauthBase(parent){} + +void OauthImplicit::link() +{ + //TODO correct linking + connect(&m_server, SIGNAL(dataReceived(QMap)), this, SLOT(ImplicitTokenReceived(QMap))); + connect(this, SIGNAL(authenticationNeeded()), this, SLOT(authenticationNeededCallback())); + connect(this, SIGNAL(tokenReceived()), &m_server, SLOT(stop())); + m_linked = true; +} + +void OauthImplicit::unlink() +{ + disconnect(this,0,0,0); + disconnect(&m_server,0,0,0); + 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)); + m_server.start(); +} + +void OauthImplicit::ImplicitTokenReceived(const QMap response) +{ + 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 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::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 + 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 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 + * + */ + +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(sender()); + if (!socket) { + qDebug() << "No socket available"; + return; + } + qDebug() << "Socket connected"; + + 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" + <<"\ + \ + \ + \ + \ + \ +

You can close this window now!

\ + \ + "; + + 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 > tokens; + + QUrlQuery query(getTokenUrl); + tokens = query.queryItems(); + + + QMap queryParams; + QPair 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->close(); + return; + } + socket->close(); + + emit dataReceived(queryParams); +} + + +} \ No newline at end of file diff --git a/samples/client/petstore/cpp-qt/client/PFXOauth.h b/samples/client/petstore/cpp-qt/client/PFXOauth.h new file mode 100644 index 00000000000..f86a29e944f --- /dev/null +++ b/samples/client/petstore/cpp-qt/client/PFXOauth.h @@ -0,0 +1,181 @@ +/** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +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 setReply(QByteArray reply){m_reply = reply;}; + void run(); +private: + QByteArray m_reply; + +signals: + void dataReceived(QMap); + +public slots: + void onConnected(); + void read(); + void start(); + 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); + bool linked(){return m_linked;}; + virtual void link()=0; + virtual void unlink()=0; + +protected: + QMap 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 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; + +public slots: + void authenticationNeededCallback() override; + void onVerificationReceived(const QMap response); + +}; + +// Implicit flow +class OauthImplicit : public OauthBase +{ + Q_OBJECT +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; + +public slots: + void authenticationNeededCallback() override; + void ImplicitTokenReceived(const QMap response); +}; + +//client credentials flow +class OauthCredentials : public OauthBase +{ + Q_OBJECT +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 7c999d98687..781e192159f 100644 --- a/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXPetApi.cpp @@ -256,6 +256,34 @@ void PFXPetApi::addPet(const PFXPet &body) { emit allPendingRequestsCompleted(); } }); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + 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); + + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::addPetCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ + if(findChildren().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + _latestInput = input; + _latestScope = scope; + + worker->execute(&input); } @@ -272,6 +300,18 @@ void PFXPetApi::addPetCallback(PFXHttpRequestWorker *worker) { if (worker->error_type == QNetworkReply::NoError) { emit addPetSignal(); emit addPetSignalFull(worker); + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + 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 + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + + } else { emit addPetSignalE(error_type, error_str); emit addPetSignalEFull(worker, error_type, error_str); @@ -324,6 +364,34 @@ void PFXPetApi::deletePet(const qint64 &pet_id, const ::test_namespace::Optional emit allPendingRequestsCompleted(); } }); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + 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); + + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::deletePetCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ + if(findChildren().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + _latestInput = input; + _latestScope = scope; + + worker->execute(&input); } @@ -340,6 +408,18 @@ void PFXPetApi::deletePetCallback(PFXHttpRequestWorker *worker) { if (worker->error_type == QNetworkReply::NoError) { emit deletePetSignal(); emit deletePetSignalFull(worker); + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + 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 + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + + } else { emit deletePetSignalE(error_type, error_str); emit deletePetSignalEFull(worker, error_type, error_str); @@ -458,6 +538,34 @@ void PFXPetApi::findPetsByStatus(const QList &status) { emit allPendingRequestsCompleted(); } }); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + 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); + + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::findPetsByStatusCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ + if(findChildren().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + _latestInput = input; + _latestScope = scope; + + worker->execute(&input); } @@ -484,6 +592,18 @@ 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(&_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 + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + + } else { emit findPetsByStatusSignalE(output, error_type, error_str); emit findPetsByStatusSignalEFull(worker, error_type, error_str); @@ -602,6 +722,34 @@ void PFXPetApi::findPetsByTags(const QList &tags) { emit allPendingRequestsCompleted(); } }); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + 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); + + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::findPetsByTagsCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ + if(findChildren().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + _latestInput = input; + _latestScope = scope; + + worker->execute(&input); } @@ -628,6 +776,18 @@ 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(&_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 + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + + } else { emit findPetsByTagsSignalE(output, error_type, error_str); emit findPetsByTagsSignalEFull(worker, error_type, error_str); @@ -731,6 +891,34 @@ void PFXPetApi::updatePet(const PFXPet &body) { emit allPendingRequestsCompleted(); } }); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + 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); + + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::updatePetCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ + if(findChildren().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + _latestInput = input; + _latestScope = scope; + + worker->execute(&input); } @@ -747,6 +935,18 @@ void PFXPetApi::updatePetCallback(PFXHttpRequestWorker *worker) { if (worker->error_type == QNetworkReply::NoError) { emit updatePetSignal(); emit updatePetSignalFull(worker); + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + 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 + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + + } else { emit updatePetSignalE(error_type, error_str); emit updatePetSignalEFull(worker, error_type, error_str); @@ -801,6 +1001,34 @@ void PFXPetApi::updatePetWithForm(const qint64 &pet_id, const ::test_namespace:: emit allPendingRequestsCompleted(); } }); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + 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); + + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::updatePetWithFormCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ + if(findChildren().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + _latestInput = input; + _latestScope = scope; + + worker->execute(&input); } @@ -817,6 +1045,18 @@ void PFXPetApi::updatePetWithFormCallback(PFXHttpRequestWorker *worker) { if (worker->error_type == QNetworkReply::NoError) { emit updatePetWithFormSignal(); emit updatePetWithFormSignalFull(worker); + } else if(worker->error_type == QNetworkReply::AuthenticationRequiredError){ + 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 + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + + } else { emit updatePetWithFormSignalE(error_type, error_str); emit updatePetWithFormSignalEFull(worker, error_type, error_str); @@ -871,6 +1111,34 @@ void PFXPetApi::uploadFile(const qint64 &pet_id, const ::test_namespace::Optiona emit allPendingRequestsCompleted(); } }); + _OauthMethod = 1; + _implicitFlow.link(); + _passwordFlow.unlink(); + _authFlow.unlink(); + _credentialFlow.unlink(); + QStringList scope; + scope.append("write:pets"); + scope.append("read:pets"); + 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); + + connect(_latestWorker, &PFXHttpRequestWorker::on_execution_finished, this, &PFXPetApi::uploadFileCallback); + connect(this, &PFXPetApi::abortRequestsSignal, _latestWorker, &QObject::deleteLater); + connect(_latestWorker, &QObject::destroyed, [this](){ + if(findChildren().count() == 0){ + emit allPendingRequestsCompleted(); + } + }); + + _latestInput = input; + _latestScope = scope; + + worker->execute(&input); } @@ -888,10 +1156,71 @@ 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(&_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 + _implicitFlow.setVariables(authorizationUrl, scopeStr, "state" , "http://127.0.0.1:9999", "clientId"); + emit _implicitFlow.authenticationNeeded(); + + } else { emit uploadFileSignalE(output, error_type, error_str); emit uploadFileSignalEFull(worker, error_type, error_str); } } +void PFXPetApi::tokenAvailable(){ + + oauthToken token; + switch (_OauthMethod) { + case 1: //implicit flow + token = _implicitFlow.getToken(_latestScope.join(" ")); + if(token.isValid()){ + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); + }else{ + _implicitFlow.removeToken(_latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 2: //authorization flow + token = _authFlow.getToken(_latestScope.join(" ")); + if(token.isValid()){ + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); + }else{ + _authFlow.removeToken(_latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 3: //client credentials flow + 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); + }else{ + _credentialFlow.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 4007bd2e942..9fc00dd6d3c 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 "PFXOauth.h" #include "PFXApiResponse.h" #include "PFXHttpFileElement.h" @@ -116,6 +117,14 @@ private: QMap _defaultHeaders; bool _isResponseCompressionEnabled; bool _isRequestCompressionEnabled; + 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); @@ -166,6 +175,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 9ff025b0ad1..6090921ce42 100644 --- a/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXStoreApi.cpp @@ -458,4 +458,53 @@ void PFXStoreApi::placeOrderCallback(PFXHttpRequestWorker *worker) { } } +void PFXStoreApi::tokenAvailable(){ + + oauthToken token; + switch (_OauthMethod) { + case 1: //implicit flow + token = _implicitFlow.getToken(_latestScope.join(" ")); + if(token.isValid()){ + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); + }else{ + _implicitFlow.removeToken(_latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 2: //authorization flow + token = _authFlow.getToken(_latestScope.join(" ")); + if(token.isValid()){ + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); + }else{ + _authFlow.removeToken(_latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 3: //client credentials flow + 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); + }else{ + _credentialFlow.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 a31a6e3a74e..037ef2f4d2f 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 "PFXOauth.h" #include "PFXOrder.h" #include @@ -88,6 +89,14 @@ private: QMap _defaultHeaders; bool _isResponseCompressionEnabled; bool _isRequestCompressionEnabled; + 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); @@ -118,6 +127,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 b2f4d4ff96d..0d206a0f837 100644 --- a/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp +++ b/samples/client/petstore/cpp-qt/client/PFXUserApi.cpp @@ -702,4 +702,53 @@ void PFXUserApi::updateUserCallback(PFXHttpRequestWorker *worker) { } } +void PFXUserApi::tokenAvailable(){ + + oauthToken token; + switch (_OauthMethod) { + case 1: //implicit flow + token = _implicitFlow.getToken(_latestScope.join(" ")); + if(token.isValid()){ + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); + }else{ + _implicitFlow.removeToken(_latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 2: //authorization flow + token = _authFlow.getToken(_latestScope.join(" ")); + if(token.isValid()){ + _latestInput.headers.insert("Authorization", "Bearer " + token.getToken()); + _latestWorker->execute(&_latestInput); + }else{ + _authFlow.removeToken(_latestScope.join(" ")); + qDebug() << "Could not retreive a valid token"; + } + break; + case 3: //client credentials flow + 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); + }else{ + _credentialFlow.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 b216ec3fff3..0fc9a73266e 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 "PFXOauth.h" #include "PFXUser.h" #include @@ -110,6 +111,14 @@ private: QMap _defaultHeaders; bool _isResponseCompressionEnabled; bool _isRequestCompressionEnabled; + 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); @@ -160,6 +169,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..7271d7055c6 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}/PFXOauth.h SOURCES += \ # Models @@ -36,4 +37,5 @@ SOURCES += \ # Others $${PWD}/PFXHelpers.cpp \ $${PWD}/PFXHttpRequest.cpp \ - $${PWD}/PFXHttpFileElement.cpp + $${PWD}/PFXHttpFileElement.cpp \ + $${PWD}/PFXOauth.cpp