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:
Markus Goetz 2014-02-25 14:22:01 +01:00
Родитель d4fa06c4e1
Коммит c7e70533a0
5 изменённых файлов: 56 добавлений и 16 удалений

Просмотреть файл

@ -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();
}