QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsauthmanager.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsauthmanager.cpp
3  ---------------------
4  begin : October 5, 2014
5  copyright : (C) 2014 by Boundless Spatial, Inc. USA
6  author : Larry Shaffer
7  email : lshaffer at boundlessgeo dot com
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgsauthmanager.h"
18 
19 #include <QDir>
20 #include <QEventLoop>
21 #include <QFile>
22 #include <QFileInfo>
23 #include <QMutexLocker>
24 #include <QObject>
25 #include <QSet>
26 #include <QSqlDatabase>
27 #include <QSqlError>
28 #include <QSqlQuery>
29 #include <QTextStream>
30 #include <QTime>
31 #include <QTimer>
32 #include <QVariant>
33 #include <QSqlDriver>
34 
35 #include <QtCrypto>
36 
37 #ifndef QT_NO_SSL
38 #include <QSslConfiguration>
39 #endif
40 
41 // QtKeyChain library
42 #include "keychain.h"
43 
44 // QGIS includes
45 #include "qgsapplication.h"
46 #include "qgsauthcertutils.h"
47 #include "qgsauthcrypto.h"
48 #include "qgsauthmethod.h"
49 #include "qgsauthmethodmetadata.h"
50 #include "qgsauthmethodregistry.h"
51 #include "qgscredentials.h"
52 #include "qgslogger.h"
53 #include "qgsmessagelog.h"
54 #include "qgssettings.h"
55 #include "qgsruntimeprofiler.h"
56 
57 QgsAuthManager *QgsAuthManager::sInstance = nullptr;
58 
59 const QString QgsAuthManager::AUTH_CONFIG_TABLE = QStringLiteral( "auth_configs" );
60 const QString QgsAuthManager::AUTH_PASS_TABLE = QStringLiteral( "auth_pass" );
61 const QString QgsAuthManager::AUTH_SETTINGS_TABLE = QStringLiteral( "auth_settings" );
62 const QString QgsAuthManager::AUTH_IDENTITIES_TABLE = QStringLiteral( "auth_identities" );
63 const QString QgsAuthManager::AUTH_SERVERS_TABLE = QStringLiteral( "auth_servers" );
64 const QString QgsAuthManager::AUTH_AUTHORITIES_TABLE = QStringLiteral( "auth_authorities" );
65 const QString QgsAuthManager::AUTH_TRUST_TABLE = QStringLiteral( "auth_trust" );
66 const QString QgsAuthManager::AUTH_MAN_TAG = QObject::tr( "Authentication Manager" );
67 const QString QgsAuthManager::AUTH_CFG_REGEX = QStringLiteral( "authcfg=([a-z]|[A-Z]|[0-9]){7}" );
68 
69 
70 const QLatin1String QgsAuthManager::AUTH_PASSWORD_HELPER_KEY_NAME( "QGIS-Master-Password" );
71 const QLatin1String QgsAuthManager::AUTH_PASSWORD_HELPER_FOLDER_NAME( "QGIS" );
72 
73 
74 
75 #if defined(Q_OS_MAC)
76 const QString QgsAuthManager::AUTH_PASSWORD_HELPER_DISPLAY_NAME( "Keychain" );
77 #elif defined(Q_OS_WIN)
78 const QString QgsAuthManager::AUTH_PASSWORD_HELPER_DISPLAY_NAME( "Password Manager" );
79 #elif defined(Q_OS_LINUX)
80 const QString QgsAuthManager::AUTH_PASSWORD_HELPER_DISPLAY_NAME( QStringLiteral( "Wallet/KeyRing" ) );
81 #else
82 const QString QgsAuthManager::AUTH_PASSWORD_HELPER_DISPLAY_NAME( "Password Manager" );
83 #endif
84 
86 {
87  static QMutex sMutex;
88  QMutexLocker locker( &sMutex );
89  if ( !sInstance )
90  {
91  sInstance = new QgsAuthManager( );
92  }
93  return sInstance;
94 }
95 
96 
98 {
99  mMutex.reset( new QMutex( QMutex::Recursive ) );
100  mMasterPasswordMutex.reset( new QMutex( QMutex::Recursive ) );
101  connect( this, &QgsAuthManager::messageOut,
102  this, &QgsAuthManager::writeToConsole );
103 }
104 
106 {
107  QSqlDatabase authdb;
108  if ( isDisabled() )
109  return authdb;
110 
111  // while everything we use from QSqlDatabase here is thread safe, we need to ensure
112  // that the connection cleanup on thread finalization happens in a predictable order
113  QMutexLocker locker( mMutex.get() );
114 
115  // Sharing the same connection between threads is not allowed.
116  // We use a dedicated connection for each thread requiring access to the database,
117  // using the thread address as connection name.
118  const QString connectionName = QStringLiteral( "authentication.configs:0x%1" ).arg( reinterpret_cast<quintptr>( QThread::currentThread() ), 2 * QT_POINTER_SIZE, 16, QLatin1Char( '0' ) );
119  QgsDebugMsgLevel( QStringLiteral( "Using auth db connection name: %1 " ).arg( connectionName ), 2 );
120  if ( !QSqlDatabase::contains( connectionName ) )
121  {
122  QgsDebugMsgLevel( QStringLiteral( "No existing connection, creating a new one" ), 2 );
123  authdb = QSqlDatabase::addDatabase( QStringLiteral( "QSQLITE" ), connectionName );
124  authdb.setDatabaseName( authenticationDatabasePath() );
125  // for background threads, remove database when current thread finishes
126  if ( QThread::currentThread() != qApp->thread() )
127  {
128  QgsDebugMsgLevel( QStringLiteral( "Scheduled auth db remove on thread close" ), 2 );
129 
130  // IMPORTANT - we use a direct connection here, because the database removal must happen immediately
131  // when the thread finishes, and we cannot let this get queued on the main thread's event loop (where
132  // QgsAuthManager lives).
133  // Otherwise, the QSqlDatabase's private data's thread gets reset immediately the QThread::finished,
134  // and a subsequent call to QSqlDatabase::database with the same thread address (yep it happens, actually a lot)
135  // triggers a condition in QSqlDatabase which detects the nullptr private thread data and returns an invalid database instead.
136  // QSqlDatabase::removeDatabase is thread safe, so this is ok to do.
137  // Right about now is a good time to re-evaluate your selected career ;)
138  QMetaObject::Connection connection = connect( QThread::currentThread(), &QThread::finished, QThread::currentThread(), [connectionName, this ]
139  {
140  QMutexLocker locker( mMutex.get() );
141  QSqlDatabase::removeDatabase( connectionName );
142  mConnectedThreads.remove( QThread::currentThread() );
143  }, Qt::DirectConnection );
144 
145  mConnectedThreads.insert( QThread::currentThread(), connection );
146  }
147  }
148  else
149  {
150  QgsDebugMsgLevel( QStringLiteral( "Reusing existing connection" ), 2 );
151  authdb = QSqlDatabase::database( connectionName );
152  }
153  locker.unlock();
154 
155  if ( !authdb.isOpen() )
156  {
157  if ( !authdb.open() )
158  {
159  const char *err = QT_TR_NOOP( "Opening of authentication db FAILED" );
160  QgsDebugMsg( err );
161  emit messageOut( tr( err ), authManTag(), CRITICAL );
162  }
163  }
164 
165  return authdb;
166 }
167 
168 bool QgsAuthManager::init( const QString &pluginPath, const QString &authDatabasePath )
169 {
170  if ( mAuthInit )
171  return true;
172  mAuthInit = true;
173 
174  QgsScopedRuntimeProfile profile( tr( "Initializing authentication manager" ) );
175 
176  QgsDebugMsgLevel( QStringLiteral( "Initializing QCA..." ), 2 );
177  mQcaInitializer = qgis::make_unique<QCA::Initializer>( QCA::Practical, 256 );
178 
179  QgsDebugMsgLevel( QStringLiteral( "QCA initialized." ), 2 );
180  QCA::scanForPlugins();
181 
182  QgsDebugMsgLevel( QStringLiteral( "QCA Plugin Diagnostics Context: %1" ).arg( QCA::pluginDiagnosticText() ), 2 );
183  QStringList capabilities;
184 
185  capabilities = QCA::supportedFeatures();
186  QgsDebugMsgLevel( QStringLiteral( "QCA supports: %1" ).arg( capabilities.join( "," ) ), 2 );
187 
188  // do run-time check for qca-ossl plugin
189  if ( !QCA::isSupported( "cert", QStringLiteral( "qca-ossl" ) ) )
190  {
191  mAuthDisabled = true;
192  mAuthDisabledMessage = tr( "QCA's OpenSSL plugin (qca-ossl) is missing" );
193  return isDisabled();
194  }
195 
196  QgsDebugMsgLevel( QStringLiteral( "Prioritizing qca-ossl over all other QCA providers..." ), 2 );
197  const QCA::ProviderList provds = QCA::providers();
198  QStringList prlist;
199  for ( QCA::Provider *p : provds )
200  {
201  QString pn = p->name();
202  int pr = 0;
203  if ( pn != QLatin1String( "qca-ossl" ) )
204  {
205  pr = QCA::providerPriority( pn ) + 1;
206  }
207  QCA::setProviderPriority( pn, pr );
208  prlist << QStringLiteral( "%1:%2" ).arg( pn ).arg( QCA::providerPriority( pn ) );
209  }
210  QgsDebugMsgLevel( QStringLiteral( "QCA provider priorities: %1" ).arg( prlist.join( ", " ) ), 2 );
211 
212  QgsDebugMsgLevel( QStringLiteral( "Populating auth method registry" ), 3 );
214 
215  QStringList methods = authreg->authMethodList();
216 
217  QgsDebugMsgLevel( QStringLiteral( "Authentication methods found: %1" ).arg( methods.join( ", " ) ), 2 );
218 
219  if ( methods.isEmpty() )
220  {
221  mAuthDisabled = true;
222  mAuthDisabledMessage = tr( "No authentication method plugins found" );
223  return isDisabled();
224  }
225 
226  if ( !registerCoreAuthMethods() )
227  {
228  mAuthDisabled = true;
229  mAuthDisabledMessage = tr( "No authentication method plugins could be loaded" );
230  return isDisabled();
231  }
232 
233  mAuthDbPath = QDir::cleanPath( authDatabasePath );
234  QgsDebugMsgLevel( QStringLiteral( "Auth database path: %1" ).arg( authenticationDatabasePath() ), 2 );
235 
236  QFileInfo dbinfo( authenticationDatabasePath() );
237  QFileInfo dbdirinfo( dbinfo.path() );
238  QgsDebugMsgLevel( QStringLiteral( "Auth db directory path: %1" ).arg( dbdirinfo.filePath() ), 2 );
239 
240  if ( !dbdirinfo.exists() )
241  {
242  QgsDebugMsgLevel( QStringLiteral( "Auth db directory path does not exist, making path: %1" ).arg( dbdirinfo.filePath() ), 2 );
243  if ( !QDir().mkpath( dbdirinfo.filePath() ) )
244  {
245  const char *err = QT_TR_NOOP( "Auth db directory path could not be created" );
246  QgsDebugMsg( err );
247  emit messageOut( tr( err ), authManTag(), CRITICAL );
248  return false;
249  }
250  }
251 
252  if ( dbinfo.exists() )
253  {
254  if ( !dbinfo.permission( QFile::ReadOwner | QFile::WriteOwner ) )
255  {
256  const char *err = QT_TR_NOOP( "Auth db is not readable or writable by user" );
257  QgsDebugMsg( err );
258  emit messageOut( tr( err ), authManTag(), CRITICAL );
259  return false;
260  }
261  if ( dbinfo.size() > 0 )
262  {
263  QgsDebugMsgLevel( QStringLiteral( "Auth db exists and has data" ), 2 );
264 
265  if ( !createCertTables() )
266  return false;
267 
269 
270 #ifndef QT_NO_SSL
271  initSslCaches();
272 #endif
273 
274  // set the master password from first line of file defined by QGIS_AUTH_PASSWORD_FILE env variable
275  const char *passenv = "QGIS_AUTH_PASSWORD_FILE";
276  if ( getenv( passenv ) && masterPasswordHashInDatabase() )
277  {
278  QString passpath( getenv( passenv ) );
279  // clear the env variable, so it can not be accessed from plugins, etc.
280  // (note: stored QgsApplication::systemEnvVars() skips this env variable as well)
281 #ifdef Q_OS_WIN
282  putenv( passenv );
283 #else
284  unsetenv( passenv );
285 #endif
286  QString masterpass;
287  QFile passfile( passpath );
288  if ( passfile.exists() && passfile.open( QIODevice::ReadOnly | QIODevice::Text ) )
289  {
290  QTextStream passin( &passfile );
291  while ( !passin.atEnd() )
292  {
293  masterpass = passin.readLine();
294  break;
295  }
296  passfile.close();
297  }
298  if ( !masterpass.isEmpty() )
299  {
300  if ( setMasterPassword( masterpass, true ) )
301  {
302  QgsDebugMsgLevel( QStringLiteral( "Authentication master password set from QGIS_AUTH_PASSWORD_FILE" ), 2 );
303  }
304  else
305  {
306  QgsDebugMsg( "QGIS_AUTH_PASSWORD_FILE set, but FAILED to set password using: " + passpath );
307  return false;
308  }
309  }
310  else
311  {
312  QgsDebugMsg( "QGIS_AUTH_PASSWORD_FILE set, but FAILED to read password from: " + passpath );
313  return false;
314  }
315  }
316 
317  return true;
318  }
319  }
320  else
321  {
322  QgsDebugMsgLevel( QStringLiteral( "Auth db does not exist: creating through QSqlDatabase initial connection" ), 2 );
323 
324  if ( !createConfigTables() )
325  return false;
326 
327  if ( !createCertTables() )
328  return false;
329  }
330 
331 #ifndef QT_NO_SSL
332  initSslCaches();
333 #endif
334 
335  return true;
336 }
337 
338 bool QgsAuthManager::createConfigTables()
339 {
340  QMutexLocker locker( mMutex.get() );
341  // create and open the db
342  if ( !authDbOpen() )
343  {
344  const char *err = QT_TR_NOOP( "Auth db could not be created and opened" );
345  QgsDebugMsg( err );
346  emit messageOut( tr( err ), authManTag(), CRITICAL );
347  return false;
348  }
349 
350  QSqlQuery query( authDatabaseConnection() );
351 
352  // create the tables
353  QString qstr;
354 
355  qstr = QStringLiteral( "CREATE TABLE %1 (\n"
356  " 'salt' TEXT NOT NULL,\n"
357  " 'civ' TEXT NOT NULL\n"
358  ", 'hash' TEXT NOT NULL);" ).arg( authDbPassTable() );
359  query.prepare( qstr );
360  if ( !authDbQuery( &query ) )
361  return false;
362  query.clear();
363 
364  qstr = QStringLiteral( "CREATE TABLE %1 (\n"
365  " 'id' TEXT NOT NULL,\n"
366  " 'name' TEXT NOT NULL,\n"
367  " 'uri' TEXT,\n"
368  " 'type' TEXT NOT NULL,\n"
369  " 'version' INTEGER NOT NULL\n"
370  ", 'config' TEXT NOT NULL);" ).arg( authDatabaseConfigTable() );
371  query.prepare( qstr );
372  if ( !authDbQuery( &query ) )
373  return false;
374  query.clear();
375 
376  qstr = QStringLiteral( "CREATE UNIQUE INDEX 'id_index' on %1 (id ASC);" ).arg( authDatabaseConfigTable() );
377  query.prepare( qstr );
378  if ( !authDbQuery( &query ) )
379  return false;
380  query.clear();
381 
382  qstr = QStringLiteral( "CREATE INDEX 'uri_index' on %1 (uri ASC);" ).arg( authDatabaseConfigTable() );
383  query.prepare( qstr );
384  if ( !authDbQuery( &query ) )
385  return false;
386  query.clear();
387 
388  return true;
389 }
390 
391 bool QgsAuthManager::createCertTables()
392 {
393  QMutexLocker locker( mMutex.get() );
394  // NOTE: these tables were added later, so IF NOT EXISTS is used
395  QgsDebugMsgLevel( QStringLiteral( "Creating cert tables in auth db" ), 2 );
396 
397  QSqlQuery query( authDatabaseConnection() );
398 
399  // create the tables
400  QString qstr;
401 
402  qstr = QStringLiteral( "CREATE TABLE IF NOT EXISTS %1 (\n"
403  " 'setting' TEXT NOT NULL\n"
404  ", 'value' TEXT);" ).arg( authDbSettingsTable() );
405  query.prepare( qstr );
406  if ( !authDbQuery( &query ) )
407  return false;
408  query.clear();
409 
410 
411  qstr = QStringLiteral( "CREATE TABLE IF NOT EXISTS %1 (\n"
412  " 'id' TEXT NOT NULL,\n"
413  " 'key' TEXT NOT NULL\n"
414  ", 'cert' TEXT NOT NULL);" ).arg( authDbIdentitiesTable() );
415  query.prepare( qstr );
416  if ( !authDbQuery( &query ) )
417  return false;
418  query.clear();
419 
420  qstr = QStringLiteral( "CREATE UNIQUE INDEX IF NOT EXISTS 'id_index' on %1 (id ASC);" ).arg( authDbIdentitiesTable() );
421  query.prepare( qstr );
422  if ( !authDbQuery( &query ) )
423  return false;
424  query.clear();
425 
426 
427  qstr = QStringLiteral( "CREATE TABLE IF NOT EXISTS %1 (\n"
428  " 'id' TEXT NOT NULL,\n"
429  " 'host' TEXT NOT NULL,\n"
430  " 'cert' TEXT\n"
431  ", 'config' TEXT NOT NULL);" ).arg( authDatabaseServersTable() );
432  query.prepare( qstr );
433  if ( !authDbQuery( &query ) )
434  return false;
435  query.clear();
436 
437  qstr = QStringLiteral( "CREATE UNIQUE INDEX IF NOT EXISTS 'host_index' on %1 (host ASC);" ).arg( authDatabaseServersTable() );
438  query.prepare( qstr );
439  if ( !authDbQuery( &query ) )
440  return false;
441  query.clear();
442 
443 
444  qstr = QStringLiteral( "CREATE TABLE IF NOT EXISTS %1 (\n"
445  " 'id' TEXT NOT NULL\n"
446  ", 'cert' TEXT NOT NULL);" ).arg( authDbAuthoritiesTable() );
447  query.prepare( qstr );
448  if ( !authDbQuery( &query ) )
449  return false;
450  query.clear();
451 
452  qstr = QStringLiteral( "CREATE UNIQUE INDEX IF NOT EXISTS 'id_index' on %1 (id ASC);" ).arg( authDbAuthoritiesTable() );
453  query.prepare( qstr );
454  if ( !authDbQuery( &query ) )
455  return false;
456  query.clear();
457 
458  qstr = QStringLiteral( "CREATE TABLE IF NOT EXISTS %1 (\n"
459  " 'id' TEXT NOT NULL\n"
460  ", 'policy' TEXT NOT NULL);" ).arg( authDbTrustTable() );
461  query.prepare( qstr );
462  if ( !authDbQuery( &query ) )
463  return false;
464  query.clear();
465 
466  qstr = QStringLiteral( "CREATE UNIQUE INDEX IF NOT EXISTS 'id_index' on %1 (id ASC);" ).arg( authDbTrustTable() );
467  query.prepare( qstr );
468  if ( !authDbQuery( &query ) )
469  return false;
470  query.clear();
471 
472  return true;
473 }
474 
476 {
477  if ( mAuthDisabled )
478  {
479  QgsDebugMsg( QStringLiteral( "Authentication system DISABLED: QCA's qca-ossl (OpenSSL) plugin is missing" ) );
480  }
481  return mAuthDisabled;
482 }
483 
484 const QString QgsAuthManager::disabledMessage() const
485 {
486  return tr( "Authentication system is DISABLED:\n%1" ).arg( mAuthDisabledMessage );
487 }
488 
490 {
491  QMutexLocker locker( mMasterPasswordMutex.get() );
492  if ( isDisabled() )
493  return false;
494 
495  if ( mScheduledDbErase )
496  return false;
497 
498  if ( mMasterPass.isEmpty() )
499  {
500  QgsDebugMsg( QStringLiteral( "Master password is not yet set by user" ) );
501  if ( !masterPasswordInput() )
502  {
503  QgsDebugMsg( QStringLiteral( "Master password input canceled by user" ) );
504  return false;
505  }
506  }
507  else
508  {
509  QgsDebugMsg( QStringLiteral( "Master password is set" ) );
510  if ( !verify )
511  return true;
512  }
513 
514  if ( !verifyMasterPassword() )
515  return false;
516 
517  QgsDebugMsg( QStringLiteral( "Master password is set and verified" ) );
518  return true;
519 }
520 
521 bool QgsAuthManager::setMasterPassword( const QString &pass, bool verify )
522 {
523  QMutexLocker locker( mMutex.get() );
524  if ( isDisabled() )
525  return false;
526 
527  if ( mScheduledDbErase )
528  return false;
529 
530  // since this is generally for automation, we don't care if passed-in is same as existing
531  QString prevpass = QString( mMasterPass );
532  mMasterPass = pass;
533  if ( verify && !verifyMasterPassword() )
534  {
535  mMasterPass = prevpass;
536  const char *err = QT_TR_NOOP( "Master password set: FAILED to verify, reset to previous" );
537  QgsDebugMsg( err );
538  emit messageOut( tr( err ), authManTag(), WARNING );
539  return false;
540  }
541 
542  QgsDebugMsg( QStringLiteral( "Master password set: SUCCESS%1" ).arg( verify ? " and verified" : "" ) );
543  return true;
544 }
545 
546 bool QgsAuthManager::verifyMasterPassword( const QString &compare )
547 {
548  if ( isDisabled() )
549  return false;
550 
551  int rows = 0;
552  if ( !masterPasswordRowsInDb( &rows ) )
553  {
554  const char *err = QT_TR_NOOP( "Master password: FAILED to access database" );
555  QgsDebugMsg( err );
556  emit messageOut( tr( err ), authManTag(), CRITICAL );
557 
559  return false;
560  }
561 
562  QgsDebugMsg( QStringLiteral( "Master password: %1 rows in database" ).arg( rows ) );
563 
564  if ( rows > 1 )
565  {
566  const char *err = QT_TR_NOOP( "Master password: FAILED to find just one master password record in database" );
567  QgsDebugMsg( err );
568  emit messageOut( tr( err ), authManTag(), WARNING );
569 
571  return false;
572  }
573  else if ( rows == 1 )
574  {
575  if ( !masterPasswordCheckAgainstDb( compare ) )
576  {
577  if ( compare.isNull() ) // don't complain when comparing, since it could be an incomplete comparison string
578  {
579  const char *err = QT_TR_NOOP( "Master password: FAILED to verify against hash in database" );
580  QgsDebugMsg( err );
581  emit messageOut( tr( err ), authManTag(), WARNING );
582 
584 
585  emit masterPasswordVerified( false );
586  }
587  ++mPassTries;
588  if ( mPassTries >= 5 )
589  {
590  mAuthDisabled = true;
591  const char *err = QT_TR_NOOP( "Master password: failed 5 times authentication system DISABLED" );
592  QgsDebugMsg( err );
593  emit messageOut( tr( err ), authManTag(), WARNING );
594  }
595  return false;
596  }
597  else
598  {
599  QgsDebugMsg( QStringLiteral( "Master password: verified against hash in database" ) );
600  if ( compare.isNull() )
601  emit masterPasswordVerified( true );
602  }
603  }
604  else if ( compare.isNull() ) // compares should never be stored
605  {
606  if ( !masterPasswordStoreInDb() )
607  {
608  const char *err = QT_TR_NOOP( "Master password: hash FAILED to be stored in database" );
609  QgsDebugMsg( err );
610  emit messageOut( tr( err ), authManTag(), CRITICAL );
611 
613  return false;
614  }
615  else
616  {
617  QgsDebugMsg( QStringLiteral( "Master password: hash stored in database" ) );
618  }
619  // double-check storing
620  if ( !masterPasswordCheckAgainstDb() )
621  {
622  const char *err = QT_TR_NOOP( "Master password: FAILED to verify against hash in database" );
623  QgsDebugMsg( err );
624  emit messageOut( tr( err ), authManTag(), WARNING );
625 
627  emit masterPasswordVerified( false );
628  return false;
629  }
630  else
631  {
632  QgsDebugMsg( QStringLiteral( "Master password: verified against hash in database" ) );
633  emit masterPasswordVerified( true );
634  }
635  }
636 
637  return true;
638 }
639 
641 {
642  return !mMasterPass.isEmpty();
643 }
644 
645 bool QgsAuthManager::masterPasswordSame( const QString &pass ) const
646 {
647  return mMasterPass == pass;
648 }
649 
650 bool QgsAuthManager::resetMasterPassword( const QString &newpass, const QString &oldpass,
651  bool keepbackup, QString *backuppath )
652 {
653  if ( isDisabled() )
654  return false;
655 
656  // verify caller knows the current master password
657  // this means that the user will have had to already set the master password as well
658  if ( !masterPasswordSame( oldpass ) )
659  return false;
660 
661  QString dbbackup;
662  if ( !backupAuthenticationDatabase( &dbbackup ) )
663  return false;
664 
665  QgsDebugMsg( QStringLiteral( "Master password reset: backed up current database" ) );
666 
667  // create new database and connection
669 
670  // store current password and civ
671  QString prevpass = QString( mMasterPass );
672  QString prevciv = QString( masterPasswordCiv() );
673 
674  // on ANY FAILURE from this point, reinstate previous password and database
675  bool ok = true;
676 
677  // clear password hash table (also clears mMasterPass)
678  if ( ok && !masterPasswordClearDb() )
679  {
680  ok = false;
681  const char *err = QT_TR_NOOP( "Master password reset FAILED: could not clear current password from database" );
682  QgsDebugMsg( err );
683  emit messageOut( tr( err ), authManTag(), WARNING );
684  }
685  if ( ok )
686  {
687  QgsDebugMsg( QStringLiteral( "Master password reset: cleared current password from database" ) );
688  }
689 
690  // mMasterPass empty, set new password (don't verify, since not stored yet)
691  setMasterPassword( newpass, false );
692 
693  // store new password hash
694  if ( ok && !masterPasswordStoreInDb() )
695  {
696  ok = false;
697  const char *err = QT_TR_NOOP( "Master password reset FAILED: could not store new password in database" );
698  QgsDebugMsg( err );
699  emit messageOut( tr( err ), authManTag(), WARNING );
700  }
701  if ( ok )
702  {
703  QgsDebugMsg( QStringLiteral( "Master password reset: stored new password in database" ) );
704  }
705 
706  // verify it stored password properly
707  if ( ok && !verifyMasterPassword() )
708  {
709  ok = false;
710  const char *err = QT_TR_NOOP( "Master password reset FAILED: could not verify new password in database" );
711  QgsDebugMsg( err );
712  emit messageOut( tr( err ), authManTag(), WARNING );
713  }
714 
715  // re-encrypt everything with new password
716  if ( ok && !reencryptAllAuthenticationConfigs( prevpass, prevciv ) )
717  {
718  ok = false;
719  const char *err = QT_TR_NOOP( "Master password reset FAILED: could not re-encrypt configs in database" );
720  QgsDebugMsg( err );
721  emit messageOut( tr( err ), authManTag(), WARNING );
722  }
723  if ( ok )
724  {
725  QgsDebugMsg( QStringLiteral( "Master password reset: re-encrypted configs in database" ) );
726  }
727 
728  // verify it all worked
729  if ( ok && !verifyPasswordCanDecryptConfigs() )
730  {
731  ok = false;
732  const char *err = QT_TR_NOOP( "Master password reset FAILED: could not verify password can decrypt re-encrypted configs" );
733  QgsDebugMsg( err );
734  emit messageOut( tr( err ), authManTag(), WARNING );
735  }
736 
737  if ( ok && !reencryptAllAuthenticationSettings( prevpass, prevciv ) )
738  {
739  ok = false;
740  const char *err = QT_TR_NOOP( "Master password reset FAILED: could not re-encrypt settings in database" );
741  QgsDebugMsg( err );
742  emit messageOut( tr( err ), authManTag(), WARNING );
743  }
744 
745  if ( ok && !reencryptAllAuthenticationIdentities( prevpass, prevciv ) )
746  {
747  ok = false;
748  const char *err = QT_TR_NOOP( "Master password reset FAILED: could not re-encrypt identities in database" );
749  QgsDebugMsg( err );
750  emit messageOut( tr( err ), authManTag(), WARNING );
751  }
752 
753  // something went wrong, reinstate previous password and database
754  if ( !ok )
755  {
756  // backup database of failed attempt, for inspection
757  authDatabaseConnection().close();
758  QString errdbbackup( dbbackup );
759  errdbbackup.replace( QLatin1String( ".db" ), QLatin1String( "_ERROR.db" ) );
760  QFile::rename( authenticationDatabasePath(), errdbbackup );
761  QgsDebugMsg( QStringLiteral( "Master password reset FAILED: backed up failed db at %1" ).arg( errdbbackup ) );
762 
763  // reinstate previous database and password
764  QFile::rename( dbbackup, authenticationDatabasePath() );
765  mMasterPass = prevpass;
767  QgsDebugMsg( QStringLiteral( "Master password reset FAILED: reinstated previous password and database" ) );
768 
769  // assign error db backup
770  if ( backuppath )
771  *backuppath = errdbbackup;
772 
773  return false;
774  }
775 
776 
777  if ( !keepbackup && !QFile::remove( dbbackup ) )
778  {
779  const char *err = QT_TR_NOOP( "Master password reset: could not remove old database backup" );
780  QgsDebugMsg( err );
781  emit messageOut( tr( err ), authManTag(), WARNING );
782  // a non-blocking error, continue
783  }
784 
785  if ( keepbackup )
786  {
787  QgsDebugMsg( QStringLiteral( "Master password reset: backed up previous db at %1" ).arg( dbbackup ) );
788  if ( backuppath )
789  *backuppath = dbbackup;
790  }
791 
792  QgsDebugMsg( QStringLiteral( "Master password reset: SUCCESS" ) );
793  emit authDatabaseChanged();
794  return true;
795 }
796 
798 {
799  mScheduledDbErase = scheduleErase;
800  // any call (start or stop) should reset these
801  mScheduledDbEraseRequestEmitted = false;
802  mScheduledDbEraseRequestCount = 0;
803 
804  if ( scheduleErase )
805  {
806  if ( !mScheduledDbEraseTimer )
807  {
808  mScheduledDbEraseTimer = new QTimer( this );
809  connect( mScheduledDbEraseTimer, &QTimer::timeout, this, &QgsAuthManager::tryToStartDbErase );
810  mScheduledDbEraseTimer->start( mScheduledDbEraseRequestWait * 1000 );
811  }
812  else if ( !mScheduledDbEraseTimer->isActive() )
813  {
814  mScheduledDbEraseTimer->start();
815  }
816  }
817  else
818  {
819  if ( mScheduledDbEraseTimer && mScheduledDbEraseTimer->isActive() )
820  mScheduledDbEraseTimer->stop();
821  }
822 }
823 
825 {
826  if ( isDisabled() )
827  return false;
828 
829  qDeleteAll( mAuthMethods );
830  mAuthMethods.clear();
831  const QStringList methods = QgsAuthMethodRegistry::instance()->authMethodList();
832  for ( const auto &authMethodKey : methods )
833  {
834  mAuthMethods.insert( authMethodKey, QgsAuthMethodRegistry::instance()->authMethod( authMethodKey ).release() );
835  }
836 
837  return !mAuthMethods.isEmpty();
838 }
839 
840 const QString QgsAuthManager::uniqueConfigId() const
841 {
842  QStringList configids = configIds();
843  QString id;
844  int len = 7;
845  // sleep just a bit to make sure the current time has changed
846  QEventLoop loop;
847  QTimer::singleShot( 3, &loop, &QEventLoop::quit );
848  loop.exec();
849 
850  uint seed = static_cast< uint >( QTime::currentTime().msec() );
851  qsrand( seed );
852 
853  while ( true )
854  {
855  id.clear();
856  for ( int i = 0; i < len; i++ )
857  {
858  switch ( qrand() % 2 )
859  {
860  case 0:
861  id += ( '0' + qrand() % 10 );
862  break;
863  case 1:
864  id += ( 'a' + qrand() % 26 );
865  break;
866  }
867  }
868  if ( !configids.contains( id ) )
869  {
870  break;
871  }
872  }
873  QgsDebugMsg( QStringLiteral( "Generated unique ID: %1" ).arg( id ) );
874  return id;
875 }
876 
877 bool QgsAuthManager::configIdUnique( const QString &id ) const
878 {
879  if ( isDisabled() )
880  return false;
881 
882  if ( id.isEmpty() )
883  {
884  const char *err = QT_TR_NOOP( "Config ID is empty" );
885  QgsDebugMsg( err );
886  emit messageOut( tr( err ), authManTag(), WARNING );
887  return false;
888  }
889  QStringList configids = configIds();
890  return !configids.contains( id );
891 }
892 
893 bool QgsAuthManager::hasConfigId( const QString &txt ) const
894 {
895  QRegExp rx( AUTH_CFG_REGEX );
896  return rx.indexIn( txt ) != -1;
897 }
898 
900 {
901  QMutexLocker locker( mMutex.get() );
902  QStringList providerAuthMethodsKeys;
903  if ( !dataprovider.isEmpty() )
904  {
905  providerAuthMethodsKeys = authMethodsKeys( dataprovider.toLower() );
906  }
907 
908  QgsAuthMethodConfigsMap baseConfigs;
909 
910  if ( isDisabled() )
911  return baseConfigs;
912 
913  QSqlQuery query( authDatabaseConnection() );
914  query.prepare( QStringLiteral( "SELECT id, name, uri, type, version FROM %1" ).arg( authDatabaseConfigTable() ) );
915 
916  if ( !authDbQuery( &query ) )
917  {
918  return baseConfigs;
919  }
920 
921  if ( query.isActive() && query.isSelect() )
922  {
923  while ( query.next() )
924  {
925  QString authcfg = query.value( 0 ).toString();
926  QgsAuthMethodConfig config;
927  config.setId( authcfg );
928  config.setName( query.value( 1 ).toString() );
929  config.setUri( query.value( 2 ).toString() );
930  config.setMethod( query.value( 3 ).toString() );
931  config.setVersion( query.value( 4 ).toInt() );
932 
933  if ( !dataprovider.isEmpty() && !providerAuthMethodsKeys.contains( config.method() ) )
934  {
935  continue;
936  }
937 
938  baseConfigs.insert( authcfg, config );
939  }
940  }
941  return baseConfigs;
942 }
943 
945 {
946  QMutexLocker locker( mMutex.get() );
947  if ( isDisabled() )
948  return;
949 
950  QSqlQuery query( authDatabaseConnection() );
951  query.prepare( QStringLiteral( "SELECT id, type FROM %1" ).arg( authDatabaseConfigTable() ) );
952 
953  if ( !authDbQuery( &query ) )
954  {
955  return;
956  }
957 
958  if ( query.isActive() )
959  {
960  QgsDebugMsgLevel( QStringLiteral( "Syncing existing auth config and their auth methods" ), 2 );
961  mConfigAuthMethods.clear();
962  QStringList cfgmethods;
963  while ( query.next() )
964  {
965  mConfigAuthMethods.insert( query.value( 0 ).toString(),
966  query.value( 1 ).toString() );
967  cfgmethods << QStringLiteral( "%1=%2" ).arg( query.value( 0 ).toString(), query.value( 1 ).toString() );
968  }
969  QgsDebugMsgLevel( QStringLiteral( "Stored auth config/methods:\n%1" ).arg( cfgmethods.join( ", " ) ), 2 );
970  }
971 }
972 
974 {
975  if ( isDisabled() )
976  return nullptr;
977 
978  if ( !mConfigAuthMethods.contains( authcfg ) )
979  {
980  QgsDebugMsg( QStringLiteral( "No config auth method found in database for authcfg: %1" ).arg( authcfg ) );
981  return nullptr;
982  }
983 
984  QString authMethodKey = mConfigAuthMethods.value( authcfg );
985 
986  return authMethod( authMethodKey );
987 }
988 
989 QString QgsAuthManager::configAuthMethodKey( const QString &authcfg ) const
990 {
991  if ( isDisabled() )
992  return QString();
993 
994  return mConfigAuthMethods.value( authcfg, QString() );
995 }
996 
997 
998 QStringList QgsAuthManager::authMethodsKeys( const QString &dataprovider )
999 {
1000  return authMethodsMap( dataprovider.toLower() ).uniqueKeys();
1001 }
1002 
1003 QgsAuthMethod *QgsAuthManager::authMethod( const QString &authMethodKey )
1004 {
1005  if ( !mAuthMethods.contains( authMethodKey ) )
1006  {
1007  QgsDebugMsg( QStringLiteral( "No auth method registered for auth method key: %1" ).arg( authMethodKey ) );
1008  return nullptr;
1009  }
1010 
1011  return mAuthMethods.value( authMethodKey );
1012 }
1013 
1015 {
1016  if ( dataprovider.isEmpty() )
1017  {
1018  return mAuthMethods;
1019  }
1020 
1021  QgsAuthMethodsMap filteredmap;
1022  QgsAuthMethodsMap::const_iterator i = mAuthMethods.constBegin();
1023  while ( i != mAuthMethods.constEnd() )
1024  {
1025  if ( i.value()
1026  && ( i.value()->supportedDataProviders().contains( QStringLiteral( "all" ) )
1027  || i.value()->supportedDataProviders().contains( dataprovider ) ) )
1028  {
1029  filteredmap.insert( i.key(), i.value() );
1030  }
1031  ++i;
1032  }
1033  return filteredmap;
1034 }
1035 
1036 QWidget *QgsAuthManager::authMethodEditWidget( const QString &authMethodKey, QWidget *parent )
1037 {
1038  return QgsAuthMethodRegistry::instance()->editWidget( authMethodKey, parent );
1039 }
1040 
1041 QgsAuthMethod::Expansions QgsAuthManager::supportedAuthMethodExpansions( const QString &authcfg )
1042 {
1043  if ( isDisabled() )
1044  return QgsAuthMethod::Expansions( nullptr );
1045 
1046  QgsAuthMethod *authmethod = configAuthMethod( authcfg );
1047  if ( authmethod )
1048  {
1049  return authmethod->supportedExpansions();
1050  }
1051  return QgsAuthMethod::Expansions( nullptr );
1052 }
1053 
1055 {
1056  QMutexLocker locker( mMutex.get() );
1057  if ( !setMasterPassword( true ) )
1058  return false;
1059 
1060  // don't need to validate id, since it has not be defined yet
1061  if ( !mconfig.isValid() )
1062  {
1063  const char *err = QT_TR_NOOP( "Store config: FAILED because config is invalid" );
1064  QgsDebugMsg( err );
1065  emit messageOut( tr( err ), authManTag(), WARNING );
1066  return false;
1067  }
1068 
1069  QString uid = mconfig.id();
1070  bool passedinID = !uid.isEmpty();
1071  if ( uid.isEmpty() )
1072  {
1073  uid = uniqueConfigId();
1074  }
1075  else if ( configIds().contains( uid ) )
1076  {
1077  const char *err = QT_TR_NOOP( "Store config: FAILED because pre-defined config ID is not unique" );
1078  QgsDebugMsg( err );
1079  emit messageOut( tr( err ), authManTag(), WARNING );
1080  return false;
1081  }
1082 
1083  QString configstring = mconfig.configString();
1084  if ( configstring.isEmpty() )
1085  {
1086  const char *err = QT_TR_NOOP( "Store config: FAILED because config string is empty" );
1087  QgsDebugMsg( err );
1088  emit messageOut( tr( err ), authManTag(), WARNING );
1089  return false;
1090  }
1091 #if( 0 )
1092  QgsDebugMsg( QStringLiteral( "authDbConfigTable(): %1" ).arg( authDbConfigTable() ) );
1093  QgsDebugMsg( QStringLiteral( "name: %1" ).arg( config.name() ) );
1094  QgsDebugMsg( QStringLiteral( "uri: %1" ).arg( config.uri() ) );
1095  QgsDebugMsg( QStringLiteral( "type: %1" ).arg( config.method() ) );
1096  QgsDebugMsg( QStringLiteral( "version: %1" ).arg( config.version() ) );
1097  QgsDebugMsg( QStringLiteral( "config: %1" ).arg( configstring ) ); // DO NOT LEAVE THIS LINE UNCOMMENTED !
1098 #endif
1099 
1100  QSqlQuery query( authDatabaseConnection() );
1101  query.prepare( QStringLiteral( "INSERT INTO %1 (id, name, uri, type, version, config) "
1102  "VALUES (:id, :name, :uri, :type, :version, :config)" ).arg( authDatabaseConfigTable() ) );
1103 
1104  query.bindValue( QStringLiteral( ":id" ), uid );
1105  query.bindValue( QStringLiteral( ":name" ), mconfig.name() );
1106  query.bindValue( QStringLiteral( ":uri" ), mconfig.uri() );
1107  query.bindValue( QStringLiteral( ":type" ), mconfig.method() );
1108  query.bindValue( QStringLiteral( ":version" ), mconfig.version() );
1109  query.bindValue( QStringLiteral( ":config" ), QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
1110 
1111  if ( !authDbStartTransaction() )
1112  return false;
1113 
1114  if ( !authDbQuery( &query ) )
1115  return false;
1116 
1117  if ( !authDbCommit() )
1118  return false;
1119 
1120  // passed-in config should now be like as if it was just loaded from db
1121  if ( !passedinID )
1122  mconfig.setId( uid );
1123 
1125 
1126  QgsDebugMsg( QStringLiteral( "Store config SUCCESS for authcfg: %1" ).arg( uid ) );
1127  return true;
1128 
1129 }
1130 
1132 {
1133  QMutexLocker locker( mMutex.get() );
1134  if ( !setMasterPassword( true ) )
1135  return false;
1136 
1137  // validate id
1138  if ( !config.isValid( true ) )
1139  {
1140  const char *err = QT_TR_NOOP( "Update config: FAILED because config is invalid" );
1141  QgsDebugMsg( err );
1142  emit messageOut( tr( err ), authManTag(), WARNING );
1143  return false;
1144  }
1145 
1146  QString configstring = config.configString();
1147  if ( configstring.isEmpty() )
1148  {
1149  const char *err = QT_TR_NOOP( "Update config: FAILED because config is empty" );
1150  QgsDebugMsg( err );
1151  emit messageOut( tr( err ), authManTag(), WARNING );
1152  return false;
1153  }
1154 
1155 #if( 0 )
1156  QgsDebugMsg( QStringLiteral( "authDbConfigTable(): %1" ).arg( authDbConfigTable() ) );
1157  QgsDebugMsg( QStringLiteral( "id: %1" ).arg( config.id() ) );
1158  QgsDebugMsg( QStringLiteral( "name: %1" ).arg( config.name() ) );
1159  QgsDebugMsg( QStringLiteral( "uri: %1" ).arg( config.uri() ) );
1160  QgsDebugMsg( QStringLiteral( "type: %1" ).arg( config.method() ) );
1161  QgsDebugMsg( QStringLiteral( "version: %1" ).arg( config.version() ) );
1162  QgsDebugMsg( QStringLiteral( "config: %1" ).arg( configstring ) ); // DO NOT LEAVE THIS LINE UNCOMMENTED !
1163 #endif
1164 
1165  QSqlQuery query( authDatabaseConnection() );
1166  if ( !query.prepare( QStringLiteral( "UPDATE %1 "
1167  "SET name = :name, uri = :uri, type = :type, version = :version, config = :config "
1168  "WHERE id = :id" ).arg( authDatabaseConfigTable() ) ) )
1169  {
1170  const char *err = QT_TR_NOOP( "Update config: FAILED to prepare query" );
1171  QgsDebugMsg( err );
1172  emit messageOut( tr( err ), authManTag(), WARNING );
1173  return false;
1174  }
1175 
1176  query.bindValue( QStringLiteral( ":id" ), config.id() );
1177  query.bindValue( QStringLiteral( ":name" ), config.name() );
1178  query.bindValue( QStringLiteral( ":uri" ), config.uri() );
1179  query.bindValue( QStringLiteral( ":type" ), config.method() );
1180  query.bindValue( QStringLiteral( ":version" ), config.version() );
1181  query.bindValue( QStringLiteral( ":config" ), QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
1182 
1183  if ( !authDbStartTransaction() )
1184  return false;
1185 
1186  if ( !authDbQuery( &query ) )
1187  return false;
1188 
1189  if ( !authDbCommit() )
1190  return false;
1191 
1192  // should come before updating auth methods, in case user switched auth methods in config
1193  clearCachedConfig( config.id() );
1194 
1196 
1197  QgsDebugMsg( QStringLiteral( "Update config SUCCESS for authcfg: %1" ).arg( config.id() ) );
1198 
1199  return true;
1200 }
1201 
1202 bool QgsAuthManager::loadAuthenticationConfig( const QString &authcfg, QgsAuthMethodConfig &mconfig, bool full )
1203 {
1204  if ( isDisabled() )
1205  return false;
1206 
1207  if ( full && !setMasterPassword( true ) )
1208  return false;
1209 
1210  QMutexLocker locker( mMutex.get() );
1211 
1212  QSqlQuery query( authDatabaseConnection() );
1213  if ( full )
1214  {
1215  query.prepare( QStringLiteral( "SELECT id, name, uri, type, version, config FROM %1 "
1216  "WHERE id = :id" ).arg( authDatabaseConfigTable() ) );
1217  }
1218  else
1219  {
1220  query.prepare( QStringLiteral( "SELECT id, name, uri, type, version FROM %1 "
1221  "WHERE id = :id" ).arg( authDatabaseConfigTable() ) );
1222  }
1223 
1224  query.bindValue( QStringLiteral( ":id" ), authcfg );
1225 
1226  if ( !authDbQuery( &query ) )
1227  {
1228  return false;
1229  }
1230 
1231  if ( query.isActive() && query.isSelect() )
1232  {
1233  if ( query.first() )
1234  {
1235  mconfig.setId( query.value( 0 ).toString() );
1236  mconfig.setName( query.value( 1 ).toString() );
1237  mconfig.setUri( query.value( 2 ).toString() );
1238  mconfig.setMethod( query.value( 3 ).toString() );
1239  mconfig.setVersion( query.value( 4 ).toInt() );
1240 
1241  if ( full )
1242  {
1243  mconfig.loadConfigString( QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 5 ).toString() ) );
1244  }
1245 
1246  QString authMethodKey = configAuthMethodKey( authcfg );
1247  QgsAuthMethod *authmethod = authMethod( authMethodKey );
1248  if ( authmethod )
1249  {
1250  authmethod->updateMethodConfig( mconfig );
1251  }
1252  else
1253  {
1254  QgsDebugMsg( QStringLiteral( "Update of authcfg %1 FAILED for auth method %2" ).arg( authcfg, authMethodKey ) );
1255  }
1256 
1257  QgsDebugMsg( QStringLiteral( "Load %1 config SUCCESS for authcfg: %2" ).arg( full ? "full" : "base", authcfg ) );
1258  return true;
1259  }
1260  if ( query.next() )
1261  {
1262  QgsDebugMsg( QStringLiteral( "Select contains more than one for authcfg: %1" ).arg( authcfg ) );
1263  emit messageOut( tr( "Authentication database contains duplicate configuration IDs" ), authManTag(), WARNING );
1264  }
1265  }
1266 
1267  return false;
1268 }
1269 
1270 bool QgsAuthManager::removeAuthenticationConfig( const QString &authcfg )
1271 {
1272  QMutexLocker locker( mMutex.get() );
1273  if ( isDisabled() )
1274  return false;
1275 
1276  if ( authcfg.isEmpty() )
1277  return false;
1278 
1279  QSqlQuery query( authDatabaseConnection() );
1280 
1281  query.prepare( QStringLiteral( "DELETE FROM %1 WHERE id = :id" ).arg( authDatabaseConfigTable() ) );
1282 
1283  query.bindValue( QStringLiteral( ":id" ), authcfg );
1284 
1285  if ( !authDbStartTransaction() )
1286  return false;
1287 
1288  if ( !authDbQuery( &query ) )
1289  return false;
1290 
1291  if ( !authDbCommit() )
1292  return false;
1293 
1294  clearCachedConfig( authcfg );
1295 
1297 
1298  QgsDebugMsg( QStringLiteral( "REMOVED config for authcfg: %1" ).arg( authcfg ) );
1299 
1300  return true;
1301 }
1302 
1304 {
1305  QMutexLocker locker( mMutex.get() );
1306  if ( isDisabled() )
1307  return false;
1308 
1309  QSqlQuery query( authDatabaseConnection() );
1310  query.prepare( QStringLiteral( "DELETE FROM %1" ).arg( authDatabaseConfigTable() ) );
1311  bool res = authDbTransactionQuery( &query );
1312 
1313  if ( res )
1314  {
1317  }
1318 
1319  QgsDebugMsg( QStringLiteral( "Remove configs from database: %1" ).arg( res ? "SUCCEEDED" : "FAILED" ) );
1320 
1321  return res;
1322 }
1323 
1325 {
1326  QMutexLocker locker( mMutex.get() );
1327  if ( !QFile::exists( authenticationDatabasePath() ) )
1328  {
1329  const char *err = QT_TR_NOOP( "No authentication database found" );
1330  QgsDebugMsg( err );
1331  emit messageOut( tr( err ), authManTag(), WARNING );
1332  return false;
1333  }
1334 
1335  // close any connection to current db
1336  QSqlDatabase authConn = authDatabaseConnection();
1337  if ( authConn.isValid() && authConn.isOpen() )
1338  authConn.close();
1339 
1340  // duplicate current db file to 'qgis-auth_YYYY-MM-DD-HHMMSS.db' backup
1341  QString datestamp( QDateTime::currentDateTime().toString( QStringLiteral( "yyyy-MM-dd-hhmmss" ) ) );
1342  QString dbbackup( authenticationDatabasePath() );
1343  dbbackup.replace( QLatin1String( ".db" ), QStringLiteral( "_%1.db" ).arg( datestamp ) );
1344 
1345  if ( !QFile::copy( authenticationDatabasePath(), dbbackup ) )
1346  {
1347  const char *err = QT_TR_NOOP( "Could not back up authentication database" );
1348  QgsDebugMsg( err );
1349  emit messageOut( tr( err ), authManTag(), WARNING );
1350  return false;
1351  }
1352 
1353  if ( backuppath )
1354  *backuppath = dbbackup;
1355 
1356  QgsDebugMsg( QStringLiteral( "Backed up auth database at %1" ).arg( dbbackup ) );
1357  return true;
1358 }
1359 
1360 bool QgsAuthManager::eraseAuthenticationDatabase( bool backup, QString *backuppath )
1361 {
1362  QMutexLocker locker( mMutex.get() );
1363  if ( isDisabled() )
1364  return false;
1365 
1366  QString dbbackup;
1367  if ( backup && !backupAuthenticationDatabase( &dbbackup ) )
1368  {
1369  return false;
1370  }
1371 
1372  if ( backuppath && !dbbackup.isEmpty() )
1373  *backuppath = dbbackup;
1374 
1375  QFileInfo dbinfo( authenticationDatabasePath() );
1376  if ( dbinfo.exists() )
1377  {
1378  if ( !dbinfo.permission( QFile::ReadOwner | QFile::WriteOwner ) )
1379  {
1380  const char *err = QT_TR_NOOP( "Auth db is not readable or writable by user" );
1381  QgsDebugMsg( err );
1382  emit messageOut( tr( err ), authManTag(), CRITICAL );
1383  return false;
1384  }
1385  }
1386  else
1387  {
1388  const char *err = QT_TR_NOOP( "No authentication database found" );
1389  QgsDebugMsg( err );
1390  emit messageOut( tr( err ), authManTag(), WARNING );
1391  return false;
1392  }
1393 
1394  if ( !QFile::remove( authenticationDatabasePath() ) )
1395  {
1396  const char *err = QT_TR_NOOP( "Authentication database could not be deleted" );
1397  QgsDebugMsg( err );
1398  emit messageOut( tr( err ), authManTag(), WARNING );
1399  return false;
1400  }
1401 
1402  mMasterPass = QString();
1403 
1404  QgsDebugMsg( QStringLiteral( "Creating Auth db through QSqlDatabase initial connection" ) );
1405 
1406  QSqlDatabase authConn = authDatabaseConnection();
1407  if ( !authConn.isValid() || !authConn.isOpen() )
1408  {
1409  const char *err = QT_TR_NOOP( "Authentication database could not be initialized" );
1410  QgsDebugMsg( err );
1411  emit messageOut( tr( err ), authManTag(), WARNING );
1412  return false;
1413  }
1414 
1415  if ( !createConfigTables() )
1416  {
1417  const char *err = QT_TR_NOOP( "FAILED to create auth database config tables" );
1418  QgsDebugMsg( err );
1419  emit messageOut( tr( err ), authManTag(), WARNING );
1420  return false;
1421  }
1422 
1423  if ( !createCertTables() )
1424  {
1425  const char *err = QT_TR_NOOP( "FAILED to create auth database cert tables" );
1426  QgsDebugMsg( err );
1427  emit messageOut( tr( err ), authManTag(), WARNING );
1428  return false;
1429  }
1430 
1433  initSslCaches();
1434 
1435  emit authDatabaseChanged();
1436 
1437  return true;
1438 }
1439 
1440 bool QgsAuthManager::updateNetworkRequest( QNetworkRequest &request, const QString &authcfg,
1441  const QString &dataprovider )
1442 {
1443  if ( isDisabled() )
1444  return false;
1445 
1446  QgsAuthMethod *authmethod = configAuthMethod( authcfg );
1447  if ( authmethod )
1448  {
1449  if ( !( authmethod->supportedExpansions() & QgsAuthMethod::NetworkRequest ) )
1450  {
1451  QgsDebugMsg( QStringLiteral( "Network request updating not supported by authcfg: %1" ).arg( authcfg ) );
1452  return true;
1453  }
1454 
1455  if ( !authmethod->updateNetworkRequest( request, authcfg, dataprovider.toLower() ) )
1456  {
1457  authmethod->clearCachedConfig( authcfg );
1458  return false;
1459  }
1460  return true;
1461  }
1462  return false;
1463 }
1464 
1465 bool QgsAuthManager::updateNetworkReply( QNetworkReply *reply, const QString &authcfg,
1466  const QString &dataprovider )
1467 {
1468  if ( isDisabled() )
1469  return false;
1470 
1471  QgsAuthMethod *authmethod = configAuthMethod( authcfg );
1472  if ( authmethod )
1473  {
1474  if ( !( authmethod->supportedExpansions() & QgsAuthMethod::NetworkReply ) )
1475  {
1476  QgsDebugMsg( QStringLiteral( "Network reply updating not supported by authcfg: %1" ).arg( authcfg ) );
1477  return true;
1478  }
1479 
1480  if ( !authmethod->updateNetworkReply( reply, authcfg, dataprovider.toLower() ) )
1481  {
1482  authmethod->clearCachedConfig( authcfg );
1483  return false;
1484  }
1485  return true;
1486  }
1487 
1488  return false;
1489 }
1490 
1491 bool QgsAuthManager::updateDataSourceUriItems( QStringList &connectionItems, const QString &authcfg,
1492  const QString &dataprovider )
1493 {
1494  if ( isDisabled() )
1495  return false;
1496 
1497  QgsAuthMethod *authmethod = configAuthMethod( authcfg );
1498  if ( authmethod )
1499  {
1500  if ( !( authmethod->supportedExpansions() & QgsAuthMethod::DataSourceUri ) )
1501  {
1502  QgsDebugMsg( QStringLiteral( "Data source URI updating not supported by authcfg: %1" ).arg( authcfg ) );
1503  return true;
1504  }
1505 
1506  if ( !authmethod->updateDataSourceUriItems( connectionItems, authcfg, dataprovider.toLower() ) )
1507  {
1508  authmethod->clearCachedConfig( authcfg );
1509  return false;
1510  }
1511  return true;
1512  }
1513 
1514  return false;
1515 }
1516 
1517 bool QgsAuthManager::updateNetworkProxy( QNetworkProxy &proxy, const QString &authcfg, const QString &dataprovider )
1518 {
1519  if ( isDisabled() )
1520  return false;
1521 
1522  QgsAuthMethod *authmethod = configAuthMethod( authcfg );
1523  if ( authmethod )
1524  {
1525  if ( !( authmethod->supportedExpansions() & QgsAuthMethod::NetworkProxy ) )
1526  {
1527  QgsDebugMsg( QStringLiteral( "Proxy updating not supported by authcfg: %1" ).arg( authcfg ) );
1528  return true;
1529  }
1530 
1531  if ( !authmethod->updateNetworkProxy( proxy, authcfg, dataprovider.toLower() ) )
1532  {
1533  authmethod->clearCachedConfig( authcfg );
1534  return false;
1535  }
1536  QgsDebugMsg( QStringLiteral( "Proxy updated successfully from authcfg: %1" ).arg( authcfg ) );
1537  return true;
1538  }
1539 
1540  return false;
1541 }
1542 
1543 bool QgsAuthManager::storeAuthSetting( const QString &key, const QVariant &value, bool encrypt )
1544 {
1545  QMutexLocker locker( mMutex.get() );
1546  if ( key.isEmpty() )
1547  return false;
1548 
1549  QString storeval( value.toString() );
1550  if ( encrypt )
1551  {
1552  if ( !setMasterPassword( true ) )
1553  {
1554  return false;
1555  }
1556  else
1557  {
1558  storeval = QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), value.toString() );
1559  }
1560  }
1561 
1562  removeAuthSetting( key );
1563 
1564  QSqlQuery query( authDatabaseConnection() );
1565  query.prepare( QStringLiteral( "INSERT INTO %1 (setting, value) "
1566  "VALUES (:setting, :value)" ).arg( authDbSettingsTable() ) );
1567 
1568  query.bindValue( QStringLiteral( ":setting" ), key );
1569  query.bindValue( QStringLiteral( ":value" ), storeval );
1570 
1571  if ( !authDbStartTransaction() )
1572  return false;
1573 
1574  if ( !authDbQuery( &query ) )
1575  return false;
1576 
1577  if ( !authDbCommit() )
1578  return false;
1579 
1580  QgsDebugMsg( QStringLiteral( "Store setting SUCCESS for key: %1" ).arg( key ) );
1581  return true;
1582 }
1583 
1584 QVariant QgsAuthManager::authSetting( const QString &key, const QVariant &defaultValue, bool decrypt )
1585 {
1586  QMutexLocker locker( mMutex.get() );
1587  if ( key.isEmpty() )
1588  return QVariant();
1589 
1590  if ( decrypt && !setMasterPassword( true ) )
1591  return QVariant();
1592 
1593  QVariant value = defaultValue;
1594  QSqlQuery query( authDatabaseConnection() );
1595  query.prepare( QStringLiteral( "SELECT value FROM %1 "
1596  "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
1597 
1598  query.bindValue( QStringLiteral( ":setting" ), key );
1599 
1600  if ( !authDbQuery( &query ) )
1601  return QVariant();
1602 
1603  if ( query.isActive() && query.isSelect() )
1604  {
1605  if ( query.first() )
1606  {
1607  if ( decrypt )
1608  {
1609  value = QVariant( QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 0 ).toString() ) );
1610  }
1611  else
1612  {
1613  value = query.value( 0 );
1614  }
1615  QgsDebugMsg( QStringLiteral( "Authentication setting retrieved for key: %1" ).arg( key ) );
1616  }
1617  if ( query.next() )
1618  {
1619  QgsDebugMsg( QStringLiteral( "Select contains more than one for setting key: %1" ).arg( key ) );
1620  emit messageOut( tr( "Authentication database contains duplicate settings" ), authManTag(), WARNING );
1621  return QVariant();
1622  }
1623  }
1624  return value;
1625 }
1626 
1627 bool QgsAuthManager::existsAuthSetting( const QString &key )
1628 {
1629  QMutexLocker locker( mMutex.get() );
1630  if ( key.isEmpty() )
1631  return false;
1632 
1633  QSqlQuery query( authDatabaseConnection() );
1634  query.prepare( QStringLiteral( "SELECT value FROM %1 "
1635  "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
1636 
1637  query.bindValue( QStringLiteral( ":setting" ), key );
1638 
1639  if ( !authDbQuery( &query ) )
1640  return false;
1641 
1642  bool res = false;
1643  if ( query.isActive() && query.isSelect() )
1644  {
1645  if ( query.first() )
1646  {
1647  QgsDebugMsg( QStringLiteral( "Authentication setting exists for key: %1" ).arg( key ) );
1648  res = true;
1649  }
1650  if ( query.next() )
1651  {
1652  QgsDebugMsg( QStringLiteral( "Select contains more than one for setting key: %1" ).arg( key ) );
1653  emit messageOut( tr( "Authentication database contains duplicate settings" ), authManTag(), WARNING );
1654  return false;
1655  }
1656  }
1657  return res;
1658 }
1659 
1660 bool QgsAuthManager::removeAuthSetting( const QString &key )
1661 {
1662  QMutexLocker locker( mMutex.get() );
1663  if ( key.isEmpty() )
1664  return false;
1665 
1666  QSqlQuery query( authDatabaseConnection() );
1667 
1668  query.prepare( QStringLiteral( "DELETE FROM %1 WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
1669 
1670  query.bindValue( QStringLiteral( ":setting" ), key );
1671 
1672  if ( !authDbStartTransaction() )
1673  return false;
1674 
1675  if ( !authDbQuery( &query ) )
1676  return false;
1677 
1678  if ( !authDbCommit() )
1679  return false;
1680 
1681  QgsDebugMsg( QStringLiteral( "REMOVED setting for key: %1" ).arg( key ) );
1682 
1683  return true;
1684 }
1685 
1686 
1687 #ifndef QT_NO_SSL
1688 
1690 
1692 {
1693  QgsScopedRuntimeProfile profile( "Initialize SSL cache" );
1694 
1695  QMutexLocker locker( mMutex.get() );
1696  bool res = true;
1697  res = res && rebuildCaCertsCache();
1698  res = res && rebuildCertTrustCache();
1699  res = res && rebuildTrustedCaCertsCache();
1700  res = res && rebuildIgnoredSslErrorCache();
1701  mCustomConfigByHostCache.clear();
1702  mHasCheckedIfCustomConfigByHostExists = false;
1703 
1704  if ( !res )
1705  QgsDebugMsg( QStringLiteral( "Init of SSL caches FAILED" ) );
1706  return res;
1707 }
1708 
1709 bool QgsAuthManager::storeCertIdentity( const QSslCertificate &cert, const QSslKey &key )
1710 {
1711  QMutexLocker locker( mMutex.get() );
1712  if ( cert.isNull() )
1713  {
1714  QgsDebugMsg( QStringLiteral( "Passed certificate is null" ) );
1715  return false;
1716  }
1717  if ( key.isNull() )
1718  {
1719  QgsDebugMsg( QStringLiteral( "Passed private key is null" ) );
1720  return false;
1721  }
1722 
1723  if ( !setMasterPassword( true ) )
1724  return false;
1725 
1726  QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
1727  removeCertIdentity( id );
1728 
1729  QString certpem( cert.toPem() );
1730  QString keypem( QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), key.toPem() ) );
1731 
1732  QSqlQuery query( authDatabaseConnection() );
1733  query.prepare( QStringLiteral( "INSERT INTO %1 (id, key, cert) "
1734  "VALUES (:id, :key, :cert)" ).arg( authDbIdentitiesTable() ) );
1735 
1736  query.bindValue( QStringLiteral( ":id" ), id );
1737  query.bindValue( QStringLiteral( ":key" ), keypem );
1738  query.bindValue( QStringLiteral( ":cert" ), certpem );
1739 
1740  if ( !authDbStartTransaction() )
1741  return false;
1742 
1743  if ( !authDbQuery( &query ) )
1744  return false;
1745 
1746  if ( !authDbCommit() )
1747  return false;
1748 
1749  QgsDebugMsgLevel( QStringLiteral( "Store certificate identity SUCCESS for id: %1" ).arg( id ), 2 );
1750  return true;
1751 }
1752 
1753 const QSslCertificate QgsAuthManager::certIdentity( const QString &id )
1754 {
1755  QMutexLocker locker( mMutex.get() );
1756  QSslCertificate emptycert;
1757  QSslCertificate cert;
1758  if ( id.isEmpty() )
1759  return emptycert;
1760 
1761  QSqlQuery query( authDatabaseConnection() );
1762  query.prepare( QStringLiteral( "SELECT cert FROM %1 "
1763  "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1764 
1765  query.bindValue( QStringLiteral( ":id" ), id );
1766 
1767  if ( !authDbQuery( &query ) )
1768  return emptycert;
1769 
1770  if ( query.isActive() && query.isSelect() )
1771  {
1772  if ( query.first() )
1773  {
1774  cert = QSslCertificate( query.value( 0 ).toByteArray(), QSsl::Pem );
1775  QgsDebugMsg( QStringLiteral( "Certificate identity retrieved for id: %1" ).arg( id ) );
1776  }
1777  if ( query.next() )
1778  {
1779  QgsDebugMsg( QStringLiteral( "Select contains more than one certificate identity for id: %1" ).arg( id ) );
1780  emit messageOut( tr( "Authentication database contains duplicate certificate identity" ), authManTag(), WARNING );
1781  return emptycert;
1782  }
1783  }
1784  return cert;
1785 }
1786 
1787 const QPair<QSslCertificate, QSslKey> QgsAuthManager::certIdentityBundle( const QString &id )
1788 {
1789  QMutexLocker locker( mMutex.get() );
1790  QPair<QSslCertificate, QSslKey> bundle;
1791  if ( id.isEmpty() )
1792  return bundle;
1793 
1794  if ( !setMasterPassword( true ) )
1795  return bundle;
1796 
1797  QSqlQuery query( authDatabaseConnection() );
1798  query.prepare( QStringLiteral( "SELECT key, cert FROM %1 "
1799  "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1800 
1801  query.bindValue( QStringLiteral( ":id" ), id );
1802 
1803  if ( !authDbQuery( &query ) )
1804  return bundle;
1805 
1806  if ( query.isActive() && query.isSelect() )
1807  {
1808  QSslCertificate cert;
1809  QSslKey key;
1810  if ( query.first() )
1811  {
1812  key = QSslKey( QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 0 ).toString() ).toLatin1(),
1813  QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey );
1814  if ( key.isNull() )
1815  {
1816  const char *err = QT_TR_NOOP( "Retrieve certificate identity bundle: FAILED to create private key" );
1817  QgsDebugMsg( err );
1818  emit messageOut( tr( err ), authManTag(), WARNING );
1819  return bundle;
1820  }
1821  cert = QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
1822  if ( cert.isNull() )
1823  {
1824  const char *err = QT_TR_NOOP( "Retrieve certificate identity bundle: FAILED to create certificate" );
1825  QgsDebugMsg( err );
1826  emit messageOut( tr( err ), authManTag(), WARNING );
1827  return bundle;
1828  }
1829  QgsDebugMsg( QStringLiteral( "Certificate identity bundle retrieved for id: %1" ).arg( id ) );
1830  }
1831  if ( query.next() )
1832  {
1833  QgsDebugMsg( QStringLiteral( "Select contains more than one certificate identity for id: %1" ).arg( id ) );
1834  emit messageOut( tr( "Authentication database contains duplicate certificate identity" ), authManTag(), WARNING );
1835  return bundle;
1836  }
1837  bundle = qMakePair( cert, key );
1838  }
1839  return bundle;
1840 }
1841 
1842 const QStringList QgsAuthManager::certIdentityBundleToPem( const QString &id )
1843 {
1844  QMutexLocker locker( mMutex.get() );
1845  QPair<QSslCertificate, QSslKey> bundle( certIdentityBundle( id ) );
1846  if ( QgsAuthCertUtils::certIsViable( bundle.first ) && !bundle.second.isNull() )
1847  {
1848  return QStringList() << QString( bundle.first.toPem() ) << QString( bundle.second.toPem() );
1849  }
1850  return QStringList();
1851 }
1852 
1853 const QList<QSslCertificate> QgsAuthManager::certIdentities()
1854 {
1855  QMutexLocker locker( mMutex.get() );
1856  QList<QSslCertificate> certs;
1857 
1858  QSqlQuery query( authDatabaseConnection() );
1859  query.prepare( QStringLiteral( "SELECT id, cert FROM %1" ).arg( authDbIdentitiesTable() ) );
1860 
1861  if ( !authDbQuery( &query ) )
1862  return certs;
1863 
1864  if ( query.isActive() && query.isSelect() )
1865  {
1866  while ( query.next() )
1867  {
1868  certs << QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
1869  }
1870  }
1871 
1872  return certs;
1873 }
1874 
1876 {
1877  QMutexLocker locker( mMutex.get() );
1878  QStringList identityids = QStringList();
1879 
1880  if ( isDisabled() )
1881  return identityids;
1882 
1883  QSqlQuery query( authDatabaseConnection() );
1884  query.prepare( QStringLiteral( "SELECT id FROM %1" ).arg( authDbIdentitiesTable() ) );
1885 
1886  if ( !authDbQuery( &query ) )
1887  {
1888  return identityids;
1889  }
1890 
1891  if ( query.isActive() )
1892  {
1893  while ( query.next() )
1894  {
1895  identityids << query.value( 0 ).toString();
1896  }
1897  }
1898  return identityids;
1899 }
1900 
1901 bool QgsAuthManager::existsCertIdentity( const QString &id )
1902 {
1903  QMutexLocker locker( mMutex.get() );
1904  if ( id.isEmpty() )
1905  return false;
1906 
1907  QSqlQuery query( authDatabaseConnection() );
1908  query.prepare( QStringLiteral( "SELECT cert FROM %1 "
1909  "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1910 
1911  query.bindValue( QStringLiteral( ":id" ), id );
1912 
1913  if ( !authDbQuery( &query ) )
1914  return false;
1915 
1916  bool res = false;
1917  if ( query.isActive() && query.isSelect() )
1918  {
1919  if ( query.first() )
1920  {
1921  QgsDebugMsg( QStringLiteral( "Certificate bundle exists for id: %1" ).arg( id ) );
1922  res = true;
1923  }
1924  if ( query.next() )
1925  {
1926  QgsDebugMsg( QStringLiteral( "Select contains more than one certificate bundle for id: %1" ).arg( id ) );
1927  emit messageOut( tr( "Authentication database contains duplicate certificate bundles" ), authManTag(), WARNING );
1928  return false;
1929  }
1930  }
1931  return res;
1932 }
1933 
1934 bool QgsAuthManager::removeCertIdentity( const QString &id )
1935 {
1936  QMutexLocker locker( mMutex.get() );
1937  if ( id.isEmpty() )
1938  {
1939  QgsDebugMsg( QStringLiteral( "Passed bundle ID is empty" ) );
1940  return false;
1941  }
1942 
1943  QSqlQuery query( authDatabaseConnection() );
1944 
1945  query.prepare( QStringLiteral( "DELETE FROM %1 WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
1946 
1947  query.bindValue( QStringLiteral( ":id" ), id );
1948 
1949  if ( !authDbStartTransaction() )
1950  return false;
1951 
1952  if ( !authDbQuery( &query ) )
1953  return false;
1954 
1955  if ( !authDbCommit() )
1956  return false;
1957 
1958  QgsDebugMsg( QStringLiteral( "REMOVED certificate identity for id: %1" ).arg( id ) );
1959  return true;
1960 }
1961 
1963 {
1964  QMutexLocker locker( mMutex.get() );
1965  if ( config.isNull() )
1966  {
1967  QgsDebugMsg( QStringLiteral( "Passed config is null" ) );
1968  return false;
1969  }
1970 
1971  QSslCertificate cert( config.sslCertificate() );
1972 
1973  QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
1974  removeSslCertCustomConfig( id, config.sslHostPort().trimmed() );
1975 
1976  QString certpem( cert.toPem() );
1977 
1978  QSqlQuery query( authDatabaseConnection() );
1979  query.prepare( QStringLiteral( "INSERT OR REPLACE INTO %1 (id, host, cert, config) "
1980  "VALUES (:id, :host, :cert, :config)" ).arg( authDatabaseServersTable() ) );
1981 
1982  query.bindValue( QStringLiteral( ":id" ), id );
1983  query.bindValue( QStringLiteral( ":host" ), config.sslHostPort().trimmed() );
1984  query.bindValue( QStringLiteral( ":cert" ), certpem );
1985  query.bindValue( QStringLiteral( ":config" ), config.configString() );
1986 
1987  if ( !authDbStartTransaction() )
1988  return false;
1989 
1990  if ( !authDbQuery( &query ) )
1991  return false;
1992 
1993  if ( !authDbCommit() )
1994  return false;
1995 
1996  QgsDebugMsg( QStringLiteral( "Store SSL cert custom config SUCCESS for host:port, id: %1, %2" )
1997  .arg( config.sslHostPort().trimmed(), id ) );
1998 
2000  mHasCheckedIfCustomConfigByHostExists = false;
2001  mCustomConfigByHostCache.clear();
2002 
2003  return true;
2004 }
2005 
2006 const QgsAuthConfigSslServer QgsAuthManager::sslCertCustomConfig( const QString &id, const QString &hostport )
2007 {
2008  QMutexLocker locker( mMutex.get() );
2009  QgsAuthConfigSslServer config;
2010 
2011  if ( id.isEmpty() || hostport.isEmpty() )
2012  {
2013  QgsDebugMsg( QStringLiteral( "Passed config ID or host:port is empty" ) );
2014  return config;
2015  }
2016 
2017  QSqlQuery query( authDatabaseConnection() );
2018  query.prepare( QStringLiteral( "SELECT id, host, cert, config FROM %1 "
2019  "WHERE id = :id AND host = :host" ).arg( authDatabaseServersTable() ) );
2020 
2021  query.bindValue( QStringLiteral( ":id" ), id );
2022  query.bindValue( QStringLiteral( ":host" ), hostport.trimmed() );
2023 
2024  if ( !authDbQuery( &query ) )
2025  return config;
2026 
2027  if ( query.isActive() && query.isSelect() )
2028  {
2029  if ( query.first() )
2030  {
2031  config.setSslCertificate( QSslCertificate( query.value( 2 ).toByteArray(), QSsl::Pem ) );
2032  config.setSslHostPort( query.value( 1 ).toString().trimmed() );
2033  config.loadConfigString( query.value( 3 ).toString() );
2034  QgsDebugMsg( QStringLiteral( "SSL cert custom config retrieved for host:port, id: %1, %2" ).arg( hostport, id ) );
2035  }
2036  if ( query.next() )
2037  {
2038  QgsDebugMsg( QStringLiteral( "Select contains more than one SSL cert custom config for host:port, id: %1, %2" ).arg( hostport, id ) );
2039  emit messageOut( tr( "Authentication database contains duplicate SSL cert custom configs for host:port, id: %1, %2" )
2040  .arg( hostport, id ), authManTag(), WARNING );
2041  QgsAuthConfigSslServer emptyconfig;
2042  return emptyconfig;
2043  }
2044  }
2045  return config;
2046 }
2047 
2049 {
2050  QgsAuthConfigSslServer config;
2051  if ( hostport.isEmpty() )
2052  {
2053  return config;
2054  }
2055 
2056  QMutexLocker locker( mMutex.get() );
2057  if ( mHasCheckedIfCustomConfigByHostExists && !mHasCustomConfigByHost )
2058  return config;
2059  if ( mCustomConfigByHostCache.contains( hostport ) )
2060  return mCustomConfigByHostCache.value( hostport );
2061 
2062  QSqlQuery query( authDatabaseConnection() );
2063 
2064  // first run -- see if we have ANY custom config by host. If not, we can skip all future checks for any host
2065  if ( !mHasCheckedIfCustomConfigByHostExists )
2066  {
2067  mHasCheckedIfCustomConfigByHostExists = true;
2068  query.prepare( QString( "SELECT count(*) FROM %1" ).arg( authDatabaseServersTable() ) );
2069  if ( !authDbQuery( &query ) )
2070  {
2071  mHasCustomConfigByHost = false;
2072  return config;
2073  }
2074  if ( query.isActive() && query.isSelect() && query.first() )
2075  {
2076  mHasCustomConfigByHost = query.value( 0 ).toInt() > 0;
2077  if ( !mHasCustomConfigByHost )
2078  return config;
2079  }
2080  else
2081  {
2082  mHasCustomConfigByHost = false;
2083  return config;
2084  }
2085  }
2086 
2087  query.prepare( QString( "SELECT id, host, cert, config FROM %1 "
2088  "WHERE host = :host" ).arg( authDatabaseServersTable() ) );
2089 
2090  query.bindValue( QStringLiteral( ":host" ), hostport.trimmed() );
2091 
2092  if ( !authDbQuery( &query ) )
2093  {
2094  mCustomConfigByHostCache.insert( hostport, config );
2095  return config;
2096  }
2097 
2098  if ( query.isActive() && query.isSelect() )
2099  {
2100  if ( query.first() )
2101  {
2102  config.setSslCertificate( QSslCertificate( query.value( 2 ).toByteArray(), QSsl::Pem ) );
2103  config.setSslHostPort( query.value( 1 ).toString().trimmed() );
2104  config.loadConfigString( query.value( 3 ).toString() );
2105  QgsDebugMsg( QStringLiteral( "SSL cert custom config retrieved for host:port: %1" ).arg( hostport ) );
2106  }
2107  if ( query.next() )
2108  {
2109  QgsDebugMsg( QStringLiteral( "Select contains more than one SSL cert custom config for host:port: %1" ).arg( hostport ) );
2110  emit messageOut( tr( "Authentication database contains duplicate SSL cert custom configs for host:port: %1" )
2111  .arg( hostport ), authManTag(), WARNING );
2112  QgsAuthConfigSslServer emptyconfig;
2113  mCustomConfigByHostCache.insert( hostport, emptyconfig );
2114  return emptyconfig;
2115  }
2116  }
2117 
2118  mCustomConfigByHostCache.insert( hostport, config );
2119  return config;
2120 }
2121 
2122 const QList<QgsAuthConfigSslServer> QgsAuthManager::sslCertCustomConfigs()
2123 {
2124  QMutexLocker locker( mMutex.get() );
2125  QList<QgsAuthConfigSslServer> configs;
2126 
2127  QSqlQuery query( authDatabaseConnection() );
2128  query.prepare( QStringLiteral( "SELECT id, host, cert, config FROM %1" ).arg( authDatabaseServersTable() ) );
2129 
2130  if ( !authDbQuery( &query ) )
2131  return configs;
2132 
2133  if ( query.isActive() && query.isSelect() )
2134  {
2135  while ( query.next() )
2136  {
2137  QgsAuthConfigSslServer config;
2138  config.setSslCertificate( QSslCertificate( query.value( 2 ).toByteArray(), QSsl::Pem ) );
2139  config.setSslHostPort( query.value( 1 ).toString().trimmed() );
2140  config.loadConfigString( query.value( 3 ).toString() );
2141 
2142  configs.append( config );
2143  }
2144  }
2145 
2146  return configs;
2147 }
2148 
2149 bool QgsAuthManager::existsSslCertCustomConfig( const QString &id, const QString &hostport )
2150 {
2151  QMutexLocker locker( mMutex.get() );
2152  if ( id.isEmpty() || hostport.isEmpty() )
2153  {
2154  QgsDebugMsg( QStringLiteral( "Passed config ID or host:port is empty" ) );
2155  return false;
2156  }
2157 
2158  QSqlQuery query( authDatabaseConnection() );
2159  query.prepare( QStringLiteral( "SELECT cert FROM %1 "
2160  "WHERE id = :id AND host = :host" ).arg( authDatabaseServersTable() ) );
2161 
2162  query.bindValue( QStringLiteral( ":id" ), id );
2163  query.bindValue( QStringLiteral( ":host" ), hostport.trimmed() );
2164 
2165  if ( !authDbQuery( &query ) )
2166  return false;
2167 
2168  bool res = false;
2169  if ( query.isActive() && query.isSelect() )
2170  {
2171  if ( query.first() )
2172  {
2173  QgsDebugMsg( QStringLiteral( "SSL cert custom config exists for host:port, id: %1, %2" ).arg( hostport, id ) );
2174  res = true;
2175  }
2176  if ( query.next() )
2177  {
2178  QgsDebugMsg( QStringLiteral( "Select contains more than one SSL cert custom config for host:port, id: %1, %2" ).arg( hostport, id ) );
2179  emit messageOut( tr( "Authentication database contains duplicate SSL cert custom configs for host:port, id: %1, %2" )
2180  .arg( hostport, id ), authManTag(), WARNING );
2181  return false;
2182  }
2183  }
2184  return res;
2185 }
2186 
2187 bool QgsAuthManager::removeSslCertCustomConfig( const QString &id, const QString &hostport )
2188 {
2189  QMutexLocker locker( mMutex.get() );
2190  if ( id.isEmpty() || hostport.isEmpty() )
2191  {
2192  QgsDebugMsg( QStringLiteral( "Passed config ID or host:port is empty" ) );
2193  return false;
2194  }
2195 
2196  mHasCheckedIfCustomConfigByHostExists = false;
2197  mCustomConfigByHostCache.clear();
2198 
2199  QSqlQuery query( authDatabaseConnection() );
2200 
2201  query.prepare( QStringLiteral( "DELETE FROM %1 WHERE id = :id AND host = :host" ).arg( authDatabaseServersTable() ) );
2202 
2203  query.bindValue( QStringLiteral( ":id" ), id );
2204  query.bindValue( QStringLiteral( ":host" ), hostport.trimmed() );
2205 
2206  if ( !authDbStartTransaction() )
2207  return false;
2208 
2209  if ( !authDbQuery( &query ) )
2210  return false;
2211 
2212  if ( !authDbCommit() )
2213  return false;
2214 
2215  QString shahostport( QStringLiteral( "%1:%2" ).arg( id, hostport ) );
2216  if ( mIgnoredSslErrorsCache.contains( shahostport ) )
2217  {
2218  mIgnoredSslErrorsCache.remove( shahostport );
2219  }
2220 
2221  QgsDebugMsg( QStringLiteral( "REMOVED SSL cert custom config for host:port, id: %1, %2" ).arg( hostport, id ) );
2223  return true;
2224 }
2225 
2227 {
2228  QMutexLocker locker( mMutex.get() );
2229  if ( !mIgnoredSslErrorsCache.isEmpty() )
2230  {
2231  QgsDebugMsg( QStringLiteral( "Ignored SSL errors cache items:" ) );
2232  QHash<QString, QSet<QSslError::SslError> >::const_iterator i = mIgnoredSslErrorsCache.constBegin();
2233  while ( i != mIgnoredSslErrorsCache.constEnd() )
2234  {
2235  QStringList errs;
2236  for ( auto err : i.value() )
2237  {
2238  errs << QgsAuthCertUtils::sslErrorEnumString( err );
2239  }
2240  QgsDebugMsg( QStringLiteral( "%1 = %2" ).arg( i.key(), errs.join( ", " ) ) );
2241  ++i;
2242  }
2243  }
2244  else
2245  {
2246  QgsDebugMsgLevel( QStringLiteral( "Ignored SSL errors cache EMPTY" ), 2 );
2247  }
2248 }
2249 
2251 {
2252  QMutexLocker locker( mMutex.get() );
2253  if ( config.isNull() )
2254  {
2255  QgsDebugMsg( QStringLiteral( "Passed config is null" ) );
2256  return false;
2257  }
2258 
2259  QString shahostport( QStringLiteral( "%1:%2" )
2260  .arg( QgsAuthCertUtils::shaHexForCert( config.sslCertificate() ).trimmed(),
2261  config.sslHostPort().trimmed() ) );
2262  if ( mIgnoredSslErrorsCache.contains( shahostport ) )
2263  {
2264  mIgnoredSslErrorsCache.remove( shahostport );
2265  }
2266  QList<QSslError::SslError> errenums( config.sslIgnoredErrorEnums() );
2267  if ( !errenums.isEmpty() )
2268  {
2269  mIgnoredSslErrorsCache.insert( shahostport, qgis::listToSet( errenums ) );
2270  QgsDebugMsg( QStringLiteral( "Update of ignored SSL errors cache SUCCEEDED for sha:host:port = %1" ).arg( shahostport ) );
2272  return true;
2273  }
2274 
2275  QgsDebugMsg( QStringLiteral( "No ignored SSL errors to cache for sha:host:port = %1" ).arg( shahostport ) );
2276  return true;
2277 }
2278 
2279 bool QgsAuthManager::updateIgnoredSslErrorsCache( const QString &shahostport, const QList<QSslError> &errors )
2280 {
2281  QMutexLocker locker( mMutex.get() );
2282  QRegExp rx( "\\S+:\\S+:\\d+" );
2283  if ( !rx.exactMatch( shahostport ) )
2284  {
2285  QgsDebugMsg( "Passed shahostport does not match \\S+:\\S+:\\d+, "
2286  "e.g. 74a4ef5ea94512a43769b744cda0ca5049a72491:www.example.com:443" );
2287  return false;
2288  }
2289 
2290  if ( mIgnoredSslErrorsCache.contains( shahostport ) )
2291  {
2292  mIgnoredSslErrorsCache.remove( shahostport );
2293  }
2294 
2295  if ( errors.isEmpty() )
2296  {
2297  QgsDebugMsg( QStringLiteral( "Passed errors list empty" ) );
2298  return false;
2299  }
2300 
2301  QSet<QSslError::SslError> errs;
2302  for ( const auto &error : errors )
2303  {
2304  if ( error.error() == QSslError::NoError )
2305  continue;
2306 
2307  errs.insert( error.error() );
2308  }
2309 
2310  if ( errs.isEmpty() )
2311  {
2312  QgsDebugMsg( QStringLiteral( "Passed errors list does not contain errors" ) );
2313  return false;
2314  }
2315 
2316  mIgnoredSslErrorsCache.insert( shahostport, errs );
2317 
2318  QgsDebugMsg( QStringLiteral( "Update of ignored SSL errors cache SUCCEEDED for sha:host:port = %1" ).arg( shahostport ) );
2320  return true;
2321 }
2322 
2324 {
2325  QMutexLocker locker( mMutex.get() );
2326  QHash<QString, QSet<QSslError::SslError> > prevcache( mIgnoredSslErrorsCache );
2327  QHash<QString, QSet<QSslError::SslError> > nextcache;
2328 
2329  QSqlQuery query( authDatabaseConnection() );
2330  query.prepare( QStringLiteral( "SELECT id, host, config FROM %1" ).arg( authDatabaseServersTable() ) );
2331 
2332  if ( !authDbQuery( &query ) )
2333  {
2334  QgsDebugMsg( QStringLiteral( "Rebuild of ignored SSL errors cache FAILED" ) );
2335  return false;
2336  }
2337 
2338  if ( query.isActive() && query.isSelect() )
2339  {
2340  while ( query.next() )
2341  {
2342  QString shahostport( QStringLiteral( "%1:%2" )
2343  .arg( query.value( 0 ).toString().trimmed(),
2344  query.value( 1 ).toString().trimmed() ) );
2345  QgsAuthConfigSslServer config;
2346  config.loadConfigString( query.value( 2 ).toString() );
2347  QList<QSslError::SslError> errenums( config.sslIgnoredErrorEnums() );
2348  if ( !errenums.isEmpty() )
2349  {
2350  nextcache.insert( shahostport, qgis::listToSet( errenums ) );
2351  }
2352  if ( prevcache.contains( shahostport ) )
2353  {
2354  prevcache.remove( shahostport );
2355  }
2356  }
2357  }
2358 
2359  if ( !prevcache.isEmpty() )
2360  {
2361  // preserve any existing per-session ignored errors for hosts
2362  QHash<QString, QSet<QSslError::SslError> >::const_iterator i = prevcache.constBegin();
2363  while ( i != prevcache.constEnd() )
2364  {
2365  nextcache.insert( i.key(), i.value() );
2366  ++i;
2367  }
2368  }
2369 
2370  if ( nextcache != mIgnoredSslErrorsCache )
2371  {
2372  mIgnoredSslErrorsCache.clear();
2373  mIgnoredSslErrorsCache = nextcache;
2374  QgsDebugMsgLevel( QStringLiteral( "Rebuild of ignored SSL errors cache SUCCEEDED" ), 2 );
2376  return true;
2377  }
2378 
2379  QgsDebugMsgLevel( QStringLiteral( "Rebuild of ignored SSL errors cache SAME AS BEFORE" ), 2 );
2381  return true;
2382 }
2383 
2384 
2385 bool QgsAuthManager::storeCertAuthorities( const QList<QSslCertificate> &certs )
2386 {
2387  QMutexLocker locker( mMutex.get() );
2388  if ( certs.isEmpty() )
2389  {
2390  QgsDebugMsg( QStringLiteral( "Passed certificate list has no certs" ) );
2391  return false;
2392  }
2393 
2394  for ( const auto &cert : certs )
2395  {
2396  if ( !storeCertAuthority( cert ) )
2397  return false;
2398  }
2399  return true;
2400 }
2401 
2402 bool QgsAuthManager::storeCertAuthority( const QSslCertificate &cert )
2403 {
2404  QMutexLocker locker( mMutex.get() );
2405  // don't refuse !cert.isValid() (actually just expired) CAs,
2406  // as user may want to ignore that SSL connection error
2407  if ( cert.isNull() )
2408  {
2409  QgsDebugMsg( QStringLiteral( "Passed certificate is null" ) );
2410  return false;
2411  }
2412 
2413  removeCertAuthority( cert );
2414 
2415  QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
2416  QString pem( cert.toPem() );
2417 
2418  QSqlQuery query( authDatabaseConnection() );
2419  query.prepare( QStringLiteral( "INSERT INTO %1 (id, cert) "
2420  "VALUES (:id, :cert)" ).arg( authDbAuthoritiesTable() ) );
2421 
2422  query.bindValue( QStringLiteral( ":id" ), id );
2423  query.bindValue( QStringLiteral( ":cert" ), pem );
2424 
2425  if ( !authDbStartTransaction() )
2426  return false;
2427 
2428  if ( !authDbQuery( &query ) )
2429  return false;
2430 
2431  if ( !authDbCommit() )
2432  return false;
2433 
2434  QgsDebugMsg( QStringLiteral( "Store certificate authority SUCCESS for id: %1" ).arg( id ) );
2435  return true;
2436 }
2437 
2438 const QSslCertificate QgsAuthManager::certAuthority( const QString &id )
2439 {
2440  QMutexLocker locker( mMutex.get() );
2441  QSslCertificate emptycert;
2442  QSslCertificate cert;
2443  if ( id.isEmpty() )
2444  return emptycert;
2445 
2446  QSqlQuery query( authDatabaseConnection() );
2447  query.prepare( QStringLiteral( "SELECT cert FROM %1 "
2448  "WHERE id = :id" ).arg( authDbAuthoritiesTable() ) );
2449 
2450  query.bindValue( QStringLiteral( ":id" ), id );
2451 
2452  if ( !authDbQuery( &query ) )
2453  return emptycert;
2454 
2455  if ( query.isActive() && query.isSelect() )
2456  {
2457  if ( query.first() )
2458  {
2459  cert = QSslCertificate( query.value( 0 ).toByteArray(), QSsl::Pem );
2460  QgsDebugMsg( QStringLiteral( "Certificate authority retrieved for id: %1" ).arg( id ) );
2461  }
2462  if ( query.next() )
2463  {
2464  QgsDebugMsg( QStringLiteral( "Select contains more than one certificate authority for id: %1" ).arg( id ) );
2465  emit messageOut( tr( "Authentication database contains duplicate certificate authorities" ), authManTag(), WARNING );
2466  return emptycert;
2467  }
2468  }
2469  return cert;
2470 }
2471 
2472 bool QgsAuthManager::existsCertAuthority( const QSslCertificate &cert )
2473 {
2474  QMutexLocker locker( mMutex.get() );
2475  if ( cert.isNull() )
2476  {
2477  QgsDebugMsg( QStringLiteral( "Passed certificate is null" ) );
2478  return false;
2479  }
2480 
2481  QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
2482 
2483  QSqlQuery query( authDatabaseConnection() );
2484  query.prepare( QStringLiteral( "SELECT value FROM %1 "
2485  "WHERE id = :id" ).arg( authDbAuthoritiesTable() ) );
2486 
2487  query.bindValue( QStringLiteral( ":id" ), id );
2488 
2489  if ( !authDbQuery( &query ) )
2490  return false;
2491 
2492  bool res = false;
2493  if ( query.isActive() && query.isSelect() )
2494  {
2495  if ( query.first() )
2496  {
2497  QgsDebugMsg( QStringLiteral( "Certificate authority exists for id: %1" ).arg( id ) );
2498  res = true;
2499  }
2500  if ( query.next() )
2501  {
2502  QgsDebugMsg( QStringLiteral( "Select contains more than one certificate authority for id: %1" ).arg( id ) );
2503  emit messageOut( tr( "Authentication database contains duplicate certificate authorities" ), authManTag(), WARNING );
2504  return false;
2505  }
2506  }
2507  return res;
2508 }
2509 
2510 bool QgsAuthManager::removeCertAuthority( const QSslCertificate &cert )
2511 {
2512  QMutexLocker locker( mMutex.get() );
2513  if ( cert.isNull() )
2514  {
2515  QgsDebugMsg( QStringLiteral( "Passed certificate is null" ) );
2516  return false;
2517  }
2518 
2519  QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
2520 
2521  QSqlQuery query( authDatabaseConnection() );
2522 
2523  query.prepare( QStringLiteral( "DELETE FROM %1 WHERE id = :id" ).arg( authDbAuthoritiesTable() ) );
2524 
2525  query.bindValue( QStringLiteral( ":id" ), id );
2526 
2527  if ( !authDbStartTransaction() )
2528  return false;
2529 
2530  if ( !authDbQuery( &query ) )
2531  return false;
2532 
2533  if ( !authDbCommit() )
2534  return false;
2535 
2536  QgsDebugMsg( QStringLiteral( "REMOVED authority for id: %1" ).arg( id ) );
2537  return true;
2538 }
2539 
2540 const QList<QSslCertificate> QgsAuthManager::systemRootCAs()
2541 {
2542  return QSslConfiguration::systemCaCertificates();
2543 }
2544 
2545 const QList<QSslCertificate> QgsAuthManager::extraFileCAs()
2546 {
2547  QMutexLocker locker( mMutex.get() );
2548  QList<QSslCertificate> certs;
2549  QList<QSslCertificate> filecerts;
2550  QVariant cafileval = QgsAuthManager::instance()->authSetting( QStringLiteral( "cafile" ) );
2551  if ( cafileval.isNull() )
2552  return certs;
2553 
2554  QVariant allowinvalid = QgsAuthManager::instance()->authSetting( QStringLiteral( "cafileallowinvalid" ), QVariant( false ) );
2555  if ( allowinvalid.isNull() )
2556  return certs;
2557 
2558  QString cafile( cafileval.toString() );
2559  if ( !cafile.isEmpty() && QFile::exists( cafile ) )
2560  {
2561  filecerts = QgsAuthCertUtils::certsFromFile( cafile );
2562  }
2563  // only CAs or certs capable of signing other certs are allowed
2564  for ( const auto &cert : qgis::as_const( filecerts ) )
2565  {
2566  if ( !allowinvalid.toBool() && ( cert.isBlacklisted()
2567  || cert.isNull()
2568  || cert.expiryDate() <= QDateTime::currentDateTime()
2569  || cert.effectiveDate() > QDateTime::currentDateTime() ) )
2570  {
2571  continue;
2572  }
2573 
2575  {
2576  certs << cert;
2577  }
2578  }
2579  return certs;
2580 }
2581 
2582 const QList<QSslCertificate> QgsAuthManager::databaseCAs()
2583 {
2584  QMutexLocker locker( mMutex.get() );
2585  QList<QSslCertificate> certs;
2586 
2587  QSqlQuery query( authDatabaseConnection() );
2588  query.prepare( QStringLiteral( "SELECT id, cert FROM %1" ).arg( authDbAuthoritiesTable() ) );
2589 
2590  if ( !authDbQuery( &query ) )
2591  return certs;
2592 
2593  if ( query.isActive() && query.isSelect() )
2594  {
2595  while ( query.next() )
2596  {
2597  certs << QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
2598  }
2599  }
2600 
2601  return certs;
2602 }
2603 
2604 const QMap<QString, QSslCertificate> QgsAuthManager::mappedDatabaseCAs()
2605 {
2606  QMutexLocker locker( mMutex.get() );
2608 }
2609 
2611 {
2612  QMutexLocker locker( mMutex.get() );
2613  mCaCertsCache.clear();
2614  // in reverse order of precedence, with regards to duplicates, so QMap inserts overwrite
2615  insertCaCertInCache( QgsAuthCertUtils::SystemRoot, systemRootCAs() );
2616  insertCaCertInCache( QgsAuthCertUtils::FromFile, extraFileCAs() );
2617  insertCaCertInCache( QgsAuthCertUtils::InDatabase, databaseCAs() );
2618 
2619  bool res = !mCaCertsCache.isEmpty(); // should at least contain system root CAs
2620  if ( !res )
2621  QgsDebugMsg( QStringLiteral( "Rebuild of CA certs cache FAILED" ) );
2622  return res;
2623 }
2624 
2626 {
2627  QMutexLocker locker( mMutex.get() );
2628  if ( cert.isNull() )
2629  {
2630  QgsDebugMsg( QStringLiteral( "Passed certificate is null" ) );
2631  return false;
2632  }
2633 
2634  removeCertTrustPolicy( cert );
2635 
2636  QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
2637 
2638  if ( policy == QgsAuthCertUtils::DefaultTrust )
2639  {
2640  QgsDebugMsg( QStringLiteral( "Passed policy was default, all cert records in database were removed for id: %1" ).arg( id ) );
2641  return true;
2642  }
2643 
2644  QSqlQuery query( authDatabaseConnection() );
2645  query.prepare( QStringLiteral( "INSERT INTO %1 (id, policy) "
2646  "VALUES (:id, :policy)" ).arg( authDbTrustTable() ) );
2647 
2648  query.bindValue( QStringLiteral( ":id" ), id );
2649  query.bindValue( QStringLiteral( ":policy" ), static_cast< int >( policy ) );
2650 
2651  if ( !authDbStartTransaction() )
2652  return false;
2653 
2654  if ( !authDbQuery( &query ) )
2655  return false;
2656 
2657  if ( !authDbCommit() )
2658  return false;
2659 
2660  QgsDebugMsg( QStringLiteral( "Store certificate trust policy SUCCESS for id: %1" ).arg( id ) );
2661  return true;
2662 }
2663 
2665 {
2666  QMutexLocker locker( mMutex.get() );
2667  if ( cert.isNull() )
2668  {
2669  QgsDebugMsg( QStringLiteral( "Passed certificate is null" ) );
2671  }
2672 
2673  QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
2674 
2675  QSqlQuery query( authDatabaseConnection() );
2676  query.prepare( QStringLiteral( "SELECT policy FROM %1 "
2677  "WHERE id = :id" ).arg( authDbTrustTable() ) );
2678 
2679  query.bindValue( QStringLiteral( ":id" ), id );
2680 
2681  if ( !authDbQuery( &query ) )
2683 
2685  if ( query.isActive() && query.isSelect() )
2686  {
2687  if ( query.first() )
2688  {
2689  policy = static_cast< QgsAuthCertUtils::CertTrustPolicy >( query.value( 0 ).toInt() );
2690  QgsDebugMsg( QStringLiteral( "Authentication cert trust policy retrieved for id: %1" ).arg( id ) );
2691  }
2692  if ( query.next() )
2693  {
2694  QgsDebugMsg( QStringLiteral( "Select contains more than one cert trust policy for id: %1" ).arg( id ) );
2695  emit messageOut( tr( "Authentication database contains duplicate cert trust policies" ), authManTag(), WARNING );
2697  }
2698  }
2699  return policy;
2700 }
2701 
2702 bool QgsAuthManager::removeCertTrustPolicies( const QList<QSslCertificate> &certs )
2703 {
2704  QMutexLocker locker( mMutex.get() );
2705  if ( certs.empty() )
2706  {
2707  QgsDebugMsg( QStringLiteral( "Passed certificate list has no certs" ) );
2708  return false;
2709  }
2710 
2711  for ( const auto &cert : certs )
2712  {
2713  if ( !removeCertTrustPolicy( cert ) )
2714  return false;
2715  }
2716  return true;
2717 }
2718 
2719 bool QgsAuthManager::removeCertTrustPolicy( const QSslCertificate &cert )
2720 {
2721  QMutexLocker locker( mMutex.get() );
2722  if ( cert.isNull() )
2723  {
2724  QgsDebugMsg( QStringLiteral( "Passed certificate is null" ) );
2725  return false;
2726  }
2727 
2728  QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
2729 
2730  QSqlQuery query( authDatabaseConnection() );
2731 
2732  query.prepare( QStringLiteral( "DELETE FROM %1 WHERE id = :id" ).arg( authDbTrustTable() ) );
2733 
2734  query.bindValue( QStringLiteral( ":id" ), id );
2735 
2736  if ( !authDbStartTransaction() )
2737  return false;
2738 
2739  if ( !authDbQuery( &query ) )
2740  return false;
2741 
2742  if ( !authDbCommit() )
2743  return false;
2744 
2745  QgsDebugMsg( QStringLiteral( "REMOVED cert trust policy for id: %1" ).arg( id ) );
2746 
2747  return true;
2748 }
2749 
2751 {
2752  QMutexLocker locker( mMutex.get() );
2753  if ( cert.isNull() )
2754  {
2756  }
2757 
2758  QString id( QgsAuthCertUtils::shaHexForCert( cert ) );
2759  const QStringList &trustedids = mCertTrustCache.value( QgsAuthCertUtils::Trusted );
2760  const QStringList &untrustedids = mCertTrustCache.value( QgsAuthCertUtils::Untrusted );
2761 
2763  if ( trustedids.contains( id ) )
2764  {
2765  policy = QgsAuthCertUtils::Trusted;
2766  }
2767  else if ( untrustedids.contains( id ) )
2768  {
2769  policy = QgsAuthCertUtils::Untrusted;
2770  }
2771  return policy;
2772 }
2773 
2775 {
2776 
2777  if ( policy == QgsAuthCertUtils::DefaultTrust )
2778  {
2779  // set default trust policy to Trusted by removing setting
2780  return removeAuthSetting( QStringLiteral( "certdefaulttrust" ) );
2781  }
2782  return storeAuthSetting( QStringLiteral( "certdefaulttrust" ), static_cast< int >( policy ) );
2783 }
2784 
2786 {
2787  QMutexLocker locker( mMutex.get() );
2788  QVariant policy( authSetting( QStringLiteral( "certdefaulttrust" ) ) );
2789  if ( policy.isNull() )
2790  {
2792  }
2793  return static_cast< QgsAuthCertUtils::CertTrustPolicy >( policy.toInt() );
2794 }
2795 
2797 {
2798  QMutexLocker locker( mMutex.get() );
2799  mCertTrustCache.clear();
2800 
2801  QSqlQuery query( authDatabaseConnection() );
2802  query.prepare( QStringLiteral( "SELECT id, policy FROM %1" ).arg( authDbTrustTable() ) );
2803 
2804  if ( !authDbQuery( &query ) )
2805  {
2806  QgsDebugMsg( QStringLiteral( "Rebuild of cert trust policy cache FAILED" ) );
2807  return false;
2808  }
2809 
2810  if ( query.isActive() && query.isSelect() )
2811  {
2812  while ( query.next() )
2813  {
2814  QString id = query.value( 0 ).toString();
2815  QgsAuthCertUtils::CertTrustPolicy policy = static_cast< QgsAuthCertUtils::CertTrustPolicy >( query.value( 1 ).toInt() );
2816 
2817  QStringList ids;
2818  if ( mCertTrustCache.contains( policy ) )
2819  {
2820  ids = mCertTrustCache.value( policy );
2821  }
2822  mCertTrustCache.insert( policy, ids << id );
2823  }
2824  }
2825 
2826  QgsDebugMsgLevel( QStringLiteral( "Rebuild of cert trust policy cache SUCCEEDED" ), 2 );
2827  return true;
2828 }
2829 
2830 const QList<QSslCertificate> QgsAuthManager::trustedCaCerts( bool includeinvalid )
2831 {
2832  QMutexLocker locker( mMutex.get() );
2834  QStringList trustedids = mCertTrustCache.value( QgsAuthCertUtils::Trusted );
2835  QStringList untrustedids = mCertTrustCache.value( QgsAuthCertUtils::Untrusted );
2836  const QList<QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> > &certpairs( mCaCertsCache.values() );
2837 
2838  QList<QSslCertificate> trustedcerts;
2839  for ( int i = 0; i < certpairs.size(); ++i )
2840  {
2841  QSslCertificate cert( certpairs.at( i ).second );
2842  QString certid( QgsAuthCertUtils::shaHexForCert( cert ) );
2843  if ( trustedids.contains( certid ) )
2844  {
2845  // trusted certs are always added regardless of their validity
2846  trustedcerts.append( cert );
2847  }
2848  else if ( defaultpolicy == QgsAuthCertUtils::Trusted && !untrustedids.contains( certid ) )
2849  {
2850  if ( !includeinvalid && !QgsAuthCertUtils::certIsViable( cert ) )
2851  continue;
2852  trustedcerts.append( cert );
2853  }
2854  }
2855 
2856  // update application default SSL config for new requests
2857  QSslConfiguration sslconfig( QSslConfiguration::defaultConfiguration() );
2858  sslconfig.setCaCertificates( trustedcerts );
2859  QSslConfiguration::setDefaultConfiguration( sslconfig );
2860 
2861  return trustedcerts;
2862 }
2863 
2864 const QList<QSslCertificate> QgsAuthManager::untrustedCaCerts( QList<QSslCertificate> trustedCAs )
2865 {
2866  QMutexLocker locker( mMutex.get() );
2867  if ( trustedCAs.isEmpty() )
2868  {
2869  if ( mTrustedCaCertsCache.isEmpty() )
2870  {
2872  }
2873  trustedCAs = trustedCaCertsCache();
2874  }
2875 
2876  const QList<QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> > &certpairs( mCaCertsCache.values() );
2877 
2878  QList<QSslCertificate> untrustedCAs;
2879  for ( int i = 0; i < certpairs.size(); ++i )
2880  {
2881  QSslCertificate cert( certpairs.at( i ).second );
2882  if ( !trustedCAs.contains( cert ) )
2883  {
2884  untrustedCAs.append( cert );
2885  }
2886  }
2887  return untrustedCAs;
2888 }
2889 
2891 {
2892  QMutexLocker locker( mMutex.get() );
2893  mTrustedCaCertsCache = trustedCaCerts();
2894  QgsDebugMsgLevel( QStringLiteral( "Rebuilt trusted cert authorities cache" ), 2 );
2895  // TODO: add some error trapping for the operation
2896  return true;
2897 }
2898 
2900 {
2901  QMutexLocker locker( mMutex.get() );
2903 }
2904 
2906 {
2907  QMutexLocker locker( mMutex.get() );
2908  if ( masterPasswordIsSet() )
2909  {
2910  return passwordHelperWrite( mMasterPass );
2911  }
2912  return false;
2913 }
2914 
2915 
2917 
2918 #endif
2919 
2921 {
2922  if ( isDisabled() )
2923  return;
2924 
2925  const QStringList ids = configIds();
2926  for ( const auto &authcfg : ids )
2927  {
2928  clearCachedConfig( authcfg );
2929  }
2930 }
2931 
2932 void QgsAuthManager::clearCachedConfig( const QString &authcfg )
2933 {
2934  if ( isDisabled() )
2935  return;
2936 
2937  QgsAuthMethod *authmethod = configAuthMethod( authcfg );
2938  if ( authmethod )
2939  {
2940  authmethod->clearCachedConfig( authcfg );
2941  }
2942 }
2943 
2944 void QgsAuthManager::writeToConsole( const QString &message,
2945  const QString &tag,
2947 {
2948  Q_UNUSED( tag )
2949 
2950  // only output WARNING and CRITICAL messages
2951  if ( level == QgsAuthManager::INFO )
2952  return;
2953 
2954  QString msg;
2955  switch ( level )
2956  {
2958  msg += QLatin1String( "WARNING: " );
2959  break;
2961  msg += QLatin1String( "ERROR: " );
2962  break;
2963  default:
2964  break;
2965  }
2966  msg += message;
2967 
2968  QTextStream out( stdout, QIODevice::WriteOnly );
2969  out << msg << endl;
2970 }
2971 
2972 void QgsAuthManager::tryToStartDbErase()
2973 {
2974  ++mScheduledDbEraseRequestCount;
2975  // wait a total of 90 seconds for GUI availiability or user interaction, then cancel schedule
2976  int trycutoff = 90 / ( mScheduledDbEraseRequestWait ? mScheduledDbEraseRequestWait : 3 );
2977  if ( mScheduledDbEraseRequestCount >= trycutoff )
2978  {
2980  QgsDebugMsg( QStringLiteral( "authDatabaseEraseRequest emitting/scheduling canceled" ) );
2981  return;
2982  }
2983  else
2984  {
2985  QgsDebugMsg( QStringLiteral( "authDatabaseEraseRequest attempt (%1 of %2)" )
2986  .arg( mScheduledDbEraseRequestCount ).arg( trycutoff ) );
2987  }
2988 
2989  if ( scheduledAuthDatabaseErase() && !mScheduledDbEraseRequestEmitted && mMutex->tryLock() )
2990  {
2991  // see note in header about this signal's use
2992  mScheduledDbEraseRequestEmitted = true;
2994 
2995  mMutex->unlock();
2996 
2997  QgsDebugMsg( QStringLiteral( "authDatabaseEraseRequest emitted" ) );
2998  return;
2999  }
3000  QgsDebugMsg( QStringLiteral( "authDatabaseEraseRequest emit skipped" ) );
3001 }
3002 
3003 
3005 {
3006  QMutexLocker locker( mMutex.get() );
3007  QMapIterator<QThread *, QMetaObject::Connection> iterator( mConnectedThreads );
3008  while ( iterator.hasNext() )
3009  {
3010  iterator.next();
3011  iterator.key()->disconnect( iterator.value() );
3012  }
3013  locker.unlock();
3014 
3015  if ( !isDisabled() )
3016  {
3018  qDeleteAll( mAuthMethods );
3019 
3020  QSqlDatabase authConn = authDatabaseConnection();
3021  if ( authConn.isValid() && authConn.isOpen() )
3022  authConn.close();
3023  }
3024  delete mScheduledDbEraseTimer;
3025  mScheduledDbEraseTimer = nullptr;
3026  QSqlDatabase::removeDatabase( QStringLiteral( "authentication.configs" ) );
3027 }
3028 
3029 
3030 QString QgsAuthManager::passwordHelperName() const
3031 {
3032  return tr( "Password Helper" );
3033 }
3034 
3035 
3036 void QgsAuthManager::passwordHelperLog( const QString &msg ) const
3037 {
3039  {
3040  QgsMessageLog::logMessage( msg, passwordHelperName() );
3041  }
3042 }
3043 
3045 {
3046  passwordHelperLog( tr( "Opening %1 for DELETE…" ).arg( AUTH_PASSWORD_HELPER_DISPLAY_NAME ) );
3047  bool result;
3048  QKeychain::DeletePasswordJob job( AUTH_PASSWORD_HELPER_FOLDER_NAME );
3049  QgsSettings settings;
3050  job.setInsecureFallback( settings.value( QStringLiteral( "password_helper_insecure_fallback" ), false, QgsSettings::Section::Auth ).toBool() );
3051  job.setAutoDelete( false );
3052  job.setKey( AUTH_PASSWORD_HELPER_KEY_NAME );
3053  QEventLoop loop;
3054  connect( &job, &QKeychain::Job::finished, &loop, &QEventLoop::quit );
3055  job.start();
3056  loop.exec();
3057  if ( job.error() )
3058  {
3059  mPasswordHelperErrorCode = job.error();
3060  mPasswordHelperErrorMessage = tr( "Delete password failed: %1." ).arg( job.errorString() );
3061  // Signals used in the tests to exit main application loop
3062  emit passwordHelperFailure();
3063  result = false;
3064  }
3065  else
3066  {
3067  // Signals used in the tests to exit main application loop
3068  emit passwordHelperSuccess();
3069  result = true;
3070  }
3071  passwordHelperProcessError();
3072  return result;
3073 }
3074 
3075 QString QgsAuthManager::passwordHelperRead()
3076 {
3077  // Retrieve it!
3078  QString password;
3079  passwordHelperLog( tr( "Opening %1 for READ…" ).arg( AUTH_PASSWORD_HELPER_DISPLAY_NAME ) );
3080  QKeychain::ReadPasswordJob job( AUTH_PASSWORD_HELPER_FOLDER_NAME );
3081  QgsSettings settings;
3082  job.setInsecureFallback( settings.value( QStringLiteral( "password_helper_insecure_fallback" ), false, QgsSettings::Section::Auth ).toBool() );
3083  job.setAutoDelete( false );
3084  job.setKey( AUTH_PASSWORD_HELPER_KEY_NAME );
3085  QEventLoop loop;
3086  connect( &job, &QKeychain::Job::finished, &loop, &QEventLoop::quit );
3087  job.start();
3088  loop.exec();
3089  if ( job.error() )
3090  {
3091  mPasswordHelperErrorCode = job.error();
3092  mPasswordHelperErrorMessage = tr( "Retrieving password from your %1 failed: %2." ).arg( AUTH_PASSWORD_HELPER_DISPLAY_NAME, job.errorString() );
3093  // Signals used in the tests to exit main application loop
3094  emit passwordHelperFailure();
3095  }
3096  else
3097  {
3098  password = job.textData();
3099  // Password is there but it is empty, treat it like if it was not found
3100  if ( password.isEmpty() )
3101  {
3102  mPasswordHelperErrorCode = QKeychain::EntryNotFound;
3103  mPasswordHelperErrorMessage = tr( "Empty password retrieved from your %1." ).arg( AUTH_PASSWORD_HELPER_DISPLAY_NAME );
3104  // Signals used in the tests to exit main application loop
3105  emit passwordHelperFailure();
3106  }
3107  else
3108  {
3109  // Signals used in the tests to exit main application loop
3110  emit passwordHelperSuccess();
3111  }
3112  }
3113  passwordHelperProcessError();
3114  return password;
3115 }
3116 
3117 bool QgsAuthManager::passwordHelperWrite( const QString &password )
3118 {
3119  Q_ASSERT( !password.isEmpty() );
3120  bool result;
3121  passwordHelperLog( tr( "Opening %1 for WRITE…" ).arg( AUTH_PASSWORD_HELPER_DISPLAY_NAME ) );
3122  QKeychain::WritePasswordJob job( AUTH_PASSWORD_HELPER_FOLDER_NAME );
3123  QgsSettings settings;
3124  job.setInsecureFallback( settings.value( QStringLiteral( "password_helper_insecure_fallback" ), false, QgsSettings::Section::Auth ).toBool() );
3125  job.setAutoDelete( false );
3126  job.setKey( AUTH_PASSWORD_HELPER_KEY_NAME );
3127  job.setTextData( password );
3128  QEventLoop loop;
3129  connect( &job, &QKeychain::Job::finished, &loop, &QEventLoop::quit );
3130  job.start();
3131  loop.exec();
3132  if ( job.error() )
3133  {
3134  mPasswordHelperErrorCode = job.error();
3135  mPasswordHelperErrorMessage = tr( "Storing password in your %1 failed: %2." ).arg( AUTH_PASSWORD_HELPER_DISPLAY_NAME, job.errorString() );
3136  // Signals used in the tests to exit main application loop
3137  emit passwordHelperFailure();
3138  result = false;
3139  }
3140  else
3141  {
3142  passwordHelperClearErrors();
3143  // Signals used in the tests to exit main application loop
3144  emit passwordHelperSuccess();
3145  result = true;
3146  }
3147  passwordHelperProcessError();
3148  return result;
3149 }
3150 
3152 {
3153  // Does the user want to store the password in the wallet?
3154  QgsSettings settings;
3155  return settings.value( QStringLiteral( "use_password_helper" ), true, QgsSettings::Section::Auth ).toBool();
3156 }
3157 
3159 {
3160  QgsSettings settings;
3161  settings.setValue( QStringLiteral( "use_password_helper" ), enabled, QgsSettings::Section::Auth );
3162  emit messageOut( enabled ? tr( "Your %1 will be <b>used from now</b> on to store and retrieve the master password." )
3164  tr( "Your %1 will <b>not be used anymore</b> to store and retrieve the master password." )
3166 }
3167 
3169 {
3170  // Does the user want to store the password in the wallet?
3171  QgsSettings settings;
3172  return settings.value( QStringLiteral( "password_helper_logging" ), false, QgsSettings::Section::Auth ).toBool();
3173 }
3174 
3176 {
3177  QgsSettings settings;
3178  settings.setValue( QStringLiteral( "password_helper_logging" ), enabled, QgsSettings::Section::Auth );
3179 }
3180 
3181 void QgsAuthManager::passwordHelperClearErrors()
3182 {
3183  mPasswordHelperErrorCode = QKeychain::NoError;
3184  mPasswordHelperErrorMessage.clear();
3185 }
3186 
3187 void QgsAuthManager::passwordHelperProcessError()
3188 {
3189  if ( mPasswordHelperErrorCode == QKeychain::AccessDenied ||
3190  mPasswordHelperErrorCode == QKeychain::AccessDeniedByUser ||
3191  mPasswordHelperErrorCode == QKeychain::NoBackendAvailable ||
3192  mPasswordHelperErrorCode == QKeychain::NotImplemented )
3193  {
3194  // If the error is permanent or the user denied access to the wallet
3195  // we also want to disable the wallet system to prevent annoying
3196  // notification on each subsequent access.
3197  setPasswordHelperEnabled( false );
3198  mPasswordHelperErrorMessage = tr( "There was an error and integration with your %1 system has been disabled. "
3199  "You can re-enable it at any time through the \"Utilities\" menu "
3200  "in the Authentication pane of the options dialog. %2" )
3201  .arg( AUTH_PASSWORD_HELPER_DISPLAY_NAME, mPasswordHelperErrorMessage );
3202  }
3203  if ( mPasswordHelperErrorCode != QKeychain::NoError )
3204  {
3205  // We've got an error from the wallet
3206  passwordHelperLog( tr( "Error in %1: %2" ).arg( AUTH_PASSWORD_HELPER_DISPLAY_NAME, mPasswordHelperErrorMessage ) );
3207  emit passwordHelperMessageOut( mPasswordHelperErrorMessage, authManTag(), CRITICAL );
3208  }
3209  passwordHelperClearErrors();
3210 }
3211 
3212 
3213 bool QgsAuthManager::masterPasswordInput()
3214 {
3215  if ( isDisabled() )
3216  return false;
3217 
3218  QString pass;
3219  bool storedPasswordIsValid = false;
3220  bool ok = false;
3221 
3222  // Read the password from the wallet
3223  if ( passwordHelperEnabled() )
3224  {
3225  pass = passwordHelperRead();
3226  if ( ! pass.isEmpty() && ( mPasswordHelperErrorCode == QKeychain::NoError ) )
3227  {
3228  // Let's check the password!
3229  if ( verifyMasterPassword( pass ) )
3230  {
3231  ok = true;
3232  storedPasswordIsValid = true;
3233  emit passwordHelperMessageOut( tr( "Master password has been successfully read from your %1" ).arg( AUTH_PASSWORD_HELPER_DISPLAY_NAME ), authManTag(), INFO );
3234  }
3235  else
3236  {
3237  emit passwordHelperMessageOut( tr( "Master password stored in your %1 is not valid" ).arg( AUTH_PASSWORD_HELPER_DISPLAY_NAME ), authManTag(), WARNING );
3238  }
3239  }
3240  }
3241 
3242  if ( ! ok )
3243  {
3244  pass.clear();
3246  }
3247 
3248  if ( ok && !pass.isEmpty() && mMasterPass != pass )
3249  {
3250  mMasterPass = pass;
3251  if ( passwordHelperEnabled() && ! storedPasswordIsValid )
3252  {
3253  if ( passwordHelperWrite( pass ) )
3254  {
3255  emit passwordHelperMessageOut( tr( "Master password has been successfully written to your %1" ).arg( AUTH_PASSWORD_HELPER_DISPLAY_NAME ), authManTag(), INFO );
3256  }
3257  else
3258  {
3259  emit passwordHelperMessageOut( tr( "Master password could not be written to your %1" ).arg( AUTH_PASSWORD_HELPER_DISPLAY_NAME ), authManTag(), WARNING );
3260  }
3261  }
3262  return true;
3263  }
3264  return false;
3265 }
3266 
3267 bool QgsAuthManager::masterPasswordRowsInDb( int *rows ) const
3268 {
3269  if ( isDisabled() )
3270  return false;
3271 
3272  QSqlQuery query( authDatabaseConnection() );
3273  query.prepare( QStringLiteral( "SELECT Count(*) FROM %1" ).arg( authDbPassTable() ) );
3274 
3275  bool ok = authDbQuery( &query );
3276  if ( query.first() )
3277  {
3278  *rows = query.value( 0 ).toInt();
3279  }
3280 
3281  return ok;
3282 }
3283 
3285 {
3286  if ( isDisabled() )
3287  return false;
3288 
3289  int rows = 0;
3290  if ( !masterPasswordRowsInDb( &rows ) )
3291  {
3292  const char *err = QT_TR_NOOP( "Master password: FAILED to access database" );
3293  QgsDebugMsg( err );
3294  emit messageOut( tr( err ), authManTag(), CRITICAL );
3295 
3296  return false;
3297  }
3298  return ( rows == 1 );
3299 }
3300 
3301 bool QgsAuthManager::masterPasswordCheckAgainstDb( const QString &compare ) const
3302 {
3303  if ( isDisabled() )
3304  return false;
3305 
3306  // first verify there is only one row in auth db (uses first found)
3307 
3308  QSqlQuery query( authDatabaseConnection() );
3309  query.prepare( QStringLiteral( "SELECT salt, hash FROM %1" ).arg( authDbPassTable() ) );
3310  if ( !authDbQuery( &query ) )
3311  return false;
3312 
3313  if ( !query.first() )
3314  return false;
3315 
3316  QString salt = query.value( 0 ).toString();
3317  QString hash = query.value( 1 ).toString();
3318 
3319  return QgsAuthCrypto::verifyPasswordKeyHash( compare.isNull() ? mMasterPass : compare, salt, hash );
3320 }
3321 
3322 bool QgsAuthManager::masterPasswordStoreInDb() const
3323 {
3324  if ( isDisabled() )
3325  return false;
3326 
3327  QString salt, hash, civ;
3328  QgsAuthCrypto::passwordKeyHash( mMasterPass, &salt, &hash, &civ );
3329 
3330  QSqlQuery query( authDatabaseConnection() );
3331  query.prepare( QStringLiteral( "INSERT INTO %1 (salt, hash, civ) VALUES (:salt, :hash, :civ)" ).arg( authDbPassTable() ) );
3332 
3333  query.bindValue( QStringLiteral( ":salt" ), salt );
3334  query.bindValue( QStringLiteral( ":hash" ), hash );
3335  query.bindValue( QStringLiteral( ":civ" ), civ );
3336 
3337  if ( !authDbStartTransaction() )
3338  return false;
3339 
3340  if ( !authDbQuery( &query ) )
3341  return false;
3342 
3343  if ( !authDbCommit() )
3344  return false;
3345 
3346  return true;
3347 }
3348 
3349 bool QgsAuthManager::masterPasswordClearDb()
3350 {
3351  if ( isDisabled() )
3352  return false;
3353 
3354  QSqlQuery query( authDatabaseConnection() );
3355  query.prepare( QStringLiteral( "DELETE FROM %1" ).arg( authDbPassTable() ) );
3356  bool res = authDbTransactionQuery( &query );
3357  if ( res )
3359  return res;
3360 }
3361 
3362 const QString QgsAuthManager::masterPasswordCiv() const
3363 {
3364  if ( isDisabled() )
3365  return QString();
3366 
3367  QSqlQuery query( authDatabaseConnection() );
3368  query.prepare( QStringLiteral( "SELECT civ FROM %1" ).arg( authDbPassTable() ) );
3369  if ( !authDbQuery( &query ) )
3370  return QString();
3371 
3372  if ( !query.first() )
3373  return QString();
3374 
3375  return query.value( 0 ).toString();
3376 }
3377 
3378 QStringList QgsAuthManager::configIds() const
3379 {
3380  QStringList configids = QStringList();
3381 
3382  if ( isDisabled() )
3383  return configids;
3384 
3385  QSqlQuery query( authDatabaseConnection() );
3386  query.prepare( QStringLiteral( "SELECT id FROM %1" ).arg( authDatabaseConfigTable() ) );
3387 
3388  if ( !authDbQuery( &query ) )
3389  {
3390  return configids;
3391  }
3392 
3393  if ( query.isActive() )
3394  {
3395  while ( query.next() )
3396  {
3397  configids << query.value( 0 ).toString();
3398  }
3399  }
3400  return configids;
3401 }
3402 
3403 bool QgsAuthManager::verifyPasswordCanDecryptConfigs() const
3404 {
3405  if ( isDisabled() )
3406  return false;
3407 
3408  // no need to check for setMasterPassword, since this is private and it will be set
3409 
3410  QSqlQuery query( authDatabaseConnection() );
3411 
3412  query.prepare( QStringLiteral( "SELECT id, config FROM %1" ).arg( authDatabaseConfigTable() ) );
3413 
3414  if ( !authDbQuery( &query ) )
3415  return false;
3416 
3417  if ( !query.isActive() || !query.isSelect() )
3418  {
3419  QgsDebugMsg( QStringLiteral( "Verify password can decrypt configs FAILED, query not active or a select operation" ) );
3420  return false;
3421  }
3422 
3423  int checked = 0;
3424  while ( query.next() )
3425  {
3426  ++checked;
3427  QString configstring( QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 1 ).toString() ) );
3428  if ( configstring.isEmpty() )
3429  {
3430  QgsDebugMsg( QStringLiteral( "Verify password can decrypt configs FAILED, could not decrypt a config (id: %1)" )
3431  .arg( query.value( 0 ).toString() ) );
3432  return false;
3433  }
3434  }
3435 
3436  QgsDebugMsg( QStringLiteral( "Verify password can decrypt configs SUCCESS (checked %1 configs)" ).arg( checked ) );
3437  return true;
3438 }
3439 
3440 bool QgsAuthManager::reencryptAllAuthenticationConfigs( const QString &prevpass, const QString &prevciv )
3441 {
3442  if ( isDisabled() )
3443  return false;
3444 
3445  bool res = true;
3446  const QStringList ids = configIds();
3447  for ( const auto &configid : ids )
3448  {
3449  res = res && reencryptAuthenticationConfig( configid, prevpass, prevciv );
3450  }
3451  return res;
3452 }
3453 
3454 bool QgsAuthManager::reencryptAuthenticationConfig( const QString &authcfg, const QString &prevpass, const QString &prevciv )
3455 {
3456  if ( isDisabled() )
3457  return false;
3458 
3459  // no need to check for setMasterPassword, since this is private and it will be set
3460 
3461  QSqlQuery query( authDatabaseConnection() );
3462 
3463  query.prepare( QStringLiteral( "SELECT config FROM %1 "
3464  "WHERE id = :id" ).arg( authDatabaseConfigTable() ) );
3465 
3466  query.bindValue( QStringLiteral( ":id" ), authcfg );
3467 
3468  if ( !authDbQuery( &query ) )
3469  return false;
3470 
3471  if ( !query.isActive() || !query.isSelect() )
3472  {
3473  QgsDebugMsg( QStringLiteral( "Reencrypt FAILED, query not active or a select operation for authcfg: %2" ).arg( authcfg ) );
3474  return false;
3475  }
3476 
3477  if ( query.first() )
3478  {
3479  QString configstring( QgsAuthCrypto::decrypt( prevpass, prevciv, query.value( 0 ).toString() ) );
3480 
3481  if ( query.next() )
3482  {
3483  QgsDebugMsg( QStringLiteral( "Select contains more than one for authcfg: %1" ).arg( authcfg ) );
3484  emit messageOut( tr( "Authentication database contains duplicate configuration IDs" ), authManTag(), WARNING );
3485  return false;
3486  }
3487 
3488  query.clear();
3489 
3490  query.prepare( QStringLiteral( "UPDATE %1 "
3491  "SET config = :config "
3492  "WHERE id = :id" ).arg( authDatabaseConfigTable() ) );
3493 
3494  query.bindValue( QStringLiteral( ":id" ), authcfg );
3495  query.bindValue( QStringLiteral( ":config" ), QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
3496 
3497  if ( !authDbStartTransaction() )
3498  return false;
3499 
3500  if ( !authDbQuery( &query ) )
3501  return false;
3502 
3503  if ( !authDbCommit() )
3504  return false;
3505 
3506  QgsDebugMsg( QStringLiteral( "Reencrypt SUCCESS for authcfg: %2" ).arg( authcfg ) );
3507  return true;
3508  }
3509  else
3510  {
3511  QgsDebugMsg( QStringLiteral( "Reencrypt FAILED, could not find in db authcfg: %2" ).arg( authcfg ) );
3512  return false;
3513  }
3514 }
3515 
3516 bool QgsAuthManager::reencryptAllAuthenticationSettings( const QString &prevpass, const QString &prevciv )
3517 {
3518  // TODO: start remove (when function is actually used)
3519  Q_UNUSED( prevpass )
3520  Q_UNUSED( prevciv )
3521  return true;
3522  // end remove
3523 
3524 #if 0
3525  if ( isDisabled() )
3526  return false;
3527 
3529  // When adding settings that require encryption, add to list //
3531 
3532  QStringList encryptedsettings;
3533  encryptedsettings << "";
3534 
3535  for ( const auto & sett, qgis::as_const( encryptedsettings ) )
3536  {
3537  if ( sett.isEmpty() || !existsAuthSetting( sett ) )
3538  continue;
3539 
3540  // no need to check for setMasterPassword, since this is private and it will be set
3541 
3542  QSqlQuery query( authDbConnection() );
3543 
3544  query.prepare( QStringLiteral( "SELECT value FROM %1 "
3545  "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
3546 
3547  query.bindValue( ":setting", sett );
3548 
3549  if ( !authDbQuery( &query ) )
3550  return false;
3551 
3552  if ( !query.isActive() || !query.isSelect() )
3553  {
3554  QgsDebugMsg( QStringLiteral( "Reencrypt FAILED, query not active or a select operation for setting: %2" ).arg( sett ) );
3555  return false;
3556  }
3557 
3558  if ( query.first() )
3559  {
3560  QString settvalue( QgsAuthCrypto::decrypt( prevpass, prevciv, query.value( 0 ).toString() ) );
3561 
3562  query.clear();
3563 
3564  query.prepare( QStringLiteral( "UPDATE %1 "
3565  "SET value = :value "
3566  "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
3567 
3568  query.bindValue( ":setting", sett );
3569  query.bindValue( ":value", QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), settvalue ) );
3570 
3571  if ( !authDbStartTransaction() )
3572  return false;
3573 
3574  if ( !authDbQuery( &query ) )
3575  return false;
3576 
3577  if ( !authDbCommit() )
3578  return false;
3579 
3580  QgsDebugMsg( QStringLiteral( "Reencrypt SUCCESS for setting: %2" ).arg( sett ) );
3581  return true;
3582  }
3583  else
3584  {
3585  QgsDebugMsg( QStringLiteral( "Reencrypt FAILED, could not find in db setting: %2" ).arg( sett ) );
3586  return false;
3587  }
3588 
3589  if ( query.next() )
3590  {
3591  QgsDebugMsg( QStringLiteral( "Select contains more than one for setting: %1" ).arg( sett ) );
3592  emit messageOut( tr( "Authentication database contains duplicate setting keys" ), authManTag(), WARNING );
3593  }
3594 
3595  return false;
3596  }
3597 
3598  return true;
3599 #endif
3600 }
3601 
3602 bool QgsAuthManager::reencryptAllAuthenticationIdentities( const QString &prevpass, const QString &prevciv )
3603 {
3604  if ( isDisabled() )
3605  return false;
3606 
3607  bool res = true;
3608  const QStringList ids = certIdentityIds();
3609  for ( const auto &identid : ids )
3610  {
3611  res = res && reencryptAuthenticationIdentity( identid, prevpass, prevciv );
3612  }
3613  return res;
3614 }
3615 
3616 bool QgsAuthManager::reencryptAuthenticationIdentity(
3617  const QString &identid,
3618  const QString &prevpass,
3619  const QString &prevciv )
3620 {
3621  if ( isDisabled() )
3622  return false;
3623 
3624  // no need to check for setMasterPassword, since this is private and it will be set
3625 
3626  QSqlQuery query( authDatabaseConnection() );
3627 
3628  query.prepare( QStringLiteral( "SELECT key FROM %1 "
3629  "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
3630 
3631  query.bindValue( QStringLiteral( ":id" ), identid );
3632 
3633  if ( !authDbQuery( &query ) )
3634  return false;
3635 
3636  if ( !query.isActive() || !query.isSelect() )
3637  {
3638  QgsDebugMsg( QStringLiteral( "Reencrypt FAILED, query not active or a select operation for identity id: %2" ).arg( identid ) );
3639  return false;
3640  }
3641 
3642  if ( query.first() )
3643  {
3644  QString keystring( QgsAuthCrypto::decrypt( prevpass, prevciv, query.value( 0 ).toString() ) );
3645 
3646  if ( query.next() )
3647  {
3648  QgsDebugMsg( QStringLiteral( "Select contains more than one for identity id: %1" ).arg( identid ) );
3649  emit messageOut( tr( "Authentication database contains duplicate identity IDs" ), authManTag(), WARNING );
3650  return false;
3651  }
3652 
3653  query.clear();
3654 
3655  query.prepare( QStringLiteral( "UPDATE %1 "
3656  "SET key = :key "
3657  "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
3658 
3659  query.bindValue( QStringLiteral( ":id" ), identid );
3660  query.bindValue( QStringLiteral( ":key" ), QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), keystring ) );
3661 
3662  if ( !authDbStartTransaction() )
3663  return false;
3664 
3665  if ( !authDbQuery( &query ) )
3666  return false;
3667 
3668  if ( !authDbCommit() )
3669  return false;
3670 
3671  QgsDebugMsg( QStringLiteral( "Reencrypt SUCCESS for identity id: %2" ).arg( identid ) );
3672  return true;
3673  }
3674  else
3675  {
3676  QgsDebugMsg( QStringLiteral( "Reencrypt FAILED, could not find in db identity id: %2" ).arg( identid ) );
3677  return false;
3678  }
3679 }
3680 
3681 bool QgsAuthManager::authDbOpen() const
3682 {
3683  if ( isDisabled() )
3684  return false;
3685 
3686  QSqlDatabase authdb = authDatabaseConnection();
3687  if ( !authdb.isOpen() )
3688  {
3689  if ( !authdb.open() )
3690  {
3691  QgsDebugMsg( QStringLiteral( "Unable to establish database connection\nDatabase: %1\nDriver error: %2\nDatabase error: %3" )
3693  authdb.lastError().driverText(),
3694  authdb.lastError().databaseText() ) );
3695  emit messageOut( tr( "Unable to establish authentication database connection" ), authManTag(), CRITICAL );
3696  return false;
3697  }
3698  }
3699  return true;
3700 }
3701 
3702 bool QgsAuthManager::authDbQuery( QSqlQuery *query ) const
3703 {
3704  if ( isDisabled() )
3705  return false;
3706 
3707  query->setForwardOnly( true );
3708  if ( !query->exec() )
3709  {
3710  const char *err = QT_TR_NOOP( "Auth db query exec() FAILED" );
3711  QgsDebugMsg( err );
3712  emit messageOut( tr( err ), authManTag(), WARNING );
3713  return false;
3714  }
3715 
3716  if ( query->lastError().isValid() )
3717  {
3718  QgsDebugMsg( QStringLiteral( "Auth db query FAILED: %1\nError: %2" )
3719  .arg( query->executedQuery(),
3720  query->lastError().text() ) );
3721  emit messageOut( tr( "Auth db query FAILED" ), authManTag(), WARNING );
3722  return false;
3723  }
3724 
3725  return true;
3726 }
3727 
3728 bool QgsAuthManager::authDbStartTransaction() const
3729 {
3730  if ( isDisabled() )
3731  return false;
3732 
3733  if ( !authDatabaseConnection().transaction() )
3734  {
3735  const char *err = QT_TR_NOOP( "Auth db FAILED to start transaction" );
3736  QgsDebugMsg( err );
3737  emit messageOut( tr( err ), authManTag(), WARNING );
3738  return false;
3739  }
3740 
3741  return true;
3742 }
3743 
3744 bool QgsAuthManager::authDbCommit() const
3745 {
3746  if ( isDisabled() )
3747  return false;
3748 
3749  if ( !authDatabaseConnection().commit() )
3750  {
3751  const char *err = QT_TR_NOOP( "Auth db FAILED to rollback changes" );
3752  QgsDebugMsg( err );
3753  emit messageOut( tr( err ), authManTag(), WARNING );
3754  ( void )authDatabaseConnection().rollback();
3755  return false;
3756  }
3757 
3758  return true;
3759 }
3760 
3761 bool QgsAuthManager::authDbTransactionQuery( QSqlQuery *query ) const
3762 {
3763  if ( isDisabled() )
3764  return false;
3765 
3766  if ( !authDatabaseConnection().transaction() )
3767  {
3768  const char *err = QT_TR_NOOP( "Auth db FAILED to start transaction" );
3769  QgsDebugMsg( err );
3770  emit messageOut( tr( err ), authManTag(), WARNING );
3771  return false;
3772  }
3773 
3774  bool ok = authDbQuery( query );
3775 
3776  if ( ok && !authDatabaseConnection().commit() )
3777  {
3778  const char *err = QT_TR_NOOP( "Auth db FAILED to rollback changes" );
3779  QgsDebugMsg( err );
3780  emit messageOut( tr( err ), authManTag(), WARNING );
3781  ( void )authDatabaseConnection().rollback();
3782  return false;
3783  }
3784 
3785  return ok;
3786 }
3787 
3788 void QgsAuthManager::insertCaCertInCache( QgsAuthCertUtils::CaCertSource source, const QList<QSslCertificate> &certs )
3789 {
3790  for ( const auto &cert : certs )
3791  {
3792  mCaCertsCache.insert( QgsAuthCertUtils::shaHexForCert( cert ),
3793  QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate>( source, cert ) );
3794  }
3795 }
3796 
QgsAuthMethod::NetworkReply
@ NetworkReply
Definition: qgsauthmethod.h:54
QgsCredentials::instance
static QgsCredentials * instance()
retrieves instance
Definition: qgscredentials.cpp:33
QgsAuthManager::verifyMasterPassword
bool verifyMasterPassword(const QString &compare=QString())
Verify the supplied master password against any existing hash in authentication database.
Definition: qgsauthmanager.cpp:546
QgsAuthManager::clearAllCachedConfigs
void clearAllCachedConfigs()
Clear all authentication configs from authentication method caches.
Definition: qgsauthmanager.cpp:2920
QgsAuthConfigSslServer::setSslHostPort
void setSslHostPort(const QString &hostport)
Sets server host:port string.
Definition: qgsauthconfig.h:385
QgsAuthManager::authMethodsKeys
QStringList authMethodsKeys(const QString &dataprovider=QString())
Gets keys of supported authentication methods.
Definition: qgsauthmanager.cpp:998
QgsAuthMethodConfig::name
const QString name() const
Gets name of configuration.
Definition: qgsauthconfig.h:78
QgsAuthCertUtils::CaCertSource
CaCertSource
Type of CA certificate source.
Definition: qgsauthcertutils.h:44
qgsauthcertutils.h
qgsruntimeprofiler.h
QgsAuthMethod
Definition: qgsauthmethod.h:36
QgsAuthManager::removeAuthSetting
bool removeAuthSetting(const QString &key)
Remove an authentication setting.
Definition: qgsauthmanager.cpp:1660
QgsAuthManager::storeCertAuthority
bool storeCertAuthority(const QSslCertificate &cert)
Store a certificate authority.
Definition: qgsauthmanager.cpp:2402
QgsAuthConfigSslServer::sslHostPort
const QString sslHostPort() const
Server host:port string.
Definition: qgsauthconfig.h:383
QgsAuthManager::messageOut
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.
QgsAuthManager::sslCertCustomConfigs
const QList< QgsAuthConfigSslServer > sslCertCustomConfigs()
sslCertCustomConfigs get SSL certificate custom configs
Definition: qgsauthmanager.cpp:2122
QgsAuthCrypto::decrypt
static const QString decrypt(const QString &pass, const QString &cipheriv, const QString &text)
Decrypt data using master password.
Definition: qgsauthcrypto.cpp:53
QgsAuthManager::rebuildCaCertsCache
bool rebuildCaCertsCache()
Rebuild certificate authority cache.
Definition: qgsauthmanager.cpp:2610
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:174
QgsAuthManager::authMethod
QgsAuthMethod * authMethod(const QString &authMethodKey)
Gets authentication method from the config/provider cache via its key.
Definition: qgsauthmanager.cpp:1003
QgsAuthManager::storeCertAuthorities
bool storeCertAuthorities(const QList< QSslCertificate > &certs)
Store multiple certificate authorities.
Definition: qgsauthmanager.cpp:2385
QgsAuthMethodRegistry::editWidget
QWidget * editWidget(const QString &authMethodKey, QWidget *parent=nullptr)
Returns the GUI edit widget associated with the auth method.
Definition: qgsauthmethodregistry.cpp:317
QgsAuthMethod::updateNetworkRequest
virtual bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Update a network request with authentication components.
Definition: qgsauthmethod.h:95
QgsAuthManager::passwordHelperSuccess
void passwordHelperSuccess()
Signals emitted on password helper success, mainly used in the tests to exit main application loop.
QgsAuthManager::loadAuthenticationConfig
bool loadAuthenticationConfig(const QString &authcfg, QgsAuthMethodConfig &mconfig, bool full=false)
Load an authentication config from the database into subclass.
Definition: qgsauthmanager.cpp:1202
QgsAuthMethodConfig::setUri
void setUri(const QString &uri)
Definition: qgsauthconfig.h:84
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsAuthMethod::updateMethodConfig
virtual void updateMethodConfig(QgsAuthMethodConfig &mconfig)=0
Update an authentication configuration in place.
qgsauthmanager.h
QgsAuthManager::instance
static QgsAuthManager * instance()
Enforce singleton pattern.
Definition: qgsauthmanager.cpp:85
QgsAuthManager::rebuildIgnoredSslErrorCache
bool rebuildIgnoredSslErrorCache()
Rebuild ignoredSSL error cache.
Definition: qgsauthmanager.cpp:2323
QgsAuthManager::configAuthMethodKey
QString configAuthMethodKey(const QString &authcfg) const
Gets key of authentication method associated with config ID.
Definition: qgsauthmanager.cpp:989
QgsAuthManager::certIdentities
const QList< QSslCertificate > certIdentities()
certIdentities get certificate identities
Definition: qgsauthmanager.cpp:1853
QgsAuthManager::setPasswordHelperLoggingEnabled
void setPasswordHelperLoggingEnabled(bool enabled)
Password helper logging enabled setter.
Definition: qgsauthmanager.cpp:3175
QgsAuthManager::trustedCaCerts
const QList< QSslCertificate > trustedCaCerts(bool includeinvalid=false)
trustedCaCerts get list of all trusted CA certificates
Definition: qgsauthmanager.cpp:2830
QgsAuthManager::storeSslCertCustomConfig
bool storeSslCertCustomConfig(const QgsAuthConfigSslServer &config)
Store an SSL certificate custom config.
Definition: qgsauthmanager.cpp:1962
QgsAuthMethodRegistry
Definition: qgsauthmethodregistry.h:46
QgsAuthMethodConfig::setMethod
void setMethod(const QString &method)
Definition: qgsauthconfig.h:88
QgsAuthManager::passwordHelperSync
bool passwordHelperSync()
Store the password manager into the wallet.
Definition: qgsauthmanager.cpp:2905
QgsAuthManager::supportedAuthMethodExpansions
QgsAuthMethod::Expansions supportedAuthMethodExpansions(const QString &authcfg)
Gets supported authentication method expansion(s), e.g.
Definition: qgsauthmanager.cpp:1041
QgsAuthMethodsMap
QHash< QString, QgsAuthMethod * > QgsAuthMethodsMap
Definition: qgsauthmethod.h:201
QgsAuthManager::configAuthMethod
QgsAuthMethod * configAuthMethod(const QString &authcfg)
Gets authentication method from the config/provider cache.
Definition: qgsauthmanager.cpp:973
QgsAuthManager::authenticationDatabasePath
const QString authenticationDatabasePath() const
The standard authentication database file in ~/.qgis3/ or defined location.
Definition: qgsauthmanager.h:111
QgsAuthManager::removeSslCertCustomConfig
bool removeSslCertCustomConfig(const QString &id, const QString &hostport)
Remove an SSL certificate custom config.
Definition: qgsauthmanager.cpp:2187
QgsAuthManager::AUTH_MAN_TAG
static const QString AUTH_MAN_TAG
The display name of the Authentication Manager.
Definition: qgsauthmanager.h:679
QgsAuthManager::setDefaultCertTrustPolicy
bool setDefaultCertTrustPolicy(QgsAuthCertUtils::CertTrustPolicy policy)
Sets the default certificate trust policy preferred by user.
Definition: qgsauthmanager.cpp:2774
QgsAuthManager::systemRootCAs
const QList< QSslCertificate > systemRootCAs()
systemRootCAs get root system certificate authorities
Definition: qgsauthmanager.cpp:2540
QgsAuthManager::defaultCertTrustPolicy
QgsAuthCertUtils::CertTrustPolicy defaultCertTrustPolicy()
Gets the default certificate trust policy preferred by user.
Definition: qgsauthmanager.cpp:2785
QgsAuthManager::databaseCAs
const QList< QSslCertificate > databaseCAs()
databaseCAs get database-stored certificate authorities
Definition: qgsauthmanager.cpp:2582
QgsAuthMethod::updateNetworkProxy
virtual bool updateNetworkProxy(QNetworkProxy &proxy, const QString &authcfg, const QString &dataprovider=QString())
Update proxy settings with authentication components.
Definition: qgsauthmethod.h:146
QgsAuthManager::hasConfigId
bool hasConfigId(const QString &txt) const
Returns whether a string includes an authcfg ID token.
Definition: qgsauthmanager.cpp:893
QgsAuthCertUtils::CertTrustPolicy
CertTrustPolicy
Type of certificate trust policy.
Definition: qgsauthcertutils.h:53
QgsAuthManager::updateNetworkReply
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,...
Definition: qgsauthmanager.cpp:1465
QgsSettings
Definition: qgssettings.h:61
QgsAuthManager::authDatabaseConfigTable
const QString authDatabaseConfigTable() const
Name of the authentication database table that stores configs.
Definition: qgsauthmanager.h:95
QgsAuthManager::uniqueConfigId
const QString uniqueConfigId() const
Gets a unique generated 7-character string to assign to as config id.
Definition: qgsauthmanager.cpp:840
qgsauthmethod.h
QgsAuthManager::extraFileCAs
const QList< QSslCertificate > extraFileCAs()
extraFileCAs extra file-based certificate authorities
Definition: qgsauthmanager.cpp:2545
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsAuthConfigSslServer::setSslCertificate
void setSslCertificate(const QSslCertificate &cert)
Sets server certificate object.
Definition: qgsauthconfig.h:380
QgsAuthMethodConfig::loadConfigString
void loadConfigString(const QString &configstr)
Load existing extended configuration.
Definition: qgsauthconfig.cpp:88
QgsAuthManager::passwordHelperEnabled
bool passwordHelperEnabled() const
Password helper enabled getter.
Definition: qgsauthmanager.cpp:3151
QgsAuthManager::backupAuthenticationDatabase
bool backupAuthenticationDatabase(QString *backuppath=nullptr)
Close connection to current authentication database and back it up.
Definition: qgsauthmanager.cpp:1324
QgsAuthManager::trustedCaCertsPemText
const QByteArray trustedCaCertsPemText()
trustedCaCertsPemText get concatenated string of all trusted CA certificates
Definition: qgsauthmanager.cpp:2899
QgsAuthManager::setScheduledAuthDatabaseErase
void setScheduledAuthDatabaseErase(bool scheduleErase)
Schedule an optional erase of authentication database, starting when mutex is lockable.
Definition: qgsauthmanager.cpp:797
QgsAuthManager::existsCertIdentity
bool existsCertIdentity(const QString &id)
Check if a certificate identity exists.
Definition: qgsauthmanager.cpp:1901
QgsAuthManager::existsSslCertCustomConfig
bool existsSslCertCustomConfig(const QString &id, const QString &hostport)
Check if SSL certificate custom config exists.
Definition: qgsauthmanager.cpp:2149
QgsAuthManager::certIdentityBundleToPem
const QStringList certIdentityBundleToPem(const QString &id)
certIdentityBundleToPem get a certificate identity bundle by id (sha hash) returned as PEM text
Definition: qgsauthmanager.cpp:1842
QgsCredentials::getMasterPassword
bool getMasterPassword(QString &password, bool stored=false)
Definition: qgscredentials.cpp:76
QgsAuthCertUtils::shaHexForCert
static QString shaHexForCert(const QSslCertificate &cert, bool formatted=false)
Gets the sha1 hash for certificate.
Definition: qgsauthcertutils.cpp:743
QgsAuthManager::disabledMessage
const QString disabledMessage() const
Standard message for when QCA's qca-ossl plugin is missing and system is disabled.
Definition: qgsauthmanager.cpp:484
QgsAuthManager::removeCertTrustPolicy
bool removeCertTrustPolicy(const QSslCertificate &cert)
Remove a certificate authority.
Definition: qgsauthmanager.cpp:2719
QgsAuthManager::CRITICAL
@ CRITICAL
Definition: qgsauthmanager.h:75
qgsauthmethodmetadata.h
QgsAuthManager::updateIgnoredSslErrorsCacheFromConfig
bool updateIgnoredSslErrorsCacheFromConfig(const QgsAuthConfigSslServer &config)
Update ignored SSL error cache with possible ignored SSL errors, using server config.
Definition: qgsauthmanager.cpp:2250
QgsAuthMethod::updateDataSourceUriItems
virtual bool updateDataSourceUriItems(QStringList &connectionItems, const QString &authcfg, const QString &dataprovider=QString())
Update data source connection items with authentication components.
Definition: qgsauthmethod.h:129
qgsapplication.h
QgsAuthManager::passwordHelperLoggingEnabled
bool passwordHelperLoggingEnabled() const
Password helper logging enabled getter.
Definition: qgsauthmanager.cpp:3168
QgsAuthManager::rebuildTrustedCaCertsCache
bool rebuildTrustedCaCertsCache()
Rebuild trusted certificate authorities cache.
Definition: qgsauthmanager.cpp:2890
QgsAuthMethod::updateNetworkReply
virtual bool updateNetworkReply(QNetworkReply *reply, const QString &authcfg, const QString &dataprovider=QString())
Update a network reply with authentication components.
Definition: qgsauthmethod.h:112
QgsAuthMethodConfigsMap
QHash< QString, QgsAuthMethodConfig > QgsAuthMethodConfigsMap
Definition: qgsauthconfig.h:179
QgsAuthManager::masterPasswordVerified
void masterPasswordVerified(bool verified)
Emitted when a password has been verify (or not)
QgsAuthMethod::DataSourceUri
@ DataSourceUri
Definition: qgsauthmethod.h:55
QgsAuthManager::certificateTrustPolicy
QgsAuthCertUtils::CertTrustPolicy certificateTrustPolicy(const QSslCertificate &cert)
certificateTrustPolicy get trust policy for a particular certificate cert
Definition: qgsauthmanager.cpp:2750
QgsAuthManager::resetMasterPassword
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,...
Definition: qgsauthmanager.cpp:650
QgsAuthManager::updateAuthenticationConfig
bool updateAuthenticationConfig(const QgsAuthMethodConfig &config)
Update an authentication config in the database.
Definition: qgsauthmanager.cpp:1131
QgsAuthMethod::NetworkRequest
@ NetworkRequest
Definition: qgsauthmethod.h:53
QgsAuthManager::eraseAuthenticationDatabase
bool eraseAuthenticationDatabase(bool backup, QString *backuppath=nullptr)
Erase all rows from all tables in authentication database.
Definition: qgsauthmanager.cpp:1360
QgsAuthMethodConfig::setVersion
void setVersion(int version)
Sets version of the configuration.
Definition: qgsauthconfig.h:93
QgsAuthManager::authMethodsMap
QgsAuthMethodsMap authMethodsMap(const QString &dataprovider=QString())
Gets available authentication methods mapped to their key.
Definition: qgsauthmanager.cpp:1014
QgsAuthConfigSslServer::sslIgnoredErrorEnums
const QList< QSslError::SslError > sslIgnoredErrorEnums() const
SSL server errors (as enum list) to ignore in connections.
Definition: qgsauthconfig.h:395
QgsAuthManager::untrustedCaCerts
const QList< QSslCertificate > untrustedCaCerts(QList< QSslCertificate > trustedCAs=QList< QSslCertificate >())
untrustedCaCerts get list of untrusted certificate authorities
Definition: qgsauthmanager.cpp:2864
qgscredentials.h
QgsAuthManager
Definition: qgsauthmanager.h:64
QgsAuthManager::MessageLevel
MessageLevel
Message log level (mirrors that of QgsMessageLog, so it can also output there)
Definition: qgsauthmanager.h:71
QgsAuthMethodConfig::version
int version() const
Gets version of the configuration.
Definition: qgsauthconfig.h:91
QgsAuthCertUtils::NoPolicy
@ NoPolicy
Definition: qgsauthcertutils.h:58
QgsAuthCertUtils::FromFile
@ FromFile
Definition: qgsauthcertutils.h:47
QgsAuthMethod::NetworkProxy
@ NetworkProxy
Definition: qgsauthmethod.h:57
qgsauthmethodregistry.h
QgsAuthManager::authManTag
QString authManTag() const
Simple text tag describing authentication system for message logs.
Definition: qgsauthmanager.h:194
QgsAuthManager::WARNING
@ WARNING
Definition: qgsauthmanager.h:74
QgsAuthManager::authDatabaseEraseRequested
void authDatabaseEraseRequested()
Emitted when a user has indicated they may want to erase the authentication db.
QgsAuthMethodConfig::method
QString method() const
Textual key of the associated authentication method.
Definition: qgsauthconfig.h:87
QgsAuthManager::sslCertCustomConfigByHost
const QgsAuthConfigSslServer sslCertCustomConfigByHost(const QString &hostport)
sslCertCustomConfigByHost get an SSL certificate custom config by hostport (host:port)
Definition: qgsauthmanager.cpp:2048
QgsAuthManager::authSetting
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 ))
Definition: qgsauthmanager.cpp:1584
QgsAuthManager::passwordHelperMessageOut
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.
QgsAuthMethodRegistry::authMethodList
QStringList authMethodList() const
Returns list of available auth methods by their keys.
Definition: qgsauthmethodregistry.cpp:359
QgsAuthManager::initSslCaches
bool initSslCaches()
Initialize various SSL authentication caches.
Definition: qgsauthmanager.cpp:1691
QgsAuthManager::clearCachedConfig
void clearCachedConfig(const QString &authcfg)
Clear an authentication config from its associated authentication method cache.
Definition: qgsauthmanager.cpp:2932
QgsAuthManager::passwordHelperFailure
void passwordHelperFailure()
Signals emitted on password helper failure, mainly used in the tests to exit main application loop.
QgsAuthManager::authDatabaseConnection
QSqlDatabase authDatabaseConnection() const
Sets up the application instance of the authentication database connection.
Definition: qgsauthmanager.cpp:105
QgsAuthManager::updateDataSourceUriItems
bool updateDataSourceUriItems(QStringList &connectionItems, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QgsDataSourceUri with an authentication config.
Definition: qgsauthmanager.cpp:1491
QgsAuthManager::existsAuthSetting
bool existsAuthSetting(const QString &key)
Check if an authentication setting exists.
Definition: qgsauthmanager.cpp:1627
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:289
QgsAuthManager::passwordHelperDelete
bool passwordHelperDelete()
Delete master password from wallet.
Definition: qgsauthmanager.cpp:3044
QgsAuthCertUtils::SystemRoot
@ SystemRoot
Definition: qgsauthcertutils.h:46
QgsAuthManager::trustedCaCertsCache
const QList< QSslCertificate > trustedCaCertsCache()
trustedCaCertsCache cache of trusted certificate authorities, ready for network connections
Definition: qgsauthmanager.h:622
QgsAuthCertUtils::DefaultTrust
@ DefaultTrust
Definition: qgsauthcertutils.h:55
QgsAuthManager::QgsAuthManager
QgsAuthManager()
Definition: qgsauthmanager.cpp:97
QgsAuthCertUtils::certsToPemText
static QByteArray certsToPemText(const QList< QSslCertificate > &certs)
certsToPemText dump a list of QSslCertificates to PEM text
Definition: qgsauthcertutils.cpp:559
QgsAuthManager::existsCertAuthority
bool existsCertAuthority(const QSslCertificate &cert)
Check if a certificate authority exists.
Definition: qgsauthmanager.cpp:2472
QgsAuthManager::certIdentityBundle
const QPair< QSslCertificate, QSslKey > certIdentityBundle(const QString &id)
Gets a certificate identity bundle by id (sha hash).
Definition: qgsauthmanager.cpp:1787
QgsAuthCrypto::passwordKeyHash
static void passwordKeyHash(const QString &pass, QString *salt, QString *hash, QString *cipheriv=nullptr)
Generate SHA256 hash for master password, with iterations and salt.
Definition: qgsauthcrypto.cpp:68
QgsAuthManager::authMethodEditWidget
QWidget * authMethodEditWidget(const QString &authMethodKey, QWidget *parent)
Gets authentication method edit widget via its key.
Definition: qgsauthmanager.cpp:1036
QgsAuthMethod::clearCachedConfig
virtual void clearCachedConfig(const QString &authcfg)=0
Clear any cached configuration.
QgsAuthManager::scheduledAuthDatabaseErase
bool scheduledAuthDatabaseErase()
Whether there is a scheduled opitonal erase of authentication database.
Definition: qgsauthmanager.h:167
QgsAuthManager::storeCertTrustPolicy
bool storeCertTrustPolicy(const QSslCertificate &cert, QgsAuthCertUtils::CertTrustPolicy policy)
Store user trust value for a certificate.
Definition: qgsauthmanager.cpp:2625
QgsAuthCertUtils::Trusted
@ Trusted
Definition: qgsauthcertutils.h:56
QgsAuthManager::certIdentity
const QSslCertificate certIdentity(const QString &id)
certIdentity get a certificate identity by id (sha hash)
Definition: qgsauthmanager.cpp:1753
QgsAuthCertUtils::certificateIsAuthorityOrIssuer
static bool certificateIsAuthorityOrIssuer(const QSslCertificate &cert)
Gets whether a certificate is an Authority or can at least sign other certificates.
Definition: qgsauthcertutils.cpp:1021
QgsAuthManager::setMasterPassword
bool setMasterPassword(bool verify=false)
Main call to initially set or continually check master password is set.
Definition: qgsauthmanager.cpp:489
QgsAuthMethod::supportedExpansions
QgsAuthMethod::Expansions supportedExpansions() const
Flags that represent the update points (where authentication configurations are expanded) supported b...
Definition: qgsauthmethod.h:79
QgsAuthManager::removeAuthenticationConfig
bool removeAuthenticationConfig(const QString &authcfg)
Remove an authentication config in the database.
Definition: qgsauthmanager.cpp:1270
QgsAuthManager::updateIgnoredSslErrorsCache
bool updateIgnoredSslErrorsCache(const QString &shahostport, const QList< QSslError > &errors)
Update ignored SSL error cache with possible ignored SSL errors, using sha:host:port key.
Definition: qgsauthmanager.cpp:2279
QgsAuthManager::removeCertAuthority
bool removeCertAuthority(const QSslCertificate &cert)
Remove a certificate authority.
Definition: qgsauthmanager.cpp:2510
QgsAuthManager::storeCertIdentity
bool storeCertIdentity(const QSslCertificate &cert, const QSslKey &key)
Store a certificate identity.
Definition: qgsauthmanager.cpp:1709
QgsAuthManager::authDatabaseChanged
void authDatabaseChanged()
Emitted when the authentication db is significantly changed, e.g. large record removal,...
QgsAuthMethodRegistry::instance
static QgsAuthMethodRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
Definition: qgsauthmethodregistry.cpp:38
QgsAuthManager::isDisabled
bool isDisabled() const
Whether QCA has the qca-ossl plugin, which a base run-time requirement.
Definition: qgsauthmanager.cpp:475
QgsAuthCertUtils::certsFromFile
static QList< QSslCertificate > certsFromFile(const QString &certspath)
Returns a list of concatenated certs from a PEM or DER formatted file.
Definition: qgsauthcertutils.cpp:125
QgsAuthConfigSslServer::configString
const QString configString() const
Configuration as a concatenated string.
Definition: qgsauthconfig.cpp:340
QgsAuthMethodConfig::id
const QString id() const
Gets 'authcfg' 7-character alphanumeric ID of the config.
Definition: qgsauthconfig.h:73
QgsAuthManager::updateNetworkRequest
bool updateNetworkRequest(QNetworkRequest &request, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkRequest with an authentication config.
Definition: qgsauthmanager.cpp:1440
QgsAuthManager::AUTH_PASSWORD_HELPER_DISPLAY_NAME
static const QString AUTH_PASSWORD_HELPER_DISPLAY_NAME
The display name of the password helper (platform dependent)
Definition: qgsauthmanager.h:676
QgsScopedRuntimeProfile
Definition: qgsruntimeprofiler.h:115
QgsAuthManager::~QgsAuthManager
~QgsAuthManager() override
Definition: qgsauthmanager.cpp:3004
qgssettings.h
QgsAuthCertUtils::mapDigestToCerts
static QMap< QString, QSslCertificate > mapDigestToCerts(const QList< QSslCertificate > &certs)
Map certificate sha1 to certificate as simple cache.
Definition: qgsauthcertutils.cpp:55
QgsAuthConfigSslServer::isNull
bool isNull() const
Whether configuration is null (missing components)
Definition: qgsauthconfig.cpp:386
QgsAuthManager::mappedDatabaseCAs
const QMap< QString, QSslCertificate > mappedDatabaseCAs()
mappedDatabaseCAs get sha1-mapped database-stored certificate authorities
Definition: qgsauthmanager.cpp:2604
QgsAuthManager::rebuildCertTrustCache
bool rebuildCertTrustCache()
Rebuild certificate authority cache.
Definition: qgsauthmanager.cpp:2796
QgsMessageLog::logMessage
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).
Definition: qgsmessagelog.cpp:27
QgsAuthMethodConfig::configString
const QString configString() const
The extended configuration, as stored and retrieved from the authentication database.
Definition: qgsauthconfig.cpp:76
QgsAuthConfigSslServer
Configuration container for SSL server connection exceptions or overrides.
Definition: qgsauthconfig.h:371
QgsAuthMethodConfig::isValid
bool isValid(bool validateid=false) const
Whether the configuration is valid.
Definition: qgsauthconfig.cpp:65
QgsAuthManager::certAuthority
const QSslCertificate certAuthority(const QString &id)
Gets a certificate authority by id (sha hash)
Definition: qgsauthmanager.cpp:2438
QgsAuthCertUtils::sslErrorEnumString
static QString sslErrorEnumString(QSslError::SslError errenum)
Gets short strings describing an SSL error.
Definition: qgsauthcertutils.cpp:1153
QgsAuthManager::masterPasswordHashInDatabase
bool masterPasswordHashInDatabase() const
Verify a password hash existing in authentication database.
Definition: qgsauthmanager.cpp:3284
QgsAuthManager::removeAllAuthenticationConfigs
bool removeAllAuthenticationConfigs()
Clear all authentication configs from table in database and from provider caches.
Definition: qgsauthmanager.cpp:1303
QgsAuthMethodConfig::setId
void setId(const QString &id)
Sets auth config ID.
Definition: qgsauthconfig.h:75
QgsAuthCrypto::encrypt
static const QString encrypt(const QString &pass, const QString &cipheriv, const QString &text)
Encrypt data using master password.
Definition: qgsauthcrypto.cpp:45
QgsAuthManager::configIdUnique
bool configIdUnique(const QString &id) const
Verify if provided authentication id is unique.
Definition: qgsauthmanager.cpp:877
QgsAuthManager::setPasswordHelperEnabled
void setPasswordHelperEnabled(bool enabled)
Password helper enabled setter.
Definition: qgsauthmanager.cpp:3158
QgsAuthManager::configIds
QStringList configIds() const
Gets list of authentication ids from database.
Definition: qgsauthmanager.cpp:3378
qgslogger.h
QgsAuthManager::certIdentityIds
QStringList certIdentityIds() const
certIdentityIds get list of certificate identity ids from database
Definition: qgsauthmanager.cpp:1875
QgsAuthManager::init
bool init(const QString &pluginPath=QString(), const QString &authDatabasePath=QString())
init initialize QCA, prioritize qca-ossl plugin and optionally set up the authentication database
Definition: qgsauthmanager.cpp:168
QgsAuthManager::masterPasswordIsSet
bool masterPasswordIsSet() const
Whether master password has be input and verified, i.e. authentication database is accessible.
Definition: qgsauthmanager.cpp:640
QgsAuthManager::INFO
@ INFO
Definition: qgsauthmanager.h:73
qgsauthcrypto.h
QgsAuthMethodConfig::setName
void setName(const QString &name)
Sets name of configuration.
Definition: qgsauthconfig.h:80
QgsAuthCertUtils::certIsViable
static bool certIsViable(const QSslCertificate &cert)
certIsViable checks for viability errors of cert and whether it is NULL
Definition: qgsauthcertutils.cpp:1300
QgsAuthManager::authDatabaseServersTable
const QString authDatabaseServersTable() const
Name of the authentication database table that stores server exceptions/configs.
Definition: qgsauthmanager.h:98
QgsAuthManager::storeAuthSetting
bool storeAuthSetting(const QString &key, const QVariant &value, bool encrypt=false)
Store an authentication setting (stored as string via QVariant( value ).toString() )
Definition: qgsauthmanager.cpp:1543
QgsAuthManager::certTrustPolicy
QgsAuthCertUtils::CertTrustPolicy certTrustPolicy(const QSslCertificate &cert)
certTrustPolicy get whether certificate cert is trusted by user
Definition: qgsauthmanager.cpp:2664
QgsAuthCertUtils::InDatabase
@ InDatabase
Definition: qgsauthcertutils.h:48
QgsAuthManager::removeCertIdentity
bool removeCertIdentity(const QString &id)
Remove a certificate identity.
Definition: qgsauthmanager.cpp:1934
QgsAuthManager::clearMasterPassword
void clearMasterPassword()
Clear supplied master password.
Definition: qgsauthmanager.h:145
QgsAuthManager::sslCertCustomConfig
const QgsAuthConfigSslServer sslCertCustomConfig(const QString &id, const QString &hostport)
sslCertCustomConfig get an SSL certificate custom config by id (sha hash) and hostport (host:port)
Definition: qgsauthmanager.cpp:2006
QgsAuthManager::removeCertTrustPolicies
bool removeCertTrustPolicies(const QList< QSslCertificate > &certs)
Remove a group certificate authorities.
Definition: qgsauthmanager.cpp:2702
QgsAuthManager::dumpIgnoredSslErrorsCache_
void dumpIgnoredSslErrorsCache_()
Utility function to dump the cache for debug purposes.
Definition: qgsauthmanager.cpp:2226
QgsAuthConfigSslServer::sslCertificate
const QSslCertificate sslCertificate() const
Server certificate object.
Definition: qgsauthconfig.h:378
QgsAuthManager::masterPasswordSame
bool masterPasswordSame(const QString &pass) const
Check whether supplied password is the same as the one already set.
Definition: qgsauthmanager.cpp:645
QgsAuthManager::updateConfigAuthMethods
void updateConfigAuthMethods()
Sync the confg/authentication method cache with what is in database.
Definition: qgsauthmanager.cpp:944
QgsAuthMethodConfig
Configuration storage class for authentication method configurations.
Definition: qgsauthconfig.h:38
QgsAuthManager::storeAuthenticationConfig
bool storeAuthenticationConfig(QgsAuthMethodConfig &mconfig)
Store an authentication config in the database.
Definition: qgsauthmanager.cpp:1054
QgsAuthConfigSslServer::loadConfigString
void loadConfigString(const QString &config=QString())
Load concatenated string into configuration, e.g. from auth database.
Definition: qgsauthconfig.cpp:359
QgsAuthManager::registerCoreAuthMethods
bool registerCoreAuthMethods()
Instantiate and register existing C++ core authentication methods from plugins.
Definition: qgsauthmanager.cpp:824
QgsAuthManager::availableAuthMethodConfigs
QgsAuthMethodConfigsMap availableAuthMethodConfigs(const QString &dataprovider=QString())
Gets mapping of authentication config ids and their base configs (not decrypted data)
Definition: qgsauthmanager.cpp:899
QgsAuthCrypto::verifyPasswordKeyHash
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.
Definition: qgsauthcrypto.cpp:92
qgsmessagelog.h
QgsAuthCertUtils::Untrusted
@ Untrusted
Definition: qgsauthcertutils.h:57
QgsAuthManager::updateNetworkProxy
bool updateNetworkProxy(QNetworkProxy &proxy, const QString &authcfg, const QString &dataprovider=QString())
Provider call to update a QNetworkProxy with an authentication config.
Definition: qgsauthmanager.cpp:1517
QgsAuthMethodConfig::uri
const QString uri() const
A URI to auto-select a config when connecting to a resource.
Definition: qgsauthconfig.h:83