23#include <QCryptographicHash>
30using namespace Qt::StringLiterals;
36const QString QgsAuthMethodConfig::CONFIG_SEP = u
"|||"_s;
37const QString QgsAuthMethodConfig::CONFIG_KEY_SEP = u
":::"_s;
38const QString QgsAuthMethodConfig::CONFIG_LIST_SEP = u
"```"_s;
40const int QgsAuthMethodConfig::CONFIG_VERSION = 1;
55 return ( other.
id() ==
id()
65 return !( *
this == other );
70 const bool idvalid = validateid ? !mId.isEmpty() :
true;
82 QgsStringMap::const_iterator i = mConfigMap.constBegin();
83 while ( i != mConfigMap.constEnd() )
85 confstrs << i.key() + CONFIG_KEY_SEP + i.value();
88 return confstrs.join( CONFIG_SEP );
94 if ( configstr.isEmpty() )
99 const QStringList confs( configstr.split( CONFIG_SEP ) );
101 for (
const auto &conf : confs )
103 if ( conf.contains( CONFIG_KEY_SEP ) )
105 const QStringList keyval( conf.split( CONFIG_KEY_SEP ) );
106 setConfig( keyval.at( 0 ), keyval.at( 1 ) );
112 setConfig( u
"oldconfigstyle"_s, configstr );
118 mConfigMap.insert( key, value );
123 setConfig( key, value.join( CONFIG_LIST_SEP ) );
128 return mConfigMap.remove( key );
133 return mConfigMap.value( key, defaultvalue );
138 return config( key ).split( CONFIG_LIST_SEP );
143 return mConfigMap.contains( key );
148 QString res = QString();
149 if ( !accessurl.isEmpty() )
151 const QUrl url( accessurl );
154 res = u
"%1://%2:%3%4"_s.arg( url.scheme(), url.host() )
155 .arg( url.port() ).arg( withpath ? url.path() : QString() );
159 return ( !res.isEmpty() );
165 QDomElement element = document.createElement( u
"AuthMethodConfig"_s );
166 element.setAttribute( u
"method"_s, mMethod );
167 element.setAttribute( u
"id"_s, mId );
168 element.setAttribute( u
"name"_s, mName );
169 element.setAttribute( u
"version"_s, QString::number( mVersion ) );
170 element.setAttribute( u
"uri"_s, mUri );
172 QDomElement configElements = document.createElement( u
"Config"_s );
173 QgsStringMap::const_iterator i = mConfigMap.constBegin();
174 while ( i != mConfigMap.constEnd() )
176 configElements.setAttribute( i.key(), i.value() );
179 element.appendChild( configElements );
181 parentElement.appendChild( element );
187 if ( element.nodeName() !=
"AuthMethodConfig"_L1 )
190 mMethod = element.attribute( u
"method"_s );
191 mId = element.attribute( u
"id"_s );
192 mName = element.attribute( u
"name"_s );
193 mVersion = element.attribute( u
"version"_s ).toInt();
194 mUri = element.attribute( u
"uri"_s );
197 const QDomNamedNodeMap configAttributes = element.firstChildElement().attributes();
198 for (
int i = 0; i < configAttributes.length(); i++ )
200 const QDomAttr configAttribute = configAttributes.item( i ).toAttr();
201 setConfig( configAttribute.name(), configAttribute.value() );
215 const QList<QSslCertificate> &
caChain )
216 : mCert( QSslCertificate() )
217 , mCertKey( QSslKey() )
225 const QString &keyPath,
226 const QString &keyPass,
227 const QList<QSslCertificate> &
caChain )
230 if ( !certPath.isEmpty() && !keyPath.isEmpty()
231 && ( certPath.endsWith(
".pem"_L1, Qt::CaseInsensitive )
232 || certPath.endsWith(
".der"_L1, Qt::CaseInsensitive ) )
233 && QFile::exists( certPath ) && QFile::exists( keyPath )
237 const bool pem = certPath.endsWith(
".pem"_L1, Qt::CaseInsensitive );
238 const QSslCertificate clientcert( QgsAuthCertUtils::fileData( certPath ), pem ? QSsl::Pem : QSsl::Der );
242 clientkey = QgsAuthCertUtils::keyFromFile( keyPath, keyPass );
253 const QString &bundlepass )
256 if ( QCA::isSupported(
"pkcs12" )
257 && !bundlepath.isEmpty()
258 && ( bundlepath.endsWith(
".p12"_L1, Qt::CaseInsensitive )
259 || bundlepath.endsWith(
".pfx"_L1, Qt::CaseInsensitive ) )
260 && QFile::exists( bundlepath ) )
262 QCA::SecureArray passarray;
263 if ( !bundlepass.isNull() )
264 passarray = QCA::SecureArray( bundlepass.toUtf8() );
265 QCA::ConvertResult res;
266 const QCA::KeyBundle bundle( QCA::KeyBundle::fromFile( bundlepath, passarray, &res, u
"qca-ossl"_s ) );
267 if ( res == QCA::ConvertGood && !bundle.isNull() )
269 const QCA::CertificateChain cert_chain( bundle.certificateChain() );
270 const QSslCertificate cert( cert_chain.primary().toPEM().toLatin1() );
271 if ( !cert.isNull() )
275 const QSslKey cert_key( bundle.privateKey().toPEM().toLatin1(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, QByteArray() );
276 if ( !cert_key.isNull() )
281 if ( cert_chain.size() > 1 )
283 QList<QSslCertificate> ca_chain;
284 for (
const auto &ca_cert : cert_chain )
286 if ( ca_cert != cert_chain.primary() )
288 ca_chain << QSslCertificate( ca_cert.toPEM().toLatin1() );
301 return ( mCert.isNull() || mCertKey.isNull() );
306 return ( !
isNull() && QgsAuthCertUtils::certIsViable( mCert ) );
311 if ( mCert.isNull() )
315 return QString( mCert.digest( QCryptographicHash::Sha1 ).toHex() );
321 if ( !cert.isNull() )
330 if ( !certkey.isNull() && certkey.type() == QSsl::PrivateKey )
342 const QSslCertificate &cert,
343 const QSslKey &certkey,
344 const QList<QSslCertificate> &cachain )
347 , mCertKey( certkey )
348 , mCaChain( cachain )
354 return ( !mCert.isNull() && !mCertKey.isNull() );
362const QString QgsAuthConfigSslServer::CONF_SEP = u
"|||"_s;
365 : mSslHostPort( QString() )
366 , mSslCert( QSslCertificate() )
367 , mSslIgnoredErrors( QList<QSslError::SslError>() )
373 mSslProtocol = QSsl::SecureProtocols;
378 QList<QSslError> errors;
380 for (
const QSslError::SslError errenum : ignoredErrors )
382 errors << QSslError( errenum );
389 QStringList configlist
391 QString::number( mVersion ),
392 QString::number( mQtVersion ),
393 encodeSslProtocol( mSslProtocol )
397 for (
const auto err : mSslIgnoredErrors )
399 errs << QString::number( static_cast< int >( err ) );
401 configlist << errs.join(
"~~"_L1 );
403 configlist << u
"%1~~%2"_s.arg(
static_cast< int >( mSslPeerVerifyMode ) ).arg( mSslPeerVerifyDepth );
405 return configlist.join( CONF_SEP );
410 if ( config.isEmpty() )
414 const QStringList configlist( config.split( CONF_SEP ) );
416 mVersion = configlist.at( 0 ).toInt();
417 mQtVersion = configlist.at( 1 ).toInt();
418 mSslProtocol = decodeSslProtocol( configlist.at( 2 ) );
420 mSslIgnoredErrors.clear();
421 const QStringList errs( configlist.at( 3 ).split( u
"~~"_s ) );
422 for (
const auto &err : errs )
424 mSslIgnoredErrors.append(
static_cast< QSslError::SslError
>( err.toInt() ) );
427 const QStringList peerverify( configlist.at( 4 ).split( u
"~~"_s ) );
428 mSslPeerVerifyMode =
static_cast< QSslSocket::PeerVerifyMode
>( peerverify.at( 0 ).toInt() );
429 mSslPeerVerifyDepth = peerverify.at( 1 ).toInt();
434 return mSslCert.isNull() && mSslHostPort.isEmpty();
437QSsl::SslProtocol QgsAuthConfigSslServer::decodeSslProtocol(
const QString &protocol )
440 const int qt5EnumInt = protocol.toInt( &ok );
445 switch ( qt5EnumInt )
448 return QSsl::SslProtocol::UnknownProtocol;
452 return QSsl::SslProtocol::TlsV1_0;
454 return QSsl::SslProtocol::TlsV1_1;
456 return QSsl::SslProtocol::TlsV1_2;
458 return QSsl::SslProtocol::AnyProtocol;
460 return QSsl::SslProtocol::TlsV1_3;
462 return QSsl::SslProtocol::SecureProtocols;
464 return QSsl::SslProtocol::TlsV1_0OrLater;
466 return QSsl::SslProtocol::TlsV1_1OrLater;
468 return QSsl::SslProtocol::TlsV1_2OrLater;
470 return QSsl::SslProtocol::DtlsV1_0;
472 return QSsl::SslProtocol::DtlsV1_0OrLater;
474 return QSsl::SslProtocol::DtlsV1_2;
476 return QSsl::SslProtocol::DtlsV1_2OrLater;
478 return QSsl::SslProtocol::TlsV1_3;
480 return QSsl::SslProtocol::TlsV1_3OrLater;
482 return QSsl::SslProtocol::UnknownProtocol;
486 if ( protocol ==
"TlsV1_0"_L1 )
487 return QSsl::SslProtocol::TlsV1_0;
488 else if ( protocol ==
"TlsV1_1"_L1 )
489 return QSsl::SslProtocol::TlsV1_1;
490 else if ( protocol ==
"TlsV1_2"_L1 )
491 return QSsl::SslProtocol::TlsV1_2;
492 else if ( protocol ==
"AnyProtocol"_L1 )
493 return QSsl::SslProtocol::AnyProtocol;
494 else if ( protocol ==
"SecureProtocols"_L1 )
495 return QSsl::SslProtocol::SecureProtocols;
496 else if ( protocol ==
"TlsV1_0OrLater"_L1 )
497 return QSsl::SslProtocol::TlsV1_0OrLater;
498 else if ( protocol ==
"TlsV1_1OrLater"_L1 )
499 return QSsl::SslProtocol::TlsV1_1OrLater;
500 else if ( protocol ==
"TlsV1_2OrLater"_L1 )
501 return QSsl::SslProtocol::TlsV1_2OrLater;
502 else if ( protocol ==
"DtlsV1_0"_L1 )
503 return QSsl::SslProtocol::DtlsV1_0;
504 else if ( protocol ==
"DtlsV1_0OrLater"_L1 )
505 return QSsl::SslProtocol::DtlsV1_0OrLater;
506 else if ( protocol ==
"DtlsV1_2"_L1 )
507 return QSsl::SslProtocol::DtlsV1_2;
508 else if ( protocol ==
"DtlsV1_2OrLater"_L1 )
509 return QSsl::SslProtocol::DtlsV1_2OrLater;
510 else if ( protocol ==
"TlsV1_3"_L1 )
511 return QSsl::SslProtocol::TlsV1_3;
512 else if ( protocol ==
"TlsV1_3OrLater"_L1 )
513 return QSsl::SslProtocol::TlsV1_3OrLater;
515 QgsDebugError( u
"Can't decode protocol \"%1\""_s.arg( protocol ) );
517 return QSsl::SslProtocol::UnknownProtocol;
520QString QgsAuthConfigSslServer::encodeSslProtocol( QSsl::SslProtocol protocol )
530 case QSsl::AnyProtocol:
531 return u
"AnyProtocol"_s;
532 case QSsl::SecureProtocols:
533 return u
"SecureProtocols"_s;
534 case QSsl::TlsV1_0OrLater:
535 return u
"TlsV1_0OrLater"_s;
536 case QSsl::TlsV1_1OrLater:
537 return u
"TlsV1_1OrLater"_s;
538 case QSsl::TlsV1_2OrLater:
539 return u
"TlsV1_2OrLater"_s;
541 return u
"DtlsV1_0"_s;
542 case QSsl::DtlsV1_0OrLater:
543 return u
"DtlsV1_0OrLater"_s;
545 return u
"DtlsV1_2"_s;
546 case QSsl::DtlsV1_2OrLater:
547 return u
"DtlsV1_2OrLater"_s;
550 case QSsl::TlsV1_3OrLater:
551 return u
"TlsV1_3OrLater"_s;
552 case QSsl::UnknownProtocol:
553 return u
"UnknownProtocol"_s;
556 QgsDebugError( u
"Can't encode protocol: %1"_s.arg( protocol ) );
558 return u
"UnknownProtocol"_s;
const QList< QSslError > sslIgnoredErrors() const
SSL server errors to ignore in connections.
bool isNull() const
Whether configuration is null (missing components).
const QList< QSslError::SslError > sslIgnoredErrorEnums() const
SSL server errors (as enum list) to ignore in connections.
const QString configString() const
Configuration as a concatenated string.
QgsAuthConfigSslServer()
Construct a default SSL server configuration.
void loadConfigString(const QString &config=QString())
Load concatenated string into configuration, e.g. from auth database.
Configuration storage class for authentication method configurations.
QString config(const QString &key, const QString &defaultvalue=QString()) const
Returns a config's value.
bool isValid(bool validateid=false) const
Whether the configuration is valid.
QString method() const
Textual key of the associated authentication method.
const QString uri() const
A URI to auto-select a config when connecting to a resource.
int removeConfig(const QString &key)
Remove a config from map.
bool readXml(const QDomElement &element)
from a DOM element.
const QString configString() const
The extended configuration, as stored and retrieved from the authentication database.
const QString name() const
Gets name of configuration.
bool operator==(const QgsAuthMethodConfig &other) const
const QString id() const
Gets 'authcfg' 7-character alphanumeric ID of the config.
void loadConfigString(const QString &configstr)
Load existing extended configuration.
void clearConfigMap()
Clear all configs.
bool writeXml(QDomElement &parentElement, QDomDocument &document)
Stores the configuration in a DOM.
void setConfig(const QString &key, const QString &value)
Set a single config value per key in the map.
QStringList configList(const QString &key) const
Returns a config's list of values.
int version() const
Gets version of the configuration.
QgsStringMap configMap() const
Gets extended configuration, mapped to key/value pairs of QStrings.
bool operator!=(const QgsAuthMethodConfig &other) const
bool hasConfig(const QString &key) const
Whether a config key exists in config map.
QgsAuthMethodConfig(const QString &method=QString(), int version=0)
Construct a configuration for an authentication method.
void setConfigList(const QString &key, const QStringList &value)
Set a multiple config values per key in the map.
static bool uriToResource(const QString &accessurl, QString *resource, bool withpath=false)
A utility function for generating a resource from a URL to be compared against the config's uri() for...
const QString certId() const
The sha hash of the client certificate.
bool isNull() const
Whether the bundle, either its certificate or private key, is null.
QgsPkiBundle(const QSslCertificate &clientCert=QSslCertificate(), const QSslKey &clientKey=QSslKey(), const QList< QSslCertificate > &caChain=QList< QSslCertificate >())
Construct a bundle from existing PKI components.
void setClientKey(const QSslKey &certkey)
Sets private key object.
void setClientCert(const QSslCertificate &cert)
Sets client certificate object.
static const QgsPkiBundle fromPkcs12Paths(const QString &bundlepath, const QString &bundlepass=QString())
Construct a bundle of PKI components from a PKCS#12 file path.
const QSslKey clientKey() const
Private key object.
void setCaChain(const QList< QSslCertificate > &cachain)
Sets chain of Certificate Authorities for client certificate.
const QList< QSslCertificate > caChain() const
Chain of Certificate Authorities for client certificate.
static const QgsPkiBundle fromPemPaths(const QString &certPath, const QString &keyPath, const QString &keyPass=QString(), const QList< QSslCertificate > &caChain=QList< QSslCertificate >())
Construct a bundle of PKI components from PEM-formatted file paths.
const QSslCertificate clientCert() const
Client certificate object.
bool isValid() const
Whether the bundle is valid.
const QgsAuthMethodConfig config() const
Authentication method configuration.
QgsPkiConfigBundle(const QgsAuthMethodConfig &config, const QSslCertificate &cert, const QSslKey &certkey, const QList< QSslCertificate > &cachain=QList< QSslCertificate >())
Construct a bundle from existing PKI components and authentication method configuration.
bool isValid()
Whether the bundle is valid.
QMap< QString, QString > QgsStringMap
#define QgsDebugError(str)