QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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  const 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  static_cast<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  const auto constTakeChildren = item->takeChildren();
110  for ( QTreeWidgetItem *child : constTakeChildren )
111  {
112  delete child;
113  }
114 }
115 
116 void QgsAuthServersEditor::populateSslConfigsView()
117 {
118  removeChildren_( mRootSslConfigItem );
119 
120  populateSslConfigsSection( mRootSslConfigItem,
121  QgsApplication::authManager()->sslCertCustomConfigs(),
122  QgsAuthServersEditor::ServerConfig );
123 }
124 
125 void QgsAuthServersEditor::refreshSslConfigsView()
126 {
127  populateSslConfigsView();
128 }
129 
130 void QgsAuthServersEditor::populateSslConfigsSection( QTreeWidgetItem *item,
131  const QList<QgsAuthConfigSslServer> &configs,
132  QgsAuthServersEditor::ConfigType conftype )
133 {
134  if ( btnGroupByOrg->isChecked() )
135  {
136  appendSslConfigsToGroup( configs, conftype, item );
137  }
138  else
139  {
140  appendSslConfigsToItem( configs, conftype, item );
141  }
142 }
143 
144 void QgsAuthServersEditor::appendSslConfigsToGroup( const QList<QgsAuthConfigSslServer> &configs,
145  QgsAuthServersEditor::ConfigType conftype,
146  QTreeWidgetItem *parent )
147 {
148  if ( configs.empty() )
149  return;
150 
151  if ( !parent )
152  {
153  parent = treeServerConfigs->currentItem();
154  }
155 
156  // TODO: find all organizational name, sort and make subsections
157  const QMap< QString, QList<QgsAuthConfigSslServer> > orgconfigs(
159 
160  QMap< QString, QList<QgsAuthConfigSslServer> >::const_iterator it = orgconfigs.constBegin();
161  for ( ; it != orgconfigs.constEnd(); ++it )
162  {
163  QTreeWidgetItem *grpitem( new QTreeWidgetItem( parent,
164  QStringList() << it.key(),
165  static_cast<int>( QgsAuthServersEditor::OrgName ) ) );
166  grpitem->setFirstColumnSpanned( true );
167  grpitem->setFlags( Qt::ItemIsEnabled );
168  grpitem->setExpanded( true );
169 
170  QBrush orgb( grpitem->foreground( 0 ) );
171  orgb.setColor( QColor::fromRgb( 90, 90, 90 ) );
172  grpitem->setForeground( 0, orgb );
173  QFont grpf( grpitem->font( 0 ) );
174  grpf.setItalic( true );
175  grpitem->setFont( 0, grpf );
176 
177  appendSslConfigsToItem( it.value(), conftype, grpitem );
178  }
179 
180  parent->sortChildren( 0, Qt::AscendingOrder );
181 }
182 
183 void QgsAuthServersEditor::appendSslConfigsToItem( const QList<QgsAuthConfigSslServer> &configs,
184  QgsAuthServersEditor::ConfigType conftype,
185  QTreeWidgetItem *parent )
186 {
187  if ( configs.empty() )
188  return;
189 
190  if ( !parent )
191  {
192  parent = treeServerConfigs->currentItem();
193  }
194 
195  const QBrush redb( QgsAuthGuiUtils::redColor() );
196 
197  // Columns: Common Name, Host, Expiry Date
198  const auto constConfigs = configs;
199  for ( const QgsAuthConfigSslServer &config : constConfigs )
200  {
201  const QSslCertificate cert( config.sslCertificate() );
202  const QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
203 
204  QStringList coltxts;
205  coltxts << QgsAuthCertUtils::resolvedCertName( cert );
206  coltxts << QString( config.sslHostPort() );
207  coltxts << cert.expiryDate().toString();
208 
209  QTreeWidgetItem *item( new QTreeWidgetItem( parent, coltxts, static_cast<int>( conftype ) ) );
210 
211  item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificate.svg" ) ) );
212  if ( !QgsAuthCertUtils::certIsViable( cert ) )
213  {
214  item->setForeground( 2, redb );
215  item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificateUntrusted.svg" ) ) );
216  }
217 
218  item->setData( 0, Qt::UserRole, id );
219  }
220 
221  parent->sortChildren( 0, Qt::AscendingOrder );
222 }
223 
224 void QgsAuthServersEditor::selectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
225 {
226  Q_UNUSED( selected )
227  Q_UNUSED( deselected )
228  checkSelection();
229 }
230 
231 void QgsAuthServersEditor::checkSelection()
232 {
233  bool isconfig = false;
234  if ( treeServerConfigs->selectionModel()->selection().length() > 0 )
235  {
236  QTreeWidgetItem *item( treeServerConfigs->currentItem() );
237 
238  switch ( ( QgsAuthServersEditor::ConfigType )item->type() )
239  {
240  case QgsAuthServersEditor::ServerConfig :
241  isconfig = true;
242  break;
243  default:
244  break;
245  }
246  }
247 
248  btnRemoveServer->setEnabled( isconfig );
249  btnEditServer->setEnabled( isconfig );
250 }
251 
252 void QgsAuthServersEditor::handleDoubleClick( QTreeWidgetItem *item, int col )
253 {
254  Q_UNUSED( col )
255  bool isconfig = true;
256 
257  switch ( ( QgsAuthServersEditor::ConfigType )item->type() )
258  {
259  case QgsAuthServersEditor::Section:
260  isconfig = false;
261  break;
262  case QgsAuthServersEditor::OrgName:
263  isconfig = false;
264  break;
265  default:
266  break;
267  }
268 
269  if ( isconfig )
270  {
271  btnEditServer_clicked();
272  }
273 }
274 
275 void QgsAuthServersEditor::btnAddServer_clicked()
276 {
278  dlg->setWindowModality( Qt::WindowModal );
279  dlg->resize( 580, 512 );
280  if ( dlg->exec() )
281  {
282  refreshSslConfigsView();
283  }
284  dlg->deleteLater();
285 }
286 
287 void QgsAuthServersEditor::btnRemoveServer_clicked()
288 {
289  QTreeWidgetItem *item( treeServerConfigs->currentItem() );
290 
291  if ( !item )
292  {
293  QgsDebugMsg( QStringLiteral( "Current tree widget item not set" ) );
294  return;
295  }
296 
297  const QString digest( item->data( 0, Qt::UserRole ).toString() );
298  const QString hostport( item->text( 1 ) );
299 
300  if ( digest.isEmpty() )
301  {
302  messageBar()->pushMessage( tr( "SSL custom config id missing" ),
303  Qgis::MessageLevel::Warning );
304  return;
305  }
306  if ( hostport.isEmpty() )
307  {
308  messageBar()->pushMessage( tr( "SSL custom config host:port missing" ),
309  Qgis::MessageLevel::Warning );
310  return;
311  }
312 
313  if ( !QgsApplication::authManager()->existsSslCertCustomConfig( digest, hostport ) )
314  {
315  QgsDebugMsg( QStringLiteral( "SSL custom config does not exist in database for host:port, id %1:" )
316  .arg( hostport, digest ) );
317  return;
318  }
319 
320  if ( QMessageBox::warning(
321  this, tr( "Remove SSL Custom Configuration" ),
322  tr( "Are you sure you want to remove the selected "
323  "SSL custom configuration from the database?\n\n"
324  "Operation can NOT be undone!" ),
325  QMessageBox::Ok | QMessageBox::Cancel,
326  QMessageBox::Cancel ) == QMessageBox::Cancel )
327  {
328  return;
329  }
330 
331  if ( !QgsApplication::authManager()->removeSslCertCustomConfig( digest, hostport ) )
332  {
333  messageBar()->pushMessage( tr( "ERROR removing SSL custom config from authentication database for host:port, id %1:" )
334  .arg( hostport, digest ),
335  Qgis::MessageLevel::Critical );
336  return;
337  }
338 
339  item->parent()->removeChild( item );
340  delete item;
341 }
342 
343 void QgsAuthServersEditor::btnEditServer_clicked()
344 {
345  QTreeWidgetItem *item( treeServerConfigs->currentItem() );
346 
347  if ( !item )
348  {
349  QgsDebugMsg( QStringLiteral( "Current tree widget item not set" ) );
350  return;
351  }
352 
353  const QString digest( item->data( 0, Qt::UserRole ).toString() );
354  const QString hostport( item->text( 1 ) );
355 
356  if ( digest.isEmpty() )
357  {
358  messageBar()->pushMessage( tr( "SSL custom config id missing." ),
359  Qgis::MessageLevel::Warning );
360  return;
361  }
362  if ( hostport.isEmpty() )
363  {
364  messageBar()->pushMessage( tr( "SSL custom config host:port missing." ),
365  Qgis::MessageLevel::Warning );
366  return;
367  }
368 
369  if ( !QgsApplication::authManager()->existsSslCertCustomConfig( digest, hostport ) )
370  {
371  QgsDebugMsg( QStringLiteral( "SSL custom config does not exist in database" ) );
372  return;
373  }
374 
375  const QgsAuthConfigSslServer config( QgsApplication::authManager()->sslCertCustomConfig( digest, hostport ) );
376  const QSslCertificate cert( config.sslCertificate() );
377 
378  QgsAuthSslConfigDialog *dlg = new QgsAuthSslConfigDialog( this, cert, hostport );
379  dlg->sslCustomConfigWidget()->setConfigCheckable( false );
380  dlg->setWindowModality( Qt::WindowModal );
381  dlg->resize( 500, 500 );
382  if ( dlg->exec() )
383  {
384  refreshSslConfigsView();
385  }
386  dlg->deleteLater();
387 }
388 
389 void QgsAuthServersEditor::btnGroupByOrg_toggled( bool checked )
390 {
391  if ( !QgsApplication::authManager()->storeAuthSetting( QStringLiteral( "serverssortby" ), QVariant( checked ) ) )
392  {
393  authMessageOut( QObject::tr( "Could not store sort by preference." ),
394  QObject::tr( "Authentication SSL Configs" ),
396  }
397  populateSslConfigsView();
398 }
399 
400 void QgsAuthServersEditor::authMessageOut( const QString &message, const QString &authtag, QgsAuthManager::MessageLevel level )
401 {
402  const int levelint = static_cast<int>( level );
403  messageBar()->pushMessage( authtag, message, ( Qgis::MessageLevel )levelint, 7 );
404 }
405 
406 void QgsAuthServersEditor::showEvent( QShowEvent *e )
407 {
408  if ( !mDisabled )
409  {
410  treeServerConfigs->setFocus();
411  }
412  QWidget::showEvent( e );
413 }
414 
415 QgsMessageBar *QgsAuthServersEditor::messageBar()
416 {
417  return msgBar;
418 }
419 
420 int QgsAuthServersEditor::messageTimeout()
421 {
422  const QgsSettings settings;
423  return settings.value( QStringLiteral( "qgis/messageTimeout" ), 5 ).toInt();
424 }
qgsauthcertutils.h
QgsAuthManager::messageOut
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.
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:161
qgsauthmanager.h
QgsAuthCertUtils::sslConfigsGroupedByOrg
static QMap< QString, QList< QgsAuthConfigSslServer > > sslConfigsGroupedByOrg(const QList< QgsAuthConfigSslServer > &configs)
Map SSL custom configs' certificates to their oraganization.
Definition: qgsauthcertutils.cpp:94
QgsAuthSslConfigWidget::setConfigCheckable
void setConfigCheckable(bool checkable)
Sets whether the config group box is checkable.
Definition: qgsauthsslconfigwidget.cpp:562
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
qgsauthguiutils.h
QgsAuthCertUtils::shaHexForCert
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Gets the sha1 hash for certificate.
Definition: qgsauthcertutils.cpp:748
QgsApplication::authManager
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
Definition: qgsapplication.cpp:1436
qgsapplication.h
QgsAuthSslImportDialog
Widget for importing an SSL server certificate exception into the authentication database.
Definition: qgsauthsslimportdialog.h:82
QgsAuthManager::MessageLevel
MessageLevel
Message log level (mirrors that of QgsMessageLog, so it can also output there)
Definition: qgsauthmanager.h:76
QgsAuthManager::WARNING
@ WARNING
Definition: qgsauthmanager.h:79
QgsMessageBar
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:60
QgsAuthManager::authSetting
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 ))
Definition: qgsauthmanager.cpp:1743
QgsAuthSslConfigDialog
Dialog wrapper of widget for editing an SSL server configuration.
Definition: qgsauthsslconfigwidget.h:191
QgsAuthServersEditor::showEvent
void showEvent(QShowEvent *e) override
Definition: qgsauthserverseditor.cpp:406
QgsAuthCertUtils::resolvedCertName
static QString resolvedCertName(const QSslCertificate &cert, bool issuer=false)
Gets the general name via RFC 5280 resolution.
Definition: qgsauthcertutils.cpp:625
QgsAuthSslConfigDialog::sslCustomConfigWidget
QgsAuthSslConfigWidget * sslCustomConfigWidget()
Access the embedded SSL server configuration widget.
Definition: qgsauthsslconfigwidget.h:208
QgsAuthServersEditor::QgsAuthServersEditor
QgsAuthServersEditor(QWidget *parent=nullptr)
Widget for editing authentication configurations directly in database.
Definition: qgsauthserverseditor.cpp:32
qgsauthcertificateinfo.h
Qgis::MessageLevel
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition: qgis.h:114
QgsAuthManager::authDatabaseChanged
void authDatabaseChanged()
Emitted when the authentication db is significantly changed, e.g. large record removal,...
qgssettings.h
QgsAuthConfigSslServer
Configuration container for SSL server connection exceptions or overrides.
Definition: qgsauthconfig.h:392
QgsAuthGuiUtils::redColor
static QColor redColor()
Red color representing invalid, untrusted, etc. certificate.
Definition: qgsauthguiutils.cpp:42
qgsauthserverseditor.h
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Definition: qgsapplication.cpp:693
qgslogger.h
QgsAuthCertUtils::certIsViable
static bool certIsViable(const QSslCertificate &cert)
certIsViable checks for viability errors of cert and whether it is NULL
Definition: qgsauthcertutils.cpp:1305
QgsMessageBar::pushMessage
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.
Definition: qgsmessagebar.cpp:405
qgsauthsslimportdialog.h