[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
This commit is contained in:
basyskom-dege 2021-11-14 16:16:29 +01:00 committed by GitHub
parent e7c3bdacc2
commit f596b32316
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1770 additions and 9 deletions

View File

@ -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 |

View File

@ -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"));

View File

@ -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

View File

@ -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}}

View File

@ -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<QString, QString> _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}}

View File

@ -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<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::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<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());
}
/*
* Class to perform the implicit flow
*
*/
OauthImplicit::OauthImplicit(QObject *parent) : OauthBase(parent){}
void OauthImplicit::link()
{
//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;
}
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<QString, QString> 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<QTcpSocket *>(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"
<<"<!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);
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->close();
return;
}
socket->close();
emit dataReceived(queryParams);
}
}

View File

@ -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 <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 setReply(QByteArray reply){m_reply = reply;};
void run();
private:
QByteArray m_reply;
signals:
void dataReceived(QMap<QString, QString>);
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<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 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<QString, QString> 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<QString, QString> 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

View File

@ -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

View File

@ -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<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::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<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());
}
/*
* Class to perform the implicit flow
*
*/
OauthImplicit::OauthImplicit(QObject *parent) : OauthBase(parent){}
void OauthImplicit::link()
{
//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;
}
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<QString, QString> 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<QTcpSocket *>(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"
<<"<!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);
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->close();
return;
}
socket->close();
emit dataReceived(queryParams);
}
}

View File

@ -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 <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 setReply(QByteArray reply){m_reply = reply;};
void run();
private:
QByteArray m_reply;
signals:
void dataReceived(QMap<QString, QString>);
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<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 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<QString, QString> 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<QString, QString> 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

View File

@ -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<PFXHttpRequestWorker*>().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<PFXHttpRequestWorker*>().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<QString> &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<PFXHttpRequestWorker*>().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<QString> &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<PFXHttpRequestWorker*>().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<PFXHttpRequestWorker*>().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<PFXHttpRequestWorker*>().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<PFXHttpRequestWorker*>().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

View File

@ -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<QString, QString> _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

View File

@ -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

View File

@ -15,6 +15,7 @@
#include "PFXHelpers.h"
#include "PFXHttpRequest.h"
#include "PFXServerConfiguration.h"
#include "PFXOauth.h"
#include "PFXOrder.h"
#include <QMap>
@ -88,6 +89,14 @@ private:
QMap<QString, QString> _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

View File

@ -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

View File

@ -15,6 +15,7 @@
#include "PFXHelpers.h"
#include "PFXHttpRequest.h"
#include "PFXServerConfiguration.h"
#include "PFXOauth.h"
#include "PFXUser.h"
#include <QList>
@ -110,6 +111,14 @@ private:
QMap<QString, QString> _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

View File

@ -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