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
 
 

Reply via email to