18 #include "ui_qgsauthimportidentitydialog.h" 
   21 #include <QFileDialog> 
   22 #include <QPushButton> 
   24 #include "qgssettings.h" 
   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       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 )
 
  442   QgsSettings settings;
 
  443   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.