QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
qgsauthtrustedcasdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsauthtrustedcasdialog.cpp
3  ---------------------
4  begin : May 9, 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 
18 #include "ui_qgsauthtrustedcasdialog.h"
19 
20 #include <QPushButton>
21 
22 #include "qgssettings.h"
23 #include "qgsapplication.h"
24 #include "qgsauthcertificateinfo.h"
25 #include "qgsauthcertutils.h"
26 #include "qgsauthguiutils.h"
27 #include "qgsauthmanager.h"
28 #include "qgslogger.h"
29 
30 
32  const QList<QSslCertificate> &trustedCAs )
33  : QDialog( parent )
34  , mTrustedCAs( trustedCAs )
35 {
36  if ( QgsApplication::authManager()->isDisabled() )
37  {
38  mDisabled = true;
39  mAuthNotifyLayout = new QVBoxLayout;
40  this->setLayout( mAuthNotifyLayout );
41  mAuthNotify = new QLabel( QgsApplication::authManager()->disabledMessage(), this );
42  mAuthNotifyLayout->addWidget( mAuthNotify );
43  }
44  else
45  {
46  setupUi( this );
47  connect( btnInfoCa, &QToolButton::clicked, this, &QgsAuthTrustedCAsDialog::btnInfoCa_clicked );
48  connect( btnGroupByOrg, &QToolButton::toggled, this, &QgsAuthTrustedCAsDialog::btnGroupByOrg_toggled );
49 
51  this, &QgsAuthTrustedCAsDialog::authMessageOut );
52 
53  setupCaCertsTree();
54 
55  connect( treeTrustedCAs->selectionModel(), &QItemSelectionModel::selectionChanged,
56  this, &QgsAuthTrustedCAsDialog::selectionChanged );
57 
58  connect( treeTrustedCAs, &QTreeWidget::itemDoubleClicked,
59  this, &QgsAuthTrustedCAsDialog::handleDoubleClick );
60 
61 
62  btnGroupByOrg->setChecked( false );
63  const QVariant sortbyval = QgsApplication::authManager()->authSetting( QStringLiteral( "trustedcasortby" ), QVariant( false ) );
64  if ( !sortbyval.isNull() )
65  btnGroupByOrg->setChecked( sortbyval.toBool() );
66 
67  populateCaCertsView();
68  checkSelection();
69  }
70 }
71 
72 static void setItemBold_( QTreeWidgetItem *item )
73 {
74  item->setFirstColumnSpanned( true );
75  QFont secf( item->font( 0 ) );
76  secf.setBold( true );
77  item->setFont( 0, secf );
78 }
79 
80 void QgsAuthTrustedCAsDialog::setupCaCertsTree()
81 {
82  treeTrustedCAs->setColumnCount( 3 );
83  treeTrustedCAs->setHeaderLabels(
84  QStringList() << tr( "Common Name" )
85  << tr( "Serial #" )
86  << tr( "Expiry Date" ) );
87  treeTrustedCAs->setColumnWidth( 0, 300 );
88  treeTrustedCAs->setColumnWidth( 1, 75 );
89 
90  // add root section
91  mRootCaSecItem = new QTreeWidgetItem(
92  treeTrustedCAs,
93  QStringList( tr( "Authorities/Issuers" ) ),
94  static_cast<int>( QgsAuthTrustedCAsDialog::Section ) );
95  setItemBold_( mRootCaSecItem );
96  mRootCaSecItem->setFlags( Qt::ItemIsEnabled );
97  mRootCaSecItem->setExpanded( true );
98  treeTrustedCAs->insertTopLevelItem( 0, mRootCaSecItem );
99 }
100 
101 static void removeChildren_( QTreeWidgetItem *item )
102 {
103  const auto constTakeChildren = item->takeChildren();
104  for ( QTreeWidgetItem *child : constTakeChildren )
105  {
106  delete child;
107  }
108 }
109 
110 void QgsAuthTrustedCAsDialog::populateCaCertsView()
111 {
112  removeChildren_( mRootCaSecItem );
113 
114  if ( mTrustedCAs.isEmpty() )
115  {
116  mTrustedCAs = QgsApplication::authManager()->trustedCaCerts();
117  }
118 
119  populateCaCertsSection( mRootCaSecItem, mTrustedCAs, QgsAuthTrustedCAsDialog::CaCert );
120 }
121 
122 void QgsAuthTrustedCAsDialog::populateCaCertsSection( QTreeWidgetItem *item, const QList<QSslCertificate> &certs,
123  QgsAuthTrustedCAsDialog::CaType catype )
124 {
125  if ( btnGroupByOrg->isChecked() )
126  {
127  appendCertsToGroup( certs, catype, item );
128  }
129  else
130  {
131  appendCertsToItem( certs, catype, item );
132  }
133 }
134 
135 void QgsAuthTrustedCAsDialog::appendCertsToGroup( const QList<QSslCertificate> &certs,
136  QgsAuthTrustedCAsDialog::CaType catype,
137  QTreeWidgetItem *parent )
138 {
139  if ( certs.empty() )
140  return;
141 
142  if ( !parent )
143  {
144  parent = treeTrustedCAs->currentItem();
145  }
146 
147  // TODO: find all organizational name, sort and make subsections
148  const QMap< QString, QList<QSslCertificate> > orgcerts(
150 
151  QMap< QString, QList<QSslCertificate> >::const_iterator it = orgcerts.constBegin();
152  for ( ; it != orgcerts.constEnd(); ++it )
153  {
154  QTreeWidgetItem *grpitem( new QTreeWidgetItem( parent,
155  QStringList() << it.key(),
156  static_cast<int>( QgsAuthTrustedCAsDialog::OrgName ) ) );
157  grpitem->setFirstColumnSpanned( true );
158  grpitem->setFlags( Qt::ItemIsEnabled );
159  grpitem->setExpanded( true );
160 
161  QBrush orgb( grpitem->foreground( 0 ) );
162  orgb.setColor( QColor::fromRgb( 90, 90, 90 ) );
163  grpitem->setForeground( 0, orgb );
164  QFont grpf( grpitem->font( 0 ) );
165  grpf.setItalic( true );
166  grpitem->setFont( 0, grpf );
167 
168  appendCertsToItem( it.value(), catype, grpitem );
169  }
170 
171  parent->sortChildren( 0, Qt::AscendingOrder );
172 }
173 
174 void QgsAuthTrustedCAsDialog::appendCertsToItem( const QList<QSslCertificate> &certs,
175  QgsAuthTrustedCAsDialog::CaType catype,
176  QTreeWidgetItem *parent )
177 {
178  if ( certs.empty() )
179  return;
180 
181  if ( !parent )
182  {
183  parent = treeTrustedCAs->currentItem();
184  }
185 
186  const QBrush redb( QgsAuthGuiUtils::redColor() );
187 
188  // Columns: Common Name, Serial #, Expiry Date
189  const auto constCerts = certs;
190  for ( const QSslCertificate &cert : constCerts )
191  {
192  const QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
193 
194  QStringList coltxts;
195  coltxts << QgsAuthCertUtils::resolvedCertName( cert );
196  coltxts << QString( cert.serialNumber() );
197  coltxts << cert.expiryDate().toString();
198 
199  QTreeWidgetItem *item( new QTreeWidgetItem( parent, coltxts, static_cast<int>( catype ) ) );
200 
201  item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificate.svg" ) ) );
202  if ( !QgsAuthCertUtils::certIsViable( cert ) )
203  {
204  item->setForeground( 2, redb );
205  item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificateUntrusted.svg" ) ) );
206  }
207 
208  item->setData( 0, Qt::UserRole, id );
209  }
210 
211  parent->sortChildren( 0, Qt::AscendingOrder );
212 }
213 
214 void QgsAuthTrustedCAsDialog::showCertInfo( QTreeWidgetItem *item )
215 {
216  if ( !item )
217  return;
218 
219  const QString digest( item->data( 0, Qt::UserRole ).toString() );
220 
221  const QMap<QString, QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> > cacertscache(
222  QgsApplication::authManager()->caCertsCache() );
223 
224  if ( !cacertscache.contains( digest ) )
225  {
226  QgsDebugMsg( QStringLiteral( "Certificate Authority not in CA certs cache" ) );
227  return;
228  }
229 
230  const QSslCertificate cert( cacertscache.value( digest ).second );
231 
232  QgsAuthCertInfoDialog *dlg = new QgsAuthCertInfoDialog( cert, false, this );
233  dlg->setWindowModality( Qt::WindowModal );
234  dlg->resize( 675, 500 );
235  dlg->exec();
236  dlg->deleteLater();
237 }
238 
239 void QgsAuthTrustedCAsDialog::selectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
240 {
241  Q_UNUSED( selected )
242  Q_UNUSED( deselected )
243  checkSelection();
244 }
245 
246 void QgsAuthTrustedCAsDialog::checkSelection()
247 {
248  bool iscert = false;
249  if ( treeTrustedCAs->selectionModel()->selection().length() > 0 )
250  {
251  QTreeWidgetItem *item( treeTrustedCAs->currentItem() );
252 
253  switch ( ( QgsAuthTrustedCAsDialog::CaType )item->type() )
254  {
255  case QgsAuthTrustedCAsDialog::CaCert:
256  iscert = true;
257  break;
258  default:
259  break;
260  }
261  }
262 
263  btnInfoCa->setEnabled( iscert );
264 }
265 
266 void QgsAuthTrustedCAsDialog::handleDoubleClick( QTreeWidgetItem *item, int col )
267 {
268  Q_UNUSED( col )
269  bool iscert = true;
270 
271  switch ( ( QgsAuthTrustedCAsDialog::CaType )item->type() )
272  {
273  case QgsAuthTrustedCAsDialog::Section:
274  iscert = false;
275  break;
276  case QgsAuthTrustedCAsDialog::OrgName:
277  iscert = false;
278  break;
279  default:
280  break;
281  }
282 
283  if ( iscert )
284  {
285  showCertInfo( item );
286  }
287 }
288 
289 void QgsAuthTrustedCAsDialog::btnInfoCa_clicked()
290 {
291  if ( treeTrustedCAs->selectionModel()->selection().length() > 0 )
292  {
293  QTreeWidgetItem *item( treeTrustedCAs->currentItem() );
294  handleDoubleClick( item, 0 );
295  }
296 }
297 
298 void QgsAuthTrustedCAsDialog::btnGroupByOrg_toggled( bool checked )
299 {
300  if ( !QgsApplication::authManager()->storeAuthSetting( QStringLiteral( "trustedcasortby" ), QVariant( checked ) ) )
301  {
302  authMessageOut( QObject::tr( "Could not store sort by preference" ),
303  QObject::tr( "Trusted Authorities/Issuers" ),
305  }
306  populateCaCertsView();
307 }
308 
309 void QgsAuthTrustedCAsDialog::authMessageOut( const QString &message, const QString &authtag, QgsAuthManager::MessageLevel level )
310 {
311  const int levelint = static_cast<int>( level );
312  messageBar()->pushMessage( authtag, message, ( Qgis::MessageLevel )levelint, 7 );
313 }
314 
316 {
317  if ( !mDisabled )
318  {
319  treeTrustedCAs->setFocus();
320  }
321  QDialog::showEvent( e );
322 }
323 
324 QgsMessageBar *QgsAuthTrustedCAsDialog::messageBar()
325 {
326  return msgBar;
327 }
328 
329 int QgsAuthTrustedCAsDialog::messageTimeout()
330 {
331  const QgsSettings settings;
332  return settings.value( QStringLiteral( "qgis/messageTimeout" ), 5 ).toInt();
333 }
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition: qgis.h:106
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
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 resolvedCertName(const QSslCertificate &cert, bool issuer=false)
Gets the general name via RFC 5280 resolution.
static QMap< QString, QList< QSslCertificate > > certsGroupedByOrg(const QList< QSslCertificate > &certs)
Map certificates to their oraganization.
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Gets the sha1 hash for certificate.
static bool certIsViable(const QSslCertificate &cert)
certIsViable checks for viability errors of cert and whether it is NULL
static QColor redColor()
Red color representing invalid, untrusted, etc. certificate.
MessageLevel
Message log level (mirrors that of QgsMessageLog, so it can also output there)
void messageOut(const QString &message, const QString &tag=QgsAuthManager::AUTH_MAN_TAG, QgsAuthManager::MessageLevel level=QgsAuthManager::INFO) const
Custom logging signal to relay to console output and QgsMessageLog.
QVariant authSetting(const QString &key, const QVariant &defaultValue=QVariant(), bool decrypt=false)
authSetting get an authentication setting (retrieved as string and returned as QVariant( QString ))
const QList< QSslCertificate > trustedCaCerts(bool includeinvalid=false)
trustedCaCerts get list of all trusted CA certificates
void showEvent(QShowEvent *e) override
QgsAuthTrustedCAsDialog(QWidget *parent=nullptr, const QList< QSslCertificate > &trustedCAs=QList< QSslCertificate >())
Construct a dialog that will list the trusted Certificate Authorities.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38