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 slotSenderDestroyed(QObject *);
61 
62 private:
63     ProxyAuthHandler();
64 
65     /// Runs the ProxyAuthDialog and returns true if new credentials were entered.
66     bool getCredsFromDialog();
67 
68     /// Checks the keychain for credentials of the current proxy.
69     bool getCredsFromKeychain();
70 
71     /// Stores the current credentials in the keychain.
72     void storeCredsInKeychain();
73 
74     template<class T, typename PointerToMemberFunction>
75     void execAwait(const T *sender,
76                    PointerToMemberFunction signal,
77                    int &counter,
78                    const QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents);
79 
80     QString keychainUsernameKey() const;
81     QString keychainPasswordKey() const;
82 
83     /// The hostname:port of the current proxy, used for detecting switches
84     /// to a different proxy.
85     QString _proxy;
86 
87     QString _username;
88     QString _password;
89 
90     /// If the user cancels the credential dialog, blocked will be set to
91     /// true and we won't bother him again.
92     bool _blocked = false;
93 
94     /// In several instances handleProxyAuthenticationRequired() can be called
95     /// while it is still running. These counters detect what we're currently
96     /// waiting for.
97     int _waitingForDialog = 0;
98     int _waitingForKeychain = 0;
99 
100     QPointer<ProxyAuthDialog> _dialog;
101 
102     /// The QSettings instance to securely store username/password in the keychain.
103     QScopedPointer<QSettings> _settings;
104 
105     /// Pointer to the most-recently-run ReadPasswordJob, needed due to reentrancy.
106     QScopedPointer<QKeychain::ReadPasswordJob> _readPasswordJob;
107 
108     /// For checking the proxy config settings.
109     QScopedPointer<ConfigFile> _configFile;
110 
111     /// To distinguish between a new QNAM asking for credentials and credentials
112     /// failing for an existing QNAM, we keep track of the senders of the
113     /// proxyAuthRequired signal here.
114     QSet<QObject *> _gaveCredentialsTo;
115 };
116 
117 } // namespace OCC
118