summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--src/oauth/qabstractoauth.cpp24
-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
17 files changed, 511 insertions, 20 deletions
diff --git a/.qmake.conf b/.qmake.conf
index b69e88b..a0d7ee5 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -2,4 +2,4 @@ load(qt_build_config)
CONFIG += warning_clean
-MODULE_VERSION = 5.12.3
+MODULE_VERSION = 5.13.0
diff --git a/src/oauth/qabstractoauth.cpp b/src/oauth/qabstractoauth.cpp
index 5326292..a7a6c29 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>
@@ -91,7 +92,7 @@ QT_BEGIN_NAMESPACE
\enum QAbstractOAuth::Stage
Identifies an authentication stage. It's passed to a
- ModifyParametersFunction so that it can make different changes to
+ modifyParametersFunction so that it can make different changes to
parameters at each call to it during the process of
authentication.
@@ -510,8 +511,25 @@ void QAbstractOAuth::setReplyHandler(QAbstractOAuthReplyHandler *handler)
}
/*!
+ \since 5.13
+
+ Authorizes the given \a request by adding a header and \a body 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
+ \sa QAbstractOAuth::ModifyParametersFunction, setModifyParametersFunction(), Stage
*/
QAbstractOAuth::ModifyParametersFunction QAbstractOAuth::modifyParametersFunction() const
{
@@ -524,7 +542,7 @@ QAbstractOAuth::ModifyParametersFunction QAbstractOAuth::modifyParametersFunctio
This function is used to customize the parameters sent to the server
during a specified authorization stage. The number of calls to this
function depends on the flow used during the authentication.
- \sa modifyParametersFunction(), ModifyParametersFunction, Stage
+ \sa modifyParametersFunction(), Stage
*/
void QAbstractOAuth::setModifyParametersFunction(
const QAbstractOAuth::ModifyParametersFunction &modifyParametersFunction)
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"