18 #include "ui_qgsauthimportidentitydialog.h"
21 #include <QFileDialog>
22 #include <QPushButton>
36 , mIdentityType( CertIdentity )
44 mAuthNotifyLayout =
new QVBoxLayout;
45 this->setLayout( mAuthNotifyLayout );
47 mAuthNotifyLayout->addWidget( mAuthNotify );
52 connect( lePkiPathsKeyPass, &QLineEdit::textChanged,
this, &QgsAuthImportIdentityDialog::lePkiPathsKeyPass_textChanged );
53 connect( chkPkiPathsPassShow, &QCheckBox::stateChanged,
this, &QgsAuthImportIdentityDialog::chkPkiPathsPassShow_stateChanged );
54 connect( btnPkiPathsCert, &QToolButton::clicked,
this, &QgsAuthImportIdentityDialog::btnPkiPathsCert_clicked );
55 connect( btnPkiPathsKey, &QToolButton::clicked,
this, &QgsAuthImportIdentityDialog::btnPkiPathsKey_clicked );
56 connect( lePkiPkcs12KeyPass, &QLineEdit::textChanged,
this, &QgsAuthImportIdentityDialog::lePkiPkcs12KeyPass_textChanged );
57 connect( chkPkiPkcs12PassShow, &QCheckBox::stateChanged,
this, &QgsAuthImportIdentityDialog::chkPkiPkcs12PassShow_stateChanged );
58 connect( btnPkiPkcs12Bundle, &QToolButton::clicked,
this, &QgsAuthImportIdentityDialog::btnPkiPkcs12Bundle_clicked );
59 connect( buttonBox, &QDialogButtonBox::rejected,
this, &QWidget::close );
60 connect( buttonBox, &QDialogButtonBox::accepted,
this, &QDialog::accept );
62 mIdentityType = identitytype;
64 populateIdentityType();
81 return qMakePair( QSslCertificate(), QSslKey() );
86 void QgsAuthImportIdentityDialog::populateIdentityType()
90 stkwBundleType->setVisible(
true );
92 cmbIdentityTypes->addItem( tr(
"PKI PEM/DER Certificate Paths" ),
94 cmbIdentityTypes->addItem( tr(
"PKI PKCS#12 Certificate Bundle" ),
97 connect( cmbIdentityTypes,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
98 stkwBundleType, &QStackedWidget::setCurrentIndex );
99 connect( stkwBundleType, &QStackedWidget::currentChanged,
100 cmbIdentityTypes, &QComboBox::setCurrentIndex );
102 connect( cmbIdentityTypes,
static_cast<void ( QComboBox::* )(
int )
>( &QComboBox::currentIndexChanged ),
103 this, [ = ] { validateIdentity(); } );
104 connect( stkwBundleType, &QStackedWidget::currentChanged,
105 this, &QgsAuthImportIdentityDialog::validateIdentity );
107 cmbIdentityTypes->setCurrentIndex( 0 );
108 stkwBundleType->setCurrentIndex( 0 );
113 void QgsAuthImportIdentityDialog::validateIdentity()
118 ok = validateBundle();
120 okButton()->setEnabled( ok );
123 bool QgsAuthImportIdentityDialog::validateBundle()
127 const QSslCertificate emptycert;
128 const QSslKey emptykey;
129 mCertBundle = qMakePair( emptycert, emptykey );
132 QWidget *curpage = stkwBundleType->currentWidget();
133 if ( curpage == pagePkiPaths )
135 return validatePkiPaths();
137 else if ( curpage == pagePkiPkcs12 )
139 return validatePkiPkcs12();
145 void QgsAuthImportIdentityDialog::clearValidation()
147 teValidation->clear();
148 teValidation->setStyleSheet( QString() );
151 void QgsAuthImportIdentityDialog::writeValidation(
const QString &msg,
161 txt = tr(
"Valid: %1" ).arg( msg );
165 txt = tr(
"Invalid: %1" ).arg( msg );
170 teValidation->setStyleSheet( ss );
173 teValidation->append( txt );
177 teValidation->setText( txt );
179 teValidation->moveCursor( QTextCursor::Start );
182 void QgsAuthImportIdentityDialog::lePkiPathsKeyPass_textChanged(
const QString &pass )
188 void QgsAuthImportIdentityDialog::chkPkiPathsPassShow_stateChanged(
int state )
190 lePkiPathsKeyPass->setEchoMode( ( state > 0 ) ? QLineEdit::Normal : QLineEdit::Password );
193 void QgsAuthImportIdentityDialog::btnPkiPathsCert_clicked()
195 const QString &fn = getOpenFileName( tr(
"Open Client Certificate File" ), tr(
"All files (*.*);;PEM (*.pem);;DER (*.der)" ) );
198 lePkiPathsCert->setText( fn );
203 void QgsAuthImportIdentityDialog::btnPkiPathsKey_clicked()
205 const QString &fn = getOpenFileName( tr(
"Open Private Key File" ), tr(
"All files (*.*);;PEM (*.pem);;DER (*.der)" ) );
208 lePkiPathsKey->setText( fn );
213 void QgsAuthImportIdentityDialog::lePkiPkcs12KeyPass_textChanged(
const QString &pass )
219 void QgsAuthImportIdentityDialog::chkPkiPkcs12PassShow_stateChanged(
int state )
221 lePkiPkcs12KeyPass->setEchoMode( ( state > 0 ) ? QLineEdit::Normal : QLineEdit::Password );
224 void QgsAuthImportIdentityDialog::btnPkiPkcs12Bundle_clicked()
226 const QString &fn = getOpenFileName( tr(
"Open PKCS#12 Certificate Bundle" ), tr(
"PKCS#12 (*.p12 *.pfx)" ) );
229 lePkiPkcs12Bundle->setText( fn );
234 bool QgsAuthImportIdentityDialog::validatePkiPaths()
236 bool isvalid =
false;
239 const QString certpath( lePkiPathsCert->text() );
240 const QString keypath( lePkiPathsKey->text() );
242 const bool certfound = QFile::exists( certpath );
243 const bool keyfound = QFile::exists( keypath );
245 fileFound( certpath.isEmpty() || certfound, lePkiPathsCert );
246 fileFound( keypath.isEmpty() || keyfound, lePkiPathsKey );
248 if ( !certfound || !keyfound )
250 writeValidation( tr(
"Missing components" ),
Invalid );
255 QSslCertificate clientcert;
257 QList<QSslCertificate> ca_certs;
258 if ( !certs.isEmpty() )
260 clientcert = certs.takeFirst();
264 writeValidation( tr(
"Failed to read client certificate from file" ),
Invalid );
268 if ( clientcert.isNull() )
270 writeValidation( tr(
"Failed to load client certificate from file" ),
Invalid );
274 if ( !certs.isEmpty() )
276 teValidation->append( tr(
"Extra certificates found with identity" ) );
282 const QDateTime startdate( clientcert.effectiveDate() );
283 const QDateTime enddate( clientcert.expiryDate() );
285 writeValidation( tr(
"%1 thru %2" ).arg( startdate.toString(), enddate.toString() ),
290 const QString keypass( lePkiPathsKeyPass->text() );
292 if ( clientkey.isNull() )
294 writeValidation( tr(
"Failed to load client private key from file" ),
Invalid,
true );
295 if ( !keypass.isEmpty() )
297 writeValidation( tr(
"Private key password may not match" ),
Invalid,
true );
304 mCertBundle = qMakePair( clientcert, clientkey );
313 bool QgsAuthImportIdentityDialog::validatePkiPkcs12()
316 const QString bundlepath( lePkiPkcs12Bundle->text() );
317 const bool bundlefound = QFile::exists( bundlepath );
318 fileFound( bundlepath.isEmpty() || bundlefound, lePkiPkcs12Bundle );
322 writeValidation( tr(
"Missing components" ),
Invalid );
326 if ( !QCA::isSupported(
"pkcs12" ) )
328 writeValidation( tr(
"QCA library has no PKCS#12 support" ),
Invalid );
333 QCA::SecureArray passarray;
334 QString keypass = QString();
335 if ( !lePkiPkcs12KeyPass->text().isEmpty() )
337 passarray = QCA::SecureArray( lePkiPkcs12KeyPass->text().toUtf8() );
338 keypass = lePkiPkcs12KeyPass->text();
341 QCA::ConvertResult res;
342 const QCA::KeyBundle bundle( QCA::KeyBundle::fromFile( bundlepath, passarray, &res, QStringLiteral(
"qca-ossl" ) ) );
344 if ( res == QCA::ErrorFile )
346 writeValidation( tr(
"Failed to read bundle file" ),
Invalid );
349 else if ( res == QCA::ErrorPassphrase )
351 writeValidation( tr(
"Incorrect bundle password" ),
Invalid );
352 lePkiPkcs12KeyPass->setPlaceholderText( QStringLiteral(
"Required passphrase" ) );
355 else if ( res == QCA::ErrorDecode )
357 writeValidation( tr(
"Failed to decode (try entering password)" ),
Invalid );
361 if ( bundle.isNull() )
363 writeValidation( tr(
"Bundle empty or can not be loaded" ),
Invalid );
368 const QCA::Certificate cert( bundle.certificateChain().primary() );
371 writeValidation( tr(
"Bundle client cert can not be loaded" ),
Invalid );
376 const QDateTime startdate( cert.notValidBefore() );
377 const QDateTime enddate( cert.notValidAfter() );
378 const QDateTime now( QDateTime::currentDateTime() );
379 const bool bundlevalid = ( now >= startdate && now <= enddate );
381 writeValidation( tr(
"%1 thru %2" ).arg( startdate.toString(), enddate.toString() ),
386 QSslCertificate clientcert;
388 if ( !certs.isEmpty() )
390 clientcert = certs.first();
392 if ( clientcert.isNull() )
394 writeValidation( tr(
"Qt cert could not be created from QCA cert" ),
Invalid,
true );
398 clientkey = QSslKey( bundle.privateKey().toRSA().toPEM().toLatin1(), QSsl::Rsa );
399 if ( clientkey.isNull() )
401 writeValidation( tr(
"Qt private key could not be created from QCA key" ),
Invalid,
true );
405 const QCA::CertificateChain cert_chain( bundle.certificateChain() );
406 QList<QSslCertificate> ca_certs;
407 if ( cert_chain.size() > 1 )
409 const auto constCert_chain = cert_chain;
410 for (
const QCA::Certificate &ca_cert : constCert_chain )
412 if ( ca_cert != cert_chain.primary() )
414 ca_certs << QSslCertificate( ca_cert.toPEM().toLatin1() );
419 mCertBundle = qMakePair( clientcert, clientkey );
420 mPkiBundle =
QgsPkiBundle( clientcert, clientkey, ca_certs );
426 void QgsAuthImportIdentityDialog::fileFound(
bool found, QWidget *widget )
431 widget->setToolTip( tr(
"File not found" ) );
435 widget->setStyleSheet( QString() );
436 widget->setToolTip( QString() );
440 QString QgsAuthImportIdentityDialog::getOpenFileName(
const QString &title,
const QString &extfilter )
443 const QString recentdir = settings.
value( QStringLiteral(
"UI/lastAuthImportBundleOpenFileDir" ), QDir::homePath() ).toString();
444 QString f = QFileDialog::getOpenFileName(
this, title, recentdir, extfilter );
448 this->activateWindow();
452 settings.
setValue( QStringLiteral(
"UI/lastAuthImportBundleOpenFileDir" ), QFileInfo( f ).absoluteDir().path() );
457 QPushButton *QgsAuthImportIdentityDialog::okButton()
459 return buttonBox->button( QDialogButtonBox::Ok );
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
static bool certIsViable(const QSslCertificate &cert)
certIsViable checks for viability errors of cert and whether it is NULL
static QList< QSslCertificate > certsFromFile(const QString &certspath)
Returns a list of concatenated certs from a PEM or DER formatted file.
static QSslKey keyFromFile(const QString &keypath, const QString &keypass=QString(), QString *algtype=nullptr)
Returns non-encrypted key from a PEM or DER formatted file.
static QList< QSslCertificate > certsFromString(const QString &pemtext)
Returns a list of concatenated certs from a PEM Base64 text block.
static bool certIsCurrent(const QSslCertificate &cert)
certIsCurrent checks if cert is viable for its not before and not after dates
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.
QgsAuthImportIdentityDialog::IdentityType identityType()
Gets identity type.
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(QgsAuthImportIdentityDialog::IdentityType identitytype, QWidget *parent=nullptr)
Construct a dialog for importing identities.
Storage set for PKI bundle: SSL certificate, key, optional CA cert chain.
This class is a composition of two QSettings instances:
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.