зеркало из https://github.com/nextcloud/desktop.git
Shibboleth: Detect also QNAM redirects
If a QNAM job (e.g. Quota or ETag job) gets redirected, we'll invalidate and then prompt to re-fetch the credentials from the user. (The keychain credentials will be wrong so they get deleted)
This commit is contained in:
Родитель
d4fa06c4e1
Коммит
c7e70533a0
|
@ -42,6 +42,10 @@ public:
|
|||
virtual void persist(Account *account) = 0;
|
||||
/** Invalidates auth token, or password for basic auth */
|
||||
virtual void invalidateToken(Account *account) = 0;
|
||||
virtual void invalidateAndFetch(Account *account) {
|
||||
invalidateToken(account);
|
||||
fetch(account);
|
||||
}
|
||||
|
||||
|
||||
static QString keychainKey(const QString &url, const QString &user);
|
||||
|
|
|
@ -31,14 +31,13 @@ QNetworkReply* ShibbolethAccessManager::createRequest(QNetworkAccessManager::Ope
|
|||
QNetworkCookieJar* jar(cookieJar());
|
||||
QUrl url(request.url());
|
||||
QList<QNetworkCookie> cookies;
|
||||
|
||||
Q_FOREACH(const QNetworkCookie& cookie, jar->cookiesForUrl(url)) {
|
||||
if (!cookie.name().startsWith("_shibsession_")) {
|
||||
cookies << cookie;
|
||||
}
|
||||
}
|
||||
|
||||
cookies << _cookie;
|
||||
cookies << _cookie; // this line and the line above replace all cookies with self and then add the shibboleth cookie (filtering the current shib cookie)
|
||||
jar->setCookiesFromUrl(cookies, url);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <QMutex>
|
||||
#include <QSettings>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#include "creds/shibbolethcredentials.h"
|
||||
#include "creds/shibboleth/shibbolethaccessmanager.h"
|
||||
|
@ -76,6 +77,7 @@ ShibbolethCredentials::ShibbolethCredentials()
|
|||
_url(),
|
||||
_shibCookie(),
|
||||
_ready(false),
|
||||
_stillValid(false),
|
||||
_browser(0),
|
||||
_otherCookies()
|
||||
{}
|
||||
|
@ -172,9 +174,22 @@ QNetworkAccessManager* ShibbolethCredentials::getQNAM() const
|
|||
|
||||
connect(this, SIGNAL(newCookie(QNetworkCookie)),
|
||||
qnam, SLOT(setCookie(QNetworkCookie)));
|
||||
connect(qnam, SIGNAL(finished(QNetworkReply*)),
|
||||
this, SLOT(slotReplyFinished(QNetworkReply*)));
|
||||
return qnam;
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::slotReplyFinished(QNetworkReply* r)
|
||||
{
|
||||
QVariant target = r->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||
if (target.isValid()) {
|
||||
_stillValid = false;
|
||||
qWarning() << Q_FUNC_INFO << "detected redirect, will open Login Window"; // will be done in NetworkJob's finished signal
|
||||
} else {
|
||||
//_stillValid = true; // gets set when reading from keychain or getting it from browser
|
||||
}
|
||||
}
|
||||
|
||||
bool ShibbolethCredentials::ready() const
|
||||
{
|
||||
return _ready;
|
||||
|
@ -201,7 +216,7 @@ void ShibbolethCredentials::fetch(Account *account)
|
|||
bool ShibbolethCredentials::stillValid(QNetworkReply *reply)
|
||||
{
|
||||
Q_UNUSED(reply)
|
||||
return true;
|
||||
return _stillValid;
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::persist(Account* account)
|
||||
|
@ -213,17 +228,20 @@ void ShibbolethCredentials::persist(Account* account)
|
|||
storeShibCookie(_shibCookie, account);
|
||||
}
|
||||
|
||||
// only used by Application::slotLogout(). Use invalidateAndFetch for normal usage
|
||||
void ShibbolethCredentials::invalidateToken(Account *account)
|
||||
{
|
||||
Q_UNUSED(account)
|
||||
_shibCookie = QNetworkCookie();
|
||||
storeShibCookie(_shibCookie, account);
|
||||
storeShibCookie(_shibCookie, account); // store/erase cookie
|
||||
|
||||
// ### access to ctx missing, but might not be required at all
|
||||
//csync_set_module_property(ctx, "session_key", "");
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::disposeBrowser()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
disconnect(_browser, SIGNAL(viewHidden()),
|
||||
this, SLOT(slotBrowserHidden()));
|
||||
disconnect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie, Account*)),
|
||||
|
@ -237,6 +255,7 @@ void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& coo
|
|||
{
|
||||
disposeBrowser();
|
||||
_ready = true;
|
||||
_stillValid = true;
|
||||
_shibCookie = cookie;
|
||||
storeShibCookie(_shibCookie, account);
|
||||
Q_EMIT newCookie(_shibCookie);
|
||||
|
@ -290,6 +309,7 @@ void ShibbolethCredentials::slotReadJobDone(QKeychain::Job *job)
|
|||
if (job->error() == QKeychain::NoError) {
|
||||
ReadPasswordJob *readJob = static_cast<ReadPasswordJob*>(job);
|
||||
delete readJob->settings();
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(readJob->textData().toUtf8());
|
||||
if (cookies.count() > 0) {
|
||||
_shibCookie = cookies.first();
|
||||
|
@ -297,20 +317,34 @@ void ShibbolethCredentials::slotReadJobDone(QKeychain::Job *job)
|
|||
job->setSettings(account->settingsWithGroup(Theme::instance()->appName()));
|
||||
|
||||
_ready = true;
|
||||
_stillValid = true;
|
||||
Q_EMIT newCookie(_shibCookie);
|
||||
Q_EMIT fetched();
|
||||
} else {
|
||||
ShibbolethConfigFile cfg;
|
||||
_browser = new ShibbolethWebView(account, cfg.createCookieJar());
|
||||
connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie, Account*)),
|
||||
this, SLOT(onShibbolethCookieReceived(QNetworkCookie, Account*)));
|
||||
connect(_browser, SIGNAL(viewHidden()),
|
||||
this, SLOT(slotBrowserHidden()));
|
||||
|
||||
_browser->show();
|
||||
showLoginWindow(account);
|
||||
}
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::showLoginWindow(Account* account)
|
||||
{
|
||||
if (_browser) {
|
||||
_browser->activateWindow();
|
||||
_browser->raise();
|
||||
// FIXME On OS X this does not raise properly
|
||||
return;
|
||||
}
|
||||
ShibbolethConfigFile cfg;
|
||||
_browser = new ShibbolethWebView(account, cfg.createCookieJar());
|
||||
connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie, Account*)),
|
||||
this, SLOT(onShibbolethCookieReceived(QNetworkCookie, Account*)));
|
||||
connect(_browser, SIGNAL(viewHidden()),
|
||||
this, SLOT(slotBrowserHidden()));
|
||||
// FIXME If the browser was hidden (e.g. user closed it) without us logging in, the logic gets stuck
|
||||
// and can only be unstuck by restarting the app or pressing "Sign in" (we should switch to offline but we don't)
|
||||
|
||||
_browser->show();
|
||||
}
|
||||
|
||||
void ShibbolethCredentials::storeShibCookie(const QNetworkCookie &cookie, Account *account)
|
||||
{
|
||||
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
|
||||
|
|
|
@ -52,6 +52,8 @@ public:
|
|||
|
||||
QNetworkCookie cookie() const;
|
||||
|
||||
void showLoginWindow(Account*);
|
||||
|
||||
public Q_SLOTS:
|
||||
void invalidateAndFetch(Account *account);
|
||||
|
||||
|
@ -61,6 +63,7 @@ private Q_SLOTS:
|
|||
void onFetched();
|
||||
void slotReadJobDone(QKeychain::Job*);
|
||||
void slotInvalidateAndFetchInvalidateDone(QKeychain::Job*);
|
||||
void slotReplyFinished(QNetworkReply*);
|
||||
|
||||
Q_SIGNALS:
|
||||
void newCookie(const QNetworkCookie& cookie);
|
||||
|
@ -74,6 +77,7 @@ private:
|
|||
|
||||
QNetworkCookie _shibCookie;
|
||||
bool _ready;
|
||||
bool _stillValid;
|
||||
ShibbolethWebView* _browser;
|
||||
QMap<QUrl, QList<QNetworkCookie> > _otherCookies;
|
||||
};
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include "creds/credentialsfactory.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include "creds/shibbolethcredentials.h"
|
||||
|
||||
Q_DECLARE_METATYPE(QTimer*)
|
||||
|
||||
|
@ -144,15 +145,13 @@ void AbstractNetworkJob::slotFinished()
|
|||
AbstractCredentials *creds = _account->credentials();
|
||||
if (!creds->stillValid(_reply) &&! _ignoreCredentialFailure
|
||||
&& _account->state() != Account::InvalidCredidential) {
|
||||
// invalidate & forget token/password
|
||||
_account->credentials()->invalidateToken(_account);
|
||||
|
||||
_account->setState(Account::InvalidCredidential);
|
||||
|
||||
// invalidate & forget token/password
|
||||
// but try to re-sign in.
|
||||
connect( creds, SIGNAL(fetched()),
|
||||
qApp, SLOT(slotCredentialsFetched()), Qt::UniqueConnection);
|
||||
creds->fetch(_account); // this triggers Application::runValidator when the credidentials are fetched
|
||||
creds->invalidateAndFetch(_account); // this triggers Application::runValidator when the credidentials are fetched
|
||||
}
|
||||
deleteLater();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче