QGIS API Documentation 3.41.0-Master (45a0abf3bec)
Loading...
Searching...
No Matches
qgsauthidentitieseditor.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsauthidentitieseditor.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_qgsauthidentitieseditor.cpp"
19#include "ui_qgsauthidentitieseditor.h"
20
21#include <QMenu>
22#include <QMessageBox>
23
24#include "qgssettings.h"
25#include "qgsapplication.h"
27#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( btnAddIdentity, &QToolButton::clicked, this, &QgsAuthIdentitiesEditor::btnAddIdentity_clicked );
49 connect( btnRemoveIdentity, &QToolButton::clicked, this, &QgsAuthIdentitiesEditor::btnRemoveIdentity_clicked );
50 connect( btnInfoIdentity, &QToolButton::clicked, this, &QgsAuthIdentitiesEditor::btnInfoIdentity_clicked );
51 connect( btnGroupByOrg, &QToolButton::toggled, this, &QgsAuthIdentitiesEditor::btnGroupByOrg_toggled );
52
54 this, &QgsAuthIdentitiesEditor::authMessageLog );
55
57 this, &QgsAuthIdentitiesEditor::refreshIdentitiesView );
58
59 setupIdentitiesTree();
60
61 connect( treeIdentities->selectionModel(), &QItemSelectionModel::selectionChanged,
62 this, &QgsAuthIdentitiesEditor::selectionChanged );
63
64 connect( treeIdentities, &QTreeWidget::itemDoubleClicked,
65 this, &QgsAuthIdentitiesEditor::handleDoubleClick );
66
67 connect( btnViewRefresh, &QAbstractButton::clicked, this, &QgsAuthIdentitiesEditor::refreshIdentitiesView );
68
69 btnGroupByOrg->setChecked( false );
70 const QVariant sortbyval = QgsApplication::authManager()->authSetting( QStringLiteral( "identitiessortby" ), QVariant( false ) );
71 if ( !QgsVariantUtils::isNull( sortbyval ) )
72 btnGroupByOrg->setChecked( sortbyval.toBool() );
73
74 populateIdentitiesView();
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
87void QgsAuthIdentitiesEditor::setupIdentitiesTree()
88{
89 treeIdentities->setColumnCount( 3 );
90 treeIdentities->setHeaderLabels(
91 QStringList() << tr( "Common Name" )
92 << tr( "Serial #" )
93 << tr( "Expiry Date" ) );
94 treeIdentities->setColumnWidth( 0, 300 );
95 treeIdentities->setColumnWidth( 1, 75 );
96
97 // add root sections
98 mRootCertIdentItem = new QTreeWidgetItem(
99 treeIdentities,
100 QStringList( tr( "Certificate Bundles" ) ),
101 static_cast<int>( QgsAuthIdentitiesEditor::Section ) );
102 setItemBold_( mRootCertIdentItem );
103 mRootCertIdentItem->setFlags( Qt::ItemIsEnabled );
104 mRootCertIdentItem->setExpanded( true );
105 treeIdentities->insertTopLevelItem( 0, mRootCertIdentItem );
106}
107
108static void removeChildren_( QTreeWidgetItem *item )
109{
110 const auto constTakeChildren = item->takeChildren();
111 for ( QTreeWidgetItem *child : constTakeChildren )
112 {
113 delete child;
114 }
115}
116
117void QgsAuthIdentitiesEditor::populateIdentitiesView()
118{
119 removeChildren_( mRootCertIdentItem );
120
121 populateIdentitiesSection( mRootCertIdentItem,
122 QgsApplication::authManager()->certIdentities(),
123 QgsAuthIdentitiesEditor::CertIdentity );
124}
125
126void QgsAuthIdentitiesEditor::refreshIdentitiesView()
127{
128 populateIdentitiesView();
129}
130
131void QgsAuthIdentitiesEditor::populateIdentitiesSection( QTreeWidgetItem *item, const QList<QSslCertificate> &certs,
132 QgsAuthIdentitiesEditor::IdentityType identype )
133{
134 if ( btnGroupByOrg->isChecked() )
135 {
136 appendIdentitiesToGroup( certs, identype, item );
137 }
138 else
139 {
140 appendIdentitiesToItem( certs, identype, item );
141 }
142}
143
144void QgsAuthIdentitiesEditor::appendIdentitiesToGroup( const QList<QSslCertificate> &certs,
145 QgsAuthIdentitiesEditor::IdentityType identype,
146 QTreeWidgetItem *parent )
147{
148 if ( certs.empty() )
149 return;
150
151 if ( !parent )
152 {
153 parent = treeIdentities->currentItem();
154 }
155
156 // TODO: find all organizational name, sort and make subsections
157 const QMap< QString, QList<QSslCertificate> > orgcerts(
159
160 QMap< QString, QList<QSslCertificate> >::const_iterator it = orgcerts.constBegin();
161 for ( ; it != orgcerts.constEnd(); ++it )
162 {
163 QTreeWidgetItem *grpitem( new QTreeWidgetItem( parent,
164 QStringList() << it.key(),
165 static_cast<int>( QgsAuthIdentitiesEditor::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 appendIdentitiesToItem( it.value(), identype, grpitem );
178 }
179
180 parent->sortChildren( 0, Qt::AscendingOrder );
181}
182
183void QgsAuthIdentitiesEditor::appendIdentitiesToItem( const QList<QSslCertificate> &certs,
184 QgsAuthIdentitiesEditor::IdentityType identype,
185 QTreeWidgetItem *parent )
186{
187 if ( certs.empty() )
188 return;
189
190 if ( !parent )
191 {
192 parent = treeIdentities->currentItem();
193 }
194
195 const QBrush redb( QgsAuthGuiUtils::redColor() );
196
197 // Columns: Common Name, Serial #, Expiry Date
198 const auto constCerts = certs;
199 for ( const QSslCertificate &cert : constCerts )
200 {
201 const QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
202
203 QStringList coltxts;
204 coltxts << QgsAuthCertUtils::resolvedCertName( cert );
205 coltxts << QString( cert.serialNumber() );
206 coltxts << cert.expiryDate().toString();
207
208 QTreeWidgetItem *item( new QTreeWidgetItem( parent, coltxts, static_cast<int>( identype ) ) );
209
210 item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificate.svg" ) ) );
211 if ( !QgsAuthCertUtils::certIsViable( cert ) )
212 {
213 item->setForeground( 2, redb );
214 item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificateUntrusted.svg" ) ) );
215 }
216
217 item->setData( 0, Qt::UserRole, id );
218 }
219
220 parent->sortChildren( 0, Qt::AscendingOrder );
221}
222
223void QgsAuthIdentitiesEditor::showCertInfo( QTreeWidgetItem *item )
224{
225 if ( !item )
226 return;
227
228 const QString digest( item->data( 0, Qt::UserRole ).toString() );
229
230 if ( !QgsApplication::authManager()->existsCertIdentity( digest ) )
231 {
232 QgsDebugError( QStringLiteral( "Certificate identity does not exist in database" ) );
233 return;
234 }
235
236 const QSslCertificate cert( QgsApplication::authManager()->certIdentity( digest ) );
237
238 QgsAuthCertInfoDialog *dlg = new QgsAuthCertInfoDialog( cert, false, this );
239 dlg->setWindowModality( Qt::WindowModal );
240 dlg->resize( 675, 500 );
241 dlg->exec();
242 dlg->deleteLater();
243}
244
245void QgsAuthIdentitiesEditor::selectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
246{
247 Q_UNUSED( selected )
248 Q_UNUSED( deselected )
249 checkSelection();
250}
251
252void QgsAuthIdentitiesEditor::checkSelection()
253{
254 bool iscert = false;
255 if ( treeIdentities->selectionModel()->selection().length() > 0 )
256 {
257 QTreeWidgetItem *item( treeIdentities->currentItem() );
258
259 switch ( ( QgsAuthIdentitiesEditor::IdentityType )item->type() )
260 {
261 case QgsAuthIdentitiesEditor::CertIdentity:
262 iscert = true;
263 break;
264 default:
265 break;
266 }
267 }
268
269 btnRemoveIdentity->setEnabled( iscert );
270 btnInfoIdentity->setEnabled( iscert );
271}
272
273void QgsAuthIdentitiesEditor::handleDoubleClick( QTreeWidgetItem *item, int col )
274{
275 Q_UNUSED( col )
276 bool iscert = true;
277
278 switch ( ( QgsAuthIdentitiesEditor::IdentityType )item->type() )
279 {
280 case QgsAuthIdentitiesEditor::Section:
281 iscert = false;
282 break;
283 case QgsAuthIdentitiesEditor::OrgName:
284 iscert = false;
285 break;
286 default:
287 break;
288 }
289
290 if ( iscert )
291 {
292 showCertInfo( item );
293 }
294}
295
296void QgsAuthIdentitiesEditor::btnAddIdentity_clicked()
297{
299 dlg->setWindowModality( Qt::WindowModal );
300 dlg->resize( 400, dlg->height() );
301 if ( dlg->exec() )
302 {
304 {
305 const QPair<QSslCertificate, QSslKey> &bundle( dlg->certBundleToImport() );
306 if ( !QgsApplication::authManager()->storeCertIdentity( bundle.first, bundle.second ) )
307 {
308 messageBar()->pushMessage( tr( "ERROR storing identity bundle in authentication database." ),
310 }
311 populateIdentitiesView();
312 mRootCertIdentItem->setExpanded( true );
313 }
314 }
315 dlg->deleteLater();
316}
317
318void QgsAuthIdentitiesEditor::btnRemoveIdentity_clicked()
319{
320 QTreeWidgetItem *item( treeIdentities->currentItem() );
321
322 if ( !item )
323 {
324 QgsDebugMsgLevel( QStringLiteral( "Current tree widget item not set" ), 2 );
325 return;
326 }
327
328 const QString digest( item->data( 0, Qt::UserRole ).toString() );
329
330 if ( digest.isEmpty() )
331 {
332 messageBar()->pushMessage( tr( "Certificate id missing." ),
334 return;
335 }
336
337 if ( !QgsApplication::authManager()->existsCertIdentity( digest ) )
338 {
339 QgsDebugError( QStringLiteral( "Certificate identity does not exist in database" ) );
340 return;
341 }
342
343 if ( QMessageBox::warning(
344 this, tr( "Remove Certificate Identity" ),
345 tr( "Are you sure you want to remove the selected "
346 "certificate identity from the database?\n\n"
347 "Operation can NOT be undone!" ),
348 QMessageBox::Ok | QMessageBox::Cancel,
349 QMessageBox::Cancel ) == QMessageBox::Cancel )
350 {
351 return;
352 }
353
354 if ( !QgsApplication::authManager()->removeCertIdentity( digest ) )
355 {
356 messageBar()->pushMessage( tr( "ERROR removing cert identity from authentication database for id %1:" ).arg( digest ),
358 return;
359 }
360
361 item->parent()->removeChild( item );
362 delete item;
363}
364
365void QgsAuthIdentitiesEditor::btnInfoIdentity_clicked()
366{
367 if ( treeIdentities->selectionModel()->selection().length() > 0 )
368 {
369 QTreeWidgetItem *item( treeIdentities->currentItem() );
370 handleDoubleClick( item, 0 );
371 }
372}
373
374void QgsAuthIdentitiesEditor::btnGroupByOrg_toggled( bool checked )
375{
376 if ( !QgsApplication::authManager()->storeAuthSetting( QStringLiteral( "identitiessortby" ), QVariant( checked ) ) )
377 {
378 authMessageLog( QObject::tr( "Could not store sort by preference." ),
379 QObject::tr( "Authentication Identities" ),
381 }
382 populateIdentitiesView();
383}
384
385void QgsAuthIdentitiesEditor::authMessageLog( const QString &message, const QString &authtag, Qgis::MessageLevel level )
386{
387 messageBar()->pushMessage( authtag, message, level, 7 );
388}
389
391{
392 if ( !mDisabled )
393 {
394 treeIdentities->setFocus();
395 }
396 QWidget::showEvent( e );
397}
398
399QgsMessageBar *QgsAuthIdentitiesEditor::messageBar()
400{
401 return msgBar;
402}
403
404int QgsAuthIdentitiesEditor::messageTimeout()
405{
406 const QgsSettings settings;
407 return settings.value( QStringLiteral( "qgis/messageTimeout" ), 5 ).toInt();
408}
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.
Dialog wrapper for widget displaying detailed info on a certificate and its hierarchical trust chain.
static QString resolvedCertName(const QSslCertificate &cert, bool issuer=false)
Gets the general name via RFC 5280 resolution.
static QMap< QString, QList< QSslCertificate > > certsGroupedByOrg(const QList< QSslCertificate > &certs)
Map certificates to their oraganization.
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 QColor redColor()
Red color representing invalid, untrusted, etc. certificate.
void showEvent(QShowEvent *e) override
Overridden show event of base widget.
QgsAuthIdentitiesEditor(QWidget *parent=nullptr)
Widget for editing authentication configurations directly in database.
Widget for importing an identity certificate/key bundle into the authentication database.
QgsAuthImportIdentityDialog::IdentityType identityType()
Gets identity type.
const QPair< QSslCertificate, QSslKey > certBundleToImport()
Gets certificate/key bundle to be imported.
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.
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