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