summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Barz <barz.felix@web.de>2018-10-16 18:44:09 +0200
committerFelix Barz <barz.felix@web.de>2019-01-28 15:14:05 +0000
commit297e842a7fcbe0def4223625b8daa3e46afe057f (patch)
tree7db5c3a24462ceab60459740a435228141722158
parent94640eb27c054baffddf44fcaebf26f800a6415e (diff)
Add method to prepare network requests
Sending authenticated requests is limited to the APIs the QAbstractOAuth class provides. With the newly added prepareRequest and sendCustomRequest methods, one can set the correct headers etc. on any custom created network request, including the verb that is used to the request as well the body to be sent. This includes a modifcation to the QOAuth1Signature class to make it possible to sign requests with a custom method. [ChangeLog][QOAuth1Signature] Added customMethodString and setCustomMethodString methods to support signing requests with custom methods. [ChangeLog][QAbstractOAuth] Added prepareRequest and sendCustomRequest methods to authenticate any custom request, including custom verbs and bodies. Change-Id: I86459844ee919e8c9d60d349257b57afbc3fa07a Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
-rw-r--r--src/oauth/qabstractoauth.cpp18
-rw-r--r--src/oauth/qabstractoauth.h5
-rw-r--r--src/oauth/qabstractoauth2.cpp11
-rw-r--r--src/oauth/qabstractoauth2_p.h4
-rw-r--r--src/oauth/qabstractoauth_p.h4
-rw-r--r--src/oauth/qoauth1.cpp95
-rw-r--r--src/oauth/qoauth1.h3
-rw-r--r--src/oauth/qoauth1_p.h12
-rw-r--r--src/oauth/qoauth1signature.cpp39
-rw-r--r--src/oauth/qoauth1signature.h3
-rw-r--r--src/oauth/qoauth1signature_p.h1
-rw-r--r--tests/auto/abstractoauth/tst_abstractoauth.cpp11
-rw-r--r--tests/auto/oauth1/BLACKLIST2
-rw-r--r--tests/auto/oauth1/tst_oauth1.cpp269
-rw-r--r--tests/auto/oauth1signature/tst_oauth1signature.cpp35
-rw-r--r--tests/auto/oauth2/tst_oauth2.cpp11
16 files changed, 507 insertions, 16 deletions
diff --git a/src/oauth/qabstractoauth.cpp b/src/oauth/qabstractoauth.cpp
index 5326292..9aaad57 100644
--- a/src/oauth/qabstractoauth.cpp
+++ b/src/oauth/qabstractoauth.cpp
@@ -44,6 +44,7 @@
#include <QtNetwork/qnetworkrequest.h>
#include <QtNetwork/qnetworkaccessmanager.h>
+#include <QtNetwork/qnetworkreply.h>
#include <random>
@@ -510,6 +511,23 @@ void QAbstractOAuth::setReplyHandler(QAbstractOAuthReplyHandler *handler)
}
/*!
+ \since 5.13
+
+ Authorizes the given \a request by adding headers etc. to it required for
+ authenticated requests.
+
+ The \a verb must be a valid HTTP verb and the same as the one that will be
+ used to send the \a request.
+*/
+void QAbstractOAuth::prepareRequest(QNetworkRequest *request,
+ const QByteArray &verb,
+ const QByteArray &body)
+{
+ Q_D(QAbstractOAuth);
+ d->prepareRequestImpl(request, verb, body);
+}
+
+/*!
Returns the current parameter-modification function.
\sa ModifyParametersFunction, setModifyParametersFunction(), Stage
*/
diff --git a/src/oauth/qabstractoauth.h b/src/oauth/qabstractoauth.h
index ab1310b..bb610a8 100644
--- a/src/oauth/qabstractoauth.h
+++ b/src/oauth/qabstractoauth.h
@@ -138,6 +138,11 @@ public:
Q_INVOKABLE virtual QNetworkReply *deleteResource(
const QUrl &url, const QVariantMap &parameters = QVariantMap()) = 0;
+ // ### Qt 6: Make this method pure virtual and remove the private implementation
+ void prepareRequest(QNetworkRequest *request,
+ const QByteArray &verb,
+ const QByteArray &body = QByteArray());
+
ModifyParametersFunction modifyParametersFunction() const;
void setModifyParametersFunction(const ModifyParametersFunction &modifyParametersFunction);
diff --git a/src/oauth/qabstractoauth2.cpp b/src/oauth/qabstractoauth2.cpp
index 96d338d..cd428ad 100644
--- a/src/oauth/qabstractoauth2.cpp
+++ b/src/oauth/qabstractoauth2.cpp
@@ -169,6 +169,17 @@ QNetworkRequest QAbstractOAuth2Private::createRequest(QUrl url, const QVariantMa
return request;
}
+void QAbstractOAuth2Private::prepareRequestImpl(QNetworkRequest *request,
+ const QByteArray &verb,
+ const QByteArray &body)
+{
+ Q_UNUSED(verb)
+ Q_UNUSED(body)
+ request->setHeader(QNetworkRequest::UserAgentHeader, userAgent);
+ const QString bearer = bearerFormat.arg(token);
+ request->setRawHeader("Authorization", bearer.toUtf8());
+}
+
/*!
Constructs a QAbstractOAuth2 object using \a parent as parent.
*/
diff --git a/src/oauth/qabstractoauth2_p.h b/src/oauth/qabstractoauth2_p.h
index b4a7b04..4dea113 100644
--- a/src/oauth/qabstractoauth2_p.h
+++ b/src/oauth/qabstractoauth2_p.h
@@ -70,6 +70,10 @@ public:
static QString generateRandomState();
QNetworkRequest createRequest(QUrl url, const QVariantMap *parameters = nullptr);
+ void prepareRequestImpl(QNetworkRequest *request,
+ const QByteArray &verb,
+ const QByteArray &body) override;
+
QString clientIdentifierSharedKey;
QString scope;
QString state = generateRandomState();
diff --git a/src/oauth/qabstractoauth_p.h b/src/oauth/qabstractoauth_p.h
index 4ec3802..58c4b21 100644
--- a/src/oauth/qabstractoauth_p.h
+++ b/src/oauth/qabstractoauth_p.h
@@ -77,6 +77,10 @@ public:
void setStatus(QAbstractOAuth::Status status);
static QByteArray generateRandomString(quint8 length);
+ virtual void prepareRequestImpl(QNetworkRequest *request,
+ const QByteArray &verb,
+ const QByteArray &body) = 0;
+
const QLoggingCategory loggingCategory;
QString clientIdentifier;
QString token;
diff --git a/src/oauth/qoauth1.cpp b/src/oauth/qoauth1.cpp
index 9713a30..efc7712 100644
--- a/src/oauth/qoauth1.cpp
+++ b/src/oauth/qoauth1.cpp
@@ -243,12 +243,29 @@ QByteArray QOAuth1Private::generateSignature(const QVariantMap &parameters,
const QUrl &url,
QNetworkAccessManager::Operation operation) const
{
- const QOAuth1Signature signature(url,
- clientIdentifierSharedKey,
- tokenSecret,
- static_cast<QOAuth1Signature::HttpRequestMethod>(operation),
- parameters);
+ QOAuth1Signature signature(url,
+ clientIdentifierSharedKey,
+ tokenSecret,
+ static_cast<QOAuth1Signature::HttpRequestMethod>(operation),
+ parameters);
+ return formatSignature(signature);
+}
+
+QByteArray QOAuth1Private::generateSignature(const QVariantMap &parameters,
+ const QUrl &url,
+ const QByteArray &verb) const
+{
+ QOAuth1Signature signature(url,
+ clientIdentifierSharedKey,
+ tokenSecret,
+ QOAuth1Signature::HttpRequestMethod::Custom,
+ parameters);
+ signature.setCustomMethodString(verb);
+ return formatSignature(signature);
+}
+QByteArray QOAuth1Private::formatSignature(const QOAuth1Signature &signature) const
+{
switch (signatureMethod) {
case QOAuth1::SignatureMethod::Hmac_Sha1:
return signature.hmacSha1().toBase64();
@@ -260,6 +277,38 @@ QByteArray QOAuth1Private::generateSignature(const QVariantMap &parameters,
}
}
+QVariantMap QOAuth1Private::createOAuthBaseParams() const
+{
+ QVariantMap oauthParams;
+
+ const auto currentDateTime = QDateTime::currentDateTimeUtc();
+
+ oauthParams.insert(Key::oauthConsumerKey, clientIdentifier);
+ oauthParams.insert(Key::oauthVersion, QStringLiteral("1.0"));
+ oauthParams.insert(Key::oauthToken, token);
+ oauthParams.insert(Key::oauthSignatureMethod, signatureMethodString());
+ oauthParams.insert(Key::oauthNonce, QOAuth1::nonce());
+ oauthParams.insert(Key::oauthTimestamp, QString::number(currentDateTime.toTime_t()));
+
+ return oauthParams;
+}
+
+void QOAuth1Private::prepareRequestImpl(QNetworkRequest *request,
+ const QByteArray &verb,
+ const QByteArray &body)
+{
+ Q_Q(QOAuth1);
+ QVariantMap signingParams;
+ if (verb == "POST" &&
+ request->header(QNetworkRequest::ContentTypeHeader).toByteArray()
+ == "application/x-www-form-urlencoded") {
+ QUrlQuery query(QString::fromUtf8(body));
+ for (const auto &item : query.queryItems(QUrl::FullyDecoded))
+ signingParams.insert(item.first, item.second);
+ }
+ q->setup(request, signingParams, verb);
+}
+
void QOAuth1Private::_q_onTokenRequestError(QNetworkReply::NetworkError error)
{
Q_Q(QOAuth1);
@@ -701,6 +750,8 @@ QNetworkReply *QOAuth1::requestTokenCredentials(QNetworkAccessManager::Operation
/*!
Signs the \a request using \a signingParameters and \a operation.
+
+ \overload
*/
void QOAuth1::setup(QNetworkRequest *request,
const QVariantMap &signingParameters,
@@ -708,16 +759,7 @@ void QOAuth1::setup(QNetworkRequest *request,
{
Q_D(const QOAuth1);
- QVariantMap oauthParams;
-
- const auto currentDateTime = QDateTime::currentDateTimeUtc();
-
- oauthParams.insert(Key::oauthConsumerKey, d->clientIdentifier);
- oauthParams.insert(Key::oauthVersion, QStringLiteral("1.0"));
- oauthParams.insert(Key::oauthToken, d->token);
- oauthParams.insert(Key::oauthSignatureMethod, d->signatureMethodString());
- oauthParams.insert(Key::oauthNonce, QOAuth1::nonce());
- oauthParams.insert(Key::oauthTimestamp, QString::number(currentDateTime.toTime_t()));
+ auto oauthParams = d->createOAuthBaseParams();
// Add signature parameter
{
@@ -747,6 +789,29 @@ void QOAuth1::setup(QNetworkRequest *request,
}
/*!
+ \since 5.13
+
+ Signs the \a request using \a signingParameters and \a operationVerb.
+
+ \overload
+*/
+void QOAuth1::setup(QNetworkRequest *request, const QVariantMap &signingParameters, const QByteArray &operationVerb)
+{
+ Q_D(const QOAuth1);
+
+ auto oauthParams = d->createOAuthBaseParams();
+
+ // Add signature parameter
+ {
+ const auto parameters = QVariantMap(oauthParams).unite(signingParameters);
+ const auto signature = d->generateSignature(parameters, request->url(), operationVerb);
+ oauthParams.insert(Key::oauthSignature, signature);
+ }
+
+ request->setRawHeader("Authorization", generateAuthorizationHeader(oauthParams));
+}
+
+/*!
Generates a nonce.
\b {See also}: \l {https://tools.ietf.org/html/rfc5849#section-3.3}
diff --git a/src/oauth/qoauth1.h b/src/oauth/qoauth1.h
index ef4f04e..20efce7 100644
--- a/src/oauth/qoauth1.h
+++ b/src/oauth/qoauth1.h
@@ -120,6 +120,9 @@ protected:
void setup(QNetworkRequest *request,
const QVariantMap &signingParameters,
QNetworkAccessManager::Operation operation);
+ void setup(QNetworkRequest *request,
+ const QVariantMap &signingParameters,
+ const QByteArray &operationVerb);
static QByteArray nonce();
static QByteArray generateAuthorizationHeader(const QVariantMap &oauthParams);
diff --git a/src/oauth/qoauth1_p.h b/src/oauth/qoauth1_p.h
index ee57fba..f60db5b 100644
--- a/src/oauth/qoauth1_p.h
+++ b/src/oauth/qoauth1_p.h
@@ -58,6 +58,8 @@
QT_BEGIN_NAMESPACE
+class QOAuth1Signature;
+
class QOAuth1Private : public QAbstractOAuthPrivate
{
Q_DECLARE_PUBLIC(QOAuth1)
@@ -82,6 +84,16 @@ public:
QByteArray generateSignature(const QVariantMap &parameters,
const QUrl &url,
QNetworkAccessManager::Operation operation) const;
+ QByteArray generateSignature(const QVariantMap &parameters,
+ const QUrl &url,
+ const QByteArray &verb) const;
+ QByteArray formatSignature(const QOAuth1Signature &signature) const;
+
+ QVariantMap createOAuthBaseParams() const;
+
+ void prepareRequestImpl(QNetworkRequest *request,
+ const QByteArray &verb,
+ const QByteArray &body) override;
void _q_onTokenRequestError(QNetworkReply::NetworkError error);
void _q_tokensReceived(const QVariantMap &tokens);
diff --git a/src/oauth/qoauth1signature.cpp b/src/oauth/qoauth1signature.cpp
index 46d8874..aec2de3 100644
--- a/src/oauth/qoauth1signature.cpp
+++ b/src/oauth/qoauth1signature.cpp
@@ -126,6 +126,14 @@ QByteArray QOAuth1SignaturePrivate::signatureBaseString() const
case QOAuth1Signature::HttpRequestMethod::Delete:
base.append("DELETE");
break;
+ case QOAuth1Signature::HttpRequestMethod::Custom:
+ if (!customVerb.isEmpty()) {
+ base.append(customVerb);
+ } else {
+ qCCritical(loggingCategory, "QOAuth1Signature: HttpRequestMethod::Custom requires "
+ "the verb to be set via setCustomMethodString");
+ }
+ break;
default:
qCCritical(loggingCategory, "QOAuth1Signature: HttpRequestMethod not supported");
}
@@ -244,6 +252,37 @@ void QOAuth1Signature::setHttpRequestMethod(QOAuth1Signature::HttpRequestMethod
}
/*!
+ \since 5.13
+
+ Returns the custom method string.
+
+ \sa httpRequestMethod()
+*/
+QByteArray QOAuth1Signature::customMethodString() const
+{
+ return d->customVerb;
+}
+
+/*!
+ \since 5.13
+
+ Sets a custom request method. Will set the httpRequestMethod
+ to QOAuth1Signature::HttpRequestMethod::Custom and store the
+ \a verb to use it for the generation of the signature.
+
+ \note Using this method is required when working with custom verbs.
+ Setting only the request method will fail, as the signure needs to
+ know the actual verb.
+
+ \sa setHttpRequestMethod(), HttpRequestMethod
+*/
+void QOAuth1Signature::setCustomMethodString(const QByteArray &verb)
+{
+ d->method = QOAuth1Signature::HttpRequestMethod::Custom;
+ d->customVerb = verb;
+}
+
+/*!
Returns the URL.
*/
QUrl QOAuth1Signature::url() const
diff --git a/src/oauth/qoauth1signature.h b/src/oauth/qoauth1signature.h
index 6890974..a75cfc0 100644
--- a/src/oauth/qoauth1signature.h
+++ b/src/oauth/qoauth1signature.h
@@ -70,6 +70,9 @@ public:
HttpRequestMethod httpRequestMethod() const;
void setHttpRequestMethod(HttpRequestMethod method);
+ QByteArray customMethodString() const;
+ void setCustomMethodString(const QByteArray &verb);
+
QUrl url() const;
void setUrl(const QUrl &url);
diff --git a/src/oauth/qoauth1signature_p.h b/src/oauth/qoauth1signature_p.h
index d4b7104..cc648d9 100644
--- a/src/oauth/qoauth1signature_p.h
+++ b/src/oauth/qoauth1signature_p.h
@@ -66,6 +66,7 @@ public:
QOAuth1Signature::HttpRequestMethod method = QOAuth1Signature::HttpRequestMethod::Post;
+ QByteArray customVerb;
QUrl url;
QString clientSharedKey;
QString tokenSecret;
diff --git a/tests/auto/abstractoauth/tst_abstractoauth.cpp b/tests/auto/abstractoauth/tst_abstractoauth.cpp
index b422dc9..775f930 100644
--- a/tests/auto/abstractoauth/tst_abstractoauth.cpp
+++ b/tests/auto/abstractoauth/tst_abstractoauth.cpp
@@ -39,8 +39,17 @@ class tst_AbstractOAuth : public QObject
Q_OBJECT
private:
+ struct AbstractOAuthPrivate : public QAbstractOAuthPrivate {
+ AbstractOAuthPrivate() : QAbstractOAuthPrivate("", QUrl(), QString(), nullptr)
+ {}
+
+ void prepareRequestImpl(QNetworkRequest *,
+ const QByteArray &,
+ const QByteArray &) override {}
+ };
+
struct AbstractOAuth : QAbstractOAuth {
- AbstractOAuth() : QAbstractOAuth(*new QAbstractOAuthPrivate("", QUrl(), QString(), nullptr),
+ AbstractOAuth() : QAbstractOAuth(*new AbstractOAuthPrivate(),
nullptr)
{}
diff --git a/tests/auto/oauth1/BLACKLIST b/tests/auto/oauth1/BLACKLIST
index 44de921..3f74a03 100644
--- a/tests/auto/oauth1/BLACKLIST
+++ b/tests/auto/oauth1/BLACKLIST
@@ -15,3 +15,5 @@ windows
*
[authenticatedCalls]
*
+[prepareRequestCalls]
+*
diff --git a/tests/auto/oauth1/tst_oauth1.cpp b/tests/auto/oauth1/tst_oauth1.cpp
index dbc793c..eb13420 100644
--- a/tests/auto/oauth1/tst_oauth1.cpp
+++ b/tests/auto/oauth1/tst_oauth1.cpp
@@ -155,15 +155,29 @@ private Q_SLOTS:
void getToken_data();
void getToken();
+ void prepareRequestSignature_data();
+ void prepareRequestSignature();
+
void grant_data();
void grant();
void authenticatedCalls_data();
void authenticatedCalls();
+ void prepareRequestCalls_data();
+ void prepareRequestCalls();
+
void secondTemporaryToken();
};
+const auto oauthVersion = QStringLiteral("oauth_version");
+const auto oauthConsumerKey = QStringLiteral("oauth_consumer_key");
+const auto oauthNonce = QStringLiteral("oauth_nonce");
+const auto oauthSignatureMethod = QStringLiteral("oauth_signature_method");
+const auto oauthTimestamp = QStringLiteral("oauth_timestamp");
+const auto oauthToken = QStringLiteral("oauth_token");
+const auto oauthSignature = QStringLiteral("oauth_signature");
+
bool hostReachable(const QLatin1String &host)
{
// check host exists
@@ -476,6 +490,118 @@ void tst_OAuth1::getToken()
QCOMPARE(oauthHeaders["oauth_signature"], expectedSignature);
}
+void tst_OAuth1::prepareRequestSignature_data()
+{
+ QTest::addColumn<QString>("consumerKey");
+ QTest::addColumn<QString>("consumerSecret");
+ QTest::addColumn<QString>("accessKey");
+ QTest::addColumn<QString>("accessKeySecret");
+ QTest::addColumn<QNetworkRequest>("request");
+ QTest::addColumn<QByteArray>("operation");
+ QTest::addColumn<QByteArray>("body");
+ QTest::addColumn<QVariantMap>("extraParams");
+
+ QTest::newRow("get_simple")
+ << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << QNetworkRequest(QUrl("http://term.ie/oauth/example/echo_api.php"))
+ << QByteArray("GET")
+ << QByteArray()
+ << QVariantMap();
+
+ QTest::newRow("get_params")
+ << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << QNetworkRequest(QUrl("http://term.ie/oauth/example/echo_api.php?"
+ "first=first&second=second"))
+ << QByteArray("GET")
+ << QByteArray()
+ << QVariantMap();
+
+ QNetworkRequest postRequest(QUrl("http://term.ie/oauth/example/echo_api.php"));
+ postRequest.setHeader(QNetworkRequest::ContentTypeHeader,
+ QByteArray("application/x-www-form-urlencoded"));
+ QTest::newRow("post_params")
+ << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << postRequest
+ << QByteArray("POST")
+ << QByteArray("first=first&second=second")
+ << QVariantMap({
+ {"first", "first"},
+ {"second", "second"}
+ });
+
+ QTest::newRow("patch_param")
+ << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << QNetworkRequest(QUrl("http://term.ie/oauth/example/echo_api.php?"
+ "first=first&second=second"))
+ << QByteArray("PATCH")
+ << QByteArray()
+ << QVariantMap();
+}
+
+void tst_OAuth1::prepareRequestSignature()
+{
+ QFETCH(QString, consumerKey);
+ QFETCH(QString, consumerSecret);
+ QFETCH(QString, accessKey);
+ QFETCH(QString, accessKeySecret);
+ QFETCH(QNetworkRequest, request);
+ QFETCH(QByteArray, operation);
+ QFETCH(QByteArray, body);
+ QFETCH(QVariantMap, extraParams);
+
+ QOAuth1 o1;
+ o1.setClientCredentials(consumerKey, consumerSecret);
+ o1.setTokenCredentials(accessKey, accessKeySecret);
+
+ o1.prepareRequest(&request, operation, body);
+
+ // extract oauth parameters from the headers
+ QVariantMap authArgs;
+ const auto authHeader = request.rawHeader("Authorization");
+ QCOMPARE(authHeader.mid(0, 6), "OAuth ");
+ const auto values = authHeader.mid(6).split(',');
+ for (const auto &pair : values) {
+ const auto argPair = pair.split('=');
+ QCOMPARE(argPair.size(), 2);
+ QCOMPARE(argPair[1].front(), '\"');
+ QCOMPARE(argPair[1].back(), '\"');
+ authArgs.insert(argPair[0], argPair[1].mid(1, argPair[1].size() - 2));
+ }
+
+ //compare known parameters
+ QCOMPARE(authArgs.value(oauthConsumerKey).toByteArray(), consumerKey);
+ QCOMPARE(authArgs.value(oauthToken).toByteArray(), accessKey);
+ QCOMPARE(authArgs.value(oauthSignatureMethod).toByteArray(), QByteArray("HMAC-SHA1"));
+ QCOMPARE(authArgs.value(oauthVersion).toByteArray(), QByteArray("1.0"));
+ QVERIFY(authArgs.contains(oauthNonce));
+ QVERIFY(authArgs.contains(oauthTimestamp));
+ QVERIFY(authArgs.contains(oauthSignature));
+
+ // verify the signature
+ const auto sigString = QUrl::fromPercentEncoding(authArgs.take(oauthSignature)
+ .toByteArray()).toUtf8();
+ QOAuth1Signature signature(request.url(),
+ consumerSecret,
+ accessKeySecret,
+ QOAuth1Signature::HttpRequestMethod::Custom,
+ authArgs.unite(extraParams));
+ signature.setCustomMethodString(operation);
+ const auto signatureData = signature.hmacSha1();
+ QCOMPARE(signatureData.toBase64(), sigString);
+}
+
void tst_OAuth1::grant_data()
{
QTest::addColumn<QString>("consumerKey");
@@ -713,6 +839,149 @@ void tst_OAuth1::authenticatedCalls()
reply.clear();
}
+void tst_OAuth1::prepareRequestCalls_data()
+{
+ QTest::addColumn<QString>("consumerKey");
+ QTest::addColumn<QString>("consumerSecret");
+ QTest::addColumn<QString>("accessKey");
+ QTest::addColumn<QString>("accessKeySecret");
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<QVariantMap>("parameters");
+ QTest::addColumn<QByteArray>("operation");
+
+ const QVariantMap parameters { { QStringLiteral("first"), QStringLiteral("first") },
+ { QStringLiteral("second"), QStringLiteral("second") },
+ { QStringLiteral("third"), QStringLiteral("third") },
+ { QStringLiteral("c2&a3"), QStringLiteral("2=%$&@q") }
+ };
+
+ if (hostReachable(QLatin1String("term.ie"))) {
+ QTest::newRow("term.ie_get") << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << QUrl("http://term.ie/oauth/example/echo_api.php")
+ << parameters
+ << QByteArray("GET");
+ QTest::newRow("term.ie_post") << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << QUrl("http://term.ie/oauth/example/echo_api.php")
+ << parameters
+ << QByteArray("POST");
+ QTest::newRow("term.ie_percent_encoded_query")
+ << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << QUrl("http://term.ie/oauth/example/echo_api.php?key=%40value+1%2B2=3")
+ << parameters
+ << QByteArray("GET");
+ }
+ if (hostReachable(QLatin1String("oauthbin.com"))) {
+ QTest::newRow("oauthbin.com_get") << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << QUrl("http://oauthbin.com/v1/echo")
+ << parameters
+ << QByteArray("GET");
+ QTest::newRow("oauthbin.com_post") << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << QUrl("http://oauthbin.com/v1/echo")
+ << parameters
+ << QByteArray("POST");
+ QTest::newRow("oauthbin.com_percent_encoded_query")
+ << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << QUrl("http://oauthbin.com/v1/echo?key=%40value+1%2B2=3")
+ << parameters
+ << QByteArray("GET");
+ QTest::newRow("oauthbin.com_patch") << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << QUrl("http://oauthbin.com/v1/echo")
+ << parameters
+ << QByteArray("PATCH");
+ }
+}
+
+void tst_OAuth1::prepareRequestCalls()
+{
+ QFETCH(QString, consumerKey);
+ QFETCH(QString, consumerSecret);
+ QFETCH(QString, accessKey);
+ QFETCH(QString, accessKeySecret);
+ QFETCH(QUrl, url);
+ QFETCH(QVariantMap, parameters);
+ QFETCH(QByteArray, operation);
+
+ QNetworkAccessManager networkAccessManager;
+ QNetworkReplyPtr reply;
+ QString receivedData;
+ QString parametersString;
+ {
+ if (url.hasQuery()) {
+ parametersString = url.query(QUrl::FullyDecoded);
+ if (!parameters.empty())
+ parametersString.append(QLatin1Char('&'));
+ }
+ bool first = true;
+ for (auto it = parameters.begin(), end = parameters.end(); it != end; ++it) {
+ if (first)
+ first = false;
+ else
+ parametersString += QLatin1Char('&');
+ parametersString += it.key() + QLatin1Char('=') + it.value().toString();
+ }
+ }
+
+ QOAuth1 o1(&networkAccessManager);
+ o1.setClientCredentials(consumerKey, consumerSecret);
+ o1.setTokenCredentials(accessKey, accessKeySecret);
+
+ if (operation != "POST") {
+ QUrlQuery query(url.query());
+ for (auto it = parameters.begin(), end = parameters.end(); it != end; ++it)
+ query.addQueryItem(it.key(), it.value().toString());
+ url.setQuery(query);
+ }
+ QNetworkRequest request(url);
+ QByteArray body;
+ if (operation == "POST") {
+ QUrlQuery query(url.query());
+ for (auto it = parameters.begin(), end = parameters.end(); it != end; ++it)
+ query.addQueryItem(it.key(), it.value().toString());
+ body = query.toString().toUtf8();
+ request.setHeader(QNetworkRequest::ContentTypeHeader,
+ QByteArray("application/x-www-form-urlencoded"));
+ }
+
+ o1.prepareRequest(&request, operation, body);
+ if (body.isEmpty())
+ reply.reset(o1.networkAccessManager()->sendCustomRequest(request, operation));
+ else
+ reply.reset(o1.networkAccessManager()->sendCustomRequest(request, operation, body));
+ QVERIFY(!reply.isNull());
+ QVERIFY(!reply->isFinished());
+
+ connect(&networkAccessManager, &QNetworkAccessManager::finished,
+ [&](QNetworkReply *reply) {
+ QByteArray data = reply->readAll();
+ QUrlQuery query(QString::fromUtf8(data));
+ receivedData = query.toString(QUrl::FullyDecoded);
+ });
+ QVERIFY(waitForFinish(reply) == Success);
+ QCOMPARE(receivedData, parametersString);
+ reply.clear();
+}
+
void tst_OAuth1::secondTemporaryToken()
{
QNetworkAccessManager networkAccessManager;
diff --git a/tests/auto/oauth1signature/tst_oauth1signature.cpp b/tests/auto/oauth1signature/tst_oauth1signature.cpp
index 616578e..912aa44 100644
--- a/tests/auto/oauth1signature/tst_oauth1signature.cpp
+++ b/tests/auto/oauth1signature/tst_oauth1signature.cpp
@@ -101,6 +101,7 @@ void tst_OAuth1Signature::signatures_data()
{
QTest::addColumn<QUrl>("url");
QTest::addColumn<QOAuth1Signature::HttpRequestMethod>("method");
+ QTest::addColumn<QByteArray>("customVerb");
QTest::addColumn<QString>("version");
QTest::addColumn<QString>("consumerKey");
QTest::addColumn<QString>("consumerSecret");
@@ -113,6 +114,7 @@ void tst_OAuth1Signature::signatures_data()
QTest::newRow("standard") << QUrl("http://example.net")
<< QOAuth1Signature::HttpRequestMethod::Get
+ << QByteArray()
<< "1.0"
<< "key"
<< "secret"
@@ -124,6 +126,7 @@ void tst_OAuth1Signature::signatures_data()
<< "mQaARxv7pqJyViuwNGtUfm6QSIQ=";
QTest::newRow("post") << QUrl("http://example.net")
<< QOAuth1Signature::HttpRequestMethod::Post
+ << QByteArray()
<< "1.0"
<< "key"
<< "secret"
@@ -135,6 +138,7 @@ void tst_OAuth1Signature::signatures_data()
<< "L4blJKqYMTSNUEt32rCgDLhxQxM=";
QTest::newRow("put") << QUrl("http://example.net")
<< QOAuth1Signature::HttpRequestMethod::Put
+ << QByteArray()
<< "1.0"
<< "key"
<< "secret"
@@ -146,6 +150,7 @@ void tst_OAuth1Signature::signatures_data()
<< "+eiZ+phNoYnETf6SqI+XSE43JSY=";
QTest::newRow("delete") << QUrl("http://example.net")
<< QOAuth1Signature::HttpRequestMethod::Delete
+ << QByteArray()
<< "1.0"
<< "key"
<< "secret"
@@ -157,6 +162,7 @@ void tst_OAuth1Signature::signatures_data()
<< "enbOVNG7/vGliie2/L44NdccMaw=";
QTest::newRow("head") << QUrl("http://example.net")
<< QOAuth1Signature::HttpRequestMethod::Head
+ << QByteArray()
<< "1.0"
<< "key"
<< "secret"
@@ -168,6 +174,7 @@ void tst_OAuth1Signature::signatures_data()
<< "6v74w0rRsVibJsJ796Nj8cJPqEU=";
QTest::newRow("no-hmac-key") << QUrl("http://example.net")
<< QOAuth1Signature::HttpRequestMethod::Get
+ << QByteArray()
<< "1.0"
<< "key"
<< QString()
@@ -179,6 +186,7 @@ void tst_OAuth1Signature::signatures_data()
<< "N2qP+LJdLbjalZq71M7oxPdeUjc=";
QTest::newRow("custom-values") << QUrl("http://example.net")
<< QOAuth1Signature::HttpRequestMethod::Get
+ << QByteArray()
<< "1.0"
<< "key"
<< "secret"
@@ -191,6 +199,30 @@ void tst_OAuth1Signature::signatures_data()
{ "secondKey", "secondValue" }
}
<< "xNXgQaO0LrQMbJZGSfKFUmWwGDw=";
+ QTest::newRow("custom-verb-get") << QUrl("http://example.net")
+ << QOAuth1Signature::HttpRequestMethod::Custom
+ << QByteArray("GET")
+ << "1.0"
+ << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << "468167367"
+ << "1494852816"
+ << QVariantMap()
+ << "mQaARxv7pqJyViuwNGtUfm6QSIQ=";
+ QTest::newRow("custom-verb-patch") << QUrl("http://example.net")
+ << QOAuth1Signature::HttpRequestMethod::Custom
+ << QByteArray("PATCH")
+ << "1.0"
+ << "key"
+ << "secret"
+ << "accesskey"
+ << "accesssecret"
+ << "468167367"
+ << "1494852816"
+ << QVariantMap()
+ << "kcRO68D7IBQWlQvUR/jkhuF8AKM=";
}
void tst_OAuth1Signature::signatures()
@@ -200,6 +232,7 @@ void tst_OAuth1Signature::signatures()
QFETCH(QUrl, url);
QFETCH(QOAuth1Signature::HttpRequestMethod, method);
+ QFETCH(QByteArray, customVerb);
QFETCH(QString, version);
QFETCH(QString, consumerKey);
QFETCH(QString, consumerSecret);
@@ -218,6 +251,8 @@ void tst_OAuth1Signature::signatures()
parameters.insert(oauthToken, token);
QOAuth1Signature signature(url, consumerSecret, tokenSecret, method, parameters);
+ if (method == QOAuth1Signature::HttpRequestMethod::Custom)
+ signature.setCustomMethodString(customVerb);
const auto signatureData = signature.hmacSha1();
QCOMPARE(signatureData.toBase64(), result);
}
diff --git a/tests/auto/oauth2/tst_oauth2.cpp b/tests/auto/oauth2/tst_oauth2.cpp
index f3a30a9..a82ad82 100644
--- a/tests/auto/oauth2/tst_oauth2.cpp
+++ b/tests/auto/oauth2/tst_oauth2.cpp
@@ -41,6 +41,7 @@ private Q_SLOTS:
void getToken();
void refreshToken();
void getAndRefreshToken();
+ void prepareRequest();
};
struct ReplyHandler : QAbstractOAuthReplyHandler
@@ -165,5 +166,15 @@ void tst_OAuth2::getAndRefreshToken()
QCOMPARE(oauth2.token(), QLatin1String("refresh_token"));
}
+void tst_OAuth2::prepareRequest()
+{
+ QOAuth2AuthorizationCodeFlow oauth2;
+ oauth2.setToken(QStringLiteral("access_token"));
+
+ QNetworkRequest request(QUrl("http://localhost"));
+ oauth2.prepareRequest(&request, QByteArray());
+ QCOMPARE(request.rawHeader("Authorization"), QByteArray("Bearer access_token"));
+}
+
QTEST_MAIN(tst_OAuth2)
#include "tst_oauth2.moc"