Axivion: Handle some SSL related issues

...when using QNetworkAccessManager.

Change-Id: I2b1a6173052ce76e7aeed0897f3d6389ace36206
Reviewed-by: Andreas Loth <andreas.loth@qt.io>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Stenger
2023-09-15 12:25:04 +02:00
parent 0632648be6
commit d87e6db168
3 changed files with 52 additions and 24 deletions

View File

@@ -7,12 +7,14 @@
#include "axivionprojectsettings.h" #include "axivionprojectsettings.h"
#include "axivionquery.h" #include "axivionquery.h"
#include "axivionresultparser.h" #include "axivionresultparser.h"
#include "axivionsettings.h"
#include "axiviontr.h" #include "axiviontr.h"
#include "dashboard/dashboardclient.h" #include "dashboard/dashboardclient.h"
#include "dashboard/dto.h" #include "dashboard/dto.h"
#include <coreplugin/editormanager/documentmodel.h> #include <coreplugin/editormanager/documentmodel.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
@@ -26,6 +28,7 @@
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
#include <texteditor/textmark.h> #include <texteditor/textmark.h>
#include <utils/algorithm.h>
#include <utils/expected.h> #include <utils/expected.h>
#include <utils/networkaccessmanager.h> #include <utils/networkaccessmanager.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -33,6 +36,9 @@
#include <QAction> #include <QAction>
#include <QFutureWatcher> #include <QFutureWatcher>
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTimer> #include <QTimer>
#include <exception> #include <exception>
@@ -45,6 +51,8 @@ namespace Axivion::Internal {
class AxivionPluginPrivate : public QObject class AxivionPluginPrivate : public QObject
{ {
public: public:
AxivionPluginPrivate();
void handleSslErrors(QNetworkReply *reply, const QList<QSslError> &errors);
void onStartupProjectChanged(); void onStartupProjectChanged();
void fetchProjectInfo(const QString &projectName); void fetchProjectInfo(const QString &projectName);
void handleProjectInfo(DashboardClient::RawProjectInfo rawInfo); void handleProjectInfo(DashboardClient::RawProjectInfo rawInfo);
@@ -55,7 +63,7 @@ public:
void handleIssuesForFile(const IssuesList &issues); void handleIssuesForFile(const IssuesList &issues);
void fetchRuleInfo(const QString &id); void fetchRuleInfo(const QString &id);
Utils::NetworkAccessManager *m_networkAccessManager = Utils::NetworkAccessManager::instance(); Utils::NetworkAccessManager m_networkAccessManager;
AxivionOutputPane m_axivionOutputPane; AxivionOutputPane m_axivionOutputPane;
std::shared_ptr<const DashboardClient::ProjectInfo> m_currentProjectInfo; std::shared_ptr<const DashboardClient::ProjectInfo> m_currentProjectInfo;
bool m_runningQuery = false; bool m_runningQuery = false;
@@ -128,6 +136,46 @@ std::shared_ptr<const DashboardClient::ProjectInfo> AxivionPlugin::projectInfo()
return dd->m_currentProjectInfo; return dd->m_currentProjectInfo;
} }
// FIXME: extend to give some details?
// FIXME: move when curl is no more in use?
bool AxivionPlugin::handleCertificateIssue()
{
QTC_ASSERT(dd, return false);
const QString serverHost = QUrl(settings().server.dashboard).host();
if (QMessageBox::question(Core::ICore::dialogParent(), Tr::tr("Certificate Error"),
Tr::tr("Server certificate for %1 cannot be authenticated.\n"
"Do you want to disable SSL verification for this server?\n"
"Note: This can expose you to man-in-the-middle attack.")
.arg(serverHost))
!= QMessageBox::Yes) {
return false;
}
settings().server.validateCert = false;
settings().apply();
return true;
}
AxivionPluginPrivate::AxivionPluginPrivate()
{
connect(&m_networkAccessManager, &QNetworkAccessManager::sslErrors,
this, &AxivionPluginPrivate::handleSslErrors);
}
void AxivionPluginPrivate::handleSslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
{
const QList<QSslError::SslError> accepted{
QSslError::CertificateNotYetValid, QSslError::CertificateExpired,
QSslError::InvalidCaCertificate, QSslError::CertificateUntrusted,
QSslError::HostNameMismatch
};
if (Utils::allOf(errors,
[&accepted](const QSslError &e) { return accepted.contains(e.error()); })) {
if (!settings().server.validateCert || AxivionPlugin::handleCertificateIssue())
reply->ignoreSslErrors(errors);
}
}
void AxivionPluginPrivate::onStartupProjectChanged() void AxivionPluginPrivate::onStartupProjectChanged()
{ {
ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
@@ -155,7 +203,7 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName)
return; return;
} }
m_runningQuery = true; m_runningQuery = true;
DashboardClient client { *this->m_networkAccessManager }; DashboardClient client { this->m_networkAccessManager };
QFuture<DashboardClient::RawProjectInfo> response = client.fetchProjectInfo(projectName); QFuture<DashboardClient::RawProjectInfo> response = client.fetchProjectInfo(projectName);
auto responseWatcher = std::make_shared<QFutureWatcher<DashboardClient::RawProjectInfo>>(); auto responseWatcher = std::make_shared<QFutureWatcher<DashboardClient::RawProjectInfo>>();
connect(responseWatcher.get(), connect(responseWatcher.get(),

View File

@@ -27,6 +27,7 @@ public:
static void fetchProjectInfo(const QString &projectName); static void fetchProjectInfo(const QString &projectName);
static std::shared_ptr<const DashboardClient::ProjectInfo> projectInfo(); static std::shared_ptr<const DashboardClient::ProjectInfo> projectInfo();
static bool handleCertificateIssue();
private: private:
void initialize() final; void initialize() final;

View File

@@ -5,14 +5,10 @@
#include "axivionplugin.h" #include "axivionplugin.h"
#include "axivionsettings.h" #include "axivionsettings.h"
#include "axiviontr.h"
#include <coreplugin/icore.h>
#include <utils/processenums.h> #include <utils/processenums.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QMessageBox>
#include <QUrl> #include <QUrl>
using namespace Utils; using namespace Utils;
@@ -54,23 +50,6 @@ QString AxivionQuery::toString() const
return {}; return {};
} }
static bool handleCertificateIssue()
{
const QString serverHost = QUrl(settings().server.dashboard).host();
if (QMessageBox::question(Core::ICore::dialogParent(), Tr::tr("Certificate Error"),
Tr::tr("Server certificate for %1 cannot be authenticated.\n"
"Do you want to disable SSL verification for this server?\n"
"Note: This can expose you to man-in-the-middle attack.")
.arg(serverHost))
!= QMessageBox::Yes) {
return false;
}
settings().server.validateCert = false;
settings().apply();
return true;
}
AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *parent) AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *parent)
: QObject(parent) : QObject(parent)
{ {
@@ -91,7 +70,7 @@ AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *paren
const int exitCode = m_process.exitCode(); const int exitCode = m_process.exitCode();
if (m_process.exitStatus() == QProcess::NormalExit if (m_process.exitStatus() == QProcess::NormalExit
&& (exitCode == 35 || exitCode == 60) && (exitCode == 35 || exitCode == 60)
&& handleCertificateIssue()) { && AxivionPlugin::handleCertificateIssue()) {
// prepend -k for re-requesting same query // prepend -k for re-requesting same query
CommandLine cmdline = m_process.commandLine(); CommandLine cmdline = m_process.commandLine();
cmdline.prependArgs({"-k"}); cmdline.prependArgs({"-k"});