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 | |
25 | class QNetworkReply; |
26 | class QAuthenticator; |
27 | |
28 | namespace QKeychain { |
29 | class Job; |
30 | class WritePasswordJob; |
31 | class ReadPasswordJob; |
32 | } |
33 | |
34 | namespace 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 | */ |
73 | class OWNCLOUDSYNC_EXPORT HttpCredentials : public AbstractCredentials |
74 | { |
75 | Q_OBJECT |
76 | friend class HttpCredentialsAccessManager; |
77 | |
78 | public: |
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 | |
110 | private 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 | |
121 | protected: |
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 | |