Passed
Push — master ( ca52c8...cf0bfa )
by Jan
12:46
created

User::isDisabled()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
/*
3
 * Copyright (C) 2020  Jan Böhmer
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 published
7
 * by the Free Software Foundation, either version 3 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,
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 <https://www.gnu.org/licenses/>.
17
 */
18
19
namespace App\Entity;
20
21
use App\Entity\Contracts\DBElementInterface;
22
use App\Repository\UserRepository;
23
use App\Validator\NoLockout;
24
use DateTime;
25
use Doctrine\ORM\Mapping as ORM;
26
use Scheb\TwoFactorBundle\Model\BackupCodeInterface;
27
use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface;
28
use Scheb\TwoFactorBundle\Model\TrustedDeviceInterface;
29
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
30
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
31
use Symfony\Component\Security\Core\User\UserInterface;
32
use Symfony\Component\Validator\Constraints as Assert;
33
34
/**
35
 * This entity describes a user that can login to the backend system (it needs an ROLE_ADMIN role however).
36
 * The login is done with the username and a user choosable password. It is possible to configure two factor authentication
37
 * methods for additional security.
38
 *
39
 * @ORM\Entity(repositoryClass=UserRepository::class)
40
 * @UniqueEntity(fields={"username"})
41
 * @NoLockout(groups={"perm_edit"})
42
 */
43
class User implements DBElementInterface, UserInterface, TwoFactorInterface, BackupCodeInterface, TrustedDeviceInterface, PasswordAuthenticatedUserInterface
44
{
45
    /**
46
     * @ORM\Id()
47
     * @ORM\GeneratedValue()
48
     * @ORM\Column(type="integer")
49
     */
50
    private $id;
51
52
    /**
53
     * @ORM\Column(type="string", length=180, unique=true)
54
     */
55
    private $username;
56
57
    /**
58
     * @var string
59
     * @ORM\Column(type="string")
60
     */
61
    private $role_description = '';
62
63
    /**
64
     * @var string
65
     * @Assert\Email()
66
     * @ORM\Column(type="string")
67
     */
68
    private $email = '';
69
70
    /**
71
     * @ORM\Column(type="json")
72
     */
73
    private $roles = ['ROLE_ADMIN'];
74
75
    /**
76
     * @ORM\Column(type="string")
77
     */
78
    private $first_name = '';
79
80
    /**
81
     * @ORM\Column(type="string")
82
     */
83
    private $last_name = '';
84
85
    /**
86
     * @var string The hashed password
87
     * @ORM\Column(type="string")
88
     */
89
    private $password;
90
91
    /**
92
     * @var string|null
93
     * @Assert\Length(min=6)
94
     */
95
    private $plain_password = null;
96
97
    /**
98
     * @ORM\Column(name="googleAuthenticatorSecret", type="string", nullable=true)
99
     */
100
    private $googleAuthenticatorSecret;
101
102
    /**
103
     * @ORM\Column(type="integer")
104
     */
105
    private $trustedVersion = 0;
106
107
    /**
108
     * @ORM\Column(type="json")
109
     */
110
    private $backupCodes = [];
111
112
    /**
113
     * @ORM\Column(type="datetime", nullable=true)
114
     */
115
    private $backupCodesDate;
116
117
    /**
118
     * @ORM\Column(type="boolean", nullable=false)
119
     * @var bool
120
     */
121
    private $disabled = false;
122
123
    /** @var bool
124
     *  @ORM\Column(type="boolean", nullable=false)
125
     */
126
    private $password_change_needed = true;
127
128
    public function getId(): ?int
129
    {
130
        return $this->id;
131
    }
132
133
    /**
134
     * The name that is used to internally identify this user. Also used as login name.
135
     * Must be unique for all users.
136
     */
137
    public function getUsername(): string
138
    {
139
        return (string) $this->username;
140
    }
141
142
    /**
143
     * Returns unique user identifier (the username)
144
     * @return string
145
     */
146
    public function getUserIdentifier(): string
147
    {
148
        return (string) $this->username;
149
    }
150
151
    /**
152
     * Sets the username for this user.
153
     *
154
     * @return $this
155
     */
156
    public function setUsername(string $username): self
157
    {
158
        $this->username = $username;
159
160
        return $this;
161
    }
162
163
    /**
164
     * Returns all roles for this user.
165
     * Every user has at least the ROLE_USER role.
166
     *
167
     * @return string[]
168
     *
169
     * @see UserInterface
170
     */
171
    public function getRoles(): array
172
    {
173
        $roles = $this->roles;
174
        // guarantee every user at least has ROLE_USER
175
        $roles[] = 'ROLE_USER';
176
177
        return array_unique($roles);
178
    }
179
180
    /**
181
     * Add the given role to this user.
182
     *
183
     * @return $this
184
     */
185
    public function addRole(string $new_role): self
186
    {
187
        $this->roles[] = $new_role;
188
        $this->roles = array_unique($this->roles);
189
190
        return $this;
191
    }
192
193
    /**
194
     * Sets all roles for this user.
195
     *
196
     * @param string[] $roles
197
     *
198
     * @return $this
199
     */
200
    public function setRoles(array $roles): self
201
    {
202
        $this->roles = $roles;
203
204
        return $this;
205
    }
206
207
    /**
208
     * Returns the (hashed) password for this user.
209
     *
210
     * @see UserInterface
211
     */
212
    public function getPassword(): string
213
    {
214
        return $this->password;
215
    }
216
217
    /**
218
     * Sets the (hashed) password for this user.
219
     * Should be generated with UserPasswordEncryptorInterface.
220
     *
221
     * @return $this
222
     */
223
    public function setPassword(string $password): self
224
    {
225
        $this->password = $password;
226
227
        return $this;
228
    }
229
230
    /**
231
     * Not used.
232
     *
233
     * @see UserInterface
234
     */
235
    public function getSalt(): ?string
236
    {
237
        // not needed when using the "bcrypt" algorithm in security.yaml
238
        return null;
239
    }
240
241
    /**
242
     * @see UserInterface
243
     */
244
    public function eraseCredentials()
245
    {
246
        // If you store any temporary, sensitive data on the user, clear it here
247
        $this->plain_password = null;
248
    }
249
250
    /**
251
     * Returns the description of what this user does or why he needs an account (the function of the user).
252
     */
253
    public function getRoleDescription(): string
254
    {
255
        return $this->role_description;
256
    }
257
258
    /**
259
     * Sets the description of what this user does or why he needs an account (the function of the user).
260
     */
261
    public function setRoleDescription(string $role_description): User
262
    {
263
        $this->role_description = $role_description;
264
265
        return $this;
266
    }
267
268
    /**
269
     * Returns the email of this user.
270
     */
271
    public function getEmail(): string
272
    {
273
        return $this->email;
274
    }
275
276
    /**
277
     * Sets the email of this user.
278
     */
279
    public function setEmail(string $email): User
280
    {
281
        $this->email = $email;
282
283
        return $this;
284
    }
285
286
    /**
287
     * Return the first name of this user.
288
     */
289
    public function getFirstName(): ?string
290
    {
291
        return $this->first_name;
292
    }
293
294
    /**
295
     * Sets the first name of this user.
296
     */
297
    public function setFirstName(string $first_name): User
298
    {
299
        $this->first_name = $first_name;
300
301
        return $this;
302
    }
303
304
    /**
305
     * Returns the last name of this user.
306
     */
307
    public function getLastName(): ?string
308
    {
309
        return $this->last_name;
310
    }
311
312
    /**
313
     * Sets the last name of this user.
314
     */
315
    public function setLastName(string $last_name): User
316
    {
317
        $this->last_name = $last_name;
318
319
        return $this;
320
    }
321
322
    /**
323
     * Returns the full name of this user (in the format "first_name last_name").
324
     */
325
    public function getFullName(): string
326
    {
327
        if (empty($this->getFirstName())) {
328
            return $this->getLastName();
329
        }
330
        if (empty($this->getLastName())) {
331
            return $this->getFirstName();
332
        }
333
334
        return $this->getFirstName().' '.$this->getLastName();
335
    }
336
337
    /**
338
     * Returns the temporary saved plain password. We need this to set a password via EasyAdmin interface.
339
     * A value is only available shortly after it was set via setPlainPassword() and is deleted by eraseCredentials().
340
     *
341
     * @return string
342
     */
343
    public function getPlainPassword(): ?string
344
    {
345
        return $this->plain_password;
346
    }
347
348
    /**
349
     * Sets the temporary saved plain password. We need this to set a password via EasyAdmin interface.
350
     * The value is deleted by eraseCredentials().
351
     *
352
     * @param string $plainPassword
353
     */
354
    public function setPlainPassword(?string $plainPassword): User
355
    {
356
        $this->plain_password = $plainPassword;
357
358
        return $this;
359
    }
360
361
    /**
362
     * Returns true if this user has any Two-Factor method enabled.
363
     */
364
    public function isTFAEnabled(): bool
365
    {
366
        return $this->isGoogleAuthenticatorEnabled();
367
    }
368
369
    /**
370
     * Returns true if this user has google authentication 2FA enabled.
371
     */
372
    public function isGoogleAuthenticatorEnabled(): bool
373
    {
374
        return $this->googleAuthenticatorSecret ? true : false;
375
    }
376
377
    /**
378
     * Returns the username that should be shown to the user for this service, when using google authenticator.
379
     * Here the standard username is used.
380
     */
381
    public function getGoogleAuthenticatorUsername(): string
382
    {
383
        return $this->username;
384
    }
385
386
    /**
387
     * Returns the secret used for google authenticator 2FA.
388
     */
389
    public function getGoogleAuthenticatorSecret(): ?string
390
    {
391
        return $this->googleAuthenticatorSecret;
392
    }
393
394
    /**
395
     * Sets the secred used for google authenticator 2FA.
396
     *
397
     * @return $this
398
     */
399
    public function setGoogleAuthenticatorSecret(?string $googleAuthenticatorSecret): self
400
    {
401
        $this->googleAuthenticatorSecret = $googleAuthenticatorSecret;
402
403
        return $this;
404
    }
405
406
    /**
407
     * Returns the trusted token version used to implement trusted device 2FA.
408
     */
409
    public function getTrustedTokenVersion(): int
410
    {
411
        return $this->trustedVersion;
412
    }
413
414
    /**
415
     * Invalidate all trusted devices used by this user.
416
     *
417
     * @return $this
418
     */
419
    public function invalidateTrustedDevices(): self
420
    {
421
        ++$this->trustedVersion;
422
423
        return $this;
424
    }
425
426
    /**
427
     * Check if it is a valid backup code.
428
     */
429
    public function isBackupCode(string $code): bool
430
    {
431
        //Don't check if no backup codes are defined.
432
        if (empty($this->backupCodes)) {
433
            return false;
434
        }
435
436
        return in_array($code, $this->backupCodes, true);
437
    }
438
439
    /**
440
     * Invalidate a backup code.
441
     */
442
    public function invalidateBackupCode(string $code): void
443
    {
444
        $key = array_search($code, $this->backupCodes, true);
445
        if (false !== $key) {
446
            unset($this->backupCodes[$key]);
447
        }
448
    }
449
450
    /**
451
     * Set all backup codes of this user. BackupCodeDate will be updated.
452
     *
453
     * @return $this
454
     */
455
    public function setBackupCodes(array $codes): self
456
    {
457
        $this->backupCodes = $codes;
458
        $this->backupCodesDate = new DateTime();
459
460
        return $this;
461
    }
462
463
    /**
464
     * Returns the date when the backup codes where generated.
465
     *
466
     * @return DateTime
467
     */
468
    public function getBackupCodesDate(): ?DateTime
469
    {
470
        return $this->backupCodesDate;
471
    }
472
473
    /**
474
     * Returns all backup codes of this user.
475
     */
476
    public function getBackupCodes(): array
477
    {
478
        return $this->backupCodes ?? [];
479
    }
480
481
    /**
482
     * Check if this user is disabled and can not log in
483
     * @return bool
484
     */
485
    public function isDisabled(): bool
486
    {
487
        return $this->disabled;
488
    }
489
490
    /**
491
     * Set if this user is disabled and can not log in
492
     * @param  bool  $disabled
493
     * @return User
494
     */
495
    public function setDisabled(bool $disabled): User
496
    {
497
        $this->disabled = $disabled;
498
        return $this;
499
    }
500
501
    /**
502
     * Check if this user needs to change his password.
503
     * @return bool
504
     */
505
    public function isPasswordChangeNeeded(): bool
506
    {
507
        return $this->password_change_needed;
508
    }
509
510
    /**
511
     * Sets if this user needs to change his password
512
     * @param  bool  $password_change_needed
513
     * @return User
514
     */
515
    public function setPasswordChangeNeeded(bool $password_change_needed): User
516
    {
517
        $this->password_change_needed = $password_change_needed;
518
        return $this;
519
    }
520
521
    public function __toString(): string
522
    {
523
        return $this->getFullName().' ('.$this->username.')';
524
    }
525
}
526