QGIS API Documentation  3.21.0-Master (909859188c)
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  const 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  const 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( QLatin1Char( '\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 }
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
Dialog wrapper for widget displaying detailed info on a certificate and its hierarchical trust chain.
static QString sslErrorEnumString(QSslError::SslError errenum)
Gets short strings describing an SSL error.
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Gets the sha1 hash for certificate.
bool updateIgnoredSslErrorsCache(const QString &shahostport, const QList< QSslError > &errors)
Update ignored SSL error cache with possible ignored SSL errors, using sha:host:port key.
void readyToSaveChanged(bool cansave)
Emitted when the configuration can be saved changes.
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.
Widget for listing trusted Certificate (Intermediate) Authorities used in secure connections.
void collapsedStateChanged(bool collapsed)
Signal emitted when groupbox collapsed/expanded state is changed, and when first shown.
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38