QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 #include <QSettings>
24 
25 #include "qgsapplication.h"
26 #include "qgsauthcertificateinfo.h"
27 #include "qgsauthmanager.h"
28 #include "qgsauthguiutils.h"
29 #include "qgslogger.h"
30 
32  : QWidget( parent )
33  , mDisabled( false )
34  , mAuthNotifyLayout( nullptr )
35  , mAuthNotify( nullptr )
36  , mRootSslConfigItem( nullptr )
37 {
38  if ( QgsAuthManager::instance()->isDisabled() )
39  {
40  mDisabled = true;
41  mAuthNotifyLayout = new QVBoxLayout;
42  this->setLayout( mAuthNotifyLayout );
43  mAuthNotify = new QLabel( QgsAuthManager::instance()->disabledMessage(), this );
44  mAuthNotifyLayout->addWidget( mAuthNotify );
45  }
46  else
47  {
48  setupUi( this );
49 
50  connect( QgsAuthManager::instance(), SIGNAL( messageOut( const QString&, const QString&, QgsAuthManager::MessageLevel ) ),
51  this, SLOT( authMessageOut( const QString&, const QString&, QgsAuthManager::MessageLevel ) ) );
52 
53  connect( QgsAuthManager::instance(), SIGNAL( authDatabaseChanged() ),
54  this, SLOT( refreshSslConfigsView() ) );
55 
56  setupSslConfigsTree();
57 
58  connect( treeServerConfigs->selectionModel(), SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
59  this, SLOT( selectionChanged( const QItemSelection&, const QItemSelection& ) ) );
60 
61  connect( treeServerConfigs, SIGNAL( itemDoubleClicked( QTreeWidgetItem *, int ) ),
62  this, SLOT( handleDoubleClick( QTreeWidgetItem *, int ) ) );
63 
64  connect( btnViewRefresh, SIGNAL( clicked() ), this, SLOT( refreshSslConfigsView() ) );
65 
66  btnGroupByOrg->setChecked( false );
67  QVariant sortbyval = QgsAuthManager::instance()->getAuthSetting( QString( "serverssortby" ), QVariant( false ) );
68  if ( !sortbyval.isNull() )
69  btnGroupByOrg->setChecked( sortbyval.toBool() );
70 
71  populateSslConfigsView();
72  checkSelection();
73  }
74 }
75 
77 {
78 }
79 
80 static void setItemBold_( QTreeWidgetItem* item )
81 {
82  item->setFirstColumnSpanned( true );
83  QFont secf( item->font( 0 ) );
84  secf.setBold( true );
85  item->setFont( 0, secf );
86 }
87 
88 
89 void QgsAuthServersEditor::setupSslConfigsTree()
90 {
91  treeServerConfigs->setColumnCount( 3 );
92  treeServerConfigs->setHeaderLabels(
93  QStringList() << tr( "Common Name" )
94  << tr( "Host" )
95  << tr( "Expiry Date" ) );
96  treeServerConfigs->setColumnWidth( 0, 275 );
97  treeServerConfigs->setColumnWidth( 1, 200 );
98 
99  // add root sections
100  mRootSslConfigItem = new QTreeWidgetItem(
101  treeServerConfigs,
102  QStringList( tr( "SSL Server Configurations" ) ),
103  ( int )QgsAuthServersEditor::Section );
104  setItemBold_( mRootSslConfigItem );
105  mRootSslConfigItem->setFlags( Qt::ItemIsEnabled );
106  mRootSslConfigItem->setExpanded( true );
107  treeServerConfigs->insertTopLevelItem( 0, mRootSslConfigItem );
108 }
109 
110 static void removeChildren_( QTreeWidgetItem* item )
111 {
112  Q_FOREACH ( QTreeWidgetItem* child, item->takeChildren() )
113  {
114  delete child;
115  }
116 }
117 
118 void QgsAuthServersEditor::populateSslConfigsView()
119 {
120  removeChildren_( mRootSslConfigItem );
121 
122  populateSslConfigsSection( mRootSslConfigItem,
123  QgsAuthManager::instance()->getSslCertCustomConfigs(),
124  QgsAuthServersEditor::ServerConfig );
125 }
126 
127 void QgsAuthServersEditor::refreshSslConfigsView()
128 {
129  populateSslConfigsView();
130 }
131 
132 void QgsAuthServersEditor::populateSslConfigsSection( QTreeWidgetItem *item,
133  const QList<QgsAuthConfigSslServer>& configs,
134  QgsAuthServersEditor::ConfigType conftype )
135 {
136  if ( btnGroupByOrg->isChecked() )
137  {
138  appendSslConfigsToGroup( configs, conftype, item );
139  }
140  else
141  {
142  appendSslConfigsToItem( configs, conftype, item );
143  }
144 }
145 
146 void QgsAuthServersEditor::appendSslConfigsToGroup( const QList<QgsAuthConfigSslServer>& configs,
147  QgsAuthServersEditor::ConfigType conftype,
149 {
150  if ( configs.size() < 1 )
151  return;
152 
153  if ( !parent )
154  {
155  parent = treeServerConfigs->currentItem();
156  }
157 
158  // TODO: find all organizational name, sort and make subsections
161 
162  QMap< QString, QList<QgsAuthConfigSslServer> >::const_iterator it = orgconfigs.constBegin();
163  for ( ; it != orgconfigs.constEnd(); ++it )
164  {
165  QTreeWidgetItem * grpitem( new QTreeWidgetItem( parent,
166  QStringList() << it.key(),
167  ( int )QgsAuthServersEditor::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  appendSslConfigsToItem( it.value(), conftype, grpitem );
180  }
181 
182  parent->sortChildren( 0, Qt::AscendingOrder );
183 }
184 
185 void QgsAuthServersEditor::appendSslConfigsToItem( const QList<QgsAuthConfigSslServer>& configs,
186  QgsAuthServersEditor::ConfigType conftype,
187  QTreeWidgetItem *parent )
188 {
189  if ( configs.size() < 1 )
190  return;
191 
192  if ( !parent )
193  {
194  parent = treeServerConfigs->currentItem();
195  }
196 
198 
199  // Columns: Common Name, Host, Expiry Date
200  Q_FOREACH ( const QgsAuthConfigSslServer& config, configs )
201  {
202  QSslCertificate cert( config.sslCertificate() );
204 
205  QStringList coltxts;
206  coltxts << QgsAuthCertUtils::resolvedCertName( cert );
207  coltxts << QString( config.sslHostPort() );
208  coltxts << cert.expiryDate().toString();
209 
210  QTreeWidgetItem * item( new QTreeWidgetItem( parent, coltxts, ( int )conftype ) );
211 
212  item->setIcon( 0, QgsApplication::getThemeIcon( "/mIconCertificate.svg" ) );
213  if ( !cert.isValid() )
214  {
215  item->setForeground( 2, redb );
216  item->setIcon( 0, QgsApplication::getThemeIcon( "/mIconCertificateUntrusted.svg" ) );
217  }
218 
219  item->setData( 0, Qt::UserRole, id );
220  }
221 
222  parent->sortChildren( 0, Qt::AscendingOrder );
223 }
224 
225 void QgsAuthServersEditor::selectionChanged( const QItemSelection& selected , const QItemSelection& deselected )
226 {
227  Q_UNUSED( selected );
228  Q_UNUSED( deselected );
229  checkSelection();
230 }
231 
232 void QgsAuthServersEditor::checkSelection()
233 {
234  bool isconfig = false;
235  if ( treeServerConfigs->selectionModel()->selection().length() > 0 )
236  {
237  QTreeWidgetItem* item( treeServerConfigs->currentItem() );
238 
239  switch (( QgsAuthServersEditor::ConfigType )item->type() )
240  {
241  case QgsAuthServersEditor::ServerConfig :
242  isconfig = true;
243  break;
244  default:
245  break;
246  }
247  }
248 
249  btnRemoveServer->setEnabled( isconfig );
250  btnEditServer->setEnabled( isconfig );
251 }
252 
253 void QgsAuthServersEditor::handleDoubleClick( QTreeWidgetItem *item, int col )
254 {
255  Q_UNUSED( col );
256  bool isconfig = true;
257 
258  switch (( QgsAuthServersEditor::ConfigType )item->type() )
259  {
260  case QgsAuthServersEditor::Section:
261  isconfig = false;
262  break;
263  case QgsAuthServersEditor::OrgName:
264  isconfig = false;
265  break;
266  default:
267  break;
268  }
269 
270  if ( isconfig )
271  {
272  on_btnEditServer_clicked();
273  }
274 }
275 
276 void QgsAuthServersEditor::on_btnAddServer_clicked()
277 {
279  dlg->setWindowModality( Qt::WindowModal );
280  dlg->resize( 580, 512 );
281  if ( dlg->exec() )
282  {
283  refreshSslConfigsView();
284  }
285  dlg->deleteLater();
286 }
287 
288 void QgsAuthServersEditor::on_btnRemoveServer_clicked()
289 {
290  QTreeWidgetItem* item( treeServerConfigs->currentItem() );
291 
292  if ( !item )
293  {
294  QgsDebugMsg( "Current tree widget item not set" );
295  return;
296  }
297 
298  QString digest( item->data( 0, Qt::UserRole ).toString() );
299  QString hostport( item->text( 1 ) );
300 
301  if ( digest.isEmpty() )
302  {
303  messageBar()->pushMessage( tr( "SSL custom config id missing" ),
305  return;
306  }
307  if ( hostport.isEmpty() )
308  {
309  messageBar()->pushMessage( tr( "SSL custom config host:port missing" ),
311  return;
312  }
313 
314  if ( !QgsAuthManager::instance()->existsSslCertCustomConfig( digest, hostport ) )
315  {
316  QgsDebugMsg( QString( "SSL custom config does not exist in database for host:port, id %1:" )
317  .arg( hostport, digest ) );
318  return;
319  }
320 
322  this, tr( "Remove SSL Custom Config" ),
323  tr( "Are you sure you want to remove the selected "
324  "SSL custom config from the database?\n\n"
325  "Operation can NOT be undone!" ),
326  QMessageBox::Ok | QMessageBox::Cancel,
327  QMessageBox::Cancel ) == QMessageBox::Cancel )
328  {
329  return;
330  }
331 
332  if ( !QgsAuthManager::instance()->removeSslCertCustomConfig( digest, hostport ) )
333  {
334  messageBar()->pushMessage( tr( "ERROR removing SSL custom config from authentication database for host:port, id %1:" )
335  .arg( hostport, digest ),
337  return;
338  }
339 
340  item->parent()->removeChild( item );
341  delete item;
342 }
343 
344 void QgsAuthServersEditor::on_btnEditServer_clicked()
345 {
346  QTreeWidgetItem* item( treeServerConfigs->currentItem() );
347 
348  if ( !item )
349  {
350  QgsDebugMsg( "Current tree widget item not set" );
351  return;
352  }
353 
354  QString digest( item->data( 0, Qt::UserRole ).toString() );
355  QString hostport( item->text( 1 ) );
356 
357  if ( digest.isEmpty() )
358  {
359  messageBar()->pushMessage( tr( "SSL custom config id missing" ),
361  return;
362  }
363  if ( hostport.isEmpty() )
364  {
365  messageBar()->pushMessage( tr( "SSL custom config host:port missing" ),
367  return;
368  }
369 
370  if ( !QgsAuthManager::instance()->existsSslCertCustomConfig( digest, hostport ) )
371  {
372  QgsDebugMsg( "SSL custom config does not exist in database" );
373  return;
374  }
375 
376  QgsAuthConfigSslServer config( QgsAuthManager::instance()->getSslCertCustomConfig( digest, hostport ) );
377  QSslCertificate cert( config.sslCertificate() );
378 
379  QgsAuthSslConfigDialog * dlg = new QgsAuthSslConfigDialog( this, cert, hostport );
380  dlg->sslCustomConfigWidget()->setConfigCheckable( false );
381  dlg->setWindowModality( Qt::WindowModal );
382  dlg->resize( 500, 500 );
383  if ( dlg->exec() )
384  {
385  refreshSslConfigsView();
386  }
387  dlg->deleteLater();
388 }
389 
390 void QgsAuthServersEditor::on_btnGroupByOrg_toggled( bool checked )
391 {
392  if ( !QgsAuthManager::instance()->storeAuthSetting( QString( "serverssortby" ), QVariant( checked ) ) )
393  {
394  authMessageOut( QObject::tr( "Could not store sort by preference" ),
395  QObject::tr( "Authentication SSL Configs" ),
397  }
398  populateSslConfigsView();
399 }
400 
401 void QgsAuthServersEditor::authMessageOut( const QString& message, const QString& authtag, QgsAuthManager::MessageLevel level )
402 {
403  int levelint = ( int )level;
404  messageBar()->pushMessage( authtag, message, ( QgsMessageBar::MessageLevel )levelint, 7 );
405 }
406 
408 {
409  if ( !mDisabled )
410  {
411  treeServerConfigs->setFocus();
412  }
413  QWidget::showEvent( e );
414 }
415 
416 QgsMessageBar * QgsAuthServersEditor::messageBar()
417 {
418  return msgBar;
419 }
420 
421 int QgsAuthServersEditor::messageTimeout()
422 {
423  QSettings settings;
424  return settings.value( "/qgis/messageTimeout", 5 ).toInt();
425 }
QObject * child(const char *objName, const char *inheritsClass, bool recursiveSearch) const
static void setItemBold_(QTreeWidgetItem *item)
void setupUi(QWidget *widget)
static QgsAuthManager * instance()
Enforce singleton pattern.
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
Configuration container for SSL server connection exceptions or overrides.
int exec()
void setFirstColumnSpanned(bool span)
virtual void setData(int column, int role, const QVariant &value)
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.
void setLayout(QLayout *layout)
void removeChild(QTreeWidgetItem *child)
int toInt(bool *ok) const
bool isNull() const
QList< QTreeWidgetItem * > takeChildren()
const_iterator constEnd() const
QFont font(int column) const
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.
static void removeChildren_(QTreeWidgetItem *item)
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
void setExpanded(bool expand)
const QSslCertificate sslCertificate() const
Server certificate object.
Dialog wrapper of widget for editing an SSL server configuration.
void showEvent(QShowEvent *e) override
Overridden show event of base widget.
bool toBool() const
QgsAuthServersEditor(QWidget *parent=nullptr)
Widget for editing authentication configurations directly in database.
StandardButton warning(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
int type() const
Widget for importing an SSL server certificate exception into the authentication database.
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.
QString text(int column) const
void setForeground(int column, const QBrush &brush)
const T value(const Key &key) const