QGIS API Documentation 3.27.0-Master (f261cc1f8b)
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
18#include "ui_qgsauthserverseditor.h"
20
21#include <QMenu>
22#include <QMessageBox>
23
24#include "qgssettings.h"
25#include "qgsapplication.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
77static 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
86void 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
107static void removeChildren_( QTreeWidgetItem *item )
108{
109 const auto constTakeChildren = item->takeChildren();
110 for ( QTreeWidgetItem *child : constTakeChildren )
111 {
112 delete child;
113 }
114}
115
116void QgsAuthServersEditor::populateSslConfigsView()
117{
118 removeChildren_( mRootSslConfigItem );
119
120 populateSslConfigsSection( mRootSslConfigItem,
121 QgsApplication::authManager()->sslCertCustomConfigs(),
122 QgsAuthServersEditor::ServerConfig );
123}
124
125void QgsAuthServersEditor::refreshSslConfigsView()
126{
127 populateSslConfigsView();
128}
129
130void 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
144void 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
183void 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
224void QgsAuthServersEditor::selectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
225{
226 Q_UNUSED( selected )
227 Q_UNUSED( deselected )
228 checkSelection();
229}
230
231void 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
252void 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
275void 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
287void 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
343void 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 );
380 dlg->setWindowModality( Qt::WindowModal );
381 dlg->resize( 500, 500 );
382 if ( dlg->exec() )
383 {
384 refreshSslConfigsView();
385 }
386 dlg->deleteLater();
387}
388
389void 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
400void 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
407{
408 if ( !mDisabled )
409 {
410 treeServerConfigs->setFocus();
411 }
412 QWidget::showEvent( e );
413}
414
415QgsMessageBar *QgsAuthServersEditor::messageBar()
416{
417 return msgBar;
418}
419
420int QgsAuthServersEditor::messageTimeout()
421{
422 const QgsSettings settings;
423 return settings.value( QStringLiteral( "qgis/messageTimeout" ), 5 ).toInt();
424}
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition: qgis.h:115
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static QString resolvedCertName(const QSslCertificate &cert, bool issuer=false)
Gets the general name via RFC 5280 resolution.
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Gets the sha1 hash for certificate.
static bool certIsViable(const QSslCertificate &cert)
certIsViable checks for viability errors of cert and whether it is NULL
static QMap< QString, QList< QgsAuthConfigSslServer > > sslConfigsGroupedByOrg(const QList< QgsAuthConfigSslServer > &configs)
Map SSL custom configs' certificates to their oraganization.
Configuration container for SSL server connection exceptions or overrides.
static QColor redColor()
Red color representing invalid, untrusted, etc. certificate.
MessageLevel
Message log level (mirrors that of QgsMessageLog, so it can also output there)
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.
void authDatabaseChanged()
Emitted when the authentication db is significantly changed, e.g. large record removal,...
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 ))
QgsAuthServersEditor(QWidget *parent=nullptr)
Widget for editing authentication configurations directly in database.
void showEvent(QShowEvent *e) override
Dialog wrapper of widget for editing an SSL server configuration.
QgsAuthSslConfigWidget * sslCustomConfigWidget()
Access the embedded SSL server configuration widget.
void setConfigCheckable(bool checkable)
Sets whether the config group box is checkable.
Widget for importing an SSL server certificate exception into the authentication database.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
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.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
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