summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/oauth/redditclient/redditmodel.cpp2
-rw-r--r--src/oauth/doc/snippets/src_oauth_replyhandlers.cpp4
-rw-r--r--src/oauth/qabstractoauth2.cpp38
-rw-r--r--src/oauth/qabstractoauth2.h15
-rw-r--r--src/oauth/qabstractoauth2_p.h8
-rw-r--r--src/oauth/qoauth2authorizationcodeflow.cpp2
-rw-r--r--src/oauth/qoauth2deviceauthorizationflow.cpp2
-rw-r--r--tests/auto/oauth2/tst_oauth2.cpp116
-rw-r--r--tests/auto/oauth2deviceflow/tst_oauth2deviceflow.cpp72
9 files changed, 147 insertions, 112 deletions
diff --git a/examples/oauth/redditclient/redditmodel.cpp b/examples/oauth/redditclient/redditmodel.cpp
index ac7ea30..c50e0c7 100644
--- a/examples/oauth/redditclient/redditmodel.cpp
+++ b/examples/oauth/redditclient/redditmodel.cpp
@@ -33,7 +33,7 @@ RedditModel::RedditModel(const QString &clientId, QObject *parent) :
oauth2.setReplyHandler(replyHandler);
oauth2.setAuthorizationUrl(QUrl(authorizationUrl));
oauth2.setTokenUrl(QUrl(accessTokenUrl));
- oauth2.setRequestedScopeTokens({"identity"_L1, "read"_L1});
+ oauth2.setRequestedScopeTokens({"identity", "read"});
oauth2.setClientIdentifier(clientId);
QObject::connect(&oauth2, &QAbstractOAuth::granted, this, [this] {
diff --git a/src/oauth/doc/snippets/src_oauth_replyhandlers.cpp b/src/oauth/doc/snippets/src_oauth_replyhandlers.cpp
index 7dff697..76dbcaa 100644
--- a/src/oauth/doc/snippets/src_oauth_replyhandlers.cpp
+++ b/src/oauth/doc/snippets/src_oauth_replyhandlers.cpp
@@ -43,7 +43,7 @@ using namespace Qt::StringLiterals;
static constexpr auto authorizationUrl = "https://www.myqtapp.example.com/api/v1/authorize"_L1;
static constexpr auto accessTokenUrl = "https://www.myqtapp.example.com/api/v1/access_token"_L1;
static constexpr auto clientIdentifier = "some_client_id"_L1;
-static constexpr auto scope = "read"_L1;
+static constexpr auto scope = "read";
static constexpr auto oidcConfigUrl =
"https://www.myqtapp.example.com/.well-known/openid-configuration"_L1;
static constexpr auto oidcJwksUrl = "https://www.myqtapp.example.com/v1/certs"_L1;
@@ -62,7 +62,7 @@ HttpExample::HttpExample()
#endif
//! [oidc-setting-scope]
- m_oauth.setRequestedScopeTokens({"openid"_L1});
+ m_oauth.setRequestedScopeTokens({"openid"});
//! [oidc-setting-scope]
//! [httpserver-service-configuration]
diff --git a/src/oauth/qabstractoauth2.cpp b/src/oauth/qabstractoauth2.cpp
index 3b40d90..e0250be 100644
--- a/src/oauth/qabstractoauth2.cpp
+++ b/src/oauth/qabstractoauth2.cpp
@@ -439,7 +439,7 @@ void QAbstractOAuth2Private::setExpiresAt(const QDateTime &expiration)
emit q->expirationAtChanged(expiresAtUtc.toLocalTime());
}
-void QAbstractOAuth2Private::setGrantedScopeTokens(const QStringList &tokens)
+void QAbstractOAuth2Private::setGrantedScopeTokens(const QSet<QByteArray> &tokens)
{
if (tokens == grantedScopeTokens)
return;
@@ -448,6 +448,26 @@ void QAbstractOAuth2Private::setGrantedScopeTokens(const QStringList &tokens)
Q_EMIT q->grantedScopeTokensChanged(grantedScopeTokens);
}
+QByteArray QAbstractOAuth2Private::joinedScope(const QSet<QByteArray> &scopeTokens)
+{
+ QByteArray joined;
+ const char *separator = "";
+ for (const auto &token : scopeTokens) {
+ joined += separator;
+ joined += token;
+ separator = " ";
+ }
+ return joined;
+}
+
+QSet<QByteArray> QAbstractOAuth2Private::splitScope(QStringView scope)
+{
+ QSet<QByteArray> split;
+ for (const auto &token : scope.split(u' ', Qt::SkipEmptyParts))
+ split.insert(token.toUtf8());
+ return split;
+}
+
QString QAbstractOAuth2Private::generateRandomState()
{
return QString::fromLatin1(QAbstractOAuthPrivate::generateRandomBase64String(8));
@@ -549,7 +569,7 @@ bool QAbstractOAuth2Private::authorizationShouldIncludeNonce() const
case QAbstractOAuth2::NonceMode::Disabled:
return false;
case QAbstractOAuth2::NonceMode::Automatic:
- return requestedScopeTokens.contains("openid"_L1);
+ return requestedScopeTokens.contains("openid");
};
return false;
}
@@ -614,7 +634,7 @@ void QAbstractOAuth2Private::_q_tokenRequestFinished(const QVariantMap &values)
// Note: 'scope' variable has two roles: requested scope, and later granted scope.
// Therefore 'scope' needs to be set if the granted scope differs from 'scope'.
const QString receivedGrantedScope = values.value(QtOAuth2RfcKeywords::scope).toString();
- const QStringList splitGrantedScope = receivedGrantedScope.split(" "_L1, Qt::SkipEmptyParts);
+ const QSet<QByteArray> splitGrantedScope = splitScope(receivedGrantedScope);
if (splitGrantedScope.isEmpty()) {
setGrantedScopeTokens(requestedScopeTokens);
} else {
@@ -631,7 +651,7 @@ void QAbstractOAuth2Private::_q_tokenRequestFinished(const QVariantMap &values)
// https://openid.net/specs/openid-connect-core-1_0-final.html#AuthRequest (cf. 'scope')
// https://openid.net/specs/openid-connect-core-1_0-final.html#TokenResponse
const QString receivedIdToken = values.value(QtOAuth2RfcKeywords::idToken).toString();
- if (grantedScopeTokens.contains("openid"_L1) && receivedIdToken.isEmpty()) {
+ if (grantedScopeTokens.contains("openid") && receivedIdToken.isEmpty()) {
setIdToken({});
_q_tokenRequestFailed(QAbstractOAuth::Error::OAuthTokenNotFoundError,
"ID token not received"_L1);
@@ -1100,7 +1120,7 @@ QString QAbstractOAuth2::scope() const
}
#endif
-QStringList QAbstractOAuth2::grantedScopeTokens() const
+QSet<QByteArray> QAbstractOAuth2::grantedScopeTokens() const
{
Q_D(const QAbstractOAuth2);
return d->grantedScopeTokens;
@@ -1114,7 +1134,7 @@ void QAbstractOAuth2::setScope(const QString &scope)
d->scope = scope;
QT_IGNORE_DEPRECATIONS(Q_EMIT scopeChanged(scope);)
}
- QStringList splitScope = scope.split(" "_L1, Qt::SkipEmptyParts);
+ const QSet<QByteArray> splitScope = d->splitScope(scope);
if (d->requestedScopeTokens != splitScope) {
d->requestedScopeTokens = splitScope;
Q_EMIT requestedScopeTokensChanged(splitScope);
@@ -1122,13 +1142,13 @@ void QAbstractOAuth2::setScope(const QString &scope)
}
#endif
-QStringList QAbstractOAuth2::requestedScopeTokens() const
+QSet<QByteArray> QAbstractOAuth2::requestedScopeTokens() const
{
Q_D(const QAbstractOAuth2);
return d->requestedScopeTokens;
}
-void QAbstractOAuth2::setRequestedScopeTokens(const QStringList &tokens)
+void QAbstractOAuth2::setRequestedScopeTokens(const QSet<QByteArray> &tokens)
{
Q_D(QAbstractOAuth2);
if (tokens != d->requestedScopeTokens) {
@@ -1136,7 +1156,7 @@ void QAbstractOAuth2::setRequestedScopeTokens(const QStringList &tokens)
Q_EMIT requestedScopeTokensChanged(tokens);
}
#if QT_REMOVAL_QT7_DEPRECATED_SINCE(6, 13)
- QString joinedScope = tokens.join(" "_L1);
+ QString joinedScope = QString::fromLatin1(d->joinedScope(tokens));
if (joinedScope != d->scope) {
d->scope = joinedScope;
QT_IGNORE_DEPRECATIONS(Q_EMIT scopeChanged(joinedScope);)
diff --git a/src/oauth/qabstractoauth2.h b/src/oauth/qabstractoauth2.h
index 4fe783f..f322f5a 100644
--- a/src/oauth/qabstractoauth2.h
+++ b/src/oauth/qabstractoauth2.h
@@ -8,6 +8,7 @@
#ifndef QT_NO_HTTP
+#include <QtCore/qcontainerfwd.h>
#include <QtCore/qdatetime.h>
#include <QtNetworkAuth/qabstractoauth.h>
@@ -23,9 +24,9 @@ class Q_OAUTH_EXPORT QAbstractOAuth2 : public QAbstractOAuth
#if QT_REMOVAL_QT7_DEPRECATED_SINCE(6, 13)
Q_PROPERTY(QString scope READ scope WRITE setScope NOTIFY scopeChanged)
#endif
- Q_PROPERTY(QStringList grantedScopeTokens
+ Q_PROPERTY(QSet<QByteArray> grantedScopeTokens
READ grantedScopeTokens NOTIFY grantedScopeTokensChanged)
- Q_PROPERTY(QStringList requestedScopeTokens
+ Q_PROPERTY(QSet<QByteArray> requestedScopeTokens
READ requestedScopeTokens
WRITE setRequestedScopeTokens
NOTIFY requestedScopeTokensChanged)
@@ -122,10 +123,10 @@ public:
void setScope(const QString &scope);
#endif
- QStringList grantedScopeTokens() const;
+ QSet<QByteArray> grantedScopeTokens() const;
- QStringList requestedScopeTokens() const;
- void setRequestedScopeTokens(const QStringList &tokens);
+ QSet<QByteArray> requestedScopeTokens() const;
+ void setRequestedScopeTokens(const QSet<QByteArray> &tokens);
QString userAgent() const;
void setUserAgent(const QString &userAgent);
@@ -190,8 +191,8 @@ Q_SIGNALS:
QT_DEPRECATED_VERSION_X_6_13("Use requestedScopeTokens and grantedScopeTokens properties instead.")
void scopeChanged(const QString &scope);
#endif
- void grantedScopeTokensChanged(const QStringList &tokens);
- void requestedScopeTokensChanged(const QStringList &tokens);
+ void grantedScopeTokensChanged(const QSet<QByteArray> &tokens);
+ void requestedScopeTokensChanged(const QSet<QByteArray> &tokens);
void userAgentChanged(const QString &userAgent);
void responseTypeChanged(const QString &responseType);
void clientIdentifierSharedKeyChanged(const QString &clientIdentifierSharedKey);
diff --git a/src/oauth/qabstractoauth2_p.h b/src/oauth/qabstractoauth2_p.h
index 00b559f..51ccd73 100644
--- a/src/oauth/qabstractoauth2_p.h
+++ b/src/oauth/qabstractoauth2_p.h
@@ -46,7 +46,9 @@ public:
~QAbstractOAuth2Private();
void setExpiresAt(const QDateTime &expiration);
- void setGrantedScopeTokens(const QStringList &tokens);
+ void setGrantedScopeTokens(const QSet<QByteArray> &tokens);
+ static QByteArray joinedScope(const QSet<QByteArray> &scopeTokens);
+ static QSet<QByteArray> splitScope(QStringView scope);
static QString generateRandomState();
static QString generateNonce();
QNetworkRequest createRequest(QUrl url, const QVariantMap *parameters = nullptr);
@@ -84,8 +86,8 @@ public:
#if QT_REMOVAL_QT7_DEPRECATED_SINCE(6, 13)
QString scope;
#endif
- QStringList requestedScopeTokens;
- QStringList grantedScopeTokens;
+ QSet<QByteArray> requestedScopeTokens;
+ QSet<QByteArray> grantedScopeTokens;
QString state = generateRandomState();
QString userAgent = QStringLiteral("QtOAuth/1.0 (+https://www.qt.io)");
QString responseType;
diff --git a/src/oauth/qoauth2authorizationcodeflow.cpp b/src/oauth/qoauth2authorizationcodeflow.cpp
index 3cf61ed..33c47fa 100644
--- a/src/oauth/qoauth2authorizationcodeflow.cpp
+++ b/src/oauth/qoauth2authorizationcodeflow.cpp
@@ -457,7 +457,7 @@ QUrl QOAuth2AuthorizationCodeFlow::buildAuthenticateUrl(const QMultiMap<QString,
p.insert(QtOAuth2RfcKeywords::clientIdentifier, d->clientIdentifier);
p.insert(QtOAuth2RfcKeywords::redirectUri, callback());
if (!d->requestedScopeTokens.isEmpty())
- p.insert(QtOAuth2RfcKeywords::scope, d->requestedScopeTokens.join(" "_L1));
+ p.insert(QtOAuth2RfcKeywords::scope, d->joinedScope(d->requestedScopeTokens));
p.insert(QtOAuth2RfcKeywords::state, toUrlFormEncoding(state));
if (d->pkceMethod != PkceMethod::None) {
p.insert(QtOAuth2RfcKeywords::codeChallenge, d->createPKCEChallenge());
diff --git a/src/oauth/qoauth2deviceauthorizationflow.cpp b/src/oauth/qoauth2deviceauthorizationflow.cpp
index 0afb354..6ac27b9 100644
--- a/src/oauth/qoauth2deviceauthorizationflow.cpp
+++ b/src/oauth/qoauth2deviceauthorizationflow.cpp
@@ -658,7 +658,7 @@ void QOAuth2DeviceAuthorizationFlow::grant()
QMultiMap<QString, QVariant> parameters;
parameters.insert(QtOAuth2RfcKeywords::clientIdentifier, d->clientIdentifier);
if (!d->requestedScopeTokens.isEmpty())
- parameters.insert(QtOAuth2RfcKeywords::scope, d->requestedScopeTokens.join(" "_L1));
+ parameters.insert(QtOAuth2RfcKeywords::scope, d->joinedScope(d->requestedScopeTokens));
if (d->authorizationShouldIncludeNonce()) {
if (d->nonce.isEmpty())
setNonce(QAbstractOAuth2Private::generateNonce());
diff --git a/tests/auto/oauth2/tst_oauth2.cpp b/tests/auto/oauth2/tst_oauth2.cpp
index 5999805..6d8a2a0 100644
--- a/tests/auto/oauth2/tst_oauth2.cpp
+++ b/tests/auto/oauth2/tst_oauth2.cpp
@@ -860,7 +860,7 @@ void tst_OAuth2::nonce()
// Verify that nonce is set to authorization request when appropriate
oauth2.setNonce(nonce);
- oauth2.setRequestedScopeTokens({u"scope_item1"_s});
+ oauth2.setRequestedScopeTokens({"scope_item1"});
// -- Nonce is always included
oauth2.setNonceMode(QAbstractOAuth2::NonceMode::Enabled);
@@ -877,7 +877,7 @@ void tst_OAuth2::nonce()
oauth2.grant();
QVERIFY(nonceInAuthorizationUrl.isEmpty());
- oauth2.setRequestedScopeTokens({u"scope_item1"_s, u"openid"_s});
+ oauth2.setRequestedScopeTokens({"scope_item1", "openid"});
oauth2.grant();
QCOMPARE(nonceInAuthorizationUrl, nonce);
@@ -892,7 +892,7 @@ void tst_OAuth2::nonce()
void tst_OAuth2::idToken()
{
QOAuth2AuthorizationCodeFlow oauth2;
- oauth2.setRequestedScopeTokens({"openid"_L1});
+ oauth2.setRequestedScopeTokens({"openid"});
oauth2.setAuthorizationUrl({"authorizationUrl"_L1});
oauth2.setTokenUrl({"accessTokenUrl"_L1});
oauth2.setState("a_state"_L1);
@@ -905,7 +905,7 @@ void tst_OAuth2::idToken()
QVERIFY(oauth2.idToken().isEmpty());
// Test without openid and verify idToken doesn't change
- oauth2.setRequestedScopeTokens({"read"_L1});
+ oauth2.setRequestedScopeTokens({"read"});
oauth2.grant();
// Conclude authorization stage in order to proceed to access token stage
replyHandler.emitCallbackReceived({{"code"_L1, "acode"_L1}, {"state"_L1, "a_state"_L1}});
@@ -919,7 +919,7 @@ void tst_OAuth2::idToken()
// Note: using a proper JWT or setting the matching 'nonce' is not required for this tests
// purpose as we don't currently validate the received token, but no harm in being thorough
auto idToken = createSignedJWT({}, {{"nonce"_L1, oauth2.nonce()}});
- oauth2.setRequestedScopeTokens({"openid"_L1});
+ oauth2.setRequestedScopeTokens({"openid"});
oauth2.grant();
replyHandler.emitCallbackReceived({{"code"_L1, "acode"_L1}, {"state"_L1, "a_state"_L1}});
replyHandler.emitTokensReceived({{"access_token"_L1, "at"_L1}, {"id_token"_L1, idToken}});
@@ -1024,25 +1024,25 @@ void tst_OAuth2::scope()
void tst_OAuth2::scopeAndRequestedScope_data()
{
- const QString f = u"first"_s;
- const QString s = u"second"_s;
- const QString fs = u"first second"_s;
+ const QByteArray f = "first";
+ const QByteArray s = "second";
+ const QByteArray fs = "first second";
- QTest::addColumn<QString>("scope");
- QTest::addColumn<QString>("expected_scope");
- QTest::addColumn<QStringList>("requested_scope");
- QTest::addColumn<QString>("expected_resulting_request_scope");
+ QTest::addColumn<QByteArray>("scope");
+ QTest::addColumn<QByteArray>("expected_scope");
+ QTest::addColumn<QSet<QByteArray>>("requested_scope");
+ QTest::addColumn<QByteArray>("expected_resulting_request_scope");
- QTest::addRow("singlescope") << f << f << QStringList{f} << f;
- QTest::addRow("multiscope") << fs << fs << QStringList{f, s} << fs;
+ QTest::addRow("singlescope") << f << f << QSet{f} << f;
+ QTest::addRow("multiscope") << fs << fs << QSet{f, s} << fs;
}
void tst_OAuth2::scopeAndRequestedScope()
{
- QFETCH(QString, scope);
- QFETCH(QString, expected_scope);
- QFETCH(QStringList, requested_scope);
- QFETCH(QString, expected_resulting_request_scope);
+ QFETCH(QByteArray, scope);
+ QFETCH(QByteArray, expected_scope);
+ QFETCH(QSet<QByteArray>, requested_scope);
+ QFETCH(QByteArray, expected_resulting_request_scope);
QOAuth2AuthorizationCodeFlow oauth2;
oauth2.setAuthorizationUrl({"authorizationUrl"_L1});
@@ -1068,10 +1068,13 @@ void tst_OAuth2::scopeAndRequestedScope()
QCOMPARE(requestedScopeTokensSpy.size(), 1);
QCOMPARE(oauth2.requestedScopeTokens(), requested_scope);
- QCOMPARE(requestedScopeTokensSpy.at(0).at(0).toStringList(), requested_scope);
+ QCOMPARE(requestedScopeTokensSpy.at(0).at(0).value<QSet<QByteArray>>(), requested_scope);
oauth2.grant();
- QCOMPARE(resultingRequestScope, expected_resulting_request_scope);
+ auto scopeTokens = resultingRequestScope.toLatin1().split(' ');
+ QCOMPARE_EQ(scopeTokens.size(), requested_scope.size());
+ for (const auto &token : scopeTokens)
+ QVERIFY2(requested_scope.contains(token), token.data());
// Clear data
oauth2.setScope(u""_s);
@@ -1085,37 +1088,40 @@ void tst_OAuth2::scopeAndRequestedScope()
QCOMPARE(requestedScopeTokensSpy.size(), 1);
QCOMPARE(oauth2.requestedScopeTokens(), requested_scope);
- QCOMPARE(requestedScopeTokensSpy.at(0).at(0).toStringList(), requested_scope);
+ QCOMPARE(requestedScopeTokensSpy.at(0).at(0).value<QSet<QByteArray>>(), requested_scope);
QCOMPARE(scopeSpy.size(), 1);
- QCOMPARE(oauth2.scope(), expected_scope);
- QCOMPARE(scopeSpy.at(0).at(0).toString(), expected_scope);
+ scopeTokens = oauth2.scope().toLatin1().split(' ');
+ QCOMPARE_EQ(scopeTokens.size(), requested_scope.size());
+ for (const auto &token : scopeTokens)
+ QVERIFY2(requested_scope.contains(token), token.data());
oauth2.grant();
- QCOMPARE(resultingRequestScope, expected_resulting_request_scope);
+
+ scopeTokens = resultingRequestScope.toLatin1().split(' ');
+ QCOMPARE_EQ(scopeTokens.size(), requested_scope.size());
+ for (const auto &token : scopeTokens)
+ QVERIFY2(requested_scope.contains(token), token.data());
}
QT_WARNING_POP
#endif // QT_REMOVAL_QT7_DEPRECATED_SINCE(6, 13)
void tst_OAuth2::requestedScopeTokens_data()
{
- const QString f = u"first"_s;
- const QString s = u"second"_s;
- const QString fs = u"first second"_s;
+ const QByteArray f = "first";
+ const QByteArray s = "second";
- QTest::addColumn<QStringList>("requested_scope");
- QTest::addColumn<QStringList>("expected_requested_scope");
- QTest::addColumn<QString>("expected_resulting_request_scope");
+ QTest::addColumn<QSet<QByteArray>>("requested_scope");
+ QTest::addColumn<QSet<QByteArray>>("expected_requested_scope");
- QTest::addRow("singlescope") << QStringList{f} << QStringList{f} << f;
- QTest::addRow("multiscope") << QStringList{f, s} << QStringList{f, s} << fs;
+ QTest::addRow("singlescope") << QSet{f} << QSet{f};
+ QTest::addRow("multiscope") << QSet{f, s} << QSet{f, s};
}
void tst_OAuth2::requestedScopeTokens()
{
- QFETCH(QStringList, requested_scope);
- QFETCH(QStringList, expected_requested_scope);
- QFETCH(QString, expected_resulting_request_scope);
+ QFETCH(QSet<QByteArray>, requested_scope);
+ QFETCH(QSet<QByteArray>, expected_requested_scope);
QOAuth2AuthorizationCodeFlow oauth2;
oauth2.setAuthorizationUrl({"authorizationUrl"_L1});
@@ -1134,43 +1140,47 @@ void tst_OAuth2::requestedScopeTokens()
QCOMPARE(requestedScopeTokensSpy.size(), 1);
QCOMPARE(oauth2.requestedScopeTokens(), expected_requested_scope);
- QCOMPARE(requestedScopeTokensSpy.at(0).at(0).toStringList(), expected_requested_scope);
+ QCOMPARE(requestedScopeTokensSpy.at(0).at(0).value<QSet<QByteArray>>(),
+ expected_requested_scope);
oauth2.grant();
- QCOMPARE(resultingRequestScope, expected_resulting_request_scope);
+ const auto scopeTokens = resultingRequestScope.toLatin1().split(' ');
+ QCOMPARE_EQ(scopeTokens.size(), requested_scope.size());
+ for (const auto &token : scopeTokens)
+ QVERIFY2(requested_scope.contains(token), token.data());
}
void tst_OAuth2::grantedScopeTokens_data()
{
- const QStringList requestedScopeTokens = {u"first"_s, u"second"_s};
- const QString scope = u"first second"_s;
- const QString granted1 = u"granted1"_s;
- const QString granted2 = u"granted2"_s;
- const QString grantedJoined = granted1 + u" "_s + granted2;
- const QStringList grantedList = {granted1, granted2};
-
- QTest::addColumn<QStringList>("requested_scope");
- QTest::addColumn<QString>("granted_scope");
- QTest::addColumn<QStringList>("expected_granted_scope");
+ const QSet<QByteArray> requestedScopeTokens = {"first", "second"};
+ const QByteArray scope = "first second";
+ const QByteArray granted1 = "granted1";
+ const QByteArray granted2 = "granted2";
+ const QByteArray grantedJoined = granted1 + " " + granted2;
+ const QSet<QByteArray> grantedList = {granted1, granted2};
+
+ QTest::addColumn<QSet<QByteArray>>("requested_scope");
+ QTest::addColumn<QByteArray>("granted_scope");
+ QTest::addColumn<QSet<QByteArray>>("expected_granted_scope");
QTest::addRow("requested_scope_returned")
<< requestedScopeTokens << scope << requestedScopeTokens;
QTest::addRow("differing_singlescope_returned")
- << requestedScopeTokens << granted1 << QStringList{granted1};
+ << requestedScopeTokens << granted1 << QSet{granted1};
QTest::addRow("differing_multiscope_returned")
<< requestedScopeTokens << grantedJoined << grantedList;
QTest::addRow("empty_scope_returned")
- << requestedScopeTokens << u""_s << requestedScopeTokens;
+ << requestedScopeTokens << ""_ba << requestedScopeTokens;
}
void tst_OAuth2::grantedScopeTokens()
{
- QFETCH(QStringList, requested_scope);
- QFETCH(QString, granted_scope);
- QFETCH(QStringList, expected_granted_scope);
+ QFETCH(QSet<QByteArray>, requested_scope);
+ QFETCH(QByteArray, granted_scope);
+ QFETCH(QSet<QByteArray>, expected_granted_scope);
QOAuth2AuthorizationCodeFlow oauth2;
QSignalSpy grantedSpy(&oauth2, &QAbstractOAuth2::grantedScopeTokensChanged);
@@ -1195,7 +1205,7 @@ void tst_OAuth2::grantedScopeTokens()
QTRY_COMPARE(grantedSpy.size(), 1);
QCOMPARE(oauth2.grantedScopeTokens(), expected_granted_scope);
- QCOMPARE(grantedSpy.at(0).at(0).toStringList(), expected_granted_scope);
+ QCOMPARE(grantedSpy.at(0).at(0).value<QSet<QByteArray>>(), expected_granted_scope);
}
void tst_OAuth2::setAutoRefresh()
diff --git a/tests/auto/oauth2deviceflow/tst_oauth2deviceflow.cpp b/tests/auto/oauth2deviceflow/tst_oauth2deviceflow.cpp
index 2ba1676..8aec9cc 100644
--- a/tests/auto/oauth2deviceflow/tst_oauth2deviceflow.cpp
+++ b/tests/auto/oauth2deviceflow/tst_oauth2deviceflow.cpp
@@ -1,6 +1,7 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#include <QtTest/qtestcase.h>
#include <QtTest>
#include "oauthtestutils.h"
@@ -501,7 +502,7 @@ void tst_OAuth2DeviceFlow::startStopTokenPolling()
void tst_OAuth2DeviceFlow::getAndRefreshToken()
{
static constexpr auto clientId = "a-client-id"_L1;
- static constexpr auto scope = "a-scope"_L1;
+ static constexpr auto scope = "a-scope";
static constexpr auto accessToken = "an-access-token"_L1;
static constexpr auto clientSecret = "a-client-secret"_L1;
static constexpr auto deviceCode = "a-device-code"_L1;
@@ -1012,7 +1013,7 @@ void tst_OAuth2DeviceFlow::nonce()
authBody, authHttpStatus, tokenBody, tokenHttpStatus));
QOAuth2DeviceAuthorizationFlow oauth2;
- oauth2.setRequestedScopeTokens({"openid"_L1});
+ oauth2.setRequestedScopeTokens({"openid"});
oauth2.setAuthorizationUrl(authorizationServer->url("authorizationEndpoint"_L1));
oauth2.setTokenUrl(authorizationServer->url("tokenEndpoint"_L1));
@@ -1047,7 +1048,7 @@ void tst_OAuth2DeviceFlow::nonce()
// Verify that nonce is set to authorization request when appropriate
oauth2.setNonce(nonce);
- oauth2.setRequestedScopeTokens({u"scope_item1"_s});
+ oauth2.setRequestedScopeTokens({"scope_item1"});
// -- Nonce is always included
oauth2.setNonceMode(QAbstractOAuth2::NonceMode::Enabled);
@@ -1073,7 +1074,7 @@ void tst_OAuth2DeviceFlow::nonce()
parameters.setQuery(receivedAuthorizationRequests.at(0).body);
QVERIFY(parameters.queryItemValue(u"nonce"_s).toUtf8().isEmpty());
- oauth2.setRequestedScopeTokens({u"scope_item1"_s, u"openid"_s});
+ oauth2.setRequestedScopeTokens({"scope_item1", "openid"});
receivedAuthorizationRequests.clear();
oauth2.grant();
QTRY_COMPARE(receivedAuthorizationRequests.size(), 1);
@@ -1102,7 +1103,7 @@ void tst_OAuth2DeviceFlow::idToken()
DeviceFlow oauth2;
oauth2.flowPrivate()->useAutoTestDurations = true;
- oauth2.setRequestedScopeTokens({"openid"_L1});
+ oauth2.setRequestedScopeTokens({"openid"});
oauth2.setAuthorizationUrl(authorizationServer->url("authorizationEndpoint"_L1));
oauth2.setTokenUrl(authorizationServer->url("tokenEndpoint"_L1));
@@ -1113,7 +1114,7 @@ void tst_OAuth2DeviceFlow::idToken()
QVERIFY(oauth2.idToken().isEmpty());
// Test without openid and verify idToken doesn't change
- oauth2.setRequestedScopeTokens({"read"_L1});
+ oauth2.setRequestedScopeTokens({"read"});
oauth2.grant();
QTRY_COMPARE(oauth2.status(), Status::Granted);
QVERIFY(idTokenSpy.isEmpty());
@@ -1123,7 +1124,7 @@ void tst_OAuth2DeviceFlow::idToken()
// Note: using a proper JWT or setting the matching 'nonce' is not required for this tests
// purpose as we don't currently validate the received token, but no harm in being thorough
auto idToken = createSignedJWT({}, {{"nonce"_L1, oauth2.nonce()}});
- oauth2.setRequestedScopeTokens({"openid"_L1});
+ oauth2.setRequestedScopeTokens({"openid"});
tokenBody = R"(
{
"access_token": "an-access-token",
@@ -1154,23 +1155,20 @@ void tst_OAuth2DeviceFlow::idToken()
void tst_OAuth2DeviceFlow::requestedScopeTokens_data()
{
- const QString f = u"first"_s;
- const QString s = u"second"_s;
- const QString fs = u"first second"_s;
+ const QByteArray f = "first";
+ const QByteArray s = "second";
- QTest::addColumn<QStringList>("requested_scope");
- QTest::addColumn<QStringList>("expected_requested_scope");
- QTest::addColumn<QString>("expected_resulting_request_scope");
+ QTest::addColumn<QSet<QByteArray>>("requested_scope");
+ QTest::addColumn<QSet<QByteArray>>("expected_requested_scope");
- QTest::addRow("singlescope") << QStringList{f} << QStringList{f} << f;
- QTest::addRow("multiscope") << QStringList{f, s} << QStringList{f, s} << fs;
+ QTest::addRow("singlescope") << QSet{f} << QSet{f};
+ QTest::addRow("multiscope") << QSet{f, s} << QSet{f, s};
}
void tst_OAuth2DeviceFlow::requestedScopeTokens()
{
- QFETCH(QStringList, requested_scope);
- QFETCH(QStringList, expected_requested_scope);
- QFETCH(QString, expected_resulting_request_scope);
+ QFETCH(QSet<QByteArray>, requested_scope);
+ QFETCH(QSet<QByteArray>, expected_requested_scope);
const QString authBody = Responses::authorizationSuccess;
const QString authHttpStatus = Responses::OK_200;
@@ -1189,45 +1187,49 @@ void tst_OAuth2DeviceFlow::requestedScopeTokens()
QCOMPARE(requestedScopeTokensSpy.size(), 1);
QCOMPARE(oauth2.requestedScopeTokens(), expected_requested_scope);
- QCOMPARE(requestedScopeTokensSpy.at(0).at(0).toStringList(), expected_requested_scope);
+ QCOMPARE(requestedScopeTokensSpy.at(0).at(0).value<QSet<QByteArray>>(),
+ expected_requested_scope);
oauth2.grant();
QTRY_COMPARE(receivedAuthorizationRequests.size(), 1);
QUrlQuery parameters(receivedAuthorizationRequests.at(0).body);
- QCOMPARE(parameters.queryItemValue(u"scope"_s), expected_resulting_request_scope);
+ const auto scopeTokens = parameters.queryItemValue(u"scope"_s).toLatin1().split(' ');
+ QCOMPARE_EQ(scopeTokens.size(), requested_scope.size());
+ for (const auto &token : scopeTokens)
+ QVERIFY2(requested_scope.contains(token), token.data());
}
void tst_OAuth2DeviceFlow::grantedScopeTokens_data()
{
- const QStringList requestedScopeTokens = {u"first"_s, u"second"_s};
- const QString scope = u"first second"_s;
- const QString granted1 = u"granted1"_s;
- const QString granted2 = u"granted2"_s;
- const QString grantedJoined = granted1 + u" "_s + granted2;
- const QStringList grantedList = {granted1, granted2};
+ const QSet<QByteArray> requestedScopeTokens = {"first", "second"};
+ const QByteArray scope = "first second";
+ const QByteArray granted1 = "granted1";
+ const QByteArray granted2 = "granted2";
+ const QByteArray grantedJoined = granted1 + " " + granted2;
+ const QSet<QByteArray> grantedList = {granted1, granted2};
- QTest::addColumn<QStringList>("requested_scope");
- QTest::addColumn<QString>("granted_scope");
- QTest::addColumn<QStringList>("expected_granted_scope");
+ QTest::addColumn<QSet<QByteArray>>("requested_scope");
+ QTest::addColumn<QByteArray>("granted_scope");
+ QTest::addColumn<QSet<QByteArray>>("expected_granted_scope");
QTest::addRow("requested_scope_returned")
<< requestedScopeTokens << scope << requestedScopeTokens;
QTest::addRow("differing_singlescope_returned")
- << requestedScopeTokens << granted1 << QStringList{granted1};
+ << requestedScopeTokens << granted1 << QSet<QByteArray>{granted1};
QTest::addRow("differing_multiscope_returned")
<< requestedScopeTokens << grantedJoined << grantedList;
QTest::addRow("empty_scope_returned")
- << requestedScopeTokens << u""_s << requestedScopeTokens;
+ << requestedScopeTokens << ""_ba << requestedScopeTokens;
}
void tst_OAuth2DeviceFlow::grantedScopeTokens()
{
- QFETCH(QStringList, requested_scope);
- QFETCH(QString, granted_scope);
- QFETCH(QStringList, expected_granted_scope);
+ QFETCH(QSet<QByteArray>, requested_scope);
+ QFETCH(QByteArray, granted_scope);
+ QFETCH(QSet<QByteArray>, expected_granted_scope);
const QString authBody = Responses::authorizationSuccess;
const QString authHttpStatus = Responses::OK_200;
@@ -1258,7 +1260,7 @@ void tst_OAuth2DeviceFlow::grantedScopeTokens()
QTRY_COMPARE(grantedSpy.size(), 1);
QCOMPARE(oauth2.grantedScopeTokens(), expected_granted_scope);
- QCOMPARE(grantedSpy.at(0).at(0).toStringList(), expected_granted_scope);
+ QCOMPARE(grantedSpy.at(0).at(0).value<QSet<QByteArray>>(), expected_granted_scope);
}
void tst_OAuth2DeviceFlow::refreshLeadTime_data()