QGIS API Documentation  3.2.0-Bonn (bc43194)
qgsauthidentitieseditor.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsauthidentitieseditor.cpp
3  ---------------------
4  begin : April 26, 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_qgsauthidentitieseditor.h"
19 
20 #include <QMenu>
21 #include <QMessageBox>
22 
23 #include "qgssettings.h"
24 #include "qgsapplication.h"
25 #include "qgsauthcertificateinfo.h"
26 #include "qgsauthcertutils.h"
28 #include "qgsauthmanager.h"
29 #include "qgsauthguiutils.h"
30 #include "qgslogger.h"
31 
32 
34  : QWidget( parent )
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( btnAddIdentity, &QToolButton::clicked, this, &QgsAuthIdentitiesEditor::btnAddIdentity_clicked );
48  connect( btnRemoveIdentity, &QToolButton::clicked, this, &QgsAuthIdentitiesEditor::btnRemoveIdentity_clicked );
49  connect( btnInfoIdentity, &QToolButton::clicked, this, &QgsAuthIdentitiesEditor::btnInfoIdentity_clicked );
50  connect( btnGroupByOrg, &QToolButton::toggled, this, &QgsAuthIdentitiesEditor::btnGroupByOrg_toggled );
51 
53  this, &QgsAuthIdentitiesEditor::authMessageOut );
54 
56  this, &QgsAuthIdentitiesEditor::refreshIdentitiesView );
57 
58  setupIdentitiesTree();
59 
60  connect( treeIdentities->selectionModel(), &QItemSelectionModel::selectionChanged,
61  this, &QgsAuthIdentitiesEditor::selectionChanged );
62 
63  connect( treeIdentities, &QTreeWidget::itemDoubleClicked,
64  this, &QgsAuthIdentitiesEditor::handleDoubleClick );
65 
66  connect( btnViewRefresh, &QAbstractButton::clicked, this, &QgsAuthIdentitiesEditor::refreshIdentitiesView );
67 
68  btnGroupByOrg->setChecked( false );
69  QVariant sortbyval = QgsApplication::authManager()->authSetting( QStringLiteral( "identitiessortby" ), QVariant( false ) );
70  if ( !sortbyval.isNull() )
71  btnGroupByOrg->setChecked( sortbyval.toBool() );
72 
73  populateIdentitiesView();
74  checkSelection();
75  }
76 }
77 
78 static void setItemBold_( QTreeWidgetItem *item )
79 {
80  item->setFirstColumnSpanned( true );
81  QFont secf( item->font( 0 ) );
82  secf.setBold( true );
83  item->setFont( 0, secf );
84 }
85 
86 void QgsAuthIdentitiesEditor::setupIdentitiesTree()
87 {
88  treeIdentities->setColumnCount( 3 );
89  treeIdentities->setHeaderLabels(
90  QStringList() << tr( "Common Name" )
91  << tr( "Serial #" )
92  << tr( "Expiry Date" ) );
93  treeIdentities->setColumnWidth( 0, 300 );
94  treeIdentities->setColumnWidth( 1, 75 );
95 
96  // add root sections
97  mRootCertIdentItem = new QTreeWidgetItem(
98  treeIdentities,
99  QStringList( tr( "Certificate Bundles" ) ),
100  ( int )QgsAuthIdentitiesEditor::Section );
101  setItemBold_( mRootCertIdentItem );
102  mRootCertIdentItem->setFlags( Qt::ItemIsEnabled );
103  mRootCertIdentItem->setExpanded( true );
104  treeIdentities->insertTopLevelItem( 0, mRootCertIdentItem );
105 }
106 
107 static void removeChildren_( QTreeWidgetItem *item )
108 {
109  Q_FOREACH ( QTreeWidgetItem *child, item->takeChildren() )
110  {
111  delete child;
112  }
113 }
114 
115 void QgsAuthIdentitiesEditor::populateIdentitiesView()
116 {
117  removeChildren_( mRootCertIdentItem );
118 
119  populateIdentitiesSection( mRootCertIdentItem,
120  QgsApplication::authManager()->certIdentities(),
121  QgsAuthIdentitiesEditor::CertIdentity );
122 }
123 
124 void QgsAuthIdentitiesEditor::refreshIdentitiesView()
125 {
126  populateIdentitiesView();
127 }
128 
129 void QgsAuthIdentitiesEditor::populateIdentitiesSection( QTreeWidgetItem *item, const QList<QSslCertificate> &certs,
130  QgsAuthIdentitiesEditor::IdentityType identype )
131 {
132  if ( btnGroupByOrg->isChecked() )
133  {
134  appendIdentitiesToGroup( certs, identype, item );
135  }
136  else
137  {
138  appendIdentitiesToItem( certs, identype, item );
139  }
140 }
141 
142 void QgsAuthIdentitiesEditor::appendIdentitiesToGroup( const QList<QSslCertificate> &certs,
143  QgsAuthIdentitiesEditor::IdentityType identype,
144  QTreeWidgetItem *parent )
145 {
146  if ( certs.empty() )
147  return;
148 
149  if ( !parent )
150  {
151  parent = treeIdentities->currentItem();
152  }
153 
154  // TODO: find all organizational name, sort and make subsections
155  QMap< QString, QList<QSslCertificate> > orgcerts(
157 
158  QMap< QString, QList<QSslCertificate> >::const_iterator it = orgcerts.constBegin();
159  for ( ; it != orgcerts.constEnd(); ++it )
160  {
161  QTreeWidgetItem *grpitem( new QTreeWidgetItem( parent,
162  QStringList() << it.key(),
163  ( int )QgsAuthIdentitiesEditor::OrgName ) );
164  grpitem->setFirstColumnSpanned( true );
165  grpitem->setFlags( Qt::ItemIsEnabled );
166  grpitem->setExpanded( true );
167 
168  QBrush orgb( grpitem->foreground( 0 ) );
169  orgb.setColor( QColor::fromRgb( 90, 90, 90 ) );
170  grpitem->setForeground( 0, orgb );
171  QFont grpf( grpitem->font( 0 ) );
172  grpf.setItalic( true );
173  grpitem->setFont( 0, grpf );
174 
175  appendIdentitiesToItem( it.value(), identype, grpitem );
176  }
177 
178  parent->sortChildren( 0, Qt::AscendingOrder );
179 }
180 
181 void QgsAuthIdentitiesEditor::appendIdentitiesToItem( const QList<QSslCertificate> &certs,
182  QgsAuthIdentitiesEditor::IdentityType identype,
183  QTreeWidgetItem *parent )
184 {
185  if ( certs.empty() )
186  return;
187 
188  if ( !parent )
189  {
190  parent = treeIdentities->currentItem();
191  }
192 
193  QBrush redb( QgsAuthGuiUtils::redColor() );
194 
195  // Columns: Common Name, Serial #, Expiry Date
196  Q_FOREACH ( const QSslCertificate &cert, certs )
197  {
198  QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
199 
200  QStringList coltxts;
201  coltxts << QgsAuthCertUtils::resolvedCertName( cert );
202  coltxts << QString( cert.serialNumber() );
203  coltxts << cert.expiryDate().toString();
204 
205  QTreeWidgetItem *item( new QTreeWidgetItem( parent, coltxts, ( int )identype ) );
206 
207  item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificate.svg" ) ) );
208  if ( !QgsAuthCertUtils::certIsViable( cert ) )
209  {
210  item->setForeground( 2, redb );
211  item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificateUntrusted.svg" ) ) );
212  }
213 
214  item->setData( 0, Qt::UserRole, id );
215  }
216 
217  parent->sortChildren( 0, Qt::AscendingOrder );
218 }
219 
220 void QgsAuthIdentitiesEditor::showCertInfo( QTreeWidgetItem *item )
221 {
222  if ( !item )
223  return;
224 
225  QString digest( item->data( 0, Qt::UserRole ).toString() );
226 
228  {
229  QgsDebugMsg( "Certificate identity does not exist in database" );
230  return;
231  }
232 
233  QSslCertificate cert( QgsApplication::authManager()->certIdentity( digest ) );
234 
235  QgsAuthCertInfoDialog *dlg = new QgsAuthCertInfoDialog( cert, false, this );
236  dlg->setWindowModality( Qt::WindowModal );
237  dlg->resize( 675, 500 );
238  dlg->exec();
239  dlg->deleteLater();
240 }
241 
242 void QgsAuthIdentitiesEditor::selectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
243 {
244  Q_UNUSED( selected );
245  Q_UNUSED( deselected );
246  checkSelection();
247 }
248 
249 void QgsAuthIdentitiesEditor::checkSelection()
250 {
251  bool iscert = false;
252  if ( treeIdentities->selectionModel()->selection().length() > 0 )
253  {
254  QTreeWidgetItem *item( treeIdentities->currentItem() );
255 
256  switch ( ( QgsAuthIdentitiesEditor::IdentityType )item->type() )
257  {
258  case QgsAuthIdentitiesEditor::CertIdentity:
259  iscert = true;
260  break;
261  default:
262  break;
263  }
264  }
265 
266  btnRemoveIdentity->setEnabled( iscert );
267  btnInfoIdentity->setEnabled( iscert );
268 }
269 
270 void QgsAuthIdentitiesEditor::handleDoubleClick( QTreeWidgetItem *item, int col )
271 {
272  Q_UNUSED( col );
273  bool iscert = true;
274 
275  switch ( ( QgsAuthIdentitiesEditor::IdentityType )item->type() )
276  {
277  case QgsAuthIdentitiesEditor::Section:
278  iscert = false;
279  break;
280  case QgsAuthIdentitiesEditor::OrgName:
281  iscert = false;
282  break;
283  default:
284  break;
285  }
286 
287  if ( iscert )
288  {
289  showCertInfo( item );
290  }
291 }
292 
293 void QgsAuthIdentitiesEditor::btnAddIdentity_clicked()
294 {
296  dlg->setWindowModality( Qt::WindowModal );
297  dlg->resize( 400, dlg->height() );
298  if ( dlg->exec() )
299  {
301  {
302  const QPair<QSslCertificate, QSslKey> &bundle( dlg->certBundleToImport() );
303  if ( !QgsApplication::authManager()->storeCertIdentity( bundle.first, bundle.second ) )
304  {
305  messageBar()->pushMessage( tr( "ERROR storing identity bundle in authentication database." ),
306  Qgis::Critical );
307  }
308  populateIdentitiesView();
309  mRootCertIdentItem->setExpanded( true );
310  }
311  }
312  dlg->deleteLater();
313 }
314 
315 void QgsAuthIdentitiesEditor::btnRemoveIdentity_clicked()
316 {
317  QTreeWidgetItem *item( treeIdentities->currentItem() );
318 
319  if ( !item )
320  {
321  QgsDebugMsg( "Current tree widget item not set" );
322  return;
323  }
324 
325  QString digest( item->data( 0, Qt::UserRole ).toString() );
326 
327  if ( digest.isEmpty() )
328  {
329  messageBar()->pushMessage( tr( "Certificate id missing." ),
330  Qgis::Warning );
331  return;
332  }
333 
334  if ( !QgsApplication::authManager()->existsCertIdentity( digest ) )
335  {
336  QgsDebugMsg( "Certificate identity does not exist in database" );
337  return;
338  }
339 
340  if ( QMessageBox::warning(
341  this, tr( "Remove Certificate Identity" ),
342  tr( "Are you sure you want to remove the selected "
343  "certificate identity from the database?\n\n"
344  "Operation can NOT be undone!" ),
345  QMessageBox::Ok | QMessageBox::Cancel,
346  QMessageBox::Cancel ) == QMessageBox::Cancel )
347  {
348  return;
349  }
350 
351  if ( !QgsApplication::authManager()->removeCertIdentity( digest ) )
352  {
353  messageBar()->pushMessage( tr( "ERROR removing cert identity from authentication database for id %1:" ).arg( digest ),
354  Qgis::Critical );
355  return;
356  }
357 
358  item->parent()->removeChild( item );
359  delete item;
360 }
361 
362 void QgsAuthIdentitiesEditor::btnInfoIdentity_clicked()
363 {
364  if ( treeIdentities->selectionModel()->selection().length() > 0 )
365  {
366  QTreeWidgetItem *item( treeIdentities->currentItem() );
367  handleDoubleClick( item, 0 );
368  }
369 }
370 
371 void QgsAuthIdentitiesEditor::btnGroupByOrg_toggled( bool checked )
372 {
373  if ( !QgsApplication::authManager()->storeAuthSetting( QStringLiteral( "identitiessortby" ), QVariant( checked ) ) )
374  {
375  authMessageOut( QObject::tr( "Could not store sort by preference." ),
376  QObject::tr( "Authentication Identities" ),
378  }
379  populateIdentitiesView();
380 }
381 
382 void QgsAuthIdentitiesEditor::authMessageOut( const QString &message, const QString &authtag, QgsAuthManager::MessageLevel level )
383 {
384  int levelint = ( int )level;
385  messageBar()->pushMessage( authtag, message, ( Qgis::MessageLevel )levelint, 7 );
386 }
387 
389 {
390  if ( !mDisabled )
391  {
392  treeIdentities->setFocus();
393  }
394  QWidget::showEvent( e );
395 }
396 
397 QgsMessageBar *QgsAuthIdentitiesEditor::messageBar()
398 {
399  return msgBar;
400 }
401 
402 int QgsAuthIdentitiesEditor::messageTimeout()
403 {
404  QgsSettings settings;
405  return settings.value( QStringLiteral( "qgis/messageTimeout" ), 5 ).toInt();
406 }
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.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
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
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:45
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Widget for importing an identity certificate/key bundle into the authentication database.
QgsAuthImportIdentityDialog::IdentityType identityType()
Gets identity type.
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition: qgis.h:78
MessageLevel
Message log level (mirrors that of QgsMessageLog, so it can also output there)
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.
Dialog wrapper for widget displaying detailed info on a certificate and its hierarchical trust chain...
void showEvent(QShowEvent *e) override
Overridden show event of base widget.
bool storeCertIdentity(const QSslCertificate &cert, const QSslKey &key)
Store a certificate identity.
void authDatabaseChanged()
Emitted when the authentication db is significantly changed, e.g. large record removal, erased, etc.
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::Info, int duration=5)
convenience method for pushing a message to the bar
Definition: qgsmessagebar.h:88
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.
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 )) ...
static QMap< QString, QList< QSslCertificate > > certsGroupedByOrg(const QList< QSslCertificate > &certs)
Map certificates to their oraganization.
bool existsCertIdentity(const QString &id)
Check if a certificate identity exists.
const QPair< QSslCertificate, QSslKey > certBundleToImport()
Gets certificate/key bundle to be imported.
static QString resolvedCertName(const QSslCertificate &cert, bool issuer=false)
Gets the general name via RFC 5280 resolution.
QgsAuthIdentitiesEditor(QWidget *parent=nullptr)
Widget for editing authentication configurations directly in database.