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