diff options
author | Gerhard Gappmeier <gerhard.gappmeier@ascolab.com> | 2018-11-13 14:18:17 +0100 |
---|---|---|
committer | Rainer Keller <Rainer.Keller@qt.io> | 2019-01-11 13:49:18 +0000 |
commit | 04a9a85872c2e54fe69902a308e6d4ed33ac1f19 (patch) | |
tree | 7c9ae9b62adc9a13bb06bfc51fda90970bcb2ded /examples | |
parent | 05022007770b087b2632568fcf061053f3924dcb (diff) |
opcuaviewer: Add certificate dialog and trust functionality
Change-Id: Ibab6725d5047512dc8db7feb2d46f41a75054eb0
Reviewed-by: Frank Meerkoetter <frank.meerkoetter@basyskom.com>
Diffstat (limited to 'examples')
-rw-r--r-- | examples/opcua/opcuaviewer/certificatedialog.cpp | 93 | ||||
-rw-r--r-- | examples/opcua/opcuaviewer/certificatedialog.h | 70 | ||||
-rw-r--r-- | examples/opcua/opcuaviewer/certificatedialog.ui | 131 | ||||
-rw-r--r-- | examples/opcua/opcuaviewer/mainwindow.cpp | 29 | ||||
-rw-r--r-- | examples/opcua/opcuaviewer/mainwindow.h | 1 | ||||
-rw-r--r-- | examples/opcua/opcuaviewer/opcuaviewer.pro | 9 |
6 files changed, 314 insertions, 19 deletions
diff --git a/examples/opcua/opcuaviewer/certificatedialog.cpp b/examples/opcua/opcuaviewer/certificatedialog.cpp new file mode 100644 index 0000000..61628bc --- /dev/null +++ b/examples/opcua/opcuaviewer/certificatedialog.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Unified Automation GmbH +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtOpcUa module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "certificatedialog.h" +#include "ui_certificatedialog.h" +#include <QPushButton> + +QT_BEGIN_NAMESPACE + +CertificateDialog::CertificateDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::CertificateDialog) +{ + ui->setupUi(this); + connect(ui->btnTrust, &QPushButton::clicked, this, &CertificateDialog::saveCertificate); +} + +CertificateDialog::~CertificateDialog() +{ + delete ui; +} + +/** Returns 0 if the connect should be aborted, 1 if it should be resumed. */ +int CertificateDialog::showCertificate(const QString &message, const QByteArray &der, const QString &trustListLocation) +{ + QList<QSslCertificate> certs = QSslCertificate::fromData(der, QSsl::Der); + + m_trustListLocation = trustListLocation; + + // if it is a unstrusted self-signed certificate we can allow to trust it + if (certs.count() == 1 && certs[0].isSelfSigned()) { + m_cert = certs[0]; + ui->btnTrust->setEnabled(true); + } else { + ui->btnTrust->setEnabled(false); + } + + for (const QSslCertificate &cert : qAsConst(certs)) + ui->certificate->appendPlainText(cert.toText()); + + ui->message->setText(message); + ui->certificate->moveCursor(QTextCursor::Start); + ui->certificate->ensureCursorVisible(); + + return exec(); +} + +void CertificateDialog::saveCertificate() +{ + const QByteArray digest = m_cert.digest(); + const QString path = m_trustListLocation + "/" + digest.toHex() + ".der"; + + QFile file(path); + if (file.open(QIODevice::WriteOnly)) { + file.write(m_cert.toDer()); + file.close(); + } +} + +QT_END_NAMESPACE diff --git a/examples/opcua/opcuaviewer/certificatedialog.h b/examples/opcua/opcuaviewer/certificatedialog.h new file mode 100644 index 0000000..6e82ae1 --- /dev/null +++ b/examples/opcua/opcuaviewer/certificatedialog.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Unified Automation GmbH +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtOpcUa module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CERTIFICATEDIALOG_H +#define CERTIFICATEDIALOG_H + +#include <QDialog> +#include <QSslCertificate> + +QT_BEGIN_NAMESPACE + +namespace Ui { +class CertificateDialog; +} + +class CertificateDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CertificateDialog(QWidget *parent = nullptr); + ~CertificateDialog(); + + int showCertificate(const QString &message, const QByteArray &der, const QString &trustListLocation); + +private slots: + void saveCertificate(); + +private: + Ui::CertificateDialog *ui; + QSslCertificate m_cert; + QString m_trustListLocation; +}; + +QT_END_NAMESPACE + +#endif // CERTIFICATEDIALOG_H diff --git a/examples/opcua/opcuaviewer/certificatedialog.ui b/examples/opcua/opcuaviewer/certificatedialog.ui new file mode 100644 index 0000000..0a25d2c --- /dev/null +++ b/examples/opcua/opcuaviewer/certificatedialog.ui @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CertificateDialog</class> + <widget class="QDialog" name="CertificateDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>720</width> + <height>423</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="message"> + <property name="text"> + <string>TextLabel</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QPlainTextEdit" name="certificate"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="btnIgnore"> + <property name="text"> + <string>Ignore Error</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnTrust"> + <property name="text"> + <string>Trust Certificate</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnCancel"> + <property name="text"> + <string>Cancel</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>btnIgnore</sender> + <signal>clicked()</signal> + <receiver>CertificateDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>475</x> + <y>402</y> + </hint> + <hint type="destinationlabel"> + <x>374</x> + <y>397</y> + </hint> + </hints> + </connection> + <connection> + <sender>btnTrust</sender> + <signal>clicked()</signal> + <receiver>CertificateDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>563</x> + <y>404</y> + </hint> + <hint type="destinationlabel"> + <x>287</x> + <y>395</y> + </hint> + </hints> + </connection> + <connection> + <sender>btnCancel</sender> + <signal>clicked()</signal> + <receiver>CertificateDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>670</x> + <y>406</y> + </hint> + <hint type="destinationlabel"> + <x>717</x> + <y>395</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/examples/opcua/opcuaviewer/mainwindow.cpp b/examples/opcua/opcuaviewer/mainwindow.cpp index c6f9d0a..eb91531 100644 --- a/examples/opcua/opcuaviewer/mainwindow.cpp +++ b/examples/opcua/opcuaviewer/mainwindow.cpp @@ -50,6 +50,7 @@ #include "mainwindow.h" #include "opcuamodel.h" +#include "certificatedialog.h" #include <QCoreApplication> #include <QDir> @@ -155,7 +156,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) widget->setLayout(vbox); setCentralWidget(widget); - mHost->setText("opc.tcp://localhost"); + mHost->setText("opc.tcp://localhost:48010"); mEndpoints->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); updateUiState(); @@ -314,9 +315,9 @@ void MainWindow::connectToServer() } if (mEndpoints->currentIndex() >= 0) { - QOpcUa::QEndpointDescription endpoint = mEndpointList[mEndpoints->currentIndex()]; + m_endpoint = mEndpointList[mEndpoints->currentIndex()]; createClient(); - mOpcUaClient->connectToEndpoint(endpoint); + mOpcUaClient->connectToEndpoint(m_endpoint); } } @@ -450,8 +451,8 @@ bool MainWindow::createPkiFolders() void MainWindow::showErrorDialog(QOpcUaErrorState *errorState) { QString msg; - QMessageBox::StandardButtons buttons = QMessageBox::Ok; - QMessageBox::StandardButton defaultButton = QMessageBox::Ok; + CertificateDialog dlg; + int result = 0; const QString statuscode = QOpcUa::statusToString(errorState->errorCode()); @@ -463,29 +464,23 @@ void MainWindow::showErrorDialog(QOpcUaErrorState *errorState) switch (errorState->connectionStep()) { case QOpcUaErrorState::ConnectionStep::CertificateValidation: msg += tr("Server certificate validation failed with error 0x%1 (%2).\nClick 'Abort' to abort the connect, or 'Ignore' to continue connecting.") - .arg(static_cast<ulong>(errorState->errorCode()), 8, 16, QLatin1Char('0')).arg(statuscode); - buttons = QMessageBox::Ignore | QMessageBox::Abort; - defaultButton = QMessageBox::Abort; + .arg(static_cast<ulong>(errorState->errorCode()), 8, 16, QLatin1Char('0')).arg(statuscode); + result = dlg.showCertificate(msg, m_endpoint.serverCertificate(), m_pkiConfig.trustListLocation()); + errorState->setIgnoreError(result == 1); break; case QOpcUaErrorState::ConnectionStep::OpenSecureChannel: msg += tr("OpenSecureChannel failed with error 0x%1 (%2).").arg(errorState->errorCode(), 8, 16, QLatin1Char('0')).arg(statuscode); + QMessageBox::warning(this, tr("Connection Error"), msg); break; case QOpcUaErrorState::ConnectionStep::CreateSession: msg += tr("CreateSession failed with error 0x%1 (%2).").arg(errorState->errorCode(), 8, 16, QLatin1Char('0')).arg(statuscode); + QMessageBox::warning(this, tr("Connection Error"), msg); break; case QOpcUaErrorState::ConnectionStep::ActivateSession: msg += tr("ActivateSession failed with error 0x%1 (%2).").arg(errorState->errorCode(), 8, 16, QLatin1Char('0')).arg(statuscode); + QMessageBox::warning(this, tr("Connection Error"), msg); break; } - - QMessageBox::StandardButton result = QMessageBox::warning( - this, - tr("Connect Error"), - msg, - buttons, - defaultButton); - - errorState->setIgnoreError(result == QMessageBox::Ignore); } QT_END_NAMESPACE diff --git a/examples/opcua/opcuaviewer/mainwindow.h b/examples/opcua/opcuaviewer/mainwindow.h index d7056d1..1457e3b 100644 --- a/examples/opcua/opcuaviewer/mainwindow.h +++ b/examples/opcua/opcuaviewer/mainwindow.h @@ -109,6 +109,7 @@ private: bool mClientConnected; QOpcUaApplicationIdentity m_identity; QOpcUaPkiConfiguration m_pkiConfig; + QOpcUa::QEndpointDescription m_endpoint; // current endpoint used to connect }; QT_END_NAMESPACE diff --git a/examples/opcua/opcuaviewer/opcuaviewer.pro b/examples/opcua/opcuaviewer/opcuaviewer.pro index 15e55ce..ce06229 100644 --- a/examples/opcua/opcuaviewer/opcuaviewer.pro +++ b/examples/opcua/opcuaviewer/opcuaviewer.pro @@ -7,7 +7,8 @@ INCLUDEPATH += \ SOURCES += main.cpp \ mainwindow.cpp \ opcuamodel.cpp \ - treeitem.cpp + treeitem.cpp \ + certificatedialog.cpp #install target.path = $$[QT_INSTALL_EXAMPLES]/opcua/opcuaviewer @@ -16,4 +17,8 @@ INSTALLS += target HEADERS += \ mainwindow.h \ opcuamodel.h \ - treeitem.h + treeitem.h \ + certificatedialog.h + +FORMS += \ + certificatedialog.ui |