18#include "ui_qgsauthimportidentitydialog.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() );
 
   86void 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 );
 
  113void QgsAuthImportIdentityDialog::validateIdentity()
 
  118    ok = validateBundle();
 
  120  okButton()->setEnabled( ok );
 
  123bool 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();
 
  145void QgsAuthImportIdentityDialog::clearValidation()
 
  147  teValidation->clear();
 
  148  teValidation->setStyleSheet( QString() );
 
  151void 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 );
 
  182void QgsAuthImportIdentityDialog::lePkiPathsKeyPass_textChanged( 
const QString &pass )
 
  188void QgsAuthImportIdentityDialog::chkPkiPathsPassShow_stateChanged( 
int state )
 
  190  lePkiPathsKeyPass->setEchoMode( ( state > 0 ) ? QLineEdit::Normal : QLineEdit::Password );
 
  193void QgsAuthImportIdentityDialog::btnPkiPathsCert_clicked()
 
  195  const QString &fn = getOpenFileName( tr( 
"Open Client Certificate File" ),  tr( 
"All files (*.*);;PEM (*.pem);;DER (*.der)" ) );
 
  198    lePkiPathsCert->setText( fn );
 
  203void QgsAuthImportIdentityDialog::btnPkiPathsKey_clicked()
 
  205  const QString &fn = getOpenFileName( tr( 
"Open Private Key File" ),  tr( 
"All files (*.*);;PEM (*.pem);;DER (*.der)" ) );
 
  208    lePkiPathsKey->setText( fn );
 
  213void QgsAuthImportIdentityDialog::lePkiPkcs12KeyPass_textChanged( 
const QString &pass )
 
  219void QgsAuthImportIdentityDialog::chkPkiPkcs12PassShow_stateChanged( 
int state )
 
  221  lePkiPkcs12KeyPass->setEchoMode( ( state > 0 ) ? QLineEdit::Normal : QLineEdit::Password );
 
  224void QgsAuthImportIdentityDialog::btnPkiPkcs12Bundle_clicked()
 
  226  const QString &fn = getOpenFileName( tr( 
"Open PKCS#12 Certificate Bundle" ),  tr( 
"PKCS#12 (*.p12 *.pfx)" ) );
 
  229    lePkiPkcs12Bundle->setText( fn );
 
  234bool 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 );
 
  313bool 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 );
 
  426void QgsAuthImportIdentityDialog::fileFound( 
bool found, QWidget *widget )
 
  431    widget->setToolTip( tr( 
"File not found" ) );
 
  435    widget->setStyleSheet( QString() );
 
  436    widget->setToolTip( QString() );
 
  440QString 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() );
 
  457QPushButton *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.