QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 #include <QSettings>
23 
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  , mDisabled( false )
36  , mAuthNotifyLayout( nullptr )
37  , mAuthNotify( nullptr )
38  , mRootCertIdentItem( nullptr )
39 {
40  if ( QgsAuthManager::instance()->isDisabled() )
41  {
42  mDisabled = true;
43  mAuthNotifyLayout = new QVBoxLayout;
44  this->setLayout( mAuthNotifyLayout );
45  mAuthNotify = new QLabel( QgsAuthManager::instance()->disabledMessage(), this );
46  mAuthNotifyLayout->addWidget( mAuthNotify );
47  }
48  else
49  {
50  setupUi( this );
51 
52  connect( QgsAuthManager::instance(), SIGNAL( messageOut( const QString&, const QString&, QgsAuthManager::MessageLevel ) ),
53  this, SLOT( authMessageOut( const QString&, const QString&, QgsAuthManager::MessageLevel ) ) );
54 
55  connect( QgsAuthManager::instance(), SIGNAL( authDatabaseChanged() ),
56  this, SLOT( refreshIdentitiesView() ) );
57 
58  setupIdentitiesTree();
59 
60  connect( treeIdentities->selectionModel(), SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
61  this, SLOT( selectionChanged( const QItemSelection&, const QItemSelection& ) ) );
62 
63  connect( treeIdentities, SIGNAL( itemDoubleClicked( QTreeWidgetItem *, int ) ),
64  this, SLOT( handleDoubleClick( QTreeWidgetItem *, int ) ) );
65 
66  connect( btnViewRefresh, SIGNAL( clicked() ), this, SLOT( refreshIdentitiesView() ) );
67 
68  btnGroupByOrg->setChecked( false );
69  QVariant sortbyval = QgsAuthManager::instance()->getAuthSetting( QString( "identitiessortby" ), QVariant( false ) );
70  if ( !sortbyval.isNull() )
71  btnGroupByOrg->setChecked( sortbyval.toBool() );
72 
73  populateIdentitiesView();
74  checkSelection();
75  }
76 }
77 
79 {
80 }
81 
82 static void setItemBold_( QTreeWidgetItem* item )
83 {
84  item->setFirstColumnSpanned( true );
85  QFont secf( item->font( 0 ) );
86  secf.setBold( true );
87  item->setFont( 0, secf );
88 }
89 
90 void QgsAuthIdentitiesEditor::setupIdentitiesTree()
91 {
92  treeIdentities->setColumnCount( 3 );
93  treeIdentities->setHeaderLabels(
94  QStringList() << tr( "Common Name" )
95  << tr( "Serial #" )
96  << tr( "Expiry Date" ) );
97  treeIdentities->setColumnWidth( 0, 300 );
98  treeIdentities->setColumnWidth( 1, 75 );
99 
100  // add root sections
101  mRootCertIdentItem = new QTreeWidgetItem(
102  treeIdentities,
103  QStringList( tr( "Certificate Bundles" ) ),
104  ( int )QgsAuthIdentitiesEditor::Section );
105  setItemBold_( mRootCertIdentItem );
106  mRootCertIdentItem->setFlags( Qt::ItemIsEnabled );
107  mRootCertIdentItem->setExpanded( true );
108  treeIdentities->insertTopLevelItem( 0, mRootCertIdentItem );
109 }
110 
111 static void removeChildren_( QTreeWidgetItem* item )
112 {
113  Q_FOREACH ( QTreeWidgetItem* child, item->takeChildren() )
114  {
115  delete child;
116  }
117 }
118 
119 void QgsAuthIdentitiesEditor::populateIdentitiesView()
120 {
121  removeChildren_( mRootCertIdentItem );
122 
123  populateIdentitiesSection( mRootCertIdentItem,
124  QgsAuthManager::instance()->getCertIdentities(),
125  QgsAuthIdentitiesEditor::CertIdentity );
126 }
127 
128 void QgsAuthIdentitiesEditor::refreshIdentitiesView()
129 {
130  populateIdentitiesView();
131 }
132 
133 void QgsAuthIdentitiesEditor::populateIdentitiesSection( QTreeWidgetItem *item, const QList<QSslCertificate>& certs,
134  QgsAuthIdentitiesEditor::IdentityType identype )
135 {
136  if ( btnGroupByOrg->isChecked() )
137  {
138  appendIdentitiesToGroup( certs, identype, item );
139  }
140  else
141  {
142  appendIdentitiesToItem( certs, identype, item );
143  }
144 }
145 
146 void QgsAuthIdentitiesEditor::appendIdentitiesToGroup( const QList<QSslCertificate>& certs,
147  QgsAuthIdentitiesEditor::IdentityType identype,
149 {
150  if ( certs.size() < 1 )
151  return;
152 
153  if ( !parent )
154  {
155  parent = treeIdentities->currentItem();
156  }
157 
158  // TODO: find all organizational name, sort and make subsections
161 
162  QMap< QString, QList<QSslCertificate> >::const_iterator it = orgcerts.constBegin();
163  for ( ; it != orgcerts.constEnd(); ++it )
164  {
165  QTreeWidgetItem * grpitem( new QTreeWidgetItem( parent,
166  QStringList() << it.key(),
167  ( int )QgsAuthIdentitiesEditor::OrgName ) );
168  grpitem->setFirstColumnSpanned( true );
169  grpitem->setFlags( Qt::ItemIsEnabled );
170  grpitem->setExpanded( true );
171 
172  QBrush orgb( grpitem->foreground( 0 ) );
173  orgb.setColor( QColor::fromRgb( 90, 90, 90 ) );
174  grpitem->setForeground( 0, orgb );
175  QFont grpf( grpitem->font( 0 ) );
176  grpf.setItalic( true );
177  grpitem->setFont( 0, grpf );
178 
179  appendIdentitiesToItem( it.value(), identype, grpitem );
180  }
181 
182  parent->sortChildren( 0, Qt::AscendingOrder );
183 }
184 
185 void QgsAuthIdentitiesEditor::appendIdentitiesToItem( const QList<QSslCertificate>& certs,
186  QgsAuthIdentitiesEditor::IdentityType identype,
187  QTreeWidgetItem *parent )
188 {
189  if ( certs.size() < 1 )
190  return;
191 
192  if ( !parent )
193  {
194  parent = treeIdentities->currentItem();
195  }
196 
198 
199  // Columns: Common Name, Serial #, Expiry Date
200  Q_FOREACH ( const QSslCertificate& cert, certs )
201  {
203 
204  QStringList coltxts;
205  coltxts << QgsAuthCertUtils::resolvedCertName( cert );
206  coltxts << QString( cert.serialNumber() );
207  coltxts << cert.expiryDate().toString();
208 
209  QTreeWidgetItem * item( new QTreeWidgetItem( parent, coltxts, ( int )identype ) );
210 
211  item->setIcon( 0, QgsApplication::getThemeIcon( "/mIconCertificate.svg" ) );
212  if ( !cert.isValid() )
213  {
214  item->setForeground( 2, redb );
215  item->setIcon( 0, QgsApplication::getThemeIcon( "/mIconCertificateUntrusted.svg" ) );
216  }
217 
218  item->setData( 0, Qt::UserRole, id );
219  }
220 
221  parent->sortChildren( 0, Qt::AscendingOrder );
222 }
223 
224 void QgsAuthIdentitiesEditor::showCertInfo( QTreeWidgetItem *item )
225 {
226  if ( !item )
227  return;
228 
229  QString digest( item->data( 0, Qt::UserRole ).toString() );
230 
231  if ( !QgsAuthManager::instance()->existsCertIdentity( digest ) )
232  {
233  QgsDebugMsg( "Certificate identity does not exist in database" );
234  return;
235  }
236 
237  QSslCertificate cert( QgsAuthManager::instance()->getCertIdentity( digest ) );
238 
239  QgsAuthCertInfoDialog * dlg = new QgsAuthCertInfoDialog( cert, false, this );
240  dlg->setWindowModality( Qt::WindowModal );
241  dlg->resize( 675, 500 );
242  dlg->exec();
243  dlg->deleteLater();
244 }
245 
246 void QgsAuthIdentitiesEditor::selectionChanged( const QItemSelection& selected , const QItemSelection& deselected )
247 {
248  Q_UNUSED( selected );
249  Q_UNUSED( deselected );
250  checkSelection();
251 }
252 
253 void QgsAuthIdentitiesEditor::checkSelection()
254 {
255  bool iscert = false;
256  if ( treeIdentities->selectionModel()->selection().length() > 0 )
257  {
258  QTreeWidgetItem* item( treeIdentities->currentItem() );
259 
260  switch (( QgsAuthIdentitiesEditor::IdentityType )item->type() )
261  {
262  case QgsAuthIdentitiesEditor::CertIdentity:
263  iscert = true;
264  break;
265  default:
266  break;
267  }
268  }
269 
270  btnRemoveIdentity->setEnabled( iscert );
271  btnInfoIdentity->setEnabled( iscert );
272 }
273 
274 void QgsAuthIdentitiesEditor::handleDoubleClick( QTreeWidgetItem *item, int col )
275 {
276  Q_UNUSED( col );
277  bool iscert = true;
278 
279  switch (( QgsAuthIdentitiesEditor::IdentityType )item->type() )
280  {
281  case QgsAuthIdentitiesEditor::Section:
282  iscert = false;
283  break;
284  case QgsAuthIdentitiesEditor::OrgName:
285  iscert = false;
286  break;
287  default:
288  break;
289  }
290 
291  if ( iscert )
292  {
293  showCertInfo( item );
294  }
295 }
296 
297 void QgsAuthIdentitiesEditor::on_btnAddIdentity_clicked()
298 {
300  dlg->setWindowModality( Qt::WindowModal );
301  dlg->resize( 400, dlg->height() );
302  if ( dlg->exec() )
303  {
305  {
306  const QPair<QSslCertificate, QSslKey>& bundle( dlg->certBundleToImport() );
307  if ( !QgsAuthManager::instance()->storeCertIdentity( bundle.first, bundle.second ) )
308  {
309  messageBar()->pushMessage( tr( "ERROR storing identity bundle in authentication database" ),
311  }
312  populateIdentitiesView();
313  mRootCertIdentItem->setExpanded( true );
314  }
315  }
316  dlg->deleteLater();
317 }
318 
319 void QgsAuthIdentitiesEditor::on_btnRemoveIdentity_clicked()
320 {
321  QTreeWidgetItem* item( treeIdentities->currentItem() );
322 
323  if ( !item )
324  {
325  QgsDebugMsg( "Current tree widget item not set" );
326  return;
327  }
328 
329  QString digest( item->data( 0, Qt::UserRole ).toString() );
330 
331  if ( digest.isEmpty() )
332  {
333  messageBar()->pushMessage( tr( "Certificate id missing" ),
335  return;
336  }
337 
338  if ( !QgsAuthManager::instance()->existsCertIdentity( digest ) )
339  {
340  QgsDebugMsg( "Certificate identity does not exist in database" );
341  return;
342  }
343 
345  this, tr( "Remove Certificate Identity" ),
346  tr( "Are you sure you want to remove the selected "
347  "certificate identity from the database?\n\n"
348  "Operation can NOT be undone!" ),
349  QMessageBox::Ok | QMessageBox::Cancel,
350  QMessageBox::Cancel ) == QMessageBox::Cancel )
351  {
352  return;
353  }
354 
355  if ( !QgsAuthManager::instance()->removeCertIdentity( digest ) )
356  {
357  messageBar()->pushMessage( tr( "ERROR removing cert identity from authentication database for id %1:" ).arg( digest ),
359  return;
360  }
361 
362  item->parent()->removeChild( item );
363  delete item;
364 }
365 
366 void QgsAuthIdentitiesEditor::on_btnInfoIdentity_clicked()
367 {
368  if ( treeIdentities->selectionModel()->selection().length() > 0 )
369  {
370  QTreeWidgetItem* item( treeIdentities->currentItem() );
371  handleDoubleClick( item, 0 );
372  }
373 }
374 
375 void QgsAuthIdentitiesEditor::on_btnGroupByOrg_toggled( bool checked )
376 {
377  if ( !QgsAuthManager::instance()->storeAuthSetting( QString( "identitiessortby" ), QVariant( checked ) ) )
378  {
379  authMessageOut( QObject::tr( "Could not store sort by preference" ),
380  QObject::tr( "Authentication Identities" ),
382  }
383  populateIdentitiesView();
384 }
385 
386 void QgsAuthIdentitiesEditor::authMessageOut( const QString& message, const QString& authtag, QgsAuthManager::MessageLevel level )
387 {
388  int levelint = ( int )level;
389  messageBar()->pushMessage( authtag, message, ( QgsMessageBar::MessageLevel )levelint, 7 );
390 }
391 
393 {
394  if ( !mDisabled )
395  {
396  treeIdentities->setFocus();
397  }
398  QWidget::showEvent( e );
399 }
400 
401 QgsMessageBar * QgsAuthIdentitiesEditor::messageBar()
402 {
403  return msgBar;
404 }
405 
406 int QgsAuthIdentitiesEditor::messageTimeout()
407 {
408  QSettings settings;
409  return settings.value( "/qgis/messageTimeout", 5 ).toInt();
410 }
QObject * child(const char *objName, const char *inheritsClass, bool recursiveSearch) const
QString toString(Qt::DateFormat format) const
void setupUi(QWidget *widget)
static QgsAuthManager * instance()
Enforce singleton pattern.
bool isValid() const
void setWindowModality(Qt::WindowModality windowModality)
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void setFont(int column, const QFont &font)
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
const_iterator constBegin() const
void setIcon(int column, const QIcon &icon)
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:42
int exec()
void setFirstColumnSpanned(bool span)
virtual void setData(int column, int role, const QVariant &value)
Widget for importing an identity certificate/key bundle into the authentication database.
QgsAuthImportIdentityDialog::IdentityType identityType()
Get identity type.
virtual QVariant data(int column, int role) const
QString tr(const char *sourceText, const char *disambiguation, int n)
MessageLevel
Message log level (mirrors that of QgsMessageLog, so it can also output there)
int size() const
QVariant getAuthSetting(const QString &key, const QVariant &defaultValue=QVariant(), bool decrypt=false)
Get an authentication setting (retrieved as string and returned as QVariant( QString )) ...
void sortChildren(int column, Qt::SortOrder order)
void setBold(bool enable)
void resize(int w, int h)
void setFlags(QFlags< Qt::ItemFlag > flags)
QColor fromRgb(QRgb rgb)
void pushMessage(const QString &text, MessageLevel level=INFO, int duration=5)
convenience method for pushing a message to the bar
Definition: qgsmessagebar.h:90
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
virtual void showEvent(QShowEvent *event)
static QColor redColor()
Red color representing invalid, untrusted, etc.
static void removeChildren_(QTreeWidgetItem *item)
Dialog wrapper for widget displaying detailed info on a certificate and its hierarchical trust chain...
void setLayout(QLayout *layout)
void removeChild(QTreeWidgetItem *child)
int toInt(bool *ok) const
bool isNull() const
void showEvent(QShowEvent *e) override
Overridden show event of base widget.
QList< QTreeWidgetItem * > takeChildren()
const_iterator constEnd() const
QFont font(int column) const
bool storeCertIdentity(const QSslCertificate &cert, const QSslKey &key)
Store a certificate identity.
void deleteLater()
QTreeWidgetItem * parent() const
void setItalic(bool enable)
const Key key(const T &value) const
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Get the sha1 hash for certificate.
QVariant value(const QString &key, const QVariant &defaultValue) const
QByteArray serialNumber() const
void setExpanded(bool expand)
QDateTime expiryDate() const
static void setItemBold_(QTreeWidgetItem *item)
bool toBool() const
StandardButton warning(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
static QMap< QString, QList< QSslCertificate > > certsGroupedByOrg(const QList< QSslCertificate > &certs)
Map certificates to their oraganization.
int type() const
bool existsCertIdentity(const QString &id)
Check if a certificate identity exists.
const QPair< QSslCertificate, QSslKey > certBundleToImport()
Get certificate/key bundle to be imported.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
void setColor(const QColor &color)
QString toString() const
static QString resolvedCertName(const QSslCertificate &cert, bool issuer=false)
Get the general name via RFC 5280 resolution.
void setForeground(int column, const QBrush &brush)
QgsAuthIdentitiesEditor(QWidget *parent=nullptr)
Widget for editing authentication configurations directly in database.
const T value(const Key &key) const