diff --git a/changelog/unreleased/11729 b/changelog/unreleased/11729 new file mode 100644 index 00000000000..f3e6d4b5e05 --- /dev/null +++ b/changelog/unreleased/11729 @@ -0,0 +1,5 @@ +Enhancement: Support for prompt_values_supported in openid-configuration + +We implemnted support for idp's to specify the supported prompt values. + +https://github.com/owncloud/client/pull/11729 diff --git a/src/common/utility.h b/src/common/utility.h index 7650eb7d86d..9a7633e3039 100644 --- a/src/common/utility.h +++ b/src/common/utility.h @@ -240,7 +240,10 @@ OCSYNC_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcUtility) template E stringToEnum(const char *key) { - return static_cast(QMetaEnum::fromType().keyToValue(key)); + bool ok; + auto out = static_cast(QMetaEnum::fromType().keyToValue(key, &ok)); + Q_ASSERT(ok); + return out; } template @@ -252,7 +255,7 @@ OCSYNC_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcUtility) template QString enumToString(E value) { - return QString::fromUtf8(QMetaEnum::fromType().valueToKeys(value)); + return QString::fromUtf8(QMetaEnum::fromType().valueToKeys(static_cast(value))); } template diff --git a/src/libsync/creds/oauth.cpp b/src/libsync/creds/oauth.cpp index 3ea137531ac..433a923d63f 100644 --- a/src/libsync/creds/oauth.cpp +++ b/src/libsync/creds/oauth.cpp @@ -44,7 +44,20 @@ Q_LOGGING_CATEGORY(lcOauth, "sync.credentials.oauth", QtInfoMsg) namespace { -static const QString wellKnownPathC = QStringLiteral("/.well-known/openid-configuration"); +const QString wellKnownPathC = QStringLiteral("/.well-known/openid-configuration"); + +const auto defaultOauthPromtValue() +{ + static const auto promptValue = [] { + OAuth::PromptValuesSupportedFlags out = OAuth::PromptValuesSupported::none; + // convert the legacy openIdConnectPrompt() to QFlags + for (const auto &x : Theme::instance()->openIdConnectPrompt().split(QLatin1Char(' '))) { + out |= Utility::stringToEnum(x); + } + return out; + }(); + return promptValue; +} QString renderHttpTemplate(const QString &title, const QString &content) { @@ -239,6 +252,7 @@ OAuth::OAuth(const QUrl &serverUrl, const QString &davUser, QNetworkAccessManage , _clientId(Theme::instance()->oauthClientId()) , _clientSecret(Theme::instance()->oauthClientSecret()) , _redirectUrl(Theme::instance()->oauthLocalhost()) + , _supportedPromtValues(defaultOauthPromtValue()) { } @@ -450,7 +464,7 @@ QUrl OAuth::authorisationLink() const {QStringLiteral("redirect_uri"), QStringLiteral("%1:%2").arg(_redirectUrl, QString::number(_server.serverPort()))}, {QStringLiteral("code_challenge"), QString::fromLatin1(code_challenge)}, {QStringLiteral("code_challenge_method"), QStringLiteral("S256")}, {QStringLiteral("scope"), QString::fromUtf8(QUrl::toPercentEncoding(Theme::instance()->openIdConnectScopes()))}, - {QStringLiteral("prompt"), QString::fromUtf8(QUrl::toPercentEncoding(Theme::instance()->openIdConnectPrompt()))}, + {QStringLiteral("prompt"), QString::fromUtf8(QUrl::toPercentEncoding(toString(_supportedPromtValues)))}, {QStringLiteral("state"), QString::fromUtf8(_state)}}; if (!_davUser.isEmpty()) { @@ -548,6 +562,16 @@ void OAuth::fetchWellKnown() } else { OC_ASSERT_X(false, qPrintable(QStringLiteral("Unsupported token_endpoint_auth_methods_supported: %1").arg(QDebug::toString(authMethods)))); } + const auto promtValuesSupported = data.value(QStringLiteral("prompt_values_supported")).toArray(); + if (!promtValuesSupported.isEmpty()) { + _supportedPromtValues = PromptValuesSupported::none; + for (const auto &x : promtValuesSupported) { + const auto flag = Utility::stringToEnum(x.toString()); + // only use flags present in Theme::instance()->openIdConnectPrompt() + if (flag & defaultOauthPromtValue()) + _supportedPromtValues |= flag; + } + } qCDebug(lcOauth) << "parsing .well-known reply successful, auth endpoint" << _authEndpoint << "and token endpoint" << _tokenEndpoint @@ -725,4 +749,15 @@ void AccountBasedOAuth::refreshAuthentication(const QString &refreshToken) }); } +QString OCC::toString(OAuth::PromptValuesSupportedFlags s) +{ + QStringList out; + for (auto k : {OAuth::PromptValuesSupported::consent, OAuth::PromptValuesSupported::select_account}) + if (s & k) { + out += Utility::enumToString(k); + } + return out.join(QLatin1Char(' ')); +} + + #include "oauth.moc" diff --git a/src/libsync/creds/oauth.h b/src/libsync/creds/oauth.h index 022840d4cb1..a37a95e90d0 100644 --- a/src/libsync/creds/oauth.h +++ b/src/libsync/creds/oauth.h @@ -55,9 +55,13 @@ class OWNCLOUDSYNC_EXPORT OAuth : public QObject public: enum Result { NotSupported, LoggedIn, Error, ErrorInsecureUrl }; Q_ENUM(Result) - enum class TokenEndpointAuthMethods { client_secret_basic, client_secret_post }; + enum class TokenEndpointAuthMethods : char { client_secret_basic, client_secret_post }; Q_ENUM(TokenEndpointAuthMethods) + enum class PromptValuesSupported : char { none = 0, consent = 1 << 0, select_account = 1 << 1 }; + Q_ENUM(PromptValuesSupported) + Q_DECLARE_FLAGS(PromptValuesSupportedFlags, PromptValuesSupported) + OAuth(const QUrl &serverUrl, const QString &davUser, QNetworkAccessManager *networkAccessManager, const QVariantMap &dynamicRegistrationData, QObject *parent); ~OAuth() override; @@ -117,6 +121,7 @@ class OWNCLOUDSYNC_EXPORT OAuth : public QObject QByteArray _state; TokenEndpointAuthMethods _endpointAuthMethod = TokenEndpointAuthMethods::client_secret_basic; + PromptValuesSupportedFlags _supportedPromtValues = {PromptValuesSupported::consent, PromptValuesSupported::select_account}; }; /** @@ -146,4 +151,6 @@ class OWNCLOUDSYNC_EXPORT AccountBasedOAuth : public OAuth AccountPtr _account; }; +QString OWNCLOUDSYNC_EXPORT toString(OAuth::PromptValuesSupportedFlags s); +Q_DECLARE_OPERATORS_FOR_FLAGS(OAuth::PromptValuesSupportedFlags) } // namespce OCC