1 | /* |
2 | * Copyright (C) 2015 by Christian Kamm <kamm@incasoftware.de> |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by |
6 | * the Free Software Foundation; either version 2 of the License, or |
7 | * (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, but |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * for more details. |
13 | */ |
14 | |
15 | #pragma once |
16 | |
17 | #include "owncloudgui.h" |
18 | #include <QObject> |
19 | #include <QString> |
20 | #include <QNetworkProxy> |
21 | #include <QAuthenticator> |
22 | #include <QPointer> |
23 | #include <QScopedPointer> |
24 | #include <QSettings> |
25 | #include <QSet> |
26 | |
27 | namespace QKeychain { |
28 | class Job; |
29 | class ReadPasswordJob; |
30 | } |
31 | |
32 | namespace OCC { |
33 | |
34 | class ConfigFile; |
35 | class ProxyAuthDialog; |
36 | |
37 | /** |
38 | * @brief Handle proxyAuthenticationRequired signals from our QNetworkAccessManagers. |
39 | * |
40 | * The main complication here is that the slot needs to return credential information |
41 | * synchronously - but running a dialog or getting password data from synchronous |
42 | * storage are asynchronous operations. This leads to reentrant calls that are |
43 | * fairly complicated to handle. |
44 | */ |
45 | class ProxyAuthHandler : public QObject |
46 | { |
47 | Q_OBJECT |
48 | |
49 | public: |
50 | static ProxyAuthHandler *instance(); |
51 | |
52 | virtual ~ProxyAuthHandler(); |
53 | |
54 | public slots: |
55 | /// Intended for QNetworkAccessManager::proxyAuthenticationRequired() |
56 | void handleProxyAuthenticationRequired(const QNetworkProxy &proxy, |
57 | QAuthenticator *authenticator); |
58 | |
59 | private slots: |
60 | void slotKeychainJobDone(); |
61 | void slotSenderDestroyed(QObject *); |
62 | |
63 | private: |
64 | ProxyAuthHandler(); |
65 | |
66 | /// Runs the ProxyAuthDialog and returns true if new credentials were entered. |
67 | bool getCredsFromDialog(); |
68 | |
69 | /// Checks the keychain for credentials of the current proxy. |
70 | bool getCredsFromKeychain(); |
71 | |
72 | /// Stores the current credentials in the keychain. |
73 | void storeCredsInKeychain(); |
74 | |
75 | QString keychainUsernameKey() const; |
76 | QString keychainPasswordKey() const; |
77 | |
78 | /// The hostname:port of the current proxy, used for detecting switches |
79 | /// to a different proxy. |
80 | QString _proxy; |
81 | |
82 | QString _username; |
83 | QString _password; |
84 | |
85 | /// If the user cancels the credential dialog, blocked will be set to |
86 | /// true and we won't bother him again. |
87 | bool _blocked; |
88 | |
89 | /// In several instances handleProxyAuthenticationRequired() can be called |
90 | /// while it is still running. These counters detect what we're currently |
91 | /// waiting for. |
92 | int _waitingForDialog; |
93 | int _waitingForKeychain; |
94 | bool _keychainJobRunning; |
95 | |
96 | QPointer<ProxyAuthDialog> _dialog; |
97 | |
98 | /// The QSettings instance to securely store username/password in the keychain. |
99 | QScopedPointer<QSettings> _settings; |
100 | |
101 | /// Pointer to the most-recently-run ReadPasswordJob, needed due to reentrancy. |
102 | QScopedPointer<QKeychain::ReadPasswordJob> _readPasswordJob; |
103 | |
104 | /// For checking the proxy config settings. |
105 | QScopedPointer<ConfigFile> _configFile; |
106 | |
107 | /// To distinguish between a new QNAM asking for credentials and credentials |
108 | /// failing for an existing QNAM, we keep track of the senders of the |
109 | /// proxyAuthRequired signal here. |
110 | QSet<QObject *> _gaveCredentialsTo; |
111 | }; |
112 | |
113 | } // namespace OCC |
114 | |