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     ~ProxyAuthHandler() override;
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