QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsauthsslerrorsdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsauthsslerrorsdialog.cpp
3  ---------------------
4  begin : May 22, 2015
5  copyright : (C) 2015 by Boundless Spatial, Inc. USA
6  author : Larry Shaffer
7  email : lshaffer at boundlessgeo dot com
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgsauthcertificateinfo.h"
18 #include "qgsauthsslerrorsdialog.h"
19 #include "qgsauthsslconfigwidget.h"
20 
21 #include <QDialogButtonBox>
22 #include <QFont>
23 #include <QPushButton>
24 #include <QStyle>
25 #include <QToolButton>
26 
27 #include "qgsauthmanager.h"
29 #include "qgsauthcertutils.h"
31 #include "qgscollapsiblegroupbox.h"
32 #include "qgslogger.h"
33 #include "qgsapplication.h"
34 
35 
37  const QList<QSslError> &sslErrors,
38  QWidget *parent,
39  const QString &digest,
40  const QString &hostport )
41  : QDialog( parent )
42  , mSslConfiguration( reply->sslConfiguration() )
43  , mSslErrors( sslErrors )
44  , mDigest( digest )
45  , mHostPort( hostport )
46 {
47  if ( mDigest.isEmpty() )
48  {
49  mDigest = QgsAuthCertUtils::shaHexForCert( mSslConfiguration.peerCertificate() );
50  }
51  if ( mHostPort.isEmpty() )
52  {
53  mHostPort = QStringLiteral( "%1:%2" )
54  .arg( reply->url().host() )
55  .arg( reply->url().port() != -1 ? reply->url().port() : 443 )
56  .trimmed();
57  }
58 
59  setupUi( this );
60  connect( buttonBox, &QDialogButtonBox::clicked, this, &QgsAuthSslErrorsDialog::buttonBox_clicked );
61  connect( btnChainInfo, &QToolButton::clicked, this, &QgsAuthSslErrorsDialog::btnChainInfo_clicked );
62  connect( btnChainCAs, &QToolButton::clicked, this, &QgsAuthSslErrorsDialog::btnChainCAs_clicked );
63  connect( grpbxSslErrors, &QgsCollapsibleGroupBoxBasic::collapsedStateChanged, this, &QgsAuthSslErrorsDialog::grpbxSslErrors_collapsedStateChanged );
64  QStyle *style = QApplication::style();
65  lblWarningIcon->setPixmap( style->standardIcon( QStyle::SP_MessageBoxWarning ).pixmap( 48, 48 ) );
66  lblWarningIcon->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
67 
68  lblErrorsText->setStyleSheet( QStringLiteral( "QLabel{ font-weight: bold; }" ) );
69  leUrl->setText( reply->request().url().toString() );
70 
71  ignoreButton()->setDefault( false );
72  abortButton()->setDefault( true );
73 
74  if ( !QgsApplication::authManager()->isDisabled() )
75  {
76  saveButton()->setEnabled( false );
77 
78  saveButton()->setText( QStringLiteral( "%1 && %2" ).arg( saveButton()->text(),
79  ignoreButton()->text() ) );
80 
81  grpbxSslConfig->setChecked( false );
82  grpbxSslConfig->setCollapsed( true );
83  connect( grpbxSslConfig, &QGroupBox::toggled,
84  this, &QgsAuthSslErrorsDialog::loadUnloadCertificate );
85 
86  connect( wdgtSslConfig, &QgsAuthSslConfigWidget::readyToSaveChanged,
87  this, &QgsAuthSslErrorsDialog::widgetReadyToSaveChanged );
88  wdgtSslConfig->setConfigCheckable( false );
89  wdgtSslConfig->certificateGroupBox()->setFlat( true );
90  }
91  else
92  {
93  btnChainInfo->setVisible( false );
94  btnChainCAs->setVisible( false );
95  grpbxSslConfig->setVisible( false );
96  saveButton()->setVisible( false );
97  }
98 
99  populateErrorsList();
100 }
101 
102 void QgsAuthSslErrorsDialog::loadUnloadCertificate( bool load )
103 {
104  grpbxSslErrors->setCollapsed( load );
105  if ( !load )
106  {
107  QgsDebugMsg( QStringLiteral( "Unloading certificate and host:port" ) );
108  clearCertificateConfig();
109  return;
110  }
111  wdgtSslConfig->setEnabled( true );
112  QgsDebugMsg( QStringLiteral( "Loading certificate for host:port = %1" ).arg( mHostPort ) );
113  wdgtSslConfig->setSslCertificate( mSslConfiguration.peerCertificate(), mHostPort );
114  if ( !mSslErrors.isEmpty() )
115  {
116  wdgtSslConfig->appendSslIgnoreErrors( mSslErrors );
117  }
118 }
119 
120 void QgsAuthSslErrorsDialog::showCertificateChainInfo()
121 {
122  QList<QSslCertificate> peerchain( mSslConfiguration.peerCertificateChain() );
123 
124  if ( !peerchain.isEmpty() )
125  {
126  QSslCertificate cert = peerchain.takeFirst();
127  if ( !cert.isNull() )
128  {
129  QgsAuthCertInfoDialog *dlg = new QgsAuthCertInfoDialog( cert, false, this, peerchain );
130  dlg->setWindowModality( Qt::WindowModal );
131  dlg->resize( 675, 500 );
132  dlg->exec();
133  dlg->deleteLater();
134  }
135  }
136 }
137 
138 void QgsAuthSslErrorsDialog::showCertificateChainCAsInfo()
139 {
140  const QList< QSslCertificate > certificates = mSslConfiguration.caCertificates();
141  for ( const auto &cert : certificates )
142  {
143  qDebug() << cert.subjectInfo( QSslCertificate::SubjectInfo::CommonName );
144  }
145 
146  QgsAuthTrustedCAsDialog *dlg = new QgsAuthTrustedCAsDialog( this, mSslConfiguration.caCertificates() );
147  dlg->setWindowModality( Qt::WindowModal );
148  dlg->resize( 675, 500 );
149  dlg->exec();
150  dlg->deleteLater();
151 }
152 
153 void QgsAuthSslErrorsDialog::widgetReadyToSaveChanged( bool cansave )
154 {
155  ignoreButton()->setDefault( false );
156  abortButton()->setDefault( !cansave );
157  saveButton()->setEnabled( cansave );
158  saveButton()->setDefault( cansave );
159 }
160 
161 void QgsAuthSslErrorsDialog::checkCanSave()
162 {
163  widgetReadyToSaveChanged( wdgtSslConfig->readyToSave() );
164 }
165 
166 void QgsAuthSslErrorsDialog::clearCertificateConfig()
167 {
168  wdgtSslConfig->resetSslCertConfig();
169  wdgtSslConfig->setEnabled( false );
170  checkCanSave();
171 }
172 
173 void QgsAuthSslErrorsDialog::buttonBox_clicked( QAbstractButton *button )
174 {
175  QDialogButtonBox::StandardButton btnenum( buttonBox->standardButton( button ) );
176  switch ( btnenum )
177  {
178  case QDialogButtonBox::Ignore:
180  QStringLiteral( "%1:%2" ).arg( mDigest, mHostPort ),
181  mSslErrors );
182  accept();
183  break;
184  case QDialogButtonBox::Save:
185  // save config and ignore errors
186  wdgtSslConfig->saveSslCertConfig();
187  accept();
188  break;
189  case QDialogButtonBox::Abort:
190  default:
191  reject();
192  break;
193  }
194  // Clear access cache if the user choose abort and the
195  // setting allows it
196  if ( btnenum == QDialogButtonBox::Abort &&
197  QgsSettings().value( QStringLiteral( "clear_auth_cache_on_errors" ),
198  true,
199  QgsSettings::Section::Auth ).toBool( ) )
200  {
201  QgsNetworkAccessManager::instance()->clearAccessCache();
202  }
203 }
204 
205 void QgsAuthSslErrorsDialog::populateErrorsList()
206 {
207  QStringList errs;
208  errs.reserve( mSslErrors.size() );
209  const auto constMSslErrors = mSslErrors;
210  for ( const QSslError &err : constMSslErrors )
211  {
212  errs << QStringLiteral( "* %1: %2" )
213  .arg( QgsAuthCertUtils::sslErrorEnumString( err.error() ),
214  err.errorString() );
215  }
216  teSslErrors->setPlainText( errs.join( QStringLiteral( "\n" ) ) );
217 }
218 
219 QPushButton *QgsAuthSslErrorsDialog::ignoreButton()
220 {
221  return buttonBox->button( QDialogButtonBox::Ignore );
222 }
223 
224 QPushButton *QgsAuthSslErrorsDialog::saveButton()
225 {
226  return buttonBox->button( QDialogButtonBox::Save );
227 }
228 
229 QPushButton *QgsAuthSslErrorsDialog::abortButton()
230 {
231  return buttonBox->button( QDialogButtonBox::Abort );
232 }
233 
234 void QgsAuthSslErrorsDialog::btnChainInfo_clicked()
235 {
236  showCertificateChainInfo();
237 }
238 
239 void QgsAuthSslErrorsDialog::btnChainCAs_clicked()
240 {
241  showCertificateChainCAsInfo();
242 }
243 
244 void QgsAuthSslErrorsDialog::grpbxSslErrors_collapsedStateChanged( bool collapsed )
245 {
246  if ( !collapsed && QgsApplication::authManager()->isDisabled() )
247  {
248  btnChainInfo->setVisible( false );
249  btnChainCAs->setVisible( false );
250  }
251 }
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
static QString sslErrorEnumString(QSslError::SslError errenum)
Gets short strings describing an SSL error.
void collapsedStateChanged(bool collapsed)
Signal emitted when groupbox collapsed/expanded state is changed, and when first shown.
Dialog wrapper for widget displaying detailed info on a certificate and its hierarchical trust chain...
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Gets the sha1 hash for certificate.
static QgsAuthManager * authManager()
Returns the application&#39;s authentication manager instance.
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
bool updateIgnoredSslErrorsCache(const QString &shahostport, const QList< QSslError > &errors)
Update ignored SSL error cache with possible ignored SSL errors, using sha:host:port key...
QgsAuthSslErrorsDialog(QNetworkReply *reply, const QList< QSslError > &sslErrors, QWidget *parent=nullptr, const QString &digest=QString(), const QString &hostport=QString())
Construct a dialog to handle SSL errors and saving SSL server certificate exceptions.
void readyToSaveChanged(bool cansave)
Emitted when the configuration can be saved changes.
Widget for listing trusted Certificate (Intermediate) Authorities used in secure connections.