Add cookie handling for Shibboleth credentials.

Which cookies are going to be stored are determined only when setting
up or modifying an account. Cookie handling allow us to avoid choosing
Identity Provider everytime when browser page appears.
This commit is contained in:
Krzesimir Nowak 2013-08-06 16:17:55 +02:00
parent 704ba791fd
commit a875b46a80
9 changed files with 242 additions and 26 deletions

View file

@ -90,6 +90,7 @@ set(libsync_SRCS
creds/shibboleth/shibbolethcookiejar.cpp
creds/shibboleth/shibbolethwebview.cpp
creds/shibboleth/shibbolethrefresher.cpp
creds/shibboleth/shibbolethconfigfile.cpp
creds/credentialscommon.cpp
)
@ -116,6 +117,7 @@ set(libsync_HEADERS
creds/shibboleth/shibbolethcookiejar.h
creds/shibboleth/shibbolethwebview.h
creds/shibboleth/shibbolethrefresher.h
creds/shibboleth/shibbolethconfigfile.h
creds/credentialscommon.h
)

View file

@ -0,0 +1,104 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <QDebug>
#include <QTextStream>
#include "creds/shibboleth/shibbolethconfigfile.h"
#include "creds/shibboleth/shibbolethcookiejar.h"
namespace Mirall
{
namespace
{
const char otherCookiesC[] = "otherCookies";
} // ns
void ShibbolethConfigFile::storeCookies(const QMap<QUrl, QList<QNetworkCookie> >& cookiesForUrl)
{
if (cookiesForUrl.isEmpty()) {
removeData(QString(), QString::fromLatin1(otherCookiesC));
} else {
QByteArray data;
QTextStream stream(&data);
Q_FOREACH (const QUrl& url, cookiesForUrl.keys()) {
const QList<QNetworkCookie>& cookies(cookiesForUrl[url]);
if (cookies.isEmpty()) {
continue;
}
stream << "URL: " << url.toString().toUtf8() << "\n";
qDebug() << "URL: " << url.toString().toUtf8();
Q_FOREACH (const QNetworkCookie& cookie, cookies) {
stream << cookie.toRawForm(QNetworkCookie::NameAndValueOnly) << "\n";
qDebug() << cookie.toRawForm(QNetworkCookie::NameAndValueOnly);
}
}
stream.flush();
const QByteArray encodedCookies(data.toBase64());
qDebug() << "Raw cookies:\n" << data;
qDebug() << "Encoded cookies: " << encodedCookies;
storeData(QString(), QString::fromLatin1(otherCookiesC), QVariant(encodedCookies));
}
}
ShibbolethCookieJar* ShibbolethConfigFile::createCookieJar() const
{
ShibbolethCookieJar* jar = new ShibbolethCookieJar();
const QVariant variant(retrieveData(QString(), QString::fromLatin1(otherCookiesC)));
if (variant.isValid()) {
QByteArray data(QByteArray::fromBase64(variant.toByteArray()));
QTextStream stream (&data);
const QString urlHeader(QString::fromLatin1("URL: "));
QUrl currentUrl;
QList<QNetworkCookie> currentCookies;
qDebug() << "Got valid cookies variant: " << data;
while (!stream.atEnd()) {
const QString line(stream.readLine());
qDebug() << line;
if (line.startsWith(urlHeader)) {
if (!currentUrl.isEmpty() && !currentCookies.isEmpty()) {
jar->setCookiesFromUrl(currentCookies, currentUrl);
currentCookies.clear();
currentUrl.clear();
}
currentUrl = QUrl(line.mid(5));
} else if (!currentUrl.isEmpty()) {
const int equalPos(line.indexOf('='));
currentCookies << QNetworkCookie(line.left(equalPos).toUtf8(), line.mid(equalPos + 1).toUtf8());
}
}
if (!currentUrl.isEmpty() && !currentCookies.isEmpty()) {
jar->setCookiesFromUrl(currentCookies, currentUrl);
}
}
return jar;
}
} // ns Mirall

View file

@ -0,0 +1,38 @@
/*
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef MIRALL_CREDS_SHIBBOLETH_CONFIG_FILE_H
#define MIRALL_CREDS_SHIBBOLETH_CONFIG_FILE_H
#include <QList>
#include <QMap>
#include <QNetworkCookie>
#include <QUrl>
#include "mirall/mirallconfigfile.h"
namespace Mirall
{
class ShibbolethCookieJar;
class ShibbolethConfigFile : public MirallConfigFile
{
public:
void storeCookies(const QMap<QUrl, QList<QNetworkCookie> >& cookies);
ShibbolethCookieJar* createCookieJar() const;
};
} // ns Mirall
#endif

View file

@ -11,6 +11,7 @@
* for more details.
*/
#include <QDebug>
#include <QNetworkCookie>
#include <QWebFrame>
#include <QWebPage>
@ -22,31 +23,56 @@
namespace Mirall
{
void ShibbolethWebView::setup(const QUrl& url, ShibbolethCookieJar* jar)
{
MirallAccessManager* nm = new MirallAccessManager(this);
QWebPage* page = new QWebPage(this);
jar->setParent(this);
connect (jar, SIGNAL (newCookiesForUrl (QList<QNetworkCookie>, QUrl)),
this, SLOT (onNewCookiesForUrl (QList<QNetworkCookie>, QUrl)));
nm->setCookieJar(jar);
page->setNetworkAccessManager(nm);
page->mainFrame ()->load (url);
this->setPage (page);
}
ShibbolethWebView::ShibbolethWebView(const QUrl& url, QWidget* parent)
: QWebView(parent)
{
MirallAccessManager* nm = new MirallAccessManager(this);
ShibbolethCookieJar* jar = new ShibbolethCookieJar(this);
QWebPage* page = new QWebPage(this);
connect (jar, SIGNAL (newCookiesForUrl (QList<QNetworkCookie>, QUrl)),
this, SLOT (onNewCookiesForUrl (QList<QNetworkCookie>, QUrl)));
nm->setCookieJar(jar);
page->setNetworkAccessManager(nm);
page->mainFrame ()->load (url);
this->setPage (page);
setup(url, new ShibbolethCookieJar(this));
}
void ShibbolethWebView::onNewCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& /*url*/)
ShibbolethWebView::ShibbolethWebView(const QUrl& url, ShibbolethCookieJar* jar, QWidget* parent)
: QWebView(parent)
{
setup(url, jar);
}
void ShibbolethWebView::onNewCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url)
{
QList<QNetworkCookie> otherCookies;
QNetworkCookie shibCookie;
Q_FOREACH (const QNetworkCookie& cookie, cookieList) {
if (cookie.name().startsWith ("_shibsession_")) {
Q_EMIT shibbolethCookieReceived (cookie);
return;
if (shibCookie.name().isEmpty()) {
shibCookie = cookie;
} else {
qWarning() << "Too many Shibboleth session cookies at once!";
}
} else {
otherCookies << cookie;
}
}
if (!otherCookies.isEmpty()) {
Q_EMIT otherCookiesReceived(otherCookies, url);
}
if (!shibCookie.name().isEmpty()) {
Q_EMIT shibbolethCookieReceived(shibCookie);
}
}
void ShibbolethWebView::hideEvent(QHideEvent* event)

View file

@ -23,22 +23,29 @@ class QUrl;
namespace Mirall
{
class ShibbolethCookieJar;
class ShibbolethWebView : public QWebView
{
Q_OBJECT
public:
ShibbolethWebView(const QUrl& url, QWidget* parent = 0);
ShibbolethWebView(const QUrl& url, ShibbolethCookieJar* jar, QWidget* parent = 0);
protected:
void hideEvent(QHideEvent* event);
Q_SIGNALS:
void shibbolethCookieReceived (const QNetworkCookie& cookie);
void shibbolethCookieReceived(const QNetworkCookie& cookie);
void viewHidden();
void otherCookiesReceived(const QList<QNetworkCookie>& cookieList, const QUrl& url);
private Q_SLOTS:
void onNewCookiesForUrl (const QList<QNetworkCookie>& cookieList, const QUrl& url);
void onNewCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
private:
void setup(const QUrl& url, ShibbolethCookieJar* jar);
};
} // ns Mirall

View file

@ -16,6 +16,7 @@
#include "creds/shibboleth/shibbolethaccessmanager.h"
#include "creds/shibboleth/shibbolethwebview.h"
#include "creds/shibboleth/shibbolethrefresher.h"
#include "creds/shibboleth/shibbolethconfigfile.h"
#include "creds/credentialscommon.h"
#include "mirall/owncloudinfo.h"
#include "mirall/mirallconfigfile.h"
@ -64,13 +65,15 @@ int shibboleth_redirect_callback(CSYNC* csync_ctx,
ShibbolethCredentials::ShibbolethCredentials()
: _shibCookie(),
_ready(false),
_browser(0)
_browser(0),
_otherCookies()
{}
ShibbolethCredentials::ShibbolethCredentials(const QNetworkCookie& cookie)
ShibbolethCredentials::ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies)
: _shibCookie(cookie),
_ready(true),
_browser(0)
_browser(0),
_otherCookies(otherCookies)
{}
void ShibbolethCredentials::syncContextPreInit(CSYNC* ctx)
@ -163,9 +166,9 @@ void ShibbolethCredentials::fetch()
if (_ready) {
Q_EMIT fetched();
} else {
MirallConfigFile cfg;
ShibbolethConfigFile cfg;
_browser = new ShibbolethWebView(QUrl(cfg.ownCloudUrl()));
_browser = new ShibbolethWebView(QUrl(cfg.ownCloudUrl()), cfg.createCookieJar());
connect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)),
this, SLOT(onShibbolethCookieReceived(QNetworkCookie)));
connect(_browser, SIGNAL(viewHidden()),
@ -176,7 +179,9 @@ void ShibbolethCredentials::fetch()
void ShibbolethCredentials::persistForUrl(const QString& /*url*/)
{
// nothing to do here, we don't store session cookies.
ShibbolethConfigFile cfg;
cfg.storeCookies(_otherCookies);
}
void ShibbolethCredentials::disposeBrowser()

View file

@ -14,7 +14,10 @@
#ifndef MIRALL_CREDS_SHIBBOLETH_CREDENTIALS_H
#define MIRALL_CREDS_SHIBBOLETH_CREDENTIALS_H
#include <QList>
#include <QMap>
#include <QNetworkCookie>
#include <QUrl>
#include "creds/abstractcredentials.h"
@ -29,7 +32,7 @@ Q_OBJECT
public:
ShibbolethCredentials();
ShibbolethCredentials(const QNetworkCookie& cookie);
ShibbolethCredentials(const QNetworkCookie& cookie, const QMap<QUrl, QList<QNetworkCookie> >& otherCookies);
void syncContextPreInit(CSYNC* ctx);
void syncContextPreStart(CSYNC* ctx);
@ -61,6 +64,7 @@ private:
QNetworkCookie _shibCookie;
bool _ready;
ShibbolethWebView* _browser;
QMap<QUrl, QList<QNetworkCookie> > _otherCookies;
};
} // ns Mirall

View file

@ -26,7 +26,8 @@ OwncloudShibbolethCredsPage::OwncloudShibbolethCredsPage()
: AbstractCredentialsWizardPage(),
_browser(0),
_cookie(),
_afterInitialSetup(false)
_afterInitialSetup(false),
_cookiesForUrl()
{}
void OwncloudShibbolethCredsPage::setupBrowser()
@ -39,6 +40,8 @@ void OwncloudShibbolethCredsPage::setupBrowser()
this, SLOT(slotShibbolethCookieReceived(QNetworkCookie)));
connect(_browser, SIGNAL(viewHidden()),
this, SLOT(slotViewHidden()));
connect(_browser, SIGNAL(otherCookiesReceived(QList<QNetworkCookie>, QUrl)),
this, SLOT(slotOtherCookiesReceived(QList<QNetworkCookie>, QUrl)));
_browser->show();
_browser->setFocus();
@ -69,11 +72,14 @@ void OwncloudShibbolethCredsPage::initializePage()
{
_afterInitialSetup = true;
_cookie = QNetworkCookie();
_cookiesForUrl.clear();
}
void OwncloudShibbolethCredsPage::disposeBrowser()
{
if (_browser) {
disconnect(_browser, SIGNAL(otherCookiesReceived(QList<QNetworkCookie>, QUrl)),
this, SLOT(slotOtherCookiesReceived(QList<QNetworkCookie>, QUrl)));
disconnect(_browser, SIGNAL(viewHidden()),
this, SLOT(slotViewHidden()));
disconnect(_browser, SIGNAL(shibbolethCookieReceived(QNetworkCookie)),
@ -96,7 +102,7 @@ void OwncloudShibbolethCredsPage::setConnected()
AbstractCredentials* OwncloudShibbolethCredsPage::getCredentials() const
{
return new ShibbolethCredentials(_cookie);
return new ShibbolethCredentials(_cookie, _cookiesForUrl);
}
void OwncloudShibbolethCredsPage::slotShibbolethCookieReceived(const QNetworkCookie& cookie)
@ -106,6 +112,25 @@ void OwncloudShibbolethCredsPage::slotShibbolethCookieReceived(const QNetworkCoo
emit connectToOCUrl(field("OCUrl").toString().simplified());
}
void OwncloudShibbolethCredsPage::slotOtherCookiesReceived(const QList<QNetworkCookie>& cookieList, const QUrl& url)
{
QList<QNetworkCookie>& cookies(_cookiesForUrl[url]);
QMap<QByteArray, QByteArray> uniqueCookies;
Q_FOREACH (const QNetworkCookie& c, cookieList) {
if (!c.isSessionCookie()) {
cookies << c;
}
}
Q_FOREACH (const QNetworkCookie& c, cookies) {
uniqueCookies[c.name()] = c.value();
}
cookies.clear();
Q_FOREACH (const QByteArray& name, uniqueCookies.keys()) {
cookies << QNetworkCookie(name, uniqueCookies[name]);
}
}
void OwncloudShibbolethCredsPage::slotViewHidden()
{
disposeBrowser();

View file

@ -14,7 +14,10 @@
#ifndef MIRALL_OWNCLOUD_SHIBBOLETH_CREDS_PAGE_H
#define MIRALL_OWNCLOUD_SHIBBOLETH_CREDS_PAGE_H
#include <QList>
#include <QMap>
#include <QNetworkCookie>
#include <QUrl>
#include "wizard/abstractcredswizardpage.h"
@ -42,6 +45,7 @@ public Q_SLOTS:
private Q_SLOTS:
void slotShibbolethCookieReceived(const QNetworkCookie& cookie);
void slotOtherCookiesReceived(const QList<QNetworkCookie>& cookieList, const QUrl& url);
void slotViewHidden();
private:
@ -51,6 +55,7 @@ private:
ShibbolethWebView* _browser;
QNetworkCookie _cookie;
bool _afterInitialSetup;
QMap<QUrl, QList<QNetworkCookie> > _cookiesForUrl;
};
} // ns Mirall