OAuth2: Have a link to the browser in the owncloud UI

When the browser is open, ad a link in the ui to re-open
the browser.

Issue #5893
This commit is contained in:
Olivier Goffart 2017-07-13 11:27:02 +02:00 committed by Olivier Goffart
parent 6be122edc4
commit 5738110cb6
9 changed files with 50 additions and 13 deletions

View file

@ -30,6 +30,7 @@
#include "accountmanager.h" #include "accountmanager.h"
#include "owncloudsetupwizard.h" #include "owncloudsetupwizard.h"
#include "creds/abstractcredentials.h" #include "creds/abstractcredentials.h"
#include "creds/httpcredentialsgui.h"
#include "tooltipupdater.h" #include "tooltipupdater.h"
#include "filesystem.h" #include "filesystem.h"
@ -180,8 +181,8 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
ui->connectLabel->setText(tr("No account configured.")); ui->connectLabel->setText(tr("No account configured."));
connect(_accountState, SIGNAL(stateChanged(int)), SLOT(slotAccountStateChanged(int))); connect(_accountState, &AccountState::stateChanged, this, &AccountSettings::slotAccountStateChanged);
slotAccountStateChanged(_accountState->state()); slotAccountStateChanged();
connect(&_quotaInfo, SIGNAL(quotaUpdated(qint64, qint64)), connect(&_quotaInfo, SIGNAL(quotaUpdated(qint64, qint64)),
this, SLOT(slotUpdateQuota(qint64, qint64))); this, SLOT(slotUpdateQuota(qint64, qint64)));
@ -622,8 +623,9 @@ void AccountSettings::slotUpdateQuota(qint64 total, qint64 used)
} }
} }
void AccountSettings::slotAccountStateChanged(int state) void AccountSettings::slotAccountStateChanged()
{ {
int state = _accountState ? _accountState->state() : AccountState::Disconnected;
if (_accountState) { if (_accountState) {
ui->sslButton->updateAccountState(_accountState); ui->sslButton->updateAccountState(_accountState);
AccountPtr account = _accountState->account(); AccountPtr account = _accountState->account();
@ -654,6 +656,20 @@ void AccountSettings::slotAccountStateChanged(int state)
showConnectionLabel(tr("Server %1 is currently in maintenance mode.").arg(server)); showConnectionLabel(tr("Server %1 is currently in maintenance mode.").arg(server));
} else if (state == AccountState::SignedOut) { } else if (state == AccountState::SignedOut) {
showConnectionLabel(tr("Signed out from %1.").arg(serverWithUser)); showConnectionLabel(tr("Signed out from %1.").arg(serverWithUser));
} else if (state == AccountState::AskingCredentials) {
QUrl url;
if (auto cred = qobject_cast<HttpCredentialsGui *>(account->credentials())) {
connect(cred, &HttpCredentialsGui::authorisationLinkChanged,
this, &AccountSettings::slotAccountStateChanged, Qt::UniqueConnection);
url = cred->authorisationLink();
}
if (url.isValid()) {
showConnectionLabel(tr("Obtaining authorization from the browser. "
"<a href='%1'>Click here</a> to re-open the browser.")
.arg(url.toString(QUrl::FullyEncoded)));
} else {
showConnectionLabel(tr("Connecting to %1...").arg(serverWithUser));
}
} else { } else {
showConnectionLabel(tr("No connection to %1 at %2.") showConnectionLabel(tr("No connection to %1 at %2.")
.arg(Utility::escape(Theme::instance()->appNameGUI()), server), .arg(Utility::escape(Theme::instance()->appNameGUI()), server),

View file

@ -65,7 +65,7 @@ signals:
public slots: public slots:
void slotOpenOC(); void slotOpenOC();
void slotUpdateQuota(qint64, qint64); void slotUpdateQuota(qint64, qint64);
void slotAccountStateChanged(int state); void slotAccountStateChanged();
AccountState *accountsState() { return _accountState; } AccountState *accountsState() { return _accountState; }

View file

@ -133,6 +133,8 @@ QString AccountState::stateString(State state)
return tr("Network error"); return tr("Network error");
case ConfigurationError: case ConfigurationError:
return tr("Configuration error"); return tr("Configuration error");
case AskingCredentials:
return tr("Asking Credentials");
} }
return tr("Unknown account state"); return tr("Unknown account state");
} }
@ -307,7 +309,7 @@ void AccountState::slotInvalidCredentials()
account()->credentials()->invalidateToken(); account()->credentials()->invalidateToken();
account()->credentials()->askFromUser(); account()->credentials()->askFromUser();
setState(ConfigurationError); setState(AskingCredentials);
_waitingForNewCredentials = true; _waitingForNewCredentials = true;
} }

View file

@ -64,8 +64,11 @@ public:
/// again automatically. /// again automatically.
NetworkError, NetworkError,
/// An error like invalid credentials where retrying won't help. /// Server configuration error. (For example: unsupported version)
ConfigurationError ConfigurationError,
/// We are currently asking the user for credentials
AskingCredentials
}; };
/// The actual current connectivity status. /// The actual current connectivity status.

View file

@ -308,7 +308,8 @@ void Application::slotCheckConnection()
// Don't check if we're manually signed out or // Don't check if we're manually signed out or
// when the error is permanent. // when the error is permanent.
if (state != AccountState::SignedOut if (state != AccountState::SignedOut
&& state != AccountState::ConfigurationError) { && state != AccountState::ConfigurationError
&& state != AccountState::AskingCredentials) {
accountState->checkConnectivity(); accountState->checkConnectivity();
} }
} }

View file

@ -42,7 +42,10 @@ void HttpCredentialsGui::askFromUser()
_asyncAuth.reset(new OAuth(_account, this)); _asyncAuth.reset(new OAuth(_account, this));
connect(_asyncAuth.data(), &OAuth::result, connect(_asyncAuth.data(), &OAuth::result,
this, &HttpCredentialsGui::asyncAuthResult); this, &HttpCredentialsGui::asyncAuthResult);
connect(_asyncAuth.data(), &OAuth::destroyed,
this, &HttpCredentialsGui::authorisationLinkChanged);
_asyncAuth->start(); _asyncAuth->start();
emit authorisationLinkChanged();
} else if (reply->error() == QNetworkReply::AuthenticationRequiredError) { } else if (reply->error() == QNetworkReply::AuthenticationRequiredError) {
// Show the dialog // Show the dialog
// We will re-enter the event loop, so better wait the next iteration // We will re-enter the event loop, so better wait the next iteration

View file

@ -49,12 +49,21 @@ public:
* or call showDialog to ask the password * or call showDialog to ask the password
*/ */
Q_INVOKABLE void askFromUser() Q_DECL_OVERRIDE; Q_INVOKABLE void askFromUser() Q_DECL_OVERRIDE;
/**
* In case of oauth, return an URL to the link to open the browser.
* An invalid URL otherwise
*/
QUrl authorisationLink() const { return _asyncAuth ? _asyncAuth->authorisationLink() : QUrl(); }
static QString requestAppPasswordText(const Account *account); static QString requestAppPasswordText(const Account *account);
private slots: private slots:
void asyncAuthResult(OAuth::Result, const QString &user, const QString &accessToken, const QString &refreshToken); void asyncAuthResult(OAuth::Result, const QString &user, const QString &accessToken, const QString &refreshToken);
void showDialog(); void showDialog();
signals:
void authorisationLinkChanged();
private: private:
QScopedPointer<OAuth, QScopedPointerObjectDeleteLater<OAuth>> _asyncAuth; QScopedPointer<OAuth, QScopedPointerObjectDeleteLater<OAuth>> _asyncAuth;
}; };

View file

@ -131,17 +131,18 @@ void OAuth::start()
QTimer::singleShot(5 * 60 * 1000, this, [this] { result(Error); }); QTimer::singleShot(5 * 60 * 1000, this, [this] { result(Error); });
} }
QUrl OAuth::authorisationLink() const
bool OAuth::openBrowser()
{ {
Q_ASSERT(_server.isListening()); Q_ASSERT(_server.isListening());
auto url = QUrl(_account->url().toString() return QUrl(_account->url().toString()
+ QLatin1String("/index.php/apps/oauth2/authorize?response_type=code&client_id=") + QLatin1String("/index.php/apps/oauth2/authorize?response_type=code&client_id=")
+ Theme::instance()->oauthClientId() + Theme::instance()->oauthClientId()
+ QLatin1String("&redirect_uri=http://localhost:") + QString::number(_server.serverPort())); + QLatin1String("&redirect_uri=http://localhost:") + QString::number(_server.serverPort()));
}
bool OAuth::openBrowser()
if (!QDesktopServices::openUrl(url)) { {
if (!QDesktopServices::openUrl(authorisationLink())) {
// We cannot open the browser, then we claim we don't support OAuth. // We cannot open the browser, then we claim we don't support OAuth.
emit result(NotSupported, QString()); emit result(NotSupported, QString());
return false; return false;

View file

@ -15,6 +15,7 @@
#pragma once #pragma once
#include <QPointer> #include <QPointer>
#include <QTcpServer> #include <QTcpServer>
#include <QUrl>
namespace OCC { namespace OCC {
@ -53,6 +54,7 @@ public:
Q_ENUM(Result); Q_ENUM(Result);
void start(); void start();
bool openBrowser(); bool openBrowser();
QUrl authorisationLink() const;
signals: signals:
/** /**