17#include "ui_qgsauthimportidentitydialog.h"
34#include "moc_qgsauthimportidentitydialog.cpp"
36using namespace Qt::StringLiterals;
45 mAuthNotifyLayout =
new QVBoxLayout;
46 this->setLayout( mAuthNotifyLayout );
48 mAuthNotifyLayout->addWidget( mAuthNotify );
53 connect( lePkiPathsKeyPass, &QLineEdit::textChanged,
this, &QgsAuthImportIdentityDialog::lePkiPathsKeyPass_textChanged );
54 connect( chkPkiPathsPassShow, &QCheckBox::stateChanged,
this, &QgsAuthImportIdentityDialog::chkPkiPathsPassShow_stateChanged );
55 connect( btnPkiPathsCert, &QToolButton::clicked,
this, &QgsAuthImportIdentityDialog::btnPkiPathsCert_clicked );
56 connect( btnPkiPathsKey, &QToolButton::clicked,
this, &QgsAuthImportIdentityDialog::btnPkiPathsKey_clicked );
57 connect( lePkiPkcs12KeyPass, &QLineEdit::textChanged,
this, &QgsAuthImportIdentityDialog::lePkiPkcs12KeyPass_textChanged );
58 connect( chkPkiPkcs12PassShow, &QCheckBox::stateChanged,
this, &QgsAuthImportIdentityDialog::chkPkiPkcs12PassShow_stateChanged );
59 connect( btnPkiPkcs12Bundle, &QToolButton::clicked,
this, &QgsAuthImportIdentityDialog::btnPkiPkcs12Bundle_clicked );
60 connect( buttonBox, &QDialogButtonBox::rejected,
this, &QWidget::close );
61 connect( buttonBox, &QDialogButtonBox::accepted,
this, &QDialog::accept );
62 connect( buttonBox, &QDialogButtonBox::helpRequested,
this, [] {
63 QgsHelp::openHelp( u
"auth_system/auth_workflows.html#authentication-identities"_s );
65 mIdentityType = identitytype;
67 populateIdentityType();
84 return qMakePair( QSslCertificate(), QSslKey() );
89void QgsAuthImportIdentityDialog::populateIdentityType()
93 stkwBundleType->setVisible(
true );
98 connect( cmbIdentityTypes,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ), stkwBundleType, &QStackedWidget::setCurrentIndex );
99 connect( stkwBundleType, &QStackedWidget::currentChanged, cmbIdentityTypes, &QComboBox::setCurrentIndex );
101 connect( cmbIdentityTypes,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
this, [
this] { validateIdentity(); } );
102 connect( stkwBundleType, &QStackedWidget::currentChanged,
this, &QgsAuthImportIdentityDialog::validateIdentity );
104 cmbIdentityTypes->setCurrentIndex( 0 );
105 stkwBundleType->setCurrentIndex( 0 );
111void QgsAuthImportIdentityDialog::validateIdentity()
116 ok = validateBundle();
118 okButton()->setEnabled( ok );
121bool QgsAuthImportIdentityDialog::validateBundle()
124 const QSslCertificate emptycert;
125 const QSslKey emptykey;
126 mCertBundle = qMakePair( emptycert, emptykey );
127 mPkiBundle = QgsPkiBundle();
129 QWidget *curpage = stkwBundleType->currentWidget();
130 if ( curpage == pagePkiPaths )
132 return validatePkiPaths();
134 else if ( curpage == pagePkiPkcs12 )
136 return validatePkiPkcs12();
142void QgsAuthImportIdentityDialog::clearValidation()
144 teValidation->clear();
145 teValidation->setStyleSheet( QString() );
156 txt = tr(
"Valid: %1" ).arg( msg );
160 txt = tr(
"Invalid: %1" ).arg( msg );
165 teValidation->setStyleSheet( ss );
168 teValidation->append( txt );
172 teValidation->setText( txt );
174 teValidation->moveCursor( QTextCursor::Start );
177void QgsAuthImportIdentityDialog::lePkiPathsKeyPass_textChanged(
const QString &pass )
183void QgsAuthImportIdentityDialog::chkPkiPathsPassShow_stateChanged(
int state )
185 lePkiPathsKeyPass->setEchoMode( ( state > 0 ) ? QLineEdit::Normal : QLineEdit::Password );
188void QgsAuthImportIdentityDialog::btnPkiPathsCert_clicked()
190 const QString &fn = getOpenFileName( tr(
"Open Client Certificate File" ), tr(
"All files (*.*);;PEM (*.pem);;DER (*.der)" ) );
193 lePkiPathsCert->setText( fn );
198void QgsAuthImportIdentityDialog::btnPkiPathsKey_clicked()
200 const QString &fn = getOpenFileName( tr(
"Open Private Key File" ), tr(
"All files (*.*);;PEM (*.pem);;DER (*.der)" ) );
203 lePkiPathsKey->setText( fn );
208void QgsAuthImportIdentityDialog::lePkiPkcs12KeyPass_textChanged(
const QString &pass )
214void QgsAuthImportIdentityDialog::chkPkiPkcs12PassShow_stateChanged(
int state )
216 lePkiPkcs12KeyPass->setEchoMode( ( state > 0 ) ? QLineEdit::Normal : QLineEdit::Password );
219void QgsAuthImportIdentityDialog::btnPkiPkcs12Bundle_clicked()
221 const QString &fn = getOpenFileName( tr(
"Open PKCS#12 Certificate Bundle" ), tr(
"PKCS#12 (*.p12 *.pfx)" ) );
224 lePkiPkcs12Bundle->setText( fn );
229bool QgsAuthImportIdentityDialog::validatePkiPaths()
231 bool isvalid =
false;
234 const QString certpath( lePkiPathsCert->text() );
235 const QString keypath( lePkiPathsKey->text() );
237 const bool certfound = QFile::exists( certpath );
238 const bool keyfound = QFile::exists( keypath );
240 fileFound( certpath.isEmpty() || certfound, lePkiPathsCert );
241 fileFound( keypath.isEmpty() || keyfound, lePkiPathsKey );
243 if ( !certfound || !keyfound )
245 writeValidation( tr(
"Missing components" ),
Invalid );
250 QSslCertificate clientcert;
251 QList<QSslCertificate> certs( QgsAuthCertUtils::certsFromFile( certpath ) );
252 QList<QSslCertificate> ca_certs;
253 if ( !certs.isEmpty() )
255 clientcert = certs.takeFirst();
259 writeValidation( tr(
"Failed to read client certificate from file" ),
Invalid );
263 if ( clientcert.isNull() )
265 writeValidation( tr(
"Failed to load client certificate from file" ),
Invalid );
269 if ( !certs.isEmpty() )
271 teValidation->append( tr(
"Extra certificates found with identity" ) );
275 isvalid = QgsAuthCertUtils::certIsViable( clientcert );
277 const QDateTime startdate( clientcert.effectiveDate() );
278 const QDateTime enddate( clientcert.expiryDate() );
280 writeValidation( tr(
"%1 thru %2" ).arg( startdate.toString(), enddate.toString() ), ( QgsAuthCertUtils::certIsCurrent( clientcert ) ?
Valid :
Invalid ) );
284 const QString keypass( lePkiPathsKeyPass->text() );
285 const QSslKey clientkey( QgsAuthCertUtils::keyFromFile( keypath, keypass ) );
286 if ( clientkey.isNull() )
288 writeValidation( tr(
"Failed to load client private key from file" ),
Invalid,
true );
289 if ( !keypass.isEmpty() )
291 writeValidation( tr(
"Private key password may not match" ),
Invalid,
true );
298 mCertBundle = qMakePair( clientcert, clientkey );
299 mPkiBundle = QgsPkiBundle( clientcert, clientkey, ca_certs );
305bool QgsAuthImportIdentityDialog::validatePkiPkcs12()
308 const QString bundlepath( lePkiPkcs12Bundle->text() );
309 const bool bundlefound = QFile::exists( bundlepath );
310 fileFound( bundlepath.isEmpty() || bundlefound, lePkiPkcs12Bundle );
314 writeValidation( tr(
"Missing components" ),
Invalid );
318 if ( !QCA::isSupported(
"pkcs12" ) )
320 writeValidation( tr(
"QCA library has no PKCS#12 support" ),
Invalid );
325 QCA::SecureArray passarray;
326 QString keypass = QString();
327 if ( !lePkiPkcs12KeyPass->text().isEmpty() )
329 passarray = QCA::SecureArray( lePkiPkcs12KeyPass->text().toUtf8() );
330 keypass = lePkiPkcs12KeyPass->text();
333 QCA::ConvertResult res;
334 const QCA::KeyBundle bundle( QCA::KeyBundle::fromFile( bundlepath, passarray, &res, u
"qca-ossl"_s ) );
336 if ( res == QCA::ErrorFile )
338 writeValidation( tr(
"Failed to read bundle file" ),
Invalid );
341 else if ( res == QCA::ErrorPassphrase )
343 writeValidation( tr(
"Incorrect bundle password" ),
Invalid );
344 lePkiPkcs12KeyPass->setPlaceholderText( u
"Required passphrase"_s );
347 else if ( res == QCA::ErrorDecode )
349 writeValidation( tr(
"Failed to decode (try entering password)" ),
Invalid );
353 if ( bundle.isNull() )
355 writeValidation( tr(
"Bundle empty or can not be loaded" ),
Invalid );
360 const QCA::Certificate cert( bundle.certificateChain().primary() );
363 writeValidation( tr(
"Bundle client cert can not be loaded" ),
Invalid );
368 const QDateTime startdate( cert.notValidBefore() );
369 const QDateTime enddate( cert.notValidAfter() );
370 const QDateTime now( QDateTime::currentDateTime() );
371 const bool bundlevalid = ( now >= startdate && now <= enddate );
373 writeValidation( tr(
"%1 thru %2" ).arg( startdate.toString(), enddate.toString() ), ( bundlevalid ?
Valid :
Invalid ) );
377 QSslCertificate clientcert;
378 QList<QSslCertificate> certs( QgsAuthCertUtils::certsFromString( cert.toPEM() ) );
379 if ( !certs.isEmpty() )
381 clientcert = certs.first();
383 if ( clientcert.isNull() )
385 writeValidation( tr(
"Qt cert could not be created from QCA cert" ),
Invalid,
true );
389 clientkey = QSslKey( bundle.privateKey().toRSA().toPEM().toLatin1(), QSsl::Rsa );
390 if ( clientkey.isNull() )
392 writeValidation( tr(
"Qt private key could not be created from QCA key" ),
Invalid,
true );
396 const QCA::CertificateChain cert_chain( bundle.certificateChain() );
397 QList<QSslCertificate> ca_certs;
398 if ( cert_chain.size() > 1 )
400 const auto constCert_chain = cert_chain;
401 for (
const QCA::Certificate &ca_cert : constCert_chain )
403 if ( ca_cert != cert_chain.primary() )
405 ca_certs << QSslCertificate( ca_cert.toPEM().toLatin1() );
410 mCertBundle = qMakePair( clientcert, clientkey );
411 mPkiBundle = QgsPkiBundle( clientcert, clientkey, ca_certs );
417void QgsAuthImportIdentityDialog::fileFound(
bool found, QWidget *widget )
422 widget->setToolTip( tr(
"File not found" ) );
426 widget->setStyleSheet( QString() );
427 widget->setToolTip( QString() );
431QString QgsAuthImportIdentityDialog::getOpenFileName(
const QString &title,
const QString &extfilter )
433 QgsSettings settings;
434 const QString recentdir = settings.
value( u
"UI/lastAuthImportBundleOpenFileDir"_s, QDir::homePath() ).toString();
435 QString f = QFileDialog::getOpenFileName(
this, title, recentdir, extfilter );
439 this->activateWindow();
443 settings.
setValue( u
"UI/lastAuthImportBundleOpenFileDir"_s, QFileInfo( f ).absoluteDir().path() );
448QPushButton *QgsAuthImportIdentityDialog::okButton()
450 return buttonBox->button( QDialogButtonBox::Ok );
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static QString greenTextStyleSheet(const QString &selector="*")
Green text stylesheet representing valid, trusted, etc. certificate.
static QString redTextStyleSheet(const QString &selector="*")
Red text stylesheet representing invalid, untrusted, etc. certificate.
const QPair< QSslCertificate, QSslKey > certBundleToImport()
Gets certificate/key bundle to be imported.
Validity
Type of certificate/bundle validity output.
IdentityType
Type of identity being imported.
QgsAuthImportIdentityDialog::IdentityType identityType() const
Gets identity type.
QgsAuthImportIdentityDialog(QgsAuthImportIdentityDialog::IdentityType identitytype, QWidget *parent=nullptr)
Construct a dialog for importing identities.
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Storage set for PKI bundle: SSL certificate, key, optional CA cert chain.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.