QGIS API Documentation  3.2.0-Bonn (bc43194)
qgsauthserverseditor.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsauthserverseditor.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 
17 #include "qgsauthserverseditor.h"
18 #include "ui_qgsauthserverseditor.h"
19 #include "qgsauthsslimportdialog.h"
20 
21 #include <QMenu>
22 #include <QMessageBox>
23 
24 #include "qgssettings.h"
25 #include "qgsapplication.h"
26 #include "qgsauthcertificateinfo.h"
27 #include "qgsauthcertutils.h"
28 #include "qgsauthmanager.h"
29 #include "qgsauthguiutils.h"
30 #include "qgslogger.h"
31 
33  : QWidget( parent )
34 {
35  if ( QgsApplication::authManager()->isDisabled() )
36  {
37  mDisabled = true;
38  mAuthNotifyLayout = new QVBoxLayout;
39  this->setLayout( mAuthNotifyLayout );
40  mAuthNotify = new QLabel( QgsApplication::authManager()->disabledMessage(), this );
41  mAuthNotifyLayout->addWidget( mAuthNotify );
42  }
43  else
44  {
45  setupUi( this );
46  connect( btnAddServer, &QToolButton::clicked, this, &QgsAuthServersEditor::btnAddServer_clicked );
47  connect( btnRemoveServer, &QToolButton::clicked, this, &QgsAuthServersEditor::btnRemoveServer_clicked );
48  connect( btnEditServer, &QToolButton::clicked, this, &QgsAuthServersEditor::btnEditServer_clicked );
49  connect( btnGroupByOrg, &QToolButton::toggled, this, &QgsAuthServersEditor::btnGroupByOrg_toggled );
50 
52  this, &QgsAuthServersEditor::authMessageOut );
53 
55  this, &QgsAuthServersEditor::refreshSslConfigsView );
56 
57  setupSslConfigsTree();
58 
59  connect( treeServerConfigs->selectionModel(), &QItemSelectionModel::selectionChanged,
60  this, &QgsAuthServersEditor::selectionChanged );
61 
62  connect( treeServerConfigs, &QTreeWidget::itemDoubleClicked,
63  this, &QgsAuthServersEditor::handleDoubleClick );
64 
65  connect( btnViewRefresh, &QAbstractButton::clicked, this, &QgsAuthServersEditor::refreshSslConfigsView );
66 
67  btnGroupByOrg->setChecked( false );
68  QVariant sortbyval = QgsApplication::authManager()->authSetting( QStringLiteral( "serverssortby" ), QVariant( false ) );
69  if ( !sortbyval.isNull() )
70  btnGroupByOrg->setChecked( sortbyval.toBool() );
71 
72  populateSslConfigsView();
73  checkSelection();
74  }
75 }
76 
77 static void setItemBold_( QTreeWidgetItem *item )
78 {
79  item->setFirstColumnSpanned( true );
80  QFont secf( item->font( 0 ) );
81  secf.setBold( true );
82  item->setFont( 0, secf );
83 }
84 
85 
86 void QgsAuthServersEditor::setupSslConfigsTree()
87 {
88  treeServerConfigs->setColumnCount( 3 );
89  treeServerConfigs->setHeaderLabels(
90  QStringList() << tr( "Common Name" )
91  << tr( "Host" )
92  << tr( "Expiry Date" ) );
93  treeServerConfigs->setColumnWidth( 0, 275 );
94  treeServerConfigs->setColumnWidth( 1, 200 );
95 
96  // add root sections
97  mRootSslConfigItem = new QTreeWidgetItem(
98  treeServerConfigs,
99  QStringList( tr( "SSL Server Configurations" ) ),
100  ( int )QgsAuthServersEditor::Section );
101  setItemBold_( mRootSslConfigItem );
102  mRootSslConfigItem->setFlags( Qt::ItemIsEnabled );
103  mRootSslConfigItem->setExpanded( true );
104  treeServerConfigs->insertTopLevelItem( 0, mRootSslConfigItem );
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 QgsAuthServersEditor::populateSslConfigsView()
116 {
117  removeChildren_( mRootSslConfigItem );
118 
119  populateSslConfigsSection( mRootSslConfigItem,
120  QgsApplication::authManager()->sslCertCustomConfigs(),
121  QgsAuthServersEditor::ServerConfig );
122 }
123 
124 void QgsAuthServersEditor::refreshSslConfigsView()
125 {
126  populateSslConfigsView();
127 }
128 
129 void QgsAuthServersEditor::populateSslConfigsSection( QTreeWidgetItem *item,
130  const QList<QgsAuthConfigSslServer> &configs,
131  QgsAuthServersEditor::ConfigType conftype )
132 {
133  if ( btnGroupByOrg->isChecked() )
134  {
135  appendSslConfigsToGroup( configs, conftype, item );
136  }
137  else
138  {
139  appendSslConfigsToItem( configs, conftype, item );
140  }
141 }
142 
143 void QgsAuthServersEditor::appendSslConfigsToGroup( const QList<QgsAuthConfigSslServer> &configs,
144  QgsAuthServersEditor::ConfigType conftype,
145  QTreeWidgetItem *parent )
146 {
147  if ( configs.empty() )
148  return;
149 
150  if ( !parent )
151  {
152  parent = treeServerConfigs->currentItem();
153  }
154 
155  // TODO: find all organizational name, sort and make subsections
156  QMap< QString, QList<QgsAuthConfigSslServer> > orgconfigs(
158 
159  QMap< QString, QList<QgsAuthConfigSslServer> >::const_iterator it = orgconfigs.constBegin();
160  for ( ; it != orgconfigs.constEnd(); ++it )
161  {
162  QTreeWidgetItem *grpitem( new QTreeWidgetItem( parent,
163  QStringList() << it.key(),
164  ( int )QgsAuthServersEditor::OrgName ) );
165  grpitem->setFirstColumnSpanned( true );
166  grpitem->setFlags( Qt::ItemIsEnabled );
167  grpitem->setExpanded( true );
168 
169  QBrush orgb( grpitem->foreground( 0 ) );
170  orgb.setColor( QColor::fromRgb( 90, 90, 90 ) );
171  grpitem->setForeground( 0, orgb );
172  QFont grpf( grpitem->font( 0 ) );
173  grpf.setItalic( true );
174  grpitem->setFont( 0, grpf );
175 
176  appendSslConfigsToItem( it.value(), conftype, grpitem );
177  }
178 
179  parent->sortChildren( 0, Qt::AscendingOrder );
180 }
181 
182 void QgsAuthServersEditor::appendSslConfigsToItem( const QList<QgsAuthConfigSslServer> &configs,
183  QgsAuthServersEditor::ConfigType conftype,
184  QTreeWidgetItem *parent )
185 {
186  if ( configs.empty() )
187  return;
188 
189  if ( !parent )
190  {
191  parent = treeServerConfigs->currentItem();
192  }
193 
194  QBrush redb( QgsAuthGuiUtils::redColor() );
195 
196  // Columns: Common Name, Host, Expiry Date
197  Q_FOREACH ( const QgsAuthConfigSslServer &config, configs )
198  {
199  QSslCertificate cert( config.sslCertificate() );
200  QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
201 
202  QStringList coltxts;
203  coltxts << QgsAuthCertUtils::resolvedCertName( cert );
204  coltxts << QString( config.sslHostPort() );
205  coltxts << cert.expiryDate().toString();
206 
207  QTreeWidgetItem *item( new QTreeWidgetItem( parent, coltxts, ( int )conftype ) );
208 
209  item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificate.svg" ) ) );
210  if ( !QgsAuthCertUtils::certIsViable( cert ) )
211  {
212  item->setForeground( 2, redb );
213  item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificateUntrusted.svg" ) ) );
214  }
215 
216  item->setData( 0, Qt::UserRole, id );
217  }
218 
219  parent->sortChildren( 0, Qt::AscendingOrder );
220 }
221 
222 void QgsAuthServersEditor::selectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
223 {
224  Q_UNUSED( selected );
225  Q_UNUSED( deselected );
226  checkSelection();
227 }
228 
229 void QgsAuthServersEditor::checkSelection()
230 {
231  bool isconfig = false;
232  if ( treeServerConfigs->selectionModel()->selection().length() > 0 )
233  {
234  QTreeWidgetItem *item( treeServerConfigs->currentItem() );
235 
236  switch ( ( QgsAuthServersEditor::ConfigType )item->type() )
237  {
238  case QgsAuthServersEditor::ServerConfig :
239  isconfig = true;
240  break;
241  default:
242  break;
243  }
244  }
245 
246  btnRemoveServer->setEnabled( isconfig );
247  btnEditServer->setEnabled( isconfig );
248 }
249 
250 void QgsAuthServersEditor::handleDoubleClick( QTreeWidgetItem *item, int col )
251 {
252  Q_UNUSED( col );
253  bool isconfig = true;
254 
255  switch ( ( QgsAuthServersEditor::ConfigType )item->type() )
256  {
257  case QgsAuthServersEditor::Section:
258  isconfig = false;
259  break;
260  case QgsAuthServersEditor::OrgName:
261  isconfig = false;
262  break;
263  default:
264  break;
265  }
266 
267  if ( isconfig )
268  {
269  btnEditServer_clicked();
270  }
271 }
272 
273 void QgsAuthServersEditor::btnAddServer_clicked()
274 {
276  dlg->setWindowModality( Qt::WindowModal );
277  dlg->resize( 580, 512 );
278  if ( dlg->exec() )
279  {
280  refreshSslConfigsView();
281  }
282  dlg->deleteLater();
283 }
284 
285 void QgsAuthServersEditor::btnRemoveServer_clicked()
286 {
287  QTreeWidgetItem *item( treeServerConfigs->currentItem() );
288 
289  if ( !item )
290  {
291  QgsDebugMsg( "Current tree widget item not set" );
292  return;
293  }
294 
295  QString digest( item->data( 0, Qt::UserRole ).toString() );
296  QString hostport( item->text( 1 ) );
297 
298  if ( digest.isEmpty() )
299  {
300  messageBar()->pushMessage( tr( "SSL custom config id missing" ),
301  Qgis::Warning );
302  return;
303  }
304  if ( hostport.isEmpty() )
305  {
306  messageBar()->pushMessage( tr( "SSL custom config host:port missing" ),
307  Qgis::Warning );
308  return;
309  }
310 
311  if ( !QgsApplication::authManager()->existsSslCertCustomConfig( digest, hostport ) )
312  {
313  QgsDebugMsg( QString( "SSL custom config does not exist in database for host:port, id %1:" )
314  .arg( hostport, digest ) );
315  return;
316  }
317 
318  if ( QMessageBox::warning(
319  this, tr( "Remove SSL Custom Configuration" ),
320  tr( "Are you sure you want to remove the selected "
321  "SSL custom configuration from the database?\n\n"
322  "Operation can NOT be undone!" ),
323  QMessageBox::Ok | QMessageBox::Cancel,
324  QMessageBox::Cancel ) == QMessageBox::Cancel )
325  {
326  return;
327  }
328 
329  if ( !QgsApplication::authManager()->removeSslCertCustomConfig( digest, hostport ) )
330  {
331  messageBar()->pushMessage( tr( "ERROR removing SSL custom config from authentication database for host:port, id %1:" )
332  .arg( hostport, digest ),
333  Qgis::Critical );
334  return;
335  }
336 
337  item->parent()->removeChild( item );
338  delete item;
339 }
340 
341 void QgsAuthServersEditor::btnEditServer_clicked()
342 {
343  QTreeWidgetItem *item( treeServerConfigs->currentItem() );
344 
345  if ( !item )
346  {
347  QgsDebugMsg( "Current tree widget item not set" );
348  return;
349  }
350 
351  QString digest( item->data( 0, Qt::UserRole ).toString() );
352  QString hostport( item->text( 1 ) );
353 
354  if ( digest.isEmpty() )
355  {
356  messageBar()->pushMessage( tr( "SSL custom config id missing." ),
357  Qgis::Warning );
358  return;
359  }
360  if ( hostport.isEmpty() )
361  {
362  messageBar()->pushMessage( tr( "SSL custom config host:port missing." ),
363  Qgis::Warning );
364  return;
365  }
366 
367  if ( !QgsApplication::authManager()->existsSslCertCustomConfig( digest, hostport ) )
368  {
369  QgsDebugMsg( "SSL custom config does not exist in database" );
370  return;
371  }
372 
373  QgsAuthConfigSslServer config( QgsApplication::authManager()->sslCertCustomConfig( digest, hostport ) );
374  QSslCertificate cert( config.sslCertificate() );
375 
376  QgsAuthSslConfigDialog *dlg = new QgsAuthSslConfigDialog( this, cert, hostport );
377  dlg->sslCustomConfigWidget()->setConfigCheckable( false );
378  dlg->setWindowModality( Qt::WindowModal );
379  dlg->resize( 500, 500 );
380  if ( dlg->exec() )
381  {
382  refreshSslConfigsView();
383  }
384  dlg->deleteLater();
385 }
386 
387 void QgsAuthServersEditor::btnGroupByOrg_toggled( bool checked )
388 {
389  if ( !QgsApplication::authManager()->storeAuthSetting( QStringLiteral( "serverssortby" ), QVariant( checked ) ) )
390  {
391  authMessageOut( QObject::tr( "Could not store sort by preference." ),
392  QObject::tr( "Authentication SSL Configs" ),
394  }
395  populateSslConfigsView();
396 }
397 
398 void QgsAuthServersEditor::authMessageOut( const QString &message, const QString &authtag, QgsAuthManager::MessageLevel level )
399 {
400  int levelint = ( int )level;
401  messageBar()->pushMessage( authtag, message, ( Qgis::MessageLevel )levelint, 7 );
402 }
403 
404 void QgsAuthServersEditor::showEvent( QShowEvent *e )
405 {
406  if ( !mDisabled )
407  {
408  treeServerConfigs->setFocus();
409  }
410  QWidget::showEvent( e );
411 }
412 
413 QgsMessageBar *QgsAuthServersEditor::messageBar()
414 {
415  return msgBar;
416 }
417 
418 int QgsAuthServersEditor::messageTimeout()
419 {
420  QgsSettings settings;
421  return settings.value( QStringLiteral( "qgis/messageTimeout" ), 5 ).toInt();
422 }
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
Configuration container for SSL server connection exceptions or overrides.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
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.
void authDatabaseChanged()
Emitted when the authentication db is significantly changed, e.g. large record removal, erased, etc.
static QMap< QString, QList< QgsAuthConfigSslServer > > sslConfigsGroupedByOrg(const QList< QgsAuthConfigSslServer > &configs)
Map SSL custom configs&#39; certificates to their oraganization.
const QString sslHostPort() const
Server host:port string.
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.
const QSslCertificate sslCertificate() const
Server certificate object.
Dialog wrapper of widget for editing an SSL server configuration.
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 )) ...
void showEvent(QShowEvent *e) override
QgsAuthServersEditor(QWidget *parent=nullptr)
Widget for editing authentication configurations directly in database.
Widget for importing an SSL server certificate exception into the authentication database.
static QString resolvedCertName(const QSslCertificate &cert, bool issuer=false)
Gets the general name via RFC 5280 resolution.