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
27namespace QKeychain {
28class Job;
29class ReadPasswordJob;
30}
31
32namespace OCC {
33
34class ConfigFile;
35class 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 */
45class ProxyAuthHandler : public QObject
46{
47 Q_OBJECT
48
49public:
50 static ProxyAuthHandler *instance();
51
52 virtual ~ProxyAuthHandler();
53
54public slots:
55 /// Intended for QNetworkAccessManager::proxyAuthenticationRequired()
56 void handleProxyAuthenticationRequired(const QNetworkProxy &proxy,
57 QAuthenticator *authenticator);
58
59private slots:
60 void slotKeychainJobDone();
61 void slotSenderDestroyed(QObject *);
62
63private:
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