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