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;
59 return !( *
this == other );
64 const bool idvalid = validateid ? !mId.isEmpty() :
true;
66 return ( idvalid && !mName.isEmpty() && !mMethod.isEmpty() );
72 QgsStringMap::const_iterator i = mConfigMap.constBegin();
73 while ( i != mConfigMap.constEnd() )
75 confstrs << i.key() + CONFIG_KEY_SEP + i.value();
78 return confstrs.join( CONFIG_SEP );
84 if ( configstr.isEmpty() )
89 const QStringList confs( configstr.split( CONFIG_SEP ) );
91 for (
const auto &conf : confs )
93 if ( conf.contains( CONFIG_KEY_SEP ) )
95 const QStringList keyval( conf.split( CONFIG_KEY_SEP ) );
96 setConfig( keyval.at( 0 ), keyval.at( 1 ) );
102 setConfig( u
"oldconfigstyle"_s, configstr );
108 mConfigMap.insert( key, value );
113 setConfig( key, value.join( CONFIG_LIST_SEP ) );
118 return mConfigMap.remove( key );
123 return mConfigMap.value( key, defaultvalue );
128 return config( key ).split( CONFIG_LIST_SEP );
133 return mConfigMap.contains( key );
138 QString res = QString();
139 if ( !accessurl.isEmpty() )
141 const QUrl url( accessurl );
144 res = u
"%1://%2:%3%4"_s.arg( url.scheme(), url.host() ).arg( url.port() ).arg( withpath ? url.path() : QString() );
148 return ( !res.isEmpty() );
154 QDomElement element = document.createElement( u
"AuthMethodConfig"_s );
155 element.setAttribute( u
"method"_s, mMethod );
156 element.setAttribute( u
"id"_s, mId );
157 element.setAttribute( u
"name"_s, mName );
158 element.setAttribute( u
"version"_s, QString::number( mVersion ) );
159 element.setAttribute( u
"uri"_s, mUri );
161 QDomElement configElements = document.createElement( u
"Config"_s );
162 QgsStringMap::const_iterator i = mConfigMap.constBegin();
163 while ( i != mConfigMap.constEnd() )
165 configElements.setAttribute( i.key(), i.value() );
168 element.appendChild( configElements );
170 parentElement.appendChild( element );
176 if ( element.nodeName() !=
"AuthMethodConfig"_L1 )
179 mMethod = element.attribute( u
"method"_s );
180 mId = element.attribute( u
"id"_s );
181 mName = element.attribute( u
"name"_s );
182 mVersion = element.attribute( u
"version"_s ).toInt();
183 mUri = element.attribute( u
"uri"_s );
186 const QDomNamedNodeMap configAttributes = element.firstChildElement().attributes();
187 for (
int i = 0; i < configAttributes.length(); i++ )
189 const QDomAttr configAttribute = configAttributes.item( i ).toAttr();
190 setConfig( configAttribute.name(), configAttribute.value() );
203 : mCert( QSslCertificate() )
204 , mCertKey( QSslKey() )
214 if ( !certPath.isEmpty()
215 && !keyPath.isEmpty()
216 && ( certPath.endsWith(
".pem"_L1, Qt::CaseInsensitive ) || certPath.endsWith(
".der"_L1, Qt::CaseInsensitive ) )
217 && QFile::exists( certPath )
218 && QFile::exists( keyPath ) )
221 const bool pem = certPath.endsWith(
".pem"_L1, Qt::CaseInsensitive );
222 const QSslCertificate clientcert( QgsAuthCertUtils::fileData( certPath ), pem ? QSsl::Pem : QSsl::Der );
226 clientkey = QgsAuthCertUtils::keyFromFile( keyPath, keyPass );
239 if ( QCA::isSupported(
"pkcs12" )
240 && !bundlepath.isEmpty()
241 && ( bundlepath.endsWith(
".p12"_L1, Qt::CaseInsensitive ) || bundlepath.endsWith(
".pfx"_L1, Qt::CaseInsensitive ) )
242 && QFile::exists( bundlepath ) )
244 QCA::SecureArray passarray;
245 if ( !bundlepass.isNull() )
246 passarray = QCA::SecureArray( bundlepass.toUtf8() );
247 QCA::ConvertResult res;
248 const QCA::KeyBundle bundle( QCA::KeyBundle::fromFile( bundlepath, passarray, &res, u
"qca-ossl"_s ) );
249 if ( res == QCA::ConvertGood && !bundle.isNull() )
251 const QCA::CertificateChain cert_chain( bundle.certificateChain() );
252 const QSslCertificate cert( cert_chain.primary().toPEM().toLatin1() );
253 if ( !cert.isNull() )
257 const QSslKey cert_key( bundle.privateKey().toPEM().toLatin1(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, QByteArray() );
258 if ( !cert_key.isNull() )
263 if ( cert_chain.size() > 1 )
265 QList<QSslCertificate> ca_chain;
266 for (
const auto &ca_cert : cert_chain )
268 if ( ca_cert != cert_chain.primary() )
270 ca_chain << QSslCertificate( ca_cert.toPEM().toLatin1() );
282 return ( mCert.isNull() || mCertKey.isNull() );
287 return ( !
isNull() && QgsAuthCertUtils::certIsViable( mCert ) );
292 if ( mCert.isNull() )
296 return QString( mCert.digest( QCryptographicHash::Sha1 ).toHex() );
302 if ( !cert.isNull() )
311 if ( !certkey.isNull() && certkey.type() == QSsl::PrivateKey )
325 , mCertKey( certkey )
326 , mCaChain( cachain )
331 return ( !mCert.isNull() && !mCertKey.isNull() );
339const QString QgsAuthConfigSslServer::CONF_SEP = u
"|||"_s;
342 : mSslHostPort( QString() )
343 , mSslCert( QSslCertificate() )
344 , mSslIgnoredErrors( QList<QSslError::SslError>() )
350 mSslProtocol = QSsl::SecureProtocols;
355 QList<QSslError> errors;
357 for (
const QSslError::SslError errenum : ignoredErrors )
359 errors << QSslError( errenum );
366 QStringList configlist { QString::number( mVersion ), QString::number( mQtVersion ), encodeSslProtocol( mSslProtocol ) };
369 for (
const auto err : mSslIgnoredErrors )
371 errs << QString::number( static_cast< int >( err ) );
373 configlist << errs.join(
"~~"_L1 );
375 configlist << u
"%1~~%2"_s.arg(
static_cast< int >( mSslPeerVerifyMode ) ).arg( mSslPeerVerifyDepth );
377 return configlist.join( CONF_SEP );
382 if ( config.isEmpty() )
386 const QStringList configlist( config.split( CONF_SEP ) );
388 mVersion = configlist.at( 0 ).toInt();
389 mQtVersion = configlist.at( 1 ).toInt();
390 mSslProtocol = decodeSslProtocol( configlist.at( 2 ) );
392 mSslIgnoredErrors.clear();
393 const QStringList errs( configlist.at( 3 ).split( u
"~~"_s ) );
394 for (
const auto &err : errs )
396 mSslIgnoredErrors.append(
static_cast< QSslError::SslError
>( err.toInt() ) );
399 const QStringList peerverify( configlist.at( 4 ).split( u
"~~"_s ) );
400 mSslPeerVerifyMode =
static_cast< QSslSocket::PeerVerifyMode
>( peerverify.at( 0 ).toInt() );
401 mSslPeerVerifyDepth = peerverify.at( 1 ).toInt();
406 return mSslCert.isNull() && mSslHostPort.isEmpty();
409QSsl::SslProtocol QgsAuthConfigSslServer::decodeSslProtocol(
const QString &protocol )
412 const int qt5EnumInt = protocol.toInt( &ok );
417 switch ( qt5EnumInt )
420 return QSsl::SslProtocol::UnknownProtocol;
424 return QSsl::SslProtocol::TlsV1_0;
426 return QSsl::SslProtocol::TlsV1_1;
428 return QSsl::SslProtocol::TlsV1_2;
430 return QSsl::SslProtocol::AnyProtocol;
432 return QSsl::SslProtocol::TlsV1_3;
434 return QSsl::SslProtocol::SecureProtocols;
436 return QSsl::SslProtocol::TlsV1_0OrLater;
438 return QSsl::SslProtocol::TlsV1_1OrLater;
440 return QSsl::SslProtocol::TlsV1_2OrLater;
442 return QSsl::SslProtocol::DtlsV1_0;
444 return QSsl::SslProtocol::DtlsV1_0OrLater;
446 return QSsl::SslProtocol::DtlsV1_2;
448 return QSsl::SslProtocol::DtlsV1_2OrLater;
450 return QSsl::SslProtocol::TlsV1_3;
452 return QSsl::SslProtocol::TlsV1_3OrLater;
454 return QSsl::SslProtocol::UnknownProtocol;
458 if ( protocol ==
"TlsV1_0"_L1 )
459 return QSsl::SslProtocol::TlsV1_0;
460 else if ( protocol ==
"TlsV1_1"_L1 )
461 return QSsl::SslProtocol::TlsV1_1;
462 else if ( protocol ==
"TlsV1_2"_L1 )
463 return QSsl::SslProtocol::TlsV1_2;
464 else if ( protocol ==
"AnyProtocol"_L1 )
465 return QSsl::SslProtocol::AnyProtocol;
466 else if ( protocol ==
"SecureProtocols"_L1 )
467 return QSsl::SslProtocol::SecureProtocols;
468 else if ( protocol ==
"TlsV1_0OrLater"_L1 )
469 return QSsl::SslProtocol::TlsV1_0OrLater;
470 else if ( protocol ==
"TlsV1_1OrLater"_L1 )
471 return QSsl::SslProtocol::TlsV1_1OrLater;
472 else if ( protocol ==
"TlsV1_2OrLater"_L1 )
473 return QSsl::SslProtocol::TlsV1_2OrLater;
474 else if ( protocol ==
"DtlsV1_0"_L1 )
475 return QSsl::SslProtocol::DtlsV1_0;
476 else if ( protocol ==
"DtlsV1_0OrLater"_L1 )
477 return QSsl::SslProtocol::DtlsV1_0OrLater;
478 else if ( protocol ==
"DtlsV1_2"_L1 )
479 return QSsl::SslProtocol::DtlsV1_2;
480 else if ( protocol ==
"DtlsV1_2OrLater"_L1 )
481 return QSsl::SslProtocol::DtlsV1_2OrLater;
482 else if ( protocol ==
"TlsV1_3"_L1 )
483 return QSsl::SslProtocol::TlsV1_3;
484 else if ( protocol ==
"TlsV1_3OrLater"_L1 )
485 return QSsl::SslProtocol::TlsV1_3OrLater;
487 QgsDebugError( u
"Can't decode protocol \"%1\""_s.arg( protocol ) );
489 return QSsl::SslProtocol::UnknownProtocol;
492QString QgsAuthConfigSslServer::encodeSslProtocol( QSsl::SslProtocol protocol )
502 case QSsl::AnyProtocol:
503 return u
"AnyProtocol"_s;
504 case QSsl::SecureProtocols:
505 return u
"SecureProtocols"_s;
506 case QSsl::TlsV1_0OrLater:
507 return u
"TlsV1_0OrLater"_s;
508 case QSsl::TlsV1_1OrLater:
509 return u
"TlsV1_1OrLater"_s;
510 case QSsl::TlsV1_2OrLater:
511 return u
"TlsV1_2OrLater"_s;
513 return u
"DtlsV1_0"_s;
514 case QSsl::DtlsV1_0OrLater:
515 return u
"DtlsV1_0OrLater"_s;
517 return u
"DtlsV1_2"_s;
518 case QSsl::DtlsV1_2OrLater:
519 return u
"DtlsV1_2OrLater"_s;
522 case QSsl::TlsV1_3OrLater:
523 return u
"TlsV1_3OrLater"_s;
524 case QSsl::UnknownProtocol:
525 return u
"UnknownProtocol"_s;
528 QgsDebugError( u
"Can't encode protocol: %1"_s.arg( protocol ) );
530 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)