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