2012-03-23 03:40:35 +00:00
|
|
|
/**
|
|
|
|
* KQOAuth - An OAuth authentication library for Qt.
|
|
|
|
*
|
|
|
|
* Author: Johan Paul (johan.paul@d-pointer.com)
|
|
|
|
* http://www.d-pointer.com
|
|
|
|
*
|
2012-10-12 19:36:01 +00:00
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2012-03-23 03:40:35 +00:00
|
|
|
*
|
|
|
|
* KQOAuth is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Lesser General Public License for more details.
|
|
|
|
*
|
2012-10-12 19:36:01 +00:00
|
|
|
* In addition, as a special exception, KQOauth provides you certain additional
|
|
|
|
* rights. These rights are described in the Nokia Qt LGPL Exception
|
|
|
|
* version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
*
|
2012-03-23 03:40:35 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
2012-10-12 19:36:01 +00:00
|
|
|
* along with KQOAuth. If not, see <http://www.gnu.org/licenses/>
|
2012-03-23 03:40:35 +00:00
|
|
|
*/
|
|
|
|
#include <QtCore>
|
|
|
|
|
|
|
|
#include "kqoauthmanager.h"
|
|
|
|
#include "kqoauthmanager_p.h"
|
|
|
|
|
|
|
|
|
|
|
|
////////////// Private d_ptr implementation ////////////////
|
|
|
|
|
|
|
|
KQOAuthManagerPrivate::KQOAuthManagerPrivate(KQOAuthManager *parent) :
|
|
|
|
error(KQOAuthManager::NoError) ,
|
|
|
|
r(0) ,
|
|
|
|
opaqueRequest(new KQOAuthRequest) ,
|
|
|
|
q_ptr(parent) ,
|
|
|
|
callbackServer(new KQOAuthAuthReplyServer(parent)) ,
|
|
|
|
isVerified(false) ,
|
|
|
|
isAuthorized(false) ,
|
|
|
|
autoAuth(false),
|
|
|
|
networkManager(new QNetworkAccessManager),
|
|
|
|
managerUserSet(false)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
KQOAuthManagerPrivate::~KQOAuthManagerPrivate() {
|
|
|
|
delete opaqueRequest;
|
|
|
|
opaqueRequest = 0;
|
|
|
|
|
|
|
|
if (!managerUserSet) {
|
|
|
|
delete networkManager;
|
|
|
|
networkManager = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QList< QPair<QString, QString> > KQOAuthManagerPrivate::createQueryParams(const KQOAuthParameters &requestParams) {
|
|
|
|
QList<QString> requestKeys = requestParams.keys();
|
|
|
|
QList<QString> requestValues = requestParams.values();
|
|
|
|
|
|
|
|
QList< QPair<QString, QString> > result;
|
|
|
|
for(int i=0; i<requestKeys.size(); i++) {
|
|
|
|
result.append( qMakePair(requestKeys.at(i),
|
|
|
|
requestValues.at(i))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
QMultiMap<QString, QString> KQOAuthManagerPrivate::createTokensFromResponse(QByteArray reply) {
|
|
|
|
QMultiMap<QString, QString> result;
|
|
|
|
QString replyString(reply);
|
|
|
|
|
|
|
|
QStringList parameterPairs = replyString.split('&', QString::SkipEmptyParts);
|
|
|
|
foreach (const QString ¶meterPair, parameterPairs) {
|
|
|
|
QStringList parameter = parameterPair.split('=');
|
|
|
|
result.insert(parameter.value(0), parameter.value(1));
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KQOAuthManagerPrivate::setSuccessfulRequestToken(const QMultiMap<QString, QString> &request) {
|
|
|
|
if (currentRequestType == KQOAuthRequest::TemporaryCredentials) {
|
|
|
|
hasTemporaryToken = (!QString(request.value("oauth_token")).isEmpty() && !QString(request.value("oauth_token_secret")).isEmpty());
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hasTemporaryToken) {
|
|
|
|
requestToken = QUrl::fromPercentEncoding( QString(request.value("oauth_token")).toLocal8Bit() );
|
|
|
|
requestTokenSecret = QUrl::fromPercentEncoding( QString(request.value("oauth_token_secret")).toLocal8Bit() );
|
|
|
|
}
|
|
|
|
|
|
|
|
return hasTemporaryToken;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KQOAuthManagerPrivate::setSuccessfulAuthorized(const QMultiMap<QString, QString> &request ) {
|
|
|
|
if (currentRequestType == KQOAuthRequest::AccessToken) {
|
|
|
|
isAuthorized = (!QString(request.value("oauth_token")).isEmpty() && !QString(request.value("oauth_token_secret")).isEmpty());
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isAuthorized) {
|
|
|
|
requestToken = QUrl::fromPercentEncoding( QString(request.value("oauth_token")).toLocal8Bit() );
|
|
|
|
requestTokenSecret = QUrl::fromPercentEncoding( QString(request.value("oauth_token_secret")).toLocal8Bit() );
|
|
|
|
}
|
|
|
|
|
|
|
|
return isAuthorized;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KQOAuthManagerPrivate::emitTokens() {
|
|
|
|
Q_Q(KQOAuthManager);
|
|
|
|
|
|
|
|
if (this->requestToken.isEmpty() || this->requestTokenSecret.isEmpty()) {
|
|
|
|
error = KQOAuthManager::RequestUnauthorized;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (currentRequestType == KQOAuthRequest::TemporaryCredentials) {
|
|
|
|
// Signal that we are ready to use the protected resources.
|
|
|
|
emit q->temporaryTokenReceived(this->requestToken, this->requestTokenSecret);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (currentRequestType == KQOAuthRequest::AccessToken) {
|
|
|
|
// Signal that we are ready to use the protected resources.
|
|
|
|
emit q->accessTokenReceived(this->requestToken, this->requestTokenSecret);
|
|
|
|
}
|
|
|
|
|
|
|
|
emit q->receivedToken(this->requestToken, this->requestTokenSecret);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KQOAuthManagerPrivate::setupCallbackServer() {
|
2016-08-09 20:27:14 +00:00
|
|
|
return callbackServer->listen(QHostAddress::LocalHost, CALLBACK_PORT);
|
2012-03-23 03:40:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////// Public implementation ////////////////
|
|
|
|
|
|
|
|
KQOAuthManager::KQOAuthManager(QObject *parent) :
|
|
|
|
QObject(parent) ,
|
|
|
|
d_ptr(new KQOAuthManagerPrivate(this))
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
KQOAuthManager::~KQOAuthManager()
|
|
|
|
{
|
|
|
|
delete d_ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KQOAuthManager::executeRequest(KQOAuthRequest *request) {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
d->r = request;
|
|
|
|
|
|
|
|
if (request == 0) {
|
|
|
|
qWarning() << "Request is NULL. Cannot proceed.";
|
|
|
|
d->error = KQOAuthManager::RequestError;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!request->requestEndpoint().isValid()) {
|
2012-04-11 18:01:21 +00:00
|
|
|
qDebug() << request->requestEndpoint();
|
2012-03-23 03:40:35 +00:00
|
|
|
qWarning() << "Request endpoint URL is not valid. Cannot proceed.";
|
|
|
|
d->error = KQOAuthManager::RequestEndpointError;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!request->isValid()) {
|
|
|
|
qWarning() << "Request is not valid. Cannot proceed.";
|
|
|
|
d->error = KQOAuthManager::RequestValidationError;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->currentRequestType = request->requestType();
|
|
|
|
|
|
|
|
QNetworkRequest networkRequest;
|
|
|
|
networkRequest.setUrl( request->requestEndpoint() );
|
|
|
|
|
|
|
|
if (d->autoAuth && d->currentRequestType == KQOAuthRequest::TemporaryCredentials) {
|
|
|
|
d->setupCallbackServer();
|
|
|
|
connect(d->callbackServer, SIGNAL(verificationReceived(QMultiMap<QString, QString>)),
|
|
|
|
this, SLOT( onVerificationReceived(QMultiMap<QString, QString>)));
|
|
|
|
|
|
|
|
QString serverString = "http://localhost:";
|
|
|
|
serverString.append(QString::number(d->callbackServer->serverPort()));
|
|
|
|
request->setCallbackUrl(QUrl(serverString));
|
|
|
|
qDebug() << serverString;
|
|
|
|
}
|
|
|
|
|
|
|
|
// And now fill the request with "Authorization" header data.
|
|
|
|
QList<QByteArray> requestHeaders = request->requestParameters();
|
|
|
|
QByteArray authHeader;
|
|
|
|
|
|
|
|
bool first = true;
|
|
|
|
foreach (const QByteArray header, requestHeaders) {
|
|
|
|
if (!first) {
|
|
|
|
authHeader.append(", ");
|
|
|
|
} else {
|
|
|
|
authHeader.append("OAuth ");
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
authHeader.append(header);
|
|
|
|
}
|
|
|
|
networkRequest.setRawHeader("Authorization", authHeader);
|
|
|
|
|
|
|
|
connect(d->networkManager, SIGNAL(finished(QNetworkReply *)),
|
|
|
|
this, SLOT(onRequestReplyReceived(QNetworkReply *)), Qt::UniqueConnection);
|
|
|
|
disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)),
|
|
|
|
this, SLOT(onAuthorizedRequestReplyReceived(QNetworkReply *)));
|
|
|
|
|
|
|
|
if (request->httpMethod() == KQOAuthRequest::GET) {
|
|
|
|
// Get the requested additional params as a list of pairs we can give QUrl
|
|
|
|
QList< QPair<QString, QString> > urlParams = d->createQueryParams(request->additionalParameters());
|
|
|
|
|
|
|
|
// Take the original URL and append the query params to it.
|
|
|
|
QUrl urlWithParams = networkRequest.url();
|
|
|
|
urlWithParams.setQueryItems(urlParams);
|
|
|
|
networkRequest.setUrl(urlWithParams);
|
|
|
|
|
|
|
|
// Submit the request including the params.
|
|
|
|
QNetworkReply *reply = d->networkManager->get(networkRequest);
|
2012-04-11 18:01:21 +00:00
|
|
|
reply->ignoreSslErrors();
|
2012-03-23 03:40:35 +00:00
|
|
|
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
|
|
|
|
this, SLOT(slotError(QNetworkReply::NetworkError)));
|
|
|
|
|
2016-09-30 21:21:39 +00:00
|
|
|
} else if (request->httpMethod() == KQOAuthRequest::POST || request->httpMethod() == KQOAuthRequest::DELETE || request->httpMethod() == KQOAuthRequest::PUT) {
|
2012-03-23 03:40:35 +00:00
|
|
|
|
|
|
|
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, request->contentType());
|
|
|
|
|
|
|
|
qDebug() << networkRequest.rawHeaderList();
|
|
|
|
qDebug() << networkRequest.rawHeader("Authorization");
|
|
|
|
qDebug() << networkRequest.rawHeader("Content-Type");
|
|
|
|
|
|
|
|
QNetworkReply *reply;
|
2016-09-30 21:21:39 +00:00
|
|
|
if (request->httpMethod() == KQOAuthRequest::PUT) {
|
|
|
|
reply = d->networkManager->put(networkRequest, request->requestBody());
|
|
|
|
} else if (request->httpMethod() == KQOAuthRequest::DELETE) {
|
|
|
|
reply = d->networkManager->deleteResource(networkRequest);
|
|
|
|
} else if (request->contentType() == "application/x-www-form-urlencoded") {
|
2012-03-23 03:40:35 +00:00
|
|
|
reply = d->networkManager->post(networkRequest, request->requestBody());
|
|
|
|
} else {
|
|
|
|
reply = d->networkManager->post(networkRequest, request->rawData());
|
|
|
|
}
|
2012-04-11 18:01:21 +00:00
|
|
|
reply->ignoreSslErrors();
|
2012-03-23 03:40:35 +00:00
|
|
|
|
|
|
|
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
|
|
|
|
this, SLOT(slotError(QNetworkReply::NetworkError)));
|
|
|
|
}
|
|
|
|
|
|
|
|
d->r->requestTimerStart();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KQOAuthManager::executeAuthorizedRequest(KQOAuthRequest *request, int id) {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
d->r = request;
|
|
|
|
|
|
|
|
if (request == 0) {
|
|
|
|
qWarning() << "Request is NULL. Cannot proceed.";
|
|
|
|
d->error = KQOAuthManager::RequestError;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!request->requestEndpoint().isValid()) {
|
2012-04-11 18:01:21 +00:00
|
|
|
qDebug() << request->requestEndpoint();
|
2012-03-23 03:40:35 +00:00
|
|
|
qWarning() << "Request endpoint URL is not valid. Cannot proceed.";
|
|
|
|
d->error = KQOAuthManager::RequestEndpointError;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!request->isValid()) {
|
|
|
|
qWarning() << "Request is not valid. Cannot proceed.";
|
|
|
|
d->error = KQOAuthManager::RequestValidationError;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->currentRequestType = request->requestType();
|
|
|
|
|
|
|
|
QNetworkRequest networkRequest;
|
|
|
|
networkRequest.setUrl( request->requestEndpoint() );
|
|
|
|
|
|
|
|
if ( d->currentRequestType != KQOAuthRequest::AuthorizedRequest){
|
|
|
|
qWarning() << "Not Authorized Request. Cannot proceed";
|
|
|
|
d->error = KQOAuthManager::RequestError;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(request->oauthMethod() != KQOAuthRequest::OAUTH2) {
|
|
|
|
// And now fill the request with "Authorization" header data.
|
|
|
|
QList<QByteArray> requestHeaders = request->requestParameters();
|
|
|
|
QByteArray authHeader;
|
|
|
|
|
|
|
|
bool first = true;
|
|
|
|
foreach (const QByteArray header, requestHeaders) {
|
|
|
|
if (!first) {
|
|
|
|
authHeader.append(", ");
|
|
|
|
} else {
|
|
|
|
authHeader.append("OAuth ");
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
authHeader.append(header);
|
|
|
|
}
|
|
|
|
networkRequest.setRawHeader("Authorization", authHeader);
|
|
|
|
}
|
|
|
|
|
2016-08-10 14:24:29 +00:00
|
|
|
if(request->oauthMethod() == KQOAuthRequest::OAUTH2) {
|
|
|
|
QByteArray bearer;
|
|
|
|
bearer.append(request->additionalParameters().value("oauth_token"));
|
|
|
|
networkRequest.setRawHeader("Authorization", "Bearer " + bearer);
|
|
|
|
qDebug() << networkRequest.rawHeader("Authorization");
|
|
|
|
}
|
2012-03-23 03:40:35 +00:00
|
|
|
|
|
|
|
disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)),
|
|
|
|
this, SLOT(onRequestReplyReceived(QNetworkReply *)));
|
|
|
|
connect(d->networkManager, SIGNAL(finished(QNetworkReply *)),
|
|
|
|
this, SLOT(onAuthorizedRequestReplyReceived(QNetworkReply*)), Qt::UniqueConnection);
|
|
|
|
|
|
|
|
if (request->httpMethod() == KQOAuthRequest::GET) {
|
2016-08-10 14:24:29 +00:00
|
|
|
// Pull the oauth_token parameter because Dropbox
|
|
|
|
KQOAuthParameters adtlparams = request->additionalParameters();
|
|
|
|
adtlparams.remove("oauth_token");
|
|
|
|
qDebug() << adtlparams;
|
|
|
|
|
2012-03-23 03:40:35 +00:00
|
|
|
// Get the requested additional params as a list of pairs we can give QUrl
|
2016-08-10 14:24:29 +00:00
|
|
|
// QList< QPair<QString, QString> > urlParams = d->createQueryParams(request->additionalParameters());
|
|
|
|
QList< QPair<QString, QString> > urlParams = d->createQueryParams(adtlparams);
|
2012-03-23 03:40:35 +00:00
|
|
|
|
|
|
|
// Take the original URL and append the query params to it.
|
|
|
|
QUrl urlWithParams = networkRequest.url();
|
|
|
|
urlWithParams.setQueryItems(urlParams);
|
|
|
|
networkRequest.setUrl(urlWithParams);
|
2012-03-30 06:11:36 +00:00
|
|
|
qDebug() << networkRequest.url();
|
2012-03-23 03:40:35 +00:00
|
|
|
|
|
|
|
// Submit the request including the params.
|
|
|
|
QNetworkReply *reply = d->networkManager->get(networkRequest);
|
2012-04-11 18:01:21 +00:00
|
|
|
reply->ignoreSslErrors();
|
2016-08-10 14:24:29 +00:00
|
|
|
|
|
|
|
d->requestIds.insert(reply, id);
|
|
|
|
|
2012-03-23 03:40:35 +00:00
|
|
|
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
|
|
|
|
this, SLOT(slotError(QNetworkReply::NetworkError)));
|
|
|
|
|
2016-09-30 21:21:39 +00:00
|
|
|
} else if (request->httpMethod() == KQOAuthRequest::POST || request->httpMethod() == KQOAuthRequest::DELETE || request->httpMethod() == KQOAuthRequest::PUT) {
|
2012-03-23 03:40:35 +00:00
|
|
|
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, request->contentType());
|
|
|
|
|
2016-08-10 14:24:29 +00:00
|
|
|
QByteArray argHeader;
|
|
|
|
argHeader.append(request->additionalParameters().value("arg"));
|
|
|
|
networkRequest.setRawHeader("Dropbox-API-Arg", argHeader);
|
|
|
|
|
2012-03-23 03:40:35 +00:00
|
|
|
qDebug() << networkRequest.rawHeaderList();
|
|
|
|
qDebug() << networkRequest.rawHeader("Authorization");
|
|
|
|
qDebug() << networkRequest.rawHeader("Content-Type");
|
2012-03-30 06:11:36 +00:00
|
|
|
|
2012-03-23 03:40:35 +00:00
|
|
|
QNetworkReply *reply;
|
2016-09-30 21:21:39 +00:00
|
|
|
if (request->httpMethod() == KQOAuthRequest::PUT) {
|
|
|
|
reply = d->networkManager->put(networkRequest, request->requestBody());
|
|
|
|
} else if (request->httpMethod() == KQOAuthRequest::DELETE) {
|
|
|
|
reply = d->networkManager->deleteResource(networkRequest);
|
|
|
|
} else if (request->contentType() == "application/x-www-form-urlencoded") {
|
2012-03-23 03:40:35 +00:00
|
|
|
reply = d->networkManager->post(networkRequest, request->requestBody());
|
|
|
|
} else {
|
|
|
|
reply = d->networkManager->post(networkRequest, request->rawData());
|
|
|
|
}
|
2012-04-19 06:48:41 +00:00
|
|
|
reply->ignoreSslErrors();
|
2012-03-23 03:40:35 +00:00
|
|
|
|
|
|
|
d->requestIds.insert(reply, id);
|
|
|
|
|
|
|
|
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
|
|
|
|
this, SLOT(slotError(QNetworkReply::NetworkError)));
|
|
|
|
}
|
|
|
|
|
|
|
|
d->r->requestTimerStart();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KQOAuthManager::setHandleUserAuthorization(bool set) {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
d->autoAuth = set;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KQOAuthManager::hasTemporaryToken() {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
return d->hasTemporaryToken;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KQOAuthManager::isVerified() {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
return d->isVerified;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KQOAuthManager::isAuthorized() {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
return d->isAuthorized;
|
|
|
|
}
|
|
|
|
|
|
|
|
KQOAuthManager::KQOAuthError KQOAuthManager::lastError() {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
return d->error;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KQOAuthManager::setNetworkManager(QNetworkAccessManager *manager) {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
if (manager == 0) {
|
|
|
|
d->error = KQOAuthManager::ManagerError;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!d->managerUserSet) {
|
|
|
|
delete d->networkManager;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->managerUserSet = true;
|
|
|
|
d->networkManager = manager;
|
|
|
|
}
|
|
|
|
|
|
|
|
QNetworkAccessManager * KQOAuthManager::networkManager() const {
|
|
|
|
Q_D(const KQOAuthManager);
|
|
|
|
|
|
|
|
if (d->managerUserSet) {
|
|
|
|
return d->networkManager;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void KQOAuthManager::setSuccessHtmlFile(QString file) {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
d->successHtmlFile = file;
|
|
|
|
d->callbackServer->setSuccessHtmlFile(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////// Public convenience API /////////////
|
2012-04-19 06:48:41 +00:00
|
|
|
void KQOAuthManager::getOauth2UserAuthorization(QUrl authorizationEndpoint, QString consumerKey, const KQOAuthParameters &additionalParams) {
|
2012-03-23 03:40:35 +00:00
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
d->setupCallbackServer();
|
|
|
|
connect(d->callbackServer, SIGNAL(verificationReceived(QMultiMap<QString, QString>)),
|
2012-04-11 18:01:21 +00:00
|
|
|
this, SLOT( onOauth2VerificationReceived(QMultiMap<QString, QString>)));
|
2012-03-23 03:40:35 +00:00
|
|
|
|
|
|
|
QString serverString = "http://localhost:";
|
|
|
|
serverString.append(QString::number(d->callbackServer->serverPort()));
|
|
|
|
QUrl openWebPageUrl(authorizationEndpoint.toString(), QUrl::StrictMode);
|
|
|
|
openWebPageUrl.addQueryItem(OAUTH2_KEY_CLIENT_ID, consumerKey);
|
|
|
|
openWebPageUrl.addQueryItem(OAUTH2_KEY_RESPONSE_TYPE, "token");
|
|
|
|
openWebPageUrl.addQueryItem(OAUTH2_KEY_REDIRECT_URI, serverString);
|
2012-04-19 06:48:41 +00:00
|
|
|
if(additionalParams.size() > 0) {
|
|
|
|
QList< QPair<QString, QString> > urlParams = d->createQueryParams(additionalParams);
|
|
|
|
for(int i=0; i < urlParams.length(); i++){
|
|
|
|
openWebPageUrl.addQueryItem(urlParams[i].first, urlParams[i].second);
|
|
|
|
}
|
|
|
|
}
|
2012-03-23 03:40:35 +00:00
|
|
|
qDebug() << openWebPageUrl.toString();
|
2017-11-05 14:15:08 +00:00
|
|
|
emit openBrowser(openWebPageUrl);
|
2012-03-23 03:40:35 +00:00
|
|
|
}
|
|
|
|
|
2013-01-05 06:49:33 +00:00
|
|
|
QUrl KQOAuthManager::getUserAuthorizationUrl(QUrl authorizationEndpoint) {
|
2012-03-23 03:40:35 +00:00
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
if (!d->hasTemporaryToken) {
|
|
|
|
qWarning() << "No temporary tokens retreieved. Cannot get user authorization.";
|
|
|
|
d->error = KQOAuthManager::RequestUnauthorized;
|
2013-01-05 06:49:33 +00:00
|
|
|
return QUrl();
|
2012-03-23 03:40:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!authorizationEndpoint.isValid()) {
|
|
|
|
qWarning() << "Authorization endpoint not valid. Cannot proceed.";
|
|
|
|
d->error = KQOAuthManager::RequestEndpointError;
|
2013-01-05 06:49:33 +00:00
|
|
|
return QUrl();
|
2012-03-23 03:40:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
d->error = KQOAuthManager::NoError;
|
|
|
|
|
|
|
|
QPair<QString, QString> tokenParam = qMakePair(QString("oauth_token"), QString(d->requestToken));
|
|
|
|
QUrl openWebPageUrl(authorizationEndpoint.toString(), QUrl::StrictMode);
|
|
|
|
openWebPageUrl.addQueryItem(tokenParam.first, tokenParam.second);
|
|
|
|
|
|
|
|
qDebug() << openWebPageUrl.toString();
|
2013-01-05 06:49:33 +00:00
|
|
|
return openWebPageUrl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KQOAuthManager::getUserAuthorization(QUrl authorizationEndpoint) {
|
|
|
|
QUrl openWebPageUrl = getUserAuthorizationUrl(authorizationEndpoint);
|
|
|
|
|
|
|
|
if(!openWebPageUrl.isEmpty()) {
|
|
|
|
// Open the user's default browser to the resource authorization page provided
|
|
|
|
// by the service.
|
|
|
|
|
2017-11-05 14:15:08 +00:00
|
|
|
emit openBrowser(openWebPageUrl);
|
2013-01-05 06:49:33 +00:00
|
|
|
}
|
2012-03-23 03:40:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void KQOAuthManager::getUserAccessTokens(QUrl accessTokenEndpoint) {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
if (!d->isVerified) {
|
|
|
|
qWarning() << "Not verified. Cannot get access tokens.";
|
|
|
|
d->error = KQOAuthManager::RequestUnauthorized;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!accessTokenEndpoint.isValid()) {
|
|
|
|
qWarning() << "Endpoint for access token exchange is not valid. Cannot proceed.";
|
|
|
|
d->error = KQOAuthManager::RequestEndpointError;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->error = KQOAuthManager::NoError;
|
|
|
|
|
|
|
|
d->opaqueRequest->clearRequest();
|
|
|
|
d->opaqueRequest->initRequest(KQOAuthRequest::AccessToken, accessTokenEndpoint);
|
|
|
|
d->opaqueRequest->setToken(d->requestToken);
|
|
|
|
d->opaqueRequest->setTokenSecret(d->requestTokenSecret);
|
|
|
|
d->opaqueRequest->setVerifier(d->requestVerifier);
|
|
|
|
d->opaqueRequest->setConsumerKey(d->consumerKey);
|
|
|
|
d->opaqueRequest->setConsumerSecretKey(d->consumerKeySecret);
|
|
|
|
|
|
|
|
executeRequest(d->opaqueRequest);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KQOAuthManager::sendAuthorizedRequest(QUrl requestEndpoint, const KQOAuthParameters &requestParameters) {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
if (!d->isAuthorized) {
|
|
|
|
qWarning() << "No access tokens retrieved. Cannot send authorized requests.";
|
|
|
|
d->error = KQOAuthManager::RequestUnauthorized;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!requestEndpoint.isValid()) {
|
|
|
|
qWarning() << "Endpoint for authorized request is not valid. Cannot proceed.";
|
|
|
|
d->error = KQOAuthManager::RequestEndpointError;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->error = KQOAuthManager::NoError;
|
|
|
|
|
|
|
|
d->opaqueRequest->clearRequest();
|
|
|
|
d->opaqueRequest->initRequest(KQOAuthRequest::AuthorizedRequest, requestEndpoint);
|
|
|
|
d->opaqueRequest->setAdditionalParameters(requestParameters);
|
|
|
|
d->opaqueRequest->setToken(d->requestToken);
|
|
|
|
d->opaqueRequest->setTokenSecret(d->requestTokenSecret);
|
|
|
|
d->opaqueRequest->setConsumerKey(d->consumerKey);
|
|
|
|
d->opaqueRequest->setConsumerSecretKey(d->consumerKeySecret);
|
|
|
|
|
|
|
|
executeRequest(d->opaqueRequest);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////// Private slots //////////////////
|
|
|
|
|
|
|
|
void KQOAuthManager::onRequestReplyReceived( QNetworkReply *reply ) {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
QNetworkReply::NetworkError networkError = reply->error();
|
|
|
|
switch (networkError) {
|
|
|
|
case QNetworkReply::NoError:
|
|
|
|
d->error = KQOAuthManager::NoError;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QNetworkReply::ContentAccessDenied:
|
|
|
|
case QNetworkReply::AuthenticationRequiredError:
|
|
|
|
d->error = KQOAuthManager::RequestUnauthorized;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
d->error = KQOAuthManager::NetworkError;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let's disconnect this slot first
|
|
|
|
/*
|
|
|
|
disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)),
|
|
|
|
this, SLOT(onRequestReplyReceived(QNetworkReply *)));
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Read the content of the reply from the network.
|
|
|
|
QByteArray networkReply = reply->readAll();
|
|
|
|
|
|
|
|
// Stop any timer we have set on the request.
|
|
|
|
d->r->requestTimerStop();
|
|
|
|
|
|
|
|
// Just don't do anything if we didn't get anything useful.
|
|
|
|
if(networkReply.isEmpty()) {
|
|
|
|
reply->deleteLater();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
QMultiMap<QString, QString> responseTokens;
|
|
|
|
|
|
|
|
// We need to emit the signal even if we got an error.
|
|
|
|
if (d->error != KQOAuthManager::NoError) {
|
|
|
|
reply->deleteLater();
|
|
|
|
emit requestReady(networkReply);
|
|
|
|
d->emitTokens();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
responseTokens = d->createTokensFromResponse(networkReply);
|
|
|
|
d->opaqueRequest->clearRequest();
|
|
|
|
d->opaqueRequest->setHttpMethod(KQOAuthRequest::POST); // XXX FIXME: Convenient API does not support GET
|
|
|
|
if (!d->isAuthorized || !d->isVerified) {
|
|
|
|
if (d->setSuccessfulRequestToken(responseTokens)) {
|
|
|
|
qDebug() << "Successfully got request tokens.";
|
|
|
|
d->consumerKey = d->r->consumerKeyForManager();
|
|
|
|
d->consumerKeySecret = d->r->consumerKeySecretForManager();
|
|
|
|
d->opaqueRequest->setSignatureMethod(KQOAuthRequest::HMAC_SHA1);
|
|
|
|
d->opaqueRequest->setCallbackUrl(d->r->callbackUrlForManager());
|
|
|
|
|
|
|
|
d->emitTokens();
|
|
|
|
|
|
|
|
} else if (d->setSuccessfulAuthorized(responseTokens)) {
|
|
|
|
qDebug() << "Successfully got access tokens.";
|
|
|
|
d->opaqueRequest->setSignatureMethod(KQOAuthRequest::HMAC_SHA1);
|
|
|
|
|
|
|
|
d->emitTokens();
|
|
|
|
} else if (d->currentRequestType == KQOAuthRequest::AuthorizedRequest) {
|
|
|
|
emit authorizedRequestDone();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
emit requestReady(networkReply);
|
|
|
|
|
|
|
|
reply->deleteLater(); // We need to clean this up, after the event processing is done.
|
|
|
|
}
|
|
|
|
|
|
|
|
void KQOAuthManager::onAuthorizedRequestReplyReceived( QNetworkReply *reply ) {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
QNetworkReply::NetworkError networkError = reply->error();
|
2016-08-10 14:24:29 +00:00
|
|
|
qDebug() << networkError;
|
2012-03-23 03:40:35 +00:00
|
|
|
switch (networkError) {
|
|
|
|
case QNetworkReply::NoError:
|
|
|
|
d->error = KQOAuthManager::NoError;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QNetworkReply::ContentAccessDenied:
|
|
|
|
case QNetworkReply::AuthenticationRequiredError:
|
|
|
|
d->error = KQOAuthManager::RequestUnauthorized;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
d->error = KQOAuthManager::NetworkError;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)),
|
|
|
|
this, SLOT(onAuthorizedRequestReplyReceived(QNetworkReply *)));
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Read the content of the reply from the network.
|
|
|
|
QByteArray networkReply = reply->readAll();
|
2016-08-10 14:24:29 +00:00
|
|
|
qDebug() << networkReply;
|
2012-03-23 03:40:35 +00:00
|
|
|
|
|
|
|
// Stop any timer we have set on the request.
|
|
|
|
d->r->requestTimerStop();
|
|
|
|
|
|
|
|
// Just don't do anything if we didn't get anything useful.
|
|
|
|
if(networkReply.isEmpty()) {
|
2017-11-05 14:15:08 +00:00
|
|
|
qDebug() << "EMPTY REPLY";
|
2012-03-23 03:40:35 +00:00
|
|
|
reply->deleteLater();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to emit the signal even if we got an error.
|
|
|
|
if (d->error != KQOAuthManager::NoError) {
|
|
|
|
qWarning() << "Network reply error";
|
2016-08-10 14:24:29 +00:00
|
|
|
qDebug() << d->error;
|
2016-10-01 19:17:13 +00:00
|
|
|
emit requestReady(networkReply);
|
2012-03-23 03:40:35 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
d->opaqueRequest->clearRequest();
|
|
|
|
d->opaqueRequest->setHttpMethod(KQOAuthRequest::POST); // XXX FIXME: Convenient API does not support GET
|
|
|
|
if (d->currentRequestType == KQOAuthRequest::AuthorizedRequest) {
|
|
|
|
emit authorizedRequestDone();
|
|
|
|
}
|
|
|
|
|
|
|
|
int id = d->requestIds.take(reply);
|
|
|
|
emit authorizedRequestReady(networkReply, id);
|
|
|
|
reply->deleteLater();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KQOAuthManager::onVerificationReceived(QMultiMap<QString, QString> response) {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
QString token = response.value("oauth_token");
|
|
|
|
QString verifier = response.value("oauth_verifier");
|
|
|
|
if (verifier.isEmpty()) {
|
|
|
|
d->error = KQOAuthManager::RequestUnauthorized;
|
|
|
|
}
|
|
|
|
|
|
|
|
verifier = QUrl::fromPercentEncoding(verifier.toUtf8()); // We get the raw URL response here so we need to convert it back
|
|
|
|
// to plain string so we can percent encode it again later in requests.
|
|
|
|
|
|
|
|
if (d->error == KQOAuthManager::NoError) {
|
|
|
|
d->requestVerifier = verifier;
|
|
|
|
d->isVerified = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit authorizationReceived(token, verifier);
|
|
|
|
}
|
|
|
|
|
2012-04-11 18:01:21 +00:00
|
|
|
void KQOAuthManager::onOauth2VerificationReceived(QMultiMap<QString, QString> response) {
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
foreach(QString key, response.keys()){
|
|
|
|
qDebug() << key;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString token = response.value("access_token");
|
|
|
|
if (token.isEmpty()) {
|
|
|
|
d->error = KQOAuthManager::RequestUnauthorized;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d->error == KQOAuthManager::NoError) {
|
|
|
|
d->isVerified = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit authorizationReceived(token, NULL);
|
|
|
|
}
|
|
|
|
|
2012-03-23 03:40:35 +00:00
|
|
|
void KQOAuthManager::slotError(QNetworkReply::NetworkError error) {
|
|
|
|
Q_UNUSED(error)
|
|
|
|
Q_D(KQOAuthManager);
|
|
|
|
|
|
|
|
d->error = KQOAuthManager::NetworkError;
|
|
|
|
QByteArray emptyResponse;
|
|
|
|
emit requestReady(emptyResponse);
|
|
|
|
emit authorizedRequestDone();
|
|
|
|
|
|
|
|
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
|
|
|
|
d->requestIds.remove(reply);
|
|
|
|
reply->deleteLater();
|
|
|
|
}
|
|
|
|
|
2012-04-11 18:01:21 +00:00
|
|
|
void KQOAuthManager::onSslError(QNetworkReply *reply, const QList<QSslError> &errors) {
|
|
|
|
Q_UNUSED(errors);
|
|
|
|
reply->ignoreSslErrors();
|
|
|
|
}
|
|
|
|
|