|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* Copyright (C) 2016 SURFnet. |
|
4
|
|
|
* |
|
5
|
|
|
* This program is free software: you can redistribute it and/or modify |
|
6
|
|
|
* it under the terms of the GNU Affero General Public License as |
|
7
|
|
|
* published by the Free Software Foundation, either version 3 of the |
|
8
|
|
|
* License, or (at your option) any later version. |
|
9
|
|
|
* |
|
10
|
|
|
* This program is distributed in the hope that it will be useful, |
|
11
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13
|
|
|
* GNU Affero General Public License for more details. |
|
14
|
|
|
* |
|
15
|
|
|
* You should have received a copy of the GNU Affero General Public License |
|
16
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
17
|
|
|
*/ |
|
18
|
|
|
|
|
19
|
|
|
namespace SURFnet\VPN\Server; |
|
20
|
|
|
|
|
21
|
|
|
use PDO; |
|
22
|
|
|
use PDOException; |
|
23
|
|
|
use SURFnet\VPN\Common\RandomInterface; |
|
24
|
|
|
|
|
25
|
|
|
class Storage |
|
26
|
|
|
{ |
|
27
|
|
|
/** @var \PDO */ |
|
28
|
|
|
private $db; |
|
29
|
|
|
|
|
30
|
|
|
/** @var \SURFnet\VPN\Common\RandomInterface */ |
|
31
|
|
|
private $random; |
|
32
|
|
|
|
|
33
|
|
|
public function __construct(PDO $db, RandomInterface $random) |
|
34
|
|
|
{ |
|
35
|
|
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
|
36
|
|
|
$this->db = $db; |
|
37
|
|
|
// enable foreign keys |
|
38
|
|
|
$this->db->query('PRAGMA foreign_keys = ON'); |
|
39
|
|
|
|
|
40
|
|
|
$this->random = $random; |
|
41
|
|
|
} |
|
42
|
|
|
|
|
43
|
|
|
public function getUsers() |
|
44
|
|
|
{ |
|
45
|
|
|
$stmt = $this->db->prepare( |
|
46
|
|
|
'SELECT external_user_id, is_disabled |
|
47
|
|
|
FROM users' |
|
48
|
|
|
); |
|
49
|
|
|
$stmt->execute(); |
|
50
|
|
|
|
|
51
|
|
|
$userList = []; |
|
52
|
|
|
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $result) { |
|
53
|
|
|
$userList[] = [ |
|
54
|
|
|
'user_id' => $result['external_user_id'], |
|
55
|
|
|
'is_disabled' => boolval($result['is_disabled']), |
|
56
|
|
|
]; |
|
57
|
|
|
} |
|
58
|
|
|
|
|
59
|
|
|
return $userList; |
|
60
|
|
|
} |
|
61
|
|
|
|
|
62
|
|
View Code Duplication |
public function getUserCertificateInfo($commonName) |
|
|
|
|
|
|
63
|
|
|
{ |
|
64
|
|
|
$stmt = $this->db->prepare( |
|
65
|
|
|
'SELECT |
|
66
|
|
|
u.external_user_id AS user_id, |
|
67
|
|
|
u.is_disabled AS user_is_disabled, |
|
68
|
|
|
c.display_name AS display_name, |
|
69
|
|
|
c.is_disabled AS certificate_is_disabled |
|
70
|
|
|
FROM |
|
71
|
|
|
users u, certificates c |
|
72
|
|
|
WHERE |
|
73
|
|
|
u.user_id = c.user_id AND |
|
74
|
|
|
c.common_name = :common_name' |
|
75
|
|
|
); |
|
76
|
|
|
|
|
77
|
|
|
$stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR); |
|
78
|
|
|
$stmt->execute(); |
|
79
|
|
|
|
|
80
|
|
|
return $stmt->fetch(PDO::FETCH_ASSOC); |
|
81
|
|
|
} |
|
82
|
|
|
|
|
83
|
|
|
private function getInternalUserId($externalUserId) |
|
84
|
|
|
{ |
|
85
|
|
|
$stmt = $this->db->prepare( |
|
86
|
|
|
'SELECT user_id |
|
87
|
|
|
FROM users |
|
88
|
|
|
WHERE external_user_id = :external_user_id' |
|
89
|
|
|
); |
|
90
|
|
|
$stmt->bindValue(':external_user_id', $externalUserId, PDO::PARAM_STR); |
|
91
|
|
|
$stmt->execute(); |
|
92
|
|
|
|
|
93
|
|
|
if (false !== $result = $stmt->fetch(PDO::FETCH_ASSOC)) { |
|
94
|
|
|
return $result['user_id']; |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
|
|
// user does not exist yet, add it |
|
98
|
|
|
$stmt = $this->db->prepare( |
|
99
|
|
|
'INSERT INTO users (external_user_id, user_id) VALUES(:external_user_id, :user_id)' |
|
100
|
|
|
); |
|
101
|
|
|
|
|
102
|
|
|
$userId = $this->random->get(16); |
|
103
|
|
|
$stmt->bindValue(':user_id', $userId, PDO::PARAM_STR); |
|
104
|
|
|
$stmt->bindValue(':external_user_id', $externalUserId, PDO::PARAM_STR); |
|
105
|
|
|
$stmt->execute(); |
|
106
|
|
|
|
|
107
|
|
|
return $userId; |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
View Code Duplication |
public function getVootToken($externalUserId) |
|
|
|
|
|
|
111
|
|
|
{ |
|
112
|
|
|
$userId = $this->getInternalUserId($externalUserId); |
|
113
|
|
|
$stmt = $this->db->prepare( |
|
114
|
|
|
'SELECT voot_token |
|
115
|
|
|
FROM voot_tokens |
|
116
|
|
|
WHERE user_id = :user_id' |
|
117
|
|
|
); |
|
118
|
|
|
$stmt->bindValue(':user_id', $userId, PDO::PARAM_STR); |
|
119
|
|
|
$stmt->execute(); |
|
120
|
|
|
|
|
121
|
|
|
return $stmt->fetchColumn(); |
|
122
|
|
|
} |
|
123
|
|
|
|
|
124
|
|
View Code Duplication |
public function setVootToken($externalUserId, $vootToken) |
|
|
|
|
|
|
125
|
|
|
{ |
|
126
|
|
|
$userId = $this->getInternalUserId($externalUserId); |
|
127
|
|
|
$stmt = $this->db->prepare( |
|
128
|
|
|
'INSERT INTO voot_tokens (user_id, voot_token) VALUES(:user_id, :voot_token)' |
|
129
|
|
|
); |
|
130
|
|
|
$stmt->bindValue(':user_id', $userId, PDO::PARAM_STR); |
|
131
|
|
|
$stmt->bindValue(':voot_token', $vootToken, PDO::PARAM_STR); |
|
132
|
|
|
|
|
133
|
|
|
$stmt->execute(); |
|
134
|
|
|
|
|
135
|
|
|
return 1 === $stmt->rowCount(); |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
|
View Code Duplication |
public function hasVootToken($externalUserId) |
|
|
|
|
|
|
139
|
|
|
{ |
|
140
|
|
|
$userId = $this->getInternalUserId($externalUserId); |
|
141
|
|
|
$stmt = $this->db->prepare( |
|
142
|
|
|
'SELECT COUNT(*) |
|
143
|
|
|
FROM voot_tokens |
|
144
|
|
|
WHERE user_id = :user_id' |
|
145
|
|
|
); |
|
146
|
|
|
$stmt->bindValue(':user_id', $userId, PDO::PARAM_STR); |
|
147
|
|
|
$stmt->execute(); |
|
148
|
|
|
|
|
149
|
|
|
return 1 === intval($stmt->fetchColumn()); |
|
150
|
|
|
} |
|
151
|
|
|
|
|
152
|
|
View Code Duplication |
public function deleteVootToken($externalUserId) |
|
|
|
|
|
|
153
|
|
|
{ |
|
154
|
|
|
$userId = $this->getInternalUserId($externalUserId); |
|
155
|
|
|
$stmt = $this->db->prepare( |
|
156
|
|
|
'DELETE FROM voot_tokens WHERE user_id = :user_id' |
|
157
|
|
|
); |
|
158
|
|
|
$stmt->bindValue(':user_id', $userId, PDO::PARAM_STR); |
|
159
|
|
|
|
|
160
|
|
|
$stmt->execute(); |
|
161
|
|
|
|
|
162
|
|
|
return 1 === $stmt->rowCount(); |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
View Code Duplication |
public function hasTotpSecret($externalUserId) |
|
|
|
|
|
|
166
|
|
|
{ |
|
167
|
|
|
$userId = $this->getInternalUserId($externalUserId); |
|
168
|
|
|
$stmt = $this->db->prepare( |
|
169
|
|
|
'SELECT COUNT(*) |
|
170
|
|
|
FROM totp_secrets |
|
171
|
|
|
WHERE user_id = :user_id' |
|
172
|
|
|
); |
|
173
|
|
|
$stmt->bindValue(':user_id', $userId, PDO::PARAM_STR); |
|
174
|
|
|
$stmt->execute(); |
|
175
|
|
|
|
|
176
|
|
|
return 1 === intval($stmt->fetchColumn()); |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
View Code Duplication |
public function getTotpSecret($externalUserId) |
|
|
|
|
|
|
180
|
|
|
{ |
|
181
|
|
|
$userId = $this->getInternalUserId($externalUserId); |
|
182
|
|
|
$stmt = $this->db->prepare( |
|
183
|
|
|
'SELECT totp_secret |
|
184
|
|
|
FROM totp_secrets |
|
185
|
|
|
WHERE user_id = :user_id' |
|
186
|
|
|
); |
|
187
|
|
|
$stmt->bindValue(':user_id', $userId, PDO::PARAM_STR); |
|
188
|
|
|
$stmt->execute(); |
|
189
|
|
|
|
|
190
|
|
|
return $stmt->fetchColumn(); |
|
191
|
|
|
} |
|
192
|
|
|
|
|
193
|
|
View Code Duplication |
public function setTotpSecret($externalUserId, $totpSecret) |
|
|
|
|
|
|
194
|
|
|
{ |
|
195
|
|
|
$userId = $this->getInternalUserId($externalUserId); |
|
196
|
|
|
$stmt = $this->db->prepare( |
|
197
|
|
|
'INSERT INTO totp_secrets (user_id, totp_secret) VALUES(:user_id, :totp_secret)' |
|
198
|
|
|
); |
|
199
|
|
|
$stmt->bindValue(':user_id', $userId, PDO::PARAM_STR); |
|
200
|
|
|
$stmt->bindValue(':totp_secret', $totpSecret, PDO::PARAM_STR); |
|
201
|
|
|
|
|
202
|
|
|
try { |
|
203
|
|
|
$stmt->execute(); |
|
204
|
|
|
} catch (PDOException $e) { |
|
205
|
|
|
// unable to add the TOTP secret, probably uniqueness contrains |
|
206
|
|
|
return false; |
|
207
|
|
|
} |
|
208
|
|
|
|
|
209
|
|
|
return true; |
|
210
|
|
|
} |
|
211
|
|
|
|
|
212
|
|
View Code Duplication |
public function deleteTotpSecret($externalUserId) |
|
|
|
|
|
|
213
|
|
|
{ |
|
214
|
|
|
$userId = $this->getInternalUserId($externalUserId); |
|
215
|
|
|
$stmt = $this->db->prepare( |
|
216
|
|
|
'DELETE FROM totp_secrets WHERE user_id = :user_id' |
|
217
|
|
|
); |
|
218
|
|
|
$stmt->bindValue(':user_id', $userId, PDO::PARAM_STR); |
|
219
|
|
|
|
|
220
|
|
|
$stmt->execute(); |
|
221
|
|
|
|
|
222
|
|
|
return 1 === $stmt->rowCount(); |
|
223
|
|
|
} |
|
224
|
|
|
|
|
225
|
|
View Code Duplication |
public function deleteUser($externalUserId) |
|
|
|
|
|
|
226
|
|
|
{ |
|
227
|
|
|
$stmt = $this->db->prepare( |
|
228
|
|
|
'DELETE FROM users WHERE external_user_id = :external_user_id' |
|
229
|
|
|
); |
|
230
|
|
|
$stmt->bindValue(':external_user_id', $externalUserId, PDO::PARAM_STR); |
|
231
|
|
|
|
|
232
|
|
|
$stmt->execute(); |
|
233
|
|
|
|
|
234
|
|
|
return 1 === $stmt->rowCount(); |
|
235
|
|
|
} |
|
236
|
|
|
|
|
237
|
|
View Code Duplication |
public function addCertificate($externalUserId, $commonName, $displayName, $validFrom, $validTo) |
|
|
|
|
|
|
238
|
|
|
{ |
|
239
|
|
|
$userId = $this->getInternalUserId($externalUserId); |
|
240
|
|
|
$stmt = $this->db->prepare( |
|
241
|
|
|
'INSERT INTO certificates (common_name, user_id, display_name, valid_from, valid_to) VALUES(:common_name, :user_id, :display_name, :valid_from, :valid_to)' |
|
242
|
|
|
); |
|
243
|
|
|
$stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR); |
|
244
|
|
|
$stmt->bindValue(':user_id', $userId, PDO::PARAM_STR); |
|
245
|
|
|
$stmt->bindValue(':display_name', $displayName, PDO::PARAM_STR); |
|
246
|
|
|
$stmt->bindValue(':valid_from', $validFrom, PDO::PARAM_INT); |
|
247
|
|
|
$stmt->bindValue(':valid_to', $validTo, PDO::PARAM_INT); |
|
248
|
|
|
|
|
249
|
|
|
$stmt->execute(); |
|
250
|
|
|
|
|
251
|
|
|
return 1 === $stmt->rowCount(); |
|
252
|
|
|
} |
|
253
|
|
|
|
|
254
|
|
|
public function getCertificates($externalUserId) |
|
255
|
|
|
{ |
|
256
|
|
|
$userId = $this->getInternalUserId($externalUserId); |
|
257
|
|
|
$stmt = $this->db->prepare( |
|
258
|
|
|
'SELECT common_name, display_name, valid_from, valid_to, is_disabled |
|
259
|
|
|
FROM certificates |
|
260
|
|
|
WHERE user_id = :user_id' |
|
261
|
|
|
); |
|
262
|
|
|
$stmt->bindValue(':user_id', $userId, PDO::PARAM_STR); |
|
263
|
|
|
$stmt->execute(); |
|
264
|
|
|
|
|
265
|
|
|
$certificateList = []; |
|
266
|
|
|
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $result) { |
|
267
|
|
|
$certificateList[] = [ |
|
268
|
|
|
'common_name' => $result['common_name'], |
|
269
|
|
|
'display_name' => $result['display_name'], |
|
270
|
|
|
'valid_from' => intval($result['valid_from']), |
|
271
|
|
|
'valid_to' => intval($result['valid_to']), |
|
272
|
|
|
'is_disabled' => boolval($result['is_disabled']), |
|
273
|
|
|
]; |
|
274
|
|
|
} |
|
275
|
|
|
|
|
276
|
|
|
return $certificateList; |
|
277
|
|
|
} |
|
278
|
|
|
|
|
279
|
|
View Code Duplication |
public function disableCertificate($commonName) |
|
|
|
|
|
|
280
|
|
|
{ |
|
281
|
|
|
$stmt = $this->db->prepare( |
|
282
|
|
|
'UPDATE certificates SET is_disabled = 1 WHERE common_name = :common_name' |
|
283
|
|
|
); |
|
284
|
|
|
$stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR); |
|
285
|
|
|
|
|
286
|
|
|
$stmt->execute(); |
|
287
|
|
|
|
|
288
|
|
|
return 1 === $stmt->rowCount(); |
|
289
|
|
|
} |
|
290
|
|
|
|
|
291
|
|
View Code Duplication |
public function deleteCertificate($commonName) |
|
|
|
|
|
|
292
|
|
|
{ |
|
293
|
|
|
$stmt = $this->db->prepare( |
|
294
|
|
|
'DELETE FROM certificates WHERE common_name = :common_name' |
|
295
|
|
|
); |
|
296
|
|
|
$stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR); |
|
297
|
|
|
|
|
298
|
|
|
$stmt->execute(); |
|
299
|
|
|
|
|
300
|
|
|
return 1 === $stmt->rowCount(); |
|
301
|
|
|
} |
|
302
|
|
|
|
|
303
|
|
View Code Duplication |
public function enableCertificate($commonName) |
|
|
|
|
|
|
304
|
|
|
{ |
|
305
|
|
|
$stmt = $this->db->prepare( |
|
306
|
|
|
'UPDATE certificates SET is_disabled = 0 WHERE common_name = :common_name' |
|
307
|
|
|
); |
|
308
|
|
|
$stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR); |
|
309
|
|
|
|
|
310
|
|
|
$stmt->execute(); |
|
311
|
|
|
|
|
312
|
|
|
return 1 === $stmt->rowCount(); |
|
313
|
|
|
} |
|
314
|
|
|
|
|
315
|
|
View Code Duplication |
public function disableUser($externalUserId) |
|
|
|
|
|
|
316
|
|
|
{ |
|
317
|
|
|
$stmt = $this->db->prepare( |
|
318
|
|
|
'UPDATE users SET is_disabled = 1 WHERE external_user_id = :external_user_id' |
|
319
|
|
|
); |
|
320
|
|
|
$stmt->bindValue(':external_user_id', $externalUserId, PDO::PARAM_STR); |
|
321
|
|
|
|
|
322
|
|
|
$stmt->execute(); |
|
323
|
|
|
|
|
324
|
|
|
// XXX it seems on update the rowCount is always 1, even if nothing was |
|
325
|
|
|
// modified? |
|
326
|
|
|
return 1 === $stmt->rowCount(); |
|
327
|
|
|
} |
|
328
|
|
|
|
|
329
|
|
View Code Duplication |
public function enableUser($externalUserId) |
|
|
|
|
|
|
330
|
|
|
{ |
|
331
|
|
|
$stmt = $this->db->prepare( |
|
332
|
|
|
'UPDATE users SET is_disabled = 0 WHERE external_user_id = :external_user_id' |
|
333
|
|
|
); |
|
334
|
|
|
$stmt->bindValue(':external_user_id', $externalUserId, PDO::PARAM_STR); |
|
335
|
|
|
|
|
336
|
|
|
$stmt->execute(); |
|
337
|
|
|
|
|
338
|
|
|
// XXX it seems on update the rowCount is always 1, even if nothing was |
|
339
|
|
|
// modified? |
|
340
|
|
|
return 1 === $stmt->rowCount(); |
|
341
|
|
|
} |
|
342
|
|
|
|
|
343
|
|
View Code Duplication |
public function isDisabledUser($externalUserId) |
|
|
|
|
|
|
344
|
|
|
{ |
|
345
|
|
|
$stmt = $this->db->prepare( |
|
346
|
|
|
'SELECT COUNT(*) |
|
347
|
|
|
FROM users |
|
348
|
|
|
WHERE external_user_id = :external_user_id AND is_disabled = 1' |
|
349
|
|
|
); |
|
350
|
|
|
$stmt->bindValue(':external_user_id', $externalUserId, PDO::PARAM_STR); |
|
351
|
|
|
$stmt->execute(); |
|
352
|
|
|
|
|
353
|
|
|
return 1 === intval($stmt->fetchColumn()); |
|
354
|
|
|
} |
|
355
|
|
|
|
|
356
|
|
|
public function getAllLogEntries() |
|
357
|
|
|
{ |
|
358
|
|
|
$stmt = $this->db->prepare( |
|
359
|
|
|
'SELECT |
|
360
|
|
|
external_user_id AS user_id, |
|
361
|
|
|
common_name, |
|
362
|
|
|
connected_at, |
|
363
|
|
|
disconnected_at, |
|
364
|
|
|
bytes_transferred |
|
365
|
|
|
FROM |
|
366
|
|
|
connection_log |
|
367
|
|
|
WHERE |
|
368
|
|
|
disconnected_at IS NOT NULL |
|
369
|
|
|
ORDER BY |
|
370
|
|
|
connected_at' |
|
371
|
|
|
); |
|
372
|
|
|
|
|
373
|
|
|
$stmt->execute(); |
|
374
|
|
|
|
|
375
|
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC); |
|
376
|
|
|
} |
|
377
|
|
|
|
|
378
|
|
View Code Duplication |
public function clientConnect($profileId, $commonName, $ip4, $ip6, $connectedAt) |
|
|
|
|
|
|
379
|
|
|
{ |
|
380
|
|
|
$stmt = $this->db->prepare( |
|
381
|
|
|
'INSERT INTO connection_log ( |
|
382
|
|
|
external_user_id, |
|
383
|
|
|
profile_id, |
|
384
|
|
|
common_name, |
|
385
|
|
|
ip4, |
|
386
|
|
|
ip6, |
|
387
|
|
|
connected_at |
|
388
|
|
|
) |
|
389
|
|
|
VALUES( |
|
390
|
|
|
( |
|
391
|
|
|
SELECT |
|
392
|
|
|
u.external_user_id |
|
393
|
|
|
FROM |
|
394
|
|
|
users u, certificates c |
|
395
|
|
|
WHERE |
|
396
|
|
|
u.user_id = c.user_id |
|
397
|
|
|
AND |
|
398
|
|
|
c.common_name = :common_name |
|
399
|
|
|
), |
|
400
|
|
|
:profile_id, |
|
401
|
|
|
:common_name, |
|
402
|
|
|
:ip4, |
|
403
|
|
|
:ip6, |
|
404
|
|
|
:connected_at |
|
405
|
|
|
)' |
|
406
|
|
|
); |
|
407
|
|
|
|
|
408
|
|
|
$stmt->bindValue(':profile_id', $profileId, PDO::PARAM_STR); |
|
409
|
|
|
$stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR); |
|
410
|
|
|
$stmt->bindValue(':ip4', $ip4, PDO::PARAM_STR); |
|
411
|
|
|
$stmt->bindValue(':ip6', $ip6, PDO::PARAM_STR); |
|
412
|
|
|
$stmt->bindValue(':connected_at', $connectedAt, PDO::PARAM_INT); |
|
413
|
|
|
|
|
414
|
|
|
$stmt->execute(); |
|
415
|
|
|
|
|
416
|
|
|
return 1 === $stmt->rowCount(); |
|
417
|
|
|
} |
|
418
|
|
|
|
|
419
|
|
|
public function clientDisconnect($profileId, $commonName, $ip4, $ip6, $connectedAt, $disconnectedAt, $bytesTransferred) |
|
420
|
|
|
{ |
|
421
|
|
|
$stmt = $this->db->prepare( |
|
422
|
|
|
'UPDATE connection_log |
|
423
|
|
|
SET |
|
424
|
|
|
disconnected_at = :disconnected_at, |
|
425
|
|
|
bytes_transferred = :bytes_transferred |
|
426
|
|
|
WHERE |
|
427
|
|
|
profile_id = :profile_id AND |
|
428
|
|
|
common_name = :common_name AND |
|
429
|
|
|
ip4 = :ip4 AND |
|
430
|
|
|
ip6 = :ip6 AND |
|
431
|
|
|
connected_at = :connected_at |
|
432
|
|
|
' |
|
433
|
|
|
); |
|
434
|
|
|
|
|
435
|
|
|
$stmt->bindValue(':profile_id', $profileId, PDO::PARAM_STR); |
|
436
|
|
|
$stmt->bindValue(':common_name', $commonName, PDO::PARAM_STR); |
|
437
|
|
|
$stmt->bindValue(':ip4', $ip4, PDO::PARAM_STR); |
|
438
|
|
|
$stmt->bindValue(':ip6', $ip6, PDO::PARAM_STR); |
|
439
|
|
|
$stmt->bindValue(':connected_at', $connectedAt, PDO::PARAM_INT); |
|
440
|
|
|
$stmt->bindValue(':disconnected_at', $disconnectedAt, PDO::PARAM_INT); |
|
441
|
|
|
$stmt->bindValue(':bytes_transferred', $bytesTransferred, PDO::PARAM_INT); |
|
442
|
|
|
|
|
443
|
|
|
$stmt->execute(); |
|
444
|
|
|
|
|
445
|
|
|
return 1 === $stmt->rowCount(); |
|
446
|
|
|
} |
|
447
|
|
|
|
|
448
|
|
View Code Duplication |
public function getLogEntry($dateTimeUnix, $ipAddress) |
|
|
|
|
|
|
449
|
|
|
{ |
|
450
|
|
|
$stmt = $this->db->prepare( |
|
451
|
|
|
'SELECT external_user_id, profile_id, common_name, ip4, ip6, connected_at, disconnected_at |
|
452
|
|
|
FROM connection_log |
|
453
|
|
|
WHERE |
|
454
|
|
|
(ip4 = :ip_address OR ip6 = :ip_address) |
|
455
|
|
|
AND connected_at < :date_time_unix |
|
456
|
|
|
AND (disconnected_at > :date_time_unix OR disconnected_at IS NULL)' |
|
457
|
|
|
); |
|
458
|
|
|
$stmt->bindValue(':ip_address', $ipAddress, PDO::PARAM_STR); |
|
459
|
|
|
$stmt->bindValue(':date_time_unix', $dateTimeUnix, PDO::PARAM_STR); |
|
460
|
|
|
$stmt->execute(); |
|
461
|
|
|
|
|
462
|
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC); |
|
463
|
|
|
} |
|
464
|
|
|
|
|
465
|
|
View Code Duplication |
public function recordTotpKey($externalUserId, $totpKey, $timeUnix) |
|
|
|
|
|
|
466
|
|
|
{ |
|
467
|
|
|
$userId = $this->getInternalUserId($externalUserId); |
|
468
|
|
|
$stmt = $this->db->prepare( |
|
469
|
|
|
'INSERT INTO totp_log ( |
|
470
|
|
|
user_id, |
|
471
|
|
|
totp_key, |
|
472
|
|
|
time_unix |
|
473
|
|
|
) |
|
474
|
|
|
VALUES( |
|
475
|
|
|
:user_id, |
|
476
|
|
|
:totp_key, |
|
477
|
|
|
:time_unix |
|
478
|
|
|
)' |
|
479
|
|
|
); |
|
480
|
|
|
|
|
481
|
|
|
$stmt->bindValue(':user_id', $userId, PDO::PARAM_STR); |
|
482
|
|
|
$stmt->bindValue(':totp_key', $totpKey, PDO::PARAM_STR); |
|
483
|
|
|
$stmt->bindValue(':time_unix', $timeUnix, PDO::PARAM_INT); |
|
484
|
|
|
|
|
485
|
|
|
try { |
|
486
|
|
|
$stmt->execute(); |
|
487
|
|
|
} catch (PDOException $e) { |
|
488
|
|
|
// unable to record the TOTP, probably uniqueness contrains |
|
489
|
|
|
return false; |
|
490
|
|
|
} |
|
491
|
|
|
|
|
492
|
|
|
return true; |
|
493
|
|
|
} |
|
494
|
|
|
|
|
495
|
|
View Code Duplication |
public function cleanConnectionLog($timeUnix) |
|
|
|
|
|
|
496
|
|
|
{ |
|
497
|
|
|
$stmt = $this->db->prepare( |
|
498
|
|
|
sprintf( |
|
499
|
|
|
'DELETE FROM connection_log |
|
500
|
|
|
WHERE |
|
501
|
|
|
connected_at < :time_unix |
|
502
|
|
|
AND |
|
503
|
|
|
disconnected_at IS NOT NULL' |
|
504
|
|
|
) |
|
505
|
|
|
); |
|
506
|
|
|
|
|
507
|
|
|
$stmt->bindValue(':time_unix', $timeUnix, PDO::PARAM_INT); |
|
508
|
|
|
|
|
509
|
|
|
return $stmt->execute(); |
|
510
|
|
|
} |
|
511
|
|
|
|
|
512
|
|
View Code Duplication |
public function cleanTotpLog($timeUnix) |
|
|
|
|
|
|
513
|
|
|
{ |
|
514
|
|
|
$stmt = $this->db->prepare( |
|
515
|
|
|
sprintf( |
|
516
|
|
|
'DELETE FROM totp_log |
|
517
|
|
|
WHERE time_unix < :time_unix' |
|
518
|
|
|
) |
|
519
|
|
|
); |
|
520
|
|
|
|
|
521
|
|
|
$stmt->bindValue(':time_unix', $timeUnix, PDO::PARAM_INT); |
|
522
|
|
|
|
|
523
|
|
|
return $stmt->execute(); |
|
524
|
|
|
} |
|
525
|
|
|
|
|
526
|
|
|
public function motd() |
|
527
|
|
|
{ |
|
528
|
|
|
$stmt = $this->db->prepare( |
|
529
|
|
|
'SELECT motd_message FROM motd' |
|
530
|
|
|
); |
|
531
|
|
|
|
|
532
|
|
|
$stmt->execute(); |
|
533
|
|
|
|
|
534
|
|
|
return $stmt->fetchColumn(); |
|
535
|
|
|
} |
|
536
|
|
|
|
|
537
|
|
View Code Duplication |
public function setMotd($motdMessage) |
|
|
|
|
|
|
538
|
|
|
{ |
|
539
|
|
|
$this->deleteMotd(); |
|
540
|
|
|
|
|
541
|
|
|
$stmt = $this->db->prepare( |
|
542
|
|
|
'INSERT INTO motd (motd_message) VALUES(:motd_message)' |
|
543
|
|
|
); |
|
544
|
|
|
|
|
545
|
|
|
$stmt->bindValue(':motd_message', $motdMessage, PDO::PARAM_STR); |
|
546
|
|
|
$stmt->execute(); |
|
547
|
|
|
|
|
548
|
|
|
return 1 === $stmt->rowCount(); |
|
549
|
|
|
} |
|
550
|
|
|
|
|
551
|
|
|
public function deleteMotd() |
|
552
|
|
|
{ |
|
553
|
|
|
$stmt = $this->db->prepare( |
|
554
|
|
|
'DELETE FROM motd' |
|
555
|
|
|
); |
|
556
|
|
|
|
|
557
|
|
|
$stmt->execute(); |
|
558
|
|
|
|
|
559
|
|
|
return 1 === $stmt->rowCount(); |
|
560
|
|
|
} |
|
561
|
|
|
|
|
562
|
|
|
public function init() |
|
563
|
|
|
{ |
|
564
|
|
|
$queryList = [ |
|
565
|
|
|
'CREATE TABLE IF NOT EXISTS users ( |
|
566
|
|
|
user_id VARCHAR(255) PRIMARY KEY, |
|
567
|
|
|
external_user_id VARCHAR(255) UNIQUE NOT NULL, |
|
568
|
|
|
is_disabled BOOLEAN DEFAULT 0 |
|
569
|
|
|
)', |
|
570
|
|
|
'CREATE TABLE IF NOT EXISTS voot_tokens ( |
|
571
|
|
|
voot_token VARCHAR(255) NOT NULL PRIMARY KEY, |
|
572
|
|
|
user_id VARCHAR(255) UNIQUE NOT NULL REFERENCES users(user_id) ON DELETE CASCADE |
|
573
|
|
|
)', |
|
574
|
|
|
'CREATE TABLE IF NOT EXISTS totp_secrets ( |
|
575
|
|
|
totp_secret VARCHAR(255) NOT NULL PRIMARY KEY, |
|
576
|
|
|
user_id VARCHAR(255) UNIQUE NOT NULL REFERENCES users(user_id) ON DELETE CASCADE |
|
577
|
|
|
)', |
|
578
|
|
|
'CREATE TABLE IF NOT EXISTS certificates ( |
|
579
|
|
|
common_name VARCHAR(255) NOT NULL PRIMARY KEY, |
|
580
|
|
|
display_name VARCHAR(255) NOT NULL, |
|
581
|
|
|
valid_from INTEGER NOT NULL, |
|
582
|
|
|
valid_to INTEGER NOT NULL, |
|
583
|
|
|
is_disabled BOOLEAN DEFAULT 0, |
|
584
|
|
|
user_id VARCHAR(255) NOT NULL REFERENCES users(user_id) ON DELETE CASCADE |
|
585
|
|
|
)', |
|
586
|
|
|
'CREATE TABLE IF NOT EXISTS connection_log ( |
|
587
|
|
|
external_user_id VARCHAR(255) NOT NULL, |
|
588
|
|
|
common_name VARCHAR(255) NOT NULL, |
|
589
|
|
|
profile_id VARCHAR(255) NOT NULL, |
|
590
|
|
|
ip4 VARCHAR(255) NOT NULL, |
|
591
|
|
|
ip6 VARCHAR(255) NOT NULL, |
|
592
|
|
|
connected_at INTEGER NOT NULL, |
|
593
|
|
|
disconnected_at INTEGER DEFAULT NULL, |
|
594
|
|
|
bytes_transferred INTEGER DEFAULT NULL |
|
595
|
|
|
)', |
|
596
|
|
|
'CREATE TABLE IF NOT EXISTS totp_log ( |
|
597
|
|
|
totp_key VARCHAR(255) NOT NULL, |
|
598
|
|
|
time_unix INTEGER NOT NULL, |
|
599
|
|
|
user_id VARCHAR(255) NOT NULL REFERENCES users(user_id) ON DELETE CASCADE, |
|
600
|
|
|
UNIQUE(user_id, totp_key) |
|
601
|
|
|
)', |
|
602
|
|
|
'CREATE TABLE IF NOT EXISTS motd ( |
|
603
|
|
|
motd_message TEXT NOT NULL |
|
604
|
|
|
)', |
|
605
|
|
|
]; |
|
606
|
|
|
|
|
607
|
|
|
foreach ($queryList as $query) { |
|
608
|
|
|
$this->db->query($query); |
|
609
|
|
|
} |
|
610
|
|
|
} |
|
611
|
|
|
} |
|
612
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.