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   QSslCertificate emptycert;
   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   QString certpath( lePkiPathsCert->text() );
   240   QString keypath( lePkiPathsKey->text() );
   242   bool certfound = QFile::exists( certpath );
   243   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   QDateTime startdate( clientcert.effectiveDate() );
   283   QDateTime enddate( clientcert.expiryDate() );
   285   writeValidation( tr( 
"%1 thru %2" ).arg( startdate.toString(), enddate.toString() ),
   290   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   QString bundlepath( lePkiPkcs12Bundle->text() );
   317   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   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   QCA::Certificate cert( bundle.certificateChain().primary() );
   371     writeValidation( tr( 
"Bundle client cert can not be loaded" ), 
Invalid );
   376   QDateTime startdate( cert.notValidBefore() );
   377   QDateTime enddate( cert.notValidAfter() );
   378   QDateTime now( QDateTime::currentDateTime() );
   379   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     QCA::CertificateChain cert_chain( bundle.certificateChain() );
   406     QList<QSslCertificate> ca_certs;
   407     if ( cert_chain.size() > 1 )
   409       Q_FOREACH ( 
const QCA::Certificate &ca_cert, cert_chain )
   411         if ( ca_cert != cert_chain.primary() )
   413           ca_certs << QSslCertificate( ca_cert.toPEM().toLatin1() );
   418     mCertBundle = qMakePair( clientcert, clientkey );
   419     mPkiBundle = 
QgsPkiBundle( clientcert, clientkey, ca_certs );
   425 void QgsAuthImportIdentityDialog::fileFound( 
bool found, QWidget *widget )
   430     widget->setToolTip( tr( 
"File not found" ) );
   434     widget->setStyleSheet( QString() );
   435     widget->setToolTip( QString() );
   439 QString QgsAuthImportIdentityDialog::getOpenFileName( 
const QString &title, 
const QString &extfilter )
   442   QString recentdir = settings.
value( QStringLiteral( 
"UI/lastAuthImportBundleOpenFileDir" ), QDir::homePath() ).toString();
   443   QString f = QFileDialog::getOpenFileName( 
this, title, recentdir, extfilter );
   447   this->activateWindow();
   451     settings.
setValue( QStringLiteral( 
"UI/lastAuthImportBundleOpenFileDir" ), QFileInfo( f ).absoluteDir().path() );
   456 QPushButton *QgsAuthImportIdentityDialog::okButton()
   458   return buttonBox->button( QDialogButtonBox::Ok );
 
IdentityType
Type of identity being imported. 
 
This class is a composition of two QSettings instances: 
 
static QSslKey keyFromFile(const QString &keypath, const QString &keypass=QString(), QString *algtype=nullptr)
Returns non-encrypted key from a PEM or DER formatted file. 
 
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key. 
 
static QList< QSslCertificate > certsFromFile(const QString &certspath)
Returns a list of concatenated certs from a PEM or DER formatted file. 
 
QgsAuthImportIdentityDialog::IdentityType identityType()
Gets identity type. 
 
Storage set for PKI bundle: SSL certificate, key, optional CA cert chain. 
 
static bool certIsViable(const QSslCertificate &cert)
certIsViable checks for viability errors of cert and whether it is NULL 
 
static QString greenTextStyleSheet(const QString &selector="*")
Green text stylesheet representing valid, trusted, etc. certificate. 
 
QgsAuthImportIdentityDialog(QgsAuthImportIdentityDialog::IdentityType identitytype, QWidget *parent=nullptr)
Construct a dialog for importing identities. 
 
static QList< QSslCertificate > certsFromString(const QString &pemtext)
Returns a list of concatenated certs from a PEM Base64 text block. 
 
static QgsAuthManager * authManager()
Returns the application's authentication manager instance. 
 
static QString redTextStyleSheet(const QString &selector="*")
Red text stylesheet representing invalid, untrusted, etc. certificate. 
 
static bool certIsCurrent(const QSslCertificate &cert)
certIsCurrent checks if cert is viable for its not before and not after dates 
 
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value. 
 
const QPair< QSslCertificate, QSslKey > certBundleToImport()
Gets certificate/key bundle to be imported. 
 
Validity
Type of certificate/bundle validity output.