Refresh Shibboleth cookie if it gets outdated during sync.

This commit is contained in:
Krzesimir Nowak 2013-08-05 17:31:52 +02:00
parent da370c8b36
commit f0b284eda7
5 changed files with 191 additions and 17 deletions

View file

@ -89,6 +89,7 @@ set(libsync_SRCS
creds/shibboleth/shibbolethaccessmanager.cpp
creds/shibboleth/shibbolethcookiejar.cpp
creds/shibboleth/shibbolethwebview.cpp
creds/shibboleth/shibbolethrefresher.cpp
)
set(libsync_HEADERS
@ -113,6 +114,7 @@ set(libsync_HEADERS
creds/shibboleth/shibbolethaccessmanager.h
creds/shibboleth/shibbolethcookiejar.h
creds/shibboleth/shibbolethwebview.h
creds/shibboleth/shibbolethrefresher.h
)
IF( INOTIFY_FOUND )

View file

@ -0,0 +1,52 @@
/*
* 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 <QEventLoop>
#include "creds/shibboleth/shibbolethrefresher.h"
#include "creds/shibbolethcredentials.h"
namespace Mirall
{
ShibbolethRefresher::ShibbolethRefresher(ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent)
: QObject(parent),
_creds(creds),
_csync_ctx(csync_ctx)
{}
void ShibbolethRefresher::refresh()
{
QEventLoop loop;
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
this, SLOT(onInvalidatedAndFetched(QByteArray)));
connect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
&loop, SLOT(quit()));
QMetaObject::invokeMethod(_creds, "invalidateAndFetch", Qt::QueuedConnection);
loop.exec();
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
&loop, SLOT(quit()));
}
void ShibbolethRefresher::onInvalidatedAndFetched(const QByteArray& cookies)
{
// "cookies" is const and its data() return const void*. We want just void*.
QByteArray myCookies(cookies);
disconnect(_creds, SIGNAL(invalidatedAndFetched(QByteArray)),
this, SLOT(onInvalidatedAndFetched(QByteArray)));
csync_set_module_property(_csync_ctx, "session_key", myCookies.data());
}
} // ns Mirall

View file

@ -0,0 +1,47 @@
/*
* 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_REFRESHER_H
#define MIRALL_CREDS_SHIBBOLETH_REFRESHER_H
#include <QObject>
#include <csync.h>
class QByteArray;
namespace Mirall
{
class ShibbolethCredentials;
class ShibbolethRefresher : public QObject
{
Q_OBJECT
public:
ShibbolethRefresher(ShibbolethCredentials* creds, CSYNC* csync_ctx, QObject* parent = 0);
void refresh();
private Q_SLOTS:
void onInvalidatedAndFetched(const QByteArray& cookieData);
private:
ShibbolethCredentials* _creds;
CSYNC* _csync_ctx;
};
} // ns Mirall
#endif

View file

@ -15,12 +15,52 @@
#include "creds/shibbolethcredentials.h"
#include "creds/shibboleth/shibbolethaccessmanager.h"
#include "creds/shibboleth/shibbolethwebview.h"
#include "creds/shibboleth/shibbolethrefresher.h"
#include "mirall/owncloudinfo.h"
#include "mirall/mirallconfigfile.h"
#include "mirall/csyncthread.h"
namespace Mirall
{
namespace
{
int shibboleth_redirect_callback(CSYNC* csync_ctx,
const char* uri)
{
if (!csync_ctx || !uri) {
return 1;
}
const QString qurl(QString::fromLatin1(uri));
QRegExp shibbolethyWords ("SAML|wayf");
shibbolethyWords.setCaseSensitivity (Qt::CaseInsensitive);
if (!qurl.contains(shibbolethyWords)) {
return 1;
}
QMutex mutex;
QMutexLocker locker(&mutex);
MirallConfigFile cfg;
ShibbolethCredentials* creds = dynamic_cast< ShibbolethCredentials* > (cfg.getCredentials());
if (!creds) {
qDebug() << "Not a Shibboleth creds instance!";
return 1;
}
ShibbolethRefresher refresher(creds, csync_ctx);
// blocks
refresher.refresh();
return 0;
}
} // ns
ShibbolethCredentials::ShibbolethCredentials()
: _shibCookie(),
_ready(false),
@ -33,29 +73,39 @@ ShibbolethCredentials::ShibbolethCredentials(const QNetworkCookie& cookie)
_browser(0)
{}
void ShibbolethCredentials::syncContextPreInit (CSYNC*)
void ShibbolethCredentials::syncContextPreInit(CSYNC*)
{}
QByteArray ShibbolethCredentials::prepareCookieData() const
{
QString cookiesAsString;
// TODO: This should not be a part of this method, but we don't
// have any way to get "session_key" module property from
// csync. Had we have it, then we could just append shibboleth
// cookies to the "session_key" value and set it in csync module.
QList<QNetworkCookie> cookies(ownCloudInfo::instance()->getLastAuthCookies());
cookies << _shibCookie;
// Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply
// when https://github.com/owncloud/core/pull/4042 is merged.
foreach(QNetworkCookie c, cookies) {
cookiesAsString += c.name();
cookiesAsString += '=';
cookiesAsString += c.value();
cookiesAsString += "; ";
}
return cookiesAsString.toLatin1();
}
void ShibbolethCredentials::syncContextPreStart (CSYNC* ctx)
{
QString cookiesAsString;
// TODO: This should not be a part of this method, but we don't
// have any way to get "session_key" module property from
// csync. Had we have it, then we could just append shibboleth
// cookies to the "session_key" value and set it in csync module.
QList<QNetworkCookie> cookies(ownCloudInfo::instance()->getLastAuthCookies());
typedef int (*csync_owncloud_redirect_callback_t)(CSYNC* ctx, const char* uri);
cookies << _shibCookie;
// Stuff cookies inside csync, then we can avoid the intermediate HTTP 401 reply
// when https://github.com/owncloud/core/pull/4042 is merged.
foreach(QNetworkCookie c, cookies) {
cookiesAsString += c.name();
cookiesAsString += '=';
cookiesAsString += c.value();
cookiesAsString += "; ";
}
csync_owncloud_redirect_callback_t cb = shibboleth_redirect_callback;
csync_set_module_property(ctx, "session_key", cookiesAsString.toLatin1().data());
csync_set_module_property(ctx, "session_key", prepareCookieData().data());
csync_set_module_property(ctx, "redirect_callback", &cb);
}
bool ShibbolethCredentials::changed(AbstractCredentials* credentials) const
@ -125,4 +175,20 @@ void ShibbolethCredentials::onShibbolethCookieReceived(const QNetworkCookie& coo
Q_EMIT fetched();
}
void ShibbolethCredentials::invalidateAndFetch()
{
_ready = false;
connect (this, SIGNAL(fetched()),
this, SLOT(onFetched()));
fetch();
}
void ShibbolethCredentials::onFetched()
{
disconnect (this, SIGNAL(fetched()),
this, SLOT(onFetched()));
Q_EMIT invalidatedAndFetched(prepareCookieData());
}
} // ns Mirall

View file

@ -42,13 +42,20 @@ public:
QNetworkCookie cookie() const;
public Q_SLOTS:
void invalidateAndFetch();
private Q_SLOTS:
void onShibbolethCookieReceived(const QNetworkCookie& cookie);
void onFetched();
Q_SIGNALS:
void newCookie(const QNetworkCookie& cookie);
void invalidatedAndFetched(const QByteArray& cookieData);
private:
QByteArray prepareCookieData() const;
QNetworkCookie _shibCookie;
bool _ready;
ShibbolethWebView* _browser;