new: usr: implement the 2FA authentication (TOTP and backup codes) #4
This commit is contained in:
@@ -18,6 +18,10 @@ use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\GeneratedValue;
|
||||
use Doctrine\ORM\Mapping\Id;
|
||||
use Doctrine\ORM\Mapping\Table;
|
||||
use Scheb\TwoFactorBundle\Model\BackupCodeInterface;
|
||||
use Scheb\TwoFactorBundle\Model\Totp\TotpConfiguration;
|
||||
use Scheb\TwoFactorBundle\Model\Totp\TotpConfigurationInterface;
|
||||
use Scheb\TwoFactorBundle\Model\Totp\TwoFactorInterface as TotpTwoFactorInterface;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
@@ -36,7 +40,7 @@ use Symfony\Component\Security\Core\User\UserInterface;
|
||||
#[Entity(repositoryClass: UserRepository::class)]
|
||||
#[UniqueEntity(fields: ['username'], message: 'This username is already taken.')]
|
||||
#[UniqueEntity(fields: ['email'], message: 'This email address is already registered.')]
|
||||
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
class User implements UserInterface, PasswordAuthenticatedUserInterface, TotpTwoFactorInterface, BackupCodeInterface
|
||||
{
|
||||
#[Id, GeneratedValue, Column]
|
||||
private ?int $id = null;
|
||||
@@ -65,6 +69,12 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
#[Column(type: Types::DATETIME_MUTABLE, nullable: true)]
|
||||
private ?DateTime $resetTokenExpiresAt = null;
|
||||
|
||||
#[Column(length: 255, nullable: true)]
|
||||
private ?string $totpSecret = null;
|
||||
|
||||
#[Column(type: Types::JSON, nullable: true)]
|
||||
private ?array $backupCodes = [];
|
||||
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
@@ -169,4 +179,58 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
$this->resetTokenExpiresAt = $resetTokenExpiresAt;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --- TotpTwoFactorInterface ---
|
||||
|
||||
public function isTotpAuthenticationEnabled(): bool
|
||||
{
|
||||
return null !== $this->totpSecret;
|
||||
}
|
||||
|
||||
public function getTotpAuthenticationUsername(): string
|
||||
{
|
||||
return $this->getUserIdentifier();
|
||||
}
|
||||
|
||||
public function getTotpAuthenticationConfiguration(): ?TotpConfigurationInterface
|
||||
{
|
||||
if (null === $this->totpSecret) {
|
||||
return null;
|
||||
}
|
||||
return new TotpConfiguration($this->totpSecret, TotpConfiguration::ALGORITHM_SHA1, 30, 6);
|
||||
}
|
||||
|
||||
public function getTotpSecret(): ?string
|
||||
{
|
||||
return $this->totpSecret;
|
||||
}
|
||||
|
||||
public function setTotpSecret(?string $totpSecret): self
|
||||
{
|
||||
$this->totpSecret = $totpSecret;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --- BackupCodeInterface ---
|
||||
|
||||
public function isBackupCode(string $code): bool
|
||||
{
|
||||
return \in_array($code, $this->backupCodes ?? [], true);
|
||||
}
|
||||
|
||||
public function invalidateBackupCode(string $code): void
|
||||
{
|
||||
$this->backupCodes = array_values(array_filter($this->backupCodes ?? [], fn($c) => $c !== $code));
|
||||
}
|
||||
|
||||
public function getBackupCodes(): array
|
||||
{
|
||||
return $this->backupCodes ?? [];
|
||||
}
|
||||
|
||||
public function setBackupCodes(array $backupCodes): self
|
||||
{
|
||||
$this->backupCodes = $backupCodes;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user