23 #include <QMutexLocker>
26 #include <QSqlDatabase>
29 #include <QTextStream>
35 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
36 #include <QRandomGenerator>
42 #include <QSslConfiguration>
63 const QString QgsAuthManager::AUTH_CONFIG_TABLE = QStringLiteral(
"auth_configs" );
64 const QString QgsAuthManager::AUTH_PASS_TABLE = QStringLiteral(
"auth_pass" );
65 const QString QgsAuthManager::AUTH_SETTINGS_TABLE = QStringLiteral(
"auth_settings" );
66 const QString QgsAuthManager::AUTH_IDENTITIES_TABLE = QStringLiteral(
"auth_identities" );
67 const QString QgsAuthManager::AUTH_SERVERS_TABLE = QStringLiteral(
"auth_servers" );
68 const QString QgsAuthManager::AUTH_AUTHORITIES_TABLE = QStringLiteral(
"auth_authorities" );
69 const QString QgsAuthManager::AUTH_TRUST_TABLE = QStringLiteral(
"auth_trust" );
71 const QString QgsAuthManager::AUTH_CFG_REGEX = QStringLiteral(
"authcfg=([a-z]|[A-Z]|[0-9]){7}" );
74 const QLatin1String QgsAuthManager::AUTH_PASSWORD_HELPER_KEY_NAME(
"QGIS-Master-Password" );
75 const QLatin1String QgsAuthManager::AUTH_PASSWORD_HELPER_FOLDER_NAME(
"QGIS" );
81 #elif defined(Q_OS_WIN)
83 #elif defined(Q_OS_LINUX)
92 QMutexLocker locker( &sMutex );
103 mMutex.reset(
new QMutex( QMutex::Recursive ) );
104 mMasterPasswordMutex.reset(
new QMutex( QMutex::Recursive ) );
106 this, &QgsAuthManager::writeToConsole );
117 QMutexLocker locker( mMutex.get() );
122 const QString connectionName = QStringLiteral(
"authentication.configs:0x%1" ).arg(
reinterpret_cast<quintptr
>( QThread::currentThread() ), 2 * QT_POINTER_SIZE, 16, QLatin1Char(
'0' ) );
123 QgsDebugMsgLevel( QStringLiteral(
"Using auth db connection name: %1 " ).arg( connectionName ), 2 );
124 if ( !QSqlDatabase::contains( connectionName ) )
126 QgsDebugMsgLevel( QStringLiteral(
"No existing connection, creating a new one" ), 2 );
127 authdb = QSqlDatabase::addDatabase( QStringLiteral(
"QSQLITE" ), connectionName );
130 if ( QThread::currentThread() != qApp->thread() )
132 QgsDebugMsgLevel( QStringLiteral(
"Scheduled auth db remove on thread close" ), 2 );
142 QMetaObject::Connection connection = connect( QThread::currentThread(), &QThread::finished, QThread::currentThread(), [connectionName,
this ]
144 QMutexLocker locker( mMutex.get() );
145 QSqlDatabase::removeDatabase( connectionName );
146 mConnectedThreads.remove( QThread::currentThread() );
147 }, Qt::DirectConnection );
149 mConnectedThreads.insert( QThread::currentThread(), connection );
155 authdb = QSqlDatabase::database( connectionName );
159 if ( !authdb.isOpen() )
161 if ( !authdb.open() )
163 const char *err = QT_TR_NOOP(
"Opening of authentication db FAILED" );
181 mQcaInitializer = qgis::make_unique<QCA::Initializer>( QCA::Practical, 256 );
184 QCA::scanForPlugins();
186 QgsDebugMsgLevel( QStringLiteral(
"QCA Plugin Diagnostics Context: %1" ).arg( QCA::pluginDiagnosticText() ), 2 );
187 QStringList capabilities;
189 capabilities = QCA::supportedFeatures();
190 QgsDebugMsgLevel( QStringLiteral(
"QCA supports: %1" ).arg( capabilities.join(
"," ) ), 2 );
193 if ( !QCA::isSupported(
"cert", QStringLiteral(
"qca-ossl" ) ) )
195 mAuthDisabled =
true;
196 mAuthDisabledMessage = tr(
"QCA's OpenSSL plugin (qca-ossl) is missing" );
200 QgsDebugMsgLevel( QStringLiteral(
"Prioritizing qca-ossl over all other QCA providers..." ), 2 );
201 const QCA::ProviderList provds = QCA::providers();
203 for ( QCA::Provider *p : provds )
205 QString pn = p->name();
207 if ( pn != QLatin1String(
"qca-ossl" ) )
209 pr = QCA::providerPriority( pn ) + 1;
211 QCA::setProviderPriority( pn, pr );
212 prlist << QStringLiteral(
"%1:%2" ).arg( pn ).arg( QCA::providerPriority( pn ) );
214 QgsDebugMsgLevel( QStringLiteral(
"QCA provider priorities: %1" ).arg( prlist.join(
", " ) ), 2 );
221 QgsDebugMsgLevel( QStringLiteral(
"Authentication methods found: %1" ).arg( methods.join(
", " ) ), 2 );
223 if ( methods.isEmpty() )
225 mAuthDisabled =
true;
226 mAuthDisabledMessage = tr(
"No authentication method plugins found" );
232 mAuthDisabled =
true;
233 mAuthDisabledMessage = tr(
"No authentication method plugins could be loaded" );
237 mAuthDbPath = QDir::cleanPath( authDatabasePath );
241 QFileInfo dbdirinfo( dbinfo.path() );
242 QgsDebugMsgLevel( QStringLiteral(
"Auth db directory path: %1" ).arg( dbdirinfo.filePath() ), 2 );
244 if ( !dbdirinfo.exists() )
246 QgsDebugMsgLevel( QStringLiteral(
"Auth db directory path does not exist, making path: %1" ).arg( dbdirinfo.filePath() ), 2 );
247 if ( !QDir().mkpath( dbdirinfo.filePath() ) )
249 const char *err = QT_TR_NOOP(
"Auth db directory path could not be created" );
256 if ( dbinfo.exists() )
258 if ( !dbinfo.permission( QFile::ReadOwner | QFile::WriteOwner ) )
260 const char *err = QT_TR_NOOP(
"Auth db is not readable or writable by user" );
265 if ( dbinfo.size() > 0 )
269 if ( !createCertTables() )
279 const char *passenv =
"QGIS_AUTH_PASSWORD_FILE";
282 QString passpath( getenv( passenv ) );
291 QFile passfile( passpath );
292 if ( passfile.exists() && passfile.open( QIODevice::ReadOnly | QIODevice::Text ) )
294 QTextStream passin( &passfile );
295 while ( !passin.atEnd() )
297 masterpass = passin.readLine();
302 if ( !masterpass.isEmpty() )
306 QgsDebugMsgLevel( QStringLiteral(
"Authentication master password set from QGIS_AUTH_PASSWORD_FILE" ), 2 );
310 QgsDebugMsg(
"QGIS_AUTH_PASSWORD_FILE set, but FAILED to set password using: " + passpath );
316 QgsDebugMsg(
"QGIS_AUTH_PASSWORD_FILE set, but FAILED to read password from: " + passpath );
326 QgsDebugMsgLevel( QStringLiteral(
"Auth db does not exist: creating through QSqlDatabase initial connection" ), 2 );
328 if ( !createConfigTables() )
331 if ( !createCertTables() )
342 bool QgsAuthManager::createConfigTables()
344 QMutexLocker locker( mMutex.get() );
348 const char *err = QT_TR_NOOP(
"Auth db could not be created and opened" );
359 qstr = QStringLiteral(
"CREATE TABLE %1 (\n"
360 " 'salt' TEXT NOT NULL,\n"
361 " 'civ' TEXT NOT NULL\n"
362 ", 'hash' TEXT NOT NULL);" ).arg( authDbPassTable() );
363 query.prepare( qstr );
364 if ( !authDbQuery( &query ) )
368 qstr = QStringLiteral(
"CREATE TABLE %1 (\n"
369 " 'id' TEXT NOT NULL,\n"
370 " 'name' TEXT NOT NULL,\n"
372 " 'type' TEXT NOT NULL,\n"
373 " 'version' INTEGER NOT NULL\n"
375 query.prepare( qstr );
376 if ( !authDbQuery( &query ) )
381 query.prepare( qstr );
382 if ( !authDbQuery( &query ) )
387 query.prepare( qstr );
388 if ( !authDbQuery( &query ) )
395 bool QgsAuthManager::createCertTables()
397 QMutexLocker locker( mMutex.get() );
406 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n"
407 " 'setting' TEXT NOT NULL\n"
408 ", 'value' TEXT);" ).arg( authDbSettingsTable() );
409 query.prepare( qstr );
410 if ( !authDbQuery( &query ) )
415 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n"
416 " 'id' TEXT NOT NULL,\n"
417 " 'key' TEXT NOT NULL\n"
418 ", 'cert' TEXT NOT NULL);" ).arg( authDbIdentitiesTable() );
419 query.prepare( qstr );
420 if ( !authDbQuery( &query ) )
424 qstr = QStringLiteral(
"CREATE UNIQUE INDEX IF NOT EXISTS 'id_index' on %1 (id ASC);" ).arg( authDbIdentitiesTable() );
425 query.prepare( qstr );
426 if ( !authDbQuery( &query ) )
431 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n"
432 " 'id' TEXT NOT NULL,\n"
433 " 'host' TEXT NOT NULL,\n"
436 query.prepare( qstr );
437 if ( !authDbQuery( &query ) )
441 qstr = QStringLiteral(
"CREATE UNIQUE INDEX IF NOT EXISTS 'host_index' on %1 (host ASC);" ).arg(
authDatabaseServersTable() );
442 query.prepare( qstr );
443 if ( !authDbQuery( &query ) )
448 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n"
449 " 'id' TEXT NOT NULL\n"
450 ", 'cert' TEXT NOT NULL);" ).arg( authDbAuthoritiesTable() );
451 query.prepare( qstr );
452 if ( !authDbQuery( &query ) )
456 qstr = QStringLiteral(
"CREATE UNIQUE INDEX IF NOT EXISTS 'id_index' on %1 (id ASC);" ).arg( authDbAuthoritiesTable() );
457 query.prepare( qstr );
458 if ( !authDbQuery( &query ) )
462 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n"
463 " 'id' TEXT NOT NULL\n"
464 ", 'policy' TEXT NOT NULL);" ).arg( authDbTrustTable() );
465 query.prepare( qstr );
466 if ( !authDbQuery( &query ) )
470 qstr = QStringLiteral(
"CREATE UNIQUE INDEX IF NOT EXISTS 'id_index' on %1 (id ASC);" ).arg( authDbTrustTable() );
471 query.prepare( qstr );
472 if ( !authDbQuery( &query ) )
483 QgsDebugMsg( QStringLiteral(
"Authentication system DISABLED: QCA's qca-ossl (OpenSSL) plugin is missing" ) );
485 return mAuthDisabled;
490 return tr(
"Authentication system is DISABLED:\n%1" ).arg( mAuthDisabledMessage );
495 QMutexLocker locker( mMasterPasswordMutex.get() );
499 if ( mScheduledDbErase )
502 if ( mMasterPass.isEmpty() )
504 QgsDebugMsgLevel( QStringLiteral(
"Master password is not yet set by user" ), 2 );
505 if ( !masterPasswordInput() )
507 QgsDebugMsgLevel( QStringLiteral(
"Master password input canceled by user" ), 2 );
521 QgsDebugMsgLevel( QStringLiteral(
"Master password is set and verified" ), 2 );
527 QMutexLocker locker( mMutex.get() );
531 if ( mScheduledDbErase )
535 QString prevpass = QString( mMasterPass );
539 mMasterPass = prevpass;
540 const char *err = QT_TR_NOOP(
"Master password set: FAILED to verify, reset to previous" );
546 QgsDebugMsgLevel( QStringLiteral(
"Master password set: SUCCESS%1" ).arg( verify ?
" and verified" :
"" ), 2 );
556 if ( !masterPasswordRowsInDb( &rows ) )
558 const char *err = QT_TR_NOOP(
"Master password: FAILED to access database" );
566 QgsDebugMsgLevel( QStringLiteral(
"Master password: %1 rows in database" ).arg( rows ), 2 );
570 const char *err = QT_TR_NOOP(
"Master password: FAILED to find just one master password record in database" );
577 else if ( rows == 1 )
579 if ( !masterPasswordCheckAgainstDb( compare ) )
581 if ( compare.isNull() )
583 const char *err = QT_TR_NOOP(
"Master password: FAILED to verify against hash in database" );
592 if ( mPassTries >= 5 )
594 mAuthDisabled =
true;
595 const char *err = QT_TR_NOOP(
"Master password: failed 5 times authentication system DISABLED" );
603 QgsDebugMsgLevel( QStringLiteral(
"Master password: verified against hash in database" ), 2 );
604 if ( compare.isNull() )
608 else if ( compare.isNull() )
610 if ( !masterPasswordStoreInDb() )
612 const char *err = QT_TR_NOOP(
"Master password: hash FAILED to be stored in database" );
621 QgsDebugMsgLevel( QStringLiteral(
"Master password: hash stored in database" ), 2 );
624 if ( !masterPasswordCheckAgainstDb() )
626 const char *err = QT_TR_NOOP(
"Master password: FAILED to verify against hash in database" );
636 QgsDebugMsgLevel( QStringLiteral(
"Master password: verified against hash in database" ), 2 );
646 return !mMasterPass.isEmpty();
651 return mMasterPass == pass;
655 bool keepbackup, QString *backuppath )
669 QgsDebugMsgLevel( QStringLiteral(
"Master password reset: backed up current database" ), 2 );
675 QString prevpass = QString( mMasterPass );
676 QString prevciv = QString( masterPasswordCiv() );
682 if ( ok && !masterPasswordClearDb() )
685 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not clear current password from database" );
691 QgsDebugMsgLevel( QStringLiteral(
"Master password reset: cleared current password from database" ), 2 );
698 if ( ok && !masterPasswordStoreInDb() )
701 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not store new password in database" );
707 QgsDebugMsgLevel( QStringLiteral(
"Master password reset: stored new password in database" ), 2 );
714 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not verify new password in database" );
720 if ( ok && !reencryptAllAuthenticationConfigs( prevpass, prevciv ) )
723 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not re-encrypt configs in database" );
729 QgsDebugMsgLevel( QStringLiteral(
"Master password reset: re-encrypted configs in database" ), 2 );
733 if ( ok && !verifyPasswordCanDecryptConfigs() )
736 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not verify password can decrypt re-encrypted configs" );
741 if ( ok && !reencryptAllAuthenticationSettings( prevpass, prevciv ) )
744 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not re-encrypt settings in database" );
749 if ( ok && !reencryptAllAuthenticationIdentities( prevpass, prevciv ) )
752 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not re-encrypt identities in database" );
762 QString errdbbackup( dbbackup );
763 errdbbackup.replace( QLatin1String(
".db" ), QLatin1String(
"_ERROR.db" ) );
765 QgsDebugMsg( QStringLiteral(
"Master password reset FAILED: backed up failed db at %1" ).arg( errdbbackup ) );
769 mMasterPass = prevpass;
771 QgsDebugMsg( QStringLiteral(
"Master password reset FAILED: reinstated previous password and database" ) );
775 *backuppath = errdbbackup;
781 if ( !keepbackup && !QFile::remove( dbbackup ) )
783 const char *err = QT_TR_NOOP(
"Master password reset: could not remove old database backup" );
791 QgsDebugMsgLevel( QStringLiteral(
"Master password reset: backed up previous db at %1" ).arg( dbbackup ), 2 );
793 *backuppath = dbbackup;
803 mScheduledDbErase = scheduleErase;
805 mScheduledDbEraseRequestEmitted =
false;
806 mScheduledDbEraseRequestCount = 0;
810 if ( !mScheduledDbEraseTimer )
812 mScheduledDbEraseTimer =
new QTimer(
this );
813 connect( mScheduledDbEraseTimer, &QTimer::timeout,
this, &QgsAuthManager::tryToStartDbErase );
814 mScheduledDbEraseTimer->start( mScheduledDbEraseRequestWait * 1000 );
816 else if ( !mScheduledDbEraseTimer->isActive() )
818 mScheduledDbEraseTimer->start();
823 if ( mScheduledDbEraseTimer && mScheduledDbEraseTimer->isActive() )
824 mScheduledDbEraseTimer->stop();
833 qDeleteAll( mAuthMethods );
834 mAuthMethods.clear();
836 for (
const auto &authMethodKey : methods )
841 return !mAuthMethods.isEmpty();
851 QTimer::singleShot( 3, &loop, &QEventLoop::quit );
854 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
855 uint seed =
static_cast< uint
>( QTime::currentTime().msec() );
862 for (
int i = 0; i < len; i++ )
864 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
865 switch ( qrand() % 2 )
867 switch ( QRandomGenerator::system()->generate() % 2 )
871 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
872 id += (
'0' + qrand() % 10 );
874 id += (
'0' + QRandomGenerator::system()->generate() % 10 );
878 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
879 id += (
'a' + qrand() % 26 );
881 id += (
'a' + QRandomGenerator::system()->generate() % 26 );
886 if ( !configids.contains(
id ) )
891 QgsDebugMsgLevel( QStringLiteral(
"Generated unique ID: %1" ).arg(
id ), 2 );
902 const char *err = QT_TR_NOOP(
"Config ID is empty" );
908 return !configids.contains(
id );
913 QRegExp rx( AUTH_CFG_REGEX );
914 return rx.indexIn( txt ) != -1;
919 QMutexLocker locker( mMutex.get() );
920 QStringList providerAuthMethodsKeys;
921 if ( !dataprovider.isEmpty() )
932 query.prepare( QStringLiteral(
"SELECT id, name, uri, type, version FROM %1" ).arg(
authDatabaseConfigTable() ) );
934 if ( !authDbQuery( &query ) )
939 if ( query.isActive() && query.isSelect() )
941 while ( query.next() )
943 QString authcfg = query.value( 0 ).toString();
945 config.
setId( authcfg );
946 config.
setName( query.value( 1 ).toString() );
947 config.
setUri( query.value( 2 ).toString() );
948 config.
setMethod( query.value( 3 ).toString() );
949 config.
setVersion( query.value( 4 ).toInt() );
951 if ( !dataprovider.isEmpty() && !providerAuthMethodsKeys.contains( config.
method() ) )
956 baseConfigs.insert( authcfg, config );
964 QMutexLocker locker( mMutex.get() );
971 if ( !authDbQuery( &query ) )
976 if ( query.isActive() )
978 QgsDebugMsgLevel( QStringLiteral(
"Syncing existing auth config and their auth methods" ), 2 );
979 mConfigAuthMethods.clear();
980 QStringList cfgmethods;
981 while ( query.next() )
983 mConfigAuthMethods.insert( query.value( 0 ).toString(),
984 query.value( 1 ).toString() );
985 cfgmethods << QStringLiteral(
"%1=%2" ).arg( query.value( 0 ).toString(), query.value( 1 ).toString() );
987 QgsDebugMsgLevel( QStringLiteral(
"Stored auth config/methods:\n%1" ).arg( cfgmethods.join(
", " ) ), 2 );
996 if ( !mConfigAuthMethods.contains( authcfg ) )
998 QgsDebugMsg( QStringLiteral(
"No config auth method found in database for authcfg: %1" ).arg( authcfg ) );
1002 QString authMethodKey = mConfigAuthMethods.value( authcfg );
1012 return mConfigAuthMethods.value( authcfg, QString() );
1023 if ( !mAuthMethods.contains( authMethodKey ) )
1025 QgsDebugMsg( QStringLiteral(
"No auth method registered for auth method key: %1" ).arg( authMethodKey ) );
1029 return mAuthMethods.value( authMethodKey );
1034 if ( dataprovider.isEmpty() )
1036 return mAuthMethods;
1040 QgsAuthMethodsMap::const_iterator i = mAuthMethods.constBegin();
1041 while ( i != mAuthMethods.constEnd() )
1044 && ( i.value()->supportedDataProviders().contains( QStringLiteral(
"all" ) )
1045 || i.value()->supportedDataProviders().contains( dataprovider ) ) )
1047 filteredmap.insert( i.key(), i.value() );
1062 return QgsAuthMethod::Expansions();
1069 return QgsAuthMethod::Expansions();
1074 QMutexLocker locker( mMutex.get() );
1081 const char *err = QT_TR_NOOP(
"Store config: FAILED because config is invalid" );
1087 QString uid = mconfig.
id();
1088 bool passedinID = !uid.isEmpty();
1089 if ( uid.isEmpty() )
1095 const char *err = QT_TR_NOOP(
"Store config: FAILED because pre-defined config ID is not unique" );
1102 if ( configstring.isEmpty() )
1104 const char *err = QT_TR_NOOP(
"Store config: FAILED because config string is empty" );
1110 QgsDebugMsg( QStringLiteral(
"authDbConfigTable(): %1" ).arg( authDbConfigTable() ) );
1111 QgsDebugMsg( QStringLiteral(
"name: %1" ).arg( config.name() ) );
1112 QgsDebugMsg( QStringLiteral(
"uri: %1" ).arg( config.uri() ) );
1113 QgsDebugMsg( QStringLiteral(
"type: %1" ).arg( config.method() ) );
1114 QgsDebugMsg( QStringLiteral(
"version: %1" ).arg( config.version() ) );
1115 QgsDebugMsg( QStringLiteral(
"config: %1" ).arg( configstring ) );
1119 query.prepare( QStringLiteral(
"INSERT INTO %1 (id, name, uri, type, version, config) "
1122 query.bindValue( QStringLiteral(
":id" ), uid );
1123 query.bindValue( QStringLiteral(
":name" ), mconfig.
name() );
1124 query.bindValue( QStringLiteral(
":uri" ), mconfig.
uri() );
1125 query.bindValue( QStringLiteral(
":type" ), mconfig.
method() );
1126 query.bindValue( QStringLiteral(
":version" ), mconfig.
version() );
1127 query.bindValue( QStringLiteral(
":config" ),
QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
1129 if ( !authDbStartTransaction() )
1132 if ( !authDbQuery( &query ) )
1135 if ( !authDbCommit() )
1140 mconfig.
setId( uid );
1144 QgsDebugMsgLevel( QStringLiteral(
"Store config SUCCESS for authcfg: %1" ).arg( uid ), 2 );
1151 QMutexLocker locker( mMutex.get() );
1156 if ( !config.
isValid(
true ) )
1158 const char *err = QT_TR_NOOP(
"Update config: FAILED because config is invalid" );
1165 if ( configstring.isEmpty() )
1167 const char *err = QT_TR_NOOP(
"Update config: FAILED because config is empty" );
1174 QgsDebugMsg( QStringLiteral(
"authDbConfigTable(): %1" ).arg( authDbConfigTable() ) );
1175 QgsDebugMsg( QStringLiteral(
"id: %1" ).arg( config.
id() ) );
1180 QgsDebugMsg( QStringLiteral(
"config: %1" ).arg( configstring ) );
1184 if ( !query.prepare( QStringLiteral(
"UPDATE %1 "
1185 "SET name = :name, uri = :uri, type = :type, version = :version, config = :config "
1188 const char *err = QT_TR_NOOP(
"Update config: FAILED to prepare query" );
1194 query.bindValue( QStringLiteral(
":id" ), config.
id() );
1195 query.bindValue( QStringLiteral(
":name" ), config.
name() );
1196 query.bindValue( QStringLiteral(
":uri" ), config.
uri() );
1197 query.bindValue( QStringLiteral(
":type" ), config.
method() );
1198 query.bindValue( QStringLiteral(
":version" ), config.
version() );
1199 query.bindValue( QStringLiteral(
":config" ),
QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
1201 if ( !authDbStartTransaction() )
1204 if ( !authDbQuery( &query ) )
1207 if ( !authDbCommit() )
1215 QgsDebugMsgLevel( QStringLiteral(
"Update config SUCCESS for authcfg: %1" ).arg( config.
id() ), 2 );
1228 QMutexLocker locker( mMutex.get() );
1233 query.prepare( QStringLiteral(
"SELECT id, name, uri, type, version, config FROM %1 "
1238 query.prepare( QStringLiteral(
"SELECT id, name, uri, type, version FROM %1 "
1242 query.bindValue( QStringLiteral(
":id" ), authcfg );
1244 if ( !authDbQuery( &query ) )
1249 if ( query.isActive() && query.isSelect() )
1251 if ( query.first() )
1253 mconfig.
setId( query.value( 0 ).toString() );
1254 mconfig.
setName( query.value( 1 ).toString() );
1255 mconfig.
setUri( query.value( 2 ).toString() );
1256 mconfig.
setMethod( query.value( 3 ).toString() );
1257 mconfig.
setVersion( query.value( 4 ).toInt() );
1272 QgsDebugMsg( QStringLiteral(
"Update of authcfg %1 FAILED for auth method %2" ).arg( authcfg, authMethodKey ) );
1275 QgsDebugMsgLevel( QStringLiteral(
"Load %1 config SUCCESS for authcfg: %2" ).arg( full ?
"full" :
"base", authcfg ), 2 );
1280 QgsDebugMsg( QStringLiteral(
"Select contains more than one for authcfg: %1" ).arg( authcfg ) );
1290 QMutexLocker locker( mMutex.get() );
1294 if ( authcfg.isEmpty() )
1301 query.bindValue( QStringLiteral(
":id" ), authcfg );
1303 if ( !authDbStartTransaction() )
1306 if ( !authDbQuery( &query ) )
1309 if ( !authDbCommit() )
1316 QgsDebugMsgLevel( QStringLiteral(
"REMOVED config for authcfg: %1" ).arg( authcfg ), 2 );
1323 QMutexLocker locker( mMutex.get() );
1329 bool res = authDbTransactionQuery( &query );
1337 QgsDebugMsgLevel( QStringLiteral(
"Remove configs from database: %1" ).arg( res ?
"SUCCEEDED" :
"FAILED" ), 2 );
1344 QMutexLocker locker( mMutex.get() );
1347 const char *err = QT_TR_NOOP(
"No authentication database found" );
1355 if ( authConn.isValid() && authConn.isOpen() )
1359 QString datestamp( QDateTime::currentDateTime().toString( QStringLiteral(
"yyyy-MM-dd-hhmmss" ) ) );
1361 dbbackup.replace( QLatin1String(
".db" ), QStringLiteral(
"_%1.db" ).arg( datestamp ) );
1365 const char *err = QT_TR_NOOP(
"Could not back up authentication database" );
1372 *backuppath = dbbackup;
1374 QgsDebugMsgLevel( QStringLiteral(
"Backed up auth database at %1" ).arg( dbbackup ), 2 );
1380 QMutexLocker locker( mMutex.get() );
1390 if ( backuppath && !dbbackup.isEmpty() )
1391 *backuppath = dbbackup;
1394 if ( dbinfo.exists() )
1396 if ( !dbinfo.permission( QFile::ReadOwner | QFile::WriteOwner ) )
1398 const char *err = QT_TR_NOOP(
"Auth db is not readable or writable by user" );
1406 const char *err = QT_TR_NOOP(
"No authentication database found" );
1414 const char *err = QT_TR_NOOP(
"Authentication database could not be deleted" );
1420 mMasterPass = QString();
1422 QgsDebugMsgLevel( QStringLiteral(
"Creating Auth db through QSqlDatabase initial connection" ), 2 );
1425 if ( !authConn.isValid() || !authConn.isOpen() )
1427 const char *err = QT_TR_NOOP(
"Authentication database could not be initialized" );
1433 if ( !createConfigTables() )
1435 const char *err = QT_TR_NOOP(
"FAILED to create auth database config tables" );
1441 if ( !createCertTables() )
1443 const char *err = QT_TR_NOOP(
"FAILED to create auth database cert tables" );
1459 const QString &dataprovider )
1469 QgsDebugMsg( QStringLiteral(
"Network request updating not supported by authcfg: %1" ).arg( authcfg ) );
1484 const QString &dataprovider )
1494 QgsDebugMsg( QStringLiteral(
"Network reply updating not supported by authcfg: %1" ).arg( authcfg ) );
1510 const QString &dataprovider )
1520 QgsDebugMsg( QStringLiteral(
"Data source URI updating not supported by authcfg: %1" ).arg( authcfg ) );
1545 QgsDebugMsg( QStringLiteral(
"Proxy updating not supported by authcfg: %1" ).arg( authcfg ) );
1554 QgsDebugMsgLevel( QStringLiteral(
"Proxy updated successfully from authcfg: %1" ).arg( authcfg ), 2 );
1563 QMutexLocker locker( mMutex.get() );
1564 if ( key.isEmpty() )
1567 QString storeval( value.toString() );
1583 query.prepare( QStringLiteral(
"INSERT INTO %1 (setting, value) "
1584 "VALUES (:setting, :value)" ).arg( authDbSettingsTable() ) );
1586 query.bindValue( QStringLiteral(
":setting" ), key );
1587 query.bindValue( QStringLiteral(
":value" ), storeval );
1589 if ( !authDbStartTransaction() )
1592 if ( !authDbQuery( &query ) )
1595 if ( !authDbCommit() )
1598 QgsDebugMsgLevel( QStringLiteral(
"Store setting SUCCESS for key: %1" ).arg( key ), 2 );
1604 QMutexLocker locker( mMutex.get() );
1605 if ( key.isEmpty() )
1611 QVariant value = defaultValue;
1613 query.prepare( QStringLiteral(
"SELECT value FROM %1 "
1614 "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
1616 query.bindValue( QStringLiteral(
":setting" ), key );
1618 if ( !authDbQuery( &query ) )
1621 if ( query.isActive() && query.isSelect() )
1623 if ( query.first() )
1627 value = QVariant(
QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 0 ).toString() ) );
1631 value = query.value( 0 );
1633 QgsDebugMsgLevel( QStringLiteral(
"Authentication setting retrieved for key: %1" ).arg( key ), 2 );
1637 QgsDebugMsg( QStringLiteral(
"Select contains more than one for setting key: %1" ).arg( key ) );
1647 QMutexLocker locker( mMutex.get() );
1648 if ( key.isEmpty() )
1652 query.prepare( QStringLiteral(
"SELECT value FROM %1 "
1653 "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
1655 query.bindValue( QStringLiteral(
":setting" ), key );
1657 if ( !authDbQuery( &query ) )
1661 if ( query.isActive() && query.isSelect() )
1663 if ( query.first() )
1665 QgsDebugMsgLevel( QStringLiteral(
"Authentication setting exists for key: %1" ).arg( key ), 2 );
1670 QgsDebugMsg( QStringLiteral(
"Select contains more than one for setting key: %1" ).arg( key ) );
1680 QMutexLocker locker( mMutex.get() );
1681 if ( key.isEmpty() )
1686 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
1688 query.bindValue( QStringLiteral(
":setting" ), key );
1690 if ( !authDbStartTransaction() )
1693 if ( !authDbQuery( &query ) )
1696 if ( !authDbCommit() )
1699 QgsDebugMsgLevel( QStringLiteral(
"REMOVED setting for key: %1" ).arg( key ), 2 );
1713 QMutexLocker locker( mMutex.get() );
1719 mCustomConfigByHostCache.clear();
1720 mHasCheckedIfCustomConfigByHostExists =
false;
1723 QgsDebugMsg( QStringLiteral(
"Init of SSL caches FAILED" ) );
1729 QMutexLocker locker( mMutex.get() );
1730 if ( cert.isNull() )
1732 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
1737 QgsDebugMsg( QStringLiteral(
"Passed private key is null" ) );
1747 QString certpem( cert.toPem() );
1751 query.prepare( QStringLiteral(
"INSERT INTO %1 (id, key, cert) "
1752 "VALUES (:id, :key, :cert)" ).arg( authDbIdentitiesTable() ) );
1754 query.bindValue( QStringLiteral(
":id" ),
id );
1755 query.bindValue( QStringLiteral(
":key" ), keypem );
1756 query.bindValue( QStringLiteral(
":cert" ), certpem );
1758 if ( !authDbStartTransaction() )
1761 if ( !authDbQuery( &query ) )
1764 if ( !authDbCommit() )
1767 QgsDebugMsgLevel( QStringLiteral(
"Store certificate identity SUCCESS for id: %1" ).arg(
id ), 2 );
1773 QMutexLocker locker( mMutex.get() );
1774 QSslCertificate emptycert;
1775 QSslCertificate cert;
1780 query.prepare( QStringLiteral(
"SELECT cert FROM %1 "
1781 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1783 query.bindValue( QStringLiteral(
":id" ),
id );
1785 if ( !authDbQuery( &query ) )
1788 if ( query.isActive() && query.isSelect() )
1790 if ( query.first() )
1792 cert = QSslCertificate( query.value( 0 ).toByteArray(), QSsl::Pem );
1793 QgsDebugMsgLevel( QStringLiteral(
"Certificate identity retrieved for id: %1" ).arg(
id ), 2 );
1797 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate identity for id: %1" ).arg(
id ) );
1807 QMutexLocker locker( mMutex.get() );
1808 QPair<QSslCertificate, QSslKey> bundle;
1816 query.prepare( QStringLiteral(
"SELECT key, cert FROM %1 "
1817 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1819 query.bindValue( QStringLiteral(
":id" ),
id );
1821 if ( !authDbQuery( &query ) )
1824 if ( query.isActive() && query.isSelect() )
1826 QSslCertificate cert;
1828 if ( query.first() )
1830 key = QSslKey(
QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 0 ).toString() ).toLatin1(),
1831 QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey );
1834 const char *err = QT_TR_NOOP(
"Retrieve certificate identity bundle: FAILED to create private key" );
1839 cert = QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
1840 if ( cert.isNull() )
1842 const char *err = QT_TR_NOOP(
"Retrieve certificate identity bundle: FAILED to create certificate" );
1847 QgsDebugMsgLevel( QStringLiteral(
"Certificate identity bundle retrieved for id: %1" ).arg(
id ), 2 );
1851 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate identity for id: %1" ).arg(
id ) );
1855 bundle = qMakePair( cert, key );
1862 QMutexLocker locker( mMutex.get() );
1866 return QStringList() << QString( bundle.first.toPem() ) << QString( bundle.second.toPem() );
1868 return QStringList();
1873 QMutexLocker locker( mMutex.get() );
1874 QList<QSslCertificate> certs;
1877 query.prepare( QStringLiteral(
"SELECT id, cert FROM %1" ).arg( authDbIdentitiesTable() ) );
1879 if ( !authDbQuery( &query ) )
1882 if ( query.isActive() && query.isSelect() )
1884 while ( query.next() )
1886 certs << QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
1895 QMutexLocker locker( mMutex.get() );
1896 QStringList identityids = QStringList();
1902 query.prepare( QStringLiteral(
"SELECT id FROM %1" ).arg( authDbIdentitiesTable() ) );
1904 if ( !authDbQuery( &query ) )
1909 if ( query.isActive() )
1911 while ( query.next() )
1913 identityids << query.value( 0 ).toString();
1921 QMutexLocker locker( mMutex.get() );
1926 query.prepare( QStringLiteral(
"SELECT cert FROM %1 "
1927 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1929 query.bindValue( QStringLiteral(
":id" ),
id );
1931 if ( !authDbQuery( &query ) )
1935 if ( query.isActive() && query.isSelect() )
1937 if ( query.first() )
1939 QgsDebugMsgLevel( QStringLiteral(
"Certificate bundle exists for id: %1" ).arg(
id ), 2 );
1944 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate bundle for id: %1" ).arg(
id ) );
1954 QMutexLocker locker( mMutex.get() );
1957 QgsDebugMsg( QStringLiteral(
"Passed bundle ID is empty" ) );
1963 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1965 query.bindValue( QStringLiteral(
":id" ),
id );
1967 if ( !authDbStartTransaction() )
1970 if ( !authDbQuery( &query ) )
1973 if ( !authDbCommit() )
1976 QgsDebugMsgLevel( QStringLiteral(
"REMOVED certificate identity for id: %1" ).arg(
id ), 2 );
1982 QMutexLocker locker( mMutex.get() );
1985 QgsDebugMsg( QStringLiteral(
"Passed config is null" ) );
1994 QString certpem( cert.toPem() );
1997 query.prepare( QStringLiteral(
"INSERT OR REPLACE INTO %1 (id, host, cert, config) "
2000 query.bindValue( QStringLiteral(
":id" ),
id );
2001 query.bindValue( QStringLiteral(
":host" ), config.
sslHostPort().trimmed() );
2002 query.bindValue( QStringLiteral(
":cert" ), certpem );
2003 query.bindValue( QStringLiteral(
":config" ), config.
configString() );
2005 if ( !authDbStartTransaction() )
2008 if ( !authDbQuery( &query ) )
2011 if ( !authDbCommit() )
2014 QgsDebugMsgLevel( QStringLiteral(
"Store SSL cert custom config SUCCESS for host:port, id: %1, %2" )
2018 mHasCheckedIfCustomConfigByHostExists =
false;
2019 mCustomConfigByHostCache.clear();
2026 QMutexLocker locker( mMutex.get() );
2029 if (
id.isEmpty() || hostport.isEmpty() )
2031 QgsDebugMsg( QStringLiteral(
"Passed config ID or host:port is empty" ) );
2036 query.prepare( QStringLiteral(
"SELECT id, host, cert, config FROM %1 "
2039 query.bindValue( QStringLiteral(
":id" ),
id );
2040 query.bindValue( QStringLiteral(
":host" ), hostport.trimmed() );
2042 if ( !authDbQuery( &query ) )
2045 if ( query.isActive() && query.isSelect() )
2047 if ( query.first() )
2049 config.
setSslCertificate( QSslCertificate( query.value( 2 ).toByteArray(), QSsl::Pem ) );
2052 QgsDebugMsgLevel( QStringLiteral(
"SSL cert custom config retrieved for host:port, id: %1, %2" ).arg( hostport,
id ), 2 );
2056 QgsDebugMsg( QStringLiteral(
"Select contains more than one SSL cert custom config for host:port, id: %1, %2" ).arg( hostport,
id ) );
2057 emit
messageOut( tr(
"Authentication database contains duplicate SSL cert custom configs for host:port, id: %1, %2" )
2069 if ( hostport.isEmpty() )
2074 QMutexLocker locker( mMutex.get() );
2075 if ( mHasCheckedIfCustomConfigByHostExists && !mHasCustomConfigByHost )
2077 if ( mCustomConfigByHostCache.contains( hostport ) )
2078 return mCustomConfigByHostCache.value( hostport );
2083 if ( !mHasCheckedIfCustomConfigByHostExists )
2085 mHasCheckedIfCustomConfigByHostExists =
true;
2087 if ( !authDbQuery( &query ) )
2089 mHasCustomConfigByHost =
false;
2092 if ( query.isActive() && query.isSelect() && query.first() )
2094 mHasCustomConfigByHost = query.value( 0 ).toInt() > 0;
2095 if ( !mHasCustomConfigByHost )
2100 mHasCustomConfigByHost =
false;
2105 query.prepare( QString(
"SELECT id, host, cert, config FROM %1 "
2108 query.bindValue( QStringLiteral(
":host" ), hostport.trimmed() );
2110 if ( !authDbQuery( &query ) )
2112 mCustomConfigByHostCache.insert( hostport, config );
2116 if ( query.isActive() && query.isSelect() )
2118 if ( query.first() )
2120 config.
setSslCertificate( QSslCertificate( query.value( 2 ).toByteArray(), QSsl::Pem ) );
2123 QgsDebugMsgLevel( QStringLiteral(
"SSL cert custom config retrieved for host:port: %1" ).arg( hostport ), 2 );
2127 QgsDebugMsg( QStringLiteral(
"Select contains more than one SSL cert custom config for host:port: %1" ).arg( hostport ) );
2128 emit
messageOut( tr(
"Authentication database contains duplicate SSL cert custom configs for host:port: %1" )
2131 mCustomConfigByHostCache.insert( hostport, emptyconfig );
2136 mCustomConfigByHostCache.insert( hostport, config );
2142 QMutexLocker locker( mMutex.get() );
2143 QList<QgsAuthConfigSslServer> configs;
2148 if ( !authDbQuery( &query ) )
2151 if ( query.isActive() && query.isSelect() )
2153 while ( query.next() )
2156 config.
setSslCertificate( QSslCertificate( query.value( 2 ).toByteArray(), QSsl::Pem ) );
2160 configs.append( config );
2169 QMutexLocker locker( mMutex.get() );
2170 if (
id.isEmpty() || hostport.isEmpty() )
2172 QgsDebugMsg( QStringLiteral(
"Passed config ID or host:port is empty" ) );
2177 query.prepare( QStringLiteral(
"SELECT cert FROM %1 "
2180 query.bindValue( QStringLiteral(
":id" ),
id );
2181 query.bindValue( QStringLiteral(
":host" ), hostport.trimmed() );
2183 if ( !authDbQuery( &query ) )
2187 if ( query.isActive() && query.isSelect() )
2189 if ( query.first() )
2191 QgsDebugMsgLevel( QStringLiteral(
"SSL cert custom config exists for host:port, id: %1, %2" ).arg( hostport,
id ), 2 );
2196 QgsDebugMsg( QStringLiteral(
"Select contains more than one SSL cert custom config for host:port, id: %1, %2" ).arg( hostport,
id ) );
2197 emit
messageOut( tr(
"Authentication database contains duplicate SSL cert custom configs for host:port, id: %1, %2" )
2207 QMutexLocker locker( mMutex.get() );
2208 if (
id.isEmpty() || hostport.isEmpty() )
2210 QgsDebugMsg( QStringLiteral(
"Passed config ID or host:port is empty" ) );
2214 mHasCheckedIfCustomConfigByHostExists =
false;
2215 mCustomConfigByHostCache.clear();
2219 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE id = :id AND host = :host" ).arg(
authDatabaseServersTable() ) );
2221 query.bindValue( QStringLiteral(
":id" ),
id );
2222 query.bindValue( QStringLiteral(
":host" ), hostport.trimmed() );
2224 if ( !authDbStartTransaction() )
2227 if ( !authDbQuery( &query ) )
2230 if ( !authDbCommit() )
2233 QString shahostport( QStringLiteral(
"%1:%2" ).arg(
id, hostport ) );
2234 if ( mIgnoredSslErrorsCache.contains( shahostport ) )
2236 mIgnoredSslErrorsCache.remove( shahostport );
2239 QgsDebugMsgLevel( QStringLiteral(
"REMOVED SSL cert custom config for host:port, id: %1, %2" ).arg( hostport,
id ), 2 );
2246 QMutexLocker locker( mMutex.get() );
2247 if ( !mIgnoredSslErrorsCache.isEmpty() )
2249 QgsDebugMsg( QStringLiteral(
"Ignored SSL errors cache items:" ) );
2250 QHash<QString, QSet<QSslError::SslError> >::const_iterator i = mIgnoredSslErrorsCache.constBegin();
2251 while ( i != mIgnoredSslErrorsCache.constEnd() )
2254 for (
auto err : i.value() )
2258 QgsDebugMsg( QStringLiteral(
"%1 = %2" ).arg( i.key(), errs.join(
", " ) ) );
2270 QMutexLocker locker( mMutex.get() );
2273 QgsDebugMsg( QStringLiteral(
"Passed config is null" ) );
2277 QString shahostport( QStringLiteral(
"%1:%2" )
2280 if ( mIgnoredSslErrorsCache.contains( shahostport ) )
2282 mIgnoredSslErrorsCache.remove( shahostport );
2285 if ( !errenums.isEmpty() )
2287 mIgnoredSslErrorsCache.insert( shahostport, qgis::listToSet( errenums ) );
2288 QgsDebugMsgLevel( QStringLiteral(
"Update of ignored SSL errors cache SUCCEEDED for sha:host:port = %1" ).arg( shahostport ), 2 );
2293 QgsDebugMsgLevel( QStringLiteral(
"No ignored SSL errors to cache for sha:host:port = %1" ).arg( shahostport ), 2 );
2299 QMutexLocker locker( mMutex.get() );
2300 QRegExp rx(
"\\S+:\\S+:\\d+" );
2301 if ( !rx.exactMatch( shahostport ) )
2303 QgsDebugMsg(
"Passed shahostport does not match \\S+:\\S+:\\d+, "
2304 "e.g. 74a4ef5ea94512a43769b744cda0ca5049a72491:www.example.com:443" );
2308 if ( mIgnoredSslErrorsCache.contains( shahostport ) )
2310 mIgnoredSslErrorsCache.remove( shahostport );
2313 if ( errors.isEmpty() )
2315 QgsDebugMsg( QStringLiteral(
"Passed errors list empty" ) );
2319 QSet<QSslError::SslError> errs;
2320 for (
const auto &error : errors )
2322 if ( error.error() == QSslError::NoError )
2325 errs.insert( error.error() );
2328 if ( errs.isEmpty() )
2330 QgsDebugMsg( QStringLiteral(
"Passed errors list does not contain errors" ) );
2334 mIgnoredSslErrorsCache.insert( shahostport, errs );
2336 QgsDebugMsgLevel( QStringLiteral(
"Update of ignored SSL errors cache SUCCEEDED for sha:host:port = %1" ).arg( shahostport ), 2 );
2343 QMutexLocker locker( mMutex.get() );
2344 QHash<QString, QSet<QSslError::SslError> > prevcache( mIgnoredSslErrorsCache );
2345 QHash<QString, QSet<QSslError::SslError> > nextcache;
2350 if ( !authDbQuery( &query ) )
2352 QgsDebugMsg( QStringLiteral(
"Rebuild of ignored SSL errors cache FAILED" ) );
2356 if ( query.isActive() && query.isSelect() )
2358 while ( query.next() )
2360 QString shahostport( QStringLiteral(
"%1:%2" )
2361 .arg( query.value( 0 ).toString().trimmed(),
2362 query.value( 1 ).toString().trimmed() ) );
2366 if ( !errenums.isEmpty() )
2368 nextcache.insert( shahostport, qgis::listToSet( errenums ) );
2370 if ( prevcache.contains( shahostport ) )
2372 prevcache.remove( shahostport );
2377 if ( !prevcache.isEmpty() )
2380 QHash<QString, QSet<QSslError::SslError> >::const_iterator i = prevcache.constBegin();
2381 while ( i != prevcache.constEnd() )
2383 nextcache.insert( i.key(), i.value() );
2388 if ( nextcache != mIgnoredSslErrorsCache )
2390 mIgnoredSslErrorsCache.clear();
2391 mIgnoredSslErrorsCache = nextcache;
2392 QgsDebugMsgLevel( QStringLiteral(
"Rebuild of ignored SSL errors cache SUCCEEDED" ), 2 );
2397 QgsDebugMsgLevel( QStringLiteral(
"Rebuild of ignored SSL errors cache SAME AS BEFORE" ), 2 );
2405 QMutexLocker locker( mMutex.get() );
2406 if ( certs.isEmpty() )
2408 QgsDebugMsg( QStringLiteral(
"Passed certificate list has no certs" ) );
2412 for (
const auto &cert : certs )
2422 QMutexLocker locker( mMutex.get() );
2425 if ( cert.isNull() )
2427 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2434 QString pem( cert.toPem() );
2437 query.prepare( QStringLiteral(
"INSERT INTO %1 (id, cert) "
2438 "VALUES (:id, :cert)" ).arg( authDbAuthoritiesTable() ) );
2440 query.bindValue( QStringLiteral(
":id" ),
id );
2441 query.bindValue( QStringLiteral(
":cert" ), pem );
2443 if ( !authDbStartTransaction() )
2446 if ( !authDbQuery( &query ) )
2449 if ( !authDbCommit() )
2452 QgsDebugMsgLevel( QStringLiteral(
"Store certificate authority SUCCESS for id: %1" ).arg(
id ), 2 );
2458 QMutexLocker locker( mMutex.get() );
2459 QSslCertificate emptycert;
2460 QSslCertificate cert;
2465 query.prepare( QStringLiteral(
"SELECT cert FROM %1 "
2466 "WHERE id = :id" ).arg( authDbAuthoritiesTable() ) );
2468 query.bindValue( QStringLiteral(
":id" ),
id );
2470 if ( !authDbQuery( &query ) )
2473 if ( query.isActive() && query.isSelect() )
2475 if ( query.first() )
2477 cert = QSslCertificate( query.value( 0 ).toByteArray(), QSsl::Pem );
2478 QgsDebugMsgLevel( QStringLiteral(
"Certificate authority retrieved for id: %1" ).arg(
id ), 2 );
2482 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate authority for id: %1" ).arg(
id ) );
2492 QMutexLocker locker( mMutex.get() );
2493 if ( cert.isNull() )
2495 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2502 query.prepare( QStringLiteral(
"SELECT value FROM %1 "
2503 "WHERE id = :id" ).arg( authDbAuthoritiesTable() ) );
2505 query.bindValue( QStringLiteral(
":id" ),
id );
2507 if ( !authDbQuery( &query ) )
2511 if ( query.isActive() && query.isSelect() )
2513 if ( query.first() )
2515 QgsDebugMsgLevel( QStringLiteral(
"Certificate authority exists for id: %1" ).arg(
id ), 2 );
2520 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate authority for id: %1" ).arg(
id ) );
2530 QMutexLocker locker( mMutex.get() );
2531 if ( cert.isNull() )
2533 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2541 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE id = :id" ).arg( authDbAuthoritiesTable() ) );
2543 query.bindValue( QStringLiteral(
":id" ),
id );
2545 if ( !authDbStartTransaction() )
2548 if ( !authDbQuery( &query ) )
2551 if ( !authDbCommit() )
2554 QgsDebugMsgLevel( QStringLiteral(
"REMOVED authority for id: %1" ).arg(
id ), 2 );
2560 return QSslConfiguration::systemCaCertificates();
2565 QMutexLocker locker( mMutex.get() );
2566 QList<QSslCertificate> certs;
2567 QList<QSslCertificate> filecerts;
2569 if ( cafileval.isNull() )
2573 if ( allowinvalid.isNull() )
2576 QString cafile( cafileval.toString() );
2577 if ( !cafile.isEmpty() && QFile::exists( cafile ) )
2582 for (
const auto &cert : qgis::as_const( filecerts ) )
2584 if ( !allowinvalid.toBool() && ( cert.isBlacklisted()
2586 || cert.expiryDate() <= QDateTime::currentDateTime()
2587 || cert.effectiveDate() > QDateTime::currentDateTime() ) )
2602 QMutexLocker locker( mMutex.get() );
2603 QList<QSslCertificate> certs;
2606 query.prepare( QStringLiteral(
"SELECT id, cert FROM %1" ).arg( authDbAuthoritiesTable() ) );
2608 if ( !authDbQuery( &query ) )
2611 if ( query.isActive() && query.isSelect() )
2613 while ( query.next() )
2615 certs << QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
2624 QMutexLocker locker( mMutex.get() );
2630 QMutexLocker locker( mMutex.get() );
2631 mCaCertsCache.clear();
2637 bool res = !mCaCertsCache.isEmpty();
2639 QgsDebugMsg( QStringLiteral(
"Rebuild of CA certs cache FAILED" ) );
2645 QMutexLocker locker( mMutex.get() );
2646 if ( cert.isNull() )
2648 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2658 QgsDebugMsg( QStringLiteral(
"Passed policy was default, all cert records in database were removed for id: %1" ).arg(
id ) );
2663 query.prepare( QStringLiteral(
"INSERT INTO %1 (id, policy) "
2664 "VALUES (:id, :policy)" ).arg( authDbTrustTable() ) );
2666 query.bindValue( QStringLiteral(
":id" ),
id );
2667 query.bindValue( QStringLiteral(
":policy" ),
static_cast< int >( policy ) );
2669 if ( !authDbStartTransaction() )
2672 if ( !authDbQuery( &query ) )
2675 if ( !authDbCommit() )
2678 QgsDebugMsgLevel( QStringLiteral(
"Store certificate trust policy SUCCESS for id: %1" ).arg(
id ), 2 );
2684 QMutexLocker locker( mMutex.get() );
2685 if ( cert.isNull() )
2687 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2694 query.prepare( QStringLiteral(
"SELECT policy FROM %1 "
2695 "WHERE id = :id" ).arg( authDbTrustTable() ) );
2697 query.bindValue( QStringLiteral(
":id" ),
id );
2699 if ( !authDbQuery( &query ) )
2703 if ( query.isActive() && query.isSelect() )
2705 if ( query.first() )
2708 QgsDebugMsgLevel( QStringLiteral(
"Authentication cert trust policy retrieved for id: %1" ).arg(
id ), 2 );
2712 QgsDebugMsg( QStringLiteral(
"Select contains more than one cert trust policy for id: %1" ).arg(
id ) );
2722 QMutexLocker locker( mMutex.get() );
2723 if ( certs.empty() )
2725 QgsDebugMsg( QStringLiteral(
"Passed certificate list has no certs" ) );
2729 for (
const auto &cert : certs )
2739 QMutexLocker locker( mMutex.get() );
2740 if ( cert.isNull() )
2742 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2750 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE id = :id" ).arg( authDbTrustTable() ) );
2752 query.bindValue( QStringLiteral(
":id" ),
id );
2754 if ( !authDbStartTransaction() )
2757 if ( !authDbQuery( &query ) )
2760 if ( !authDbCommit() )
2763 QgsDebugMsgLevel( QStringLiteral(
"REMOVED cert trust policy for id: %1" ).arg(
id ), 2 );
2770 QMutexLocker locker( mMutex.get() );
2771 if ( cert.isNull() )
2781 if ( trustedids.contains(
id ) )
2785 else if ( untrustedids.contains(
id ) )
2800 return storeAuthSetting( QStringLiteral(
"certdefaulttrust" ),
static_cast< int >( policy ) );
2805 QMutexLocker locker( mMutex.get() );
2806 QVariant policy(
authSetting( QStringLiteral(
"certdefaulttrust" ) ) );
2807 if ( policy.isNull() )
2816 QMutexLocker locker( mMutex.get() );
2817 mCertTrustCache.clear();
2820 query.prepare( QStringLiteral(
"SELECT id, policy FROM %1" ).arg( authDbTrustTable() ) );
2822 if ( !authDbQuery( &query ) )
2824 QgsDebugMsg( QStringLiteral(
"Rebuild of cert trust policy cache FAILED" ) );
2828 if ( query.isActive() && query.isSelect() )
2830 while ( query.next() )
2832 QString
id = query.value( 0 ).toString();
2836 if ( mCertTrustCache.contains( policy ) )
2838 ids = mCertTrustCache.value( policy );
2840 mCertTrustCache.insert( policy, ids <<
id );
2844 QgsDebugMsgLevel( QStringLiteral(
"Rebuild of cert trust policy cache SUCCEEDED" ), 2 );
2850 QMutexLocker locker( mMutex.get() );
2854 const QList<QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> > &certpairs( mCaCertsCache.values() );
2856 QList<QSslCertificate> trustedcerts;
2857 for (
int i = 0; i < certpairs.size(); ++i )
2859 QSslCertificate cert( certpairs.at( i ).second );
2861 if ( trustedids.contains( certid ) )
2864 trustedcerts.append( cert );
2870 trustedcerts.append( cert );
2875 QSslConfiguration sslconfig( QSslConfiguration::defaultConfiguration() );
2876 sslconfig.setCaCertificates( trustedcerts );
2877 QSslConfiguration::setDefaultConfiguration( sslconfig );
2879 return trustedcerts;
2884 QMutexLocker locker( mMutex.get() );
2885 if ( trustedCAs.isEmpty() )
2887 if ( mTrustedCaCertsCache.isEmpty() )
2894 const QList<QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> > &certpairs( mCaCertsCache.values() );
2896 QList<QSslCertificate> untrustedCAs;
2897 for (
int i = 0; i < certpairs.size(); ++i )
2899 QSslCertificate cert( certpairs.at( i ).second );
2900 if ( !trustedCAs.contains( cert ) )
2902 untrustedCAs.append( cert );
2905 return untrustedCAs;
2910 QMutexLocker locker( mMutex.get() );
2912 QgsDebugMsgLevel( QStringLiteral(
"Rebuilt trusted cert authorities cache" ), 2 );
2919 QMutexLocker locker( mMutex.get() );
2925 QMutexLocker locker( mMutex.get() );
2928 return passwordHelperWrite( mMasterPass );
2944 for (
const auto &authcfg : ids )
2962 void QgsAuthManager::writeToConsole(
const QString &message,
2976 msg += QLatin1String(
"WARNING: " );
2979 msg += QLatin1String(
"ERROR: " );
2986 QTextStream out( stdout, QIODevice::WriteOnly );
2987 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
2990 out << msg << Qt::endl;
2994 void QgsAuthManager::tryToStartDbErase()
2996 ++mScheduledDbEraseRequestCount;
2998 int trycutoff = 90 / ( mScheduledDbEraseRequestWait ? mScheduledDbEraseRequestWait : 3 );
2999 if ( mScheduledDbEraseRequestCount >= trycutoff )
3002 QgsDebugMsgLevel( QStringLiteral(
"authDatabaseEraseRequest emitting/scheduling canceled" ), 2 );
3007 QgsDebugMsgLevel( QStringLiteral(
"authDatabaseEraseRequest attempt (%1 of %2)" )
3008 .arg( mScheduledDbEraseRequestCount ).arg( trycutoff ), 2 );
3014 mScheduledDbEraseRequestEmitted =
true;
3019 QgsDebugMsgLevel( QStringLiteral(
"authDatabaseEraseRequest emitted" ), 2 );
3022 QgsDebugMsgLevel( QStringLiteral(
"authDatabaseEraseRequest emit skipped" ), 2 );
3028 QMutexLocker locker( mMutex.get() );
3029 QMapIterator<QThread *, QMetaObject::Connection> iterator( mConnectedThreads );
3030 while ( iterator.hasNext() )
3033 iterator.key()->disconnect( iterator.value() );
3040 qDeleteAll( mAuthMethods );
3043 if ( authConn.isValid() && authConn.isOpen() )
3046 delete mScheduledDbEraseTimer;
3047 mScheduledDbEraseTimer =
nullptr;
3048 QSqlDatabase::removeDatabase( QStringLiteral(
"authentication.configs" ) );
3052 QString QgsAuthManager::passwordHelperName()
const
3054 return tr(
"Password Helper" );
3058 void QgsAuthManager::passwordHelperLog(
const QString &msg )
const
3070 QKeychain::DeletePasswordJob job( AUTH_PASSWORD_HELPER_FOLDER_NAME );
3072 job.setInsecureFallback( settings.
value( QStringLiteral(
"password_helper_insecure_fallback" ),
false, QgsSettings::Section::Auth ).toBool() );
3073 job.setAutoDelete(
false );
3074 job.setKey( AUTH_PASSWORD_HELPER_KEY_NAME );
3076 connect( &job, &QKeychain::Job::finished, &loop, &QEventLoop::quit );
3081 mPasswordHelperErrorCode = job.error();
3082 mPasswordHelperErrorMessage = tr(
"Delete password failed: %1." ).arg( job.errorString() );
3093 passwordHelperProcessError();
3097 QString QgsAuthManager::passwordHelperRead()
3102 QKeychain::ReadPasswordJob job( AUTH_PASSWORD_HELPER_FOLDER_NAME );
3104 job.setInsecureFallback( settings.
value( QStringLiteral(
"password_helper_insecure_fallback" ),
false, QgsSettings::Section::Auth ).toBool() );
3105 job.setAutoDelete(
false );
3106 job.setKey( AUTH_PASSWORD_HELPER_KEY_NAME );
3108 connect( &job, &QKeychain::Job::finished, &loop, &QEventLoop::quit );
3113 mPasswordHelperErrorCode = job.error();
3120 password = job.textData();
3122 if ( password.isEmpty() )
3124 mPasswordHelperErrorCode = QKeychain::EntryNotFound;
3135 passwordHelperProcessError();
3139 bool QgsAuthManager::passwordHelperWrite(
const QString &password )
3141 Q_ASSERT( !password.isEmpty() );
3144 QKeychain::WritePasswordJob job( AUTH_PASSWORD_HELPER_FOLDER_NAME );
3146 job.setInsecureFallback( settings.
value( QStringLiteral(
"password_helper_insecure_fallback" ),
false, QgsSettings::Section::Auth ).toBool() );
3147 job.setAutoDelete(
false );
3148 job.setKey( AUTH_PASSWORD_HELPER_KEY_NAME );
3149 job.setTextData( password );
3151 connect( &job, &QKeychain::Job::finished, &loop, &QEventLoop::quit );
3156 mPasswordHelperErrorCode = job.error();
3164 passwordHelperClearErrors();
3169 passwordHelperProcessError();
3177 return settings.
value( QStringLiteral(
"use_password_helper" ),
true, QgsSettings::Section::Auth ).toBool();
3183 settings.
setValue( QStringLiteral(
"use_password_helper" ), enabled, QgsSettings::Section::Auth );
3184 emit
messageOut( enabled ? tr(
"Your %1 will be <b>used from now</b> on to store and retrieve the master password." )
3186 tr(
"Your %1 will <b>not be used anymore</b> to store and retrieve the master password." )
3194 return settings.
value( QStringLiteral(
"password_helper_logging" ),
false, QgsSettings::Section::Auth ).toBool();
3200 settings.
setValue( QStringLiteral(
"password_helper_logging" ), enabled, QgsSettings::Section::Auth );
3203 void QgsAuthManager::passwordHelperClearErrors()
3205 mPasswordHelperErrorCode = QKeychain::NoError;
3206 mPasswordHelperErrorMessage.clear();
3209 void QgsAuthManager::passwordHelperProcessError()
3211 if ( mPasswordHelperErrorCode == QKeychain::AccessDenied ||
3212 mPasswordHelperErrorCode == QKeychain::AccessDeniedByUser ||
3213 mPasswordHelperErrorCode == QKeychain::NoBackendAvailable ||
3214 mPasswordHelperErrorCode == QKeychain::NotImplemented )
3220 mPasswordHelperErrorMessage = tr(
"There was an error and integration with your %1 system has been disabled. "
3221 "You can re-enable it at any time through the \"Utilities\" menu "
3222 "in the Authentication pane of the options dialog. %2" )
3225 if ( mPasswordHelperErrorCode != QKeychain::NoError )
3231 passwordHelperClearErrors();
3235 bool QgsAuthManager::masterPasswordInput()
3241 bool storedPasswordIsValid =
false;
3247 pass = passwordHelperRead();
3248 if ( ! pass.isEmpty() && ( mPasswordHelperErrorCode == QKeychain::NoError ) )
3254 storedPasswordIsValid =
true;
3270 if ( ok && !pass.isEmpty() && mMasterPass != pass )
3275 if ( passwordHelperWrite( pass ) )
3289 bool QgsAuthManager::masterPasswordRowsInDb(
int *rows )
const
3295 query.prepare( QStringLiteral(
"SELECT Count(*) FROM %1" ).arg( authDbPassTable() ) );
3297 bool ok = authDbQuery( &query );
3298 if ( query.first() )
3300 *rows = query.value( 0 ).toInt();
3312 if ( !masterPasswordRowsInDb( &rows ) )
3314 const char *err = QT_TR_NOOP(
"Master password: FAILED to access database" );
3320 return ( rows == 1 );
3323 bool QgsAuthManager::masterPasswordCheckAgainstDb(
const QString &compare )
const
3331 query.prepare( QStringLiteral(
"SELECT salt, hash FROM %1" ).arg( authDbPassTable() ) );
3332 if ( !authDbQuery( &query ) )
3335 if ( !query.first() )
3338 QString salt = query.value( 0 ).toString();
3339 QString hash = query.value( 1 ).toString();
3344 bool QgsAuthManager::masterPasswordStoreInDb()
const
3349 QString salt, hash, civ;
3353 query.prepare( QStringLiteral(
"INSERT INTO %1 (salt, hash, civ) VALUES (:salt, :hash, :civ)" ).arg( authDbPassTable() ) );
3355 query.bindValue( QStringLiteral(
":salt" ), salt );
3356 query.bindValue( QStringLiteral(
":hash" ), hash );
3357 query.bindValue( QStringLiteral(
":civ" ), civ );
3359 if ( !authDbStartTransaction() )
3362 if ( !authDbQuery( &query ) )
3365 if ( !authDbCommit() )
3371 bool QgsAuthManager::masterPasswordClearDb()
3377 query.prepare( QStringLiteral(
"DELETE FROM %1" ).arg( authDbPassTable() ) );
3378 bool res = authDbTransactionQuery( &query );
3384 const QString QgsAuthManager::masterPasswordCiv()
const
3390 query.prepare( QStringLiteral(
"SELECT civ FROM %1" ).arg( authDbPassTable() ) );
3391 if ( !authDbQuery( &query ) )
3394 if ( !query.first() )
3397 return query.value( 0 ).toString();
3402 QStringList configids = QStringList();
3410 if ( !authDbQuery( &query ) )
3415 if ( query.isActive() )
3417 while ( query.next() )
3419 configids << query.value( 0 ).toString();
3425 bool QgsAuthManager::verifyPasswordCanDecryptConfigs()
const
3436 if ( !authDbQuery( &query ) )
3439 if ( !query.isActive() || !query.isSelect() )
3441 QgsDebugMsg( QStringLiteral(
"Verify password can decrypt configs FAILED, query not active or a select operation" ) );
3446 while ( query.next() )
3449 QString configstring(
QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 1 ).toString() ) );
3450 if ( configstring.isEmpty() )
3452 QgsDebugMsg( QStringLiteral(
"Verify password can decrypt configs FAILED, could not decrypt a config (id: %1)" )
3453 .arg( query.value( 0 ).toString() ) );
3458 QgsDebugMsgLevel( QStringLiteral(
"Verify password can decrypt configs SUCCESS (checked %1 configs)" ).arg( checked ), 2 );
3462 bool QgsAuthManager::reencryptAllAuthenticationConfigs(
const QString &prevpass,
const QString &prevciv )
3469 for (
const auto &configid : ids )
3471 res = res && reencryptAuthenticationConfig( configid, prevpass, prevciv );
3476 bool QgsAuthManager::reencryptAuthenticationConfig(
const QString &authcfg,
const QString &prevpass,
const QString &prevciv )
3485 query.prepare( QStringLiteral(
"SELECT config FROM %1 "
3488 query.bindValue( QStringLiteral(
":id" ), authcfg );
3490 if ( !authDbQuery( &query ) )
3493 if ( !query.isActive() || !query.isSelect() )
3495 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, query not active or a select operation for authcfg: %2" ).arg( authcfg ) );
3499 if ( query.first() )
3505 QgsDebugMsg( QStringLiteral(
"Select contains more than one for authcfg: %1" ).arg( authcfg ) );
3512 query.prepare( QStringLiteral(
"UPDATE %1 "
3513 "SET config = :config "
3516 query.bindValue( QStringLiteral(
":id" ), authcfg );
3517 query.bindValue( QStringLiteral(
":config" ),
QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
3519 if ( !authDbStartTransaction() )
3522 if ( !authDbQuery( &query ) )
3525 if ( !authDbCommit() )
3528 QgsDebugMsgLevel( QStringLiteral(
"Reencrypt SUCCESS for authcfg: %2" ).arg( authcfg ), 2 );
3533 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, could not find in db authcfg: %2" ).arg( authcfg ) );
3538 bool QgsAuthManager::reencryptAllAuthenticationSettings(
const QString &prevpass,
const QString &prevciv )
3541 Q_UNUSED( prevpass )
3554 QStringList encryptedsettings;
3555 encryptedsettings <<
"";
3557 for (
const auto & sett, qgis::as_const( encryptedsettings ) )
3564 QSqlQuery query( authDbConnection() );
3566 query.prepare( QStringLiteral(
"SELECT value FROM %1 "
3567 "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
3569 query.bindValue(
":setting", sett );
3571 if ( !authDbQuery( &query ) )
3574 if ( !query.isActive() || !query.isSelect() )
3576 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, query not active or a select operation for setting: %2" ).arg( sett ) );
3580 if ( query.first() )
3586 query.prepare( QStringLiteral(
"UPDATE %1 "
3587 "SET value = :value "
3588 "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
3590 query.bindValue(
":setting", sett );
3593 if ( !authDbStartTransaction() )
3596 if ( !authDbQuery( &query ) )
3599 if ( !authDbCommit() )
3602 QgsDebugMsg( QStringLiteral(
"Reencrypt SUCCESS for setting: %2" ).arg( sett ) );
3607 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, could not find in db setting: %2" ).arg( sett ) );
3613 QgsDebugMsg( QStringLiteral(
"Select contains more than one for setting: %1" ).arg( sett ) );
3624 bool QgsAuthManager::reencryptAllAuthenticationIdentities(
const QString &prevpass,
const QString &prevciv )
3631 for (
const auto &identid : ids )
3633 res = res && reencryptAuthenticationIdentity( identid, prevpass, prevciv );
3638 bool QgsAuthManager::reencryptAuthenticationIdentity(
3639 const QString &identid,
3640 const QString &prevpass,
3641 const QString &prevciv )
3650 query.prepare( QStringLiteral(
"SELECT key FROM %1 "
3651 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
3653 query.bindValue( QStringLiteral(
":id" ), identid );
3655 if ( !authDbQuery( &query ) )
3658 if ( !query.isActive() || !query.isSelect() )
3660 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, query not active or a select operation for identity id: %2" ).arg( identid ) );
3664 if ( query.first() )
3670 QgsDebugMsg( QStringLiteral(
"Select contains more than one for identity id: %1" ).arg( identid ) );
3677 query.prepare( QStringLiteral(
"UPDATE %1 "
3679 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
3681 query.bindValue( QStringLiteral(
":id" ), identid );
3682 query.bindValue( QStringLiteral(
":key" ),
QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), keystring ) );
3684 if ( !authDbStartTransaction() )
3687 if ( !authDbQuery( &query ) )
3690 if ( !authDbCommit() )
3693 QgsDebugMsgLevel( QStringLiteral(
"Reencrypt SUCCESS for identity id: %2" ).arg( identid ), 2 );
3698 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, could not find in db identity id: %2" ).arg( identid ) );
3703 bool QgsAuthManager::authDbOpen()
const
3709 if ( !authdb.isOpen() )
3711 if ( !authdb.open() )
3713 QgsDebugMsg( QStringLiteral(
"Unable to establish database connection\nDatabase: %1\nDriver error: %2\nDatabase error: %3" )
3715 authdb.lastError().driverText(),
3716 authdb.lastError().databaseText() ) );
3724 bool QgsAuthManager::authDbQuery( QSqlQuery *query )
const
3729 query->setForwardOnly(
true );
3730 if ( !query->exec() )
3732 const char *err = QT_TR_NOOP(
"Auth db query exec() FAILED" );
3738 if ( query->lastError().isValid() )
3740 QgsDebugMsg( QStringLiteral(
"Auth db query FAILED: %1\nError: %2" )
3741 .arg( query->executedQuery(),
3742 query->lastError().text() ) );
3750 bool QgsAuthManager::authDbStartTransaction()
const
3757 const char *err = QT_TR_NOOP(
"Auth db FAILED to start transaction" );
3766 bool QgsAuthManager::authDbCommit()
const
3773 const char *err = QT_TR_NOOP(
"Auth db FAILED to rollback changes" );
3783 bool QgsAuthManager::authDbTransactionQuery( QSqlQuery *query )
const
3790 const char *err = QT_TR_NOOP(
"Auth db FAILED to start transaction" );
3796 bool ok = authDbQuery( query );
3800 const char *err = QT_TR_NOOP(
"Auth db FAILED to rollback changes" );
3812 for (
const auto &cert : certs )
3815 QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate>( source, cert ) );
static QString sslErrorEnumString(QSslError::SslError errenum)
Gets short strings describing an SSL error.
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Gets the sha1 hash for certificate.
CertTrustPolicy
Type of certificate trust policy.
static QMap< QString, QSslCertificate > mapDigestToCerts(const QList< QSslCertificate > &certs)
Map certificate sha1 to certificate as simple cache.
static QByteArray certsToPemText(const QList< QSslCertificate > &certs)
certsToPemText dump a list of QSslCertificates to PEM text
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 bool certificateIsAuthorityOrIssuer(const QSslCertificate &cert)
Gets whether a certificate is an Authority or can at least sign other certificates.
CaCertSource
Type of CA certificate source.
Configuration container for SSL server connection exceptions or overrides.
void setSslCertificate(const QSslCertificate &cert)
Sets server certificate object.
void setSslHostPort(const QString &hostport)
Sets server host:port string.
const QList< QSslError::SslError > sslIgnoredErrorEnums() const
SSL server errors (as enum list) to ignore in connections.
bool isNull() const
Whether configuration is null (missing components)
const QSslCertificate sslCertificate() const
Server certificate object.
const QString sslHostPort() const
Server host:port string.
const QString configString() const
Configuration as a concatenated string.
void loadConfigString(const QString &config=QString())
Load concatenated string into configuration, e.g. from auth database.
static void passwordKeyHash(const QString &pass, QString *salt, QString *hash, QString *cipheriv=nullptr)
Generate SHA256 hash for master password, with iterations and salt.
static const QString encrypt(const QString &pass, const QString &cipheriv, const QString &text)
Encrypt data using master password.
static bool verifyPasswordKeyHash(const QString &pass, const QString &salt, const QString &hash, QString *hashderived=nullptr)
Verify existing master password hash to a re-generated one.
static const QString decrypt(const QString &pass, const QString &cipheriv, const QString &text)
Decrypt data using master password.
Singleton offering an interface to manage the authentication configuration database and to utilize co...
bool storeAuthSetting(const QString &key, const QVariant &value, bool encrypt=false)
Store an authentication setting (stored as string via QVariant( value ).toString() )
const QString authDatabaseServersTable() const
Name of the authentication database table that stores server exceptions/configs.
bool setDefaultCertTrustPolicy(QgsAuthCertUtils::CertTrustPolicy policy)
Sets the default certificate trust policy preferred by user.
void clearAllCachedConfigs()
Clear all authentication configs from authentication method caches.
const QSslCertificate certIdentity(const QString &id)
certIdentity get a certificate identity by id (sha hash)
const QStringList certIdentityBundleToPem(const QString &id)
certIdentityBundleToPem get a certificate identity bundle by id (sha hash) returned as PEM text
bool updateIgnoredSslErrorsCache(const QString &shahostport, const QList< QSslError > &errors)
Update ignored SSL error cache with possible ignored SSL errors, using sha:host:port key.
bool verifyMasterPassword(const QString &compare=QString())
Verify the supplied master password against any existing hash in authentication database.
bool updateIgnoredSslErrorsCacheFromConfig(const QgsAuthConfigSslServer &config)
Update ignored SSL error cache with possible ignored SSL errors, using server config.
MessageLevel
Message log level (mirrors that of QgsMessageLog, so it can also output there)
const QString disabledMessage() const
Standard message for when QCA's qca-ossl plugin is missing and system is disabled.
QgsAuthMethod * configAuthMethod(const QString &authcfg)
Gets authentication method from the config/provider cache.
void messageOut(const QString &message, const QString &tag=QgsAuthManager::AUTH_MAN_TAG, QgsAuthManager::MessageLevel level=QgsAuthManager::INFO) const
Custom logging signal to relay to console output and QgsMessageLog.
bool storeCertIdentity(const QSslCertificate &cert, const QSslKey &key)
Store a certificate identity.
QgsAuthMethodsMap authMethodsMap(const QString &dataprovider=QString())
Gets available authentication methods mapped to their key.
QWidget * authMethodEditWidget(const QString &authMethodKey, QWidget *parent)
Gets authentication method edit widget via its key.
bool rebuildIgnoredSslErrorCache()
Rebuild ignoredSSL error cache.
bool initSslCaches()
Initialize various SSL authentication caches.
bool masterPasswordSame(const QString &pass) const
Check whether supplied password is the same as the one already set.
const QList< QSslCertificate > extraFileCAs()
extraFileCAs extra file-based certificate authorities
bool removeAuthSetting(const QString &key)
Remove an authentication setting.
bool storeCertTrustPolicy(const QSslCertificate &cert, QgsAuthCertUtils::CertTrustPolicy policy)
Store user trust value for a certificate.
bool rebuildCaCertsCache()
Rebuild certificate authority cache.
bool scheduledAuthDatabaseErase()
Whether there is a scheduled opitonal erase of authentication database.
bool eraseAuthenticationDatabase(bool backup, QString *backuppath=nullptr)
Erase all rows from all tables in authentication database.
bool init(const QString &pluginPath=QString(), const QString &authDatabasePath=QString())
init initialize QCA, prioritize qca-ossl plugin and optionally set up the authentication database
void authDatabaseChanged()
Emitted when the authentication db is significantly changed, e.g. large record removal,...
void setPasswordHelperEnabled(bool enabled)
Password helper enabled setter.
void setScheduledAuthDatabaseErase(bool scheduleErase)
Schedule an optional erase of authentication database, starting when mutex is lockable.
void passwordHelperMessageOut(const QString &message, const QString &tag=QgsAuthManager::AUTH_MAN_TAG, QgsAuthManager::MessageLevel level=QgsAuthManager::INFO)
Custom logging signal to inform the user about master password <-> password manager interactions.
const QList< QgsAuthConfigSslServer > sslCertCustomConfigs()
sslCertCustomConfigs get SSL certificate custom configs
const QList< QSslCertificate > untrustedCaCerts(QList< QSslCertificate > trustedCAs=QList< QSslCertificate >())
untrustedCaCerts get list of untrusted certificate authorities
const QString uniqueConfigId() const
Gets a unique generated 7-character string to assign to as config id.
const QPair< QSslCertificate, QSslKey > certIdentityBundle(const QString &id)
Gets a certificate identity bundle by id (sha hash).
bool isDisabled() const
Whether QCA has the qca-ossl plugin, which a base run-time requirement.
QVariant authSetting(const QString &key, const QVariant &defaultValue=QVariant(), bool decrypt=false)
authSetting get an authentication setting (retrieved as string and returned as QVariant( QString ))
static const QString AUTH_MAN_TAG
The display name of the Authentication Manager.
QgsAuthCertUtils::CertTrustPolicy defaultCertTrustPolicy()
Gets the default certificate trust policy preferred by user.
const QByteArray trustedCaCertsPemText()
trustedCaCertsPemText get concatenated string of all trusted CA certificates
bool removeAllAuthenticationConfigs()
Clear all authentication configs from table in database and from provider caches.
QgsAuthCertUtils::CertTrustPolicy certificateTrustPolicy(const QSslCertificate &cert)
certificateTrustPolicy get trust policy for a particular certificate cert
bool rebuildCertTrustCache()
Rebuild certificate authority cache.
const QString authenticationDatabasePath() const
The standard authentication database file in ~/.qgis3/ or defined location.
const QList< QSslCertificate > systemRootCAs()
systemRootCAs get root system certificate authorities
bool removeCertAuthority(const QSslCertificate &cert)
Remove a certificate authority.
const QList< QSslCertificate > trustedCaCerts(bool includeinvalid=false)
trustedCaCerts get list of all trusted CA certificates
bool existsCertAuthority(const QSslCertificate &cert)
Check if a certificate authority exists.
bool storeAuthenticationConfig(QgsAuthMethodConfig &mconfig)
Store an authentication config in the database.
const QMap< QString, QSslCertificate > mappedDatabaseCAs()
mappedDatabaseCAs get sha1-mapped database-stored certificate authorities
bool configIdUnique(const QString &id) const
Verify if provided authentication id is unique.
QStringList configIds() const
Gets list of authentication ids from database.
QString authManTag() const
Simple text tag describing authentication system for message logs.
bool loadAuthenticationConfig(const QString &authcfg, QgsAuthMethodConfig &mconfig, bool full=false)
Load an authentication config from the database into subclass.
QgsAuthCertUtils::CertTrustPolicy certTrustPolicy(const QSslCertificate &cert)
certTrustPolicy get whether certificate cert is trusted by user
bool masterPasswordHashInDatabase() const
Verify a password hash existing in authentication database.
bool updateNetworkProxy(QNetworkProxy &proxy, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkProxy with an authentication config.
const QSslCertificate certAuthority(const QString &id)
Gets a certificate authority by id (sha hash)
void passwordHelperSuccess()
Signals emitted on password helper success, mainly used in the tests to exit main application loop.
bool registerCoreAuthMethods()
Instantiate and register existing C++ core authentication methods from plugins.
bool passwordHelperDelete()
Delete master password from wallet.
~QgsAuthManager() override
void dumpIgnoredSslErrorsCache_()
Utility function to dump the cache for debug purposes.
const QList< QSslCertificate > databaseCAs()
databaseCAs get database-stored certificate authorities
bool backupAuthenticationDatabase(QString *backuppath=nullptr)
Close connection to current authentication database and back it up.
void authDatabaseEraseRequested()
Emitted when a user has indicated they may want to erase the authentication db.
void passwordHelperFailure()
Signals emitted on password helper failure, mainly used in the tests to exit main application loop.
bool existsSslCertCustomConfig(const QString &id, const QString &hostport)
Check if SSL certificate custom config exists.
bool existsAuthSetting(const QString &key)
Check if an authentication setting exists.
void clearCachedConfig(const QString &authcfg)
Clear an authentication config from its associated authentication method cache.
void clearMasterPassword()
Clear supplied master password.
bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkRequest with an authentication config.
const QList< QSslCertificate > certIdentities()
certIdentities get certificate identities
bool storeCertAuthority(const QSslCertificate &cert)
Store a certificate authority.
QStringList certIdentityIds() const
certIdentityIds get list of certificate identity ids from database
bool removeCertTrustPolicies(const QList< QSslCertificate > &certs)
Remove a group certificate authorities.
QgsAuthMethod * authMethod(const QString &authMethodKey)
Gets authentication method from the config/provider cache via its key.
bool updateDataSourceUriItems(QStringList &connectionItems, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QgsDataSourceUri with an authentication config.
static QgsAuthManager * instance()
Enforce singleton pattern.
QSqlDatabase authDatabaseConnection() const
Sets up the application instance of the authentication database connection.
void updateConfigAuthMethods()
Sync the confg/authentication method cache with what is in database.
bool storeSslCertCustomConfig(const QgsAuthConfigSslServer &config)
Store an SSL certificate custom config.
void setPasswordHelperLoggingEnabled(bool enabled)
Password helper logging enabled setter.
const QgsAuthConfigSslServer sslCertCustomConfigByHost(const QString &hostport)
sslCertCustomConfigByHost get an SSL certificate custom config by hostport (host:port)
bool updateAuthenticationConfig(const QgsAuthMethodConfig &config)
Update an authentication config in the database.
const QString authDatabaseConfigTable() const
Name of the authentication database table that stores configs.
bool existsCertIdentity(const QString &id)
Check if a certificate identity exists.
bool resetMasterPassword(const QString &newpass, const QString &oldpass, bool keepbackup, QString *backuppath=nullptr)
Reset the master password to a new one, then re-encrypt all previous configs in a new database file,...
QStringList authMethodsKeys(const QString &dataprovider=QString())
Gets keys of supported authentication methods.
bool passwordHelperSync()
Store the password manager into the wallet.
bool masterPasswordIsSet() const
Whether master password has be input and verified, i.e. authentication database is accessible.
bool passwordHelperEnabled() const
Password helper enabled getter.
bool passwordHelperLoggingEnabled() const
Password helper logging enabled getter.
void masterPasswordVerified(bool verified)
Emitted when a password has been verify (or not)
bool setMasterPassword(bool verify=false)
Main call to initially set or continually check master password is set.
bool storeCertAuthorities(const QList< QSslCertificate > &certs)
Store multiple certificate authorities.
bool removeSslCertCustomConfig(const QString &id, const QString &hostport)
Remove an SSL certificate custom config.
static const QString AUTH_PASSWORD_HELPER_DISPLAY_NAME
The display name of the password helper (platform dependent)
bool updateNetworkReply(QNetworkReply *reply, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkReply with an authentication config (used to skip known SSL errors,...
bool rebuildTrustedCaCertsCache()
Rebuild trusted certificate authorities cache.
bool removeAuthenticationConfig(const QString &authcfg)
Remove an authentication config in the database.
bool removeCertTrustPolicy(const QSslCertificate &cert)
Remove a certificate authority.
bool hasConfigId(const QString &txt) const
Returns whether a string includes an authcfg ID token.
QgsAuthMethod::Expansions supportedAuthMethodExpansions(const QString &authcfg)
Gets supported authentication method expansion(s), e.g.
const QgsAuthConfigSslServer sslCertCustomConfig(const QString &id, const QString &hostport)
sslCertCustomConfig get an SSL certificate custom config by id (sha hash) and hostport (host:port)
QgsAuthMethodConfigsMap availableAuthMethodConfigs(const QString &dataprovider=QString())
Gets mapping of authentication config ids and their base configs (not decrypted data)
bool removeCertIdentity(const QString &id)
Remove a certificate identity.
QString configAuthMethodKey(const QString &authcfg) const
Gets key of authentication method associated with config ID.
const QList< QSslCertificate > trustedCaCertsCache()
trustedCaCertsCache cache of trusted certificate authorities, ready for network connections
Configuration storage class for authentication method configurations.
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.
void setName(const QString &name)
Sets name of configuration.
void setVersion(int version)
Sets version of the configuration.
const QString configString() const
The extended configuration, as stored and retrieved from the authentication database.
const QString name() const
Gets name of configuration.
const QString id() const
Gets 'authcfg' 7-character alphanumeric ID of the config.
void loadConfigString(const QString &configstr)
Load existing extended configuration.
int version() const
Gets version of the configuration.
void setMethod(const QString &method)
void setUri(const QString &uri)
void setId(const QString &id)
Sets auth config ID.
A registry / canonical manager of authentication methods.
static QgsAuthMethodRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QWidget * editWidget(const QString &authMethodKey, QWidget *parent=nullptr)
Returns the GUI edit widget associated with the auth method.
QStringList authMethodList() const
Returns list of available auth methods by their keys.
Abstract base class for authentication method plugins.
virtual bool updateNetworkProxy(QNetworkProxy &proxy, const QString &authcfg, const QString &dataprovider=QString())
Update proxy settings with authentication components.
virtual bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Update a network request with authentication components.
QgsAuthMethod::Expansions supportedExpansions() const
Flags that represent the update points (where authentication configurations are expanded) supported b...
virtual void clearCachedConfig(const QString &authcfg)=0
Clear any cached configuration.
virtual void updateMethodConfig(QgsAuthMethodConfig &mconfig)=0
Update an authentication configuration in place.
virtual bool updateNetworkReply(QNetworkReply *reply, const QString &authcfg, const QString &dataprovider=QString())
Update a network reply with authentication components.
virtual bool updateDataSourceUriItems(QStringList &connectionItems, const QString &authcfg, const QString &dataprovider=QString())
Update data source connection items with authentication components.
static QgsCredentials * instance()
retrieves instance
bool getMasterPassword(QString &password, bool stored=false)
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Scoped object for logging of the runtime for a single operation or group of operations.
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.
QHash< QString, QgsAuthMethodConfig > QgsAuthMethodConfigsMap
QHash< QString, QgsAuthMethod * > QgsAuthMethodsMap
#define QgsDebugMsgLevel(str, level)