23 #include <QMutexLocker> 26 #include <QSqlDatabase> 29 #include <QTextStream> 38 #include <QSslConfiguration> 58 const QString QgsAuthManager::AUTH_CONFIG_TABLE = QStringLiteral(
"auth_configs" );
59 const QString QgsAuthManager::AUTH_PASS_TABLE = QStringLiteral(
"auth_pass" );
60 const QString QgsAuthManager::AUTH_SETTINGS_TABLE = QStringLiteral(
"auth_settings" );
61 const QString QgsAuthManager::AUTH_IDENTITIES_TABLE = QStringLiteral(
"auth_identities" );
62 const QString QgsAuthManager::AUTH_SERVERS_TABLE = QStringLiteral(
"auth_servers" );
63 const QString QgsAuthManager::AUTH_AUTHORITIES_TABLE = QStringLiteral(
"auth_authorities" );
64 const QString QgsAuthManager::AUTH_TRUST_TABLE = QStringLiteral(
"auth_trust" );
66 const QString QgsAuthManager::AUTH_CFG_REGEX = QStringLiteral(
"authcfg=([a-z]|[A-Z]|[0-9]){7}" );
69 const QLatin1String QgsAuthManager::AUTH_PASSWORD_HELPER_KEY_NAME(
"QGIS-Master-Password" );
70 const QLatin1String QgsAuthManager::AUTH_PASSWORD_HELPER_FOLDER_NAME(
"QGIS" );
74 static const QString sDescription = QObject::tr(
"Master Password <-> KeyChain storage plugin. Store and retrieve your master password in your KeyChain" );
75 #elif defined(Q_OS_WIN) 77 static const QString sDescription = QObject::tr(
"Master Password <-> Password Manager storage plugin. Store and retrieve your master password in your Password Manager" );
78 #elif defined(Q_OS_LINUX) 80 static const QString sDescription = QObject::tr(
"Master Password <-> Wallet/KeyRing storage plugin. Store and retrieve your master password in your Wallet/KeyRing" );
83 static const QString sDescription = QObject::tr(
"Master Password <-> KeyChain storage plugin. Store and retrieve your master password in your Wallet/KeyChain/Password Manager" );
93 QMutexLocker locker( &sMutex );
105 mMutex =
new QMutex( QMutex::Recursive );
107 this, &QgsAuthManager::writeToConsole );
118 QMutexLocker locker( mMutex );
123 const QString connectionName = QStringLiteral(
"authentication.configs:0x%1" ).arg( reinterpret_cast<quintptr>( QThread::currentThread() ), 2 * QT_POINTER_SIZE, 16, QLatin1Char(
'0' ) );
124 QgsDebugMsgLevel( QStringLiteral(
"Using auth db connection name: %1 " ).arg( connectionName ), 2 );
125 if ( !QSqlDatabase::contains( connectionName ) )
127 QgsDebugMsgLevel( QStringLiteral(
"No existing connection, creating a new one" ), 2 );
128 authdb = QSqlDatabase::addDatabase( QStringLiteral(
"QSQLITE" ), connectionName );
133 QgsDebugMsgLevel( QStringLiteral(
"Scheduled auth db remove on thread close" ), 2 );
143 QMetaObject::Connection connection = connect( QThread::currentThread(), &QThread::finished, QThread::currentThread(), [connectionName,
this ]
145 QMutexLocker locker( mMutex );
146 QSqlDatabase::removeDatabase( connectionName );
147 mConnectedThreads.remove( QThread::currentThread() );
148 }, Qt::DirectConnection );
150 mConnectedThreads.insert( QThread::currentThread(), connection );
156 authdb = QSqlDatabase::database( connectionName );
160 if ( !authdb.isOpen() )
162 if ( !authdb.open() )
164 const char *err = QT_TR_NOOP(
"Opening of authentication db FAILED" );
179 QgsDebugMsg( QStringLiteral(
"Initializing QCA..." ) );
180 mQcaInitializer = qgis::make_unique<QCA::Initializer>( QCA::Practical, 256 );
182 QgsDebugMsg( QStringLiteral(
"QCA initialized." ) );
183 QCA::scanForPlugins();
185 QgsDebugMsg( QStringLiteral(
"QCA Plugin Diagnostics Context: %1" ).arg( QCA::pluginDiagnosticText() ) );
186 QStringList capabilities;
188 capabilities = QCA::supportedFeatures();
189 QgsDebugMsg( QStringLiteral(
"QCA supports: %1" ).arg( capabilities.join(
"," ) ) );
192 if ( !QCA::isSupported(
"cert", QStringLiteral(
"qca-ossl" ) ) )
194 mAuthDisabled =
true;
195 mAuthDisabledMessage = tr(
"QCA's OpenSSL plugin (qca-ossl) is missing" );
199 QgsDebugMsg( QStringLiteral(
"Prioritizing qca-ossl over all other QCA providers..." ) );
200 const QCA::ProviderList provds = QCA::providers();
202 for ( QCA::Provider *p : provds )
204 QString pn = p->name();
206 if ( pn != QLatin1String(
"qca-ossl" ) )
208 pr = QCA::providerPriority( pn ) + 1;
210 QCA::setProviderPriority( pn, pr );
211 prlist << QStringLiteral(
"%1:%2" ).arg( pn ).arg( QCA::providerPriority( pn ) );
213 QgsDebugMsg( QStringLiteral(
"QCA provider priorities: %1" ).arg( prlist.join(
", " ) ) );
215 QgsDebugMsg( QStringLiteral(
"Populating auth method registry" ) );
220 QgsDebugMsg( QStringLiteral(
"Authentication methods found: %1" ).arg( methods.join(
", " ) ) );
222 if ( methods.isEmpty() )
224 mAuthDisabled =
true;
225 mAuthDisabledMessage = tr(
"No authentication method plugins found" );
231 mAuthDisabled =
true;
232 mAuthDisabledMessage = tr(
"No authentication method plugins could be loaded" );
236 mAuthDbPath = QDir::cleanPath( authDatabasePath );
240 QFileInfo dbdirinfo( dbinfo.path() );
241 QgsDebugMsg( QStringLiteral(
"Auth db directory path: %1" ).arg( dbdirinfo.filePath() ) );
243 if ( !dbdirinfo.exists() )
245 QgsDebugMsg( QStringLiteral(
"Auth db directory path does not exist, making path: %1" ).arg( dbdirinfo.filePath() ) );
246 if ( !QDir().mkpath( dbdirinfo.filePath() ) )
248 const char *err = QT_TR_NOOP(
"Auth db directory path could not be created" );
255 if ( dbinfo.exists() )
257 if ( !dbinfo.permission( QFile::ReadOwner | QFile::WriteOwner ) )
259 const char *err = QT_TR_NOOP(
"Auth db is not readable or writable by user" );
264 if ( dbinfo.size() > 0 )
266 QgsDebugMsg( QStringLiteral(
"Auth db exists and has data" ) );
268 if ( !createCertTables() )
278 const char *passenv =
"QGIS_AUTH_PASSWORD_FILE";
281 QString passpath( getenv( passenv ) );
290 QFile passfile( passpath );
291 if ( passfile.exists() && passfile.open( QIODevice::ReadOnly | QIODevice::Text ) )
293 QTextStream passin( &passfile );
294 while ( !passin.atEnd() )
296 masterpass = passin.readLine();
301 if ( !masterpass.isEmpty() )
305 QgsDebugMsg( QStringLiteral(
"Authentication master password set from QGIS_AUTH_PASSWORD_FILE" ) );
309 QgsDebugMsg(
"QGIS_AUTH_PASSWORD_FILE set, but FAILED to set password using: " + passpath );
315 QgsDebugMsg(
"QGIS_AUTH_PASSWORD_FILE set, but FAILED to read password from: " + passpath );
325 QgsDebugMsg( QStringLiteral(
"Auth db does not exist: creating through QSqlDatabase initial connection" ) );
327 if ( !createConfigTables() )
330 if ( !createCertTables() )
341 bool QgsAuthManager::createConfigTables()
343 QMutexLocker locker( mMutex );
347 const char *err = QT_TR_NOOP(
"Auth db could not be created and opened" );
358 qstr = QStringLiteral(
"CREATE TABLE %1 (\n" 359 " 'salt' TEXT NOT NULL,\n" 360 " 'civ' TEXT NOT NULL\n" 361 ", 'hash' TEXT NOT NULL);" ).arg( authDbPassTable() );
362 query.prepare( qstr );
363 if ( !authDbQuery( &query ) )
367 qstr = QStringLiteral(
"CREATE TABLE %1 (\n" 368 " 'id' TEXT NOT NULL,\n" 369 " 'name' TEXT NOT NULL,\n" 371 " 'type' TEXT NOT NULL,\n" 372 " 'version' INTEGER NOT NULL\n" 374 query.prepare( qstr );
375 if ( !authDbQuery( &query ) )
380 query.prepare( qstr );
381 if ( !authDbQuery( &query ) )
386 query.prepare( qstr );
387 if ( !authDbQuery( &query ) )
394 bool QgsAuthManager::createCertTables()
396 QMutexLocker locker( mMutex );
398 QgsDebugMsg( QStringLiteral(
"Creating cert tables in auth db" ) );
405 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n" 406 " 'setting' TEXT NOT NULL\n" 407 ", 'value' TEXT);" ).arg( authDbSettingsTable() );
408 query.prepare( qstr );
409 if ( !authDbQuery( &query ) )
414 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n" 415 " 'id' TEXT NOT NULL,\n" 416 " 'key' TEXT NOT NULL\n" 417 ", 'cert' TEXT NOT NULL);" ).arg( authDbIdentitiesTable() );
418 query.prepare( qstr );
419 if ( !authDbQuery( &query ) )
423 qstr = QStringLiteral(
"CREATE UNIQUE INDEX IF NOT EXISTS 'id_index' on %1 (id ASC);" ).arg( authDbIdentitiesTable() );
424 query.prepare( qstr );
425 if ( !authDbQuery( &query ) )
430 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n" 431 " 'id' TEXT NOT NULL,\n" 432 " 'host' TEXT NOT NULL,\n" 435 query.prepare( qstr );
436 if ( !authDbQuery( &query ) )
440 qstr = QStringLiteral(
"CREATE UNIQUE INDEX IF NOT EXISTS 'host_index' on %1 (host ASC);" ).arg(
authDatabaseServersTable() );
441 query.prepare( qstr );
442 if ( !authDbQuery( &query ) )
447 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n" 448 " 'id' TEXT NOT NULL\n" 449 ", 'cert' TEXT NOT NULL);" ).arg( authDbAuthoritiesTable() );
450 query.prepare( qstr );
451 if ( !authDbQuery( &query ) )
455 qstr = QStringLiteral(
"CREATE UNIQUE INDEX IF NOT EXISTS 'id_index' on %1 (id ASC);" ).arg( authDbAuthoritiesTable() );
456 query.prepare( qstr );
457 if ( !authDbQuery( &query ) )
461 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n" 462 " 'id' TEXT NOT NULL\n" 463 ", 'policy' TEXT NOT NULL);" ).arg( authDbTrustTable() );
464 query.prepare( qstr );
465 if ( !authDbQuery( &query ) )
469 qstr = QStringLiteral(
"CREATE UNIQUE INDEX IF NOT EXISTS 'id_index' on %1 (id ASC);" ).arg( authDbTrustTable() );
470 query.prepare( qstr );
471 if ( !authDbQuery( &query ) )
482 QgsDebugMsg( QStringLiteral(
"Authentication system DISABLED: QCA's qca-ossl (OpenSSL) plugin is missing" ) );
484 return mAuthDisabled;
489 return tr(
"Authentication system is DISABLED:\n%1" ).arg( mAuthDisabledMessage );
494 QMutexLocker locker( mMutex );
498 if ( mScheduledDbErase )
501 if ( mMasterPass.isEmpty() )
503 QgsDebugMsg( QStringLiteral(
"Master password is not yet set by user" ) );
504 if ( !masterPasswordInput() )
506 QgsDebugMsg( QStringLiteral(
"Master password input canceled by user" ) );
512 QgsDebugMsg( QStringLiteral(
"Master password is set" ) );
520 QgsDebugMsg( QStringLiteral(
"Master password is set and verified" ) );
526 QMutexLocker locker( mMutex );
530 if ( mScheduledDbErase )
534 QString prevpass = QString( mMasterPass );
538 mMasterPass = prevpass;
539 const char *err = QT_TR_NOOP(
"Master password set: FAILED to verify, reset to previous" );
545 QgsDebugMsg( QStringLiteral(
"Master password set: SUCCESS%1" ).arg( verify ?
" and verified" :
"" ) );
555 if ( !masterPasswordRowsInDb( &rows ) )
557 const char *err = QT_TR_NOOP(
"Master password: FAILED to access database" );
565 QgsDebugMsg( QStringLiteral(
"Master password: %1 rows in database" ).arg( rows ) );
569 const char *err = QT_TR_NOOP(
"Master password: FAILED to find just one master password record in database" );
576 else if ( rows == 1 )
578 if ( !masterPasswordCheckAgainstDb( compare ) )
580 if ( compare.isNull() )
582 const char *err = QT_TR_NOOP(
"Master password: FAILED to verify against hash in database" );
591 if ( mPassTries >= 5 )
593 mAuthDisabled =
true;
594 const char *err = QT_TR_NOOP(
"Master password: failed 5 times authentication system DISABLED" );
602 QgsDebugMsg( QStringLiteral(
"Master password: verified against hash in database" ) );
603 if ( compare.isNull() )
607 else if ( compare.isNull() )
609 if ( !masterPasswordStoreInDb() )
611 const char *err = QT_TR_NOOP(
"Master password: hash FAILED to be stored in database" );
620 QgsDebugMsg( QStringLiteral(
"Master password: hash stored in database" ) );
623 if ( !masterPasswordCheckAgainstDb() )
625 const char *err = QT_TR_NOOP(
"Master password: FAILED to verify against hash in database" );
635 QgsDebugMsg( QStringLiteral(
"Master password: verified against hash in database" ) );
645 return !mMasterPass.isEmpty();
650 return mMasterPass == pass;
654 bool keepbackup, QString *backuppath )
668 QgsDebugMsg( QStringLiteral(
"Master password reset: backed up current database" ) );
674 QString prevpass = QString( mMasterPass );
675 QString prevciv = QString( masterPasswordCiv() );
681 if ( ok && !masterPasswordClearDb() )
684 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not clear current password from database" );
690 QgsDebugMsg( QStringLiteral(
"Master password reset: cleared current password from database" ) );
697 if ( ok && !masterPasswordStoreInDb() )
700 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not store new password in database" );
706 QgsDebugMsg( QStringLiteral(
"Master password reset: stored new password in database" ) );
713 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not verify new password in database" );
719 if ( ok && !reencryptAllAuthenticationConfigs( prevpass, prevciv ) )
722 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not re-encrypt configs in database" );
728 QgsDebugMsg( QStringLiteral(
"Master password reset: re-encrypted configs in database" ) );
732 if ( ok && !verifyPasswordCanDecryptConfigs() )
735 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not verify password can decrypt re-encrypted configs" );
740 if ( ok && !reencryptAllAuthenticationSettings( prevpass, prevciv ) )
743 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not re-encrypt settings in database" );
748 if ( ok && !reencryptAllAuthenticationIdentities( prevpass, prevciv ) )
751 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not re-encrypt identities in database" );
761 QString errdbbackup( dbbackup );
762 errdbbackup.replace( QLatin1String(
".db" ), QLatin1String(
"_ERROR.db" ) );
764 QgsDebugMsg( QStringLiteral(
"Master password reset FAILED: backed up failed db at %1" ).arg( errdbbackup ) );
768 mMasterPass = prevpass;
770 QgsDebugMsg( QStringLiteral(
"Master password reset FAILED: reinstated previous password and database" ) );
774 *backuppath = errdbbackup;
780 if ( !keepbackup && !QFile::remove( dbbackup ) )
782 const char *err = QT_TR_NOOP(
"Master password reset: could not remove old database backup" );
790 QgsDebugMsg( QStringLiteral(
"Master password reset: backed up previous db at %1" ).arg( dbbackup ) );
792 *backuppath = dbbackup;
795 QgsDebugMsg( QStringLiteral(
"Master password reset: SUCCESS" ) );
802 mScheduledDbErase = scheduleErase;
804 mScheduledDbEraseRequestEmitted =
false;
805 mScheduledDbEraseRequestCount = 0;
809 if ( !mScheduledDbEraseTimer )
811 mScheduledDbEraseTimer =
new QTimer(
this );
812 connect( mScheduledDbEraseTimer, &QTimer::timeout,
this, &QgsAuthManager::tryToStartDbErase );
813 mScheduledDbEraseTimer->start( mScheduledDbEraseRequestWait * 1000 );
815 else if ( !mScheduledDbEraseTimer->isActive() )
817 mScheduledDbEraseTimer->start();
822 if ( mScheduledDbEraseTimer && mScheduledDbEraseTimer->isActive() )
823 mScheduledDbEraseTimer->stop();
832 qDeleteAll( mAuthMethods );
833 mAuthMethods.clear();
835 for (
const auto &authMethodKey : methods )
840 return !mAuthMethods.isEmpty();
850 QTimer::singleShot( 3, &loop, &QEventLoop::quit );
853 uint seed =
static_cast< uint
>( QTime::currentTime().msec() );
859 for (
int i = 0; i < len; i++ )
861 switch ( qrand() % 2 )
864 id += (
'0' + qrand() % 10 );
867 id += (
'a' + qrand() % 26 );
871 if ( !configids.contains(
id ) )
876 QgsDebugMsg( QStringLiteral(
"Generated unique ID: %1" ).arg(
id ) );
887 const char *err = QT_TR_NOOP(
"Config ID is empty" );
893 return !configids.contains(
id );
898 QRegExp rx( AUTH_CFG_REGEX );
899 return rx.indexIn( txt ) != -1;
904 QMutexLocker locker( mMutex );
905 QStringList providerAuthMethodsKeys;
906 if ( !dataprovider.isEmpty() )
917 query.prepare( QStringLiteral(
"SELECT id, name, uri, type, version FROM %1" ).arg(
authDatabaseConfigTable() ) );
919 if ( !authDbQuery( &query ) )
924 if ( query.isActive() && query.isSelect() )
926 while ( query.next() )
928 QString authcfg = query.value( 0 ).toString();
930 config.
setId( authcfg );
931 config.
setName( query.value( 1 ).toString() );
932 config.
setUri( query.value( 2 ).toString() );
933 config.
setMethod( query.value( 3 ).toString() );
934 config.
setVersion( query.value( 4 ).toInt() );
936 if ( !dataprovider.isEmpty() && !providerAuthMethodsKeys.contains( config.
method() ) )
941 baseConfigs.insert( authcfg, config );
949 QMutexLocker locker( mMutex );
956 if ( !authDbQuery( &query ) )
961 if ( query.isActive() )
963 QgsDebugMsg( QStringLiteral(
"Synching existing auth config and their auth methods" ) );
964 mConfigAuthMethods.clear();
965 QStringList cfgmethods;
966 while ( query.next() )
968 mConfigAuthMethods.insert( query.value( 0 ).toString(),
969 query.value( 1 ).toString() );
970 cfgmethods << QStringLiteral(
"%1=%2" ).arg( query.value( 0 ).toString(), query.value( 1 ).toString() );
972 QgsDebugMsg( QStringLiteral(
"Stored auth config/methods:\n%1" ).arg( cfgmethods.join(
", " ) ) );
981 if ( !mConfigAuthMethods.contains( authcfg ) )
983 QgsDebugMsg( QStringLiteral(
"No config auth method found in database for authcfg: %1" ).arg( authcfg ) );
987 QString authMethodKey = mConfigAuthMethods.value( authcfg );
997 return mConfigAuthMethods.value( authcfg, QString() );
1008 if ( !mAuthMethods.contains( authMethodKey ) )
1010 QgsDebugMsg( QStringLiteral(
"No auth method registered for auth method key: %1" ).arg( authMethodKey ) );
1014 return mAuthMethods.value( authMethodKey );
1019 if ( dataprovider.isEmpty() )
1021 return mAuthMethods;
1025 QgsAuthMethodsMap::const_iterator i = mAuthMethods.constBegin();
1026 while ( i != mAuthMethods.constEnd() )
1029 && ( i.value()->supportedDataProviders().contains( QStringLiteral(
"all" ) )
1030 || i.value()->supportedDataProviders().contains( dataprovider ) ) )
1032 filteredmap.insert( i.key(), i.value() );
1047 return QgsAuthMethod::Expansions(
nullptr );
1054 return QgsAuthMethod::Expansions(
nullptr );
1059 QMutexLocker locker( mMutex );
1066 const char *err = QT_TR_NOOP(
"Store config: FAILED because config is invalid" );
1072 QString uid = mconfig.
id();
1073 bool passedinID = !uid.isEmpty();
1074 if ( uid.isEmpty() )
1080 const char *err = QT_TR_NOOP(
"Store config: FAILED because pre-defined config ID is not unique" );
1087 if ( configstring.isEmpty() )
1089 const char *err = QT_TR_NOOP(
"Store config: FAILED because config string is empty" );
1095 QgsDebugMsg( QStringLiteral(
"authDbConfigTable(): %1" ).arg( authDbConfigTable() ) );
1096 QgsDebugMsg( QStringLiteral(
"name: %1" ).arg( config.name() ) );
1097 QgsDebugMsg( QStringLiteral(
"uri: %1" ).arg( config.uri() ) );
1098 QgsDebugMsg( QStringLiteral(
"type: %1" ).arg( config.method() ) );
1099 QgsDebugMsg( QStringLiteral(
"version: %1" ).arg( config.version() ) );
1100 QgsDebugMsg( QStringLiteral(
"config: %1" ).arg( configstring ) );
1104 query.prepare( QStringLiteral(
"INSERT INTO %1 (id, name, uri, type, version, config) " 1107 query.bindValue( QStringLiteral(
":id" ), uid );
1108 query.bindValue( QStringLiteral(
":name" ), mconfig.
name() );
1109 query.bindValue( QStringLiteral(
":uri" ), mconfig.
uri() );
1110 query.bindValue( QStringLiteral(
":type" ), mconfig.
method() );
1111 query.bindValue( QStringLiteral(
":version" ), mconfig.
version() );
1112 query.bindValue( QStringLiteral(
":config" ),
QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
1114 if ( !authDbStartTransaction() )
1117 if ( !authDbQuery( &query ) )
1120 if ( !authDbCommit() )
1125 mconfig.
setId( uid );
1129 QgsDebugMsg( QStringLiteral(
"Store config SUCCESS for authcfg: %1" ).arg( uid ) );
1136 QMutexLocker locker( mMutex );
1141 if ( !config.
isValid(
true ) )
1143 const char *err = QT_TR_NOOP(
"Update config: FAILED because config is invalid" );
1150 if ( configstring.isEmpty() )
1152 const char *err = QT_TR_NOOP(
"Update config: FAILED because config is empty" );
1159 QgsDebugMsg( QStringLiteral(
"authDbConfigTable(): %1" ).arg( authDbConfigTable() ) );
1160 QgsDebugMsg( QStringLiteral(
"id: %1" ).arg( config.
id() ) );
1165 QgsDebugMsg( QStringLiteral(
"config: %1" ).arg( configstring ) );
1169 if ( !query.prepare( QStringLiteral(
"UPDATE %1 " 1170 "SET name = :name, uri = :uri, type = :type, version = :version, config = :config " 1173 const char *err = QT_TR_NOOP(
"Update config: FAILED to prepare query" );
1179 query.bindValue( QStringLiteral(
":id" ), config.
id() );
1180 query.bindValue( QStringLiteral(
":name" ), config.
name() );
1181 query.bindValue( QStringLiteral(
":uri" ), config.
uri() );
1182 query.bindValue( QStringLiteral(
":type" ), config.
method() );
1183 query.bindValue( QStringLiteral(
":version" ), config.
version() );
1184 query.bindValue( QStringLiteral(
":config" ),
QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
1186 if ( !authDbStartTransaction() )
1189 if ( !authDbQuery( &query ) )
1192 if ( !authDbCommit() )
1200 QgsDebugMsg( QStringLiteral(
"Update config SUCCESS for authcfg: %1" ).arg( config.
id() ) );
1207 QMutexLocker locker( mMutex );
1217 query.prepare( QStringLiteral(
"SELECT id, name, uri, type, version, config FROM %1 " 1222 query.prepare( QStringLiteral(
"SELECT id, name, uri, type, version FROM %1 " 1226 query.bindValue( QStringLiteral(
":id" ), authcfg );
1228 if ( !authDbQuery( &query ) )
1233 if ( query.isActive() && query.isSelect() )
1235 if ( query.first() )
1237 mconfig.
setId( query.value( 0 ).toString() );
1238 mconfig.
setName( query.value( 1 ).toString() );
1239 mconfig.
setUri( query.value( 2 ).toString() );
1240 mconfig.
setMethod( query.value( 3 ).toString() );
1241 mconfig.
setVersion( query.value( 4 ).toInt() );
1256 QgsDebugMsg( QStringLiteral(
"Update of authcfg %1 FAILED for auth method %2" ).arg( authcfg, authMethodKey ) );
1259 QgsDebugMsg( QStringLiteral(
"Load %1 config SUCCESS for authcfg: %2" ).arg( full ?
"full" :
"base", authcfg ) );
1264 QgsDebugMsg( QStringLiteral(
"Select contains more than one for authcfg: %1" ).arg( authcfg ) );
1274 QMutexLocker locker( mMutex );
1278 if ( authcfg.isEmpty() )
1285 query.bindValue( QStringLiteral(
":id" ), authcfg );
1287 if ( !authDbStartTransaction() )
1290 if ( !authDbQuery( &query ) )
1293 if ( !authDbCommit() )
1300 QgsDebugMsg( QStringLiteral(
"REMOVED config for authcfg: %1" ).arg( authcfg ) );
1307 QMutexLocker locker( mMutex );
1313 bool res = authDbTransactionQuery( &query );
1321 QgsDebugMsg( QStringLiteral(
"Remove configs from database: %1" ).arg( res ?
"SUCCEEDED" :
"FAILED" ) );
1328 QMutexLocker locker( mMutex );
1331 const char *err = QT_TR_NOOP(
"No authentication database found" );
1339 if ( authConn.isValid() && authConn.isOpen() )
1343 QString datestamp( QDateTime::currentDateTime().toString( QStringLiteral(
"yyyy-MM-dd-hhmmss" ) ) );
1345 dbbackup.replace( QLatin1String(
".db" ), QStringLiteral(
"_%1.db" ).arg( datestamp ) );
1349 const char *err = QT_TR_NOOP(
"Could not back up authentication database" );
1356 *backuppath = dbbackup;
1358 QgsDebugMsg( QStringLiteral(
"Backed up auth database at %1" ).arg( dbbackup ) );
1364 QMutexLocker locker( mMutex );
1374 if ( backuppath && !dbbackup.isEmpty() )
1375 *backuppath = dbbackup;
1378 if ( dbinfo.exists() )
1380 if ( !dbinfo.permission( QFile::ReadOwner | QFile::WriteOwner ) )
1382 const char *err = QT_TR_NOOP(
"Auth db is not readable or writable by user" );
1390 const char *err = QT_TR_NOOP(
"No authentication database found" );
1398 const char *err = QT_TR_NOOP(
"Authentication database could not be deleted" );
1404 mMasterPass = QString();
1406 QgsDebugMsg( QStringLiteral(
"Creating Auth db through QSqlDatabase initial connection" ) );
1409 if ( !authConn.isValid() || !authConn.isOpen() )
1411 const char *err = QT_TR_NOOP(
"Authentication database could not be initialized" );
1417 if ( !createConfigTables() )
1419 const char *err = QT_TR_NOOP(
"FAILED to create auth database config tables" );
1425 if ( !createCertTables() )
1427 const char *err = QT_TR_NOOP(
"FAILED to create auth database cert tables" );
1443 const QString &dataprovider )
1453 QgsDebugMsg( QStringLiteral(
"Network request updating not supported by authcfg: %1" ).arg( authcfg ) );
1468 const QString &dataprovider )
1478 QgsDebugMsg( QStringLiteral(
"Network reply updating not supported by authcfg: %1" ).arg( authcfg ) );
1494 const QString &dataprovider )
1504 QgsDebugMsg( QStringLiteral(
"Data source URI updating not supported by authcfg: %1" ).arg( authcfg ) );
1529 QgsDebugMsg( QStringLiteral(
"Proxy updating not supported by authcfg: %1" ).arg( authcfg ) );
1538 QgsDebugMsg( QStringLiteral(
"Proxy updated successfully from authcfg: %1" ).arg( authcfg ) );
1547 QMutexLocker locker( mMutex );
1548 if ( key.isEmpty() )
1551 QString storeval( value.toString() );
1567 query.prepare( QStringLiteral(
"INSERT INTO %1 (setting, value) " 1568 "VALUES (:setting, :value)" ).arg( authDbSettingsTable() ) );
1570 query.bindValue( QStringLiteral(
":setting" ), key );
1571 query.bindValue( QStringLiteral(
":value" ), storeval );
1573 if ( !authDbStartTransaction() )
1576 if ( !authDbQuery( &query ) )
1579 if ( !authDbCommit() )
1582 QgsDebugMsg( QStringLiteral(
"Store setting SUCCESS for key: %1" ).arg( key ) );
1588 QMutexLocker locker( mMutex );
1589 if ( key.isEmpty() )
1595 QVariant value = defaultValue;
1597 query.prepare( QStringLiteral(
"SELECT value FROM %1 " 1598 "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
1600 query.bindValue( QStringLiteral(
":setting" ), key );
1602 if ( !authDbQuery( &query ) )
1605 if ( query.isActive() && query.isSelect() )
1607 if ( query.first() )
1611 value = QVariant(
QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 0 ).toString() ) );
1615 value = query.value( 0 );
1617 QgsDebugMsg( QStringLiteral(
"Authentication setting retrieved for key: %1" ).arg( key ) );
1621 QgsDebugMsg( QStringLiteral(
"Select contains more than one for setting key: %1" ).arg( key ) );
1631 QMutexLocker locker( mMutex );
1632 if ( key.isEmpty() )
1636 query.prepare( QStringLiteral(
"SELECT value FROM %1 " 1637 "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
1639 query.bindValue( QStringLiteral(
":setting" ), key );
1641 if ( !authDbQuery( &query ) )
1645 if ( query.isActive() && query.isSelect() )
1647 if ( query.first() )
1649 QgsDebugMsg( QStringLiteral(
"Authentication setting exists for key: %1" ).arg( key ) );
1654 QgsDebugMsg( QStringLiteral(
"Select contains more than one for setting key: %1" ).arg( key ) );
1664 QMutexLocker locker( mMutex );
1665 if ( key.isEmpty() )
1670 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
1672 query.bindValue( QStringLiteral(
":setting" ), key );
1674 if ( !authDbStartTransaction() )
1677 if ( !authDbQuery( &query ) )
1680 if ( !authDbCommit() )
1683 QgsDebugMsg( QStringLiteral(
"REMOVED setting for key: %1" ).arg( key ) );
1695 QMutexLocker locker( mMutex );
1701 mCustomConfigByHostCache.clear();
1702 mHasCheckedIfCustomConfigByHostExists =
false;
1704 QgsDebugMsg( QStringLiteral(
"Init of SSL caches %1" ).arg( res ?
"SUCCEEDED" :
"FAILED" ) );
1710 QMutexLocker locker( mMutex );
1711 if ( cert.isNull() )
1713 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
1718 QgsDebugMsg( QStringLiteral(
"Passed private key is null" ) );
1728 QString certpem( cert.toPem() );
1732 query.prepare( QStringLiteral(
"INSERT INTO %1 (id, key, cert) " 1733 "VALUES (:id, :key, :cert)" ).arg( authDbIdentitiesTable() ) );
1735 query.bindValue( QStringLiteral(
":id" ),
id );
1736 query.bindValue( QStringLiteral(
":key" ), keypem );
1737 query.bindValue( QStringLiteral(
":cert" ), certpem );
1739 if ( !authDbStartTransaction() )
1742 if ( !authDbQuery( &query ) )
1745 if ( !authDbCommit() )
1748 QgsDebugMsg( QStringLiteral(
"Store certificate identity SUCCESS for id: %1" ).arg(
id ) );
1754 QMutexLocker locker( mMutex );
1755 QSslCertificate emptycert;
1756 QSslCertificate cert;
1761 query.prepare( QStringLiteral(
"SELECT cert FROM %1 " 1762 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1764 query.bindValue( QStringLiteral(
":id" ),
id );
1766 if ( !authDbQuery( &query ) )
1769 if ( query.isActive() && query.isSelect() )
1771 if ( query.first() )
1773 cert = QSslCertificate( query.value( 0 ).toByteArray(), QSsl::Pem );
1774 QgsDebugMsg( QStringLiteral(
"Certificate identity retrieved for id: %1" ).arg(
id ) );
1778 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate identity for id: %1" ).arg(
id ) );
1788 QMutexLocker locker( mMutex );
1789 QPair<QSslCertificate, QSslKey> bundle;
1797 query.prepare( QStringLiteral(
"SELECT key, cert FROM %1 " 1798 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1800 query.bindValue( QStringLiteral(
":id" ),
id );
1802 if ( !authDbQuery( &query ) )
1805 if ( query.isActive() && query.isSelect() )
1807 QSslCertificate cert;
1809 if ( query.first() )
1811 key = QSslKey(
QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 0 ).toString() ).toLatin1(),
1812 QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey );
1815 const char *err = QT_TR_NOOP(
"Retrieve certificate identity bundle: FAILED to create private key" );
1820 cert = QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
1821 if ( cert.isNull() )
1823 const char *err = QT_TR_NOOP(
"Retrieve certificate identity bundle: FAILED to create certificate" );
1828 QgsDebugMsg( QStringLiteral(
"Certificate identity bundle retrieved for id: %1" ).arg(
id ) );
1832 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate identity for id: %1" ).arg(
id ) );
1836 bundle = qMakePair( cert, key );
1843 QMutexLocker locker( mMutex );
1847 return QStringList() << QString( bundle.first.toPem() ) << QString( bundle.second.toPem() );
1849 return QStringList();
1854 QMutexLocker locker( mMutex );
1855 QList<QSslCertificate> certs;
1858 query.prepare( QStringLiteral(
"SELECT id, cert FROM %1" ).arg( authDbIdentitiesTable() ) );
1860 if ( !authDbQuery( &query ) )
1863 if ( query.isActive() && query.isSelect() )
1865 while ( query.next() )
1867 certs << QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
1876 QMutexLocker locker( mMutex );
1877 QStringList identityids = QStringList();
1883 query.prepare( QStringLiteral(
"SELECT id FROM %1" ).arg( authDbIdentitiesTable() ) );
1885 if ( !authDbQuery( &query ) )
1890 if ( query.isActive() )
1892 while ( query.next() )
1894 identityids << query.value( 0 ).toString();
1902 QMutexLocker locker( mMutex );
1907 query.prepare( QStringLiteral(
"SELECT cert FROM %1 " 1908 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1910 query.bindValue( QStringLiteral(
":id" ),
id );
1912 if ( !authDbQuery( &query ) )
1916 if ( query.isActive() && query.isSelect() )
1918 if ( query.first() )
1920 QgsDebugMsg( QStringLiteral(
"Certificate bundle exists for id: %1" ).arg(
id ) );
1925 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate bundle for id: %1" ).arg(
id ) );
1935 QMutexLocker locker( mMutex );
1938 QgsDebugMsg( QStringLiteral(
"Passed bundle ID is empty" ) );
1944 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1946 query.bindValue( QStringLiteral(
":id" ),
id );
1948 if ( !authDbStartTransaction() )
1951 if ( !authDbQuery( &query ) )
1954 if ( !authDbCommit() )
1957 QgsDebugMsg( QStringLiteral(
"REMOVED certificate identity for id: %1" ).arg(
id ) );
1963 QMutexLocker locker( mMutex );
1966 QgsDebugMsg( QStringLiteral(
"Passed config is null" ) );
1975 QString certpem( cert.toPem() );
1978 query.prepare( QStringLiteral(
"INSERT OR REPLACE INTO %1 (id, host, cert, config) " 1981 query.bindValue( QStringLiteral(
":id" ),
id );
1982 query.bindValue( QStringLiteral(
":host" ), config.
sslHostPort().trimmed() );
1983 query.bindValue( QStringLiteral(
":cert" ), certpem );
1984 query.bindValue( QStringLiteral(
":config" ), config.
configString() );
1986 if ( !authDbStartTransaction() )
1989 if ( !authDbQuery( &query ) )
1992 if ( !authDbCommit() )
1995 QgsDebugMsg( QStringLiteral(
"Store SSL cert custom config SUCCESS for host:port, id: %1, %2" )
1999 mHasCheckedIfCustomConfigByHostExists =
false;
2000 mCustomConfigByHostCache.clear();
2007 QMutexLocker locker( mMutex );
2010 if (
id.isEmpty() || hostport.isEmpty() )
2012 QgsDebugMsg( QStringLiteral(
"Passed config ID or host:port is empty" ) );
2017 query.prepare( QStringLiteral(
"SELECT id, host, cert, config FROM %1 " 2020 query.bindValue( QStringLiteral(
":id" ),
id );
2021 query.bindValue( QStringLiteral(
":host" ), hostport.trimmed() );
2023 if ( !authDbQuery( &query ) )
2026 if ( query.isActive() && query.isSelect() )
2028 if ( query.first() )
2030 config.
setSslCertificate( QSslCertificate( query.value( 2 ).toByteArray(), QSsl::Pem ) );
2033 QgsDebugMsg( QStringLiteral(
"SSL cert custom config retrieved for host:port, id: %1, %2" ).arg( hostport,
id ) );
2037 QgsDebugMsg( QStringLiteral(
"Select contains more than one SSL cert custom config for host:port, id: %1, %2" ).arg( hostport,
id ) );
2038 emit
messageOut( tr(
"Authentication database contains duplicate SSL cert custom configs for host:port, id: %1, %2" )
2050 if ( hostport.isEmpty() )
2055 QMutexLocker locker( mMutex );
2056 if ( mHasCheckedIfCustomConfigByHostExists && !mHasCustomConfigByHost )
2058 if ( mCustomConfigByHostCache.contains( hostport ) )
2059 return mCustomConfigByHostCache.value( hostport );
2064 if ( !mHasCheckedIfCustomConfigByHostExists )
2066 mHasCheckedIfCustomConfigByHostExists =
true;
2068 if ( !authDbQuery( &query ) )
2070 mHasCustomConfigByHost =
false;
2073 if ( query.isActive() && query.isSelect() && query.first() )
2075 mHasCustomConfigByHost = query.value( 0 ).toInt() > 0;
2076 if ( !mHasCustomConfigByHost )
2081 mHasCustomConfigByHost =
false;
2086 query.prepare( QString(
"SELECT id, host, cert, config FROM %1 " 2089 query.bindValue( QStringLiteral(
":host" ), hostport.trimmed() );
2091 if ( !authDbQuery( &query ) )
2093 mCustomConfigByHostCache.insert( hostport, config );
2097 if ( query.isActive() && query.isSelect() )
2099 if ( query.first() )
2101 config.
setSslCertificate( QSslCertificate( query.value( 2 ).toByteArray(), QSsl::Pem ) );
2104 QgsDebugMsg( QStringLiteral(
"SSL cert custom config retrieved for host:port: %1" ).arg( hostport ) );
2108 QgsDebugMsg( QStringLiteral(
"Select contains more than one SSL cert custom config for host:port: %1" ).arg( hostport ) );
2109 emit
messageOut( tr(
"Authentication database contains duplicate SSL cert custom configs for host:port: %1" )
2112 mCustomConfigByHostCache.insert( hostport, emptyconfig );
2117 mCustomConfigByHostCache.insert( hostport, config );
2123 QMutexLocker locker( mMutex );
2124 QList<QgsAuthConfigSslServer> configs;
2129 if ( !authDbQuery( &query ) )
2132 if ( query.isActive() && query.isSelect() )
2134 while ( query.next() )
2137 config.
setSslCertificate( QSslCertificate( query.value( 2 ).toByteArray(), QSsl::Pem ) );
2141 configs.append( config );
2150 QMutexLocker locker( mMutex );
2151 if (
id.isEmpty() || hostport.isEmpty() )
2153 QgsDebugMsg( QStringLiteral(
"Passed config ID or host:port is empty" ) );
2158 query.prepare( QStringLiteral(
"SELECT cert FROM %1 " 2161 query.bindValue( QStringLiteral(
":id" ),
id );
2162 query.bindValue( QStringLiteral(
":host" ), hostport.trimmed() );
2164 if ( !authDbQuery( &query ) )
2168 if ( query.isActive() && query.isSelect() )
2170 if ( query.first() )
2172 QgsDebugMsg( QStringLiteral(
"SSL cert custom config exists for host:port, id: %1, %2" ).arg( hostport,
id ) );
2177 QgsDebugMsg( QStringLiteral(
"Select contains more than one SSL cert custom config for host:port, id: %1, %2" ).arg( hostport,
id ) );
2178 emit
messageOut( tr(
"Authentication database contains duplicate SSL cert custom configs for host:port, id: %1, %2" )
2188 QMutexLocker locker( mMutex );
2189 if (
id.isEmpty() || hostport.isEmpty() )
2191 QgsDebugMsg( QStringLiteral(
"Passed config ID or host:port is empty" ) );
2195 mHasCheckedIfCustomConfigByHostExists =
false;
2196 mCustomConfigByHostCache.clear();
2200 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE id = :id AND host = :host" ).arg(
authDatabaseServersTable() ) );
2202 query.bindValue( QStringLiteral(
":id" ),
id );
2203 query.bindValue( QStringLiteral(
":host" ), hostport.trimmed() );
2205 if ( !authDbStartTransaction() )
2208 if ( !authDbQuery( &query ) )
2211 if ( !authDbCommit() )
2214 QString shahostport( QStringLiteral(
"%1:%2" ).arg(
id, hostport ) );
2215 if ( mIgnoredSslErrorsCache.contains( shahostport ) )
2217 mIgnoredSslErrorsCache.remove( shahostport );
2220 QgsDebugMsg( QStringLiteral(
"REMOVED SSL cert custom config for host:port, id: %1, %2" ).arg( hostport,
id ) );
2227 QMutexLocker locker( mMutex );
2228 if ( !mIgnoredSslErrorsCache.isEmpty() )
2230 QgsDebugMsg( QStringLiteral(
"Ignored SSL errors cache items:" ) );
2231 QHash<QString, QSet<QSslError::SslError> >::const_iterator i = mIgnoredSslErrorsCache.constBegin();
2232 while ( i != mIgnoredSslErrorsCache.constEnd() )
2235 for (
auto err : i.value() )
2239 QgsDebugMsg( QStringLiteral(
"%1 = %2" ).arg( i.key(), errs.join(
", " ) ) );
2245 QgsDebugMsg( QStringLiteral(
"Ignored SSL errors cache EMPTY" ) );
2251 QMutexLocker locker( mMutex );
2254 QgsDebugMsg( QStringLiteral(
"Passed config is null" ) );
2258 QString shahostport( QStringLiteral(
"%1:%2" )
2261 if ( mIgnoredSslErrorsCache.contains( shahostport ) )
2263 mIgnoredSslErrorsCache.remove( shahostport );
2266 if ( !errenums.isEmpty() )
2268 mIgnoredSslErrorsCache.insert( shahostport, QSet<QSslError::SslError>::fromList( errenums ) );
2269 QgsDebugMsg( QStringLiteral(
"Update of ignored SSL errors cache SUCCEEDED for sha:host:port = %1" ).arg( shahostport ) );
2274 QgsDebugMsg( QStringLiteral(
"No ignored SSL errors to cache for sha:host:port = %1" ).arg( shahostport ) );
2280 QMutexLocker locker( mMutex );
2281 QRegExp rx(
"\\S+:\\S+:\\d+" );
2282 if ( !rx.exactMatch( shahostport ) )
2284 QgsDebugMsg(
"Passed shahostport does not match \\S+:\\S+:\\d+, " 2285 "e.g. 74a4ef5ea94512a43769b744cda0ca5049a72491:www.example.com:443" );
2289 if ( mIgnoredSslErrorsCache.contains( shahostport ) )
2291 mIgnoredSslErrorsCache.remove( shahostport );
2294 if ( errors.isEmpty() )
2296 QgsDebugMsg( QStringLiteral(
"Passed errors list empty" ) );
2300 QSet<QSslError::SslError> errs;
2301 for (
const auto &error : errors )
2303 if ( error.error() == QSslError::NoError )
2306 errs.insert( error.error() );
2309 if ( errs.isEmpty() )
2311 QgsDebugMsg( QStringLiteral(
"Passed errors list does not contain errors" ) );
2315 mIgnoredSslErrorsCache.insert( shahostport, errs );
2317 QgsDebugMsg( QStringLiteral(
"Update of ignored SSL errors cache SUCCEEDED for sha:host:port = %1" ).arg( shahostport ) );
2324 QMutexLocker locker( mMutex );
2325 QHash<QString, QSet<QSslError::SslError> > prevcache( mIgnoredSslErrorsCache );
2326 QHash<QString, QSet<QSslError::SslError> > nextcache;
2331 if ( !authDbQuery( &query ) )
2333 QgsDebugMsg( QStringLiteral(
"Rebuild of ignored SSL errors cache FAILED" ) );
2337 if ( query.isActive() && query.isSelect() )
2339 while ( query.next() )
2341 QString shahostport( QStringLiteral(
"%1:%2" )
2342 .arg( query.value( 0 ).toString().trimmed(),
2343 query.value( 1 ).toString().trimmed() ) );
2347 if ( !errenums.isEmpty() )
2349 nextcache.insert( shahostport, QSet<QSslError::SslError>::fromList( errenums ) );
2351 if ( prevcache.contains( shahostport ) )
2353 prevcache.remove( shahostport );
2358 if ( !prevcache.isEmpty() )
2361 QHash<QString, QSet<QSslError::SslError> >::const_iterator i = prevcache.constBegin();
2362 while ( i != prevcache.constEnd() )
2364 nextcache.insert( i.key(), i.value() );
2369 if ( nextcache != mIgnoredSslErrorsCache )
2371 mIgnoredSslErrorsCache.clear();
2372 mIgnoredSslErrorsCache = nextcache;
2373 QgsDebugMsg( QStringLiteral(
"Rebuild of ignored SSL errors cache SUCCEEDED" ) );
2378 QgsDebugMsg( QStringLiteral(
"Rebuild of ignored SSL errors cache SAME AS BEFORE" ) );
2386 QMutexLocker locker( mMutex );
2387 if ( certs.isEmpty() )
2389 QgsDebugMsg( QStringLiteral(
"Passed certificate list has no certs" ) );
2393 for (
const auto &cert : certs )
2403 QMutexLocker locker( mMutex );
2406 if ( cert.isNull() )
2408 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2415 QString pem( cert.toPem() );
2418 query.prepare( QStringLiteral(
"INSERT INTO %1 (id, cert) " 2419 "VALUES (:id, :cert)" ).arg( authDbAuthoritiesTable() ) );
2421 query.bindValue( QStringLiteral(
":id" ),
id );
2422 query.bindValue( QStringLiteral(
":cert" ), pem );
2424 if ( !authDbStartTransaction() )
2427 if ( !authDbQuery( &query ) )
2430 if ( !authDbCommit() )
2433 QgsDebugMsg( QStringLiteral(
"Store certificate authority SUCCESS for id: %1" ).arg(
id ) );
2439 QMutexLocker locker( mMutex );
2440 QSslCertificate emptycert;
2441 QSslCertificate cert;
2446 query.prepare( QStringLiteral(
"SELECT cert FROM %1 " 2447 "WHERE id = :id" ).arg( authDbAuthoritiesTable() ) );
2449 query.bindValue( QStringLiteral(
":id" ),
id );
2451 if ( !authDbQuery( &query ) )
2454 if ( query.isActive() && query.isSelect() )
2456 if ( query.first() )
2458 cert = QSslCertificate( query.value( 0 ).toByteArray(), QSsl::Pem );
2459 QgsDebugMsg( QStringLiteral(
"Certificate authority retrieved for id: %1" ).arg(
id ) );
2463 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate authority for id: %1" ).arg(
id ) );
2473 QMutexLocker locker( mMutex );
2474 if ( cert.isNull() )
2476 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2483 query.prepare( QStringLiteral(
"SELECT value FROM %1 " 2484 "WHERE id = :id" ).arg( authDbAuthoritiesTable() ) );
2486 query.bindValue( QStringLiteral(
":id" ),
id );
2488 if ( !authDbQuery( &query ) )
2492 if ( query.isActive() && query.isSelect() )
2494 if ( query.first() )
2496 QgsDebugMsg( QStringLiteral(
"Certificate authority exists for id: %1" ).arg(
id ) );
2501 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate authority for id: %1" ).arg(
id ) );
2511 QMutexLocker locker( mMutex );
2512 if ( cert.isNull() )
2514 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2522 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE id = :id" ).arg( authDbAuthoritiesTable() ) );
2524 query.bindValue( QStringLiteral(
":id" ),
id );
2526 if ( !authDbStartTransaction() )
2529 if ( !authDbQuery( &query ) )
2532 if ( !authDbCommit() )
2535 QgsDebugMsg( QStringLiteral(
"REMOVED authority for id: %1" ).arg(
id ) );
2542 return QSslSocket::systemCaCertificates();
2544 QNetworkRequest req;
2545 return req.sslConfiguration().caCertificates();
2551 QMutexLocker locker( mMutex );
2552 QList<QSslCertificate> certs;
2553 QList<QSslCertificate> filecerts;
2555 if ( cafileval.isNull() )
2559 if ( allowinvalid.isNull() )
2562 QString cafile( cafileval.toString() );
2563 if ( !cafile.isEmpty() && QFile::exists( cafile ) )
2568 for (
const auto &cert : qgis::as_const( filecerts ) )
2570 if ( !allowinvalid.toBool() && !cert.isValid() )
2585 QMutexLocker locker( mMutex );
2586 QList<QSslCertificate> certs;
2589 query.prepare( QStringLiteral(
"SELECT id, cert FROM %1" ).arg( authDbAuthoritiesTable() ) );
2591 if ( !authDbQuery( &query ) )
2594 if ( query.isActive() && query.isSelect() )
2596 while ( query.next() )
2598 certs << QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
2607 QMutexLocker locker( mMutex );
2613 QMutexLocker locker( mMutex );
2614 mCaCertsCache.clear();
2620 bool res = !mCaCertsCache.isEmpty();
2621 QgsDebugMsg( QStringLiteral(
"Rebuild of CA certs cache %1" ).arg( res ?
"SUCCEEDED" :
"FAILED" ) );
2627 QMutexLocker locker( mMutex );
2628 if ( cert.isNull() )
2630 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2640 QgsDebugMsg( QStringLiteral(
"Passed policy was default, all cert records in database were removed for id: %1" ).arg(
id ) );
2645 query.prepare( QStringLiteral(
"INSERT INTO %1 (id, policy) " 2646 "VALUES (:id, :policy)" ).arg( authDbTrustTable() ) );
2648 query.bindValue( QStringLiteral(
":id" ),
id );
2649 query.bindValue( QStringLiteral(
":policy" ), static_cast< int >( policy ) );
2651 if ( !authDbStartTransaction() )
2654 if ( !authDbQuery( &query ) )
2657 if ( !authDbCommit() )
2660 QgsDebugMsg( QStringLiteral(
"Store certificate trust policy SUCCESS for id: %1" ).arg(
id ) );
2666 QMutexLocker locker( mMutex );
2667 if ( cert.isNull() )
2669 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2676 query.prepare( QStringLiteral(
"SELECT policy FROM %1 " 2677 "WHERE id = :id" ).arg( authDbTrustTable() ) );
2679 query.bindValue( QStringLiteral(
":id" ),
id );
2681 if ( !authDbQuery( &query ) )
2685 if ( query.isActive() && query.isSelect() )
2687 if ( query.first() )
2690 QgsDebugMsg( QStringLiteral(
"Authentication cert trust policy retrieved for id: %1" ).arg(
id ) );
2694 QgsDebugMsg( QStringLiteral(
"Select contains more than one cert trust policy for id: %1" ).arg(
id ) );
2704 QMutexLocker locker( mMutex );
2705 if ( certs.empty() )
2707 QgsDebugMsg( QStringLiteral(
"Passed certificate list has no certs" ) );
2711 for (
const auto &cert : certs )
2721 QMutexLocker locker( mMutex );
2722 if ( cert.isNull() )
2724 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2732 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE id = :id" ).arg( authDbTrustTable() ) );
2734 query.bindValue( QStringLiteral(
":id" ),
id );
2736 if ( !authDbStartTransaction() )
2739 if ( !authDbQuery( &query ) )
2742 if ( !authDbCommit() )
2745 QgsDebugMsg( QStringLiteral(
"REMOVED cert trust policy for id: %1" ).arg(
id ) );
2752 QMutexLocker locker( mMutex );
2753 if ( cert.isNull() )
2763 if ( trustedids.contains(
id ) )
2767 else if ( untrustedids.contains(
id ) )
2782 return storeAuthSetting( QStringLiteral(
"certdefaulttrust" ), static_cast< int >( policy ) );
2787 QMutexLocker locker( mMutex );
2788 QVariant policy(
authSetting( QStringLiteral(
"certdefaulttrust" ) ) );
2789 if ( policy.isNull() )
2798 QMutexLocker locker( mMutex );
2799 mCertTrustCache.clear();
2802 query.prepare( QStringLiteral(
"SELECT id, policy FROM %1" ).arg( authDbTrustTable() ) );
2804 if ( !authDbQuery( &query ) )
2806 QgsDebugMsg( QStringLiteral(
"Rebuild of cert trust policy cache FAILED" ) );
2810 if ( query.isActive() && query.isSelect() )
2812 while ( query.next() )
2814 QString
id = query.value( 0 ).toString();
2818 if ( mCertTrustCache.contains( policy ) )
2820 ids = mCertTrustCache.value( policy );
2822 mCertTrustCache.insert( policy, ids <<
id );
2826 QgsDebugMsg( QStringLiteral(
"Rebuild of cert trust policy cache SUCCEEDED" ) );
2832 QMutexLocker locker( mMutex );
2836 const QList<QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> > &certpairs( mCaCertsCache.values() );
2838 QList<QSslCertificate> trustedcerts;
2839 for (
int i = 0; i < certpairs.size(); ++i )
2841 QSslCertificate cert( certpairs.at( i ).second );
2843 if ( trustedids.contains( certid ) )
2846 trustedcerts.append( cert );
2852 trustedcerts.append( cert );
2857 QSslConfiguration sslconfig( QSslConfiguration::defaultConfiguration() );
2858 sslconfig.setCaCertificates( trustedcerts );
2859 QSslConfiguration::setDefaultConfiguration( sslconfig );
2861 return trustedcerts;
2866 QMutexLocker locker( mMutex );
2867 if ( trustedCAs.isEmpty() )
2869 if ( mTrustedCaCertsCache.isEmpty() )
2876 const QList<QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> > &certpairs( mCaCertsCache.values() );
2878 QList<QSslCertificate> untrustedCAs;
2879 for (
int i = 0; i < certpairs.size(); ++i )
2881 QSslCertificate cert( certpairs.at( i ).second );
2882 if ( !trustedCAs.contains( cert ) )
2884 untrustedCAs.append( cert );
2887 return untrustedCAs;
2892 QMutexLocker locker( mMutex );
2894 QgsDebugMsg( QStringLiteral(
"Rebuilt trusted cert authorities cache" ) );
2901 QMutexLocker locker( mMutex );
2907 QMutexLocker locker( mMutex );
2910 return passwordHelperWrite( mMasterPass );
2926 for (
const auto &authcfg : ids )
2944 void QgsAuthManager::writeToConsole(
const QString &message,
2958 msg += QLatin1String(
"WARNING: " );
2961 msg += QLatin1String(
"ERROR: " );
2968 QTextStream out( stdout, QIODevice::WriteOnly );
2972 void QgsAuthManager::tryToStartDbErase()
2974 ++mScheduledDbEraseRequestCount;
2976 int trycutoff = 90 / ( mScheduledDbEraseRequestWait ? mScheduledDbEraseRequestWait : 3 );
2977 if ( mScheduledDbEraseRequestCount >= trycutoff )
2980 QgsDebugMsg( QStringLiteral(
"authDatabaseEraseRequest emitting/scheduling canceled" ) );
2985 QgsDebugMsg( QStringLiteral(
"authDatabaseEraseRequest attempt (%1 of %2)" )
2986 .arg( mScheduledDbEraseRequestCount ).arg( trycutoff ) );
2992 mScheduledDbEraseRequestEmitted =
true;
2997 QgsDebugMsg( QStringLiteral(
"authDatabaseEraseRequest emitted" ) );
3000 QgsDebugMsg( QStringLiteral(
"authDatabaseEraseRequest emit skipped" ) );
3006 QMutexLocker locker( mMutex );
3007 QMapIterator<QThread *, QMetaObject::Connection> iterator( mConnectedThreads );
3008 while ( iterator.hasNext() )
3011 iterator.key()->disconnect( iterator.value() );
3018 qDeleteAll( mAuthMethods );
3021 if ( authConn.isValid() && authConn.isOpen() )
3026 delete mScheduledDbEraseTimer;
3027 mScheduledDbEraseTimer =
nullptr;
3028 QSqlDatabase::removeDatabase( QStringLiteral(
"authentication.configs" ) );
3032 QString QgsAuthManager::passwordHelperName()
const 3034 return tr(
"Password Helper" );
3038 void QgsAuthManager::passwordHelperLog(
const QString &msg )
const 3050 QKeychain::DeletePasswordJob job( AUTH_PASSWORD_HELPER_FOLDER_NAME );
3052 job.setInsecureFallback( settings.
value( QStringLiteral(
"password_helper_insecure_fallback" ),
false, QgsSettings::Section::Auth ).toBool() );
3053 job.setAutoDelete(
false );
3054 job.setKey( AUTH_PASSWORD_HELPER_KEY_NAME );
3056 connect( &job, &QKeychain::Job::finished, &loop, &QEventLoop::quit );
3061 mPasswordHelperErrorCode = job.error();
3062 mPasswordHelperErrorMessage = tr(
"Delete password failed: %1." ).arg( job.errorString() );
3073 passwordHelperProcessError();
3077 QString QgsAuthManager::passwordHelperRead()
3082 QKeychain::ReadPasswordJob job( AUTH_PASSWORD_HELPER_FOLDER_NAME );
3084 job.setInsecureFallback( settings.
value( QStringLiteral(
"password_helper_insecure_fallback" ),
false, QgsSettings::Section::Auth ).toBool() );
3085 job.setAutoDelete(
false );
3086 job.setKey( AUTH_PASSWORD_HELPER_KEY_NAME );
3088 connect( &job, &QKeychain::Job::finished, &loop, &QEventLoop::quit );
3093 mPasswordHelperErrorCode = job.error();
3100 password = job.textData();
3102 if ( password.isEmpty() )
3104 mPasswordHelperErrorCode = QKeychain::EntryNotFound;
3115 passwordHelperProcessError();
3119 bool QgsAuthManager::passwordHelperWrite(
const QString &password )
3121 Q_ASSERT( !password.isEmpty() );
3124 QKeychain::WritePasswordJob job( AUTH_PASSWORD_HELPER_FOLDER_NAME );
3126 job.setInsecureFallback( settings.
value( QStringLiteral(
"password_helper_insecure_fallback" ),
false, QgsSettings::Section::Auth ).toBool() );
3127 job.setAutoDelete(
false );
3128 job.setKey( AUTH_PASSWORD_HELPER_KEY_NAME );
3129 job.setTextData( password );
3131 connect( &job, &QKeychain::Job::finished, &loop, &QEventLoop::quit );
3136 mPasswordHelperErrorCode = job.error();
3144 passwordHelperClearErrors();
3149 passwordHelperProcessError();
3157 return settings.
value( QStringLiteral(
"use_password_helper" ),
true, QgsSettings::Section::Auth ).toBool();
3163 settings.
setValue( QStringLiteral(
"use_password_helper" ), enabled, QgsSettings::Section::Auth );
3164 emit
messageOut( enabled ? tr(
"Your %1 will be <b>used from now</b> on to store and retrieve the master password." )
3166 tr(
"Your %1 will <b>not be used anymore</b> to store and retrieve the master password." )
3174 return settings.
value( QStringLiteral(
"password_helper_logging" ),
false, QgsSettings::Section::Auth ).toBool();
3180 settings.
setValue( QStringLiteral(
"password_helper_logging" ), enabled, QgsSettings::Section::Auth );
3183 void QgsAuthManager::passwordHelperClearErrors()
3185 mPasswordHelperErrorCode = QKeychain::NoError;
3186 mPasswordHelperErrorMessage.clear();
3189 void QgsAuthManager::passwordHelperProcessError()
3191 if ( mPasswordHelperErrorCode == QKeychain::AccessDenied ||
3192 mPasswordHelperErrorCode == QKeychain::AccessDeniedByUser ||
3193 mPasswordHelperErrorCode == QKeychain::NoBackendAvailable ||
3194 mPasswordHelperErrorCode == QKeychain::NotImplemented )
3200 mPasswordHelperErrorMessage = tr(
"There was an error and integration with your %1 system has been disabled. " 3201 "You can re-enable it at any time through the \"Utilities\" menu " 3202 "in the Authentication pane of the options dialog. %2" )
3205 if ( mPasswordHelperErrorCode != QKeychain::NoError )
3211 passwordHelperClearErrors();
3215 bool QgsAuthManager::masterPasswordInput()
3221 bool storedPasswordIsValid =
false;
3227 pass = passwordHelperRead();
3228 if ( ! pass.isEmpty() && ( mPasswordHelperErrorCode == QKeychain::NoError ) )
3234 storedPasswordIsValid =
true;
3250 if ( ok && !pass.isEmpty() && mMasterPass != pass )
3255 if ( passwordHelperWrite( pass ) )
3269 bool QgsAuthManager::masterPasswordRowsInDb(
int *rows )
const 3275 query.prepare( QStringLiteral(
"SELECT Count(*) FROM %1" ).arg( authDbPassTable() ) );
3277 bool ok = authDbQuery( &query );
3278 if ( query.first() )
3280 *rows = query.value( 0 ).toInt();
3292 if ( !masterPasswordRowsInDb( &rows ) )
3294 const char *err = QT_TR_NOOP(
"Master password: FAILED to access database" );
3300 return ( rows == 1 );
3303 bool QgsAuthManager::masterPasswordCheckAgainstDb(
const QString &compare )
const 3311 query.prepare( QStringLiteral(
"SELECT salt, hash FROM %1" ).arg( authDbPassTable() ) );
3312 if ( !authDbQuery( &query ) )
3315 if ( !query.first() )
3318 QString salt = query.value( 0 ).toString();
3319 QString hash = query.value( 1 ).toString();
3324 bool QgsAuthManager::masterPasswordStoreInDb()
const 3329 QString salt, hash, civ;
3333 query.prepare( QStringLiteral(
"INSERT INTO %1 (salt, hash, civ) VALUES (:salt, :hash, :civ)" ).arg( authDbPassTable() ) );
3335 query.bindValue( QStringLiteral(
":salt" ), salt );
3336 query.bindValue( QStringLiteral(
":hash" ), hash );
3337 query.bindValue( QStringLiteral(
":civ" ), civ );
3339 if ( !authDbStartTransaction() )
3342 if ( !authDbQuery( &query ) )
3345 if ( !authDbCommit() )
3351 bool QgsAuthManager::masterPasswordClearDb()
3357 query.prepare( QStringLiteral(
"DELETE FROM %1" ).arg( authDbPassTable() ) );
3358 bool res = authDbTransactionQuery( &query );
3364 const QString QgsAuthManager::masterPasswordCiv()
const 3370 query.prepare( QStringLiteral(
"SELECT civ FROM %1" ).arg( authDbPassTable() ) );
3371 if ( !authDbQuery( &query ) )
3374 if ( !query.first() )
3377 return query.value( 0 ).toString();
3382 QStringList configids = QStringList();
3390 if ( !authDbQuery( &query ) )
3395 if ( query.isActive() )
3397 while ( query.next() )
3399 configids << query.value( 0 ).toString();
3405 bool QgsAuthManager::verifyPasswordCanDecryptConfigs()
const 3416 if ( !authDbQuery( &query ) )
3419 if ( !query.isActive() || !query.isSelect() )
3421 QgsDebugMsg( QStringLiteral(
"Verify password can decrypt configs FAILED, query not active or a select operation" ) );
3426 while ( query.next() )
3429 QString configstring(
QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 1 ).toString() ) );
3430 if ( configstring.isEmpty() )
3432 QgsDebugMsg( QStringLiteral(
"Verify password can decrypt configs FAILED, could not decrypt a config (id: %1)" )
3433 .arg( query.value( 0 ).toString() ) );
3438 QgsDebugMsg( QStringLiteral(
"Verify password can decrypt configs SUCCESS (checked %1 configs)" ).arg( checked ) );
3442 bool QgsAuthManager::reencryptAllAuthenticationConfigs(
const QString &prevpass,
const QString &prevciv )
3449 for (
const auto &configid : ids )
3451 res = res && reencryptAuthenticationConfig( configid, prevpass, prevciv );
3456 bool QgsAuthManager::reencryptAuthenticationConfig(
const QString &authcfg,
const QString &prevpass,
const QString &prevciv )
3465 query.prepare( QStringLiteral(
"SELECT config FROM %1 " 3468 query.bindValue( QStringLiteral(
":id" ), authcfg );
3470 if ( !authDbQuery( &query ) )
3473 if ( !query.isActive() || !query.isSelect() )
3475 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, query not active or a select operation for authcfg: %2" ).arg( authcfg ) );
3479 if ( query.first() )
3485 QgsDebugMsg( QStringLiteral(
"Select contains more than one for authcfg: %1" ).arg( authcfg ) );
3492 query.prepare( QStringLiteral(
"UPDATE %1 " 3493 "SET config = :config " 3496 query.bindValue( QStringLiteral(
":id" ), authcfg );
3497 query.bindValue( QStringLiteral(
":config" ),
QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
3499 if ( !authDbStartTransaction() )
3502 if ( !authDbQuery( &query ) )
3505 if ( !authDbCommit() )
3508 QgsDebugMsg( QStringLiteral(
"Reencrypt SUCCESS for authcfg: %2" ).arg( authcfg ) );
3513 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, could not find in db authcfg: %2" ).arg( authcfg ) );
3518 bool QgsAuthManager::reencryptAllAuthenticationSettings(
const QString &prevpass,
const QString &prevciv )
3521 Q_UNUSED( prevpass )
3534 QStringList encryptedsettings;
3535 encryptedsettings <<
"";
3537 for (
const auto & sett, qgis::as_const( encryptedsettings ) )
3544 QSqlQuery query( authDbConnection() );
3546 query.prepare( QStringLiteral(
"SELECT value FROM %1 " 3547 "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
3549 query.bindValue(
":setting", sett );
3551 if ( !authDbQuery( &query ) )
3554 if ( !query.isActive() || !query.isSelect() )
3556 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, query not active or a select operation for setting: %2" ).arg( sett ) );
3560 if ( query.first() )
3566 query.prepare( QStringLiteral(
"UPDATE %1 " 3567 "SET value = :value " 3568 "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
3570 query.bindValue(
":setting", sett );
3573 if ( !authDbStartTransaction() )
3576 if ( !authDbQuery( &query ) )
3579 if ( !authDbCommit() )
3582 QgsDebugMsg( QStringLiteral(
"Reencrypt SUCCESS for setting: %2" ).arg( sett ) );
3587 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, could not find in db setting: %2" ).arg( sett ) );
3593 QgsDebugMsg( QStringLiteral(
"Select contains more than one for setting: %1" ).arg( sett ) );
3604 bool QgsAuthManager::reencryptAllAuthenticationIdentities(
const QString &prevpass,
const QString &prevciv )
3611 for (
const auto &identid : ids )
3613 res = res && reencryptAuthenticationIdentity( identid, prevpass, prevciv );
3618 bool QgsAuthManager::reencryptAuthenticationIdentity(
3619 const QString &identid,
3620 const QString &prevpass,
3621 const QString &prevciv )
3630 query.prepare( QStringLiteral(
"SELECT key FROM %1 " 3631 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
3633 query.bindValue( QStringLiteral(
":id" ), identid );
3635 if ( !authDbQuery( &query ) )
3638 if ( !query.isActive() || !query.isSelect() )
3640 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, query not active or a select operation for identity id: %2" ).arg( identid ) );
3644 if ( query.first() )
3650 QgsDebugMsg( QStringLiteral(
"Select contains more than one for identity id: %1" ).arg( identid ) );
3657 query.prepare( QStringLiteral(
"UPDATE %1 " 3659 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
3661 query.bindValue( QStringLiteral(
":id" ), identid );
3662 query.bindValue( QStringLiteral(
":key" ),
QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), keystring ) );
3664 if ( !authDbStartTransaction() )
3667 if ( !authDbQuery( &query ) )
3670 if ( !authDbCommit() )
3673 QgsDebugMsg( QStringLiteral(
"Reencrypt SUCCESS for identity id: %2" ).arg( identid ) );
3678 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, could not find in db identity id: %2" ).arg( identid ) );
3683 bool QgsAuthManager::authDbOpen()
const 3689 if ( !authdb.isOpen() )
3691 if ( !authdb.open() )
3693 QgsDebugMsg( QStringLiteral(
"Unable to establish database connection\nDatabase: %1\nDriver error: %2\nDatabase error: %3" )
3695 authdb.lastError().driverText(),
3696 authdb.lastError().databaseText() ) );
3704 bool QgsAuthManager::authDbQuery( QSqlQuery *query )
const 3709 query->setForwardOnly(
true );
3710 if ( !query->exec() )
3712 const char *err = QT_TR_NOOP(
"Auth db query exec() FAILED" );
3718 if ( query->lastError().isValid() )
3720 QgsDebugMsg( QStringLiteral(
"Auth db query FAILED: %1\nError: %2" )
3721 .arg( query->executedQuery(),
3722 query->lastError().text() ) );
3730 bool QgsAuthManager::authDbStartTransaction()
const 3737 const char *err = QT_TR_NOOP(
"Auth db FAILED to start transaction" );
3746 bool QgsAuthManager::authDbCommit()
const 3753 const char *err = QT_TR_NOOP(
"Auth db FAILED to rollback changes" );
3763 bool QgsAuthManager::authDbTransactionQuery( QSqlQuery *query )
const 3770 const char *err = QT_TR_NOOP(
"Auth db FAILED to start transaction" );
3776 bool ok = authDbQuery( query );
3780 const char *err = QT_TR_NOOP(
"Auth db FAILED to rollback changes" );
3792 for (
const auto &cert : certs )
3795 QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate>( source, cert ) );
Singleton offering an interface to manage the authentication configuration database and to utilize co...
bool rebuildTrustedCaCertsCache()
Rebuild trusted certificate authorities cache.
bool getMasterPassword(QString &password, bool stored=false)
bool isNull() const
Whether configuration is null (missing components)
void setUri(const QString &uri)
const QString authDatabaseConfigTable() const
Name of the authentication database table that stores configs.
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 isValid(bool validateid=false) const
Whether the configuration is valid.
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.
bool passwordHelperEnabled() const
Password helper enabled getter.
void setId(const QString &id)
Sets auth config ID.
static QgsAuthManager * instance()
Enforce singleton pattern.
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
QgsAuthMethod::Expansions supportedAuthMethodExpansions(const QString &authcfg)
Gets supported authentication method expansion(s), e.g.
void setScheduledAuthDatabaseErase(bool scheduleErase)
Schedule an optional erase of authentication database, starting when mutex is lockable.
bool storeSslCertCustomConfig(const QgsAuthConfigSslServer &config)
Store an SSL certificate custom config.
This class is a composition of two QSettings instances:
bool existsAuthSetting(const QString &key)
Check if an authentication setting exists.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
QStringList authMethodList() const
Returns list of available auth methods by their keys.
bool storeAuthSetting(const QString &key, const QVariant &value, bool encrypt=false)
Store an authentication setting (stored as string via QVariant( value ).toString() ) ...
bool removeCertAuthority(const QSslCertificate &cert)
Remove a certificate authority.
bool updateNetworkProxy(QNetworkProxy &proxy, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkProxy with an authentication config.
bool masterPasswordSame(const QString &pass) const
Check whether supplied password is the same as the one already set.
static QString sslErrorEnumString(QSslError::SslError errenum)
Gets short strings describing an SSL error.
bool initSslCaches()
Initialize various SSL authentication caches.
static QList< QSslCertificate > certsFromFile(const QString &certspath)
Returns a list of concatenated certs from a PEM or DER formatted file.
void passwordHelperFailure()
Signals emitted on password helper failure, mainly used in the tests to exit main application loop...
static QMap< QString, QSslCertificate > mapDigestToCerts(const QList< QSslCertificate > &certs)
Map certificate sha1 to certificate as simple cache.
Configuration container for SSL server connection exceptions or overrides.
virtual bool updateDataSourceUriItems(QStringList &connectionItems, const QString &authcfg, const QString &dataprovider=QString())
Update data source connection items with authentication components.
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...
static QgsCredentials * instance()
retrieves instance
static bool certificateIsAuthorityOrIssuer(const QSslCertificate &cert)
Gets whether a certificate is an Authority or can at least sign other certificates.
const QString disabledMessage() const
Standard message for when QCA's qca-ossl plugin is missing and system is disabled.
bool removeCertTrustPolicy(const QSslCertificate &cert)
Remove a certificate authority.
const QList< QgsAuthConfigSslServer > sslCertCustomConfigs()
sslCertCustomConfigs get SSL certificate custom configs
QStringList authMethodsKeys(const QString &dataprovider=QString())
Gets keys of supported authentication methods.
QgsAuthMethod * authMethod(const QString &authMethodKey)
Gets authentication method from the config/provider cache via its key.
bool storeCertAuthority(const QSslCertificate &cert)
Store a certificate authority.
const QList< QSslCertificate > extraFileCAs()
extraFileCAs extra file-based certificate authorities
static void passwordKeyHash(const QString &pass, QString *salt, QString *hash, QString *cipheriv=nullptr)
Generate SHA256 hash for master password, with iterations and salt.
MessageLevel
Message log level (mirrors that of QgsMessageLog, so it can also output there)
bool rebuildCaCertsCache()
Rebuild certificate authority cache.
QgsAuthCertUtils::CertTrustPolicy certificateTrustPolicy(const QSslCertificate &cert)
certificateTrustPolicy get trust policy for a particular certificate cert
A registry / canonical manager of authentication methods.
const QPair< QSslCertificate, QSslKey > certIdentityBundle(const QString &id)
Gets a certificate identity bundle by id (sha hash).
const QString uniqueConfigId() const
Gets a unique generated 7-character string to assign to as config id.
static const QString AUTH_PASSWORD_HELPER_DISPLAY_NAME
The display name of the password helper (platform dependent)
bool updateAuthenticationConfig(const QgsAuthMethodConfig &config)
Update an authentication config in the database.
bool eraseAuthenticationDatabase(bool backup, QString *backuppath=nullptr)
Erase all rows from all tables in authentication database.
const QList< QSslCertificate > trustedCaCerts(bool includeinvalid=false)
trustedCaCerts get list of all trusted CA certificates
virtual bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Update a network request with authentication components.
void clearCachedConfig(const QString &authcfg)
Clear an authentication config from its associated authentication method cache.
void masterPasswordVerified(bool verified)
Emitted when a password has been verify (or not)
static bool certIsViable(const QSslCertificate &cert)
certIsViable checks for viability errors of cert and whether it is NULL
bool setDefaultCertTrustPolicy(QgsAuthCertUtils::CertTrustPolicy policy)
Sets the default certificate trust policy preferred by user.
bool removeAllAuthenticationConfigs()
Clear all authentication configs from table in database and from provider caches. ...
bool hasConfigId(const QString &txt) const
Returns whether a string includes an authcfg ID token.
const QList< QSslCertificate > untrustedCaCerts(QList< QSslCertificate > trustedCAs=QList< QSslCertificate >())
untrustedCaCerts get list of untrusted certificate authorities
bool passwordHelperLoggingEnabled() const
Password helper logging enabled getter.
QWidget * editWidget(const QString &authMethodKey, QWidget *parent=nullptr)
Returns the auth method capabilities.
QHash< QString, QgsAuthMethodConfig > QgsAuthMethodConfigsMap
const QMap< QString, QSslCertificate > mappedDatabaseCAs()
mappedDatabaseCAs get sha1-mapped database-stored certificate authorities
QgsAuthMethodConfigsMap availableAuthMethodConfigs(const QString &dataprovider=QString())
Gets mapping of authentication config ids and their base configs (not decrypted data) ...
#define QgsDebugMsgLevel(str, level)
QString authManTag() const
Simple text tag describing authentication system for message logs.
void setMethod(const QString &method)
~QgsAuthManager() override
Configuration storage class for authentication method configurations.
const QString configString() const
Configuration as a concatenated string.
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).
const QString authenticationDatabasePath() const
The standard authentication database file in ~/.qgis3/ or defined location.
bool storeCertIdentity(const QSslCertificate &cert, const QSslKey &key)
Store a certificate identity.
bool updateDataSourceUriItems(QStringList &connectionItems, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QgsDataSourceUri with an authentication config.
bool removeCertTrustPolicies(const QList< QSslCertificate > &certs)
Remove a group certificate authorities.
bool removeSslCertCustomConfig(const QString &id, const QString &hostport)
Remove an SSL certificate custom config.
const QStringList certIdentityBundleToPem(const QString &id)
certIdentityBundleToPem get a certificate identity bundle by id (sha hash) returned as PEM text ...
bool passwordHelperSync()
Store the password manager into the wallet.
void authDatabaseChanged()
Emitted when the authentication db is significantly changed, e.g. large record removal, erased, etc.
void loadConfigString(const QString &configstr)
Load existing extended configuration.
const QString name() const
Gets name of configuration.
const QString sslHostPort() const
Server host:port string.
void passwordHelperSuccess()
Signals emitted on password helper success, mainly used in the tests to exit main application loop...
QStringList configIds() const
Gets list of authentication ids from database.
QWidget * authMethodEditWidget(const QString &authMethodKey, QWidget *parent)
Gets authentication method edit widget via its key.
const QgsAuthConfigSslServer sslCertCustomConfigByHost(const QString &hostport)
sslCertCustomConfigByHost get an SSL certificate custom config by hostport (host:port) ...
void authDatabaseEraseRequested()
Emitted when a user has indicated they may want to erase the authentication db.
const QList< QSslError::SslError > sslIgnoredErrorEnums() const
SSL server errors (as enum list) to ignore in connections.
void setSslHostPort(const QString &hostport)
Sets server host:port string.
void updateConfigAuthMethods()
Sync the confg/authentication method cache with what is in database.
QSqlDatabase authDatabaseConnection() const
Sets up the application instance of the authentication database connection.
bool storeCertTrustPolicy(const QSslCertificate &cert, QgsAuthCertUtils::CertTrustPolicy policy)
Store user trust value for a certificate.
int version() const
Gets version of the configuration.
virtual void clearCachedConfig(const QString &authcfg)=0
Clear any cached configuration.
bool masterPasswordHashInDatabase() const
Verify a password hash existing in authentication database.
bool passwordHelperDelete()
Delete master password from wallet.
bool storeCertAuthorities(const QList< QSslCertificate > &certs)
Store multiple certificate authorities.
bool existsCertAuthority(const QSslCertificate &cert)
Check if a certificate authority exists.
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Gets the sha1 hash for certificate.
QString configAuthMethodKey(const QString &authcfg) const
Gets key of authentication method associated with config ID.
const QList< QSslCertificate > certIdentities()
certIdentities get certificate identities
virtual bool updateNetworkProxy(QNetworkProxy &proxy, const QString &authcfg, const QString &dataprovider=QString())
Update proxy settings with authentication components.
bool updateIgnoredSslErrorsCacheFromConfig(const QgsAuthConfigSslServer &config)
Update ignored SSL error cache with possible ignored SSL errors, using server config.
QgsAuthMethod * configAuthMethod(const QString &authcfg)
Gets authentication method from the config/provider cache.
const QSslCertificate sslCertificate() const
Server certificate object.
const QSslCertificate certIdentity(const QString &id)
certIdentity get a certificate identity by id (sha hash)
Abstract base class for authentication method plugins.
static const QString encrypt(const QString &pass, const QString &cipheriv, const QString &text)
Encrypt data using master password.
CaCertSource
Type of CA certificate source.
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 )) ...
bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkRequest with an authentication config.
bool removeCertIdentity(const QString &id)
Remove a certificate identity.
const QByteArray trustedCaCertsPemText()
trustedCaCertsPemText get concatenated string of all trusted CA certificates
void clearMasterPassword()
Clear supplied master password.
const QgsAuthConfigSslServer sslCertCustomConfig(const QString &id, const QString &hostport)
sslCertCustomConfig get an SSL certificate custom config by id (sha hash) and hostport (host:port) ...
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
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 setMasterPassword(bool verify=false)
Main call to initially set or continually check master password is set.
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...
bool storeAuthenticationConfig(QgsAuthMethodConfig &mconfig)
Store an authentication config in the database.
const QList< QSslCertificate > trustedCaCertsCache()
trustedCaCertsCache cache of trusted certificate authorities, ready for network connections ...
void setVersion(int version)
Sets version of the configuration.
bool loadAuthenticationConfig(const QString &authcfg, QgsAuthMethodConfig &mconfig, bool full=false)
Load an authentication config from the database into subclass.
const QSslCertificate certAuthority(const QString &id)
Gets a certificate authority by id (sha hash)
bool existsSslCertCustomConfig(const QString &id, const QString &hostport)
Check if SSL certificate custom config exists.
bool isDisabled() const
Whether QCA has the qca-ossl plugin, which a base run-time requirement.
static const QString decrypt(const QString &pass, const QString &cipheriv, const QString &text)
Decrypt data using master password.
virtual bool updateNetworkReply(QNetworkReply *reply, const QString &authcfg, const QString &dataprovider=QString())
Update a network reply with authentication components.
bool configIdUnique(const QString &id) const
Verify if provided authentication id is unique.
QString method() const
Textual key of the associated authentication method.
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 loadConfigString(const QString &config=QString())
Load concatenated string into configuration, e.g. from auth database.
void setPasswordHelperEnabled(bool enabled)
Password helper enabled setter.
static const QString AUTH_MAN_TAG
The display name of the Authentication Manager.
const QString uri() const
A URI to auto-select a config when connecting to a resource.
bool existsCertIdentity(const QString &id)
Check if a certificate identity exists.
bool masterPasswordIsSet() const
Whether master password has be input and verified, i.e. authentication database is accessible...
const QList< QSslCertificate > databaseCAs()
databaseCAs get database-stored certificate authorities
CertTrustPolicy
Type of certificate trust policy.
QgsAuthMethodsMap authMethodsMap(const QString &dataprovider=QString())
Gets available authentication methods mapped to their key.
bool scheduledAuthDatabaseErase()
Whether there is a scheduled opitonal erase of authentication database.
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 removeAuthenticationConfig(const QString &authcfg)
Remove an authentication config in the database.
QgsAuthCertUtils::CertTrustPolicy certTrustPolicy(const QSslCertificate &cert)
certTrustPolicy get whether certificate cert is trusted by user
void dumpIgnoredSslErrorsCache_()
Utility function to dump the cache for debug purposes.
const QList< QSslCertificate > systemRootCAs()
systemRootCAs get root system certificate authorities
QgsAuthCertUtils::CertTrustPolicy defaultCertTrustPolicy()
Gets the default certificate trust policy preferred by user.
const QString authDatabaseServersTable() const
Name of the authentication database table that stores server exceptions/configs.
QgsAuthMethod::Expansions supportedExpansions() const
Flags that represent the update points (where authentication configurations are expanded) supported b...
bool removeAuthSetting(const QString &key)
Remove an authentication setting.
static QgsAuthMethodRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
void setName(const QString &name)
Sets name of configuration.
const QString configString() const
The extended configuration, as stored and retrieved from the authentication database.
bool rebuildIgnoredSslErrorCache()
Rebuild ignoredSSL error cache.
void setSslCertificate(const QSslCertificate &cert)
Sets server certificate object.
bool backupAuthenticationDatabase(QString *backuppath=nullptr)
Close connection to current authentication database and back it up.
virtual void updateMethodConfig(QgsAuthMethodConfig &mconfig)=0
Update an authentication configuration in place.
bool registerCoreAuthMethods()
Instantiate and register existing C++ core authentication methods from plugins.
QStringList certIdentityIds() const
certIdentityIds get list of certificate identity ids from database
void setPasswordHelperLoggingEnabled(bool enabled)
Password helper logging enabled setter.
const QString id() const
Gets 'authcfg' 7-character alphanumeric ID of the config.
static QByteArray certsToPemText(const QList< QSslCertificate > &certs)
certsToPemText dump a list of QSslCertificates to PEM text
bool verifyMasterPassword(const QString &compare=QString())
Verify the supplied master password against any existing hash in authentication database.
void clearAllCachedConfigs()
Clear all authentication configs from authentication method caches.
bool rebuildCertTrustCache()
Rebuild certificate authority cache.
QHash< QString, QgsAuthMethod * > QgsAuthMethodsMap