1/*
2 * Copyright (C) by Klaas Freitag <freitag@kde.org>
3 * Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16#ifndef MIRALL_CREDS_HTTP_CREDENTIALS_H
17#define MIRALL_CREDS_HTTP_CREDENTIALS_H
18
19#include <QMap>
20#include <QSslCertificate>
21#include <QSslKey>
22#include <QNetworkRequest>
23#include "creds/abstractcredentials.h"
24
25class QNetworkReply;
26class QAuthenticator;
27
28namespace QKeychain {
29class Job;
30class WritePasswordJob;
31class ReadPasswordJob;
32}
33
34namespace OCC {
35
36/*
37 The authentication system is this way because of Shibboleth.
38 There used to be two different ways to authenticate: Shibboleth and HTTP Basic Auth.
39 AbstractCredentials can be inherited from both ShibbolethCrendentials and HttpCredentials.
40
41 HttpCredentials is then split in HttpCredentials and HttpCredentialsGui.
42
43 This class handle both HTTP Basic Auth and OAuth. But anything that needs GUI to ask the user
44 is in HttpCredentialsGui.
45
46 The authentication mechanism looks like this.
47
48 1) First, AccountState will attempt to load the certificate from the keychain
49
50 ----> fetchFromKeychain
51 | }
52 v }
53 slotReadClientCertPEMJobDone } There are first 3 QtKeychain jobs to fetch
54 | } the TLS client keys, if any, and the password
55 v } (or refresh token
56 slotReadClientKeyPEMJobDone }
57 | }
58 v
59 slotReadJobDone
60 | |
61 | +-------> emit fetched() if OAuth is not used
62 |
63 v
64 refreshAccessToken()
65 |
66 v
67 emit fetched()
68
69 2) If the credentials is still not valid when fetched() is emitted, the ui, will call askFromUser()
70 which is implemented in HttpCredentialsGui
71
72 */
73class OWNCLOUDSYNC_EXPORT HttpCredentials : public AbstractCredentials
74{
75 Q_OBJECT
76 friend class HttpCredentialsAccessManager;
77
78public:
79 /// Don't add credentials if this is set on a QNetworkRequest
80 static constexpr QNetworkRequest::Attribute DontAddCredentialsAttribute = QNetworkRequest::User;
81
82 explicit HttpCredentials();
83 HttpCredentials(const QString &user, const QString &password, const QSslCertificate &certificate = QSslCertificate(), const QSslKey &key = QSslKey());
84
85 QString authType() const Q_DECL_OVERRIDE;
86 QNetworkAccessManager *createQNAM() const Q_DECL_OVERRIDE;
87 bool ready() const Q_DECL_OVERRIDE;
88 void fetchFromKeychain() Q_DECL_OVERRIDE;
89 bool stillValid(QNetworkReply *reply) Q_DECL_OVERRIDE;
90 void persist() Q_DECL_OVERRIDE;
91 QString user() const Q_DECL_OVERRIDE;
92 // the password or token
93 QString password() const;
94 void invalidateToken() Q_DECL_OVERRIDE;
95 void forgetSensitiveData() Q_DECL_OVERRIDE;
96 QString fetchUser();
97 virtual bool sslIsTrusted() { return false; }
98
99 /* If we still have a valid refresh token, try to refresh it assynchronously and emit fetched()
100 * otherwise return false
101 */
102 bool refreshAccessToken();
103
104 // To fetch the user name as early as possible
105 void setAccount(Account *account) Q_DECL_OVERRIDE;
106
107 // Whether we are using OAuth
108 bool isUsingOAuth() const { return !_refreshToken.isNull(); }
109
110private Q_SLOTS:
111 void slotAuthentication(QNetworkReply *, QAuthenticator *);
112
113 void slotReadClientCertPEMJobDone(QKeychain::Job *);
114 void slotReadClientKeyPEMJobDone(QKeychain::Job *);
115 void slotReadJobDone(QKeychain::Job *);
116
117 void slotWriteClientCertPEMJobDone();
118 void slotWriteClientKeyPEMJobDone();
119 void slotWriteJobDone(QKeychain::Job *);
120
121protected:
122 /** Reads data from keychain locations
123 *
124 * Goes through
125 * slotReadClientCertPEMJobDone to
126 * slotReadClientCertPEMJobDone to
127 * slotReadJobDone
128 */
129 void fetchFromKeychainHelper();
130
131 /// Wipes legacy keychain locations
132 void deleteOldKeychainEntries();
133
134 QString _user;
135 QString _password; // user's password, or access_token for OAuth
136 QString _refreshToken; // OAuth _refreshToken, set if OAuth is used.
137 QString _previousPassword;
138
139 QString _fetchErrorString;
140 bool _ready;
141 QSslKey _clientSslKey;
142 QSslCertificate _clientSslCertificate;
143 bool _keychainMigration;
144 bool _retryOnKeyChainError = true; // true if we haven't done yet any reading from keychain
145};
146
147
148} // namespace OCC
149
150#endif
151