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" );
76 #elif defined(Q_OS_WIN) 78 #elif defined(Q_OS_LINUX) 89 QMutexLocker locker( &sMutex );
101 mMutex =
new QMutex( QMutex::Recursive );
103 this, &QgsAuthManager::writeToConsole );
114 QMutexLocker locker( mMutex );
119 const QString connectionName = QStringLiteral(
"authentication.configs:0x%1" ).arg( reinterpret_cast<quintptr>( QThread::currentThread() ), 2 * QT_POINTER_SIZE, 16, QLatin1Char(
'0' ) );
120 QgsDebugMsgLevel( QStringLiteral(
"Using auth db connection name: %1 " ).arg( connectionName ), 2 );
121 if ( !QSqlDatabase::contains( connectionName ) )
123 QgsDebugMsgLevel( QStringLiteral(
"No existing connection, creating a new one" ), 2 );
124 authdb = QSqlDatabase::addDatabase( QStringLiteral(
"QSQLITE" ), connectionName );
127 if ( QThread::currentThread() != qApp->thread() )
129 QgsDebugMsgLevel( QStringLiteral(
"Scheduled auth db remove on thread close" ), 2 );
139 QMetaObject::Connection connection = connect( QThread::currentThread(), &QThread::finished, QThread::currentThread(), [connectionName,
this ]
141 QMutexLocker locker( mMutex );
142 QSqlDatabase::removeDatabase( connectionName );
143 mConnectedThreads.remove( QThread::currentThread() );
144 }, Qt::DirectConnection );
146 mConnectedThreads.insert( QThread::currentThread(), connection );
152 authdb = QSqlDatabase::database( connectionName );
156 if ( !authdb.isOpen() )
158 if ( !authdb.open() )
160 const char *err = QT_TR_NOOP(
"Opening of authentication db FAILED" );
175 QgsDebugMsg( QStringLiteral(
"Initializing QCA..." ) );
176 mQcaInitializer = qgis::make_unique<QCA::Initializer>( QCA::Practical, 256 );
178 QgsDebugMsg( QStringLiteral(
"QCA initialized." ) );
179 QCA::scanForPlugins();
181 QgsDebugMsg( QStringLiteral(
"QCA Plugin Diagnostics Context: %1" ).arg( QCA::pluginDiagnosticText() ) );
182 QStringList capabilities;
184 capabilities = QCA::supportedFeatures();
185 QgsDebugMsg( QStringLiteral(
"QCA supports: %1" ).arg( capabilities.join(
"," ) ) );
188 if ( !QCA::isSupported(
"cert", QStringLiteral(
"qca-ossl" ) ) )
190 mAuthDisabled =
true;
191 mAuthDisabledMessage = tr(
"QCA's OpenSSL plugin (qca-ossl) is missing" );
195 QgsDebugMsg( QStringLiteral(
"Prioritizing qca-ossl over all other QCA providers..." ) );
196 const QCA::ProviderList provds = QCA::providers();
198 for ( QCA::Provider *p : provds )
200 QString pn = p->name();
202 if ( pn != QLatin1String(
"qca-ossl" ) )
204 pr = QCA::providerPriority( pn ) + 1;
206 QCA::setProviderPriority( pn, pr );
207 prlist << QStringLiteral(
"%1:%2" ).arg( pn ).arg( QCA::providerPriority( pn ) );
209 QgsDebugMsg( QStringLiteral(
"QCA provider priorities: %1" ).arg( prlist.join(
", " ) ) );
211 QgsDebugMsg( QStringLiteral(
"Populating auth method registry" ) );
216 QgsDebugMsg( QStringLiteral(
"Authentication methods found: %1" ).arg( methods.join(
", " ) ) );
218 if ( methods.isEmpty() )
220 mAuthDisabled =
true;
221 mAuthDisabledMessage = tr(
"No authentication method plugins found" );
227 mAuthDisabled =
true;
228 mAuthDisabledMessage = tr(
"No authentication method plugins could be loaded" );
232 mAuthDbPath = QDir::cleanPath( authDatabasePath );
236 QFileInfo dbdirinfo( dbinfo.path() );
237 QgsDebugMsg( QStringLiteral(
"Auth db directory path: %1" ).arg( dbdirinfo.filePath() ) );
239 if ( !dbdirinfo.exists() )
241 QgsDebugMsg( QStringLiteral(
"Auth db directory path does not exist, making path: %1" ).arg( dbdirinfo.filePath() ) );
242 if ( !QDir().mkpath( dbdirinfo.filePath() ) )
244 const char *err = QT_TR_NOOP(
"Auth db directory path could not be created" );
251 if ( dbinfo.exists() )
253 if ( !dbinfo.permission( QFile::ReadOwner | QFile::WriteOwner ) )
255 const char *err = QT_TR_NOOP(
"Auth db is not readable or writable by user" );
260 if ( dbinfo.size() > 0 )
262 QgsDebugMsg( QStringLiteral(
"Auth db exists and has data" ) );
264 if ( !createCertTables() )
274 const char *passenv =
"QGIS_AUTH_PASSWORD_FILE";
277 QString passpath( getenv( passenv ) );
286 QFile passfile( passpath );
287 if ( passfile.exists() && passfile.open( QIODevice::ReadOnly | QIODevice::Text ) )
289 QTextStream passin( &passfile );
290 while ( !passin.atEnd() )
292 masterpass = passin.readLine();
297 if ( !masterpass.isEmpty() )
301 QgsDebugMsg( QStringLiteral(
"Authentication master password set from QGIS_AUTH_PASSWORD_FILE" ) );
305 QgsDebugMsg(
"QGIS_AUTH_PASSWORD_FILE set, but FAILED to set password using: " + passpath );
311 QgsDebugMsg(
"QGIS_AUTH_PASSWORD_FILE set, but FAILED to read password from: " + passpath );
321 QgsDebugMsg( QStringLiteral(
"Auth db does not exist: creating through QSqlDatabase initial connection" ) );
323 if ( !createConfigTables() )
326 if ( !createCertTables() )
337 bool QgsAuthManager::createConfigTables()
339 QMutexLocker locker( mMutex );
343 const char *err = QT_TR_NOOP(
"Auth db could not be created and opened" );
354 qstr = QStringLiteral(
"CREATE TABLE %1 (\n" 355 " 'salt' TEXT NOT NULL,\n" 356 " 'civ' TEXT NOT NULL\n" 357 ", 'hash' TEXT NOT NULL);" ).arg( authDbPassTable() );
358 query.prepare( qstr );
359 if ( !authDbQuery( &query ) )
363 qstr = QStringLiteral(
"CREATE TABLE %1 (\n" 364 " 'id' TEXT NOT NULL,\n" 365 " 'name' TEXT NOT NULL,\n" 367 " 'type' TEXT NOT NULL,\n" 368 " 'version' INTEGER NOT NULL\n" 370 query.prepare( qstr );
371 if ( !authDbQuery( &query ) )
376 query.prepare( qstr );
377 if ( !authDbQuery( &query ) )
382 query.prepare( qstr );
383 if ( !authDbQuery( &query ) )
390 bool QgsAuthManager::createCertTables()
392 QMutexLocker locker( mMutex );
394 QgsDebugMsg( QStringLiteral(
"Creating cert tables in auth db" ) );
401 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n" 402 " 'setting' TEXT NOT NULL\n" 403 ", 'value' TEXT);" ).arg( authDbSettingsTable() );
404 query.prepare( qstr );
405 if ( !authDbQuery( &query ) )
410 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n" 411 " 'id' TEXT NOT NULL,\n" 412 " 'key' TEXT NOT NULL\n" 413 ", 'cert' TEXT NOT NULL);" ).arg( authDbIdentitiesTable() );
414 query.prepare( qstr );
415 if ( !authDbQuery( &query ) )
419 qstr = QStringLiteral(
"CREATE UNIQUE INDEX IF NOT EXISTS 'id_index' on %1 (id ASC);" ).arg( authDbIdentitiesTable() );
420 query.prepare( qstr );
421 if ( !authDbQuery( &query ) )
426 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n" 427 " 'id' TEXT NOT NULL,\n" 428 " 'host' TEXT NOT NULL,\n" 431 query.prepare( qstr );
432 if ( !authDbQuery( &query ) )
436 qstr = QStringLiteral(
"CREATE UNIQUE INDEX IF NOT EXISTS 'host_index' on %1 (host ASC);" ).arg(
authDatabaseServersTable() );
437 query.prepare( qstr );
438 if ( !authDbQuery( &query ) )
443 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n" 444 " 'id' TEXT NOT NULL\n" 445 ", 'cert' TEXT NOT NULL);" ).arg( authDbAuthoritiesTable() );
446 query.prepare( qstr );
447 if ( !authDbQuery( &query ) )
451 qstr = QStringLiteral(
"CREATE UNIQUE INDEX IF NOT EXISTS 'id_index' on %1 (id ASC);" ).arg( authDbAuthoritiesTable() );
452 query.prepare( qstr );
453 if ( !authDbQuery( &query ) )
457 qstr = QStringLiteral(
"CREATE TABLE IF NOT EXISTS %1 (\n" 458 " 'id' TEXT NOT NULL\n" 459 ", 'policy' TEXT NOT NULL);" ).arg( authDbTrustTable() );
460 query.prepare( qstr );
461 if ( !authDbQuery( &query ) )
465 qstr = QStringLiteral(
"CREATE UNIQUE INDEX IF NOT EXISTS 'id_index' on %1 (id ASC);" ).arg( authDbTrustTable() );
466 query.prepare( qstr );
467 if ( !authDbQuery( &query ) )
478 QgsDebugMsg( QStringLiteral(
"Authentication system DISABLED: QCA's qca-ossl (OpenSSL) plugin is missing" ) );
480 return mAuthDisabled;
485 return tr(
"Authentication system is DISABLED:\n%1" ).arg( mAuthDisabledMessage );
490 QMutexLocker locker( mMutex );
494 if ( mScheduledDbErase )
497 if ( mMasterPass.isEmpty() )
499 QgsDebugMsg( QStringLiteral(
"Master password is not yet set by user" ) );
500 if ( !masterPasswordInput() )
502 QgsDebugMsg( QStringLiteral(
"Master password input canceled by user" ) );
508 QgsDebugMsg( QStringLiteral(
"Master password is set" ) );
516 QgsDebugMsg( QStringLiteral(
"Master password is set and verified" ) );
522 QMutexLocker locker( mMutex );
526 if ( mScheduledDbErase )
530 QString prevpass = QString( mMasterPass );
534 mMasterPass = prevpass;
535 const char *err = QT_TR_NOOP(
"Master password set: FAILED to verify, reset to previous" );
541 QgsDebugMsg( QStringLiteral(
"Master password set: SUCCESS%1" ).arg( verify ?
" and verified" :
"" ) );
551 if ( !masterPasswordRowsInDb( &rows ) )
553 const char *err = QT_TR_NOOP(
"Master password: FAILED to access database" );
561 QgsDebugMsg( QStringLiteral(
"Master password: %1 rows in database" ).arg( rows ) );
565 const char *err = QT_TR_NOOP(
"Master password: FAILED to find just one master password record in database" );
572 else if ( rows == 1 )
574 if ( !masterPasswordCheckAgainstDb( compare ) )
576 if ( compare.isNull() )
578 const char *err = QT_TR_NOOP(
"Master password: FAILED to verify against hash in database" );
587 if ( mPassTries >= 5 )
589 mAuthDisabled =
true;
590 const char *err = QT_TR_NOOP(
"Master password: failed 5 times authentication system DISABLED" );
598 QgsDebugMsg( QStringLiteral(
"Master password: verified against hash in database" ) );
599 if ( compare.isNull() )
603 else if ( compare.isNull() )
605 if ( !masterPasswordStoreInDb() )
607 const char *err = QT_TR_NOOP(
"Master password: hash FAILED to be stored in database" );
616 QgsDebugMsg( QStringLiteral(
"Master password: hash stored in database" ) );
619 if ( !masterPasswordCheckAgainstDb() )
621 const char *err = QT_TR_NOOP(
"Master password: FAILED to verify against hash in database" );
631 QgsDebugMsg( QStringLiteral(
"Master password: verified against hash in database" ) );
641 return !mMasterPass.isEmpty();
646 return mMasterPass == pass;
650 bool keepbackup, QString *backuppath )
664 QgsDebugMsg( QStringLiteral(
"Master password reset: backed up current database" ) );
670 QString prevpass = QString( mMasterPass );
671 QString prevciv = QString( masterPasswordCiv() );
677 if ( ok && !masterPasswordClearDb() )
680 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not clear current password from database" );
686 QgsDebugMsg( QStringLiteral(
"Master password reset: cleared current password from database" ) );
693 if ( ok && !masterPasswordStoreInDb() )
696 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not store new password in database" );
702 QgsDebugMsg( QStringLiteral(
"Master password reset: stored new password in database" ) );
709 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not verify new password in database" );
715 if ( ok && !reencryptAllAuthenticationConfigs( prevpass, prevciv ) )
718 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not re-encrypt configs in database" );
724 QgsDebugMsg( QStringLiteral(
"Master password reset: re-encrypted configs in database" ) );
728 if ( ok && !verifyPasswordCanDecryptConfigs() )
731 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not verify password can decrypt re-encrypted configs" );
736 if ( ok && !reencryptAllAuthenticationSettings( prevpass, prevciv ) )
739 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not re-encrypt settings in database" );
744 if ( ok && !reencryptAllAuthenticationIdentities( prevpass, prevciv ) )
747 const char *err = QT_TR_NOOP(
"Master password reset FAILED: could not re-encrypt identities in database" );
757 QString errdbbackup( dbbackup );
758 errdbbackup.replace( QLatin1String(
".db" ), QLatin1String(
"_ERROR.db" ) );
760 QgsDebugMsg( QStringLiteral(
"Master password reset FAILED: backed up failed db at %1" ).arg( errdbbackup ) );
764 mMasterPass = prevpass;
766 QgsDebugMsg( QStringLiteral(
"Master password reset FAILED: reinstated previous password and database" ) );
770 *backuppath = errdbbackup;
776 if ( !keepbackup && !QFile::remove( dbbackup ) )
778 const char *err = QT_TR_NOOP(
"Master password reset: could not remove old database backup" );
786 QgsDebugMsg( QStringLiteral(
"Master password reset: backed up previous db at %1" ).arg( dbbackup ) );
788 *backuppath = dbbackup;
791 QgsDebugMsg( QStringLiteral(
"Master password reset: SUCCESS" ) );
798 mScheduledDbErase = scheduleErase;
800 mScheduledDbEraseRequestEmitted =
false;
801 mScheduledDbEraseRequestCount = 0;
805 if ( !mScheduledDbEraseTimer )
807 mScheduledDbEraseTimer =
new QTimer(
this );
808 connect( mScheduledDbEraseTimer, &QTimer::timeout,
this, &QgsAuthManager::tryToStartDbErase );
809 mScheduledDbEraseTimer->start( mScheduledDbEraseRequestWait * 1000 );
811 else if ( !mScheduledDbEraseTimer->isActive() )
813 mScheduledDbEraseTimer->start();
818 if ( mScheduledDbEraseTimer && mScheduledDbEraseTimer->isActive() )
819 mScheduledDbEraseTimer->stop();
828 qDeleteAll( mAuthMethods );
829 mAuthMethods.clear();
831 for (
const auto &authMethodKey : methods )
836 return !mAuthMethods.isEmpty();
846 QTimer::singleShot( 3, &loop, &QEventLoop::quit );
849 uint seed =
static_cast< uint
>( QTime::currentTime().msec() );
855 for (
int i = 0; i < len; i++ )
857 switch ( qrand() % 2 )
860 id += (
'0' + qrand() % 10 );
863 id += (
'a' + qrand() % 26 );
867 if ( !configids.contains(
id ) )
872 QgsDebugMsg( QStringLiteral(
"Generated unique ID: %1" ).arg(
id ) );
883 const char *err = QT_TR_NOOP(
"Config ID is empty" );
889 return !configids.contains(
id );
894 QRegExp rx( AUTH_CFG_REGEX );
895 return rx.indexIn( txt ) != -1;
900 QMutexLocker locker( mMutex );
901 QStringList providerAuthMethodsKeys;
902 if ( !dataprovider.isEmpty() )
913 query.prepare( QStringLiteral(
"SELECT id, name, uri, type, version FROM %1" ).arg(
authDatabaseConfigTable() ) );
915 if ( !authDbQuery( &query ) )
920 if ( query.isActive() && query.isSelect() )
922 while ( query.next() )
924 QString authcfg = query.value( 0 ).toString();
926 config.
setId( authcfg );
927 config.
setName( query.value( 1 ).toString() );
928 config.
setUri( query.value( 2 ).toString() );
929 config.
setMethod( query.value( 3 ).toString() );
930 config.
setVersion( query.value( 4 ).toInt() );
932 if ( !dataprovider.isEmpty() && !providerAuthMethodsKeys.contains( config.
method() ) )
937 baseConfigs.insert( authcfg, config );
945 QMutexLocker locker( mMutex );
952 if ( !authDbQuery( &query ) )
957 if ( query.isActive() )
959 QgsDebugMsg( QStringLiteral(
"Syncing existing auth config and their auth methods" ) );
960 mConfigAuthMethods.clear();
961 QStringList cfgmethods;
962 while ( query.next() )
964 mConfigAuthMethods.insert( query.value( 0 ).toString(),
965 query.value( 1 ).toString() );
966 cfgmethods << QStringLiteral(
"%1=%2" ).arg( query.value( 0 ).toString(), query.value( 1 ).toString() );
968 QgsDebugMsg( QStringLiteral(
"Stored auth config/methods:\n%1" ).arg( cfgmethods.join(
", " ) ) );
977 if ( !mConfigAuthMethods.contains( authcfg ) )
979 QgsDebugMsg( QStringLiteral(
"No config auth method found in database for authcfg: %1" ).arg( authcfg ) );
983 QString authMethodKey = mConfigAuthMethods.value( authcfg );
993 return mConfigAuthMethods.value( authcfg, QString() );
1004 if ( !mAuthMethods.contains( authMethodKey ) )
1006 QgsDebugMsg( QStringLiteral(
"No auth method registered for auth method key: %1" ).arg( authMethodKey ) );
1010 return mAuthMethods.value( authMethodKey );
1015 if ( dataprovider.isEmpty() )
1017 return mAuthMethods;
1021 QgsAuthMethodsMap::const_iterator i = mAuthMethods.constBegin();
1022 while ( i != mAuthMethods.constEnd() )
1025 && ( i.value()->supportedDataProviders().contains( QStringLiteral(
"all" ) )
1026 || i.value()->supportedDataProviders().contains( dataprovider ) ) )
1028 filteredmap.insert( i.key(), i.value() );
1043 return QgsAuthMethod::Expansions(
nullptr );
1050 return QgsAuthMethod::Expansions(
nullptr );
1055 QMutexLocker locker( mMutex );
1062 const char *err = QT_TR_NOOP(
"Store config: FAILED because config is invalid" );
1068 QString uid = mconfig.
id();
1069 bool passedinID = !uid.isEmpty();
1070 if ( uid.isEmpty() )
1076 const char *err = QT_TR_NOOP(
"Store config: FAILED because pre-defined config ID is not unique" );
1083 if ( configstring.isEmpty() )
1085 const char *err = QT_TR_NOOP(
"Store config: FAILED because config string is empty" );
1091 QgsDebugMsg( QStringLiteral(
"authDbConfigTable(): %1" ).arg( authDbConfigTable() ) );
1092 QgsDebugMsg( QStringLiteral(
"name: %1" ).arg( config.name() ) );
1093 QgsDebugMsg( QStringLiteral(
"uri: %1" ).arg( config.uri() ) );
1094 QgsDebugMsg( QStringLiteral(
"type: %1" ).arg( config.method() ) );
1095 QgsDebugMsg( QStringLiteral(
"version: %1" ).arg( config.version() ) );
1096 QgsDebugMsg( QStringLiteral(
"config: %1" ).arg( configstring ) );
1100 query.prepare( QStringLiteral(
"INSERT INTO %1 (id, name, uri, type, version, config) " 1103 query.bindValue( QStringLiteral(
":id" ), uid );
1104 query.bindValue( QStringLiteral(
":name" ), mconfig.
name() );
1105 query.bindValue( QStringLiteral(
":uri" ), mconfig.
uri() );
1106 query.bindValue( QStringLiteral(
":type" ), mconfig.
method() );
1107 query.bindValue( QStringLiteral(
":version" ), mconfig.
version() );
1108 query.bindValue( QStringLiteral(
":config" ),
QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
1110 if ( !authDbStartTransaction() )
1113 if ( !authDbQuery( &query ) )
1116 if ( !authDbCommit() )
1121 mconfig.
setId( uid );
1125 QgsDebugMsg( QStringLiteral(
"Store config SUCCESS for authcfg: %1" ).arg( uid ) );
1132 QMutexLocker locker( mMutex );
1137 if ( !config.
isValid(
true ) )
1139 const char *err = QT_TR_NOOP(
"Update config: FAILED because config is invalid" );
1146 if ( configstring.isEmpty() )
1148 const char *err = QT_TR_NOOP(
"Update config: FAILED because config is empty" );
1155 QgsDebugMsg( QStringLiteral(
"authDbConfigTable(): %1" ).arg( authDbConfigTable() ) );
1156 QgsDebugMsg( QStringLiteral(
"id: %1" ).arg( config.
id() ) );
1161 QgsDebugMsg( QStringLiteral(
"config: %1" ).arg( configstring ) );
1165 if ( !query.prepare( QStringLiteral(
"UPDATE %1 " 1166 "SET name = :name, uri = :uri, type = :type, version = :version, config = :config " 1169 const char *err = QT_TR_NOOP(
"Update config: FAILED to prepare query" );
1175 query.bindValue( QStringLiteral(
":id" ), config.
id() );
1176 query.bindValue( QStringLiteral(
":name" ), config.
name() );
1177 query.bindValue( QStringLiteral(
":uri" ), config.
uri() );
1178 query.bindValue( QStringLiteral(
":type" ), config.
method() );
1179 query.bindValue( QStringLiteral(
":version" ), config.
version() );
1180 query.bindValue( QStringLiteral(
":config" ),
QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
1182 if ( !authDbStartTransaction() )
1185 if ( !authDbQuery( &query ) )
1188 if ( !authDbCommit() )
1196 QgsDebugMsg( QStringLiteral(
"Update config SUCCESS for authcfg: %1" ).arg( config.
id() ) );
1203 QMutexLocker locker( mMutex );
1213 query.prepare( QStringLiteral(
"SELECT id, name, uri, type, version, config FROM %1 " 1218 query.prepare( QStringLiteral(
"SELECT id, name, uri, type, version FROM %1 " 1222 query.bindValue( QStringLiteral(
":id" ), authcfg );
1224 if ( !authDbQuery( &query ) )
1229 if ( query.isActive() && query.isSelect() )
1231 if ( query.first() )
1233 mconfig.
setId( query.value( 0 ).toString() );
1234 mconfig.
setName( query.value( 1 ).toString() );
1235 mconfig.
setUri( query.value( 2 ).toString() );
1236 mconfig.
setMethod( query.value( 3 ).toString() );
1237 mconfig.
setVersion( query.value( 4 ).toInt() );
1252 QgsDebugMsg( QStringLiteral(
"Update of authcfg %1 FAILED for auth method %2" ).arg( authcfg, authMethodKey ) );
1255 QgsDebugMsg( QStringLiteral(
"Load %1 config SUCCESS for authcfg: %2" ).arg( full ?
"full" :
"base", authcfg ) );
1260 QgsDebugMsg( QStringLiteral(
"Select contains more than one for authcfg: %1" ).arg( authcfg ) );
1270 QMutexLocker locker( mMutex );
1274 if ( authcfg.isEmpty() )
1281 query.bindValue( QStringLiteral(
":id" ), authcfg );
1283 if ( !authDbStartTransaction() )
1286 if ( !authDbQuery( &query ) )
1289 if ( !authDbCommit() )
1296 QgsDebugMsg( QStringLiteral(
"REMOVED config for authcfg: %1" ).arg( authcfg ) );
1303 QMutexLocker locker( mMutex );
1309 bool res = authDbTransactionQuery( &query );
1317 QgsDebugMsg( QStringLiteral(
"Remove configs from database: %1" ).arg( res ?
"SUCCEEDED" :
"FAILED" ) );
1324 QMutexLocker locker( mMutex );
1327 const char *err = QT_TR_NOOP(
"No authentication database found" );
1335 if ( authConn.isValid() && authConn.isOpen() )
1339 QString datestamp( QDateTime::currentDateTime().toString( QStringLiteral(
"yyyy-MM-dd-hhmmss" ) ) );
1341 dbbackup.replace( QLatin1String(
".db" ), QStringLiteral(
"_%1.db" ).arg( datestamp ) );
1345 const char *err = QT_TR_NOOP(
"Could not back up authentication database" );
1352 *backuppath = dbbackup;
1354 QgsDebugMsg( QStringLiteral(
"Backed up auth database at %1" ).arg( dbbackup ) );
1360 QMutexLocker locker( mMutex );
1370 if ( backuppath && !dbbackup.isEmpty() )
1371 *backuppath = dbbackup;
1374 if ( dbinfo.exists() )
1376 if ( !dbinfo.permission( QFile::ReadOwner | QFile::WriteOwner ) )
1378 const char *err = QT_TR_NOOP(
"Auth db is not readable or writable by user" );
1386 const char *err = QT_TR_NOOP(
"No authentication database found" );
1394 const char *err = QT_TR_NOOP(
"Authentication database could not be deleted" );
1400 mMasterPass = QString();
1402 QgsDebugMsg( QStringLiteral(
"Creating Auth db through QSqlDatabase initial connection" ) );
1405 if ( !authConn.isValid() || !authConn.isOpen() )
1407 const char *err = QT_TR_NOOP(
"Authentication database could not be initialized" );
1413 if ( !createConfigTables() )
1415 const char *err = QT_TR_NOOP(
"FAILED to create auth database config tables" );
1421 if ( !createCertTables() )
1423 const char *err = QT_TR_NOOP(
"FAILED to create auth database cert tables" );
1439 const QString &dataprovider )
1449 QgsDebugMsg( QStringLiteral(
"Network request updating not supported by authcfg: %1" ).arg( authcfg ) );
1464 const QString &dataprovider )
1474 QgsDebugMsg( QStringLiteral(
"Network reply updating not supported by authcfg: %1" ).arg( authcfg ) );
1490 const QString &dataprovider )
1500 QgsDebugMsg( QStringLiteral(
"Data source URI updating not supported by authcfg: %1" ).arg( authcfg ) );
1525 QgsDebugMsg( QStringLiteral(
"Proxy updating not supported by authcfg: %1" ).arg( authcfg ) );
1534 QgsDebugMsg( QStringLiteral(
"Proxy updated successfully from authcfg: %1" ).arg( authcfg ) );
1543 QMutexLocker locker( mMutex );
1544 if ( key.isEmpty() )
1547 QString storeval( value.toString() );
1563 query.prepare( QStringLiteral(
"INSERT INTO %1 (setting, value) " 1564 "VALUES (:setting, :value)" ).arg( authDbSettingsTable() ) );
1566 query.bindValue( QStringLiteral(
":setting" ), key );
1567 query.bindValue( QStringLiteral(
":value" ), storeval );
1569 if ( !authDbStartTransaction() )
1572 if ( !authDbQuery( &query ) )
1575 if ( !authDbCommit() )
1578 QgsDebugMsg( QStringLiteral(
"Store setting SUCCESS for key: %1" ).arg( key ) );
1584 QMutexLocker locker( mMutex );
1585 if ( key.isEmpty() )
1591 QVariant value = defaultValue;
1593 query.prepare( QStringLiteral(
"SELECT value FROM %1 " 1594 "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
1596 query.bindValue( QStringLiteral(
":setting" ), key );
1598 if ( !authDbQuery( &query ) )
1601 if ( query.isActive() && query.isSelect() )
1603 if ( query.first() )
1607 value = QVariant(
QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 0 ).toString() ) );
1611 value = query.value( 0 );
1613 QgsDebugMsg( QStringLiteral(
"Authentication setting retrieved for key: %1" ).arg( key ) );
1617 QgsDebugMsg( QStringLiteral(
"Select contains more than one for setting key: %1" ).arg( key ) );
1627 QMutexLocker locker( mMutex );
1628 if ( key.isEmpty() )
1632 query.prepare( QStringLiteral(
"SELECT value FROM %1 " 1633 "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
1635 query.bindValue( QStringLiteral(
":setting" ), key );
1637 if ( !authDbQuery( &query ) )
1641 if ( query.isActive() && query.isSelect() )
1643 if ( query.first() )
1645 QgsDebugMsg( QStringLiteral(
"Authentication setting exists for key: %1" ).arg( key ) );
1650 QgsDebugMsg( QStringLiteral(
"Select contains more than one for setting key: %1" ).arg( key ) );
1660 QMutexLocker locker( mMutex );
1661 if ( key.isEmpty() )
1666 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
1668 query.bindValue( QStringLiteral(
":setting" ), key );
1670 if ( !authDbStartTransaction() )
1673 if ( !authDbQuery( &query ) )
1676 if ( !authDbCommit() )
1679 QgsDebugMsg( QStringLiteral(
"REMOVED setting for key: %1" ).arg( key ) );
1691 QMutexLocker locker( mMutex );
1697 mCustomConfigByHostCache.clear();
1698 mHasCheckedIfCustomConfigByHostExists =
false;
1700 QgsDebugMsg( QStringLiteral(
"Init of SSL caches %1" ).arg( res ?
"SUCCEEDED" :
"FAILED" ) );
1706 QMutexLocker locker( mMutex );
1707 if ( cert.isNull() )
1709 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
1714 QgsDebugMsg( QStringLiteral(
"Passed private key is null" ) );
1724 QString certpem( cert.toPem() );
1728 query.prepare( QStringLiteral(
"INSERT INTO %1 (id, key, cert) " 1729 "VALUES (:id, :key, :cert)" ).arg( authDbIdentitiesTable() ) );
1731 query.bindValue( QStringLiteral(
":id" ),
id );
1732 query.bindValue( QStringLiteral(
":key" ), keypem );
1733 query.bindValue( QStringLiteral(
":cert" ), certpem );
1735 if ( !authDbStartTransaction() )
1738 if ( !authDbQuery( &query ) )
1741 if ( !authDbCommit() )
1744 QgsDebugMsg( QStringLiteral(
"Store certificate identity SUCCESS for id: %1" ).arg(
id ) );
1750 QMutexLocker locker( mMutex );
1751 QSslCertificate emptycert;
1752 QSslCertificate cert;
1757 query.prepare( QStringLiteral(
"SELECT cert FROM %1 " 1758 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1760 query.bindValue( QStringLiteral(
":id" ),
id );
1762 if ( !authDbQuery( &query ) )
1765 if ( query.isActive() && query.isSelect() )
1767 if ( query.first() )
1769 cert = QSslCertificate( query.value( 0 ).toByteArray(), QSsl::Pem );
1770 QgsDebugMsg( QStringLiteral(
"Certificate identity retrieved for id: %1" ).arg(
id ) );
1774 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate identity for id: %1" ).arg(
id ) );
1784 QMutexLocker locker( mMutex );
1785 QPair<QSslCertificate, QSslKey> bundle;
1793 query.prepare( QStringLiteral(
"SELECT key, cert FROM %1 " 1794 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1796 query.bindValue( QStringLiteral(
":id" ),
id );
1798 if ( !authDbQuery( &query ) )
1801 if ( query.isActive() && query.isSelect() )
1803 QSslCertificate cert;
1805 if ( query.first() )
1807 key = QSslKey(
QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 0 ).toString() ).toLatin1(),
1808 QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey );
1811 const char *err = QT_TR_NOOP(
"Retrieve certificate identity bundle: FAILED to create private key" );
1816 cert = QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
1817 if ( cert.isNull() )
1819 const char *err = QT_TR_NOOP(
"Retrieve certificate identity bundle: FAILED to create certificate" );
1824 QgsDebugMsg( QStringLiteral(
"Certificate identity bundle retrieved for id: %1" ).arg(
id ) );
1828 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate identity for id: %1" ).arg(
id ) );
1832 bundle = qMakePair( cert, key );
1839 QMutexLocker locker( mMutex );
1843 return QStringList() << QString( bundle.first.toPem() ) << QString( bundle.second.toPem() );
1845 return QStringList();
1850 QMutexLocker locker( mMutex );
1851 QList<QSslCertificate> certs;
1854 query.prepare( QStringLiteral(
"SELECT id, cert FROM %1" ).arg( authDbIdentitiesTable() ) );
1856 if ( !authDbQuery( &query ) )
1859 if ( query.isActive() && query.isSelect() )
1861 while ( query.next() )
1863 certs << QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
1872 QMutexLocker locker( mMutex );
1873 QStringList identityids = QStringList();
1879 query.prepare( QStringLiteral(
"SELECT id FROM %1" ).arg( authDbIdentitiesTable() ) );
1881 if ( !authDbQuery( &query ) )
1886 if ( query.isActive() )
1888 while ( query.next() )
1890 identityids << query.value( 0 ).toString();
1898 QMutexLocker locker( mMutex );
1903 query.prepare( QStringLiteral(
"SELECT cert FROM %1 " 1904 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1906 query.bindValue( QStringLiteral(
":id" ),
id );
1908 if ( !authDbQuery( &query ) )
1912 if ( query.isActive() && query.isSelect() )
1914 if ( query.first() )
1916 QgsDebugMsg( QStringLiteral(
"Certificate bundle exists for id: %1" ).arg(
id ) );
1921 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate bundle for id: %1" ).arg(
id ) );
1931 QMutexLocker locker( mMutex );
1934 QgsDebugMsg( QStringLiteral(
"Passed bundle ID is empty" ) );
1940 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1942 query.bindValue( QStringLiteral(
":id" ),
id );
1944 if ( !authDbStartTransaction() )
1947 if ( !authDbQuery( &query ) )
1950 if ( !authDbCommit() )
1953 QgsDebugMsg( QStringLiteral(
"REMOVED certificate identity for id: %1" ).arg(
id ) );
1959 QMutexLocker locker( mMutex );
1962 QgsDebugMsg( QStringLiteral(
"Passed config is null" ) );
1971 QString certpem( cert.toPem() );
1974 query.prepare( QStringLiteral(
"INSERT OR REPLACE INTO %1 (id, host, cert, config) " 1977 query.bindValue( QStringLiteral(
":id" ),
id );
1978 query.bindValue( QStringLiteral(
":host" ), config.
sslHostPort().trimmed() );
1979 query.bindValue( QStringLiteral(
":cert" ), certpem );
1980 query.bindValue( QStringLiteral(
":config" ), config.
configString() );
1982 if ( !authDbStartTransaction() )
1985 if ( !authDbQuery( &query ) )
1988 if ( !authDbCommit() )
1991 QgsDebugMsg( QStringLiteral(
"Store SSL cert custom config SUCCESS for host:port, id: %1, %2" )
1995 mHasCheckedIfCustomConfigByHostExists =
false;
1996 mCustomConfigByHostCache.clear();
2003 QMutexLocker locker( mMutex );
2006 if (
id.isEmpty() || hostport.isEmpty() )
2008 QgsDebugMsg( QStringLiteral(
"Passed config ID or host:port is empty" ) );
2013 query.prepare( QStringLiteral(
"SELECT id, host, cert, config FROM %1 " 2016 query.bindValue( QStringLiteral(
":id" ),
id );
2017 query.bindValue( QStringLiteral(
":host" ), hostport.trimmed() );
2019 if ( !authDbQuery( &query ) )
2022 if ( query.isActive() && query.isSelect() )
2024 if ( query.first() )
2026 config.
setSslCertificate( QSslCertificate( query.value( 2 ).toByteArray(), QSsl::Pem ) );
2029 QgsDebugMsg( QStringLiteral(
"SSL cert custom config retrieved for host:port, id: %1, %2" ).arg( hostport,
id ) );
2033 QgsDebugMsg( QStringLiteral(
"Select contains more than one SSL cert custom config for host:port, id: %1, %2" ).arg( hostport,
id ) );
2034 emit
messageOut( tr(
"Authentication database contains duplicate SSL cert custom configs for host:port, id: %1, %2" )
2046 if ( hostport.isEmpty() )
2051 QMutexLocker locker( mMutex );
2052 if ( mHasCheckedIfCustomConfigByHostExists && !mHasCustomConfigByHost )
2054 if ( mCustomConfigByHostCache.contains( hostport ) )
2055 return mCustomConfigByHostCache.value( hostport );
2060 if ( !mHasCheckedIfCustomConfigByHostExists )
2062 mHasCheckedIfCustomConfigByHostExists =
true;
2064 if ( !authDbQuery( &query ) )
2066 mHasCustomConfigByHost =
false;
2069 if ( query.isActive() && query.isSelect() && query.first() )
2071 mHasCustomConfigByHost = query.value( 0 ).toInt() > 0;
2072 if ( !mHasCustomConfigByHost )
2077 mHasCustomConfigByHost =
false;
2082 query.prepare( QString(
"SELECT id, host, cert, config FROM %1 " 2085 query.bindValue( QStringLiteral(
":host" ), hostport.trimmed() );
2087 if ( !authDbQuery( &query ) )
2089 mCustomConfigByHostCache.insert( hostport, config );
2093 if ( query.isActive() && query.isSelect() )
2095 if ( query.first() )
2097 config.
setSslCertificate( QSslCertificate( query.value( 2 ).toByteArray(), QSsl::Pem ) );
2100 QgsDebugMsg( QStringLiteral(
"SSL cert custom config retrieved for host:port: %1" ).arg( hostport ) );
2104 QgsDebugMsg( QStringLiteral(
"Select contains more than one SSL cert custom config for host:port: %1" ).arg( hostport ) );
2105 emit
messageOut( tr(
"Authentication database contains duplicate SSL cert custom configs for host:port: %1" )
2108 mCustomConfigByHostCache.insert( hostport, emptyconfig );
2113 mCustomConfigByHostCache.insert( hostport, config );
2119 QMutexLocker locker( mMutex );
2120 QList<QgsAuthConfigSslServer> configs;
2125 if ( !authDbQuery( &query ) )
2128 if ( query.isActive() && query.isSelect() )
2130 while ( query.next() )
2133 config.
setSslCertificate( QSslCertificate( query.value( 2 ).toByteArray(), QSsl::Pem ) );
2137 configs.append( config );
2146 QMutexLocker locker( mMutex );
2147 if (
id.isEmpty() || hostport.isEmpty() )
2149 QgsDebugMsg( QStringLiteral(
"Passed config ID or host:port is empty" ) );
2154 query.prepare( QStringLiteral(
"SELECT cert FROM %1 " 2157 query.bindValue( QStringLiteral(
":id" ),
id );
2158 query.bindValue( QStringLiteral(
":host" ), hostport.trimmed() );
2160 if ( !authDbQuery( &query ) )
2164 if ( query.isActive() && query.isSelect() )
2166 if ( query.first() )
2168 QgsDebugMsg( QStringLiteral(
"SSL cert custom config exists for host:port, id: %1, %2" ).arg( hostport,
id ) );
2173 QgsDebugMsg( QStringLiteral(
"Select contains more than one SSL cert custom config for host:port, id: %1, %2" ).arg( hostport,
id ) );
2174 emit
messageOut( tr(
"Authentication database contains duplicate SSL cert custom configs for host:port, id: %1, %2" )
2184 QMutexLocker locker( mMutex );
2185 if (
id.isEmpty() || hostport.isEmpty() )
2187 QgsDebugMsg( QStringLiteral(
"Passed config ID or host:port is empty" ) );
2191 mHasCheckedIfCustomConfigByHostExists =
false;
2192 mCustomConfigByHostCache.clear();
2196 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE id = :id AND host = :host" ).arg(
authDatabaseServersTable() ) );
2198 query.bindValue( QStringLiteral(
":id" ),
id );
2199 query.bindValue( QStringLiteral(
":host" ), hostport.trimmed() );
2201 if ( !authDbStartTransaction() )
2204 if ( !authDbQuery( &query ) )
2207 if ( !authDbCommit() )
2210 QString shahostport( QStringLiteral(
"%1:%2" ).arg(
id, hostport ) );
2211 if ( mIgnoredSslErrorsCache.contains( shahostport ) )
2213 mIgnoredSslErrorsCache.remove( shahostport );
2216 QgsDebugMsg( QStringLiteral(
"REMOVED SSL cert custom config for host:port, id: %1, %2" ).arg( hostport,
id ) );
2223 QMutexLocker locker( mMutex );
2224 if ( !mIgnoredSslErrorsCache.isEmpty() )
2226 QgsDebugMsg( QStringLiteral(
"Ignored SSL errors cache items:" ) );
2227 QHash<QString, QSet<QSslError::SslError> >::const_iterator i = mIgnoredSslErrorsCache.constBegin();
2228 while ( i != mIgnoredSslErrorsCache.constEnd() )
2231 for (
auto err : i.value() )
2235 QgsDebugMsg( QStringLiteral(
"%1 = %2" ).arg( i.key(), errs.join(
", " ) ) );
2241 QgsDebugMsg( QStringLiteral(
"Ignored SSL errors cache EMPTY" ) );
2247 QMutexLocker locker( mMutex );
2250 QgsDebugMsg( QStringLiteral(
"Passed config is null" ) );
2254 QString shahostport( QStringLiteral(
"%1:%2" )
2257 if ( mIgnoredSslErrorsCache.contains( shahostport ) )
2259 mIgnoredSslErrorsCache.remove( shahostport );
2262 if ( !errenums.isEmpty() )
2264 mIgnoredSslErrorsCache.insert( shahostport, QSet<QSslError::SslError>::fromList( errenums ) );
2265 QgsDebugMsg( QStringLiteral(
"Update of ignored SSL errors cache SUCCEEDED for sha:host:port = %1" ).arg( shahostport ) );
2270 QgsDebugMsg( QStringLiteral(
"No ignored SSL errors to cache for sha:host:port = %1" ).arg( shahostport ) );
2276 QMutexLocker locker( mMutex );
2277 QRegExp rx(
"\\S+:\\S+:\\d+" );
2278 if ( !rx.exactMatch( shahostport ) )
2280 QgsDebugMsg(
"Passed shahostport does not match \\S+:\\S+:\\d+, " 2281 "e.g. 74a4ef5ea94512a43769b744cda0ca5049a72491:www.example.com:443" );
2285 if ( mIgnoredSslErrorsCache.contains( shahostport ) )
2287 mIgnoredSslErrorsCache.remove( shahostport );
2290 if ( errors.isEmpty() )
2292 QgsDebugMsg( QStringLiteral(
"Passed errors list empty" ) );
2296 QSet<QSslError::SslError> errs;
2297 for (
const auto &error : errors )
2299 if ( error.error() == QSslError::NoError )
2302 errs.insert( error.error() );
2305 if ( errs.isEmpty() )
2307 QgsDebugMsg( QStringLiteral(
"Passed errors list does not contain errors" ) );
2311 mIgnoredSslErrorsCache.insert( shahostport, errs );
2313 QgsDebugMsg( QStringLiteral(
"Update of ignored SSL errors cache SUCCEEDED for sha:host:port = %1" ).arg( shahostport ) );
2320 QMutexLocker locker( mMutex );
2321 QHash<QString, QSet<QSslError::SslError> > prevcache( mIgnoredSslErrorsCache );
2322 QHash<QString, QSet<QSslError::SslError> > nextcache;
2327 if ( !authDbQuery( &query ) )
2329 QgsDebugMsg( QStringLiteral(
"Rebuild of ignored SSL errors cache FAILED" ) );
2333 if ( query.isActive() && query.isSelect() )
2335 while ( query.next() )
2337 QString shahostport( QStringLiteral(
"%1:%2" )
2338 .arg( query.value( 0 ).toString().trimmed(),
2339 query.value( 1 ).toString().trimmed() ) );
2343 if ( !errenums.isEmpty() )
2345 nextcache.insert( shahostport, QSet<QSslError::SslError>::fromList( errenums ) );
2347 if ( prevcache.contains( shahostport ) )
2349 prevcache.remove( shahostport );
2354 if ( !prevcache.isEmpty() )
2357 QHash<QString, QSet<QSslError::SslError> >::const_iterator i = prevcache.constBegin();
2358 while ( i != prevcache.constEnd() )
2360 nextcache.insert( i.key(), i.value() );
2365 if ( nextcache != mIgnoredSslErrorsCache )
2367 mIgnoredSslErrorsCache.clear();
2368 mIgnoredSslErrorsCache = nextcache;
2369 QgsDebugMsg( QStringLiteral(
"Rebuild of ignored SSL errors cache SUCCEEDED" ) );
2374 QgsDebugMsg( QStringLiteral(
"Rebuild of ignored SSL errors cache SAME AS BEFORE" ) );
2382 QMutexLocker locker( mMutex );
2383 if ( certs.isEmpty() )
2385 QgsDebugMsg( QStringLiteral(
"Passed certificate list has no certs" ) );
2389 for (
const auto &cert : certs )
2399 QMutexLocker locker( mMutex );
2402 if ( cert.isNull() )
2404 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2411 QString pem( cert.toPem() );
2414 query.prepare( QStringLiteral(
"INSERT INTO %1 (id, cert) " 2415 "VALUES (:id, :cert)" ).arg( authDbAuthoritiesTable() ) );
2417 query.bindValue( QStringLiteral(
":id" ),
id );
2418 query.bindValue( QStringLiteral(
":cert" ), pem );
2420 if ( !authDbStartTransaction() )
2423 if ( !authDbQuery( &query ) )
2426 if ( !authDbCommit() )
2429 QgsDebugMsg( QStringLiteral(
"Store certificate authority SUCCESS for id: %1" ).arg(
id ) );
2435 QMutexLocker locker( mMutex );
2436 QSslCertificate emptycert;
2437 QSslCertificate cert;
2442 query.prepare( QStringLiteral(
"SELECT cert FROM %1 " 2443 "WHERE id = :id" ).arg( authDbAuthoritiesTable() ) );
2445 query.bindValue( QStringLiteral(
":id" ),
id );
2447 if ( !authDbQuery( &query ) )
2450 if ( query.isActive() && query.isSelect() )
2452 if ( query.first() )
2454 cert = QSslCertificate( query.value( 0 ).toByteArray(), QSsl::Pem );
2455 QgsDebugMsg( QStringLiteral(
"Certificate authority retrieved for id: %1" ).arg(
id ) );
2459 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate authority for id: %1" ).arg(
id ) );
2469 QMutexLocker locker( mMutex );
2470 if ( cert.isNull() )
2472 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2479 query.prepare( QStringLiteral(
"SELECT value FROM %1 " 2480 "WHERE id = :id" ).arg( authDbAuthoritiesTable() ) );
2482 query.bindValue( QStringLiteral(
":id" ),
id );
2484 if ( !authDbQuery( &query ) )
2488 if ( query.isActive() && query.isSelect() )
2490 if ( query.first() )
2492 QgsDebugMsg( QStringLiteral(
"Certificate authority exists for id: %1" ).arg(
id ) );
2497 QgsDebugMsg( QStringLiteral(
"Select contains more than one certificate authority for id: %1" ).arg(
id ) );
2507 QMutexLocker locker( mMutex );
2508 if ( cert.isNull() )
2510 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2518 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE id = :id" ).arg( authDbAuthoritiesTable() ) );
2520 query.bindValue( QStringLiteral(
":id" ),
id );
2522 if ( !authDbStartTransaction() )
2525 if ( !authDbQuery( &query ) )
2528 if ( !authDbCommit() )
2531 QgsDebugMsg( QStringLiteral(
"REMOVED authority for id: %1" ).arg(
id ) );
2537 return QSslConfiguration::systemCaCertificates();
2542 QMutexLocker locker( mMutex );
2543 QList<QSslCertificate> certs;
2544 QList<QSslCertificate> filecerts;
2546 if ( cafileval.isNull() )
2550 if ( allowinvalid.isNull() )
2553 QString cafile( cafileval.toString() );
2554 if ( !cafile.isEmpty() && QFile::exists( cafile ) )
2559 for (
const auto &cert : qgis::as_const( filecerts ) )
2561 if ( !allowinvalid.toBool() && ( cert.isBlacklisted()
2563 || cert.expiryDate() <= QDateTime::currentDateTime()
2564 || cert.effectiveDate() > QDateTime::currentDateTime() ) )
2579 QMutexLocker locker( mMutex );
2580 QList<QSslCertificate> certs;
2583 query.prepare( QStringLiteral(
"SELECT id, cert FROM %1" ).arg( authDbAuthoritiesTable() ) );
2585 if ( !authDbQuery( &query ) )
2588 if ( query.isActive() && query.isSelect() )
2590 while ( query.next() )
2592 certs << QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
2601 QMutexLocker locker( mMutex );
2607 QMutexLocker locker( mMutex );
2608 mCaCertsCache.clear();
2614 bool res = !mCaCertsCache.isEmpty();
2615 QgsDebugMsg( QStringLiteral(
"Rebuild of CA certs cache %1" ).arg( res ?
"SUCCEEDED" :
"FAILED" ) );
2621 QMutexLocker locker( mMutex );
2622 if ( cert.isNull() )
2624 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2634 QgsDebugMsg( QStringLiteral(
"Passed policy was default, all cert records in database were removed for id: %1" ).arg(
id ) );
2639 query.prepare( QStringLiteral(
"INSERT INTO %1 (id, policy) " 2640 "VALUES (:id, :policy)" ).arg( authDbTrustTable() ) );
2642 query.bindValue( QStringLiteral(
":id" ),
id );
2643 query.bindValue( QStringLiteral(
":policy" ), static_cast< int >( policy ) );
2645 if ( !authDbStartTransaction() )
2648 if ( !authDbQuery( &query ) )
2651 if ( !authDbCommit() )
2654 QgsDebugMsg( QStringLiteral(
"Store certificate trust policy SUCCESS for id: %1" ).arg(
id ) );
2660 QMutexLocker locker( mMutex );
2661 if ( cert.isNull() )
2663 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2670 query.prepare( QStringLiteral(
"SELECT policy FROM %1 " 2671 "WHERE id = :id" ).arg( authDbTrustTable() ) );
2673 query.bindValue( QStringLiteral(
":id" ),
id );
2675 if ( !authDbQuery( &query ) )
2679 if ( query.isActive() && query.isSelect() )
2681 if ( query.first() )
2684 QgsDebugMsg( QStringLiteral(
"Authentication cert trust policy retrieved for id: %1" ).arg(
id ) );
2688 QgsDebugMsg( QStringLiteral(
"Select contains more than one cert trust policy for id: %1" ).arg(
id ) );
2698 QMutexLocker locker( mMutex );
2699 if ( certs.empty() )
2701 QgsDebugMsg( QStringLiteral(
"Passed certificate list has no certs" ) );
2705 for (
const auto &cert : certs )
2715 QMutexLocker locker( mMutex );
2716 if ( cert.isNull() )
2718 QgsDebugMsg( QStringLiteral(
"Passed certificate is null" ) );
2726 query.prepare( QStringLiteral(
"DELETE FROM %1 WHERE id = :id" ).arg( authDbTrustTable() ) );
2728 query.bindValue( QStringLiteral(
":id" ),
id );
2730 if ( !authDbStartTransaction() )
2733 if ( !authDbQuery( &query ) )
2736 if ( !authDbCommit() )
2739 QgsDebugMsg( QStringLiteral(
"REMOVED cert trust policy for id: %1" ).arg(
id ) );
2746 QMutexLocker locker( mMutex );
2747 if ( cert.isNull() )
2757 if ( trustedids.contains(
id ) )
2761 else if ( untrustedids.contains(
id ) )
2776 return storeAuthSetting( QStringLiteral(
"certdefaulttrust" ), static_cast< int >( policy ) );
2781 QMutexLocker locker( mMutex );
2782 QVariant policy(
authSetting( QStringLiteral(
"certdefaulttrust" ) ) );
2783 if ( policy.isNull() )
2792 QMutexLocker locker( mMutex );
2793 mCertTrustCache.clear();
2796 query.prepare( QStringLiteral(
"SELECT id, policy FROM %1" ).arg( authDbTrustTable() ) );
2798 if ( !authDbQuery( &query ) )
2800 QgsDebugMsg( QStringLiteral(
"Rebuild of cert trust policy cache FAILED" ) );
2804 if ( query.isActive() && query.isSelect() )
2806 while ( query.next() )
2808 QString
id = query.value( 0 ).toString();
2812 if ( mCertTrustCache.contains( policy ) )
2814 ids = mCertTrustCache.value( policy );
2816 mCertTrustCache.insert( policy, ids <<
id );
2820 QgsDebugMsg( QStringLiteral(
"Rebuild of cert trust policy cache SUCCEEDED" ) );
2826 QMutexLocker locker( mMutex );
2830 const QList<QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> > &certpairs( mCaCertsCache.values() );
2832 QList<QSslCertificate> trustedcerts;
2833 for (
int i = 0; i < certpairs.size(); ++i )
2835 QSslCertificate cert( certpairs.at( i ).second );
2837 if ( trustedids.contains( certid ) )
2840 trustedcerts.append( cert );
2846 trustedcerts.append( cert );
2851 QSslConfiguration sslconfig( QSslConfiguration::defaultConfiguration() );
2852 sslconfig.setCaCertificates( trustedcerts );
2853 QSslConfiguration::setDefaultConfiguration( sslconfig );
2855 return trustedcerts;
2860 QMutexLocker locker( mMutex );
2861 if ( trustedCAs.isEmpty() )
2863 if ( mTrustedCaCertsCache.isEmpty() )
2870 const QList<QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> > &certpairs( mCaCertsCache.values() );
2872 QList<QSslCertificate> untrustedCAs;
2873 for (
int i = 0; i < certpairs.size(); ++i )
2875 QSslCertificate cert( certpairs.at( i ).second );
2876 if ( !trustedCAs.contains( cert ) )
2878 untrustedCAs.append( cert );
2881 return untrustedCAs;
2886 QMutexLocker locker( mMutex );
2888 QgsDebugMsg( QStringLiteral(
"Rebuilt trusted cert authorities cache" ) );
2895 QMutexLocker locker( mMutex );
2901 QMutexLocker locker( mMutex );
2904 return passwordHelperWrite( mMasterPass );
2920 for (
const auto &authcfg : ids )
2938 void QgsAuthManager::writeToConsole(
const QString &message,
2952 msg += QLatin1String(
"WARNING: " );
2955 msg += QLatin1String(
"ERROR: " );
2962 QTextStream out( stdout, QIODevice::WriteOnly );
2966 void QgsAuthManager::tryToStartDbErase()
2968 ++mScheduledDbEraseRequestCount;
2970 int trycutoff = 90 / ( mScheduledDbEraseRequestWait ? mScheduledDbEraseRequestWait : 3 );
2971 if ( mScheduledDbEraseRequestCount >= trycutoff )
2974 QgsDebugMsg( QStringLiteral(
"authDatabaseEraseRequest emitting/scheduling canceled" ) );
2979 QgsDebugMsg( QStringLiteral(
"authDatabaseEraseRequest attempt (%1 of %2)" )
2980 .arg( mScheduledDbEraseRequestCount ).arg( trycutoff ) );
2986 mScheduledDbEraseRequestEmitted =
true;
2991 QgsDebugMsg( QStringLiteral(
"authDatabaseEraseRequest emitted" ) );
2994 QgsDebugMsg( QStringLiteral(
"authDatabaseEraseRequest emit skipped" ) );
3000 QMutexLocker locker( mMutex );
3001 QMapIterator<QThread *, QMetaObject::Connection> iterator( mConnectedThreads );
3002 while ( iterator.hasNext() )
3005 iterator.key()->disconnect( iterator.value() );
3012 qDeleteAll( mAuthMethods );
3015 if ( authConn.isValid() && authConn.isOpen() )
3020 delete mScheduledDbEraseTimer;
3021 mScheduledDbEraseTimer =
nullptr;
3022 QSqlDatabase::removeDatabase( QStringLiteral(
"authentication.configs" ) );
3026 QString QgsAuthManager::passwordHelperName()
const 3028 return tr(
"Password Helper" );
3032 void QgsAuthManager::passwordHelperLog(
const QString &msg )
const 3044 QKeychain::DeletePasswordJob job( AUTH_PASSWORD_HELPER_FOLDER_NAME );
3046 job.setInsecureFallback( settings.
value( QStringLiteral(
"password_helper_insecure_fallback" ),
false, QgsSettings::Section::Auth ).toBool() );
3047 job.setAutoDelete(
false );
3048 job.setKey( AUTH_PASSWORD_HELPER_KEY_NAME );
3050 connect( &job, &QKeychain::Job::finished, &loop, &QEventLoop::quit );
3055 mPasswordHelperErrorCode = job.error();
3056 mPasswordHelperErrorMessage = tr(
"Delete password failed: %1." ).arg( job.errorString() );
3067 passwordHelperProcessError();
3071 QString QgsAuthManager::passwordHelperRead()
3076 QKeychain::ReadPasswordJob job( AUTH_PASSWORD_HELPER_FOLDER_NAME );
3078 job.setInsecureFallback( settings.
value( QStringLiteral(
"password_helper_insecure_fallback" ),
false, QgsSettings::Section::Auth ).toBool() );
3079 job.setAutoDelete(
false );
3080 job.setKey( AUTH_PASSWORD_HELPER_KEY_NAME );
3082 connect( &job, &QKeychain::Job::finished, &loop, &QEventLoop::quit );
3087 mPasswordHelperErrorCode = job.error();
3094 password = job.textData();
3096 if ( password.isEmpty() )
3098 mPasswordHelperErrorCode = QKeychain::EntryNotFound;
3109 passwordHelperProcessError();
3113 bool QgsAuthManager::passwordHelperWrite(
const QString &password )
3115 Q_ASSERT( !password.isEmpty() );
3118 QKeychain::WritePasswordJob job( AUTH_PASSWORD_HELPER_FOLDER_NAME );
3120 job.setInsecureFallback( settings.
value( QStringLiteral(
"password_helper_insecure_fallback" ),
false, QgsSettings::Section::Auth ).toBool() );
3121 job.setAutoDelete(
false );
3122 job.setKey( AUTH_PASSWORD_HELPER_KEY_NAME );
3123 job.setTextData( password );
3125 connect( &job, &QKeychain::Job::finished, &loop, &QEventLoop::quit );
3130 mPasswordHelperErrorCode = job.error();
3138 passwordHelperClearErrors();
3143 passwordHelperProcessError();
3151 return settings.
value( QStringLiteral(
"use_password_helper" ),
true, QgsSettings::Section::Auth ).toBool();
3157 settings.
setValue( QStringLiteral(
"use_password_helper" ), enabled, QgsSettings::Section::Auth );
3158 emit
messageOut( enabled ? tr(
"Your %1 will be <b>used from now</b> on to store and retrieve the master password." )
3160 tr(
"Your %1 will <b>not be used anymore</b> to store and retrieve the master password." )
3168 return settings.
value( QStringLiteral(
"password_helper_logging" ),
false, QgsSettings::Section::Auth ).toBool();
3174 settings.
setValue( QStringLiteral(
"password_helper_logging" ), enabled, QgsSettings::Section::Auth );
3177 void QgsAuthManager::passwordHelperClearErrors()
3179 mPasswordHelperErrorCode = QKeychain::NoError;
3180 mPasswordHelperErrorMessage.clear();
3183 void QgsAuthManager::passwordHelperProcessError()
3185 if ( mPasswordHelperErrorCode == QKeychain::AccessDenied ||
3186 mPasswordHelperErrorCode == QKeychain::AccessDeniedByUser ||
3187 mPasswordHelperErrorCode == QKeychain::NoBackendAvailable ||
3188 mPasswordHelperErrorCode == QKeychain::NotImplemented )
3194 mPasswordHelperErrorMessage = tr(
"There was an error and integration with your %1 system has been disabled. " 3195 "You can re-enable it at any time through the \"Utilities\" menu " 3196 "in the Authentication pane of the options dialog. %2" )
3199 if ( mPasswordHelperErrorCode != QKeychain::NoError )
3205 passwordHelperClearErrors();
3209 bool QgsAuthManager::masterPasswordInput()
3215 bool storedPasswordIsValid =
false;
3221 pass = passwordHelperRead();
3222 if ( ! pass.isEmpty() && ( mPasswordHelperErrorCode == QKeychain::NoError ) )
3228 storedPasswordIsValid =
true;
3244 if ( ok && !pass.isEmpty() && mMasterPass != pass )
3249 if ( passwordHelperWrite( pass ) )
3263 bool QgsAuthManager::masterPasswordRowsInDb(
int *rows )
const 3269 query.prepare( QStringLiteral(
"SELECT Count(*) FROM %1" ).arg( authDbPassTable() ) );
3271 bool ok = authDbQuery( &query );
3272 if ( query.first() )
3274 *rows = query.value( 0 ).toInt();
3286 if ( !masterPasswordRowsInDb( &rows ) )
3288 const char *err = QT_TR_NOOP(
"Master password: FAILED to access database" );
3294 return ( rows == 1 );
3297 bool QgsAuthManager::masterPasswordCheckAgainstDb(
const QString &compare )
const 3305 query.prepare( QStringLiteral(
"SELECT salt, hash FROM %1" ).arg( authDbPassTable() ) );
3306 if ( !authDbQuery( &query ) )
3309 if ( !query.first() )
3312 QString salt = query.value( 0 ).toString();
3313 QString hash = query.value( 1 ).toString();
3318 bool QgsAuthManager::masterPasswordStoreInDb()
const 3323 QString salt, hash, civ;
3327 query.prepare( QStringLiteral(
"INSERT INTO %1 (salt, hash, civ) VALUES (:salt, :hash, :civ)" ).arg( authDbPassTable() ) );
3329 query.bindValue( QStringLiteral(
":salt" ), salt );
3330 query.bindValue( QStringLiteral(
":hash" ), hash );
3331 query.bindValue( QStringLiteral(
":civ" ), civ );
3333 if ( !authDbStartTransaction() )
3336 if ( !authDbQuery( &query ) )
3339 if ( !authDbCommit() )
3345 bool QgsAuthManager::masterPasswordClearDb()
3351 query.prepare( QStringLiteral(
"DELETE FROM %1" ).arg( authDbPassTable() ) );
3352 bool res = authDbTransactionQuery( &query );
3358 const QString QgsAuthManager::masterPasswordCiv()
const 3364 query.prepare( QStringLiteral(
"SELECT civ FROM %1" ).arg( authDbPassTable() ) );
3365 if ( !authDbQuery( &query ) )
3368 if ( !query.first() )
3371 return query.value( 0 ).toString();
3376 QStringList configids = QStringList();
3384 if ( !authDbQuery( &query ) )
3389 if ( query.isActive() )
3391 while ( query.next() )
3393 configids << query.value( 0 ).toString();
3399 bool QgsAuthManager::verifyPasswordCanDecryptConfigs()
const 3410 if ( !authDbQuery( &query ) )
3413 if ( !query.isActive() || !query.isSelect() )
3415 QgsDebugMsg( QStringLiteral(
"Verify password can decrypt configs FAILED, query not active or a select operation" ) );
3420 while ( query.next() )
3423 QString configstring(
QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 1 ).toString() ) );
3424 if ( configstring.isEmpty() )
3426 QgsDebugMsg( QStringLiteral(
"Verify password can decrypt configs FAILED, could not decrypt a config (id: %1)" )
3427 .arg( query.value( 0 ).toString() ) );
3432 QgsDebugMsg( QStringLiteral(
"Verify password can decrypt configs SUCCESS (checked %1 configs)" ).arg( checked ) );
3436 bool QgsAuthManager::reencryptAllAuthenticationConfigs(
const QString &prevpass,
const QString &prevciv )
3443 for (
const auto &configid : ids )
3445 res = res && reencryptAuthenticationConfig( configid, prevpass, prevciv );
3450 bool QgsAuthManager::reencryptAuthenticationConfig(
const QString &authcfg,
const QString &prevpass,
const QString &prevciv )
3459 query.prepare( QStringLiteral(
"SELECT config FROM %1 " 3462 query.bindValue( QStringLiteral(
":id" ), authcfg );
3464 if ( !authDbQuery( &query ) )
3467 if ( !query.isActive() || !query.isSelect() )
3469 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, query not active or a select operation for authcfg: %2" ).arg( authcfg ) );
3473 if ( query.first() )
3479 QgsDebugMsg( QStringLiteral(
"Select contains more than one for authcfg: %1" ).arg( authcfg ) );
3486 query.prepare( QStringLiteral(
"UPDATE %1 " 3487 "SET config = :config " 3490 query.bindValue( QStringLiteral(
":id" ), authcfg );
3491 query.bindValue( QStringLiteral(
":config" ),
QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
3493 if ( !authDbStartTransaction() )
3496 if ( !authDbQuery( &query ) )
3499 if ( !authDbCommit() )
3502 QgsDebugMsg( QStringLiteral(
"Reencrypt SUCCESS for authcfg: %2" ).arg( authcfg ) );
3507 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, could not find in db authcfg: %2" ).arg( authcfg ) );
3512 bool QgsAuthManager::reencryptAllAuthenticationSettings(
const QString &prevpass,
const QString &prevciv )
3515 Q_UNUSED( prevpass )
3528 QStringList encryptedsettings;
3529 encryptedsettings <<
"";
3531 for (
const auto & sett, qgis::as_const( encryptedsettings ) )
3538 QSqlQuery query( authDbConnection() );
3540 query.prepare( QStringLiteral(
"SELECT value FROM %1 " 3541 "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
3543 query.bindValue(
":setting", sett );
3545 if ( !authDbQuery( &query ) )
3548 if ( !query.isActive() || !query.isSelect() )
3550 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, query not active or a select operation for setting: %2" ).arg( sett ) );
3554 if ( query.first() )
3560 query.prepare( QStringLiteral(
"UPDATE %1 " 3561 "SET value = :value " 3562 "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
3564 query.bindValue(
":setting", sett );
3567 if ( !authDbStartTransaction() )
3570 if ( !authDbQuery( &query ) )
3573 if ( !authDbCommit() )
3576 QgsDebugMsg( QStringLiteral(
"Reencrypt SUCCESS for setting: %2" ).arg( sett ) );
3581 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, could not find in db setting: %2" ).arg( sett ) );
3587 QgsDebugMsg( QStringLiteral(
"Select contains more than one for setting: %1" ).arg( sett ) );
3598 bool QgsAuthManager::reencryptAllAuthenticationIdentities(
const QString &prevpass,
const QString &prevciv )
3605 for (
const auto &identid : ids )
3607 res = res && reencryptAuthenticationIdentity( identid, prevpass, prevciv );
3612 bool QgsAuthManager::reencryptAuthenticationIdentity(
3613 const QString &identid,
3614 const QString &prevpass,
3615 const QString &prevciv )
3624 query.prepare( QStringLiteral(
"SELECT key FROM %1 " 3625 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
3627 query.bindValue( QStringLiteral(
":id" ), identid );
3629 if ( !authDbQuery( &query ) )
3632 if ( !query.isActive() || !query.isSelect() )
3634 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, query not active or a select operation for identity id: %2" ).arg( identid ) );
3638 if ( query.first() )
3644 QgsDebugMsg( QStringLiteral(
"Select contains more than one for identity id: %1" ).arg( identid ) );
3651 query.prepare( QStringLiteral(
"UPDATE %1 " 3653 "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
3655 query.bindValue( QStringLiteral(
":id" ), identid );
3656 query.bindValue( QStringLiteral(
":key" ),
QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), keystring ) );
3658 if ( !authDbStartTransaction() )
3661 if ( !authDbQuery( &query ) )
3664 if ( !authDbCommit() )
3667 QgsDebugMsg( QStringLiteral(
"Reencrypt SUCCESS for identity id: %2" ).arg( identid ) );
3672 QgsDebugMsg( QStringLiteral(
"Reencrypt FAILED, could not find in db identity id: %2" ).arg( identid ) );
3677 bool QgsAuthManager::authDbOpen()
const 3683 if ( !authdb.isOpen() )
3685 if ( !authdb.open() )
3687 QgsDebugMsg( QStringLiteral(
"Unable to establish database connection\nDatabase: %1\nDriver error: %2\nDatabase error: %3" )
3689 authdb.lastError().driverText(),
3690 authdb.lastError().databaseText() ) );
3698 bool QgsAuthManager::authDbQuery( QSqlQuery *query )
const 3703 query->setForwardOnly(
true );
3704 if ( !query->exec() )
3706 const char *err = QT_TR_NOOP(
"Auth db query exec() FAILED" );
3712 if ( query->lastError().isValid() )
3714 QgsDebugMsg( QStringLiteral(
"Auth db query FAILED: %1\nError: %2" )
3715 .arg( query->executedQuery(),
3716 query->lastError().text() ) );
3724 bool QgsAuthManager::authDbStartTransaction()
const 3731 const char *err = QT_TR_NOOP(
"Auth db FAILED to start transaction" );
3740 bool QgsAuthManager::authDbCommit()
const 3747 const char *err = QT_TR_NOOP(
"Auth db FAILED to rollback changes" );
3757 bool QgsAuthManager::authDbTransactionQuery( QSqlQuery *query )
const 3764 const char *err = QT_TR_NOOP(
"Auth db FAILED to start transaction" );
3770 bool ok = authDbQuery( query );
3774 const char *err = QT_TR_NOOP(
"Auth db FAILED to rollback changes" );
3786 for (
const auto &cert : certs )
3789 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.
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 GUI edit widget associated with the auth method.
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