362 lines
15 KiB
Diff
362 lines
15 KiB
Diff
From 61070476b491baa046c7c40722e0270a10d7d622 Mon Sep 17 00:00:00 2001
|
|
From: Ian Wadham <iandw.au@gmail.com>
|
|
Date: Fri, 10 Oct 2014 09:11:06 +1100
|
|
Subject: [PATCH 1/1] BUG: 337742 REVIEW: 120431. Fix and future-proof security
|
|
in Dr Konqi.
|
|
|
|
In July 2014, the bugs.kde.org database switched to v4.4.5 of Bugzilla
|
|
and cookies were no longer accepted, causing bug 337742. This patch uses
|
|
the new security system, based on tokens, and implements the future use
|
|
of passwords only, whenever Bugzilla changes to the announced v4.5.x. It
|
|
also avoids a crash in Dr K on Apple OS X when KCookieJar is not found.
|
|
|
|
Forward port of review 120431 to plasma-workspace.
|
|
|
|
REVIEW: 120876
|
|
---
|
|
drkonqi/bugzillaintegration/bugzillalib.cpp | 129 +++++++++++++++++----
|
|
drkonqi/bugzillaintegration/bugzillalib.h | 16 +++
|
|
.../reportassistantpages_bugzilla.cpp | 21 +++-
|
|
.../reportassistantpages_bugzilla.h | 2 +
|
|
4 files changed, 144 insertions(+), 24 deletions(-)
|
|
|
|
diff --git a/drkonqi/bugzillaintegration/bugzillalib.cpp b/drkonqi/bugzillaintegration/bugzillalib.cpp
|
|
index 8fd8399baab804a2a6ef839435c604edda90c1a5..54fca48a99146b3be78f4abe88a58d07ab416446 100644
|
|
--- a/drkonqi/bugzillaintegration/bugzillalib.cpp
|
|
+++ b/drkonqi/bugzillaintegration/bugzillalib.cpp
|
|
@@ -20,6 +20,7 @@
|
|
|
|
#include "bugzillalib.h"
|
|
|
|
+#include <QtCore/QtGlobal>
|
|
#include <QtCore/QTextStream>
|
|
#include <QtCore/QByteArray>
|
|
#include <QtCore/QString>
|
|
@@ -33,6 +34,7 @@
|
|
#include <KLocalizedString>
|
|
#include <QDebug>
|
|
|
|
+#define MAKE_BUGZILLA_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c))
|
|
|
|
static const char columns[] = "bug_severity,priority,bug_status,product,short_desc,resolution";
|
|
|
|
@@ -62,23 +64,110 @@ BugzillaManager::BugzillaManager(const QString &bugTrackerUrl, QObject *parent)
|
|
{
|
|
m_xmlRpcClient = new KXmlRpc::Client(QUrl(m_bugTrackerUrl + "xmlrpc.cgi"), this);
|
|
m_xmlRpcClient->setUserAgent(QLatin1String("DrKonqi"));
|
|
+ // Allow constructors for ReportInterface and assistant dialogs to finish.
|
|
+ // We do not want them to be racing the remote Bugzilla database.
|
|
+ QMetaObject::invokeMethod (this, "lookupVersion", Qt::QueuedConnection);
|
|
}
|
|
|
|
+// BEGIN Checks of Bugzilla software versions.
|
|
+void BugzillaManager::lookupVersion()
|
|
+{
|
|
+ QMap<QString, QVariant> args;
|
|
+ callBugzilla("Bugzilla.version", "version", args, SecurityDisabled);
|
|
+}
|
|
+
|
|
+void BugzillaManager::setFeaturesForVersion(const QString& version)
|
|
+{
|
|
+ // A procedure to change Dr Konqi behaviour automatically when Bugzilla
|
|
+ // software versions change.
|
|
+ //
|
|
+ // Changes should be added to Dr Konqi AHEAD of when the corresponding
|
|
+ // Bugzilla software changes are released into bugs.kde.org, so that
|
|
+ // Dr Konqi can continue to operate smoothly, without bug reports and a
|
|
+ // reactive KDE software release.
|
|
+ //
|
|
+ // If Bugzilla announces a change to its software that affects Dr Konqi,
|
|
+ // add executable code to implement the change automatically when the
|
|
+ // Bugzilla software version changes. It goes at the end of this procedure
|
|
+ // and elsewhere in this class (BugzillaManager) and/or other classes where
|
|
+ // the change should actually be implemented.
|
|
+
|
|
+ const int nVersionParts = 3;
|
|
+ QString seps = QLatin1String("[._-]");
|
|
+ QStringList digits = version.split(QRegExp(seps), QString::SkipEmptyParts);
|
|
+ while (digits.count() < nVersionParts) {
|
|
+ digits << QLatin1String("0");
|
|
+ }
|
|
+ if (digits.count() > nVersionParts) {
|
|
+ qWarning() << QString("Current Bugzilla version %1 has more than %2 parts. Check that this is not a problem.").arg(version).arg(nVersionParts);
|
|
+ }
|
|
+ int currentVersion = MAKE_BUGZILLA_VERSION(digits.at(0).toUInt(),
|
|
+ digits.at(1).toUInt(), digits.at(2).toUInt());
|
|
+
|
|
+ // Set the code(s) for historical versions of Bugzilla - before any change.
|
|
+ m_security = UseCookies; // Used to have cookies for update-security.
|
|
+
|
|
+ if (currentVersion >= MAKE_BUGZILLA_VERSION(4, 4, 3)) {
|
|
+ // Security method changes from cookies to tokens in v4.4.3.
|
|
+ m_security = UseTokens;
|
|
+ }
|
|
+ if (currentVersion >= MAKE_BUGZILLA_VERSION(4, 5, 0)) {
|
|
+ // Security method changes from tokens to password-only in v4.5.x.
|
|
+ m_security = UsePasswords;
|
|
+ }
|
|
+
|
|
+ qDebug() << "VERSION" << version << "SECURITY" << m_security;
|
|
+}
|
|
+// END Checks of Bugzilla software versions.
|
|
+
|
|
+// BEGIN Generic remote-procedure (RPC) call to Bugzilla
|
|
+void BugzillaManager::callBugzilla(const char* method, const char* id,
|
|
+ QMap<QString, QVariant>& args,
|
|
+ SecurityStatus security)
|
|
+{
|
|
+ if (security == SecurityEnabled) {
|
|
+ switch (m_security) {
|
|
+ case UseTokens:
|
|
+ qDebug() << method << id << "using token";
|
|
+ args.insert(QLatin1String("Bugzilla_token"), m_token);
|
|
+ break;
|
|
+ case UsePasswords:
|
|
+ qDebug() << method << id << "using username" << m_username;
|
|
+ args.insert(QLatin1String("Bugzilla_login"), m_username);
|
|
+ args.insert(QLatin1String("Bugzilla_password"), m_password);
|
|
+ break;
|
|
+ case UseCookies:
|
|
+ qDebug() << method << id << "using cookies";
|
|
+ // Some KDE process other than Dr Konqi should provide cookies.
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ m_xmlRpcClient->call(QLatin1String(method), args,
|
|
+ this, SLOT(callMessage(QList<QVariant>,QVariant)),
|
|
+ this, SLOT(callFault(int,QString,QVariant)),
|
|
+ QString::fromAscii(id));
|
|
+}
|
|
+// END Generic call to Bugzilla
|
|
+
|
|
//BEGIN Login methods
|
|
void BugzillaManager::tryLogin(const QString& username, const QString& password)
|
|
{
|
|
m_username = username;
|
|
+ if (m_security == UsePasswords) {
|
|
+ m_password = password;
|
|
+ }
|
|
m_logged = false;
|
|
|
|
QMap<QString, QVariant> args;
|
|
args.insert(QLatin1String("login"), username);
|
|
args.insert(QLatin1String("password"), password);
|
|
- args.insert(QLatin1String("remember"), false);
|
|
+ if (m_security == UseCookies) {
|
|
+ // Removed in Bugzilla 4.4.3 software, which no longer issues cookies.
|
|
+ args.insert(QLatin1String("remember"), false);
|
|
+ }
|
|
|
|
- m_xmlRpcClient->call(QLatin1String("User.login"), args,
|
|
- this, SLOT(callMessage(QList<QVariant>,QVariant)),
|
|
- this, SLOT(callFault(int,QString,QVariant)),
|
|
- QString::fromAscii("login"));
|
|
+ callBugzilla("User.login", "login", args, SecurityDisabled);
|
|
}
|
|
|
|
bool BugzillaManager::getLogged() const
|
|
@@ -147,10 +236,7 @@ void BugzillaManager::sendReport(const BugReport & report)
|
|
args.insert(QLatin1String("priority"), report.priority());
|
|
args.insert(QLatin1String("severity"), report.bugSeverity());
|
|
|
|
- m_xmlRpcClient->call(QLatin1String("Bug.create"), args,
|
|
- this, SLOT(callMessage(QList<QVariant>,QVariant)),
|
|
- this, SLOT(callFault(int,QString,QVariant)),
|
|
- QString::fromAscii("Bug.create"));
|
|
+ callBugzilla("Bug.create", "Bug.create", args, SecurityEnabled);
|
|
}
|
|
|
|
void BugzillaManager::attachTextToReport(const QString & text, const QString & filename,
|
|
@@ -166,10 +252,8 @@ void BugzillaManager::attachTextToReport(const QString & text, const QString & f
|
|
//data needs to be a QByteArray so that it is encoded in base64 (query.cpp:246)
|
|
args.insert(QLatin1String("data"), text.toUtf8());
|
|
|
|
- m_xmlRpcClient->call(QLatin1String("Bug.add_attachment"), args,
|
|
- this, SLOT(callMessage(QList<QVariant>,QVariant)),
|
|
- this, SLOT(callFault(int,QString,QVariant)),
|
|
- QString::fromAscii("Bug.add_attachment"));
|
|
+ callBugzilla("Bug.add_attachment", "Bug.add_attachment", args,
|
|
+ SecurityEnabled);
|
|
}
|
|
|
|
void BugzillaManager::addMeToCC(int bugId)
|
|
@@ -181,10 +265,7 @@ void BugzillaManager::addMeToCC(int bugId)
|
|
ccChanges.insert(QLatin1String("add"), QVariantList() << m_username);
|
|
args.insert(QLatin1String("cc"), ccChanges);
|
|
|
|
- m_xmlRpcClient->call(QLatin1String("Bug.update"), args,
|
|
- this, SLOT(callMessage(QList<QVariant>,QVariant)),
|
|
- this, SLOT(callFault(int,QString,QVariant)),
|
|
- QString::fromAscii("Bug.update.cc"));
|
|
+ callBugzilla("Bug.update", "Bug.update.cc", args, SecurityEnabled);
|
|
}
|
|
|
|
void BugzillaManager::fetchProductInfo(const QString & product)
|
|
@@ -199,10 +280,7 @@ void BugzillaManager::fetchProductInfo(const QString & product)
|
|
|
|
args.insert("include_fields", includeFields) ;
|
|
|
|
- m_xmlRpcClient->call(QLatin1String("Product.get"), args,
|
|
- this, SLOT(callMessage(QList<QVariant>,QVariant)),
|
|
- this, SLOT(callFault(int,QString,QVariant)),
|
|
- QString::fromAscii("Product.get.versions"));
|
|
+ callBugzilla("Product.get", "Product.get.versions", args, SecurityDisabled);
|
|
}
|
|
|
|
|
|
@@ -333,6 +411,10 @@ void BugzillaManager::callMessage(const QList<QVariant> & result, const QVariant
|
|
qDebug() << id << result;
|
|
|
|
if (id.toString() == QLatin1String("login")) {
|
|
+ if ((m_security == UseTokens) && (result.count() > 0)) {
|
|
+ QVariantMap map = result.at(0).toMap();
|
|
+ m_token = map.value(QLatin1String("token")).toString();
|
|
+ }
|
|
m_logged = true;
|
|
Q_EMIT loginFinished(true);
|
|
} else if (id.toString() == QLatin1String("Product.get.versions")) {
|
|
@@ -359,6 +441,11 @@ void BugzillaManager::callMessage(const QList<QVariant> & result, const QVariant
|
|
int bug_id = map.value(QLatin1String("id")).toInt();
|
|
Q_ASSERT(bug_id != 0);
|
|
Q_EMIT addMeToCCFinished(bug_id);
|
|
+ } else if (id.toString() == QLatin1String("version")) {
|
|
+ QVariantMap map = result.at(0).toMap();
|
|
+ QString bugzillaVersion = map.value(QLatin1String("version")).toString();
|
|
+ setFeaturesForVersion(bugzillaVersion);
|
|
+ Q_EMIT bugzillaVersionFound();
|
|
}
|
|
}
|
|
|
|
diff --git a/drkonqi/bugzillaintegration/bugzillalib.h b/drkonqi/bugzillaintegration/bugzillalib.h
|
|
index 570169bb6afc5b124a6c7866dbb5bf30ba61cf41..481805cb31799d50c071feaec78101317b488d93 100644
|
|
--- a/drkonqi/bugzillaintegration/bugzillalib.h
|
|
+++ b/drkonqi/bugzillaintegration/bugzillalib.h
|
|
@@ -387,12 +387,18 @@ public:
|
|
|
|
void stopCurrentSearch();
|
|
|
|
+ /* Codes for security methods used by Bugzilla in various versions. */
|
|
+ enum SecurityMethod {UseCookies, UseTokens, UsePasswords};
|
|
+ SecurityMethod securityMethod() { return m_security; };
|
|
+
|
|
private Q_SLOTS:
|
|
/* Slots to handle KJob::finished */
|
|
void fetchBugJobFinished(KJob*);
|
|
void searchBugsJobFinished(KJob*);
|
|
void fetchProductInfoFinished(const QVariantMap&);
|
|
|
|
+ void lookupVersion();
|
|
+
|
|
void callMessage(const QList<QVariant> & result, const QVariant & id);
|
|
void callFault(int errorCode, const QString & errorString, const QVariant &id);
|
|
|
|
@@ -405,6 +411,7 @@ Q_SIGNALS:
|
|
void attachToReportSent(int);
|
|
void addMeToCCFinished(int);
|
|
void productInfoFetched(Product);
|
|
+ void bugzillaVersionFound();
|
|
|
|
/* Bugzilla actions had errors */
|
|
void loginError(const QString & errorMsg, const QString & extendedErrorMsg = QString());
|
|
@@ -419,10 +426,19 @@ Q_SIGNALS:
|
|
private:
|
|
QString m_bugTrackerUrl;
|
|
QString m_username;
|
|
+ QString m_token;
|
|
+ QString m_password;
|
|
bool m_logged;
|
|
+ SecurityMethod m_security;
|
|
|
|
KIO::Job * m_searchJob;
|
|
KXmlRpc::Client *m_xmlRpcClient;
|
|
+
|
|
+ enum SecurityStatus {SecurityDisabled, SecurityEnabled};
|
|
+ void callBugzilla(const char* method, const char* id,
|
|
+ QMap<QString, QVariant>& args,
|
|
+ SecurityStatus security);
|
|
+ void setFeaturesForVersion(const QString& version);
|
|
};
|
|
|
|
#endif
|
|
diff --git a/drkonqi/bugzillaintegration/reportassistantpages_bugzilla.cpp b/drkonqi/bugzillaintegration/reportassistantpages_bugzilla.cpp
|
|
index 5a6096f1483950ba6c9e037c7c4c5068a5382e82..3a25b44757027ecebf4687b4e96fcedf20c24cb7 100644
|
|
--- a/drkonqi/bugzillaintegration/reportassistantpages_bugzilla.cpp
|
|
+++ b/drkonqi/bugzillaintegration/reportassistantpages_bugzilla.cpp
|
|
@@ -66,8 +66,10 @@ static const char konquerorKWalletEntryPassword[] = "Bugzilla_password";
|
|
|
|
BugzillaLoginPage::BugzillaLoginPage(ReportAssistantDialog * parent) :
|
|
ReportAssistantPage(parent),
|
|
- m_wallet(0), m_walletWasOpenedBefore(false)
|
|
+ m_wallet(0), m_walletWasOpenedBefore(false),
|
|
+ m_bugzillaVersionFound(false)
|
|
{
|
|
+ connect(bugzillaManager(), SIGNAL(bugzillaVersionFound()), this, SLOT(bugzillaVersionFound()));
|
|
connect(bugzillaManager(), SIGNAL(loginFinished(bool)), this, SLOT(loginFinished(bool)));
|
|
connect(bugzillaManager(), SIGNAL(loginError(QString,QString)), this, SLOT(loginError(QString,QString)));
|
|
|
|
@@ -107,10 +109,18 @@ bool BugzillaLoginPage::isComplete()
|
|
return bugzillaManager()->getLogged();
|
|
}
|
|
|
|
+void BugzillaLoginPage::bugzillaVersionFound()
|
|
+{
|
|
+ // Login depends on first knowing the Bugzilla software version number.
|
|
+ m_bugzillaVersionFound = true;
|
|
+ updateLoginButtonStatus();
|
|
+}
|
|
+
|
|
void BugzillaLoginPage::updateLoginButtonStatus()
|
|
{
|
|
ui.m_loginButton->setEnabled( !ui.m_userEdit->text().isEmpty() &&
|
|
- !ui.m_passwordEdit->text().isEmpty() );
|
|
+ !ui.m_passwordEdit->text().isEmpty() &&
|
|
+ m_bugzillaVersionFound );
|
|
}
|
|
|
|
void BugzillaLoginPage::loginError(const QString & err, const QString & extendedMessage)
|
|
@@ -223,6 +233,10 @@ void BugzillaLoginPage::walletLogin()
|
|
|
|
bool BugzillaLoginPage::canSetCookies()
|
|
{
|
|
+ if (bugzillaManager()->securityMethod() != BugzillaManager::UseCookies) {
|
|
+ qDebug() << "Bugzilla software no longer issues cookies.";
|
|
+ return false;
|
|
+ }
|
|
QDBusInterface kded(QLatin1String("org.kde.kded5"),
|
|
QLatin1String("/kded"),
|
|
QLatin1String("org.kde.kded5"));
|
|
@@ -285,7 +299,8 @@ void BugzillaLoginPage::loginClicked()
|
|
{
|
|
if (!(ui.m_userEdit->text().isEmpty() || ui.m_passwordEdit->text().isEmpty())) {
|
|
|
|
- if (!canSetCookies()) {
|
|
+ if ((bugzillaManager()->securityMethod() == BugzillaManager::UseCookies)
|
|
+ && (!canSetCookies())) {
|
|
return;
|
|
}
|
|
|
|
diff --git a/drkonqi/bugzillaintegration/reportassistantpages_bugzilla.h b/drkonqi/bugzillaintegration/reportassistantpages_bugzilla.h
|
|
index 50cf05f5ce724984e9900ca111533aec75c08cbe..da2d39f88f9aa6e69784e35e29ee06ab44b66c76 100644
|
|
--- a/drkonqi/bugzillaintegration/reportassistantpages_bugzilla.h
|
|
+++ b/drkonqi/bugzillaintegration/reportassistantpages_bugzilla.h
|
|
@@ -45,6 +45,7 @@ public:
|
|
bool isComplete();
|
|
|
|
private Q_SLOTS:
|
|
+ void bugzillaVersionFound();
|
|
void loginClicked();
|
|
void loginFinished(bool);
|
|
void loginError(const QString &, const QString &);
|
|
@@ -65,6 +66,7 @@ private:
|
|
|
|
KWallet::Wallet * m_wallet;
|
|
bool m_walletWasOpenedBefore;
|
|
+ bool m_bugzillaVersionFound;
|
|
};
|
|
|
|
/** Title and details page **/
|
|
--
|
|
2.1.3
|
|
|