Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgsauthmanager.h
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 : : #ifndef QGSAUTHMANAGER_H
18 : : #define QGSAUTHMANAGER_H
19 : :
20 : : #include "qgis_core.h"
21 : : #include "qgis_sip.h"
22 : : #include <QObject>
23 : : #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
24 : : #include <QMutex>
25 : : #else
26 : : #include <QRecursiveMutex>
27 : : #endif
28 : : #include <QNetworkReply>
29 : : #include <QNetworkRequest>
30 : : #include <QSqlDatabase>
31 : : #include <QSqlError>
32 : : #include <QSqlQuery>
33 : : #include <QStringList>
34 : :
35 : : #ifndef QT_NO_SSL
36 : : #include <QSslCertificate>
37 : : #include <QSslKey>
38 : : #include <QtCrypto>
39 : : #include "qgsauthcertutils.h"
40 : : #endif
41 : :
42 : : #include "qgsauthconfig.h"
43 : : #include "qgsauthmethod.h"
44 : :
45 : : // Qt5KeyChain library
46 : : #include "keychain.h"
47 : :
48 : : #ifndef SIP_RUN
49 : : namespace QCA
50 : : {
51 : : class Initializer;
52 : : }
53 : : #endif
54 : : class QgsAuthMethod;
55 : : class QgsAuthMethodEdit;
56 : : class QgsAuthProvider;
57 : : class QTimer;
58 : :
59 : :
60 : : /**
61 : : * \ingroup core
62 : : * \brief Singleton offering an interface to manage the authentication configuration database
63 : : * and to utilize configurations through various authentication method plugins
64 : : *
65 : : * QgsAuthManager should not usually be directly created, but rather accessed through
66 : : * QgsApplication::authManager().
67 : : */
68 : : class CORE_EXPORT QgsAuthManager : public QObject
69 : : {
70 : 6 : Q_OBJECT
71 : :
72 : : public:
73 : :
74 : : //! Message log level (mirrors that of QgsMessageLog, so it can also output there)
75 : : enum MessageLevel
76 : : {
77 : : INFO = 0,
78 : : WARNING = 1,
79 : : CRITICAL = 2
80 : : };
81 : 15 : Q_ENUM( MessageLevel )
82 : :
83 : : /**
84 : : * \brief init initialize QCA, prioritize qca-ossl plugin and optionally set up the authentication database
85 : : * \param pluginPath the plugin path
86 : : * \param authDatabasePath the authentication DB path
87 : : * \return TRUE on success
88 : : * \see QgsApplication::pluginPath
89 : : * \see QgsApplication::qgisAuthDatabaseFilePath
90 : : */
91 : : bool init( const QString &pluginPath = QString(), const QString &authDatabasePath = QString() );
92 : :
93 : : ~QgsAuthManager() override;
94 : :
95 : : //! Sets up the application instance of the authentication database connection
96 : : QSqlDatabase authDatabaseConnection() const;
97 : :
98 : : //! Name of the authentication database table that stores configs
99 : 0 : const QString authDatabaseConfigTable() const { return AUTH_CONFIG_TABLE; }
100 : :
101 : : //! Name of the authentication database table that stores server exceptions/configs
102 : 0 : const QString authDatabaseServersTable() const { return AUTH_SERVERS_TABLE; }
103 : :
104 : :
105 : : //! Whether QCA has the qca-ossl plugin, which a base run-time requirement
106 : : bool isDisabled() const;
107 : :
108 : : //! Standard message for when QCA's qca-ossl plugin is missing and system is disabled
109 : : const QString disabledMessage() const;
110 : :
111 : : /**
112 : : * The standard authentication database file in ~/.qgis3/ or defined location
113 : : * \see QgsApplication::qgisAuthDatabaseFilePath
114 : : */
115 : 0 : const QString authenticationDatabasePath() const { return mAuthDbPath; }
116 : :
117 : : /**
118 : : * Main call to initially set or continually check master password is set
119 : : * \note If it is not set, the user is asked for its input
120 : : * \param verify Whether password's hash was saved in authentication database
121 : : */
122 : : bool setMasterPassword( bool verify = false );
123 : :
124 : : /**
125 : : * Overloaded call to reset master password or set it initially without user interaction
126 : : * \note Only use this in trusted reset functions, unit tests or user/app setup scripts!
127 : : * \param pass Password to use
128 : : * \param verify Whether password's hash was saved in authentication database
129 : : */
130 : : bool setMasterPassword( const QString &pass, bool verify = false );
131 : :
132 : : /**
133 : : * Verify the supplied master password against any existing hash in authentication database
134 : : * \note Do not emit verification signals when only comparing
135 : : * \param compare Password to compare against
136 : : */
137 : : bool verifyMasterPassword( const QString &compare = QString() );
138 : :
139 : : //! Whether master password has be input and verified, i.e. authentication database is accessible
140 : : bool masterPasswordIsSet() const;
141 : :
142 : : //! Verify a password hash existing in authentication database
143 : : bool masterPasswordHashInDatabase() const;
144 : :
145 : : /**
146 : : * Clear supplied master password
147 : : * \note This will not necessarily clear authenticated connections cached in network connection managers
148 : : */
149 : 0 : void clearMasterPassword() { mMasterPass = QString(); }
150 : :
151 : : /**
152 : : * Check whether supplied password is the same as the one already set
153 : : * \param pass Password to verify
154 : : */
155 : : bool masterPasswordSame( const QString &pass ) const;
156 : :
157 : : /**
158 : : * Reset the master password to a new one, then re-encrypt all previous
159 : : * configs in a new database file, optionally backup curren database
160 : : * \param newpass New master password to replace existing
161 : : * \param oldpass Current master password to replace existing
162 : : * \param keepbackup Whether to keep the generated backup of current database
163 : : * \param backuppath Where the backup is located, if kept
164 : : */
165 : : bool resetMasterPassword( const QString &newpass, const QString &oldpass, bool keepbackup, QString *backuppath SIP_INOUT = nullptr );
166 : :
167 : : /**
168 : : * Whether there is a scheduled opitonal erase of authentication database.
169 : : * \note not available in Python bindings
170 : : */
171 : 0 : bool scheduledAuthDatabaseErase() { return mScheduledDbErase; } SIP_SKIP
172 : :
173 : : /**
174 : : * Schedule an optional erase of authentication database, starting when mutex is lockable.
175 : : * \note When an erase is scheduled, any attempt to set the master password,
176 : : * e.g. password input dialog, is effectively canceled.
177 : : * For example: In a GUI app, this keeps excess password input dialogs from popping
178 : : * up when a user has initiated an erase, from a password input dialog, because
179 : : * they forgot their password.
180 : : * The created schedule timer will emit a request to gain access to the user,
181 : : * through the given application, to prompt the erase operation (e.g. via a dialog);
182 : : * if no access to user interaction occurs within 90 seconds, it cancels the schedule.
183 : : * \note not available in Python bindings
184 : : */
185 : : void setScheduledAuthDatabaseErase( bool scheduleErase ) SIP_SKIP;
186 : :
187 : : /**
188 : : * Re-emit a signal to schedule an optional erase of authentication database.
189 : : * \note This can be called from the slot connected to a previously emitted scheduling signal,
190 : : * so that the slot can ask for another emit later, if the slot noticies the current GUI
191 : : * processing state is not ready for interacting with the user, e.g. project is still loading
192 : : * \param emitted Setting to FALSE will cause signal to be emitted by the schedule timer.
193 : : * Setting to TRUE will stop any emitting, but will not stop the schedule timer.
194 : : */
195 : : void setScheduledAuthDatabaseEraseRequestEmitted( bool emitted ) { mScheduledDbEraseRequestEmitted = emitted; }
196 : :
197 : : //! Simple text tag describing authentication system for message logs
198 : 0 : QString authManTag() const { return AUTH_MAN_TAG; }
199 : :
200 : : //! Instantiate and register existing C++ core authentication methods from plugins
201 : : bool registerCoreAuthMethods();
202 : :
203 : : //! Gets mapping of authentication config ids and their base configs (not decrypted data)
204 : : QgsAuthMethodConfigsMap availableAuthMethodConfigs( const QString &dataprovider = QString() );
205 : :
206 : : //! Sync the confg/authentication method cache with what is in database
207 : : void updateConfigAuthMethods();
208 : :
209 : : /**
210 : : * Gets authentication method from the config/provider cache
211 : : * \param authcfg Authentication config id
212 : : */
213 : : QgsAuthMethod *configAuthMethod( const QString &authcfg );
214 : :
215 : : /**
216 : : * Gets key of authentication method associated with config ID
217 : : * \param authcfg
218 : : */
219 : : QString configAuthMethodKey( const QString &authcfg ) const;
220 : :
221 : : /**
222 : : * Gets keys of supported authentication methods
223 : : */
224 : : QStringList authMethodsKeys( const QString &dataprovider = QString() );
225 : :
226 : : /**
227 : : * Gets authentication method from the config/provider cache via its key
228 : : * \param authMethodKey Authentication method key
229 : : */
230 : : QgsAuthMethod *authMethod( const QString &authMethodKey );
231 : :
232 : : /**
233 : : * Gets available authentication methods mapped to their key
234 : : * \param dataprovider Provider key filter, returning only methods that support a particular provider
235 : : * \note not available in Python bindings
236 : : */
237 : : QgsAuthMethodsMap authMethodsMap( const QString &dataprovider = QString() ) SIP_SKIP;
238 : :
239 : : /**
240 : : * Gets authentication method edit widget via its key
241 : : * \param authMethodKey Authentication method key
242 : : * \param parent Parent widget
243 : : */
244 : : QWidget *authMethodEditWidget( const QString &authMethodKey, QWidget *parent );
245 : :
246 : : /**
247 : : * Gets supported authentication method expansion(s), e.g. NetworkRequest | DataSourceURI, as flags
248 : : * \param authcfg
249 : : */
250 : : QgsAuthMethod::Expansions supportedAuthMethodExpansions( const QString &authcfg );
251 : :
252 : : //! Gets a unique generated 7-character string to assign to as config id
253 : : const QString uniqueConfigId() const;
254 : :
255 : : /**
256 : : * Verify if provided authentication id is unique
257 : : * \param id Id to check
258 : : */
259 : : bool configIdUnique( const QString &id ) const;
260 : :
261 : : /**
262 : : * Returns whether a string includes an authcfg ID token
263 : : * \param txt String to check
264 : : */
265 : : bool hasConfigId( const QString &txt ) const;
266 : :
267 : : //! Returns the regular expression for authcfg=.{7} key/value token for authentication ids
268 : : QString configIdRegex() const { return AUTH_CFG_REGEX;}
269 : :
270 : : //! Gets list of authentication ids from database
271 : : QStringList configIds() const;
272 : :
273 : : /**
274 : : * Store an authentication config in the database
275 : : * \param mconfig Associated authentication config id
276 : : * \returns Whether operation succeeded
277 : : */
278 : : bool storeAuthenticationConfig( QgsAuthMethodConfig &mconfig SIP_INOUT );
279 : :
280 : : /**
281 : : * Update an authentication config in the database
282 : : * \param config Associated authentication config id
283 : : * \returns Whether operation succeeded
284 : : */
285 : : bool updateAuthenticationConfig( const QgsAuthMethodConfig &config );
286 : :
287 : : /**
288 : : * Load an authentication config from the database into subclass
289 : : * \param authcfg Associated authentication config id
290 : : * \param mconfig Subclassed config to load into
291 : : * \param full Whether to decrypt and populate all sensitive data in subclass
292 : : * \returns Whether operation succeeded
293 : : */
294 : : bool loadAuthenticationConfig( const QString &authcfg, QgsAuthMethodConfig &mconfig SIP_INOUT, bool full = false );
295 : :
296 : : /**
297 : : * Remove an authentication config in the database
298 : : * \param authcfg Associated authentication config id
299 : : * \returns Whether operation succeeded
300 : : */
301 : : bool removeAuthenticationConfig( const QString &authcfg );
302 : :
303 : : /**
304 : : * Clear all authentication configs from table in database and from provider caches
305 : : * \returns Whether operation succeeded
306 : : */
307 : : bool removeAllAuthenticationConfigs();
308 : :
309 : : /**
310 : : * Close connection to current authentication database and back it up
311 : : * \returns Path to backup
312 : : */
313 : : bool backupAuthenticationDatabase( QString *backuppath SIP_INOUT = nullptr );
314 : :
315 : : /**
316 : : * Erase all rows from all tables in authentication database
317 : : * \param backup Whether to backup of current database
318 : : * \param backuppath Where the backup is locate
319 : : * \returns Whether operation succeeded
320 : : */
321 : : bool eraseAuthenticationDatabase( bool backup, QString *backuppath SIP_INOUT = nullptr );
322 : :
323 : :
324 : : ////////////////// Auth Method calls ///////////////////////
325 : :
326 : : /**
327 : : * Provider call to update a QNetworkRequest with an authentication config
328 : : * \param request The QNetworkRequest
329 : : * \param authcfg Associated authentication config id
330 : : * \param dataprovider Provider key filter, offering logic branching in authentication method
331 : : * \returns Whether operation succeeded
332 : : */
333 : : bool updateNetworkRequest( QNetworkRequest &request SIP_INOUT, const QString &authcfg,
334 : : const QString &dataprovider = QString() );
335 : :
336 : : /**
337 : : * Provider call to update a QNetworkReply with an authentication config (used to skip known SSL errors, etc.)
338 : : * \param reply The QNetworkReply
339 : : * \param authcfg Associated authentication config id
340 : : * \param dataprovider Provider key filter, offering logic branching in authentication method
341 : : * \returns Whether operation succeeded
342 : : */
343 : : bool updateNetworkReply( QNetworkReply *reply, const QString &authcfg,
344 : : const QString &dataprovider = QString() );
345 : :
346 : : /**
347 : : * Provider call to update a QgsDataSourceUri with an authentication config
348 : : * \param connectionItems The connection items, e.g. username=myname, of QgsDataSourceUri
349 : : * \param authcfg Associated authentication config id
350 : : * \param dataprovider Provider key filter, offering logic branching in authentication method
351 : : * \returns Whether operation succeeded
352 : : */
353 : : bool updateDataSourceUriItems( QStringList &connectionItems SIP_INOUT, const QString &authcfg,
354 : : const QString &dataprovider = QString() );
355 : :
356 : : /**
357 : : * Provider call to update a QNetworkProxy with an authentication config
358 : : * \param proxy the QNetworkProxy
359 : : * \param authcfg Associated authentication config id
360 : : * \param dataprovider Provider key filter, offering logic branching in authentication method
361 : : * \returns Whether operation succeeded
362 : : */
363 : : bool updateNetworkProxy( QNetworkProxy &proxy SIP_INOUT, const QString &authcfg,
364 : : const QString &dataprovider = QString() );
365 : :
366 : : ////////////////// Generic settings ///////////////////////
367 : :
368 : : //! Store an authentication setting (stored as string via QVariant( value ).toString() )
369 : : bool storeAuthSetting( const QString &key, const QVariant &value, bool encrypt = false );
370 : :
371 : : /**
372 : : * \brief authSetting get an authentication setting (retrieved as string and returned as QVariant( QString ))
373 : : * \param key setting key
374 : : * \param defaultValue
375 : : * \param decrypt if the value needs decrypted
376 : : * \return QVariant( QString ) authentication setting
377 : : * \since QGIS 3.0
378 : : */
379 : : QVariant authSetting( const QString &key, const QVariant &defaultValue = QVariant(), bool decrypt = false );
380 : :
381 : : //! Check if an authentication setting exists
382 : : bool existsAuthSetting( const QString &key );
383 : :
384 : : //! Remove an authentication setting
385 : : bool removeAuthSetting( const QString &key );
386 : :
387 : : #ifndef QT_NO_SSL
388 : : ////////////////// Certificate calls ///////////////////////
389 : :
390 : : //! Initialize various SSL authentication caches
391 : : bool initSslCaches();
392 : :
393 : : //! Store a certificate identity
394 : : bool storeCertIdentity( const QSslCertificate &cert, const QSslKey &key );
395 : :
396 : : /**
397 : : * \brief certIdentity get a certificate identity by \a id (sha hash)
398 : : * \param id sha hash of the cert
399 : : * \return the certificate
400 : : * \since QGIS 3.0
401 : : */
402 : : const QSslCertificate certIdentity( const QString &id );
403 : :
404 : : /**
405 : : * Gets a certificate identity bundle by \a id (sha hash).
406 : : * \param id sha shash
407 : : * \return a pair with the certificate and its SSL key
408 : : * \note not available in Python bindings
409 : : * \since QGIS 3.0
410 : : */
411 : : const QPair<QSslCertificate, QSslKey> certIdentityBundle( const QString &id ) SIP_SKIP;
412 : :
413 : : /**
414 : : * \brief certIdentityBundleToPem get a certificate identity bundle by \a id (sha hash) returned as PEM text
415 : : * \param id sha hash
416 : : * \return a list of strings
417 : : * \since QGIS 3.0
418 : : */
419 : : const QStringList certIdentityBundleToPem( const QString &id );
420 : :
421 : : /**
422 : : * \brief certIdentities get certificate identities
423 : : * \return list of certificates
424 : : * \since QGIS 3.0
425 : : */
426 : : const QList<QSslCertificate> certIdentities();
427 : :
428 : : //!
429 : :
430 : : /**
431 : : * \brief certIdentityIds get list of certificate identity ids from database
432 : : * \return list of certificate ids
433 : : * \since QGIS 3.0
434 : : */
435 : : QStringList certIdentityIds() const;
436 : :
437 : : //! Check if a certificate identity exists
438 : : bool existsCertIdentity( const QString &id );
439 : :
440 : : //! Remove a certificate identity
441 : : bool removeCertIdentity( const QString &id );
442 : :
443 : :
444 : : //! Store an SSL certificate custom config
445 : : bool storeSslCertCustomConfig( const QgsAuthConfigSslServer &config );
446 : :
447 : : /**
448 : : * \brief sslCertCustomConfig get an SSL certificate custom config by \a id (sha hash) and \a hostport (host:port)
449 : : * \param id sha hash
450 : : * \param hostport string host:port
451 : : * \return a SSL certificate custom config
452 : : * \since QGIS 3.0
453 : : */
454 : : const QgsAuthConfigSslServer sslCertCustomConfig( const QString &id, const QString &hostport );
455 : :
456 : : /**
457 : : * \brief sslCertCustomConfigByHost get an SSL certificate custom config by \a hostport (host:port)
458 : : * \param hostport host:port
459 : : * \return a SSL certificate custom config
460 : : * \since QGIS 3.0
461 : : */
462 : : const QgsAuthConfigSslServer sslCertCustomConfigByHost( const QString &hostport );
463 : :
464 : : /**
465 : : * \brief sslCertCustomConfigs get SSL certificate custom configs
466 : : * \return list of SSL certificate custom config
467 : : * \since QGIS 3.0
468 : : */
469 : : const QList<QgsAuthConfigSslServer> sslCertCustomConfigs();
470 : :
471 : : //! Check if SSL certificate custom config exists
472 : : bool existsSslCertCustomConfig( const QString &id, const QString &hostport );
473 : :
474 : : //! Remove an SSL certificate custom config
475 : : bool removeSslCertCustomConfig( const QString &id, const QString &hostport );
476 : :
477 : : /**
478 : : * \brief ignoredSslErrorCache Get ignored SSL error cache, keyed with cert/connection's sha:host:port.
479 : : * \return hash keyed with cert/connection's sha:host:port.
480 : : * \note not available in Python bindings
481 : : * \since QGIS 3.0
482 : : */
483 : : QHash<QString, QSet<QSslError::SslError> > ignoredSslErrorCache() { return mIgnoredSslErrorsCache; } SIP_SKIP
484 : :
485 : : //! Utility function to dump the cache for debug purposes
486 : : void dumpIgnoredSslErrorsCache_();
487 : :
488 : : //! Update ignored SSL error cache with possible ignored SSL errors, using server config
489 : : bool updateIgnoredSslErrorsCacheFromConfig( const QgsAuthConfigSslServer &config );
490 : :
491 : : //! Update ignored SSL error cache with possible ignored SSL errors, using sha:host:port key
492 : : bool updateIgnoredSslErrorsCache( const QString &shahostport, const QList<QSslError> &errors );
493 : :
494 : : //! Rebuild ignoredSSL error cache
495 : : bool rebuildIgnoredSslErrorCache();
496 : :
497 : :
498 : : //! Store multiple certificate authorities
499 : : bool storeCertAuthorities( const QList<QSslCertificate> &certs );
500 : :
501 : : //! Store a certificate authority
502 : : bool storeCertAuthority( const QSslCertificate &cert );
503 : :
504 : : //! Gets a certificate authority by id (sha hash)
505 : :
506 : : /**
507 : : * \brief certAuthority get a certificate authority by \a id (sha hash)
508 : : * \param id sha hash
509 : : * \return a certificate
510 : : * \since QGIS 3.0
511 : : */
512 : : const QSslCertificate certAuthority( const QString &id );
513 : :
514 : : //! Check if a certificate authority exists
515 : : bool existsCertAuthority( const QSslCertificate &cert );
516 : :
517 : : //! Remove a certificate authority
518 : : bool removeCertAuthority( const QSslCertificate &cert );
519 : :
520 : : /**
521 : : * \brief systemRootCAs get root system certificate authorities
522 : : * \return list of certificate authorities
523 : : * \since QGIS 3.0
524 : : */
525 : : const QList<QSslCertificate> systemRootCAs();
526 : :
527 : : /**
528 : : * \brief extraFileCAs extra file-based certificate authorities
529 : : * \return list of certificate authorities
530 : : * \since QGIS 3.0
531 : : */
532 : : const QList<QSslCertificate> extraFileCAs();
533 : :
534 : : /**
535 : : * \brief databaseCAs get database-stored certificate authorities
536 : : * \return list of certificate authorities
537 : : * \since QGIS 3.0
538 : : */
539 : : const QList<QSslCertificate> databaseCAs();
540 : :
541 : : /**
542 : : * \brief mappedDatabaseCAs get sha1-mapped database-stored certificate authorities
543 : : * \return sha1-mapped certificate authorities
544 : : * \since QGIS 3.0
545 : : */
546 : : const QMap<QString, QSslCertificate> mappedDatabaseCAs();
547 : :
548 : : /**
549 : : * \brief caCertsCache get all CA certs mapped to their sha1 from cache.
550 : : * \return map of sha1 <source, certificates>
551 : : * \note not available in Python bindings
552 : : * \since QGIS 3.0
553 : : */
554 : : const QMap<QString, QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> > caCertsCache() SIP_SKIP
555 : : {
556 : : return mCaCertsCache;
557 : : }
558 : :
559 : : //! Rebuild certificate authority cache
560 : : bool rebuildCaCertsCache();
561 : :
562 : : //! Store user trust value for a certificate
563 : : bool storeCertTrustPolicy( const QSslCertificate &cert, QgsAuthCertUtils::CertTrustPolicy policy );
564 : :
565 : : /**
566 : : * \brief certTrustPolicy get whether certificate \a cert is trusted by user
567 : : * \param cert
568 : : * \return DefaultTrust if certificate sha not in trust table, i.e. follows default trust policy
569 : : * \since QGIS 3.0
570 : : */
571 : : QgsAuthCertUtils::CertTrustPolicy certTrustPolicy( const QSslCertificate &cert );
572 : :
573 : : //! Remove a group certificate authorities
574 : : bool removeCertTrustPolicies( const QList<QSslCertificate> &certs );
575 : :
576 : : //! Remove a certificate authority
577 : : bool removeCertTrustPolicy( const QSslCertificate &cert );
578 : :
579 : : /**
580 : : * \brief certificateTrustPolicy get trust policy for a particular certificate \a cert
581 : : * \param cert
582 : : * \return DefaultTrust if certificate sha not in trust table, i.e. follows default trust policy
583 : : * \since QGIS 3.0
584 : : */
585 : : QgsAuthCertUtils::CertTrustPolicy certificateTrustPolicy( const QSslCertificate &cert );
586 : :
587 : : //! Sets the default certificate trust policy preferred by user
588 : : bool setDefaultCertTrustPolicy( QgsAuthCertUtils::CertTrustPolicy policy );
589 : :
590 : : //! Gets the default certificate trust policy preferred by user
591 : : QgsAuthCertUtils::CertTrustPolicy defaultCertTrustPolicy();
592 : :
593 : : /**
594 : : * \brief certTrustCache get cache of certificate sha1s, per trust policy
595 : : * \return trust-policy-mapped certificate sha1s
596 : : * \since QGIS 3.0
597 : : */
598 : : const QMap<QgsAuthCertUtils::CertTrustPolicy, QStringList > certTrustCache() { return mCertTrustCache; }
599 : :
600 : : //! Rebuild certificate authority cache
601 : : bool rebuildCertTrustCache();
602 : :
603 : : /**
604 : : * \brief trustedCaCerts get list of all trusted CA certificates
605 : : * \param includeinvalid whether invalid certs needs to be returned
606 : : * \return list of certificates
607 : : * \since QGIS 3.0
608 : : */
609 : : const QList<QSslCertificate> trustedCaCerts( bool includeinvalid = false );
610 : :
611 : : /**
612 : : * \brief untrustedCaCerts get list of untrusted certificate authorities
613 : : * \return list of certificates
614 : : * \since QGIS 3.0
615 : : */
616 : : const QList<QSslCertificate> untrustedCaCerts( QList<QSslCertificate> trustedCAs = QList<QSslCertificate>() );
617 : :
618 : : //! Rebuild trusted certificate authorities cache
619 : : bool rebuildTrustedCaCertsCache();
620 : :
621 : : /**
622 : : * \brief trustedCaCertsCache cache of trusted certificate authorities, ready for network connections
623 : : * \return list of certificates
624 : : * \since QGIS 3.0
625 : : */
626 : 0 : const QList<QSslCertificate> trustedCaCertsCache() { return mTrustedCaCertsCache; }
627 : :
628 : : /**
629 : : * \brief trustedCaCertsPemText get concatenated string of all trusted CA certificates
630 : : * \return bye array with all PEM encoded trusted CAs
631 : : * \since QGIS 3.0
632 : : */
633 : : const QByteArray trustedCaCertsPemText();
634 : :
635 : : #endif
636 : :
637 : : /**
638 : : * Error message getter
639 : : * \note not available in Python bindings
640 : : */
641 : : const QString passwordHelperErrorMessage() { return mPasswordHelperErrorMessage; } SIP_SKIP
642 : :
643 : : /**
644 : : * Delete master password from wallet
645 : : * \note not available in Python bindings
646 : : */
647 : : bool passwordHelperDelete() SIP_SKIP;
648 : :
649 : : /**
650 : : * Password helper enabled getter
651 : : * \note Available in Python bindings since QGIS 3.8.0
652 : : */
653 : : bool passwordHelperEnabled() const;
654 : :
655 : : /**
656 : : * Password helper enabled setter
657 : : * \note Available in Python bindings since QGIS 3.8.0
658 : : */
659 : : void setPasswordHelperEnabled( bool enabled );
660 : :
661 : : /**
662 : : * Password helper logging enabled getter
663 : : * \note not available in Python bindings
664 : : */
665 : : bool passwordHelperLoggingEnabled() const SIP_SKIP;
666 : :
667 : : /**
668 : : * Password helper logging enabled setter
669 : : * \note not available in Python bindings
670 : : */
671 : : void setPasswordHelperLoggingEnabled( bool enabled ) SIP_SKIP;
672 : :
673 : : /**
674 : : * Store the password manager into the wallet
675 : : * \note Available in Python bindings since QGIS 3.8.0
676 : : */
677 : : bool passwordHelperSync();
678 : :
679 : : //! The display name of the password helper (platform dependent)
680 : : static const QString AUTH_PASSWORD_HELPER_DISPLAY_NAME;
681 : :
682 : : //! The display name of the Authentication Manager
683 : : static const QString AUTH_MAN_TAG;
684 : :
685 : : signals:
686 : :
687 : : /**
688 : : * Signals emitted on password helper failure,
689 : : * mainly used in the tests to exit main application loop
690 : : */
691 : : void passwordHelperFailure();
692 : :
693 : : /**
694 : : * Signals emitted on password helper success,
695 : : * mainly used in the tests to exit main application loop
696 : : */
697 : : void passwordHelperSuccess();
698 : :
699 : : /**
700 : : * Custom logging signal to relay to console output and QgsMessageLog
701 : : * \param message Message to send
702 : : * \param tag Associated tag (title)
703 : : * \param level Message log level
704 : : * \see QgsMessageLog
705 : : */
706 : : void messageOut( const QString &message, const QString &tag = QgsAuthManager::AUTH_MAN_TAG, QgsAuthManager::MessageLevel level = QgsAuthManager::INFO ) const;
707 : :
708 : : /**
709 : : * Custom logging signal to inform the user about master password <-> password manager interactions
710 : : * \param message Message to send
711 : : * \param tag Associated tag (title)
712 : : * \param level Message log level
713 : : * \see QgsMessageLog
714 : : */
715 : : void passwordHelperMessageOut( const QString &message, const QString &tag = QgsAuthManager::AUTH_MAN_TAG, QgsAuthManager::MessageLevel level = QgsAuthManager::INFO );
716 : :
717 : :
718 : : /**
719 : : * Emitted when a password has been verify (or not)
720 : : * \param verified The state of password's verification
721 : : */
722 : : void masterPasswordVerified( bool verified );
723 : :
724 : : //! Emitted when a user has indicated they may want to erase the authentication db.
725 : : void authDatabaseEraseRequested();
726 : :
727 : : //! Emitted when the authentication db is significantly changed, e.g. large record removal, erased, etc.
728 : : void authDatabaseChanged();
729 : :
730 : : public slots:
731 : : //! Clear all authentication configs from authentication method caches
732 : : void clearAllCachedConfigs();
733 : :
734 : : //! Clear an authentication config from its associated authentication method cache
735 : : void clearCachedConfig( const QString &authcfg );
736 : :
737 : : private slots:
738 : : void writeToConsole( const QString &message, const QString &tag = QString(), QgsAuthManager::MessageLevel level = INFO );
739 : :
740 : : /**
741 : : * This slot emits the authDatabaseEraseRequested signal, instead of attempting
742 : : * the erase. It relies upon a slot connected to the signal in calling application
743 : : * (the one that initiated the erase) to initiate the erase, when it is ready.
744 : : * Upon activation, a receiving slot should get confimation from the user, then
745 : : * IMMEDIATELY call setScheduledAuthDatabaseErase( FALSE ) to stop the scheduling timer.
746 : : * If receiving slot is NOT ready to initiate the erase, e.g. project is still loading,
747 : : * it can skip the confirmation and request another signal emit from the scheduling timer.
748 : : */
749 : : void tryToStartDbErase();
750 : :
751 : : protected:
752 : :
753 : : /**
754 : : * Enforce singleton pattern
755 : : * \note To set up the manager instance and initialize everything use QgsAuthManager::instance()->init()
756 : : */
757 : : static QgsAuthManager *instance() SIP_SKIP;
758 : :
759 : :
760 : : #ifdef Q_OS_WIN
761 : : public:
762 : : explicit QgsAuthManager() SIP_SKIP;
763 : : #else
764 : : protected:
765 : : explicit QgsAuthManager() SIP_SKIP;
766 : : #endif
767 : :
768 : : private:
769 : :
770 : : //////////////////////////////////////////////////////////////////////////////
771 : : // Password Helper methods
772 : :
773 : : //! Returns the name for logging
774 : : QString passwordHelperName() const;
775 : :
776 : : //! Print a debug message in QGIS
777 : : void passwordHelperLog( const QString &msg ) const;
778 : :
779 : : //! Read Master password from the wallet
780 : : QString passwordHelperRead();
781 : :
782 : : //! Store Master password in the wallet
783 : : bool passwordHelperWrite( const QString &password );
784 : :
785 : : //! Error message setter
786 : : void passwordHelperSetErrorMessage( const QString &errorMessage ) { mPasswordHelperErrorMessage = errorMessage; }
787 : :
788 : : //! Clear error code and message
789 : : void passwordHelperClearErrors();
790 : :
791 : : /**
792 : : * Process the error: show it and/or disable the password helper system in case of
793 : : * access denied or no backend, reset error flags at the end
794 : : */
795 : : void passwordHelperProcessError();
796 : :
797 : : bool createConfigTables();
798 : :
799 : : bool createCertTables();
800 : :
801 : : bool masterPasswordInput();
802 : :
803 : : bool masterPasswordRowsInDb( int *rows ) const;
804 : :
805 : : bool masterPasswordCheckAgainstDb( const QString &compare = QString() ) const;
806 : :
807 : : bool masterPasswordStoreInDb() const;
808 : :
809 : : bool masterPasswordClearDb();
810 : :
811 : : const QString masterPasswordCiv() const;
812 : :
813 : : bool verifyPasswordCanDecryptConfigs() const;
814 : :
815 : : bool reencryptAllAuthenticationConfigs( const QString &prevpass, const QString &prevciv );
816 : :
817 : : bool reencryptAuthenticationConfig( const QString &authcfg, const QString &prevpass, const QString &prevciv );
818 : :
819 : : bool reencryptAllAuthenticationSettings( const QString &prevpass, const QString &prevciv );
820 : :
821 : : bool reencryptAllAuthenticationIdentities( const QString &prevpass, const QString &prevciv );
822 : :
823 : : bool reencryptAuthenticationIdentity( const QString &identid, const QString &prevpass, const QString &prevciv );
824 : :
825 : : bool authDbOpen() const;
826 : :
827 : : bool authDbQuery( QSqlQuery *query ) const;
828 : :
829 : : bool authDbStartTransaction() const;
830 : :
831 : : bool authDbCommit() const;
832 : :
833 : : bool authDbTransactionQuery( QSqlQuery *query ) const;
834 : :
835 : : #ifndef QT_NO_SSL
836 : : void insertCaCertInCache( QgsAuthCertUtils::CaCertSource source, const QList<QSslCertificate> &certs );
837 : : #endif
838 : :
839 : 0 : const QString authDbPassTable() const { return AUTH_PASS_TABLE; }
840 : :
841 : 0 : const QString authDbSettingsTable() const { return AUTH_SETTINGS_TABLE; }
842 : :
843 : 0 : const QString authDbIdentitiesTable() const { return AUTH_IDENTITIES_TABLE; }
844 : :
845 : 0 : const QString authDbAuthoritiesTable() const { return AUTH_AUTHORITIES_TABLE; }
846 : :
847 : 0 : const QString authDbTrustTable() const { return AUTH_TRUST_TABLE; }
848 : :
849 : : static QgsAuthManager *sInstance;
850 : : static const QString AUTH_CONFIG_TABLE;
851 : : static const QString AUTH_PASS_TABLE;
852 : : static const QString AUTH_SETTINGS_TABLE;
853 : : static const QString AUTH_IDENTITIES_TABLE;
854 : : static const QString AUTH_SERVERS_TABLE;
855 : : static const QString AUTH_AUTHORITIES_TABLE;
856 : : static const QString AUTH_TRUST_TABLE;
857 : : static const QString AUTH_CFG_REGEX;
858 : :
859 : : bool mAuthInit = false;
860 : : QString mAuthDbPath;
861 : :
862 : : std::unique_ptr<QCA::Initializer> mQcaInitializer;
863 : :
864 : : QHash<QString, QString> mConfigAuthMethods;
865 : : QHash<QString, QgsAuthMethod *> mAuthMethods;
866 : :
867 : : QString mMasterPass;
868 : : int mPassTries = 0;
869 : : bool mAuthDisabled = false;
870 : : QString mAuthDisabledMessage;
871 : : QTimer *mScheduledDbEraseTimer = nullptr;
872 : : bool mScheduledDbErase = false;
873 : : int mScheduledDbEraseRequestWait = 3 ; // in seconds
874 : : bool mScheduledDbEraseRequestEmitted = false;
875 : : int mScheduledDbEraseRequestCount = 0;
876 : :
877 : : #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
878 : : std::unique_ptr<QMutex> mMutex;
879 : : std::unique_ptr<QMutex> mMasterPasswordMutex;
880 : : #else
881 : : std::unique_ptr<QRecursiveMutex> mMutex;
882 : : std::unique_ptr<QRecursiveMutex> mMasterPasswordMutex;
883 : : #endif
884 : : #ifndef QT_NO_SSL
885 : : // mapping of sha1 digest and cert source and cert
886 : : // appending removes duplicates
887 : : QMap<QString, QPair<QgsAuthCertUtils::CaCertSource, QSslCertificate> > mCaCertsCache;
888 : : // list of sha1 digests per policy
889 : : QMap<QgsAuthCertUtils::CertTrustPolicy, QStringList > mCertTrustCache;
890 : : // cache of certs ready to be utilized in network connections
891 : : QList<QSslCertificate> mTrustedCaCertsCache;
892 : : // cache of SSL errors to be ignored in network connections, per sha-hostport
893 : : QHash<QString, QSet<QSslError::SslError> > mIgnoredSslErrorsCache;
894 : :
895 : : bool mHasCustomConfigByHost = false;
896 : : bool mHasCheckedIfCustomConfigByHostExists = false;
897 : : QMap< QString, QgsAuthConfigSslServer > mCustomConfigByHostCache;
898 : : #endif
899 : :
900 : : //////////////////////////////////////////////////////////////////////////////
901 : : // Password Helper Variables
902 : :
903 : : //! Master password verification has failed
904 : : bool mPasswordHelperVerificationError = false;
905 : :
906 : : //! Store last error message
907 : : QString mPasswordHelperErrorMessage;
908 : :
909 : : //! Store last error code (enum)
910 : : QKeychain::Error mPasswordHelperErrorCode = QKeychain::NoError;
911 : :
912 : : //! Enable logging
913 : : bool mPasswordHelperLoggingEnabled = false;
914 : :
915 : : //! Whether the keychain bridge failed to initialize
916 : : bool mPasswordHelperFailedInit = false;
917 : :
918 : : //! Master password name in the wallets
919 : : static const QLatin1String AUTH_PASSWORD_HELPER_KEY_NAME;
920 : :
921 : : //! password helper folder in the wallets
922 : : static const QLatin1String AUTH_PASSWORD_HELPER_FOLDER_NAME;
923 : :
924 : : mutable QMap<QThread *, QMetaObject::Connection> mConnectedThreads;
925 : :
926 : : friend class QgsApplication;
927 : :
928 : : };
929 : :
930 : : #endif // QGSAUTHMANAGER_H
|