diff --git a/README b/README.md
similarity index 90%
rename from README
rename to README.md
index 4280f41..3b53c8b 100644
--- a/README
+++ b/README.md
@@ -1,4 +1,5 @@
-#About the oauth library for BlackBerry 10
+About the oauth library for BlackBerry 10
+==========================================
This is a OAuth library built for the Cascades development framework for BlackBerry 10. It is a fork and BlackBerry specific implementation of the KQOauth library that can be found here http://www.gitorious.org/kqoauth under the LGPL license.
This library supports both OAuth1 and OAuth2 authorization flow and authorized requests.
diff --git a/oauth/kqoauth2request.cpp b/oauth/kqoauth2request.cpp
new file mode 100644
index 0000000..ef72428
--- /dev/null
+++ b/oauth/kqoauth2request.cpp
@@ -0,0 +1,56 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#include
+
+#include "kqoauth2request_p.h"
+#include "kqoauth2request.h"
+
+/**
+ * Private d_ptr implementations.
+ */
+KQOAuth2Request_Private::KQOAuth2Request_Private()
+{
+
+}
+
+KQOAuth2Request_Private::~KQOAuth2Request_Private()
+{
+}
+
+/**
+ * Public implementations.
+ */
+KQOAuth2Request::KQOAuth2Request(QObject *parent) :
+ KQOAuthRequest(parent),
+ d_ptr(new KQOAuth2Request_Private)
+{
+}
+
+bool KQOAuth2Request::isValid() const {
+ // Access token must always be retrieved using the POST HTTP method.
+ // And then check the validity of the XAuth request.
+ // Provided by the base class as a protected method for us.
+ return validateOauth2Request();
+}
+
+void KQOAuth2Request::initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint) {
+ KQOAuthRequest::initRequest(type,requestEndpoint);
+ setRequestOAuthMethod(KQOAuthRequest::OAUTH2);
+}
diff --git a/oauth/kqoauth2request.h b/oauth/kqoauth2request.h
new file mode 100644
index 0000000..1bcc15e
--- /dev/null
+++ b/oauth/kqoauth2request.h
@@ -0,0 +1,45 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#ifndef KQOAUTH2REQUEST_H
+#define KQOAUTH2REQUEST_H
+
+#include "kqoauthrequest.h"
+#include "kqoauthrequest_1.h"
+
+class KQOAuth2Request_Private;
+class KQOAUTH_EXPORT KQOAuth2Request : public KQOAuthRequest
+{
+ Q_OBJECT
+public:
+ KQOAuth2Request(QObject *parent = 0);
+
+ /**
+ * These methods can be overridden in child classes which are different types of
+ * OAuth requests.
+ */
+ // Validate the request of this type.
+ bool isValid() const;
+ void initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint);
+
+private:
+ KQOAuth2Request_Private * const d_ptr;
+};
+
+#endif // KQOAUTHREQUEST_XAUTH_H
diff --git a/oauth/kqoauth2request_p.h b/oauth/kqoauth2request_p.h
new file mode 100644
index 0000000..2a0dcd3
--- /dev/null
+++ b/oauth/kqoauth2request_p.h
@@ -0,0 +1,14 @@
+#ifndef KQOAUTH2REQUEST_P_H
+#define KQOAUTH2REQUEST_P_H
+
+#include "kqoauthglobals.h"
+
+class KQOAuthRequest;
+class KQOAUTH_EXPORT KQOAuth2Request_Private
+{
+public:
+ KQOAuth2Request_Private();
+ ~KQOAuth2Request_Private();
+};
+
+#endif // KQOAUTHREQUEST_XAUTH_P_H
diff --git a/oauth/kqoauthauthreplyserver.cpp b/oauth/kqoauthauthreplyserver.cpp
new file mode 100644
index 0000000..cc666db
--- /dev/null
+++ b/oauth/kqoauthauthreplyserver.cpp
@@ -0,0 +1,110 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#include
+#include
+#include
+
+#include "kqoauthauthreplyserver.h"
+#include "kqoauthauthreplyserver_p.h"
+
+KQOAuthAuthReplyServerPrivate::KQOAuthAuthReplyServerPrivate(KQOAuthAuthReplyServer *parent):
+ q_ptr(parent)
+{
+
+}
+
+KQOAuthAuthReplyServerPrivate::~KQOAuthAuthReplyServerPrivate()
+{
+
+}
+
+void KQOAuthAuthReplyServerPrivate::onIncomingConnection() {
+ Q_Q(KQOAuthAuthReplyServer);
+
+ socket = q->nextPendingConnection();
+ connect(socket, SIGNAL(readyRead()),
+ this, SLOT(onBytesReady()), Qt::UniqueConnection);
+}
+
+void KQOAuthAuthReplyServerPrivate::onBytesReady() {
+ Q_Q(KQOAuthAuthReplyServer);
+
+ QByteArray reply;
+ QByteArray content;
+ content.append("Account authorized, go ahead back to the tumblr app and start your experience!
");
+
+ reply.append("HTTP/1.0 200 OK \r\n");
+ reply.append("Content-Type: text/html; charset=\"utf-8\"\r\n");
+ reply.append(QString("Content-Length: %1\r\n").arg(content.size()));
+ reply.append("\r\n");
+ reply.append(content);
+ socket->write(reply);
+
+ QByteArray data = socket->readAll();
+ QMultiMap queryParams = parseQueryParams(&data);
+
+ socket->disconnectFromHost();
+ q->close();
+ emit q->verificationReceived(queryParams);
+}
+
+QMultiMap KQOAuthAuthReplyServerPrivate::parseQueryParams(QByteArray *data) {
+ QString splitGetLine = QString(*data).split("\r\n").first(); // Retrieve the first line with query params.
+ splitGetLine.remove("GET "); // Clean the line from GET
+ splitGetLine.remove("HTTP/1.1"); // From HTTP
+ splitGetLine.remove("\r\n"); // And from rest.
+ splitGetLine.prepend("http://localhost"); // Now, make it a URL
+
+ QUrl getTokenUrl(splitGetLine);
+ QList< QPair > tokens = getTokenUrl.queryItems(); // Ask QUrl to do our work.
+
+ QMultiMap queryParams;
+ QPair tokenPair;
+ foreach (tokenPair, tokens) {
+ queryParams.insert(tokenPair.first.trimmed(), tokenPair.second.trimmed());
+ }
+
+ return queryParams;
+}
+
+
+
+KQOAuthAuthReplyServer::KQOAuthAuthReplyServer(QObject *parent) :
+ QTcpServer(parent),
+ d_ptr( new KQOAuthAuthReplyServerPrivate(this) )
+{
+ Q_D(KQOAuthAuthReplyServer);
+
+ connect(this, SIGNAL(newConnection()),
+ d, SLOT(onIncomingConnection()));
+}
+
+KQOAuthAuthReplyServer::~KQOAuthAuthReplyServer()
+{
+ delete d_ptr;
+}
+
+
+void KQOAuthAuthReplyServer::setSuccessHtmlFile(QString filePath) {
+ Q_D(KQOAuthAuthReplyServer);
+ d->localFile = filePath;
+}
+
+
diff --git a/oauth/kqoauthauthreplyserver.h b/oauth/kqoauthauthreplyserver.h
new file mode 100644
index 0000000..409a165
--- /dev/null
+++ b/oauth/kqoauthauthreplyserver.h
@@ -0,0 +1,48 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#ifndef KQOAUTHAUTHREPLYSERVER_H
+#define KQOAUTHAUTHREPLYSERVER_H
+
+#include
+
+#include "kqoauthglobals.h"
+
+class KQOAuthAuthReplyServerPrivate;
+class KQOAUTH_EXPORT KQOAuthAuthReplyServer : public QTcpServer
+{
+ Q_OBJECT
+public:
+ explicit KQOAuthAuthReplyServer(QObject *parent);
+ ~KQOAuthAuthReplyServer();
+ void setSuccessHtmlFile(QString filePath);
+
+Q_SIGNALS:
+ void verificationReceived(QMultiMap);
+
+
+private:
+ KQOAuthAuthReplyServerPrivate * const d_ptr;
+ Q_DECLARE_PRIVATE(KQOAuthAuthReplyServer);
+ Q_DISABLE_COPY(KQOAuthAuthReplyServer);
+
+
+};
+
+#endif // KQOAUTHAUTHREPLYSERVER_H
diff --git a/oauth/kqoauthauthreplyserver_p.h b/oauth/kqoauthauthreplyserver_p.h
new file mode 100644
index 0000000..4d94ec6
--- /dev/null
+++ b/oauth/kqoauthauthreplyserver_p.h
@@ -0,0 +1,47 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+// Note this class shouldn't be copied or used and the implementation might change later.
+#ifndef KQOAUTHAUTHREPLYSERVER_P_H
+#define KQOAUTHAUTHREPLYSERVER_P_H
+
+#include "kqoauthauthreplyserver.h"
+#include
+#include
+
+class KQOAUTH_EXPORT KQOAuthAuthReplyServerPrivate: public QObject
+{
+ Q_OBJECT
+public:
+ KQOAuthAuthReplyServerPrivate( KQOAuthAuthReplyServer * parent );
+ ~KQOAuthAuthReplyServerPrivate();
+ QMultiMap parseQueryParams(QByteArray *sdata);
+
+public Q_SLOTS:
+ void onIncomingConnection();
+ void onBytesReady();
+
+public:
+ KQOAuthAuthReplyServer * q_ptr;
+ Q_DECLARE_PUBLIC(KQOAuthAuthReplyServer);
+ QTcpSocket *socket;
+ QString localFile;
+};
+
+#endif // KQOAUTHAUTHREPLYSERVER_P_H
diff --git a/oauth/kqoauthglobals.h b/oauth/kqoauthglobals.h
new file mode 100644
index 0000000..337e56e
--- /dev/null
+++ b/oauth/kqoauthglobals.h
@@ -0,0 +1,48 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#ifndef KQOAUTHGLOBALS_H
+#define KQOAUTHGLOBALS_H
+
+#include
+
+#if defined(KQOAUTH)
+# define KQOAUTH_EXPORT Q_DECL_EXPORT
+#else
+# define KQOAUTH_EXPORT Q_DECL_IMPORT
+#endif
+
+//////////// Static constant definitions ///////////
+const QString OAUTH_KEY_CONSUMER("oauth_consumer");
+const QString OAUTH_KEY_CONSUMER_KEY("oauth_consumer_key");
+const QString OAUTH_KEY_TOKEN("oauth_token");
+const QString OAUTH_KEY_TOKEN_SECRET("oauth_token_secret");
+const QString OAUTH_KEY_SIGNATURE_METHOD("oauth_signature_method");
+const QString OAUTH_KEY_TIMESTAMP("oauth_timestamp");
+const QString OAUTH_KEY_NONCE("oauth_nonce");
+const QString OAUTH_KEY_SIGNATURE("oauth_signature");
+const QString OAUTH_KEY_CALLBACK("oauth_callback");
+const QString OAUTH_KEY_VERIFIER("oauth_verifier");
+const QString OAUTH_KEY_VERSION("oauth_version");
+const QString OAUTH2_KEY_CLIENT_ID("client_id");
+const QString OAUTH2_KEY_CLIENT_SECRET("client_secret");
+const QString OAUTH2_KEY_REDIRECT_URI("redirect_uri");
+const QString OAUTH2_KEY_RESPONSE_TYPE("response_type");
+
+#endif // KQOAUTHGLOBALS_H
diff --git a/oauth/kqoauthmanager.cpp b/oauth/kqoauthmanager.cpp
new file mode 100644
index 0000000..943701b
--- /dev/null
+++ b/oauth/kqoauthmanager.cpp
@@ -0,0 +1,677 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#include
+
+#include "kqoauthmanager.h"
+#include "kqoauthmanager_p.h"
+#include "bps/navigator.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 > KQOAuthManagerPrivate::createQueryParams(const KQOAuthParameters &requestParams) {
+ QList requestKeys = requestParams.keys();
+ QList requestValues = requestParams.values();
+
+ QList< QPair > result;
+ for(int i=0; i KQOAuthManagerPrivate::createTokensFromResponse(QByteArray reply) {
+ QMultiMap 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 &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 &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() {
+ return callbackServer->listen();
+}
+
+
+/////////////// 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()) {
+ 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)),
+ this, SLOT( onVerificationReceived(QMultiMap)));
+
+ 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 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 > 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);
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ this, SLOT(slotError(QNetworkReply::NetworkError)));
+
+ } else if (request->httpMethod() == KQOAuthRequest::POST) {
+
+ networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, request->contentType());
+
+ qDebug() << networkRequest.rawHeaderList();
+ qDebug() << networkRequest.rawHeader("Authorization");
+ qDebug() << networkRequest.rawHeader("Content-Type");
+
+ QNetworkReply *reply;
+ if (request->contentType() == "application/x-www-form-urlencoded") {
+ reply = d->networkManager->post(networkRequest, request->requestBody());
+ } else {
+ reply = d->networkManager->post(networkRequest, request->rawData());
+ }
+
+ 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()) {
+ 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 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);
+ }
+
+
+ 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) {
+ // Get the requested additional params as a list of pairs we can give QUrl
+ QList< QPair > 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);
+ connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
+ this, SLOT(slotError(QNetworkReply::NetworkError)));
+
+ } else if (request->httpMethod() == KQOAuthRequest::POST) {
+
+ networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, request->contentType());
+
+ /*
+ qDebug() << networkRequest.rawHeaderList();
+ qDebug() << networkRequest.rawHeader("Authorization");
+ qDebug() << networkRequest.rawHeader("Content-Type");
+ */
+ QNetworkReply *reply;
+ if (request->contentType() == "application/x-www-form-urlencoded") {
+ reply = d->networkManager->post(networkRequest, request->requestBody());
+ } else {
+ reply = d->networkManager->post(networkRequest, request->rawData());
+ }
+
+ 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 /////////////
+void KQOAuthManager::getOauth2UserAuthorization(QUrl authorizationEndpoint, QString consumerKey) {
+ Q_D(KQOAuthManager);
+
+ d->setupCallbackServer();
+ connect(d->callbackServer, SIGNAL(verificationReceived(QMultiMap)),
+ this, SLOT( onVerificationReceived(QMultiMap)));
+
+ 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);
+ qDebug() << openWebPageUrl.toString();
+ navigator_invoke(openWebPageUrl.toString().toStdString().c_str(),0);
+}
+
+void KQOAuthManager::getUserAuthorization(QUrl authorizationEndpoint) {
+ Q_D(KQOAuthManager);
+
+ if (!d->hasTemporaryToken) {
+ qWarning() << "No temporary tokens retreieved. Cannot get user authorization.";
+ d->error = KQOAuthManager::RequestUnauthorized;
+ return;
+ }
+
+ if (!authorizationEndpoint.isValid()) {
+ qWarning() << "Authorization endpoint not valid. Cannot proceed.";
+ d->error = KQOAuthManager::RequestEndpointError;
+ return;
+ }
+
+ d->error = KQOAuthManager::NoError;
+
+ QPair tokenParam = qMakePair(QString("oauth_token"), QString(d->requestToken));
+ QUrl openWebPageUrl(authorizationEndpoint.toString(), QUrl::StrictMode);
+ openWebPageUrl.addQueryItem(tokenParam.first, tokenParam.second);
+
+ // Open the user's default browser to the resource authorization page provided
+ // by the service.
+
+ qDebug() << openWebPageUrl.toString();
+ navigator_invoke(openWebPageUrl.toString().toStdString().c_str(),0);
+}
+
+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 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();
+ 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();
+
+ // 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;
+ }
+
+ // We need to emit the signal even if we got an error.
+ if (d->error != KQOAuthManager::NoError) {
+ qWarning() << "Network reply error";
+ 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 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);
+}
+
+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(sender());
+ d->requestIds.remove(reply);
+ reply->deleteLater();
+}
+
diff --git a/oauth/kqoauthmanager.h b/oauth/kqoauthmanager.h
new file mode 100644
index 0000000..2bf88df
--- /dev/null
+++ b/oauth/kqoauthmanager.h
@@ -0,0 +1,192 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#ifndef KQOAUTHMANAGER_H
+#define KQOAUTHMANAGER_H
+
+#include
+#include
+#include
+
+#include "kqoauthrequest.h"
+
+class KQOAuthRequest;
+class KQOAuthManagerThread;
+class KQOAuthManagerPrivate;
+class QNetworkAccessManager;
+class QUrl;
+class QByteArray;
+class KQOAUTH_EXPORT KQOAuthManager : public QObject
+{
+ Q_OBJECT
+public:
+
+ enum KQOAuthError {
+ NoError, // No error
+ NetworkError, // Network error: timeout, cannot connect.
+ RequestEndpointError, // Request endpoint is not valid.
+ RequestValidationError, // Request is not valid: some parameter missing?
+ RequestUnauthorized, // Authorization error: trying to access a resource without tokens.
+ RequestError, // The given request to KQOAuthManager is invalid: NULL?,
+ ManagerError // Manager error, cannot use for sending requests.
+ };
+
+ explicit KQOAuthManager(QObject *parent = 0);
+ ~KQOAuthManager();
+
+ KQOAuthError lastError();
+
+ /**
+ * The manager executes the given request. It takes the HTTP parameters from the
+ * request and uses QNetworkAccessManager to submit the HTTP request to the net.
+ * When the request is done it will emit signal requestReady(QByteArray networkReply).
+ * NOTE: At the moment there is no timeout for the request.
+ */
+ void executeRequest(KQOAuthRequest *request);
+ void executeAuthorizedRequest(KQOAuthRequest *request, int id);
+ /**
+ * Indicates to the user that KQOAuthManager should handle user authorization by
+ * opening the user's default browser and parsing the reply from the service.
+ * By setting the parameter to true, KQOAuthManager will store intermediate results
+ * of the OAuth 1.0 process in its own opaque request. This information is used in
+ * the user authorization process and also when calling sendAuthorizedRequest().
+ * NOTE: You need to set this to true if you want to use getUserAccessTokens() or
+ * sendAuthorizedRequest().
+ */
+ void setHandleUserAuthorization(bool set);
+
+ /**
+ * Returns true if the KQOAuthManager has retrieved the oauth_token value. Otherwise
+ * return false.
+ */
+ bool hasTemporaryToken();
+ /**
+ * Returns true if the user has authorized us to use the protected resources. Otherwise
+ * returns false.
+ * NOTE: In order for KQOAuthManager to know if the user has authorized us to use the
+ * protected resources, KQOAuthManager must be in control of the user authorization
+ * process. Hence, this returns true if setHandleUserAuthorization() is set to true
+ * and the user is authorized with getUserAuthorization().
+ */
+ bool isVerified();
+ /**
+ * Returns true if KQOAuthManager has the access token and hence can access the protected
+ * resources. Otherwise returns false.
+ * NOTE: In order for KQOAuthManager to know if we have access to protected resource
+ * KQOAuthManager must be in control of the user authorization process and requesting
+ * the acess token. Hence, this returns true if setHandleUserAuthorization() is set to true
+ * and the user is authorized with getUserAuthorization() and the access token must be retrieved
+ * with getUserAccessTokens.
+ */
+ bool isAuthorized();
+
+ /**
+ * Sets the file path string that the local server will serve on a successful authentication. This will generally direct
+ * your user to go back to your application and continue using the app.
+ */
+ void setSuccessHtmlFile(QString filePath);
+
+ /**
+ * This is a convenience API for authorizing the user.
+ * The call will open the user's default browser, setup a local HTTP server and parse the reply from the
+ * service after the user has authorized us to access protected resources. If the user authorizes
+ * us to access protected resources, the verifier token is stored in KQOAuthManager for further use.
+ * In order to use this method, you must set setHandleUserAuthorization() to true.
+ */
+ void getUserAuthorization(QUrl authorizationEndpoint);
+ /**
+ * This is a convenience API for retrieving the access token in exchange for the temporary token and the
+ * verifier.
+ * This call will create a KQOAuthRequest and use the previously stored temporary token and verifier to
+ * exchange for the access token, which will be used to access the protected resources.
+ * Note that in order to use this method, KQOAuthManager must be in control of the user authorization process.
+ * Set setHandleUserAuthorization() to true and retrieve user authorization with void getUserAuthorization.
+ */
+ void getUserAccessTokens(QUrl accessTokenEndpoint);
+ /**
+ * This is a method for bypassing all the oauth1 auth process and using the browser based oauth2 flow. This will
+ * launch the browser and set the callback url pointed to a localhost url. Make sure your oauth2 service supports redirect_uri param.
+ */
+ void getOauth2UserAuthorization(QUrl authorizationEndpoint, QString consumerKey);
+ /**
+ * Sends a request to the protected resources. Parameters for the request are service specific and
+ * are given to the 'requestParameters' as parameters.
+ * Note that in order to use this method, KQOAuthManager must be in control of the user authorization process.
+ * Set setHandleUserAuthorization() to true and retrieve user authorization with void getUserAuthorization.
+ */
+ void sendAuthorizedRequest(QUrl requestEndpoint, const KQOAuthParameters &requestParameters);
+
+ /**
+ * Sets a custom QNetworkAccessManager to handle network requests. This method can be useful if the
+ * application is using some proxy settings for example.
+ * The application is responsible for deleting this manager. KQOAuthManager will not delete any
+ * previously given manager.
+ * If the manager is NULL, the manager will not be set and the KQOAuthManager::Error.
+ * If no manager is given, KQOAuthManager will use the default one it will create by itself.
+ */
+ void setNetworkManager(QNetworkAccessManager *manager);
+
+ /**
+ * Returns the given QNetworkAccessManager. Returns NULL if none is given.
+ */
+ QNetworkAccessManager* networkManager() const;
+
+Q_SIGNALS:
+ // This signal will be emitted after each request has got a reply.
+ // Parameter is the raw response from the service.
+ void requestReady(QByteArray networkReply);
+
+ void authorizedRequestReady(QByteArray networkReply, int id);
+
+ // This signal will be emited when we have an request tokens available
+ // (either temporary resource tokens, or authorization tokens).
+ void receivedToken(QString oauth_token, QString oauth_token_secret); // oauth_token, oauth_token_secret
+
+ // This signal is emited when temporary tokens are returned from the service.
+ // Note that this signal is also emited in case temporary tokens are not available.
+ void temporaryTokenReceived(QString oauth_token, QString oauth_token_secret); // oauth_token, oauth_token_secret
+
+ // This signal is emited when the user has authenticated the application to
+ // communicate with the protected resources. Next we need to exchange the
+ // temporary tokens for access tokens.
+ // Note that this signal is also emited if user denies access.
+ void authorizationReceived(QString oauth_token, QString oauth_verifier); // oauth_token, oauth_verifier
+
+ // This signal is emited when access tokens are received from the service. We are
+ // ready to start communicating with the protected resources.
+ void accessTokenReceived(QString oauth_token, QString oauth_token_secret); // oauth_token, oauth_token_secret
+
+ // This signal is emited when the authorized request is done.
+ // This ends the kQOAuth interactions.
+ void authorizedRequestDone();
+
+private Q_SLOTS:
+ void onRequestReplyReceived( QNetworkReply *reply );
+ void onAuthorizedRequestReplyReceived( QNetworkReply *reply );
+ void onVerificationReceived(QMultiMap response);
+ void slotError(QNetworkReply::NetworkError error);
+
+private:
+ KQOAuthManagerPrivate *d_ptr;
+ Q_DECLARE_PRIVATE(KQOAuthManager);
+ Q_DISABLE_COPY(KQOAuthManager);
+
+};
+
+#endif // KQOAUTHMANAGER_H
diff --git a/oauth/kqoauthmanager_p.h b/oauth/kqoauthmanager_p.h
new file mode 100644
index 0000000..e5033a2
--- /dev/null
+++ b/oauth/kqoauthmanager_p.h
@@ -0,0 +1,74 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#ifndef KQOAUTHMANAGER_P_H
+#define KQOAUTHMANAGER_P_H
+
+#include "kqoauthauthreplyserver.h"
+#include "kqoauthrequest.h"
+
+class KQOAUTH_EXPORT KQOAuthManagerPrivate {
+
+public:
+ KQOAuthManagerPrivate(KQOAuthManager *parent);
+ ~KQOAuthManagerPrivate();
+
+ QList< QPair > createQueryParams(const KQOAuthParameters &requestParams);
+ QMultiMap createTokensFromResponse(QByteArray reply);
+ bool setSuccessfulRequestToken(const QMultiMap &request);
+ bool setSuccessfulAuthorized(const QMultiMap &request);
+ void emitTokens();
+ bool setupCallbackServer();
+
+ KQOAuthManager::KQOAuthError error;
+ KQOAuthRequest *r; // This request is used to cache the user sent request.
+ KQOAuthRequest *opaqueRequest; // This request is used to creating opaque convenience requests for the user.
+ KQOAuthManager * const q_ptr;
+
+ /**
+ * The items below are needed in order to store the state of the manager and
+ * by that be able to do convenience operations for the user.
+ */
+ KQOAuthRequest::RequestType currentRequestType;
+
+ // Variables we store here for opaque request handling.
+ // NOTE: The variables are labeled the same for both access token request
+ // and protected resource access.
+ QString requestToken;
+ QString requestTokenSecret;
+ QString consumerKey;
+ QString consumerKeySecret;
+ QString requestVerifier;
+
+ QString successHtmlFile;
+
+ KQOAuthAuthReplyServer *callbackServer;
+
+ bool hasTemporaryToken;
+ bool isVerified;
+ bool isAuthorized;
+ bool autoAuth;
+ QNetworkAccessManager *networkManager;
+ bool managerUserSet;
+ QMap requestIds;
+
+ Q_DECLARE_PUBLIC(KQOAuthManager);
+};
+
+#endif // KQOAUTHMANAGER_P_H
diff --git a/oauth/kqoauthrequest.cpp b/oauth/kqoauthrequest.cpp
new file mode 100644
index 0000000..3a9f85e
--- /dev/null
+++ b/oauth/kqoauthrequest.cpp
@@ -0,0 +1,628 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "kqoauthrequest.h"
+#include "kqoauthrequest_p.h"
+#include "kqoauthutils.h"
+#include "kqoauthglobals.h"
+
+
+//////////// Private d_ptr implementation /////////
+
+KQOAuthRequestPrivate::KQOAuthRequestPrivate() :
+ timeout(0)
+{
+
+}
+
+KQOAuthRequestPrivate::~KQOAuthRequestPrivate()
+{
+
+}
+
+// This method will not include the "oauthSignature" paramater, since it is calculated from these parameters.
+void KQOAuthRequestPrivate::prepareRequest() {
+
+ // If parameter list is not empty, we don't want to insert these values by
+ // accident a second time. So giving up.
+ if( !requestParameters.isEmpty() ) {
+ return;
+ }
+
+ switch ( requestType ) {
+ case KQOAuthRequest::TemporaryCredentials:
+ requestParameters.append( qMakePair( OAUTH_KEY_CALLBACK, oauthCallbackUrl.toString()) ); // This is so ugly that it is almost beautiful.
+ requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod) );
+ requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey ));
+ requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion ));
+ requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() ));
+ requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() ));
+ break;
+
+ case KQOAuthRequest::AccessToken:
+ requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod ));
+ requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey ));
+ requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion ));
+ requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() ));
+ requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() ));
+ requestParameters.append( qMakePair( OAUTH_KEY_VERIFIER, oauthVerifier ));
+ requestParameters.append( qMakePair( OAUTH_KEY_TOKEN, oauthToken ));
+ break;
+
+ case KQOAuthRequest::AuthorizedRequest:
+ if(requestOAuthMethod == KQOAuthRequest::OAUTH1) {
+ requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod ));
+ requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey ));
+ requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion ));
+ requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() ));
+ requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() ));
+ requestParameters.append( qMakePair( OAUTH_KEY_TOKEN, oauthToken ));
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void KQOAuthRequestPrivate::signRequest() {
+ QString signature = this->oauthSignature();
+ requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE, signature) );
+}
+
+QString KQOAuthRequestPrivate::oauthSignature() {
+ /**
+ * http://oauth.net/core/1.0/#anchor16
+ * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] where the
+ * Signature Base String is the text and the key is the concatenated values (each first encoded per Parameter
+ * Encoding) of the Consumer Secret and Token Secret, separated by an ‘&’ character (ASCII code 38) even if empty.
+ **/
+ QByteArray baseString = this->requestBaseString();
+
+ QString secret = QString(QUrl::toPercentEncoding(oauthConsumerSecretKey)) + "&" + QString(QUrl::toPercentEncoding(oauthTokenSecret));
+ QString signature = KQOAuthUtils::hmac_sha1(baseString, secret);
+
+ if (debugOutput) {
+ qDebug() << "========== KQOAuthRequest has the following signature:";
+ qDebug() << " * Signature : " << QUrl::toPercentEncoding(signature) << "\n";
+ }
+ return QString( QUrl::toPercentEncoding(signature) );
+}
+
+bool normalizedParameterSort(const QPair &left, const QPair &right) {
+ QString keyLeft = left.first;
+ QString valueLeft = left.second;
+ QString keyRight = right.first;
+ QString valueRight = right.second;
+
+ if(keyLeft == keyRight) {
+ return (valueLeft < valueRight);
+ } else {
+ return (keyLeft < keyRight);
+ }
+}
+QByteArray KQOAuthRequestPrivate::requestBaseString() {
+ QByteArray baseString;
+
+ // Every request has these as the commont parameters.
+ baseString.append( oauthHttpMethodString.toUtf8() + "&"); // HTTP method
+ baseString.append( QUrl::toPercentEncoding( oauthRequestEndpoint.toString(QUrl::RemoveQuery) ) + "&" ); // The path and query components
+
+ QList< QPair > baseStringParameters;
+ baseStringParameters.append(requestParameters);
+ baseStringParameters.append(additionalParameters);
+
+ // Sort the request parameters. These parameters have been
+ // initialized earlier.
+ qSort(baseStringParameters.begin(),
+ baseStringParameters.end(),
+ normalizedParameterSort
+ );
+
+ // Last append the request parameters correctly encoded.
+ baseString.append( encodedParamaterList(baseStringParameters) );
+
+ if (debugOutput) {
+ qDebug() << "========== KQOAuthRequest has the following base string:";
+ qDebug() << baseString << "\n";
+ }
+
+ return baseString;
+}
+
+QByteArray KQOAuthRequestPrivate::encodedParamaterList(const QList< QPair > ¶meters) {
+ QByteArray resultList;
+
+ bool first = true;
+ QPair parameter;
+
+ // Do the debug output.
+ if (debugOutput) {
+ qDebug() << "========== KQOAuthRequest has the following parameters:";
+ }
+ foreach (parameter, parameters) {
+ if(!first) {
+ resultList.append( "&" );
+ } else {
+ first = false;
+ }
+
+ // Here we don't need to explicitely encode the strings to UTF-8 since
+ // QUrl::toPercentEncoding() takes care of that for us.
+ resultList.append( QUrl::toPercentEncoding(parameter.first) // Parameter key
+ + "="
+ + QUrl::toPercentEncoding(parameter.second) // Parameter value
+ );
+ if (debugOutput) {
+ qDebug() << " * "
+ << parameter.first
+ << " : "
+ << parameter.second;
+ }
+ }
+ if (debugOutput) {
+ qDebug() << "\n";
+ }
+
+ return QUrl::toPercentEncoding(resultList);
+}
+
+QString KQOAuthRequestPrivate::oauthTimestamp() const {
+ // This is basically for unit tests only. In most cases we don't set the nonce beforehand.
+ if (!oauthTimestamp_.isEmpty()) {
+ return oauthTimestamp_;
+ }
+
+#if QT_VERSION >= 0x040700
+ return QString::number(QDateTime::currentDateTimeUtc().toTime_t());
+#else
+ return QString::number(QDateTime::currentDateTime().toUTC().toTime_t());
+#endif
+
+}
+
+QString KQOAuthRequestPrivate::oauthNonce() const {
+ // This is basically for unit tests only. In most cases we don't set the nonce beforehand.
+ if (!oauthNonce_.isEmpty()) {
+ return oauthNonce_;
+ }
+
+ return QString::number(qrand());
+}
+
+bool KQOAuthRequestPrivate::validateRequest() const {
+ switch ( requestType ) {
+ case KQOAuthRequest::TemporaryCredentials:
+ if (oauthRequestEndpoint.isEmpty()
+ || oauthConsumerKey.isEmpty()
+ || oauthNonce_.isEmpty()
+ || oauthSignatureMethod.isEmpty()
+ || oauthTimestamp_.isEmpty()
+ || oauthVersion.isEmpty())
+ {
+ return false;
+ }
+ return true;
+
+ case KQOAuthRequest::AccessToken:
+ if (oauthRequestEndpoint.isEmpty()
+ || oauthVerifier.isEmpty()
+ || oauthConsumerKey.isEmpty()
+ || oauthNonce_.isEmpty()
+ || oauthSignatureMethod.isEmpty()
+ || oauthTimestamp_.isEmpty()
+ || oauthToken.isEmpty()
+ || oauthTokenSecret.isEmpty()
+ || oauthVersion.isEmpty())
+ {
+ return false;
+ }
+ return true;
+
+ case KQOAuthRequest::AuthorizedRequest:
+ if(requestOAuthMethod == KQOAuthRequest::OAUTH1) {
+ if (oauthRequestEndpoint.isEmpty()
+ || oauthConsumerKey.isEmpty()
+ || oauthNonce_.isEmpty()
+ || oauthSignatureMethod.isEmpty()
+ || oauthTimestamp_.isEmpty()
+ || oauthToken.isEmpty()
+ || oauthTokenSecret.isEmpty()
+ || oauthVersion.isEmpty())
+ {
+ return false;
+ }
+ return true;
+ } else {
+ if(oauthToken.isEmpty()){
+ return false;
+ }
+ return true;
+ }
+
+ default:
+ return false;
+ }
+
+ // We should not come here.
+ return false;
+}
+
+//////////// Public implementation ////////////////
+
+KQOAuthRequest::KQOAuthRequest(QObject *parent) :
+ QObject(parent),
+ d_ptr(new KQOAuthRequestPrivate)
+{
+ d_ptr->debugOutput = false; // No debug output by default.
+ qsrand(QTime::currentTime().msec()); // We need to seed the nonce random number with something.
+ // However, we cannot do this while generating the nonce since
+ // we might get the same seed. So initializing here should be fine.
+}
+
+KQOAuthRequest::~KQOAuthRequest()
+{
+ delete d_ptr;
+}
+
+void KQOAuthRequest::initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint) {
+ Q_D(KQOAuthRequest);
+
+ if (!requestEndpoint.isValid()) {
+ qWarning() << "Endpoint URL is not valid. Ignoring. This request might not work.";
+ return;
+ }
+
+ if (type < 0 || type > KQOAuthRequest::AuthorizedRequest) {
+ qWarning() << "Invalid request type. Ignoring. This request might not work.";
+ return;
+ }
+
+ // Clear the request
+ clearRequest();
+
+ // Set smart defaults.
+ d->requestType = type;
+ d->oauthRequestEndpoint = requestEndpoint;
+ d->oauthTimestamp_ = d->oauthTimestamp();
+ d->oauthNonce_ = d->oauthNonce();
+ this->setSignatureMethod(KQOAuthRequest::HMAC_SHA1);
+ this->setHttpMethod(KQOAuthRequest::POST);
+ d->oauthVersion = "1.0"; // Currently supports only version 1.0
+
+ d->contentType = "application/x-www-form-urlencoded";
+}
+
+void KQOAuthRequest::setConsumerKey(const QString &consumerKey) {
+ Q_D(KQOAuthRequest);
+ d->oauthConsumerKey = consumerKey;
+}
+
+void KQOAuthRequest::setConsumerSecretKey(const QString &consumerSecretKey) {
+ Q_D(KQOAuthRequest);
+ d->oauthConsumerSecretKey = consumerSecretKey;
+}
+
+void KQOAuthRequest::setCallbackUrl(const QUrl &callbackUrl) {
+ Q_D(KQOAuthRequest);
+
+ d->oauthCallbackUrl = callbackUrl;
+}
+
+void KQOAuthRequest::setSignatureMethod(KQOAuthRequest::RequestSignatureMethod requestMethod) {
+ Q_D(KQOAuthRequest);
+ QString requestMethodString;
+
+ switch (requestMethod) {
+ case KQOAuthRequest::PLAINTEXT:
+ requestMethodString = "PLAINTEXT";
+ break;
+ case KQOAuthRequest::HMAC_SHA1:
+ requestMethodString = "HMAC-SHA1";
+ break;
+ case KQOAuthRequest::RSA_SHA1:
+ requestMethodString = "RSA-SHA1";
+ break;
+ default:
+ // We should not come here
+ qWarning() << "Invalid signature method set.";
+ break;
+ }
+
+ d->oauthSignatureMethod = requestMethodString;
+}
+
+void KQOAuthRequest::setTokenSecret(const QString &tokenSecret) {
+ Q_D(KQOAuthRequest);
+
+ d->oauthTokenSecret = tokenSecret;
+}
+
+void KQOAuthRequest::setToken(const QString &token) {
+ Q_D(KQOAuthRequest);
+
+ d->oauthToken = token;
+}
+
+void KQOAuthRequest::setVerifier(const QString &verifier) {
+ Q_D(KQOAuthRequest);
+
+ d->oauthVerifier = verifier;
+}
+
+
+void KQOAuthRequest::setHttpMethod(KQOAuthRequest::RequestHttpMethod httpMethod) {
+ Q_D(KQOAuthRequest);
+
+ QString requestHttpMethodString;
+
+ switch (httpMethod) {
+ case KQOAuthRequest::GET:
+ requestHttpMethodString = "GET";
+ break;
+ case KQOAuthRequest::POST:
+ requestHttpMethodString = "POST";
+ break;
+ default:
+ qWarning() << "Invalid HTTP method set.";
+ break;
+ }
+
+ d->oauthHttpMethod = httpMethod;
+ d->oauthHttpMethodString = requestHttpMethodString;
+}
+
+void KQOAuthRequest::setRequestOAuthMethod(KQOAuthRequest::RequestOAuthMethod oauthMethod) {
+ Q_D(KQOAuthRequest);
+
+ d->requestOAuthMethod = oauthMethod;
+}
+
+KQOAuthRequest::RequestHttpMethod KQOAuthRequest::httpMethod() const {
+ Q_D(const KQOAuthRequest);
+
+ return d->oauthHttpMethod;
+}
+
+KQOAuthRequest::RequestOAuthMethod KQOAuthRequest::oauthMethod() const {
+ Q_D(const KQOAuthRequest);
+
+ return d->requestOAuthMethod;
+}
+
+void KQOAuthRequest::setAdditionalParameters(const KQOAuthParameters &additionalParams) {
+ Q_D(KQOAuthRequest);
+
+ QList additionalKeys = additionalParams.keys();
+ QList additionalValues = additionalParams.values();
+
+ int i=0;
+ foreach(QString key, additionalKeys) {
+ QString value = additionalValues.at(i);
+ d->additionalParameters.append( qMakePair(key, value) );
+ i++;
+ }
+}
+
+KQOAuthParameters KQOAuthRequest::additionalParameters() const {
+ Q_D(const KQOAuthRequest);
+
+ QMultiMap additionalParams;
+ for(int i=0; iadditionalParameters.size(); i++) {
+ additionalParams.insert(d->additionalParameters.at(i).first,
+ d->additionalParameters.at(i).second);
+ }
+ if(d->requestOAuthMethod == KQOAuthRequest::OAUTH2) {
+ additionalParams.insert(OAUTH_KEY_TOKEN, d->oauthToken);
+ }
+
+ return additionalParams;
+}
+
+KQOAuthRequest::RequestType KQOAuthRequest::requestType() const {
+ Q_D(const KQOAuthRequest);
+ return d->requestType;
+}
+
+QUrl KQOAuthRequest::requestEndpoint() const {
+ Q_D(const KQOAuthRequest);
+ return d->oauthRequestEndpoint;
+}
+
+QList KQOAuthRequest::requestParameters() {
+ Q_D(KQOAuthRequest);
+
+ QList requestParamList;
+
+ d->prepareRequest();
+ if (!isValid() ) {
+ qWarning() << "Request is not valid! I will still sign it, but it will probably not work.";
+ }
+ if(d->requestOAuthMethod != KQOAuthRequest::OAUTH2) {
+ d->signRequest();
+ }
+
+ QPair requestParam;
+ QString param;
+ QString value;
+ foreach (requestParam, d->requestParameters) {
+ param = requestParam.first;
+ value = requestParam.second;
+ requestParamList.append(QString(param + "=\"" + value +"\"").toUtf8());
+ }
+
+ return requestParamList;
+}
+
+QString KQOAuthRequest::contentType()
+{
+ Q_D(const KQOAuthRequest);
+ return d->contentType;
+}
+
+void KQOAuthRequest::setContentType(const QString &contentType)
+{
+ Q_D(KQOAuthRequest);
+ d->contentType = contentType;
+}
+
+QByteArray KQOAuthRequest::rawData()
+{
+ Q_D(const KQOAuthRequest);
+ return d->postRawData;
+}
+
+void KQOAuthRequest::setRawData(const QByteArray &rawData)
+{
+ Q_D(KQOAuthRequest);
+ d->postRawData = rawData;
+}
+
+QByteArray KQOAuthRequest::requestBody() const {
+ Q_D(const KQOAuthRequest);
+
+ QByteArray postBodyContent;
+ bool first = true;
+ for(int i=0; i < d->additionalParameters.size(); i++) {
+ if(!first) {
+ postBodyContent.append("&");
+ } else {
+ first = false;
+ }
+
+ QString key = d->additionalParameters.at(i).first;
+ QString value = d->additionalParameters.at(i).second;
+
+ postBodyContent.append(QUrl::toPercentEncoding(key) + QString("=").toUtf8() +
+ QUrl::toPercentEncoding(value));
+ }
+ qDebug() << postBodyContent;
+ return postBodyContent;
+}
+
+bool KQOAuthRequest::isValid() const {
+ Q_D(const KQOAuthRequest);
+
+ return d->validateRequest();
+}
+
+void KQOAuthRequest::setTimeout(int timeoutMilliseconds) {
+ Q_D(KQOAuthRequest);
+ d->timeout = timeoutMilliseconds;
+}
+
+void KQOAuthRequest::clearRequest() {
+ Q_D(KQOAuthRequest);
+
+ d->oauthRequestEndpoint = "";
+ d->oauthHttpMethodString = "";
+ d->oauthConsumerKey = "";
+ d->oauthConsumerSecretKey = "";
+ d->oauthToken = "";
+ d->oauthTokenSecret = "";
+ d->oauthSignatureMethod = "";
+ d->oauthCallbackUrl = "";
+ d->oauthVerifier = "";
+ d->oauthTimestamp_ = "";
+ d->oauthNonce_ = "";
+ d->requestParameters.clear();
+ d->additionalParameters.clear();
+ d->timeout = 0;
+}
+
+void KQOAuthRequest::setEnableDebugOutput(bool enabled) {
+ Q_D(KQOAuthRequest);
+ d->debugOutput = enabled;
+}
+
+/**
+ * Protected implementations for inherited classes
+ */
+bool KQOAuthRequest::validateXAuthRequest() const {
+ Q_D(const KQOAuthRequest);
+
+ if (d->oauthRequestEndpoint.isEmpty()
+ || d->oauthConsumerKey.isEmpty()
+ || d->oauthNonce_.isEmpty()
+ || d->oauthSignatureMethod.isEmpty()
+ || d->oauthTimestamp_.isEmpty()
+ || d->oauthVersion.isEmpty())
+ {
+ return false;
+ }
+ return true;
+}
+
+bool KQOAuthRequest::validateOauth2Request() const {
+ Q_D(const KQOAuthRequest);
+
+ if (d->oauthRequestEndpoint.isEmpty()
+ || d->oauthConsumerKey.isEmpty()
+ || d->oauthConsumerSecretKey.isEmpty())
+ {
+ return false;
+ }
+ return true;
+}
+
+
+/**
+ * Private implementations for friend classes
+ */
+QString KQOAuthRequest::consumerKeyForManager() const {
+ Q_D(const KQOAuthRequest);
+ return d->oauthConsumerKey;
+}
+
+QString KQOAuthRequest::consumerKeySecretForManager() const {
+ Q_D(const KQOAuthRequest);
+ return d->oauthConsumerSecretKey;
+}
+
+QUrl KQOAuthRequest::callbackUrlForManager() const {
+ Q_D(const KQOAuthRequest);
+ return d->oauthCallbackUrl;
+}
+
+void KQOAuthRequest::requestTimerStart()
+{
+ Q_D(KQOAuthRequest);
+ if (d->timeout > 0) {
+ connect(&(d->timer), SIGNAL(timeout()), this, SIGNAL(requestTimedout()));
+ d->timer.start(d->timeout);
+ }
+}
+
+void KQOAuthRequest::requestTimerStop()
+{
+ Q_D(KQOAuthRequest);
+ if (d->timeout > 0) {
+ disconnect(&(d->timer), SIGNAL(timeout()), this, SIGNAL(requestTimedout()));
+ d->timer.stop();
+ }
+}
diff --git a/oauth/kqoauthrequest.h b/oauth/kqoauthrequest.h
new file mode 100644
index 0000000..8b56036
--- /dev/null
+++ b/oauth/kqoauthrequest.h
@@ -0,0 +1,153 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#ifndef KQOAUTHREQUEST_H
+#define KQOAUTHREQUEST_H
+
+#include
+#include
+#include
+
+#include "kqoauthglobals.h"
+
+typedef QMultiMap KQOAuthParameters;
+
+class KQOAuthRequestPrivate;
+class KQOAUTH_EXPORT KQOAuthRequest : public QObject
+{
+ Q_OBJECT
+public:
+ explicit KQOAuthRequest(QObject *parent = 0);
+ ~KQOAuthRequest();
+
+ enum RequestType {
+ TemporaryCredentials = 0,
+ AccessToken,
+ AuthorizedRequest
+ };
+
+ enum RequestSignatureMethod {
+ PLAINTEXT = 0,
+ HMAC_SHA1,
+ RSA_SHA1
+ };
+
+ enum RequestHttpMethod {
+ GET = 0,
+ POST
+ };
+
+ enum RequestOAuthMethod {
+ OAUTH1 = 0,
+ OAUTH2
+ };
+
+ /**
+ * These methods can be overridden in child classes which are different types of
+ * OAuth requests.
+ */
+ // Validate the request of this type.
+ virtual bool isValid() const;
+
+ /**
+ * These methods are OAuth request type specific and not overridden in child
+ * classes.
+ * NOTE: Refactorting still a TODO
+ */
+ // Initialize the request of this type.
+ virtual void initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint);
+
+ void setConsumerKey(const QString &consumerKey);
+ void setConsumerSecretKey(const QString &consumerSecretKey);
+
+ // Mandatory methods for acquiring a request token
+ void setCallbackUrl(const QUrl &callbackUrl);
+
+ // Mandator methods for acquiring a access token
+ void setTokenSecret(const QString &tokenSecret);
+ void setToken(const QString &token);
+ void setVerifier(const QString &verifier);
+
+ // Request signature method to use - HMAC_SHA1 currently only supported
+ void setSignatureMethod(KQOAuthRequest::RequestSignatureMethod = KQOAuthRequest::HMAC_SHA1);
+
+ // Request's HTTP method.
+ void setHttpMethod(KQOAuthRequest::RequestHttpMethod = KQOAuthRequest::POST);
+ KQOAuthRequest::RequestHttpMethod httpMethod() const;
+ KQOAuthRequest::RequestOAuthMethod oauthMethod() const;
+ void setRequestOAuthMethod(KQOAuthRequest::RequestOAuthMethod = KQOAuthRequest::OAUTH1);
+
+ // Sets the timeout for this request. If the timeout expires, signal "requestTimedout" will be
+ // emitted from the manager.
+ // 0 = If set to zero, timeout is disabled.
+ // TODO: Do we need some request ID now?
+ void setTimeout(int timeoutMilliseconds);
+
+ // Additional optional parameters to the request.
+ void setAdditionalParameters(const KQOAuthParameters &additionalParams);
+ KQOAuthParameters additionalParameters() const;
+ QList requestParameters(); // This will return all request's parameters in the raw format given
+ // to the QNetworkRequest.
+ QByteArray requestBody() const; // This will return the POST body as given to the QNetworkRequest.
+
+ KQOAuthRequest::RequestType requestType() const;
+ QUrl requestEndpoint() const;
+
+ void setContentType(const QString &contentType);
+ QString contentType();
+
+ void setRawData(const QByteArray &rawData);
+ QByteArray rawData();
+
+ void clearRequest();
+
+ // Enable verbose debug output for request content.
+ void setEnableDebugOutput(bool enabled);
+
+Q_SIGNALS:
+ // This signal is emited if the request is not completed before the request's timeout
+ // value has expired.
+ void requestTimedout();
+
+protected:
+ bool validateXAuthRequest() const;
+ bool validateOauth2Request() const;
+
+private:
+ KQOAuthRequestPrivate * const d_ptr;
+ Q_DECLARE_PRIVATE(KQOAuthRequest);
+ Q_DISABLE_COPY(KQOAuthRequest);
+
+ // These classes are only for the internal use of KQOAuthManager so it can
+ // work with the opaque request.
+ QString consumerKeyForManager() const;
+ QString consumerKeySecretForManager() const;
+ QUrl callbackUrlForManager() const;
+
+ // This method is for timeout handling by the KQOAuthManager.
+ void requestTimerStart();
+ void requestTimerStop();
+
+ friend class KQOAuthManager;
+#ifdef UNIT_TEST
+ friend class Ut_KQOAuth;
+#endif
+};
+
+#endif // KQOAUTHREQUEST_H
diff --git a/oauth/kqoauthrequest_1.cpp b/oauth/kqoauthrequest_1.cpp
new file mode 100644
index 0000000..165eb3c
--- /dev/null
+++ b/oauth/kqoauthrequest_1.cpp
@@ -0,0 +1,5 @@
+#include "kqoauthrequest_1.h"
+
+KQOAuthRequest_1::KQOAuthRequest_1()
+{
+}
diff --git a/oauth/kqoauthrequest_1.h b/oauth/kqoauthrequest_1.h
new file mode 100644
index 0000000..8da5df8
--- /dev/null
+++ b/oauth/kqoauthrequest_1.h
@@ -0,0 +1,12 @@
+#ifndef KQOAUTHREQUEST_1_H
+#define KQOAUTHREQUEST_1_H
+
+#include "kqoauthrequest.h"
+
+class KQOAUTH_EXPORT KQOAuthRequest_1 : public KQOAuthRequest
+{
+public:
+ KQOAuthRequest_1();
+};
+
+#endif // KQOAUTHREQUEST_1_H
diff --git a/oauth/kqoauthrequest_p.h b/oauth/kqoauthrequest_p.h
new file mode 100644
index 0000000..c981e64
--- /dev/null
+++ b/oauth/kqoauthrequest_p.h
@@ -0,0 +1,94 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#ifndef KQOAUTHREQUEST_P_H
+#define KQOAUTHREQUEST_P_H
+#include "kqoauthglobals.h"
+#include "kqoauthrequest.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+class KQOAUTH_EXPORT KQOAuthRequestPrivate {
+
+public:
+ KQOAuthRequestPrivate();
+ ~KQOAuthRequestPrivate();
+
+ // Helper methods to get the values for the OAuth request parameters.
+ QString oauthTimestamp() const;
+ QString oauthNonce() const;
+ QString oauthSignature();
+
+ // Utility methods for making the request happen.
+ void prepareRequest();
+ void signRequest();
+ bool validateRequest() const;
+ QByteArray requestBaseString();
+ QByteArray encodedParamaterList(const QList< QPair > &requestParameters);
+ void insertAdditionalParams();
+ void insertPostBody();
+
+ QUrl oauthRequestEndpoint;
+ KQOAuthRequest::RequestHttpMethod oauthHttpMethod;
+ QString oauthHttpMethodString;
+ QString oauthConsumerKey;
+ QString oauthConsumerSecretKey;
+ QString oauthToken;
+ QString oauthTokenSecret;
+ QString oauthSignatureMethod;
+ QUrl oauthCallbackUrl;
+ QString oauthVersion;
+ QString oauthVerifier;
+
+ // These will be generated by the helper methods
+ QString oauthTimestamp_;
+ QString oauthNonce_;
+
+ // User specified additional parameters needed for the request.
+ QList< QPair > additionalParameters;
+
+ // The raw POST body content as given to the HTTP request.
+ QByteArray postBodyContent;
+
+ // Protocol parameters.
+ // These parameters are used in the "Authorized" header of the HTTP request.
+ QList< QPair > requestParameters;
+
+ KQOAuthRequest::RequestType requestType;
+ KQOAuthRequest::RequestOAuthMethod requestOAuthMethod;
+
+ //The Content-Type HTTP header
+ QString contentType;
+
+ //Raw data to post if type is not url-encoded
+ QByteArray postRawData;
+
+ // Timeout for this request in milliseconds.
+ int timeout;
+ QTimer timer;
+
+ bool debugOutput;
+
+};
+#endif // KQOAUTHREQUEST_P_H
diff --git a/oauth/kqoauthrequest_xauth.cpp b/oauth/kqoauthrequest_xauth.cpp
new file mode 100644
index 0000000..30ae58d
--- /dev/null
+++ b/oauth/kqoauthrequest_xauth.cpp
@@ -0,0 +1,91 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#include
+
+#include "kqoauthrequest_xauth_p.h"
+#include "kqoauthrequest_xauth.h"
+
+/**
+ * Private d_ptr implementations.
+ */
+KQOAuthRequest_XAuthPrivate::KQOAuthRequest_XAuthPrivate()
+{
+
+}
+
+KQOAuthRequest_XAuthPrivate::~KQOAuthRequest_XAuthPrivate()
+{
+}
+
+/**
+ * Public implementations.
+ */
+KQOAuthRequest_XAuth::KQOAuthRequest_XAuth(QObject *parent) :
+ KQOAuthRequest(parent),
+ d_ptr(new KQOAuthRequest_XAuthPrivate)
+{
+}
+
+bool KQOAuthRequest_XAuth::isValid() const {
+ // An xAuth can never request temporary credentials.
+ if (requestType() == KQOAuthRequest::TemporaryCredentials) {
+ qWarning() << "XAuth request cannot be of type KQOAuthRequest::TemporaryCredentials. Aborting.";
+ return false;
+ }
+
+ // Access token must always be retrieved using the POST HTTP method.
+ if (requestType() == KQOAuthRequest::AccessToken
+ && httpMethod() != KQOAuthRequest::POST) {
+
+ qWarning() << "Access tokens must be fetched using the POST HTTP method. Aborting.";
+
+ return false;
+ }
+
+ if (!xauth_parameters_set) {
+ qWarning() << "No XAuth parameters set. Aborting.";
+ return false;
+ }
+
+ // And then check the validity of the XAuth request.
+ // Provided by the base class as a protected method for us.
+ return validateXAuthRequest();
+}
+
+void KQOAuthRequest_XAuth::setXAuthLogin(const QString &username,
+ const QString &password) {
+
+ if (username.isEmpty() || password.isEmpty()) {
+ qWarning() << "Username or password cannot be empty. Aborting.";
+ return;
+ }
+
+ xauth_parameters_set = true;
+
+ qDebug() << username << password;
+
+ KQOAuthParameters xauthParams;
+ xauthParams.insert("x_auth_username", username);
+ xauthParams.insert("x_auth_password", password);
+ xauthParams.insert("x_auth_mode", "client_auth");
+
+ setAdditionalParameters(xauthParams);
+}
+
diff --git a/oauth/kqoauthrequest_xauth.h b/oauth/kqoauthrequest_xauth.h
new file mode 100644
index 0000000..6266c02
--- /dev/null
+++ b/oauth/kqoauthrequest_xauth.h
@@ -0,0 +1,49 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#ifndef KQOAUTHREQUEST_XAUTH_H
+#define KQOAUTHREQUEST_XAUTH_H
+
+#include "kqoauthrequest.h"
+#include "kqoauthrequest_1.h"
+
+class KQOAuthRequest_XAuthPrivate;
+class KQOAUTH_EXPORT KQOAuthRequest_XAuth : public KQOAuthRequest
+{
+ Q_OBJECT
+public:
+ KQOAuthRequest_XAuth(QObject *parent = 0);
+
+ /**
+ * These methods can be overridden in child classes which are different types of
+ * OAuth requests.
+ */
+ // Validate the request of this type.
+ bool isValid() const;
+
+ // Give the xAuth specific parameters.
+ void setXAuthLogin(const QString &username = "",
+ const QString &password = "");
+
+private:
+ KQOAuthRequest_XAuthPrivate * const d_ptr;
+ bool xauth_parameters_set;
+};
+
+#endif // KQOAUTHREQUEST_XAUTH_H
diff --git a/oauth/kqoauthrequest_xauth_p.h b/oauth/kqoauthrequest_xauth_p.h
new file mode 100644
index 0000000..9f79d31
--- /dev/null
+++ b/oauth/kqoauthrequest_xauth_p.h
@@ -0,0 +1,14 @@
+#ifndef KQOAUTHREQUEST_XAUTH_P_H
+#define KQOAUTHREQUEST_XAUTH_P_H
+
+#include "kqoauthglobals.h"
+
+class KQOAuthRequest;
+class KQOAUTH_EXPORT KQOAuthRequest_XAuthPrivate
+{
+public:
+ KQOAuthRequest_XAuthPrivate();
+ ~KQOAuthRequest_XAuthPrivate();
+};
+
+#endif // KQOAUTHREQUEST_XAUTH_P_H
diff --git a/oauth/kqoauthutils.cpp b/oauth/kqoauthutils.cpp
new file mode 100644
index 0000000..839f9d6
--- /dev/null
+++ b/oauth/kqoauthutils.cpp
@@ -0,0 +1,79 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#include
+#include
+#include
+
+#include
+#include "kqoauthutils.h"
+
+QString KQOAuthUtils::hmac_sha1(const QString &message, const QString &key)
+{
+ QByteArray keyBytes = key.toAscii();
+ int keyLength; // Lenght of key word
+ const int blockSize = 64; // Both MD5 and SHA-1 have a block size of 64.
+
+ keyLength = keyBytes.size();
+ // If key is longer than block size, we need to hash the key
+ if (keyLength > blockSize) {
+ QCryptographicHash hash(QCryptographicHash::Sha1);
+ hash.addData(keyBytes);
+ keyBytes = hash.result();
+ }
+
+ /* http://tools.ietf.org/html/rfc2104 - (1) */
+ // Create the opad and ipad for the hash function.
+ QByteArray ipad;
+ QByteArray opad;
+
+ ipad.fill( 0, blockSize);
+ opad.fill( 0, blockSize);
+
+ ipad.replace(0, keyBytes.length(), keyBytes);
+ opad.replace(0, keyBytes.length(), keyBytes);
+
+ /* http://tools.ietf.org/html/rfc2104 - (2) & (5) */
+ for (int i=0; i<64; i++) {
+ ipad[i] = ipad[i] ^ 0x36;
+ opad[i] = opad[i] ^ 0x5c;
+ }
+
+ QByteArray workArray;
+ workArray.clear();
+
+ workArray.append(ipad, 64);
+ /* http://tools.ietf.org/html/rfc2104 - (3) */
+ workArray.append(message.toAscii());
+
+
+ /* http://tools.ietf.org/html/rfc2104 - (4) */
+ QByteArray sha1 = QCryptographicHash::hash(workArray, QCryptographicHash::Sha1);
+
+ /* http://tools.ietf.org/html/rfc2104 - (6) */
+ workArray.clear();
+ workArray.append(opad, 64);
+ workArray.append(sha1);
+
+ sha1.clear();
+
+ /* http://tools.ietf.org/html/rfc2104 - (7) */
+ sha1 = QCryptographicHash::hash(workArray, QCryptographicHash::Sha1);
+ return QString(sha1.toBase64());
+}
diff --git a/oauth/kqoauthutils.h b/oauth/kqoauthutils.h
new file mode 100644
index 0000000..4d2adfc
--- /dev/null
+++ b/oauth/kqoauthutils.h
@@ -0,0 +1,33 @@
+/**
+ * KQOAuth - An OAuth authentication library for Qt.
+ *
+ * Author: Johan Paul (johan.paul@d-pointer.com)
+ * http://www.d-pointer.com
+ *
+ * KQOAuth 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with KQOAuth. If not, see .
+ */
+#ifndef KQOAUTHUTILS_H
+#define KQOAUTHUTILS_H
+
+#include "kqoauthglobals.h"
+
+class QString;
+class KQOAUTH_EXPORT KQOAuthUtils
+{
+public:
+
+ static QString hmac_sha1(const QString &message, const QString &key);
+};
+
+#endif // KQOAUTHUTILS_H