2017-11-25 22:19:25 +03:00
|
|
|
#include "webflowcredentials.h"
|
|
|
|
|
2017-11-28 22:06:27 +03:00
|
|
|
#include "creds/httpcredentials.h"
|
|
|
|
|
|
|
|
#include <QAuthenticator>
|
|
|
|
#include <QNetworkAccessManager>
|
|
|
|
#include <QNetworkReply>
|
|
|
|
#include <QPointer>
|
|
|
|
#include <QTimer>
|
2017-11-25 22:19:25 +03:00
|
|
|
#include <keychain.h>
|
2017-11-29 00:25:35 +03:00
|
|
|
#include <QDialog>
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
#include <QLabel>
|
2017-11-25 22:19:25 +03:00
|
|
|
|
|
|
|
#include "accessmanager.h"
|
|
|
|
#include "account.h"
|
|
|
|
#include "theme.h"
|
2017-11-29 00:25:35 +03:00
|
|
|
#include "wizard/webview.h"
|
|
|
|
#include "webflowcredentialsdialog.h"
|
2017-11-25 22:19:25 +03:00
|
|
|
|
|
|
|
using namespace QKeychain;
|
|
|
|
|
|
|
|
namespace OCC {
|
|
|
|
|
2017-11-28 22:06:27 +03:00
|
|
|
Q_LOGGING_CATEGORY(lcWebFlowCredentials, "sync.credentials.webflow", QtInfoMsg)
|
|
|
|
|
2017-11-25 22:19:25 +03:00
|
|
|
WebFlowCredentials::WebFlowCredentials()
|
2017-11-28 22:06:27 +03:00
|
|
|
: _ready(false),
|
|
|
|
_credentialsValid(false)
|
2017-11-25 22:19:25 +03:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
WebFlowCredentials::WebFlowCredentials(const QString &user, const QString &password, const QSslCertificate &certificate, const QSslKey &key)
|
|
|
|
: _user(user)
|
|
|
|
, _password(password)
|
|
|
|
, _clientSslKey(key)
|
|
|
|
, _clientSslCertificate(certificate)
|
|
|
|
, _ready(true)
|
2017-11-28 22:06:27 +03:00
|
|
|
, _credentialsValid(true)
|
2017-11-25 22:19:25 +03:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
QString WebFlowCredentials::authType() const {
|
|
|
|
return QString::fromLatin1("webflow");
|
|
|
|
}
|
|
|
|
|
|
|
|
QString WebFlowCredentials::user() const {
|
|
|
|
return _user;
|
|
|
|
}
|
|
|
|
|
2017-11-28 22:06:27 +03:00
|
|
|
QString WebFlowCredentials::password() const {
|
|
|
|
return _password;
|
|
|
|
}
|
|
|
|
|
2017-11-25 22:19:25 +03:00
|
|
|
QNetworkAccessManager *WebFlowCredentials::createQNAM() const {
|
2017-11-28 22:06:27 +03:00
|
|
|
qCInfo(lcWebFlowCredentials()) << "Get QNAM";
|
2017-11-25 22:19:25 +03:00
|
|
|
AccessManager *qnam = new AccessManager();
|
2017-11-28 22:06:27 +03:00
|
|
|
|
|
|
|
connect(qnam, &AccessManager::authenticationRequired, this, &WebFlowCredentials::slotAuthentication);
|
|
|
|
connect(qnam, &AccessManager::finished, this, &WebFlowCredentials::slotFinished);
|
|
|
|
|
2017-11-25 22:19:25 +03:00
|
|
|
return qnam;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WebFlowCredentials::ready() const {
|
2017-11-28 22:06:27 +03:00
|
|
|
return _ready;
|
2017-11-25 22:19:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void WebFlowCredentials::fetchFromKeychain() {
|
2017-11-28 22:06:27 +03:00
|
|
|
_wasFetched = true;
|
|
|
|
|
|
|
|
// Make sure we get the user fromt he config file
|
|
|
|
fetchUser();
|
2017-11-25 22:19:25 +03:00
|
|
|
|
2017-11-28 22:06:27 +03:00
|
|
|
if (ready()) {
|
|
|
|
emit fetched();
|
|
|
|
} else {
|
|
|
|
qCInfo(lcWebFlowCredentials()) << "Fetch from keyhchain!";
|
|
|
|
fetchFromKeychainHelper();
|
|
|
|
}
|
2017-11-25 22:19:25 +03:00
|
|
|
}
|
|
|
|
|
2017-11-28 22:06:27 +03:00
|
|
|
void WebFlowCredentials::askFromUser() {
|
2017-11-29 00:25:35 +03:00
|
|
|
_askDialog = new WebFlowCredentialsDialog();
|
|
|
|
|
|
|
|
QUrl url = _account->url();
|
|
|
|
QString path = url.path() + "/index.php/login/flow";
|
|
|
|
url.setPath(path);
|
|
|
|
_askDialog->setUrl(url);
|
|
|
|
|
|
|
|
QString msg = tr("You have been logged out of %1 as user %2. Please login again")
|
|
|
|
.arg(_account->displayName(), _user);
|
|
|
|
_askDialog->setInfo(msg);
|
|
|
|
|
|
|
|
_askDialog->show();
|
|
|
|
|
|
|
|
connect(_askDialog, &WebFlowCredentialsDialog::urlCatched, this, &WebFlowCredentials::slotAskFromUserCredentialsProvided);
|
|
|
|
|
2017-11-28 22:06:27 +03:00
|
|
|
qCWarning(lcWebFlowCredentials()) << "User needs to reauth!";
|
2017-11-25 22:19:25 +03:00
|
|
|
}
|
|
|
|
|
2017-11-29 00:25:35 +03:00
|
|
|
void WebFlowCredentials::slotAskFromUserCredentialsProvided(const QString &user, const QString &pass, const QString &host) {
|
|
|
|
if (_user != user) {
|
|
|
|
qCInfo(lcWebFlowCredentials()) << "Authed with the wrong user!";
|
|
|
|
|
|
|
|
QString msg = tr("Please login with the user: %1")
|
|
|
|
.arg(_user);
|
|
|
|
_askDialog->setError(msg);
|
|
|
|
|
|
|
|
QUrl url = _account->url();
|
|
|
|
QString path = url.path() + "/index.php/login/flow";
|
|
|
|
url.setPath(path);
|
|
|
|
_askDialog->setUrl(url);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-23 22:28:03 +03:00
|
|
|
qCInfo(lcWebFlowCredentials()) << "Obtained a new password";
|
2017-11-29 00:25:35 +03:00
|
|
|
|
|
|
|
_password = pass;
|
|
|
|
_ready = true;
|
|
|
|
_credentialsValid = true;
|
|
|
|
persist();
|
|
|
|
emit asked();
|
|
|
|
|
|
|
|
_askDialog->close();
|
|
|
|
delete _askDialog;
|
|
|
|
_askDialog = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-25 22:19:25 +03:00
|
|
|
bool WebFlowCredentials::stillValid(QNetworkReply *reply) {
|
2017-11-28 22:06:27 +03:00
|
|
|
qCWarning(lcWebFlowCredentials()) << "Still valid?";
|
|
|
|
qCWarning(lcWebFlowCredentials()) << reply->error();
|
|
|
|
qCWarning(lcWebFlowCredentials()) << reply->errorString();
|
|
|
|
return (reply->error() != QNetworkReply::AuthenticationRequiredError);
|
2017-11-25 22:19:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void WebFlowCredentials::persist() {
|
2017-11-28 22:06:27 +03:00
|
|
|
if (_user.isEmpty()) {
|
|
|
|
// We don't even have a user nothing to see here move along
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_account->setCredentialSetting("user", _user);
|
|
|
|
_account->wantsAccountSaved(_account);
|
|
|
|
|
2017-11-25 22:19:25 +03:00
|
|
|
//TODO: Add ssl cert and key storing
|
|
|
|
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
|
|
|
|
job->setInsecureFallback(false);
|
|
|
|
job->setKey(keychainKey(_account->url().toString(), _user, _account->id()));
|
|
|
|
job->setTextData(_password);
|
|
|
|
job->start();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebFlowCredentials::invalidateToken() {
|
2017-11-28 22:06:27 +03:00
|
|
|
// clear the session cookie.
|
|
|
|
_account->clearCookieJar();
|
|
|
|
|
|
|
|
// let QNAM forget about the password
|
|
|
|
// This needs to be done later in the event loop because we might be called (directly or
|
|
|
|
// indirectly) from QNetworkAccessManagerPrivate::authenticationRequired, which itself
|
|
|
|
// is a called from a BlockingQueuedConnection from the Qt HTTP thread. And clearing the
|
|
|
|
// cache needs to synchronize again with the HTTP thread.
|
|
|
|
QTimer::singleShot(0, _account, &Account::clearQNAMCache);
|
2017-11-25 22:19:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void WebFlowCredentials::forgetSensitiveData(){
|
2017-11-28 22:06:27 +03:00
|
|
|
_password = QString();
|
|
|
|
_ready = false;
|
|
|
|
|
|
|
|
fetchUser();
|
|
|
|
|
|
|
|
const QString kck = keychainKey(_account->url().toString(), _user, _account->id());
|
|
|
|
if (kck.isEmpty()) {
|
|
|
|
qCWarning(lcWebFlowCredentials()) << "InvalidateToken: User is empty, bailing out!";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
|
|
|
job->setInsecureFallback(false);
|
|
|
|
job->setKey(kck);
|
|
|
|
job->start();
|
|
|
|
|
|
|
|
invalidateToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebFlowCredentials::setAccount(Account *account) {
|
|
|
|
AbstractCredentials::setAccount(account);
|
|
|
|
if (_user.isEmpty()) {
|
|
|
|
fetchUser();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString WebFlowCredentials::fetchUser() {
|
|
|
|
_user = _account->credentialSetting("user").toString();
|
|
|
|
return _user;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebFlowCredentials::slotAuthentication(QNetworkReply *reply, QAuthenticator *authenticator) {
|
|
|
|
Q_UNUSED(reply);
|
|
|
|
|
|
|
|
if (!_ready) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_credentialsValid == false) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
qCWarning(lcWebFlowCredentials()) << "Requires authentication";
|
|
|
|
|
|
|
|
authenticator->setUser(_user);
|
|
|
|
authenticator->setPassword(_password);
|
|
|
|
_credentialsValid = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebFlowCredentials::slotFinished(QNetworkReply *reply) {
|
|
|
|
qCInfo(lcWebFlowCredentials()) << "request finished";
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebFlowCredentials::fetchFromKeychainHelper() {
|
|
|
|
const QString kck = keychainKey(
|
|
|
|
_account->url().toString(),
|
|
|
|
_user,
|
|
|
|
_account->id());
|
|
|
|
|
|
|
|
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
|
|
|
job->setInsecureFallback(false);
|
|
|
|
job->setKey(kck);
|
|
|
|
connect(job, &Job::finished, this, &WebFlowCredentials::slotReadPasswordJobDone);
|
|
|
|
job->start();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebFlowCredentials::slotReadPasswordJobDone(Job *incomingJob) {
|
|
|
|
QKeychain::ReadPasswordJob *job = static_cast<ReadPasswordJob *>(incomingJob);
|
|
|
|
QKeychain::Error error = job->error();
|
|
|
|
|
|
|
|
if (error == QKeychain::NoError) {
|
|
|
|
_password = job->textData();
|
|
|
|
_ready = true;
|
|
|
|
_credentialsValid = true;
|
|
|
|
} else {
|
|
|
|
_ready = false;
|
|
|
|
}
|
2017-11-25 22:19:25 +03:00
|
|
|
|
2017-11-28 22:06:27 +03:00
|
|
|
emit fetched();
|
2017-11-25 22:19:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|