mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-27 09:30:13 +03:00
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:
parent
704ba791fd
commit
a875b46a80
9 changed files with 242 additions and 26 deletions
|
@ -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
|
||||
)
|
||||
|
||||
|
|
104
src/creds/shibboleth/shibbolethconfigfile.cpp
Normal file
104
src/creds/shibboleth/shibbolethconfigfile.cpp
Normal 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
|
38
src/creds/shibboleth/shibbolethconfigfile.h
Normal file
38
src/creds/shibboleth/shibbolethconfigfile.h
Normal 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
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue