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