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