18 #include "ui_qgsauthauthoritieseditor.h"
24 #include <QFileDialog>
27 #include <QMessageBox>
29 #include <QPushButton>
30 #include <QSslConfiguration>
32 #include "qgssettings.h"
48 mAuthNotifyLayout =
new QVBoxLayout;
49 this->setLayout( mAuthNotifyLayout );
51 mAuthNotifyLayout->addWidget( mAuthNotify );
56 connect( btnAddCa, &QToolButton::clicked,
this, &QgsAuthAuthoritiesEditor::btnAddCa_clicked );
57 connect( btnRemoveCa, &QToolButton::clicked,
this, &QgsAuthAuthoritiesEditor::btnRemoveCa_clicked );
58 connect( btnInfoCa, &QToolButton::clicked,
this, &QgsAuthAuthoritiesEditor::btnInfoCa_clicked );
59 connect( btnGroupByOrg, &QToolButton::toggled,
this, &QgsAuthAuthoritiesEditor::btnGroupByOrg_toggled );
60 connect( btnCaFile, &QToolButton::clicked,
this, &QgsAuthAuthoritiesEditor::btnCaFile_clicked );
61 connect( btnCaFileClear, &QToolButton::clicked,
this, &QgsAuthAuthoritiesEditor::btnCaFileClear_clicked );
64 this, &QgsAuthAuthoritiesEditor::authMessageOut );
67 this, &QgsAuthAuthoritiesEditor::refreshCaCertsView );
71 connect( treeWidgetCAs->selectionModel(), &QItemSelectionModel::selectionChanged,
72 this, &QgsAuthAuthoritiesEditor::selectionChanged );
74 connect( treeWidgetCAs, &QTreeWidget::itemDoubleClicked,
75 this, &QgsAuthAuthoritiesEditor::handleDoubleClick );
77 connect( btnViewRefresh, &QAbstractButton::clicked,
this, &QgsAuthAuthoritiesEditor::refreshCaCertsView );
80 if ( !cafileval.isNull() )
82 leCaFile->setText( cafileval.toString() );
85 btnGroupByOrg->setChecked(
false );
87 if ( !sortbyval.isNull() )
88 btnGroupByOrg->setChecked( sortbyval.toBool() );
91 populateCaCertsView();
94 populateUtilitiesMenu();
98 static void setItemBold_( QTreeWidgetItem *item )
100 item->setFirstColumnSpanned(
true );
101 QFont secf( item->font( 0 ) );
102 secf.setBold(
true );
103 item->setFont( 0, secf );
106 void QgsAuthAuthoritiesEditor::setupCaCertsTree()
108 treeWidgetCAs->setColumnCount( 4 );
109 treeWidgetCAs->setHeaderLabels(
110 QStringList() << tr(
"Common Name" )
112 << tr(
"Expiry Date" )
113 << tr(
"Trust Policy" ) );
114 treeWidgetCAs->setColumnWidth( 0, 300 );
115 treeWidgetCAs->setColumnWidth( 1, 75 );
116 treeWidgetCAs->setColumnWidth( 2, 200 );
119 mDbCaSecItem =
new QTreeWidgetItem(
122 static_cast<int>( QgsAuthAuthoritiesEditor::Section ) );
123 setItemBold_( mDbCaSecItem );
124 mDbCaSecItem->setFlags( Qt::ItemIsEnabled );
125 mDbCaSecItem->setExpanded(
true );
126 treeWidgetCAs->insertTopLevelItem( 0, mDbCaSecItem );
128 mFileCaSecItem =
new QTreeWidgetItem(
131 static_cast<int>( QgsAuthAuthoritiesEditor::Section ) );
132 setItemBold_( mFileCaSecItem );
133 mFileCaSecItem->setFlags( Qt::ItemIsEnabled );
134 mFileCaSecItem->setExpanded(
true );
135 treeWidgetCAs->insertTopLevelItem( 0, mFileCaSecItem );
137 mRootCaSecItem =
new QTreeWidgetItem(
140 static_cast<int>( QgsAuthAuthoritiesEditor::Section ) );
141 setItemBold_( mRootCaSecItem );
142 mRootCaSecItem->setFlags( Qt::ItemIsEnabled );
143 mRootCaSecItem->setExpanded(
false );
144 treeWidgetCAs->insertTopLevelItem( 0, mRootCaSecItem );
147 void QgsAuthAuthoritiesEditor::populateCaCertsView()
149 updateCertTrustPolicyCache();
150 populateDatabaseCaCerts();
151 populateFileCaCerts();
152 populateRootCaCerts();
155 void QgsAuthAuthoritiesEditor::refreshCaCertsView()
158 populateCaCertsView();
161 static void removeChildren_( QTreeWidgetItem *item )
163 const auto constTakeChildren = item->takeChildren();
164 for ( QTreeWidgetItem *child : constTakeChildren )
170 void QgsAuthAuthoritiesEditor::populateDatabaseCaCerts()
172 removeChildren_( mDbCaSecItem );
174 bool expanded = mDbCaSecItem->isExpanded();
175 populateCaCertsSection( mDbCaSecItem,
177 QgsAuthAuthoritiesEditor::DbCaCert );
178 mDbCaSecItem->setExpanded( expanded );
181 void QgsAuthAuthoritiesEditor::populateFileCaCerts()
183 removeChildren_( mFileCaSecItem );
185 bool expanded = mFileCaSecItem->isExpanded();
186 populateCaCertsSection( mFileCaSecItem,
188 QgsAuthAuthoritiesEditor::FileCaCert );
189 mFileCaSecItem->setExpanded( expanded );
192 void QgsAuthAuthoritiesEditor::populateRootCaCerts()
194 removeChildren_( mRootCaSecItem );
196 bool expanded = mRootCaSecItem->isExpanded();
197 populateCaCertsSection( mRootCaSecItem,
199 QgsAuthAuthoritiesEditor::RootCaCert );
200 mRootCaSecItem->setExpanded( expanded );
203 void QgsAuthAuthoritiesEditor::populateCaCertsSection( QTreeWidgetItem *item,
const QList<QSslCertificate> &certs,
204 QgsAuthAuthoritiesEditor::CaType catype )
206 if ( btnGroupByOrg->isChecked() )
208 appendCertsToGroup( certs, catype, item );
212 appendCertsToItem( certs, catype, item );
216 void QgsAuthAuthoritiesEditor::appendCertsToGroup(
const QList<QSslCertificate> &certs,
217 QgsAuthAuthoritiesEditor::CaType catype,
218 QTreeWidgetItem *parent )
225 parent = treeWidgetCAs->currentItem();
229 QMap< QString, QList<QSslCertificate> > orgcerts(
232 QMap< QString, QList<QSslCertificate> >::const_iterator it = orgcerts.constBegin();
233 for ( ; it != orgcerts.constEnd(); ++it )
235 QTreeWidgetItem *grpitem(
new QTreeWidgetItem( parent,
236 QStringList() << it.key(),
237 static_cast<int>( QgsAuthAuthoritiesEditor::OrgName ) ) );
238 grpitem->setFirstColumnSpanned(
true );
239 grpitem->setFlags( Qt::ItemIsEnabled );
240 grpitem->setExpanded(
true );
242 QBrush orgb( grpitem->foreground( 0 ) );
243 orgb.setColor( QColor::fromRgb( 90, 90, 90 ) );
244 grpitem->setForeground( 0, orgb );
245 QFont grpf( grpitem->font( 0 ) );
246 grpf.setItalic(
true );
247 grpitem->setFont( 0, grpf );
249 appendCertsToItem( it.value(), catype, grpitem );
252 parent->sortChildren( 0, Qt::AscendingOrder );
255 void QgsAuthAuthoritiesEditor::appendCertsToItem(
const QList<QSslCertificate> &certs,
256 QgsAuthAuthoritiesEditor::CaType catype,
257 QTreeWidgetItem *parent )
264 parent = treeWidgetCAs->currentItem();
274 const auto constCerts = certs;
275 for (
const QSslCertificate &cert : constCerts )
281 coltxts << QString( cert.serialNumber() );
282 coltxts << cert.expiryDate().toString();
286 if ( trustedids.contains(
id ) )
290 else if ( untrustedids.contains(
id )
291 || cert.isBlacklisted()
293 || cert.expiryDate() <= QDateTime::currentDateTime()
294 || cert.effectiveDate() > QDateTime::currentDateTime() )
300 QTreeWidgetItem *item(
new QTreeWidgetItem( parent, coltxts,
static_cast<int>( catype ) ) );
303 if ( cert.isBlacklisted()
305 || cert.expiryDate() <= QDateTime::currentDateTime()
306 || cert.effectiveDate() > QDateTime::currentDateTime() )
308 item->setForeground( 2, redb );
312 if ( trustedids.contains(
id ) )
314 item->setForeground( 3, greenb );
315 if ( !cert.isBlacklisted()
317 && cert.expiryDate() > QDateTime::currentDateTime()
318 && cert.effectiveDate() <= QDateTime::currentDateTime() )
323 else if ( untrustedids.contains(
id ) )
325 item->setForeground( 3, redb );
333 item->setData( 0, Qt::UserRole,
id );
336 parent->sortChildren( 0, Qt::AscendingOrder );
339 void QgsAuthAuthoritiesEditor::updateCertTrustPolicyCache()
344 void QgsAuthAuthoritiesEditor::populateUtilitiesMenu()
346 mActionDefaultTrustPolicy =
new QAction( QStringLiteral(
"Change default trust policy" ),
this );
347 connect( mActionDefaultTrustPolicy, &QAction::triggered,
this, &QgsAuthAuthoritiesEditor::editDefaultTrustPolicy );
349 mActionShowTrustedCAs =
new QAction( QStringLiteral(
"Show trusted authorities/issuers" ),
this );
350 connect( mActionShowTrustedCAs, &QAction::triggered,
this, &QgsAuthAuthoritiesEditor::showTrustedCertificateAuthorities );
352 mUtilitiesMenu =
new QMenu(
this );
353 mUtilitiesMenu->addAction( mActionDefaultTrustPolicy );
354 mUtilitiesMenu->addSeparator();
355 mUtilitiesMenu->addAction( mActionShowTrustedCAs );
357 btnUtilities->setMenu( mUtilitiesMenu );
360 void QgsAuthAuthoritiesEditor::showCertInfo( QTreeWidgetItem *item )
365 QString digest( item->data( 0, Qt::UserRole ).toString() );
367 QMap<QString, QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> > cacertscache(
370 if ( !cacertscache.contains( digest ) )
372 QgsDebugMsg( QStringLiteral(
"Certificate Authority not in CA certs cache" ) );
376 QSslCertificate cert( cacertscache.value( digest ).second );
379 dlg->setWindowModality( Qt::WindowModal );
380 dlg->resize( 675, 500 );
385 populateCaCertsView();
390 void QgsAuthAuthoritiesEditor::selectionChanged(
const QItemSelection &selected,
const QItemSelection &deselected )
393 Q_UNUSED( deselected )
397 void QgsAuthAuthoritiesEditor::checkSelection()
400 bool isdbcert =
false;
401 if ( treeWidgetCAs->selectionModel()->selection().length() > 0 )
403 QTreeWidgetItem *item( treeWidgetCAs->currentItem() );
405 switch ( ( QgsAuthAuthoritiesEditor::CaType )item->type() )
407 case QgsAuthAuthoritiesEditor::RootCaCert:
410 case QgsAuthAuthoritiesEditor::FileCaCert:
413 case QgsAuthAuthoritiesEditor::DbCaCert:
422 btnRemoveCa->setEnabled( isdbcert );
423 btnInfoCa->setEnabled( iscert );
426 void QgsAuthAuthoritiesEditor::handleDoubleClick( QTreeWidgetItem *item,
int col )
431 switch ( ( QgsAuthAuthoritiesEditor::CaType )item->type() )
433 case QgsAuthAuthoritiesEditor::Section:
436 case QgsAuthAuthoritiesEditor::OrgName:
445 showCertInfo( item );
449 void QgsAuthAuthoritiesEditor::btnAddCa_clicked()
452 dlg->setWindowModality( Qt::WindowModal );
453 dlg->resize( 400, 450 );
459 messageBar()->
pushMessage( tr(
"ERROR storing CA(s) in authentication database" ),
460 Qgis::MessageLevel::Critical );
467 const auto constCerts = certs;
468 for (
const QSslCertificate &cert : constCerts )
472 authMessageOut( QObject::tr(
"Could not set trust policy for imported certificates" ),
473 QObject::tr(
"Authorities Manager" ),
478 updateCertTrustPolicyCache();
482 populateDatabaseCaCerts();
483 mDbCaSecItem->setExpanded(
true );
488 void QgsAuthAuthoritiesEditor::btnRemoveCa_clicked()
490 QTreeWidgetItem *item( treeWidgetCAs->currentItem() );
494 QgsDebugMsg( QStringLiteral(
"Current tree widget item not set" ) );
498 QString digest( item->data( 0, Qt::UserRole ).toString() );
500 if ( digest.isEmpty() )
502 messageBar()->
pushMessage( tr(
"Certificate id missing" ),
503 Qgis::MessageLevel::Warning );
507 QMap<QString, QSslCertificate> mappedcerts(
510 if ( !mappedcerts.contains( digest ) )
512 QgsDebugMsg( QStringLiteral(
"Certificate Authority not in mapped database CAs" ) );
516 if ( QMessageBox::warning(
517 this, tr(
"Remove Certificate Authority" ),
518 tr(
"Are you sure you want to remove the selected "
519 "Certificate Authority from the database?\n\n"
520 "Operation can NOT be undone!" ),
521 QMessageBox::Ok | QMessageBox::Cancel,
522 QMessageBox::Cancel ) == QMessageBox::Cancel )
527 QSslCertificate cert( mappedcerts.value( digest ) );
531 messageBar()->
pushMessage( tr(
"Certificate could not be found in database for id %1:" ).arg( digest ),
532 Qgis::MessageLevel::Warning );
538 messageBar()->
pushMessage( tr(
"ERROR removing CA from authentication database for id %1:" ).arg( digest ),
539 Qgis::MessageLevel::Critical );
545 messageBar()->
pushMessage( tr(
"ERROR removing cert trust policy from authentication database for id %1:" ).arg( digest ),
546 Qgis::MessageLevel::Critical );
552 updateCertTrustPolicyCache();
554 item->parent()->removeChild( item );
558 mDbCaSecItem->setExpanded(
true );
561 void QgsAuthAuthoritiesEditor::btnInfoCa_clicked()
563 if ( treeWidgetCAs->selectionModel()->selection().length() > 0 )
565 QTreeWidgetItem *item( treeWidgetCAs->currentItem() );
566 handleDoubleClick( item, 0 );
570 void QgsAuthAuthoritiesEditor::btnGroupByOrg_toggled(
bool checked )
574 authMessageOut( QObject::tr(
"Could not store sort by preference" ),
575 QObject::tr(
"Authorities Manager" ),
578 populateCaCertsView();
581 void QgsAuthAuthoritiesEditor::editDefaultTrustPolicy()
583 QDialog *dlg =
new QDialog(
this );
584 dlg->setWindowTitle( tr(
"Default Trust Policy" ) );
585 QVBoxLayout *layout =
new QVBoxLayout( dlg );
587 QHBoxLayout *hlayout =
new QHBoxLayout();
589 QLabel *lblwarn =
new QLabel( dlg );
590 QStyle *style = QApplication::style();
591 lblwarn->setPixmap( style->standardIcon( QStyle::SP_MessageBoxWarning ).pixmap( 48, 48 ) );
592 lblwarn->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
593 hlayout->addWidget( lblwarn );
595 QLabel *lbltxt =
new QLabel( dlg );
596 lbltxt->setText( tr(
"Changing the default certificate authority trust policy to 'Untrusted' "
597 "can cause unexpected SSL network connection results." ) );
598 lbltxt->setWordWrap(
true );
599 hlayout->addWidget( lbltxt );
601 layout->addLayout( hlayout );
603 QHBoxLayout *hlayout2 =
new QHBoxLayout();
605 QLabel *lblpolicy =
new QLabel( tr(
"Default policy" ), dlg );
606 lblpolicy->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );
607 hlayout2->addWidget( lblpolicy );
609 QComboBox *cmbpolicy =
new QComboBox( dlg );
610 QList < QPair<QgsAuthCertUtils::CertTrustPolicy, QString> > policies;
616 for (
int i = 0; i < policies.size(); i++ )
618 cmbpolicy->addItem( policies.at( i ).second, QVariant(
static_cast<int>( policies.at( i ).first ) ) );
621 int idx = cmbpolicy->findData( QVariant(
static_cast<int>( mDefaultTrustPolicy ) ) );
622 cmbpolicy->setCurrentIndex( idx == -1 ? 0 : idx );
623 hlayout2->addWidget( cmbpolicy );
625 layout->addLayout( hlayout2 );
627 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Close | QDialogButtonBox::Ok,
628 Qt::Horizontal, dlg );
629 buttonBox->button( QDialogButtonBox::Close )->setDefault(
true );
631 layout->addWidget( buttonBox );
633 connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
634 connect( buttonBox, &QDialogButtonBox::rejected, dlg, &QWidget::close );
636 dlg->setLayout( layout );
637 dlg->setWindowModality( Qt::WindowModal );
638 dlg->resize( 400, 200 );
639 dlg->setMinimumSize( 400, 200 );
640 dlg->setMaximumSize( 500, 300 );
645 if ( mDefaultTrustPolicy != trustpolicy )
647 defaultTrustPolicyChanged( trustpolicy );
657 authMessageOut( QObject::tr(
"Could not store default trust policy." ),
658 QObject::tr(
"Authorities Manager" ),
661 mDefaultTrustPolicy = trustpolicy;
664 populateCaCertsView();
667 void QgsAuthAuthoritiesEditor::btnCaFile_clicked()
672 dlg->setWindowModality( Qt::WindowModal );
673 dlg->resize( 400, 250 );
677 if ( !leCaFile->text().isEmpty() )
679 btnCaFileClear_clicked();
683 leCaFile->setText( fn );
687 authMessageOut( QObject::tr(
"Could not store 'CA file path' in authentication database." ),
688 QObject::tr(
"Authorities Manager" ),
694 authMessageOut( QObject::tr(
"Could not store 'CA file allow invalids' setting in authentication database." ),
695 QObject::tr(
"Authorities Manager" ),
704 const auto constCerts = certs;
705 for (
const QSslCertificate &cert : constCerts )
709 authMessageOut( QObject::tr(
"Could not set trust policy for imported certificates." ),
710 QObject::tr(
"Authorities Manager" ),
715 updateCertTrustPolicyCache();
720 populateFileCaCerts();
721 mFileCaSecItem->setExpanded(
true );
726 void QgsAuthAuthoritiesEditor::btnCaFileClear_clicked()
730 authMessageOut( QObject::tr(
"Could not remove 'CA file path' from authentication database." ),
731 QObject::tr(
"Authorities Manager" ),
737 authMessageOut( QObject::tr(
"Could not remove 'CA file allow invalids' setting from authentication database." ),
738 QObject::tr(
"Authorities Manager" ),
745 QString fn( leCaFile->text() );
746 if ( QFile::exists( fn ) )
750 if ( !certs.isEmpty() )
754 messageBar()->
pushMessage( tr(
"ERROR removing cert(s) trust policy from authentication database." ),
755 Qgis::MessageLevel::Critical );
759 updateCertTrustPolicyCache();
766 populateFileCaCerts();
769 void QgsAuthAuthoritiesEditor::showTrustedCertificateAuthorities()
772 dlg->setWindowModality( Qt::WindowModal );
773 dlg->resize( 675, 500 );
780 int levelint =
static_cast<int>( level );
788 treeWidgetCAs->setFocus();
790 QWidget::showEvent( e );
798 int QgsAuthAuthoritiesEditor::messageTimeout()
800 QgsSettings settings;
801 return settings.value( QStringLiteral(
"qgis/messageTimeout" ), 5 ).toInt();
MessageLevel
Level for messages This will be used both for message log and message bar in application.
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.
void showEvent(QShowEvent *e) override
Overridden show event of base widget.
QgsAuthAuthoritiesEditor(QWidget *parent=nullptr)
Widget for viewing and editing certificate authorities directly in database.
Dialog wrapper for widget displaying detailed info on a certificate and its hierarchical trust chain.
bool trustCacheRebuilt()
Whether the trust cache has been rebuilt.
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 getCertTrustName(QgsAuthCertUtils::CertTrustPolicy trust)
Gets the general name for certificate trust.
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Gets the sha1 hash for certificate.
CertTrustPolicy
Type of certificate trust policy.
static QList< QSslCertificate > certsFromFile(const QString &certspath)
Returns a list of concatenated certs from a PEM or DER formatted file.
static QString getCaSourceName(QgsAuthCertUtils::CaCertSource source, bool single=false)
Gets the general name for CA source enum type.
static QColor greenColor()
Green color representing valid, trusted, etc. certificate.
static QColor redColor()
Red color representing invalid, untrusted, etc. certificate.
Widget for importing a certificate into the authentication database.
QgsAuthCertUtils::CertTrustPolicy certTrustPolicy()
Defined trust policy for imported certificates.
const QString certFileToImport()
Gets the file path to a certificate to import.
const QList< QSslCertificate > certificatesToImport()
Gets list of certificate objects to import.
bool allowInvalidCerts()
Whether to allow importation of invalid certificates (so trust policy can be overridden)
const QMap< QgsAuthCertUtils::CertTrustPolicy, QStringList > certTrustCache()
certTrustCache get cache of certificate sha1s, per trust policy
MessageLevel
Message log level (mirrors that of QgsMessageLog, so it can also output there)
void messageOut(const QString &message, const QString &tag=QgsAuthManager::AUTH_MAN_TAG, QgsAuthManager::MessageLevel level=QgsAuthManager::INFO) const
Custom logging signal to relay to console output and QgsMessageLog.
bool rebuildCaCertsCache()
Rebuild certificate authority cache.
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 ))
QgsAuthCertUtils::CertTrustPolicy defaultCertTrustPolicy()
Gets the default certificate trust policy preferred by user.
bool rebuildCertTrustCache()
Rebuild certificate authority cache.
bool rebuildTrustedCaCertsCache()
Rebuild trusted certificate authorities cache.
Widget for listing trusted Certificate (Intermediate) Authorities used in secure connections.
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.