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