17
17
#include < QDebug>
18
18
#include < QNetworkReply>
19
19
#include < QSettings>
20
+ #include < QSslKey>
20
21
21
22
#include < keychain.h>
22
23
@@ -36,8 +37,8 @@ namespace OCC
36
37
namespace
37
38
{
38
39
const char userC[] = " user" ;
39
- const char certifPathC [] = " certificatePath " ;
40
- const char certifPasswdC [] = " certificatePasswd " ;
40
+ const char clientCertificatePEMC [] = " _clientCertificatePEM " ;
41
+ const char clientKeyPEMC [] = " _clientKeyPEM " ;
41
42
const char authenticationFailedC[] = " owncloud-authentication-failed" ;
42
43
} // ns
43
44
@@ -50,24 +51,47 @@ class HttpCredentialsAccessManager : public AccessManager {
50
51
QByteArray credHash = QByteArray (_cred->user ().toUtf8 ()+" :" +_cred->password ().toUtf8 ()).toBase64 ();
51
52
QNetworkRequest req (request);
52
53
req.setRawHeader (QByteArray (" Authorization" ), QByteArray (" Basic " ) + credHash);
53
- // qDebug() << "Request for " << req.url() << "with authorization" << QByteArray::fromBase64(credHash);
54
+ // qDebug() << "Request for " << req.url() << "with authorization"
55
+ // << QByteArray::fromBase64(credHash)
56
+ // << _cred->_clientSslKey << _cred->_clientSslCertificate
57
+ // << _cred->_clientSslKey.isNull() << _cred->_clientSslCertificate.isNull();
58
+
59
+ if (!_cred->_clientSslKey .isNull () && !_cred->_clientSslCertificate .isNull ()) {
60
+ // SSL configuration
61
+ QSslConfiguration sslConfiguration = req.sslConfiguration ();
62
+ sslConfiguration.setLocalCertificate (_cred->_clientSslCertificate );
63
+ sslConfiguration.setPrivateKey (_cred->_clientSslKey );
64
+ req.setSslConfiguration (sslConfiguration);
65
+ }
66
+
67
+
54
68
return AccessManager::createRequest (op, req, outgoingData);
55
69
}
56
70
private:
57
71
const HttpCredentials *_cred;
58
72
};
59
73
74
+
75
+ static void addSettingsToJob (Account *account, QKeychain::Job *job)
76
+ {
77
+ Q_UNUSED (account);
78
+ auto settings = Utility::settingsWithGroup (Theme::instance ()->appName ());
79
+ settings->setParent (job); // make the job parent to make setting deleted properly
80
+ job->setSettings (settings.release ());
81
+ }
82
+
60
83
HttpCredentials::HttpCredentials ()
61
84
: _ready(false )
62
85
{
63
86
}
64
87
65
- HttpCredentials::HttpCredentials (const QString& user, const QString& password, const QString& certificatePath, const QString& certificatePasswd)
88
+ // From wizard
89
+ HttpCredentials::HttpCredentials (const QString& user, const QString& password, const QSslCertificate& certificate, const QSslKey& key)
66
90
: _user(user),
67
91
_password (password),
68
92
_ready(true ),
69
- _certificatePath(certificatePath ),
70
- _certificatePasswd(certificatePasswd )
93
+ _clientSslKey(key ),
94
+ _clientSslCertificate(certificate )
71
95
{
72
96
}
73
97
@@ -86,16 +110,6 @@ QString HttpCredentials::password() const
86
110
return _password;
87
111
}
88
112
89
- QString HttpCredentials::certificatePath () const
90
- {
91
- return _certificatePath;
92
- }
93
-
94
- QString HttpCredentials::certificatePasswd () const
95
- {
96
- return _certificatePasswd;
97
- }
98
-
99
113
void HttpCredentials::setAccount (Account* account)
100
114
{
101
115
AbstractCredentials::setAccount (account);
@@ -129,35 +143,83 @@ void HttpCredentials::fetchFromKeychain()
129
143
{
130
144
// User must be fetched from config file
131
145
fetchUser ();
132
- _certificatePath = _account->credentialSetting (QLatin1String (certifPathC)).toString ();
133
- _certificatePasswd = _account->credentialSetting (QLatin1String (certifPasswdC)).toString ();
134
146
135
- auto settings = Utility::settingsWithGroup (Theme::instance ()->appName ());
136
147
const QString kck = keychainKey (_account->url ().toString (), _user );
137
148
138
- QString key = QString::fromLatin1 ( " %1/data" ).arg ( kck );
139
- if ( settings && settings->contains (key) ) {
140
- // Clean the password from the config file if it is in there.
141
- // we do not want a security problem.
142
- settings->remove (key);
143
- key = QString::fromLatin1 ( " %1/type" ).arg ( kck );
144
- settings->remove (key);
145
- settings->sync ();
146
- }
147
-
148
149
if (_ready) {
149
150
Q_EMIT fetched ();
150
151
} else {
152
+ // Read client cert from keychain
153
+ const QString kck = keychainKey (_account->url ().toString (), _user + clientCertificatePEMC);
151
154
ReadPasswordJob *job = new ReadPasswordJob (Theme::instance ()->appName ());
152
- settings->setParent (job); // make the job parent to make setting deleted properly
153
- job->setSettings (settings.release ());
154
-
155
+ addSettingsToJob (_account, job);
155
156
job->setInsecureFallback (false );
156
157
job->setKey (kck);
157
- connect (job, SIGNAL (finished (QKeychain::Job*)), SLOT (slotReadJobDone (QKeychain::Job*)));
158
+ qDebug () << " -------- ----->" << _clientSslCertificate << _clientSslKey;
159
+
160
+ connect (job, SIGNAL (finished (QKeychain::Job*)), SLOT (slotReadClientCertPEMJobDone (QKeychain::Job*)));
158
161
job->start ();
159
162
}
160
163
}
164
+
165
+ void HttpCredentials::slotReadClientCertPEMJobDone (QKeychain::Job* incoming)
166
+ {
167
+ // Store PEM in memory
168
+ ReadPasswordJob *readJob = static_cast <ReadPasswordJob*>(incoming);
169
+ if (readJob->error () == NoError && readJob->binaryData ().length () > 0 ) {
170
+ QList<QSslCertificate> sslCertificateList = QSslCertificate::fromData (readJob->binaryData (), QSsl::Pem);
171
+ if (sslCertificateList.length () >= 1 ) {
172
+ _clientSslCertificate = sslCertificateList.at (0 );
173
+ }
174
+ }
175
+
176
+ // Load key too
177
+ const QString kck = keychainKey (_account->url ().toString (), _user + clientKeyPEMC);
178
+ ReadPasswordJob *job = new ReadPasswordJob (Theme::instance ()->appName ());
179
+ addSettingsToJob (_account, job);
180
+ job->setInsecureFallback (false );
181
+ job->setKey (kck);
182
+
183
+ connect (job, SIGNAL (finished (QKeychain::Job*)), SLOT (slotReadClientKeyPEMJobDone (QKeychain::Job*)));
184
+ job->start ();
185
+ }
186
+
187
+ void HttpCredentials::slotReadClientKeyPEMJobDone (QKeychain::Job* incoming)
188
+ {
189
+ // Store key in memory
190
+ ReadPasswordJob *readJob = static_cast <ReadPasswordJob*>(incoming);
191
+
192
+ if (readJob->error () == NoError && readJob->binaryData ().length () > 0 ) {
193
+ QByteArray clientKeyPEM = readJob->binaryData ();
194
+ // FIXME Unfortunately Qt has a bug and we can't just use QSsl::Opaque to let it
195
+ // load whatever we have. So we try until it works.
196
+ _clientSslKey = QSslKey (clientKeyPEM, QSsl::Rsa);
197
+ if (_clientSslKey.isNull ()) {
198
+ _clientSslKey = QSslKey (clientKeyPEM, QSsl::Dsa);
199
+ }
200
+ #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
201
+ // ec keys are Qt 5.5
202
+ if (_clientSslKey.isNull ()) {
203
+ _clientSslKey = QSslKey (clientKeyPEM, QSsl::Ec);
204
+ }
205
+ #endif
206
+ if (_clientSslKey.isNull ()) {
207
+ qDebug () << " Warning: Could not load SSL key into Qt!" ;
208
+ }
209
+ }
210
+
211
+ // Now fetch the actual server password
212
+ const QString kck = keychainKey (_account->url ().toString (), _user );
213
+ ReadPasswordJob *job = new ReadPasswordJob (Theme::instance ()->appName ());
214
+ addSettingsToJob (_account, job);
215
+ job->setInsecureFallback (false );
216
+ job->setKey (kck);
217
+
218
+ connect (job, SIGNAL (finished (QKeychain::Job*)), SLOT (slotReadJobDone (QKeychain::Job*)));
219
+ job->start ();
220
+ }
221
+
222
+
161
223
bool HttpCredentials::stillValid (QNetworkReply *reply)
162
224
{
163
225
return ((reply->error () != QNetworkReply::AuthenticationRequiredError)
@@ -166,10 +228,10 @@ bool HttpCredentials::stillValid(QNetworkReply *reply)
166
228
|| !reply->property (authenticationFailedC).toBool ()));
167
229
}
168
230
169
- void HttpCredentials::slotReadJobDone (QKeychain::Job *job )
231
+ void HttpCredentials::slotReadJobDone (QKeychain::Job *incomingJob )
170
232
{
171
- ReadPasswordJob *readJob = static_cast <ReadPasswordJob*>(job );
172
- _password = readJob ->textData ();
233
+ QKeychain:: ReadPasswordJob *job = static_cast <ReadPasswordJob*>(incomingJob );
234
+ _password = job ->textData ();
173
235
174
236
if ( _user.isEmpty ()) {
175
237
qDebug () << " Strange: User is empty!" ;
@@ -178,7 +240,6 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
178
240
QKeychain::Error error = job->error ();
179
241
180
242
if ( !_password.isEmpty () && error == NoError ) {
181
-
182
243
// All cool, the keychain did not come back with error.
183
244
// Still, the password can be empty which indicates a problem and
184
245
// the password dialog has to be opened.
@@ -214,9 +275,7 @@ void HttpCredentials::invalidateToken()
214
275
}
215
276
216
277
DeletePasswordJob *job = new DeletePasswordJob (Theme::instance ()->appName ());
217
- auto settings = Utility::settingsWithGroup (Theme::instance ()->appName ());
218
- settings->setParent (job); // make the job parent to make setting deleted properly
219
- job->setSettings (settings.release ());
278
+ addSettingsToJob (_account, job);
220
279
job->setInsecureFallback (true );
221
280
job->setKey (kck);
222
281
job->start ();
@@ -261,14 +320,37 @@ void HttpCredentials::persist()
261
320
// We never connected or fetched the user, there is nothing to save.
262
321
return ;
263
322
}
323
+
264
324
_account->setCredentialSetting (QLatin1String (userC), _user);
265
- _account-> setCredentialSetting ( QLatin1String (certifPathC), _certificatePath);
266
- _account-> setCredentialSetting ( QLatin1String (certifPasswdC), _certificatePasswd);
325
+
326
+ // write cert
267
327
WritePasswordJob *job = new WritePasswordJob (Theme::instance ()->appName ());
268
- auto settings = Utility::settingsWithGroup (Theme::instance ()->appName ());
269
- settings->setParent (job); // make the job parent to make setting deleted properly
270
- job->setSettings (settings.release ());
328
+ addSettingsToJob (_account, job);
329
+ job->setInsecureFallback (false );
330
+ connect (job, SIGNAL (finished (QKeychain::Job*)), SLOT (slotWriteClientCertPEMJobDone (QKeychain::Job*)));
331
+ job->setKey (keychainKey (_account->url ().toString (), _user + clientCertificatePEMC));
332
+ job->setBinaryData (_clientSslCertificate.toPem ());
333
+ job->start ();
334
+ }
271
335
336
+ void HttpCredentials::slotWriteClientCertPEMJobDone (Job *incomingJob)
337
+ {
338
+ Q_UNUSED (incomingJob);
339
+ // write ssl key
340
+ WritePasswordJob* job = new WritePasswordJob (Theme::instance ()->appName ());
341
+ addSettingsToJob (_account, job);
342
+ job->setInsecureFallback (false );
343
+ connect (job, SIGNAL (finished (QKeychain::Job*)), SLOT (slotWriteClientKeyPEMJobDone (QKeychain::Job*)));
344
+ job->setKey (keychainKey (_account->url ().toString (), _user + clientKeyPEMC));
345
+ job->setBinaryData (_clientSslKey.toPem ());
346
+ job->start ();
347
+ }
348
+
349
+ void HttpCredentials::slotWriteClientKeyPEMJobDone (Job *incomingJob)
350
+ {
351
+ Q_UNUSED (incomingJob);
352
+ WritePasswordJob* job = new WritePasswordJob (Theme::instance ()->appName ());
353
+ addSettingsToJob (_account, job);
272
354
job->setInsecureFallback (false );
273
355
connect (job, SIGNAL (finished (QKeychain::Job*)), SLOT (slotWriteJobDone (QKeychain::Job*)));
274
356
job->setKey (keychainKey (_account->url ().toString (), _user));
0 commit comments