QGIS API Documentation 3.41.0-Master (cea29feecf2)
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
53 connect( QgsApplication::authManager(), &QgsAuthManager::messageLog, this, &QgsAuthIdentitiesEditor::authMessageLog );
54
55 connect( QgsApplication::authManager(), &QgsAuthManager::authDatabaseChanged, this, &QgsAuthIdentitiesEditor::refreshIdentitiesView );
56
57 setupIdentitiesTree();
58
59 connect( treeIdentities->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAuthIdentitiesEditor::selectionChanged );
60
61 connect( treeIdentities, &QTreeWidget::itemDoubleClicked, this, &QgsAuthIdentitiesEditor::handleDoubleClick );
62
63 connect( btnViewRefresh, &QAbstractButton::clicked, this, &QgsAuthIdentitiesEditor::refreshIdentitiesView );
64
65 btnGroupByOrg->setChecked( false );
66 const QVariant sortbyval = QgsApplication::authManager()->authSetting( QStringLiteral( "identitiessortby" ), QVariant( false ) );
67 if ( !QgsVariantUtils::isNull( sortbyval ) )
68 btnGroupByOrg->setChecked( sortbyval.toBool() );
69
70 populateIdentitiesView();
71 checkSelection();
72 }
73}
74
75void QgsAuthIdentitiesEditor::setupIdentitiesTree()
76{
77 treeIdentities->setColumnCount( 3 );
78 treeIdentities->setHeaderLabels(
79 QStringList() << tr( "Common Name" )
80 << tr( "Serial #" )
81 << tr( "Expiry Date" )
82 );
83 treeIdentities->setColumnWidth( 0, 300 );
84 treeIdentities->setColumnWidth( 1, 75 );
85
86 // add root sections
87 mRootCertIdentItem = new QTreeWidgetItem(
88 treeIdentities,
89 QStringList( tr( "Certificate Bundles" ) ),
90 static_cast<int>( QgsAuthIdentitiesEditor::Section )
91 );
92 QgsAuthGuiUtils::setItemBold( mRootCertIdentItem );
93 mRootCertIdentItem->setFlags( Qt::ItemIsEnabled );
94 mRootCertIdentItem->setExpanded( true );
95 treeIdentities->insertTopLevelItem( 0, mRootCertIdentItem );
96}
97
98void QgsAuthIdentitiesEditor::populateIdentitiesView()
99{
100 QgsAuthGuiUtils::removeChildren( mRootCertIdentItem );
101
102 populateIdentitiesSection( mRootCertIdentItem, QgsApplication::authManager()->certIdentities(), QgsAuthIdentitiesEditor::CertIdentity );
103}
104
105void QgsAuthIdentitiesEditor::refreshIdentitiesView()
106{
107 populateIdentitiesView();
108}
109
110void QgsAuthIdentitiesEditor::populateIdentitiesSection( QTreeWidgetItem *item, const QList<QSslCertificate> &certs, QgsAuthIdentitiesEditor::IdentityType identype )
111{
112 if ( btnGroupByOrg->isChecked() )
113 {
114 appendIdentitiesToGroup( certs, identype, item );
115 }
116 else
117 {
118 appendIdentitiesToItem( certs, identype, item );
119 }
120}
121
122void QgsAuthIdentitiesEditor::appendIdentitiesToGroup( const QList<QSslCertificate> &certs, QgsAuthIdentitiesEditor::IdentityType identype, QTreeWidgetItem *parent )
123{
124 if ( certs.empty() )
125 return;
126
127 if ( !parent )
128 {
129 parent = treeIdentities->currentItem();
130 }
131
132 // TODO: find all organizational name, sort and make subsections
133 const QMap<QString, QList<QSslCertificate>> orgcerts(
135 );
136
137 QMap<QString, QList<QSslCertificate>>::const_iterator it = orgcerts.constBegin();
138 for ( ; it != orgcerts.constEnd(); ++it )
139 {
140 QTreeWidgetItem *grpitem( new QTreeWidgetItem( parent, QStringList() << it.key(), static_cast<int>( QgsAuthIdentitiesEditor::OrgName ) ) );
141 grpitem->setFirstColumnSpanned( true );
142 grpitem->setFlags( Qt::ItemIsEnabled );
143 grpitem->setExpanded( true );
144
145 QBrush orgb( grpitem->foreground( 0 ) );
146 orgb.setColor( QColor::fromRgb( 90, 90, 90 ) );
147 grpitem->setForeground( 0, orgb );
148 QFont grpf( grpitem->font( 0 ) );
149 grpf.setItalic( true );
150 grpitem->setFont( 0, grpf );
151
152 appendIdentitiesToItem( it.value(), identype, grpitem );
153 }
154
155 parent->sortChildren( 0, Qt::AscendingOrder );
156}
157
158void QgsAuthIdentitiesEditor::appendIdentitiesToItem( const QList<QSslCertificate> &certs, QgsAuthIdentitiesEditor::IdentityType identype, QTreeWidgetItem *parent )
159{
160 if ( certs.empty() )
161 return;
162
163 if ( !parent )
164 {
165 parent = treeIdentities->currentItem();
166 }
167
168 const QBrush redb( QgsAuthGuiUtils::redColor() );
169
170 // Columns: Common Name, Serial #, Expiry Date
171 const auto constCerts = certs;
172 for ( const QSslCertificate &cert : constCerts )
173 {
174 const QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
175
176 QStringList coltxts;
177 coltxts << QgsAuthCertUtils::resolvedCertName( cert );
178 coltxts << QString( cert.serialNumber() );
179 coltxts << cert.expiryDate().toString();
180
181 QTreeWidgetItem *item( new QTreeWidgetItem( parent, coltxts, static_cast<int>( identype ) ) );
182
183 item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificate.svg" ) ) );
184 if ( !QgsAuthCertUtils::certIsViable( cert ) )
185 {
186 item->setForeground( 2, redb );
187 item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificateUntrusted.svg" ) ) );
188 }
189
190 item->setData( 0, Qt::UserRole, id );
191 }
192
193 parent->sortChildren( 0, Qt::AscendingOrder );
194}
195
196void QgsAuthIdentitiesEditor::showCertInfo( QTreeWidgetItem *item )
197{
198 if ( !item )
199 return;
200
201 const QString digest( item->data( 0, Qt::UserRole ).toString() );
202
203 if ( !QgsApplication::authManager()->existsCertIdentity( digest ) )
204 {
205 QgsDebugError( QStringLiteral( "Certificate identity does not exist in database" ) );
206 return;
207 }
208
209 const QSslCertificate cert( QgsApplication::authManager()->certIdentity( digest ) );
210
211 QgsAuthCertInfoDialog *dlg = new QgsAuthCertInfoDialog( cert, false, this );
212 dlg->setWindowModality( Qt::WindowModal );
213 dlg->resize( 675, 500 );
214 dlg->exec();
215 dlg->deleteLater();
216}
217
218void QgsAuthIdentitiesEditor::selectionChanged( const QItemSelection &selected, const QItemSelection &deselected )
219{
220 Q_UNUSED( selected )
221 Q_UNUSED( deselected )
222 checkSelection();
223}
224
225void QgsAuthIdentitiesEditor::checkSelection()
226{
227 bool iscert = false;
228 if ( treeIdentities->selectionModel()->selection().length() > 0 )
229 {
230 QTreeWidgetItem *item( treeIdentities->currentItem() );
231
232 switch ( ( QgsAuthIdentitiesEditor::IdentityType ) item->type() )
233 {
234 case QgsAuthIdentitiesEditor::CertIdentity:
235 iscert = true;
236 break;
237 default:
238 break;
239 }
240 }
241
242 btnRemoveIdentity->setEnabled( iscert );
243 btnInfoIdentity->setEnabled( iscert );
244}
245
246void QgsAuthIdentitiesEditor::handleDoubleClick( QTreeWidgetItem *item, int col )
247{
248 Q_UNUSED( col )
249 bool iscert = true;
250
251 switch ( ( QgsAuthIdentitiesEditor::IdentityType ) item->type() )
252 {
253 case QgsAuthIdentitiesEditor::Section:
254 iscert = false;
255 break;
256 case QgsAuthIdentitiesEditor::OrgName:
257 iscert = false;
258 break;
259 default:
260 break;
261 }
262
263 if ( iscert )
264 {
265 showCertInfo( item );
266 }
267}
268
269void QgsAuthIdentitiesEditor::btnAddIdentity_clicked()
270{
272 dlg->setWindowModality( Qt::WindowModal );
273 dlg->resize( 400, dlg->height() );
274 if ( dlg->exec() )
275 {
277 {
278 const QPair<QSslCertificate, QSslKey> &bundle( dlg->certBundleToImport() );
279 if ( !QgsApplication::authManager()->storeCertIdentity( bundle.first, bundle.second ) )
280 {
281 messageBar()->pushMessage( tr( "ERROR storing identity bundle in authentication database." ), Qgis::MessageLevel::Critical );
282 }
283 populateIdentitiesView();
284 mRootCertIdentItem->setExpanded( true );
285 }
286 }
287 dlg->deleteLater();
288}
289
290void QgsAuthIdentitiesEditor::btnRemoveIdentity_clicked()
291{
292 QTreeWidgetItem *item( treeIdentities->currentItem() );
293
294 if ( !item )
295 {
296 QgsDebugMsgLevel( QStringLiteral( "Current tree widget item not set" ), 2 );
297 return;
298 }
299
300 const QString digest( item->data( 0, Qt::UserRole ).toString() );
301
302 if ( digest.isEmpty() )
303 {
304 messageBar()->pushMessage( tr( "Certificate id missing." ), Qgis::MessageLevel::Warning );
305 return;
306 }
307
308 if ( !QgsApplication::authManager()->existsCertIdentity( digest ) )
309 {
310 QgsDebugError( QStringLiteral( "Certificate identity does not exist in database" ) );
311 return;
312 }
313
314 if ( QMessageBox::warning(
315 this, tr( "Remove Certificate Identity" ),
316 tr( "Are you sure you want to remove the selected "
317 "certificate identity from the database?\n\n"
318 "Operation can NOT be undone!" ),
319 QMessageBox::Ok | QMessageBox::Cancel,
320 QMessageBox::Cancel
321 )
322 == QMessageBox::Cancel )
323 {
324 return;
325 }
326
327 if ( !QgsApplication::authManager()->removeCertIdentity( digest ) )
328 {
329 messageBar()->pushMessage( tr( "ERROR removing cert identity from authentication database for id %1:" ).arg( digest ), Qgis::MessageLevel::Critical );
330 return;
331 }
332
333 item->parent()->removeChild( item );
334 delete item;
335}
336
337void QgsAuthIdentitiesEditor::btnInfoIdentity_clicked()
338{
339 if ( treeIdentities->selectionModel()->selection().length() > 0 )
340 {
341 QTreeWidgetItem *item( treeIdentities->currentItem() );
342 handleDoubleClick( item, 0 );
343 }
344}
345
346void QgsAuthIdentitiesEditor::btnGroupByOrg_toggled( bool checked )
347{
348 if ( !QgsApplication::authManager()->storeAuthSetting( QStringLiteral( "identitiessortby" ), QVariant( checked ) ) )
349 {
350 authMessageLog( QObject::tr( "Could not store sort by preference." ), QObject::tr( "Authentication Identities" ), Qgis::MessageLevel::Warning );
351 }
352 populateIdentitiesView();
353}
354
355void QgsAuthIdentitiesEditor::authMessageLog( const QString &message, const QString &authtag, Qgis::MessageLevel level )
356{
357 messageBar()->pushMessage( authtag, message, level, 7 );
358}
359
361{
362 if ( !mDisabled )
363 {
364 treeIdentities->setFocus();
365 }
366 QWidget::showEvent( e );
367}
368
369QgsMessageBar *QgsAuthIdentitiesEditor::messageBar()
370{
371 return msgBar;
372}
373
374int QgsAuthIdentitiesEditor::messageTimeout()
375{
376 const QgsSettings settings;
377 return settings.value( QStringLiteral( "qgis/messageTimeout" ), 5 ).toInt();
378}
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 void setItemBold(QTreeWidgetItem *item)
Call setFirstColumnSpanned(true) on the item and make its font bold.
static void removeChildren(QTreeWidgetItem *item)
Remove the children of the passed item.
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