Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package signon-plugin-oauth2 for
openSUSE:Factory checked in at 2021-05-21 21:49:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/signon-plugin-oauth2 (Old)
and /work/SRC/openSUSE:Factory/.signon-plugin-oauth2.new.2988 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "signon-plugin-oauth2"
Fri May 21 21:49:32 2021 rev:6 rq:894536 version:0.25
Changes:
--------
---
/work/SRC/openSUSE:Factory/signon-plugin-oauth2/signon-plugin-oauth2.changes
2019-04-26 22:45:18.649617096 +0200
+++
/work/SRC/openSUSE:Factory/.signon-plugin-oauth2.new.2988/signon-plugin-oauth2.changes
2021-05-21 21:49:34.238344215 +0200
@@ -1,0 +2,12 @@
+Wed May 19 19:03:12 UTC 2021 - Ferdinand Thiessen <[email protected]>
+
+- Update to version 0.25
+ * OAuth2: try using specialized hostname first, use "Host" as
+ fallback only
+ * OAuth1: add UserAgent parameter
+ * OAuth2: pass token query in request body
+ * OAuth2: always try normal authentication if refresh token fails
+ * OAuth2: let the client read all extra info from the response
+ * Plugin: implement also new AuthPluginInterface2
+
+-------------------------------------------------------------------
Old:
----
signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae.tar.bz2
New:
----
signon-plugin-oauth2-VERSION_0.25.tar.bz2
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ signon-plugin-oauth2.spec ++++++
--- /var/tmp/diff_new_pack.VNBXmt/_old 2021-05-21 21:49:34.718342224 +0200
+++ /var/tmp/diff_new_pack.VNBXmt/_new 2021-05-21 21:49:34.722342207 +0200
@@ -1,7 +1,7 @@
#
# spec file for package signon-plugin-oauth2
#
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2021 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -16,16 +16,14 @@
#
-%define _version VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae
-
Name: signon-plugin-oauth2
-Version: 0.24
+Version: 0.25
Release: 0
Summary: Oauth2 plugin for the Single Sign On Framework
License: LGPL-2.0-only
Group: System/GUI/Other
-Url: https://gitlab.com/accounts-sso/signon-plugin-oauth2
-Source:
https://gitlab.com/accounts-sso/%{name}/repository/VERSION_%{version}/archive.tar.bz2#/%{name}-%{_version}.tar.bz2
+URL: https://gitlab.com/accounts-sso/signon-plugin-oauth2
+Source:
%{url}/-/archive/VERSION_%{version}/signon-plugin-oauth2-VERSION_%{version}.tar.bz2
Patch0: 0001_Multilib.patch
BuildRequires: pkgconfig(Qt5Core)
BuildRequires: pkgconfig(Qt5Network)
@@ -48,7 +46,7 @@
Sign On Framework.
%prep
-%setup -q -n %{name}-%{_version}
+%setup -q -n signon-plugin-oauth2-VERSION_%{version}
%patch0 -p1 -b .multilib
sed -i 's|@LIB@|%{_lib}|g' src/signon-oauth2plugin.pc src/src.pro
@@ -71,8 +69,6 @@
rm -rf %{buildroot}/%{_bindir} %{buildroot}/%{_datadir}
popd
-rm -v %{buildroot}%{_sysconfdir}/signon-ui/webkit-options.d/*
-
%files
%license COPYING
%doc README.md
++++++
signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae.tar.bz2
-> signon-plugin-oauth2-VERSION_0.25.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/common-project-config.pri
new/signon-plugin-oauth2-VERSION_0.25/common-project-config.pri
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/common-project-config.pri
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/common-project-config.pri
2020-11-10 20:43:33.000000000 +0100
@@ -7,7 +7,9 @@
# Common configuration for all projects.
#-----------------------------------------------------------------------------
-CONFIG += link_pkgconfig
+CONFIG += \
+ c++11 \
+ link_pkgconfig
#MOC_DIR = .moc
#OBJECTS_DIR = .obj
RCC_DIR = resources
@@ -18,7 +20,7 @@
QMAKE_CXXFLAGS += -fno-exceptions \
-fno-rtti
# we don't like warnings...
-QMAKE_CXXFLAGS += -Werror
+unix:QMAKE_CXXFLAGS += -Werror
TOP_SRC_DIR = $$PWD
@@ -67,12 +69,13 @@
}
# Default directory for signond extensions
-_PLUGINS = $$system(pkg-config --variable=plugindir signon-plugins)
-isEmpty(_PLUGINS) {
- error("plugin directory not available through pkg-config")
-} else {
- SIGNON_PLUGINS_DIR = $$_PLUGINS
+isEmpty(SIGNON_PLUGINS_DIR) {
+ _PLUGINS = $$system(pkg-config --variable=plugindir signon-plugins)
+ isEmpty(_PLUGINS) {
+ error("plugin directory not available through pkg-config")
+ } else {
+ SIGNON_PLUGINS_DIR = $$_PLUGINS
+ }
}
-SIGNON_PLUGINS_DIR_QUOTED = \\\"$$SIGNON_PLUGINS_DIR\\\"
include( coverage.pri )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/common-vars.pri
new/signon-plugin-oauth2-VERSION_0.25/common-vars.pri
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/common-vars.pri
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/common-vars.pri 2020-11-10
20:43:33.000000000 +0100
@@ -13,7 +13,7 @@
# Project version
# remember to update debian/* files if you changes this
#-----------------------------------------------------------------------------
-PROJECT_VERSION = 0.24
+PROJECT_VERSION = 0.25
#-----------------------------------------------------------------------------
# Library version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/signon-oauth2.pro
new/signon-plugin-oauth2-VERSION_0.25/signon-oauth2.pro
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/signon-oauth2.pro
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/signon-oauth2.pro 2020-11-10
20:43:33.000000000 +0100
@@ -3,7 +3,15 @@
TEMPLATE = subdirs
CONFIG += ordered
-SUBDIRS = src tests example
+SUBDIRS = src tests
+
+CONFIG(make_examples) {
+ SUBDIRS += example
+}
+
+CONFIG(nomake_tests) {
+ SUBDIRS -= tests
+}
include( common-installs-config.pri )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/oauth1data.h
new/signon-plugin-oauth2-VERSION_0.25/src/oauth1data.h
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/oauth1data.h
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/src/oauth1data.h 2020-11-10
20:43:33.000000000 +0100
@@ -37,6 +37,8 @@
{
friend class ::OAuth2PluginTest;
public:
+ using SignOn::SessionData::SessionData;
+
/*!
* Request token endpoint of the server
*/
@@ -61,6 +63,12 @@
SIGNON_SESSION_DECLARE_PROPERTY(QString, Realm);
/*!
+ * one of "PLAINTEXT", "HMAC-SHA1", or "RSA-SHA1"
+ * a method used used to sign the requests.
+ */
+ SIGNON_SESSION_DECLARE_PROPERTY(QString, SignatureMethod);
+
+ /*!
* Set this to true if the access token returned by the previous
* authentication is invalid. This instructs the OAuth plugin to
* generate a new access token.
@@ -69,6 +77,11 @@
/* Optional username */
SIGNON_SESSION_DECLARE_PROPERTY(QString, UserName);
+
+ /*!
+ * The User-Agent to be used in all HTTP requests.
+ */
+ SIGNON_SESSION_DECLARE_PROPERTY(QString, UserAgent);
};
class OAuth1PluginTokenData : public SignOn::SessionData
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/oauth1plugin.cpp
new/signon-plugin-oauth2-VERSION_0.25/src/oauth1plugin.cpp
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/oauth1plugin.cpp
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/src/oauth1plugin.cpp 2020-11-10
20:43:33.000000000 +0100
@@ -47,6 +47,7 @@
const QString HMAC_SHA1 = QString("HMAC-SHA1");
const QString PLAINTEXT = QString("PLAINTEXT");
const QString RSA_SHA1 = QString("RSA-SHA1");
+const QString OAUTH1 = QString("oauth1");
const QString EXPIRY = QString ("Expiry");
const QString USER_ID = QString("user_id");
@@ -136,6 +137,7 @@
QStringList res = QStringList();
res.append(HMAC_SHA1);
res.append(PLAINTEXT);
+ res.append(OAUTH1);
return res;
}
@@ -167,9 +169,12 @@
bool OAuth1Plugin::validateInput(const SignOn::SessionData &inData,
const QString &mechanism)
{
- Q_UNUSED(mechanism);
-
OAuth1PluginData input = inData.data<OAuth1PluginData>();
+
+ if (mechanism == OAUTH1 && input.SignatureMethod().isEmpty()) {
+ return false;
+ }
+
if (input.AuthorizationEndpoint().isEmpty()
|| input.ConsumerKey().isEmpty()
|| input.ConsumerSecret().isEmpty()
@@ -223,9 +228,13 @@
return;
}
- d->m_mechanism = mechanism;
d->m_oauth1Data = inData.data<OAuth1PluginData>();
- d->m_key = inData.data<OAuth1PluginData>().ConsumerKey();
+ d->m_key = d->m_oauth1Data.ConsumerKey();
+ if (mechanism == OAUTH1) {
+ d->m_mechanism = d->m_oauth1Data.SignatureMethod();
+ } else {
+ d->m_mechanism = mechanism;
+ }
//get stored data
OAuth2TokenData tokens = inData.data<OAuth2TokenData>();
@@ -656,6 +665,11 @@
QNetworkRequest request;
request.setRawHeader(CONTENT_TYPE, CONTENT_APP_URLENCODED);
+ if (!d->m_oauth1Data.UserAgent().isEmpty()) {
+ request.setHeader(QNetworkRequest::UserAgentHeader,
+ d->m_oauth1Data.UserAgent());
+ }
+
QString authHeader;
if (d->m_oauth1RequestType == OAUTH1_POST_REQUEST_TOKEN) {
request.setUrl(d->m_oauth1Data.RequestEndpoint());
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/oauth2data.h
new/signon-plugin-oauth2-VERSION_0.25/src/oauth2data.h
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/oauth2data.h
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/src/oauth2data.h 2020-11-10
20:43:33.000000000 +0100
@@ -36,13 +36,25 @@
{
friend class ::OAuth2PluginTest;
public:
+ using SignOn::SessionData::SessionData;
+
/*!
* hostname of the server
*/
SIGNON_SESSION_DECLARE_PROPERTY(QString, Host);
/*!
- * Authorization endpoint of the server
+ * hostname component of the authorization endpoint URI
+ */
+ SIGNON_SESSION_DECLARE_PROPERTY(QString, AuthHost);
+
+ /*!
+ * hostname component of the token endpoint URI
+ */
+ SIGNON_SESSION_DECLARE_PROPERTY(QString, TokenHost);
+
+ /*!
+ * authorization endpoint of the server
*/
SIGNON_SESSION_DECLARE_PROPERTY(QString, AuthPath);
@@ -52,6 +64,16 @@
SIGNON_SESSION_DECLARE_PROPERTY(QString, TokenPath);
/*!
+ * port component of the token endpoint URI
+ */
+ SIGNON_SESSION_DECLARE_PROPERTY(quint16, AuthPort);
+
+ /*!
+ * port component of the authorization endpoint URI
+ */
+ SIGNON_SESSION_DECLARE_PROPERTY(quint16, TokenPort);
+
+ /*!
* Application client ID and secret
*/
SIGNON_SESSION_DECLARE_PROPERTY(QString, ClientId);
@@ -94,9 +116,14 @@
SIGNON_SESSION_DECLARE_PROPERTY(QStringList, ResponseType);
/*!
- * Not in the OAuth2 standard: display type
+ * query component of the authorization endpoint URI
+ */
+ SIGNON_SESSION_DECLARE_PROPERTY(QString, AuthQuery);
+
+ /*!
+ * query component of the token endpoint URI
*/
- SIGNON_SESSION_DECLARE_PROPERTY(QString, Display);
+ SIGNON_SESSION_DECLARE_PROPERTY(QString, TokenQuery);
};
class OAuth2PluginTokenData : public SignOn::SessionData
@@ -107,6 +134,10 @@
*/
SIGNON_SESSION_DECLARE_PROPERTY(QString, AccessToken);
/*!
+ * OpenID token received from the server (optional)
+ */
+ SIGNON_SESSION_DECLARE_PROPERTY(QString, IdToken);
+ /*!
* Refresh token received from the server
*/
SIGNON_SESSION_DECLARE_PROPERTY(QString, RefreshToken);
@@ -118,6 +149,10 @@
* Granted permissions
*/
SIGNON_SESSION_DECLARE_PROPERTY(QStringList, Scope);
+ /*!
+ * Any extra (non standard) fields which were returned by the server
+ */
+ SIGNON_SESSION_DECLARE_PROPERTY(QVariantMap, ExtraFields);
};
} // namespace OAuth2PluginNS
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/oauth2plugin.cpp
new/signon-plugin-oauth2-VERSION_0.25/src/oauth2plugin.cpp
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/oauth2plugin.cpp
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/src/oauth2plugin.cpp 2020-11-10
20:43:33.000000000 +0100
@@ -40,10 +40,12 @@
const QString WEB_SERVER = QString("web_server");
const QString USER_AGENT = QString("user_agent");
+const QString OAUTH2 = QString("oauth2");
const QString TOKEN = QString("Token");
const QString EXPIRY = QString("Expiry");
const QString SCOPES = QString("Scopes");
+const QString EXTRA_FIELDS = QString("ExtraFields");
const int HTTP_STATUS_OK = 200;
const QString AUTH_CODE = QString("code");
@@ -55,7 +57,7 @@
const QString ASSERTION_TYPE = QString("assertion_type");
const QString ASSERTION = QString("assertion");
const QString ACCESS_TOKEN = QString("access_token");
-const QString DISPLAY = QString("display");
+const QString ID_TOKEN = QString("id_token");
const QString EXPIRES_IN = QString("expires_in");
const QString SCOPE = QString("scope");
const QString TIMESTAMP = QString("timestamp");
@@ -122,47 +124,78 @@
QStringList res = QStringList();
res.append(WEB_SERVER);
res.append(USER_AGENT);
+ res.append(OAUTH2);
return res;
}
+QUrl OAuth2Plugin::getAuthUrl()
+{
+ Q_D(OAuth2Plugin);
+
+ QString host = d->m_oauth2Data.AuthHost();
+ if (host.isEmpty())
+ host = d->m_oauth2Data.Host();
+
+ if (host.isEmpty())
+ return QUrl();
+
+ QUrl
url(QString("https://%1/%2").arg(host).arg(d->m_oauth2Data.AuthPath()));
+ quint16 port = d->m_oauth2Data.AuthPort();
+ if (port != 0)
+ url.setPort(port);
+
+ QString query = d->m_oauth2Data.AuthQuery();
+ if (!query.isEmpty())
+ url.setQuery(query);
+
+ return url;
+}
+
+QUrl OAuth2Plugin::getTokenUrl()
+{
+ Q_D(OAuth2Plugin);
+
+ QString host = d->m_oauth2Data.TokenHost();
+ if (host.isEmpty())
+ host = d->m_oauth2Data.Host();
+
+ if (host.isEmpty())
+ return QUrl();
+
+ QUrl
url(QString("https://%1/%2").arg(host).arg(d->m_oauth2Data.TokenPath()));
+ quint16 port = d->m_oauth2Data.TokenPort();
+ if (port != 0)
+ url.setPort(port);
+
+ return url;
+}
+
void OAuth2Plugin::sendOAuth2AuthRequest()
{
Q_D(OAuth2Plugin);
- QUrl
url(QString("https://%1/%2").arg(d->m_oauth2Data.Host()).arg(d->m_oauth2Data.AuthPath()));
+ QUrl url = getAuthUrl();
url.addQueryItem(CLIENT_ID, d->m_oauth2Data.ClientId());
- url.addQueryItem(REDIRECT_URI, d->m_oauth2Data.RedirectUri());
+ QString redirectUri = d->m_oauth2Data.RedirectUri();
+ url.addQueryItem(REDIRECT_URI, QUrl::toPercentEncoding(redirectUri));
if (!d->m_oauth2Data.DisableStateParameter()) {
d->m_state = QString::number(qrand());
url.addQueryItem(STATE, d->m_state);
}
- if (!d->m_oauth2Data.ResponseType().isEmpty()) {
- url.addQueryItem(RESPONSE_TYPE,
- d->m_oauth2Data.ResponseType().join(" "));
- }
- if (!d->m_oauth2Data.Display().isEmpty()) {
- url.addQueryItem(DISPLAY, d->m_oauth2Data.Display());
- }
- if (!d->m_oauth2Data.Scope().empty()) {
- QString separator = QLatin1String(" ");
-
- /* The scopes separator defined in the OAuth 2.0 spec is a space;
- * unfortunately facebook accepts only a comma, so we have to treat
- * it as a special case. See:
- * http://bugs.developers.facebook.net/show_bug.cgi?id=11120
- */
- if (d->m_oauth2Data.Host().contains(QLatin1String("facebook.com"))) {
- separator = QLatin1String(",");
- }
-
+ QStringList responseType = d->m_oauth2Data.ResponseType();
+ if (!responseType.isEmpty()) {
+ url.addQueryItem(RESPONSE_TYPE, responseType.join(" "));
+ }
+ QStringList scopes = d->m_oauth2Data.Scope();
+ if (!scopes.isEmpty()) {
// Passing list of scopes
- url.addQueryItem(SCOPE, d->m_oauth2Data.Scope().join(separator));
+ url.addQueryItem(SCOPE, QUrl::toPercentEncoding(scopes.join(" ")));
}
TRACE() << "Url = " << url.toString();
SignOn::UiSessionData uiSession;
uiSession.setOpenUrl(url.toString());
- if (!d->m_oauth2Data.RedirectUri().isEmpty())
- uiSession.setFinalUrl(d->m_oauth2Data.RedirectUri());
+ if (!redirectUri.isEmpty())
+ uiSession.setFinalUrl(redirectUri);
/* add username and password, for fields initialization (the
* decision on whether to actually use them is up to the signon UI */
@@ -176,13 +209,14 @@
const QString &mechanism)
{
OAuth2PluginData input = inData.data<OAuth2PluginData>();
- if (input.Host().isEmpty()
+ if ((input.Host().isEmpty() &&
+ (input.AuthHost().isEmpty() || input.TokenHost().isEmpty()))
|| input.ClientId().isEmpty()
|| input.RedirectUri().isEmpty()
|| input.AuthPath().isEmpty())
return false;
- if (mechanism == WEB_SERVER) {
+ if (mechanism == WEB_SERVER || mechanism == OAUTH2) {
/* According to the specs, the client secret is also required; however,
* some services do not require it, see for instance point 8 from
*
http://msdn.microsoft.com/en-us/library/live/hh243647.aspx#authcodegrant
@@ -222,12 +256,18 @@
if (token.contains(TOKEN)) {
OAuth2PluginTokenData response;
response.setAccessToken(token.value(TOKEN).toByteArray());
+ if (token.contains(ID_TOKEN)) {
+ response.setIdToken(token.value(ID_TOKEN).toByteArray());
+ }
if (token.contains(REFRESH_TOKEN)) {
response.setRefreshToken(token.value(REFRESH_TOKEN).toByteArray());
}
if (token.contains(EXPIRY)) {
response.setExpiresIn(timeToExpiry);
}
+ if (token.contains(EXTRA_FIELDS)) {
+ response.setExtraFields(token.value(EXTRA_FIELDS).toMap());
+ }
TRACE() << "Responding with stored token";
emit result(response);
return true;
@@ -252,6 +292,18 @@
return;
}
+ const QVariant scopeVariant = inData.getProperty("Scope");
+ if (scopeVariant.type() == QVariant::String) {
+ inData.toMap().insert(QLatin1String("Scope"),
+ QVariant(scopeVariant.toString().split(" ")));
+ }
+
+ const QVariant resptypeVariant = inData.getProperty("ResponseType");
+ if (resptypeVariant.type() == QVariant::String) {
+ inData.toMap().insert(QLatin1String("ResponseType"),
+ QVariant(resptypeVariant.toString().split(" ")));
+ }
+
d->m_mechanism = mechanism;
d->m_oauth2Data = inData.data<OAuth2PluginData>();
d->m_key = d->m_oauth2Data.ClientId();
@@ -292,6 +344,9 @@
TRACE() << "Storing provided tokens";
OAuth2PluginTokenData storeTokens;
storeTokens.setAccessToken(providedTokens.AccessToken());
+ if (!providedTokens.IdToken().isEmpty()) {
+ storeTokens.setIdToken(providedTokens.IdToken());
+ }
storeTokens.setRefreshToken(providedTokens.RefreshToken());
storeTokens.setExpiresIn(providedTokens.ExpiresIn());
storeResponse(storeTokens);
@@ -312,8 +367,10 @@
d->m_username = inData.UserName();
d->m_password = inData.Secret();
- if (mechanism == WEB_SERVER || mechanism == USER_AGENT) {
- if (mechanism == WEB_SERVER &&
+ if (mechanism == WEB_SERVER
+ || mechanism == USER_AGENT
+ || mechanism == OAUTH2) {
+ if ((mechanism == WEB_SERVER || mechanism == OAUTH2) &&
storedData.contains(REFRESH_TOKEN) &&
!storedData[REFRESH_TOKEN].toString().isEmpty()) {
/* If we have a refresh token, use it to get a renewed
@@ -356,10 +413,13 @@
QString state;
respData.setScope(d->m_oauth2Data.Scope());
QUrlQuery fragment(url.fragment());
+ QVariantMap extraFields;
typedef QPair<QString, QString> StringPair;
Q_FOREACH(const StringPair &pair, fragment.queryItems()) {
if (pair.first == ACCESS_TOKEN) {
respData.setAccessToken(pair.second);
+ } else if (pair.first == ID_TOKEN) {
+ respData.setIdToken(pair.second);
} else if (pair.first == EXPIRES_IN) {
respData.setExpiresIn(pair.second.toInt());
} else if (pair.first == REFRESH_TOKEN) {
@@ -368,8 +428,11 @@
state = pair.second;
} else if (pair.first == SCOPE) {
respData.setScope(pair.second.split(' ',
QString::SkipEmptyParts));
+ } else {
+ extraFields.insert(pair.first, pair.second);
}
}
+ respData.setExtraFields(extraFields);
if (!d->m_oauth2Data.DisableStateParameter() &&
state != d->m_state) {
Q_EMIT error(Error(Error::NotAuthorized,
@@ -388,13 +451,18 @@
else {
emit error(Error(Error::NotAuthorized, QString("Access token not
present")));
}
- } else if (d->m_mechanism == WEB_SERVER) {
+ } else if (d->m_mechanism == WEB_SERVER || d->m_mechanism == OAUTH2) {
// Access grant can be one of the floolwing types
// 1. Authorization code (code, redirect_uri)
// 2. Resource owner credentials (username, password)
// 3. Assertion (assertion_type, assertion)
// 4. Refresh Token (refresh_token)
QUrl newUrl;
+ QString query = d->m_oauth2Data.TokenQuery();
+ if (!query.isEmpty()) {
+ newUrl.setQuery(query);
+ }
+
if (url.hasQueryItem(AUTH_CODE)) {
if (!d->m_oauth2Data.DisableStateParameter() &&
d->m_state != url.queryItemValue(STATE)) {
@@ -502,17 +570,18 @@
// The error has already been delivered
return;
}
- QByteArray accessToken = map["access_token"].toByteArray();
- int expiresIn = map["expires_in"].toInt();
+ QByteArray accessToken = map.take("access_token").toByteArray();
+ QByteArray idToken = map.take("id_token").toByteArray();
+ int expiresIn = map.take("expires_in").toInt();
if (expiresIn == 0) {
// Facebook uses just "expires" as key
- expiresIn = map["expires"].toInt();
+ expiresIn = map.take("expires").toInt();
}
- QByteArray refreshToken = map["refresh_token"].toByteArray();
+ QByteArray refreshToken = map.take("refresh_token").toByteArray();
QStringList scope;
if (map.contains(SCOPE)) {
- QString rawScope = QString::fromUtf8(map[SCOPE].toByteArray());
+ QString rawScope =
QString::fromUtf8(map.take(SCOPE).toByteArray());
scope = rawScope.split(' ', QString::SkipEmptyParts);
} else {
scope = d->m_oauth2Data.Scope();
@@ -525,9 +594,13 @@
} else {
OAuth2PluginTokenData response;
response.setAccessToken(accessToken);
+ if (idToken.length() > 0) {
+ response.setIdToken(idToken);
+ }
response.setRefreshToken(refreshToken);
response.setExpiresIn(expiresIn);
response.setScope(scope);
+ response.setExtraFields(map);
storeResponse(response);
emit result(response);
}
@@ -559,6 +632,13 @@
QVariantMap map = parseJSONReply(reply);
QByteArray errorString = map["error"].toByteArray();
if (!errorString.isEmpty()) {
+ if (d->m_grantType == GrantType::RefreshToken) {
+ /* The refresh token has expired; try once more using
+ * the web-based authentication flow. */
+ TRACE() << "Authenticating without refresh token";
+ sendOAuth2AuthRequest();
+ return;
+ }
Error::ErrorType type = Error::OperationFailed;
if (errorString == QByteArray("incorrect_client_credentials")) {
type = Error::InvalidCredentials;
@@ -591,13 +671,6 @@
type = Error::InvalidCredentials;
}
else if (errorString == QByteArray("invalid_grant")) {
- if (d->m_grantType == GrantType::RefreshToken) {
- /* The refresh token has expired; try once more using
- * the web-based authentication flow. */
- TRACE() << "Authenticating without refresh token";
- sendOAuth2AuthRequest();
- return;
- }
type = Error::NotAuthorized;
}
TRACE() << "Error Emitted";
@@ -630,8 +703,7 @@
QUrl url(d->m_oauth2Data.TokenPath());
if (url.isRelative()) {
- url = QUrl(QString("https://%1/%2").arg(d->m_oauth2Data.Host())
- .arg(d->m_oauth2Data.TokenPath()));
+ url = getTokenUrl();
}
QNetworkRequest request(url);
request.setRawHeader(CONTENT_TYPE, CONTENT_APP_URLENCODED);
@@ -665,6 +737,9 @@
OAuth2TokenData tokens;
QVariantMap token;
token.insert(TOKEN, response.AccessToken());
+ if (response.IdToken().length() > 0) {
+ token.insert(ID_TOKEN, response.IdToken());
+ }
/* Do not overwrite the refresh token with an empty one: when using the
* refresh token to obtain a new access token, the replie could not contain
* a refresh token (or contain an empty one).
@@ -690,6 +765,7 @@
}
token.insert(TIMESTAMP, QDateTime::currentDateTime().toTime_t());
token.insert(SCOPES, d->m_oauth2Data.Scope());
+ token.insert(EXTRA_FIELDS, response.ExtraFields());
d->m_tokens.insert(d->m_key, QVariant::fromValue(token));
tokens.setTokens(d->m_tokens);
Q_EMIT store(tokens);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/oauth2plugin.h
new/signon-plugin-oauth2-VERSION_0.25/src/oauth2plugin.h
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/oauth2plugin.h
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/src/oauth2plugin.h 2020-11-10
20:43:33.000000000 +0100
@@ -83,6 +83,8 @@
QVariantMap parseTextReply(const QByteArray &reply);
void handleOAuth2Error(const QByteArray &reply);
QString urlEncode(QString strData);
+ QUrl getAuthUrl();
+ QUrl getTokenUrl();
OAuth2PluginPrivate *d_ptr;
Q_DECLARE_PRIVATE(OAuth2Plugin)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/plugin.cpp
new/signon-plugin-oauth2-VERSION_0.25/src/plugin.cpp
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/plugin.cpp
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/src/plugin.cpp 2020-11-10
20:43:33.000000000 +0100
@@ -134,3 +134,12 @@
TRACE();
if (impl != 0) impl->refresh(data);
}
+
+#ifdef SIGNON_PLUGINS_HAS_AUTHPLUGINIF_2
+
+AuthPluginInterface *PluginInterface::createAuthPlugin(QObject *parent)
+{
+ return new Plugin(parent);
+}
+
+#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/plugin.h
new/signon-plugin-oauth2-VERSION_0.25/src/plugin.h
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/plugin.h
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/src/plugin.h 2020-11-10
20:43:33.000000000 +0100
@@ -64,6 +64,20 @@
QNetworkAccessManager *m_networkAccessManager;
};
+#ifdef SIGNON_PLUGINS_HAS_AUTHPLUGINIF_2
+
+class PluginInterface: public QObject, AuthPluginInterface2
+{
+ Q_OBJECT
+ Q_INTERFACES(AuthPluginInterface2)
+ Q_PLUGIN_METADATA(IID "com.nokia.SingleSignOn.PluginInterface/2")
+
+public:
+ AuthPluginInterface *createAuthPlugin(QObject *parent = 0) Q_DECL_OVERRIDE;
+};
+
+#endif
+
} //namespace OAuth2PluginNS
#endif // SIGNON_PLUGIN_OAUTH2_MAIN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/src.pro
new/signon-plugin-oauth2-VERSION_0.25/src/src.pro
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/src/src.pro
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/src/src.pro 2020-11-10
20:43:33.000000000 +0100
@@ -7,7 +7,6 @@
network
QT -= gui
CONFIG += plugin \
- build_all \
warn_on \
link_pkgconfig
public_headers += oauth2data.h oauth1data.h
@@ -25,9 +24,14 @@
oauth1plugin.cpp \
oauth2plugin.cpp \
plugin.cpp
-PKGCONFIG += \
- libsignon-qt5 \
- signon-plugins
+
+isEmpty(SIGNON_PLUGINS_INCLUDEPATH) {
+ PKGCONFIG += signon-plugins
+} else {
+ INCLUDEPATH += $${SIGNON_PLUGINS_INCLUDEPATH}
+ LIBS += $${SIGNON_PLUGINS_LIBS}
+ QMAKE_LIBDIR += $${SIGNON_PLUGINS_LIBDIR}
+}
headers.files = $$public_headers
pkgconfig.files = signon-oauth2plugin.pc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/tests/oauth2plugintest.cpp
new/signon-plugin-oauth2-VERSION_0.25/tests/oauth2plugintest.cpp
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/tests/oauth2plugintest.cpp
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/tests/oauth2plugintest.cpp
2020-11-10 20:43:33.000000000 +0100
@@ -27,6 +27,7 @@
#include <QNetworkReply>
#include <QPointer>
#include <QRegExp>
+#include <QScopedPointer>
#include <QSignalSpy>
#include <QTimer>
#include <QtTest/QtTest>
@@ -363,6 +364,17 @@
-1 <<
false << response << QVariantMap();
+ token.insert("id_token", QLatin1String("idtokenfromtest"));
+ tokens.insert(webServerData.ClientId(), QVariant::fromValue(token));
+ webServerData.m_data.insert(QLatin1String("Tokens"), tokens);
+ response.insert("IdToken", QLatin1String("idtokenfromtest"));
+
+ QTest::newRow("stored response including id token, sufficient cached
scopes") <<
+ "web_server" <<
+ webServerData.toMap() <<
+ -1 <<
+ false << response << QVariantMap();
+
webServerData.setForceTokenRefresh(true);
QTest::newRow("force token refresh, without refresh token") <<
"web_server" <<
@@ -383,12 +395,14 @@
providedTokens.insert("AccessToken", "providedtokenfromtest");
providedTokens.insert("RefreshToken", "providedrefreshfromtest");
providedTokens.insert("ExpiresIn", 12345);
+ providedTokens.insert("ExtraFields", QVariantMap());
/* try providing tokens to be stored */
providedTokensWebServerData.m_data.insert("ProvidedTokens",
providedTokens);
QVariantMap storedTokensForKey;
storedTokensForKey.insert("Token", providedTokens.value("AccessToken"));
storedTokensForKey.insert("refresh_token",
providedTokens.value("RefreshToken"));
+ storedTokensForKey.insert("ExtraFields",
providedTokens.value("ExtraFields"));
QVariantMap storedTokens;
storedTokens.insert(providedTokensWebServerData.ClientId(),
storedTokensForKey);
QVariantMap stored;
@@ -398,6 +412,18 @@
providedTokensWebServerData.toMap() <<
-1 <<
false << providedTokens << stored;
+
+ /* try providing tokens to be stored and include an openid token */
+ providedTokens.insert("IdToken", "providedidtokenfromtest");
+ providedTokensWebServerData.m_data.insert("ProvidedTokens",
providedTokens);
+ storedTokensForKey.insert("id_token", providedTokens.value("IdToken"));
+ storedTokens.insert(providedTokensWebServerData.ClientId(),
storedTokensForKey);
+ stored.insert("Tokens", storedTokens);
+ QTest::newRow("provided tokens with openid token") <<
+ "web_server" <<
+ providedTokensWebServerData.toMap() <<
+ -1 <<
+ false << providedTokens << stored;
}
void OAuth2PluginTest::testPluginProcess()
@@ -497,6 +523,22 @@
-1 <<
true << QVariantMap() << QVariantMap();
+ QTest::newRow("ui-request, User-Agent") <<
+ "PLAINTEXT" <<
+ QVariantMap {
+ { "RequestEndpoint", "https://localhost/oauth/request_token" },
+ { "TokenEndpoint", "https://localhost/oauth/access_token" },
+ { "AuthorizationEndpoint", "https://localhost/oauth/authorize" },
+ { "Callback", "https://localhost/connect/login_success.html" },
+ { "ConsumerKey", "104660106251471" },
+ { "ConsumerSecret", "fa28f40b5a1f8c1d5628963d880636fbkjkjkj" },
+ { "UserAgent", "PhotoTeleport/1.0" },
+ } <<
+ int(200) << "text/plain" <<
+ "oauth_token=HiThere&oauth_token_secret=BigSecret" <<
+ -1 <<
+ true << QVariantMap() << QVariantMap();
+
/* Now store some tokens and test the responses */
hmacSha1Data.m_data.insert("UiPolicy", NoUserInteractionPolicy);
QVariantMap tokens; // ConsumerKey to Token map
@@ -678,6 +720,11 @@
QTRY_COMPARE(userActionRequired.count(), uiExpected ? 1 : 0);
QTRY_COMPARE(error.count(), errorCode < 0 ? 0 : 1);
+ /* Check the user agent */
+ const QNetworkRequest &req = nam->m_lastRequest;
+ QVariant expectedUserAgent = sessionData.value("UserAgent");
+ QCOMPARE(req.header(QNetworkRequest::UserAgentHeader), expectedUserAgent);
+
if (errorCode < 0) {
QCOMPARE(error.count(), 0);
@@ -789,6 +836,47 @@
QCOMPARE(storedClientData["Scopes"].toStringList(), scopes);
store.clear();
+ //valid data with openid token
+
info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html#access_token=testtoken.&id_token=idtesttoken&expires_in=4776&state=%1").
+ arg(state));
+ m_testPlugin->userActionFinished(info);
+ QTRY_COMPARE(resultSpy.count(), 1);
+ response = resultSpy.at(0).at(0).value<SessionData>();
+ result = response.data<OAuth2PluginTokenData>();
+ QCOMPARE(result.AccessToken(), QString("testtoken."));
+ QCOMPARE(result.IdToken(), QString("idtesttoken"));
+ QCOMPARE(result.ExpiresIn(), 4776);
+ QCOMPARE(result.Scope(), QStringList() << "scope1" << "scope2");
+ resultSpy.clear();
+ QTRY_COMPARE(store.count(), 1);
+ storedData = store.at(0).at(0).value<SessionData>();
+ storedTokenData = storedData.data<OAuth2TokenData>().Tokens();
+ storedClientData = storedTokenData.value(data.ClientId()).toMap();
+ QVERIFY(!storedClientData.isEmpty());
+ QCOMPARE(storedClientData["Scopes"].toStringList(), scopes);
+ store.clear();
+
+ //valid data with openid token, and refresh token
+
info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html#access_token=testtoken.&id_token=idtesttoken&refresh_token=testrefreshtoken&expires_in=4776&state=%1").
+ arg(state));
+ m_testPlugin->userActionFinished(info);
+ QTRY_COMPARE(resultSpy.count(), 1);
+ response = resultSpy.at(0).at(0).value<SessionData>();
+ result = response.data<OAuth2PluginTokenData>();
+ QCOMPARE(result.AccessToken(), QString("testtoken."));
+ QCOMPARE(result.IdToken(), QString("idtesttoken"));
+ QCOMPARE(result.RefreshToken(), QString("testrefreshtoken"));
+ QCOMPARE(result.ExpiresIn(), 4776);
+ QCOMPARE(result.Scope(), QStringList() << "scope1" << "scope2");
+ resultSpy.clear();
+ QTRY_COMPARE(store.count(), 1);
+ storedData = store.at(0).at(0).value<SessionData>();
+ storedTokenData = storedData.data<OAuth2TokenData>().Tokens();
+ storedClientData = storedTokenData.value(data.ClientId()).toMap();
+ QVERIFY(!storedClientData.isEmpty());
+ QCOMPARE(storedClientData["Scopes"].toStringList(), scopes);
+ store.clear();
+
//valid data, got scopes
info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html#access_token=testtoken.&expires_in=4776&state=%1&scope=scope2").
arg(state));
@@ -802,6 +890,25 @@
resultSpy.clear();
store.clear();
+ //valid data, with extra
+
info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html#"
+ "access_token=testtoken.&expires_in=4776&"
+ "state=%1&scope=scope2&user_id=987").
+ arg(state));
+ m_testPlugin->userActionFinished(info);
+ QTRY_COMPARE(resultSpy.count(), 1);
+ response = resultSpy.at(0).at(0).value<SessionData>();
+ result = response.data<OAuth2PluginTokenData>();
+ QCOMPARE(result.AccessToken(), QString("testtoken."));
+ QCOMPARE(result.ExpiresIn(), 4776);
+ QCOMPARE(result.Scope(), QStringList() << "scope2");
+ QVariantMap expectedExtraData {
+ { "user_id", "987" },
+ };
+ QCOMPARE(result.ExtraFields(), expectedExtraData);
+ resultSpy.clear();
+ store.clear();
+
//valid data
info.setUrlResponse(QString("http://www.facebook.com/connect/login_success.html"
"#state=%1&access_token=testtoken.").
@@ -942,6 +1049,7 @@
response.insert("ExpiresIn", int(3600));
response.insert("RefreshToken", QString());
response.insert("Scope", QStringList() << "one" << "two");
+ response.insert("ExtraFields", QVariantMap());
QTest::newRow("reply code, valid token, wrong state ignored") <<
"http://localhost/resp.html?code=c0d3&$wrongstate" <<
int(-1) <<
@@ -959,6 +1067,7 @@
response.insert("ExpiresIn", int(3600));
response.insert("RefreshToken", QString());
response.insert("Scope", QStringList() << "one" << "two" << "three");
+ response.insert("ExtraFields", QVariantMap());
QTest::newRow("reply code, valid token, no scope") <<
"http://localhost/resp.html?code=c0d3&$state" <<
int(-1) <<
@@ -975,6 +1084,7 @@
response.insert("ExpiresIn", int(3600));
response.insert("RefreshToken", QString());
response.insert("Scope", QStringList());
+ response.insert("ExtraFields", QVariantMap());
QTest::newRow("reply code, valid token, empty scope") <<
"http://localhost/resp.html?code=c0d3&$state" <<
int(-1) <<
@@ -991,6 +1101,7 @@
response.insert("ExpiresIn", int(3600));
response.insert("RefreshToken", QString());
response.insert("Scope", QStringList() << "one" << "two");
+ response.insert("ExtraFields", QVariantMap());
QTest::newRow("reply code, valid token, other scope") <<
"http://localhost/resp.html?code=c0d3&$state" <<
int(-1) <<
@@ -1004,6 +1115,72 @@
response;
response.clear();
+ response.insert("AccessToken", "t0k3n");
+ response.insert("IdToken", "t0k3n2");
+ response.insert("ExpiresIn", int(3600));
+ response.insert("RefreshToken", QString());
+ response.insert("Scope", QStringList() << "one" << "two");
+ response.insert("ExtraFields", QVariantMap());
+ QTest::newRow("reply code, valid token, openid token, other scope") <<
+ "http://localhost/resp.html?code=c0d3&$state" <<
+ int(-1) <<
+ "https://localhost/access_token" <<
+
"grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html"
<<
+ false <<
+ int(200) <<
+ "application/json" <<
+ "{ \"access_token\":\"t0k3n\", \"id_token\":\"t0k3n2\",
\"expires_in\": 3600, "
+ "\"scope\": \"one two\" }" <<
+ response;
+
+ response = {
+ { "AccessToken", "t0k3n" },
+ { "ExpiresIn", int(3600) },
+ { "RefreshToken", QString() },
+ { "Scope", QStringList { "one" } },
+ { "ExtraFields", QVariantMap {
+ { "userId", "345" },
+ { "verified", true },
+ }
+ },
+ };
+ QTest::newRow("reply code, valid token, extra data") <<
+ "http://localhost/resp.html?code=c0d3&$state" <<
+ int(-1) <<
+ "https://localhost/access_token" <<
+
"grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html"
<<
+ false <<
+ int(200) <<
+ "application/json" <<
+ "{ \"access_token\":\"t0k3n\", \"expires_in\": 3600, "
+ "\"scope\": \"one\", \"userId\": \"345\", \"verified\": true }" <<
+ response;
+
+ response = {
+ { "AccessToken", "t0k3n" },
+ { "IdToken", "t0k3n2" },
+ { "ExpiresIn", int(3600) },
+ { "RefreshToken", QString() },
+ { "Scope", QStringList { "one" } },
+ { "ExtraFields", QVariantMap {
+ { "userId", "345" },
+ { "verified", true },
+ }
+ },
+ };
+ QTest::newRow("reply code, valid token, openid token, extra data") <<
+ "http://localhost/resp.html?code=c0d3&$state" <<
+ int(-1) <<
+ "https://localhost/access_token" <<
+
"grant_type=authorization_code&code=c0d3&redirect_uri=http://localhost/resp.html"
<<
+ false <<
+ int(200) <<
+ "application/json" <<
+ "{ \"access_token\":\"t0k3n\", \"id_token\":\"t0k3n2\",
\"expires_in\": 3600, "
+ "\"scope\": \"one\", \"userId\": \"345\", \"verified\": true }" <<
+ response;
+
+ response.clear();
QTest::newRow("reply code, facebook, no token") <<
"http://localhost/resp.html?code=c0d3&$state" <<
int(Error::NotAuthorized) <<
@@ -1020,6 +1197,7 @@
response.insert("ExpiresIn", int(3600));
response.insert("RefreshToken", QString());
response.insert("Scope", QStringList() << "one" << "two" << "three");
+ response.insert("ExtraFields", QVariantMap());
QTest::newRow("reply code, facebook, valid token") <<
"http://localhost/resp.html?code=c0d3&$state" <<
int(-1) <<
@@ -1036,6 +1214,7 @@
response.insert("ExpiresIn", int(3600));
response.insert("RefreshToken", QString());
response.insert("Scope", QStringList() << "one" << "two" << "three");
+ response.insert("ExtraFields", QVariantMap());
QTest::newRow("username-password, valid token") <<
"http://localhost/resp.html?username=us3r&password=s3cr3t" <<
int(-1) <<
@@ -1052,6 +1231,7 @@
response.insert("ExpiresIn", int(3600));
response.insert("RefreshToken", QString());
response.insert("Scope", QStringList() << "one" << "two" << "three");
+ response.insert("ExtraFields", QVariantMap());
QTest::newRow("assertion, valid token") <<
"http://localhost/resp.html?assertion_type=http://oauth.net/token/1.0"
"&assertion=oauth1t0k3n" <<
@@ -1069,6 +1249,7 @@
response.insert("ExpiresIn", int(3600));
response.insert("RefreshToken", QString());
response.insert("Scope", QStringList() << "one" << "two" << "three");
+ response.insert("ExtraFields", QVariantMap());
QTest::newRow("username-password, valid token, wrong content type") <<
"http://localhost/resp.html?username=us3r&password=s3cr3t" <<
int(-1) <<
@@ -1480,11 +1661,13 @@
response.insert("ExpiresIn", 3600);
response.insert("RefreshToken", QString());
response.insert("Scope", QStringList());
+ response.insert("ExtraFields", QVariantMap());
QTest::newRow("expired access token") << data.toMap() << response;
token.insert("timestamp", QDateTime::currentDateTime().toTime_t());
token.insert("Expiry", 50000);
+ token.insert("ExtraFields", QVariantMap());
tokens.insert(data.ClientId(), QVariant::fromValue(token));
data.m_data.insert("Tokens", tokens);
data.setForceTokenRefresh(true);
@@ -1749,6 +1932,142 @@
delete nam;
}
+void OAuth2PluginTest::testTokenQuery_data()
+{
+ QTest::addColumn<QVariantMap>("sessionData");
+ QTest::addColumn<QString>("expectedTokenUrl");
+ QTest::addColumn<QString>("expectedTokenData");
+
+ QString fixedData =
+ QStringLiteral("grant_type=authorization_code&code=c0d3&"
+ "redirect_uri=http://localhost/resp.html&"
+ "client_id=104660106251471");
+
+ QTest::newRow("no query") <<
+ QVariantMap {
+ { "Host", "localhost" },
+ { "TokenPath", "access_token" },
+ } <<
+ "https://localhost/access_token" <<
+ fixedData;
+
+ QTest::newRow("with query") <<
+ QVariantMap {
+ { "Host", "localhost" },
+ { "TokenPath", "access_token" },
+ { "TokenQuery", "one=1&bool=false" },
+ } <<
+ "https://localhost/access_token" <<
+ QString("one=1&bool=false&") + fixedData;
+
+ QTest::newRow("token host, no query") <<
+ QVariantMap {
+ { "AuthHost", "localhost" },
+ { "TokenHost", "localhost" },
+ { "TokenPath", "access_token" },
+ } <<
+ "https://localhost/access_token" <<
+ fixedData;
+
+ QTest::newRow("token host, with query") <<
+ QVariantMap {
+ { "AuthHost", "localhost" },
+ { "TokenHost", "localhost" },
+ { "TokenPath", "access_token" },
+ { "TokenQuery", "one=1&bool=false" },
+ } <<
+ "https://localhost/access_token" <<
+ QString("one=1&bool=false&") + fixedData;
+}
+
+void OAuth2PluginTest::testTokenQuery()
+{
+ QFETCH(QVariantMap, sessionData);
+ QFETCH(QString, expectedTokenUrl);
+ QFETCH(QString, expectedTokenData);
+
+ SignOn::UiSessionData info;
+ OAuth2PluginData data(sessionData);
+ data.setAuthPath("authorize");
+ data.setClientId("104660106251471");
+ data.setRedirectUri("http://localhost/resp.html");
+
+ QSignalSpy result(m_testPlugin, SIGNAL(result(const
SignOn::SessionData&)));
+ QSignalSpy error(m_testPlugin, SIGNAL(error(const SignOn::Error &)));
+ QSignalSpy userActionRequired(m_testPlugin,
+ SIGNAL(userActionRequired(const
SignOn::UiSessionData&)));
+
+ QScopedPointer<TestNetworkAccessManager> nam(new TestNetworkAccessManager);
+ m_testPlugin->m_networkAccessManager = nam.data();
+ TestNetworkReply *reply = new TestNetworkReply(this);
+ reply->setStatusCode(200);
+ reply->setContentType("application/json");
+ reply->setContent("{ \"access_token\":\"t0k3n\", \"expires_in\": 3600 }");
+ nam->setNextReply(reply);
+
+ m_testPlugin->process(data, QString("web_server"));
+ QTRY_COMPARE(userActionRequired.count(), 1);
+ QString state = parseState(userActionRequired);
+
+ info.setUrlResponse("http://localhost/resp.html?code=c0d3&state=" + state);
+ m_testPlugin->userActionFinished(info);
+
+ QTRY_COMPARE(result.count(), 1);
+ QCOMPARE(error.count(), 0);
+ QCOMPARE(nam->m_lastRequest.url(), QUrl(expectedTokenUrl));
+ QCOMPARE(nam->m_lastRequestData, expectedTokenData.toUtf8());
+}
+
+void OAuth2PluginTest::testOAuth2AuthRequestUri_data()
+{
+ QTest::addColumn<QString>("mechanism");
+ QTest::addColumn<QVariantMap>("sessionData");
+ QTest::addColumn<QString>("expectedUri");
+
+ OAuth2PluginData sessionData;
+ sessionData.setHost("localhost");
+ sessionData.setAuthPath("authorize");
+ sessionData.setClientId("104660106251471");
+ sessionData.setClientSecret("fa28f40b5a1f8c1d5628963d880636fbkjkjkj");
+ sessionData.setRedirectUri("http://localhost/connect/login_success.html");
+ sessionData.setDisableStateParameter(true);
+
+ QTest::newRow("no scopes") <<
+ "user_agent" <<
+ sessionData.toMap() <<
+ "https://localhost/authorize?client_id=104660106251471&"
+ "redirect_uri=http%3A%2F%2Flocalhost%2Fconnect%2Flogin_success.html";
+
+ sessionData.setHost("www.example.com");
+ sessionData.setTokenPath("access_token");
+ sessionData.setClientId("104660106251471");
+ sessionData.setClientSecret("fa28f40b5a1f8c1d5628963d880636fbkjkjkj");
+ sessionData.setRedirectUri("http://localhost/connect/login_success.html");
+ sessionData.setScope(QStringList() << "http://scope1" << "http://scope2");
+
+ QTest::newRow("with scopes") <<
+ "web_server" <<
+ sessionData.toMap() <<
+ "https://www.example.com/authorize?client_id=104660106251471&"
+ "redirect_uri=http%3A%2F%2Flocalhost%2Fconnect%2Flogin_success.html&"
+ "scope=http%3A%2F%2Fscope1 http%3A%2F%2Fscope2";
+}
+
+void OAuth2PluginTest::testOAuth2AuthRequestUri()
+{
+ QFETCH(QString, mechanism);
+ QFETCH(QVariantMap, sessionData);
+ QFETCH(QString, expectedUri);
+
+ QSignalSpy userActionRequired(m_testPlugin,
+ SIGNAL(userActionRequired(const
SignOn::UiSessionData&)));
+
+ m_testPlugin->process(sessionData, mechanism);
+ QCOMPARE(userActionRequired.count(), 1);
+ UiSessionData uiRequest =
userActionRequired.at(0).at(0).value<UiSessionData>();
+ QCOMPARE(uiRequest.OpenUrl(), expectedUri);
+}
+
//end test cases
QTEST_MAIN(OAuth2PluginTest)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/tests/oauth2plugintest.h
new/signon-plugin-oauth2-VERSION_0.25/tests/oauth2plugintest.h
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/tests/oauth2plugintest.h
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/tests/oauth2plugintest.h
2020-11-10 20:43:33.000000000 +0100
@@ -67,6 +67,10 @@
void testClientAuthentication();
void testTokenPath_data();
void testTokenPath();
+ void testTokenQuery_data();
+ void testTokenQuery();
+ void testOAuth2AuthRequestUri_data();
+ void testOAuth2AuthRequestUri();
private:
Plugin *m_testPlugin;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/tests/tests.pro
new/signon-plugin-oauth2-VERSION_0.25/tests/tests.pro
---
old/signon-plugin-oauth2-VERSION_0.24-2dd9ba521a0dd4277c4bf6970a7f4e3894fd85ae/tests/tests.pro
2016-06-02 11:44:21.000000000 +0200
+++ new/signon-plugin-oauth2-VERSION_0.25/tests/tests.pro 2020-11-10
20:43:33.000000000 +0100
@@ -22,10 +22,8 @@
$${TOP_SRC_DIR}/src/plugin.h \
oauth2plugintest.h
INCLUDEPATH += . \
- $${TOP_SRC_DIR}/src \
- /usr/include/signon-qt
+ $${TOP_SRC_DIR}/src
PKGCONFIG += \
- libsignon-qt5 \
signon-plugins