QGIS API Documentation 3.41.0-Master (45a0abf3bec)
Loading...
Searching...
No Matches
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 "moc_qgsauthserverseditor.cpp"
19#include "ui_qgsauthserverseditor.h"
21
22#include <QMenu>
23#include <QMessageBox>
24
25#include "qgssettings.h"
26#include "qgsapplication.h"
28#include "qgsauthcertutils.h"
29#include "qgsauthmanager.h"
30#include "qgsauthguiutils.h"
31#include "qgslogger.h"
32#include "qgsvariantutils.h"
33
35 : QWidget( parent )
36{
37 if ( QgsApplication::authManager()->isDisabled() )
38 {
39 mDisabled = true;
40 mAuthNotifyLayout = new QVBoxLayout;
41 this->setLayout( mAuthNotifyLayout );
42 mAuthNotify = new QLabel( QgsApplication::authManager()->disabledMessage(), this );
43 mAuthNotifyLayout->addWidget( mAuthNotify );
44 }
45 else
46 {
47 setupUi( this );
48 connect( btnAddServer, &QToolButton::clicked, this, &QgsAuthServersEditor::btnAddServer_clicked );
49 connect( btnRemoveServer, &QToolButton::clicked, this, &QgsAuthServersEditor::btnRemoveServer_clicked );
50 connect( btnEditServer, &QToolButton::clicked, this, &QgsAuthServersEditor::btnEditServer_clicked );
51 connect( btnGroupByOrg, &QToolButton::toggled, this, &QgsAuthServersEditor::btnGroupByOrg_toggled );
52
54 this, &QgsAuthServersEditor::authMessageLog );
55
57 this, &QgsAuthServersEditor::refreshSslConfigsView );
58
59 setupSslConfigsTree();
60
61 connect( treeServerConfigs->selectionModel(), &QItemSelectionModel::selectionChanged,
62 this, &QgsAuthServersEditor::selectionChanged );
63
64 connect( treeServerConfigs, &QTreeWidget::itemDoubleClicked,
65 this, &QgsAuthServersEditor::handleDoubleClick );
66
67 connect( btnViewRefresh, &QAbstractButton::clicked, this, &QgsAuthServersEditor::refreshSslConfigsView );
68
69 btnGroupByOrg->setChecked( false );
70 const QVariant sortbyval = QgsApplication::authManager()->authSetting( QStringLiteral( "serverssortby" ), QVariant( false ) );
71 if ( !QgsVariantUtils::isNull( sortbyval ) )
72 btnGroupByOrg->setChecked( sortbyval.toBool() );
73
74 populateSslConfigsView();
75 checkSelection();
76 }
77}
78
79static void setItemBold_( QTreeWidgetItem *item )
80{
81 item->setFirstColumnSpanned( true );
82 QFont secf( item->font( 0 ) );
83 secf.setBold( true );
84 item->setFont( 0, secf );
85}
86
87
88void QgsAuthServersEditor::setupSslConfigsTree()
89{
90 treeServerConfigs->setColumnCount( 3 );
91 treeServerConfigs->setHeaderLabels(
92 QStringList() << tr( "Common Name" )
93 << tr( "Host" )
94 << tr( "Expiry Date" ) );
95 treeServerConfigs->setColumnWidth( 0, 275 );
96 treeServerConfigs->setColumnWidth( 1, 200 );
97
98 // add root sections
99 mRootSslConfigItem = new QTreeWidgetItem(
100 treeServerConfigs,
101 QStringList( tr( "SSL Server Configurations" ) ),
102 static_cast<int>( QgsAuthServersEditor::Section ) );
103 setItemBold_( mRootSslConfigItem );
104 mRootSslConfigItem->setFlags( Qt::ItemIsEnabled );
105 mRootSslConfigItem->setExpanded( true );
106 treeServerConfigs->insertTopLevelItem( 0, mRootSslConfigItem );
107}
108
109static void removeChildren_( QTreeWidgetItem *item )
110{
111 const auto constTakeChildren = item->takeChildren();
112 for ( QTreeWidgetItem *child : constTakeChildren )
113 {
114 delete child;
115 }
116}
117
118void QgsAuthServersEditor::populateSslConfigsView()
119{
120 removeChildren_( mRootSslConfigItem );
121
122 populateSslConfigsSection( mRootSslConfigItem,
123 QgsApplication::authManager()->sslCertCustomConfigs(),
124 QgsAuthServersEditor::ServerConfig );
125}
126
127void QgsAuthServersEditor::refreshSslConfigsView()
128{
129 populateSslConfigsView();
130}
131
132void 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
146void QgsAuthServersEditor::appendSslConfigsToGroup( const QList<QgsAuthConfigSslServer> &configs,
147 QgsAuthServersEditor::ConfigType conftype,
148 QTreeWidgetItem *parent )
149{
150 if ( configs.empty() )
151 return;
152
153 if ( !parent )
154 {
155 parent = treeServerConfigs->currentItem();
156 }
157
158 // TODO: find all organizational name, sort and make subsections
159 const QMap< QString, QList<QgsAuthConfigSslServer> > orgconfigs(
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 static_cast<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
185void QgsAuthServersEditor::appendSslConfigsToItem( const QList<QgsAuthConfigSslServer> &configs,
186 QgsAuthServersEditor::ConfigType conftype,
187 QTreeWidgetItem *parent )
188{
189 if ( configs.empty() )
190 return;
191
192 if ( !parent )
193 {
194 parent = treeServerConfigs->currentItem();
195 }
196
197 const QBrush redb( QgsAuthGuiUtils::redColor() );
198
199 // Columns: Common Name, Host, Expiry Date
200 const auto constConfigs = configs;
201 for ( const QgsAuthConfigSslServer &config : constConfigs )
202 {
203 const QSslCertificate cert( config.sslCertificate() );
204 const QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
205
206 QStringList coltxts;
207 coltxts << QgsAuthCertUtils::resolvedCertName( cert );
208 coltxts << QString( config.sslHostPort() );
209 coltxts << cert.expiryDate().toString();
210
211 QTreeWidgetItem *item( new QTreeWidgetItem( parent, coltxts, static_cast<int>( conftype ) ) );
212
213 item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificate.svg" ) ) );
214 if ( !QgsAuthCertUtils::certIsViable( cert ) )
215 {
216 item->setForeground( 2, redb );
217 item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificateUntrusted.svg" ) ) );
218 }
219
220 item->setData( 0, Qt::UserRole, id );
221 }
222
223 parent->sortChildren( 0, Qt::AscendingOrder );
224}
225
226void QgsAuthServersEditor::selectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
227{
228 Q_UNUSED( selected )
229 Q_UNUSED( deselected )
230 checkSelection();
231}
232
233void QgsAuthServersEditor::checkSelection()
234{
235 bool isconfig = false;
236 if ( treeServerConfigs->selectionModel()->selection().length() > 0 )
237 {
238 QTreeWidgetItem *item( treeServerConfigs->currentItem() );
239
240 switch ( ( QgsAuthServersEditor::ConfigType )item->type() )
241 {
242 case QgsAuthServersEditor::ServerConfig :
243 isconfig = true;
244 break;
245 default:
246 break;
247 }
248 }
249
250 btnRemoveServer->setEnabled( isconfig );
251 btnEditServer->setEnabled( isconfig );
252}
253
254void QgsAuthServersEditor::handleDoubleClick( QTreeWidgetItem *item, int col )
255{
256 Q_UNUSED( col )
257 bool isconfig = true;
258
259 switch ( ( QgsAuthServersEditor::ConfigType )item->type() )
260 {
261 case QgsAuthServersEditor::Section:
262 isconfig = false;
263 break;
264 case QgsAuthServersEditor::OrgName:
265 isconfig = false;
266 break;
267 default:
268 break;
269 }
270
271 if ( isconfig )
272 {
273 btnEditServer_clicked();
274 }
275}
276
277void QgsAuthServersEditor::btnAddServer_clicked()
278{
280 dlg->setWindowModality( Qt::WindowModal );
281 dlg->resize( 580, 512 );
282 if ( dlg->exec() )
283 {
284 refreshSslConfigsView();
285 }
286 dlg->deleteLater();
287}
288
289void QgsAuthServersEditor::btnRemoveServer_clicked()
290{
291 QTreeWidgetItem *item( treeServerConfigs->currentItem() );
292
293 if ( !item )
294 {
295 QgsDebugMsgLevel( QStringLiteral( "Current tree widget item not set" ), 2 );
296 return;
297 }
298
299 const QString digest( item->data( 0, Qt::UserRole ).toString() );
300 const QString hostport( item->text( 1 ) );
301
302 if ( digest.isEmpty() )
303 {
304 messageBar()->pushMessage( tr( "SSL custom config id missing" ),
306 return;
307 }
308 if ( hostport.isEmpty() )
309 {
310 messageBar()->pushMessage( tr( "SSL custom config host:port missing" ),
312 return;
313 }
314
315 if ( !QgsApplication::authManager()->existsSslCertCustomConfig( digest, hostport ) )
316 {
317 QgsDebugError( QStringLiteral( "SSL custom config does not exist in database for host:port, id %1:" )
318 .arg( hostport, digest ) );
319 return;
320 }
321
322 if ( QMessageBox::warning(
323 this, tr( "Remove SSL Custom Configuration" ),
324 tr( "Are you sure you want to remove the selected "
325 "SSL custom configuration from the database?\n\n"
326 "Operation can NOT be undone!" ),
327 QMessageBox::Ok | QMessageBox::Cancel,
328 QMessageBox::Cancel ) == QMessageBox::Cancel )
329 {
330 return;
331 }
332
333 if ( !QgsApplication::authManager()->removeSslCertCustomConfig( digest, hostport ) )
334 {
335 messageBar()->pushMessage( tr( "ERROR removing SSL custom config from authentication database for host:port, id %1:" )
336 .arg( hostport, digest ),
338 return;
339 }
340
341 item->parent()->removeChild( item );
342 delete item;
343}
344
345void QgsAuthServersEditor::btnEditServer_clicked()
346{
347 QTreeWidgetItem *item( treeServerConfigs->currentItem() );
348
349 if ( !item )
350 {
351 QgsDebugMsgLevel( QStringLiteral( "Current tree widget item not set" ), 2 );
352 return;
353 }
354
355 const QString digest( item->data( 0, Qt::UserRole ).toString() );
356 const QString hostport( item->text( 1 ) );
357
358 if ( digest.isEmpty() )
359 {
360 messageBar()->pushMessage( tr( "SSL custom config id missing." ),
362 return;
363 }
364 if ( hostport.isEmpty() )
365 {
366 messageBar()->pushMessage( tr( "SSL custom config host:port missing." ),
368 return;
369 }
370
371 if ( !QgsApplication::authManager()->existsSslCertCustomConfig( digest, hostport ) )
372 {
373 QgsDebugError( QStringLiteral( "SSL custom config does not exist in database" ) );
374 return;
375 }
376
377 const QgsAuthConfigSslServer config( QgsApplication::authManager()->sslCertCustomConfig( digest, hostport ) );
378 const QSslCertificate cert( config.sslCertificate() );
379
380 QgsAuthSslConfigDialog *dlg = new QgsAuthSslConfigDialog( this, cert, hostport );
382 dlg->setWindowModality( Qt::WindowModal );
383 dlg->resize( 500, 500 );
384 if ( dlg->exec() )
385 {
386 refreshSslConfigsView();
387 }
388 dlg->deleteLater();
389}
390
391void QgsAuthServersEditor::btnGroupByOrg_toggled( bool checked )
392{
393 if ( !QgsApplication::authManager()->storeAuthSetting( QStringLiteral( "serverssortby" ), QVariant( checked ) ) )
394 {
395 authMessageLog( QObject::tr( "Could not store sort by preference." ),
396 QObject::tr( "Authentication SSL Configs" ),
398 }
399 populateSslConfigsView();
400}
401
402void QgsAuthServersEditor::authMessageLog( const QString &message, const QString &authtag, Qgis::MessageLevel level )
403{
404 messageBar()->pushMessage( authtag, message, level, 7 );
405}
406
408{
409 if ( !mDisabled )
410 {
411 treeServerConfigs->setFocus();
412 }
413 QWidget::showEvent( e );
414}
415
416QgsMessageBar *QgsAuthServersEditor::messageBar()
417{
418 return msgBar;
419}
420
421int QgsAuthServersEditor::messageTimeout()
422{
423 const QgsSettings settings;
424 return settings.value( QStringLiteral( "qgis/messageTimeout" ), 5 ).toInt();
425}
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition qgis.h:154
@ Warning
Warning message.
Definition qgis.h:156
@ Critical
Critical/error message.
Definition qgis.h:157
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.
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 ))
void messageLog(const QString &message, const QString &tag=QgsAuthManager::AUTH_MAN_TAG, Qgis::MessageLevel level=Qgis::MessageLevel::Info) const
Custom logging signal to relay to console output and QgsMessageLog.
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.
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:64
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
#define QgsDebugError(str)
Definition qgslogger.h:38