QGIS API Documentation  2.12.0-Lyon
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 = 0;
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 = ( 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 0;
902 
903  if ( !mConfigAuthMethods.contains( authcfg ) )
904  {
905  QgsDebugMsg( QString( "No config auth method found in database for authcfg: %1" ).arg( authcfg ) );
906  return 0;
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 0;
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( 0 );
970 
971  QgsAuthMethod* authmethod = configAuthMethod( authcfg );
972  if ( authmethod )
973  {
974  return authmethod->supportedExpansions();
975  }
976  return QgsAuthMethod::Expansions( 0 );
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( "Data source URI updating not supported by authcfg: %1" ).arg( authcfg ) );
1369  return false;
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 false;
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 false;
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  QNetworkRequest req;
2364  return req.sslConfiguration().caCertificates();
2365 }
2366 
2368 {
2369  QList<QSslCertificate> certs;
2370  QList<QSslCertificate> filecerts;
2371  QVariant cafileval = QgsAuthManager::instance()->getAuthSetting( QString( "cafile" ) );
2372  if ( cafileval.isNull() )
2373  return certs;
2374 
2375  QVariant allowinvalid = QgsAuthManager::instance()->getAuthSetting( QString( "cafileallowinvalid" ), QVariant( false ) );
2376  if ( allowinvalid.isNull() )
2377  return certs;
2378 
2379  QString cafile( cafileval.toString() );
2380  if ( !cafile.isEmpty() && QFile::exists( cafile ) )
2381  {
2382  filecerts = QgsAuthCertUtils::certsFromFile( cafile );
2383  }
2384  // only CAs or certs capable of signing other certs are allowed
2385  Q_FOREACH ( const QSslCertificate& cert, filecerts )
2386  {
2387  if ( !allowinvalid.toBool() && !cert.isValid() )
2388  {
2389  continue;
2390  }
2391 
2393  {
2394  certs << cert;
2395  }
2396  }
2397  return certs;
2398 }
2399 
2401 {
2402  QList<QSslCertificate> certs;
2403 
2404  QSqlQuery query( authDbConnection() );
2405  query.prepare( QString( "SELECT id, cert FROM %1" ).arg( authDbAuthoritiesTable() ) );
2406 
2407  if ( !authDbQuery( &query ) )
2408  return certs;
2409 
2410  if ( query.isActive() && query.isSelect() )
2411  {
2412  while ( query.next() )
2413  {
2414  certs << QSslCertificate( query.value( 1 ).toByteArray(), QSsl::Pem );
2415  }
2416  }
2417 
2418  return certs;
2419 }
2420 
2422 {
2424 }
2425 
2427 {
2428  mCaCertsCache.clear();
2429  // in reverse order of precedence, with regards to duplicates, so QMap inserts overwrite
2430  insertCaCertInCache( QgsAuthCertUtils::SystemRoot, getSystemRootCAs() );
2431  insertCaCertInCache( QgsAuthCertUtils::FromFile, getExtraFileCAs() );
2432  insertCaCertInCache( QgsAuthCertUtils::InDatabase, getDatabaseCAs() );
2433 
2434  bool res = !mCaCertsCache.isEmpty(); // should at least contain system root CAs
2435  QgsDebugMsg( QString( "Rebuild of CA certs cache %1" ).arg( res ? "SUCCEEDED" : "FAILED" ) );
2436  return res;
2437 }
2438 
2440 {
2441  if ( cert.isNull() )
2442  {
2443  QgsDebugMsg( "Passed certificate is null" );
2444  return false;
2445  }
2446 
2447  removeCertTrustPolicy( cert );
2448 
2450 
2451  if ( policy == QgsAuthCertUtils::DefaultTrust )
2452  {
2453  QgsDebugMsg( QString( "Passed policy was default, all cert records in database were removed for id: %1" ).arg( id ) );
2454  return true;
2455  }
2456 
2457  QSqlQuery query( authDbConnection() );
2458  query.prepare( QString( "INSERT INTO %1 (id, policy) "
2459  "VALUES (:id, :policy)" ).arg( authDbTrustTable() ) );
2460 
2461  query.bindValue( ":id", id );
2462  query.bindValue( ":policy", ( int )policy );
2463 
2464  if ( !authDbStartTransaction() )
2465  return false;
2466 
2467  if ( !authDbQuery( &query ) )
2468  return false;
2469 
2470  if ( !authDbCommit() )
2471  return false;
2472 
2473  QgsDebugMsg( QString( "Store certificate trust policy SUCCESS for id: %1" ).arg( id ) );
2474  return true;
2475 }
2476 
2478 {
2479  if ( cert.isNull() )
2480  {
2481  QgsDebugMsg( "Passed certificate is null" );
2483  }
2484 
2486 
2487  QSqlQuery query( authDbConnection() );
2488  query.prepare( QString( "SELECT policy FROM %1 "
2489  "WHERE id = :id" ).arg( authDbTrustTable() ) );
2490 
2491  query.bindValue( ":id", id );
2492 
2493  if ( !authDbQuery( &query ) )
2495 
2497  if ( query.isActive() && query.isSelect() )
2498  {
2499  if ( query.first() )
2500  {
2501  policy = ( QgsAuthCertUtils::CertTrustPolicy )query.value( 0 ).toInt();
2502  QgsDebugMsg( QString( "Authentication cert trust policy retrieved for id: %1" ).arg( id ) );
2503  }
2504  if ( query.next() )
2505  {
2506  QgsDebugMsg( QString( "Select contains more than one cert trust policy for id: %1" ).arg( id ) );
2507  emit messageOut( tr( "Authentication database contains duplicate cert trust policies" ), authManTag(), WARNING );
2509  }
2510  }
2511  return policy;
2512 }
2513 
2515 {
2516  if ( certs.size() < 1 )
2517  {
2518  QgsDebugMsg( "Passed certificate list has no certs" );
2519  return false;
2520  }
2521 
2522  Q_FOREACH ( const QSslCertificate& cert, certs )
2523  {
2524  if ( !removeCertTrustPolicy( cert ) )
2525  return false;
2526  }
2527  return true;
2528 }
2529 
2531 {
2532  if ( cert.isNull() )
2533  {
2534  QgsDebugMsg( "Passed certificate is null" );
2535  return false;
2536  }
2537 
2539 
2540  QSqlQuery query( authDbConnection() );
2541 
2542  query.prepare( QString( "DELETE FROM %1 WHERE id = :id" ).arg( authDbTrustTable() ) );
2543 
2544  query.bindValue( ":id", id );
2545 
2546  if ( !authDbStartTransaction() )
2547  return false;
2548 
2549  if ( !authDbQuery( &query ) )
2550  return false;
2551 
2552  if ( !authDbCommit() )
2553  return false;
2554 
2555  QgsDebugMsg( QString( "REMOVED cert trust policy for id: %1" ).arg( id ) );
2556 
2557  return true;
2558 }
2559 
2561 {
2562  if ( cert.isNull() )
2563  {
2565  }
2566 
2568  const QStringList& trustedids = mCertTrustCache.value( QgsAuthCertUtils::Trusted );
2569  const QStringList& untrustedids = mCertTrustCache.value( QgsAuthCertUtils::Untrusted );
2570 
2572  if ( trustedids.contains( id ) )
2573  {
2574  policy = QgsAuthCertUtils::Trusted;
2575  }
2576  else if ( untrustedids.contains( id ) )
2577  {
2578  policy = QgsAuthCertUtils::Untrusted;
2579  }
2580  return policy;
2581 }
2582 
2584 {
2585  if ( policy == QgsAuthCertUtils::DefaultTrust )
2586  {
2587  // set default trust policy to Trusted by removing setting
2588  return removeAuthSetting( "certdefaulttrust" );
2589  }
2590  return storeAuthSetting( "certdefaulttrust", ( int )policy );
2591 }
2592 
2594 {
2595  QVariant policy( getAuthSetting( "certdefaulttrust" ) );
2596  if ( policy.isNull() )
2597  {
2599  }
2600  return ( QgsAuthCertUtils::CertTrustPolicy )policy.toInt();
2601 }
2602 
2604 {
2605  mCertTrustCache.clear();
2606 
2607  QSqlQuery query( authDbConnection() );
2608  query.prepare( QString( "SELECT id, policy FROM %1" ).arg( authDbTrustTable() ) );
2609 
2610  if ( !authDbQuery( &query ) )
2611  {
2612  QgsDebugMsg( "Rebuild of cert trust policy cache FAILED" );
2613  return false;
2614  }
2615 
2616  if ( query.isActive() && query.isSelect() )
2617  {
2618  while ( query.next() )
2619  {
2620  QString id = query.value( 0 ).toString();
2622 
2623  QStringList ids;
2624  if ( mCertTrustCache.contains( policy ) )
2625  {
2626  ids = mCertTrustCache.value( policy );
2627  }
2628  mCertTrustCache.insert( policy, ids << id );
2629  }
2630  }
2631 
2632  QgsDebugMsg( "Rebuild of cert trust policy cache SUCCEEDED" );
2633  return true;
2634 }
2635 
2637 {
2639  QStringList trustedids = mCertTrustCache.value( QgsAuthCertUtils::Trusted );
2640  QStringList untrustedids = mCertTrustCache.value( QgsAuthCertUtils::Untrusted );
2641  const QList<QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> >& certpairs( mCaCertsCache.values() );
2642 
2643  QList<QSslCertificate> trustedcerts;
2644  for ( int i = 0; i < certpairs.size(); ++i )
2645  {
2646  QSslCertificate cert( certpairs.at( i ).second );
2647  QString certid( QgsAuthCertUtils::shaHexForCert( cert ) );
2648  if ( trustedids.contains( certid ) )
2649  {
2650  // trusted certs are always added regardless of their validity
2651  trustedcerts.append( cert );
2652  }
2653  else if ( defaultpolicy == QgsAuthCertUtils::Trusted && !untrustedids.contains( certid ) )
2654  {
2655  if ( !includeinvalid && !cert.isValid() )
2656  continue;
2657  trustedcerts.append( cert );
2658  }
2659  }
2660 
2661  // update application default SSL config for new requests
2663  sslconfig.setCaCertificates( trustedcerts );
2665 
2666  return trustedcerts;
2667 }
2668 
2670 {
2671  if ( trustedCAs.isEmpty() )
2672  {
2673  if ( mTrustedCaCertsCache.isEmpty() )
2674  {
2676  }
2677  trustedCAs = getTrustedCaCertsCache();
2678  }
2679 
2680  const QList<QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> >& certpairs( mCaCertsCache.values() );
2681 
2682  QList<QSslCertificate> untrustedCAs;
2683  for ( int i = 0; i < certpairs.size(); ++i )
2684  {
2685  QSslCertificate cert( certpairs.at( i ).second );
2686  if ( !trustedCAs.contains( cert ) )
2687  {
2688  untrustedCAs.append( cert );
2689  }
2690  }
2691  return untrustedCAs;
2692 }
2693 
2695 {
2696  mTrustedCaCertsCache = getTrustedCaCerts();
2697  QgsDebugMsg( "Rebuilt trusted cert authorities cache" );
2698  // TODO: add some error trapping for the operation
2699  return true;
2700 }
2701 
2703 {
2704  QByteArray capem;
2706  if ( !certs.isEmpty() )
2707  {
2708  QStringList certslist;
2709  Q_FOREACH ( const QSslCertificate& cert, certs )
2710  {
2711  certslist << cert.toPem();
2712  }
2713  capem = certslist.join( "\n" ).toAscii(); //+ "\n";
2714  }
2715  return capem;
2716 }
2717 
2718 
2720 
2721 #endif
2722 
2724 {
2725  if ( isDisabled() )
2726  return;
2727 
2728  Q_FOREACH ( QString authcfg, configIds() )
2729  {
2730  clearCachedConfig( authcfg );
2731  }
2732 }
2733 
2735 {
2736  if ( isDisabled() )
2737  return;
2738 
2739  QgsAuthMethod* authmethod = configAuthMethod( authcfg );
2740  if ( authmethod )
2741  {
2742  authmethod->clearCachedConfig( authcfg );
2743  }
2744 }
2745 
2746 void QgsAuthManager::writeToConsole( const QString &message,
2747  const QString &tag,
2749 {
2750  Q_UNUSED( tag );
2751 
2752  // only output WARNING and CRITICAL messages
2753  if ( level == QgsAuthManager::INFO )
2754  return;
2755 
2756  QString msg;
2757  switch ( level )
2758  {
2760  msg += "WARNING: ";
2761  break;
2763  msg += "ERROR: ";
2764  break;
2765  default:
2766  break;
2767  }
2768  msg += message;
2769 
2770  QTextStream out( stdout, QIODevice::WriteOnly );
2771  out << msg << endl;
2772 }
2773 
2774 void QgsAuthManager::tryToStartDbErase()
2775 {
2776  ++mScheduledDbEraseRequestCount;
2777  // wait a total of 90 seconds for GUI availiability or user interaction, then cancel schedule
2778  int trycutoff = 90 / ( mScheduledDbEraseRequestWait ? mScheduledDbEraseRequestWait : 3 );
2779  if ( mScheduledDbEraseRequestCount >= trycutoff )
2780  {
2781  setScheduledAuthDbErase( false );
2782  QgsDebugMsg( "authDatabaseEraseRequest emitting/scheduling cancelled" );
2783  return;
2784  }
2785  else
2786  {
2787  QgsDebugMsg( QString( "authDatabaseEraseRequest attempt (%1 of %2)" )
2788  .arg( mScheduledDbEraseRequestCount ).arg( trycutoff ) );
2789  }
2790 
2791  if ( scheduledAuthDbErase() && !mScheduledDbEraseRequestEmitted && mMutex->tryLock() )
2792  {
2793  // see note in header about this signal's use
2794  mScheduledDbEraseRequestEmitted = true;
2796 
2797  mMutex->unlock();
2798 
2799  QgsDebugMsg( "authDatabaseEraseRequest emitted" );
2800  return;
2801  }
2802  QgsDebugMsg( "authDatabaseEraseRequest emit skipped" );
2803 }
2804 
2806  : QObject()
2807  , mAuthInit( false )
2808  , mAuthDbPath( QString() )
2809  , mQcaInitializer( 0 )
2810  , mMasterPass( QString() )
2811  , mPassTries( 0 )
2812  , mAuthDisabled( false )
2813  , mScheduledDbEraseTimer( 0 )
2814  , mScheduledDbErase( false )
2815  , mScheduledDbEraseRequestWait( 3 )
2816  , mScheduledDbEraseRequestEmitted( false )
2817  , mScheduledDbEraseRequestCount( 0 )
2818  , mMutex( 0 )
2819  , mIgnoredSslErrorsCache( QHash<QString, QSet<QSslError::SslError> >() )
2820 {
2821  mMutex = new QMutex( QMutex::Recursive );
2822  connect( this, SIGNAL( messageOut( const QString&, const QString&, QgsAuthManager::MessageLevel ) ),
2823  this, SLOT( writeToConsole( const QString&, const QString&, QgsAuthManager::MessageLevel ) ) );
2824 }
2825 
2827 {
2828  if ( !isDisabled() )
2829  {
2831  qDeleteAll( mAuthMethods );
2832 
2833  QSqlDatabase authConn = authDbConnection();
2834  if ( authConn.isValid() && authConn.isOpen() )
2835  authConn.close();
2836  }
2837  delete mMutex;
2838  mMutex = 0;
2839  delete mScheduledDbEraseTimer;
2840  mScheduledDbEraseTimer = 0;
2841  delete mQcaInitializer;
2842  mQcaInitializer = 0;
2843 }
2844 
2845 bool QgsAuthManager::masterPasswordInput()
2846 {
2847  if ( isDisabled() )
2848  return false;
2849 
2850  QString pass;
2852  creds->lock();
2853  bool ok = creds->getMasterPassword( pass, masterPasswordHashInDb() );
2854  creds->unlock();
2855 
2856  if ( ok && !pass.isEmpty() && !masterPasswordSame( pass ) )
2857  {
2858  mMasterPass = pass;
2859  return true;
2860  }
2861  return false;
2862 }
2863 
2864 bool QgsAuthManager::masterPasswordRowsInDb( int *rows ) const
2865 {
2866  if ( isDisabled() )
2867  return false;
2868 
2869  QSqlQuery query( authDbConnection() );
2870  query.prepare( QString( "SELECT Count(*) FROM %1" ).arg( authDbPassTable() ) );
2871 
2872  bool ok = authDbQuery( &query );
2873  if ( query.first() )
2874  {
2875  *rows = query.value( 0 ).toInt();
2876  }
2877 
2878  return ok;
2879 }
2880 
2882 {
2883  if ( isDisabled() )
2884  return false;
2885 
2886  int rows = 0;
2887  if ( !masterPasswordRowsInDb( &rows ) )
2888  {
2889  const char* err = QT_TR_NOOP( "Master password: FAILED to access database" );
2890  QgsDebugMsg( err );
2891  emit messageOut( tr( err ), authManTag(), CRITICAL );
2892 
2893  return false;
2894  }
2895  return ( rows == 1 );
2896 }
2897 
2898 bool QgsAuthManager::masterPasswordCheckAgainstDb( const QString &compare ) const
2899 {
2900  if ( isDisabled() )
2901  return false;
2902 
2903  // first verify there is only one row in auth db (uses first found)
2904 
2905  QSqlQuery query( authDbConnection() );
2906  query.prepare( QString( "SELECT salt, hash FROM %1" ).arg( authDbPassTable() ) );
2907  if ( !authDbQuery( &query ) )
2908  return false;
2909 
2910  if ( !query.first() )
2911  return false;
2912 
2913  QString salt = query.value( 0 ).toString();
2914  QString hash = query.value( 1 ).toString();
2915 
2916  return QgsAuthCrypto::verifyPasswordKeyHash( compare.isNull() ? mMasterPass : compare, salt, hash );
2917 }
2918 
2919 bool QgsAuthManager::masterPasswordStoreInDb() const
2920 {
2921  if ( isDisabled() )
2922  return false;
2923 
2924  QString salt, hash, civ;
2925  QgsAuthCrypto::passwordKeyHash( mMasterPass, &salt, &hash, &civ );
2926 
2927  QSqlQuery query( authDbConnection() );
2928  query.prepare( QString( "INSERT INTO %1 (salt, hash, civ) VALUES (:salt, :hash, :civ)" ).arg( authDbPassTable() ) );
2929 
2930  query.bindValue( ":salt", salt );
2931  query.bindValue( ":hash", hash );
2932  query.bindValue( ":civ", civ );
2933 
2934  if ( !authDbStartTransaction() )
2935  return false;
2936 
2937  if ( !authDbQuery( &query ) )
2938  return false;
2939 
2940  if ( !authDbCommit() )
2941  return false;
2942 
2943  return true;
2944 }
2945 
2946 bool QgsAuthManager::masterPasswordClearDb()
2947 {
2948  if ( isDisabled() )
2949  return false;
2950 
2951  QSqlQuery query( authDbConnection() );
2952  query.prepare( QString( "DELETE FROM %1" ).arg( authDbPassTable() ) );
2953  bool res = authDbTransactionQuery( &query );
2954  if ( res )
2956  return res;
2957 }
2958 
2959 const QString QgsAuthManager::masterPasswordCiv() const
2960 {
2961  if ( isDisabled() )
2962  return QString();
2963 
2964  QSqlQuery query( authDbConnection() );
2965  query.prepare( QString( "SELECT civ FROM %1" ).arg( authDbPassTable() ) );
2966  if ( !authDbQuery( &query ) )
2967  return QString();
2968 
2969  if ( !query.first() )
2970  return QString();
2971 
2972  return query.value( 0 ).toString();
2973 }
2974 
2976 {
2977  QStringList configids = QStringList();
2978 
2979  if ( isDisabled() )
2980  return configids;
2981 
2982  QSqlQuery query( authDbConnection() );
2983  query.prepare( QString( "SELECT id FROM %1" ).arg( authDbConfigTable() ) );
2984 
2985  if ( !authDbQuery( &query ) )
2986  {
2987  return configids;
2988  }
2989 
2990  if ( query.isActive() )
2991  {
2992  while ( query.next() )
2993  {
2994  configids << query.value( 0 ).toString();
2995  }
2996  }
2997  return configids;
2998 }
2999 
3000 bool QgsAuthManager::verifyPasswordCanDecryptConfigs() const
3001 {
3002  if ( isDisabled() )
3003  return false;
3004 
3005  // no need to check for setMasterPassword, since this is private and it will be set
3006 
3007  QSqlQuery query( authDbConnection() );
3008 
3009  query.prepare( QString( "SELECT id, config FROM %1" ).arg( authDbConfigTable() ) );
3010 
3011  if ( !authDbQuery( &query ) )
3012  return false;
3013 
3014  if ( !query.isActive() || !query.isSelect() )
3015  {
3016  QgsDebugMsg( QString( "Verify password can decrypt configs FAILED, query not active or a select operation" ) );
3017  return false;
3018  }
3019 
3020  int checked = 0;
3021  while ( query.next() )
3022  {
3023  ++checked;
3024  QString configstring( QgsAuthCrypto::decrypt( mMasterPass, masterPasswordCiv(), query.value( 1 ).toString() ) );
3025  if ( configstring.isEmpty() )
3026  {
3027  QgsDebugMsg( QString( "Verify password can decrypt configs FAILED, could not decrypt a config (id: %1)" )
3028  .arg( query.value( 0 ).toString() ) );
3029  return false;
3030  }
3031  }
3032 
3033  QgsDebugMsg( QString( "Verify password can decrypt configs SUCCESS (checked %1 configs)" ).arg( checked ) );
3034  return true;
3035 }
3036 
3037 bool QgsAuthManager::reencryptAllAuthenticationConfigs( const QString &prevpass, const QString &prevciv )
3038 {
3039  if ( isDisabled() )
3040  return false;
3041 
3042  bool res = true;
3043  Q_FOREACH ( QString configid, configIds() )
3044  {
3045  res = res && reencryptAuthenticationConfig( configid, prevpass, prevciv );
3046  }
3047  return res;
3048 }
3049 
3050 bool QgsAuthManager::reencryptAuthenticationConfig( const QString &authcfg, const QString &prevpass, const QString &prevciv )
3051 {
3052  if ( isDisabled() )
3053  return false;
3054 
3055  // no need to check for setMasterPassword, since this is private and it will be set
3056 
3057  QSqlQuery query( authDbConnection() );
3058 
3059  query.prepare( QString( "SELECT config FROM %1 "
3060  "WHERE id = :id" ).arg( authDbConfigTable() ) );
3061 
3062  query.bindValue( ":id", authcfg );
3063 
3064  if ( !authDbQuery( &query ) )
3065  return false;
3066 
3067  if ( !query.isActive() || !query.isSelect() )
3068  {
3069  QgsDebugMsg( QString( "Reencrypt FAILED, query not active or a select operation for authcfg: %2" ).arg( authcfg ) );
3070  return false;
3071  }
3072 
3073  if ( query.first() )
3074  {
3075  QString configstring( QgsAuthCrypto::decrypt( prevpass, prevciv, query.value( 0 ).toString() ) );
3076 
3077  if ( query.next() )
3078  {
3079  QgsDebugMsg( QString( "Select contains more than one for authcfg: %1" ).arg( authcfg ) );
3080  emit messageOut( tr( "Authentication database contains duplicate configuration IDs" ), authManTag(), WARNING );
3081  return false;
3082  }
3083 
3084  query.clear();
3085 
3086  query.prepare( QString( "UPDATE %1 "
3087  "SET config = :config "
3088  "WHERE id = :id" ).arg( authDbConfigTable() ) );
3089 
3090  query.bindValue( ":id", authcfg );
3091  query.bindValue( ":config", QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), configstring ) );
3092 
3093  if ( !authDbStartTransaction() )
3094  return false;
3095 
3096  if ( !authDbQuery( &query ) )
3097  return false;
3098 
3099  if ( !authDbCommit() )
3100  return false;
3101 
3102  QgsDebugMsg( QString( "Reencrypt SUCCESS for authcfg: %2" ).arg( authcfg ) );
3103  return true;
3104  }
3105  else
3106  {
3107  QgsDebugMsg( QString( "Reencrypt FAILED, could not find in db authcfg: %2" ).arg( authcfg ) );
3108  return false;
3109  }
3110 }
3111 
3112 bool QgsAuthManager::reencryptAllAuthenticationSettings( const QString &prevpass, const QString &prevciv )
3113 {
3114  // TODO: start remove (when function is actually used)
3115  Q_UNUSED( prevpass );
3116  Q_UNUSED( prevciv );
3117  return true;
3118  // end remove
3119 
3120 #if 0
3121  if ( isDisabled() )
3122  return false;
3123 
3125  // When adding settings that require encryption, add to list //
3127 
3128  QStringList encryptedsettings;
3129  encryptedsettings << "";
3130 
3131  Q_FOREACH ( const QString &sett, encryptedsettings )
3132  {
3133  if ( sett.isEmpty() || !existsAuthSetting( sett ) )
3134  continue;
3135 
3136  // no need to check for setMasterPassword, since this is private and it will be set
3137 
3138  QSqlQuery query( authDbConnection() );
3139 
3140  query.prepare( QString( "SELECT value FROM %1 "
3141  "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
3142 
3143  query.bindValue( ":setting", sett );
3144 
3145  if ( !authDbQuery( &query ) )
3146  return false;
3147 
3148  if ( !query.isActive() || !query.isSelect() )
3149  {
3150  QgsDebugMsg( QString( "Reencrypt FAILED, query not active or a select operation for setting: %2" ).arg( sett ) );
3151  return false;
3152  }
3153 
3154  if ( query.first() )
3155  {
3156  QString settvalue( QgsAuthCrypto::decrypt( prevpass, prevciv, query.value( 0 ).toString() ) );
3157 
3158  query.clear();
3159 
3160  query.prepare( QString( "UPDATE %1 "
3161  "SET value = :value "
3162  "WHERE setting = :setting" ).arg( authDbSettingsTable() ) );
3163 
3164  query.bindValue( ":setting", sett );
3165  query.bindValue( ":value", QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), settvalue ) );
3166 
3167  if ( !authDbStartTransaction() )
3168  return false;
3169 
3170  if ( !authDbQuery( &query ) )
3171  return false;
3172 
3173  if ( !authDbCommit() )
3174  return false;
3175 
3176  QgsDebugMsg( QString( "Reencrypt SUCCESS for setting: %2" ).arg( sett ) );
3177  return true;
3178  }
3179  else
3180  {
3181  QgsDebugMsg( QString( "Reencrypt FAILED, could not find in db setting: %2" ).arg( sett ) );
3182  return false;
3183  }
3184 
3185  if ( query.next() )
3186  {
3187  QgsDebugMsg( QString( "Select contains more than one for setting: %1" ).arg( sett ) );
3188  emit messageOut( tr( "Authentication database contains duplicate setting keys" ), authManTag(), WARNING );
3189  }
3190 
3191  return false;
3192  }
3193 
3194  return true;
3195 #endif
3196 }
3197 
3198 bool QgsAuthManager::reencryptAllAuthenticationIdentities( const QString &prevpass, const QString &prevciv )
3199 {
3200  if ( isDisabled() )
3201  return false;
3202 
3203  bool res = true;
3204  Q_FOREACH ( const QString &identid, getCertIdentityIds() )
3205  {
3206  res = res && reencryptAuthenticationIdentity( identid, prevpass, prevciv );
3207  }
3208  return res;
3209 }
3210 
3211 bool QgsAuthManager::reencryptAuthenticationIdentity(
3212  const QString &identid,
3213  const QString &prevpass,
3214  const QString &prevciv )
3215 {
3216  if ( isDisabled() )
3217  return false;
3218 
3219  // no need to check for setMasterPassword, since this is private and it will be set
3220 
3221  QSqlQuery query( authDbConnection() );
3222 
3223  query.prepare( QString( "SELECT key FROM %1 "
3224  "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
3225 
3226  query.bindValue( ":id", identid );
3227 
3228  if ( !authDbQuery( &query ) )
3229  return false;
3230 
3231  if ( !query.isActive() || !query.isSelect() )
3232  {
3233  QgsDebugMsg( QString( "Reencrypt FAILED, query not active or a select operation for identity id: %2" ).arg( identid ) );
3234  return false;
3235  }
3236 
3237  if ( query.first() )
3238  {
3239  QString keystring( QgsAuthCrypto::decrypt( prevpass, prevciv, query.value( 0 ).toString() ) );
3240 
3241  if ( query.next() )
3242  {
3243  QgsDebugMsg( QString( "Select contains more than one for identity id: %1" ).arg( identid ) );
3244  emit messageOut( tr( "Authentication database contains duplicate identity IDs" ), authManTag(), WARNING );
3245  return false;
3246  }
3247 
3248  query.clear();
3249 
3250  query.prepare( QString( "UPDATE %1 "
3251  "SET key = :key "
3252  "WHERE id = :id" ).arg( authDbIdentitiesTable() ) );
3253 
3254  query.bindValue( ":id", identid );
3255  query.bindValue( ":key", QgsAuthCrypto::encrypt( mMasterPass, masterPasswordCiv(), keystring ) );
3256 
3257  if ( !authDbStartTransaction() )
3258  return false;
3259 
3260  if ( !authDbQuery( &query ) )
3261  return false;
3262 
3263  if ( !authDbCommit() )
3264  return false;
3265 
3266  QgsDebugMsg( QString( "Reencrypt SUCCESS for identity id: %2" ).arg( identid ) );
3267  return true;
3268  }
3269  else
3270  {
3271  QgsDebugMsg( QString( "Reencrypt FAILED, could not find in db identity id: %2" ).arg( identid ) );
3272  return false;
3273  }
3274 }
3275 
3276 bool QgsAuthManager::authDbOpen() const
3277 {
3278  if ( isDisabled() )
3279  return false;
3280 
3281  QSqlDatabase authdb = authDbConnection();
3282  if ( !authdb.isOpen() )
3283  {
3284  if ( !authdb.open() )
3285  {
3286  QgsDebugMsg( QString( "Unable to establish database connection\nDatabase: %1\nDriver error: %2\nDatabase error: %3" )
3287  .arg( authenticationDbPath(),
3288  authdb.lastError().driverText(),
3289  authdb.lastError().databaseText() ) );
3290  emit messageOut( tr( "Unable to establish authentication database connection" ), authManTag(), CRITICAL );
3291  return false;
3292  }
3293  }
3294  return true;
3295 }
3296 
3297 bool QgsAuthManager::authDbQuery( QSqlQuery *query ) const
3298 {
3299  if ( isDisabled() )
3300  return false;
3301 
3302  query->setForwardOnly( true );
3303  if ( !query->exec() )
3304  {
3305  const char* err = QT_TR_NOOP( "Auth db query exec() FAILED" );
3306  QgsDebugMsg( err );
3307  emit messageOut( tr( err ), authManTag(), WARNING );
3308  return false;
3309  }
3310 
3311  if ( query->lastError().isValid() )
3312  {
3313  QgsDebugMsg( QString( "Auth db query FAILED: %1\nError: %2" )
3314  .arg( query->executedQuery(),
3315  query->lastError().text() ) );
3316  emit messageOut( tr( "Auth db query FAILED" ), authManTag(), WARNING );
3317  return false;
3318  }
3319 
3320  return true;
3321 }
3322 
3323 bool QgsAuthManager::authDbStartTransaction() const
3324 {
3325  if ( isDisabled() )
3326  return false;
3327 
3328  if ( !authDbConnection().transaction() )
3329  {
3330  const char* err = QT_TR_NOOP( "Auth db FAILED to start transaction" );
3331  QgsDebugMsg( err );
3332  emit messageOut( tr( err ), authManTag(), WARNING );
3333  return false;
3334  }
3335 
3336  return true;
3337 }
3338 
3339 bool QgsAuthManager::authDbCommit() const
3340 {
3341  if ( isDisabled() )
3342  return false;
3343 
3344  if ( !authDbConnection().commit() )
3345  {
3346  const char* err = QT_TR_NOOP( "Auth db FAILED to rollback changes" );
3347  QgsDebugMsg( err );
3348  emit messageOut( tr( err ), authManTag(), WARNING );
3350  return false;
3351  }
3352 
3353  return true;
3354 }
3355 
3356 bool QgsAuthManager::authDbTransactionQuery( QSqlQuery *query ) const
3357 {
3358  if ( isDisabled() )
3359  return false;
3360 
3361  if ( !authDbConnection().transaction() )
3362  {
3363  const char* err = QT_TR_NOOP( "Auth db FAILED to start transaction" );
3364  QgsDebugMsg( err );
3365  emit messageOut( tr( err ), authManTag(), WARNING );
3366  return false;
3367  }
3368 
3369  bool ok = authDbQuery( query );
3370 
3371  if ( ok && !authDbConnection().commit() )
3372  {
3373  const char* err = QT_TR_NOOP( "Auth db FAILED to rollback changes" );
3374  QgsDebugMsg( err );
3375  emit messageOut( tr( err ), authManTag(), WARNING );
3377  return false;
3378  }
3379 
3380  return ok;
3381 }
3382 
3383 void QgsAuthManager::insertCaCertInCache( QgsAuthCertUtils::CaCertSource source, const QList<QSslCertificate>& certs )
3384 {
3385  Q_FOREACH ( const QSslCertificate& cert, certs )
3386  {
3387  mCaCertsCache.insert( QgsAuthCertUtils::shaHexForCert( cert ),
3389  }
3390 }
3391 
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:73
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
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:64
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
Emmitted when a password has been verify (or not)
bool removeCertAuthority(const QSslCertificate &cert)
Remove a certificate authority.
QSslConfiguration sslConfiguration() const
void authDatabaseEraseRequested() const
Emmitted when a user has indicated they may want to erase the authentication db.
bool resetMasterPassword(const QString &newpass, const QString &oldpass, bool keepbackup, QString *backuppath=0)
Reset the master password to a new one, then re-encrypt all previous configs in a new database file...
const QList< QSslCertificate > getUntrustedCaCerts(QList< QSslCertificate > trustedCAs=QList< QSslCertificate >())
Get list of all untrusted CA certificates.
bool exec(const QString &query)
CertTrustPolicy
Type of certificate trust policy.
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.
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
Emmitted 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.
static bool verifyPasswordKeyHash(const QString &pass, const QString &salt, const QString &hash, QString *hashderived=0)
Verify existing master password hash to a re-generated one.
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)
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.
const QString authManTag() const
Simple text tag describing authentication system for message logs.
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:67
const QgsAuthConfigSslServer getSslCertCustomConfig(const QString &id, const QString &hostport)
Get an SSL certificate custom config by id (sha hash) and host:port.
void clear()
bool contains(const QString &connectionName)
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:72
void append(const T &value)
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:77
void bindValue(const QString &placeholder, const QVariant &val, QFlags< QSql::ParamTypeFlag > paramType)
Configuration storage class for authentication method configurations.
Definition: qgsauthconfig.h:36
bool backupAuthenticationDatabase(QString *backuppath=0)
Close connection to current authentication database and back it up.
bool isEmpty() const
const T & value() const
CaCertSource
Type of CA certificate source.
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 'authcfg' 7-character alphanumeric ID of the config.
Definition: qgsauthconfig.h:62
QByteArray toPem() const
const QSslCertificate sslCertificate() const
Server certificate object.
MessageLevel
Message log level (mirrors that of QgsMessageLog, so it can also output there)
int remove(const Key &key)
QWidget * editWidget(const QString &authMethodKey, QWidget *parent=0)
Return the auth method capabilities.
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'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()
static void passwordKeyHash(const QString &pass, QString *salt, QString *hash, QString *cipheriv=0)
Generate SHA256 hash for master password, with iterations and salt.
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.
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 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:82
bool loadAuthenticationConfig(const QString &authcfg, QgsAuthMethodConfig &mconfig, bool full=false)
Load an authentication config from the database into subclass.
bool eraseAuthenticationDatabase(bool backup, QString *backuppath=0)
Erase all rows from all tables in authentication database.
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.
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
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.
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:80
void setName(const QString &name)
Set name of configuration.
Definition: qgsauthconfig.h:69
bool rebuildIgnoredSslErrorCache()
Rebuild ignoredSSL error cache.
void setSslCertificate(const QSslCertificate &cert)
Set server certificate object.
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:76
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.