Skip to content

Commit 9b51a74

Browse files
committed
feat: Add TOTP double authentication
1 parent c731f66 commit 9b51a74

File tree

4 files changed

+17
-61
lines changed

4 files changed

+17
-61
lines changed

ROADMAP.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,3 @@
44
* Add mutation testing
55
* Add reset password
66
* Upgrade to PHP 8.4
7-
* Restore 2FA by email (allow TOTP and email)

migrations/Version20250308115237.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DoctrineMigrations;
6+
7+
use Doctrine\DBAL\Schema\Schema;
8+
use Doctrine\Migrations\AbstractMigration;
9+
10+
final class Version20250308115237 extends AbstractMigration
11+
{
12+
public function up(Schema $schema): void
13+
{
14+
$this->addSql('ALTER TABLE user DROP two_factors_authentication_email_enabled, DROP two_factors_authentication_email_code');
15+
}
16+
}

src/Entity/User.php

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,19 @@
66

77
use App\Repository\UserRepository;
88
use Doctrine\ORM\Mapping as ORM;
9-
use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface as TwoFactorInterfaceEmail;
109
use Scheb\TwoFactorBundle\Model\Totp\TotpConfiguration;
1110
use Scheb\TwoFactorBundle\Model\Totp\TotpConfigurationInterface;
1211
use Scheb\TwoFactorBundle\Model\Totp\TwoFactorInterface as TwoFactorInterfaceTotp;
1312
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
1413
use Symfony\Component\Security\Core\User\UserInterface;
1514
use Symfony\Component\Uid\Uuid;
1615
use DateTimeImmutable;
17-
use LogicException;
1816

1917
#[ORM\Entity(repositoryClass: UserRepository::class)]
2018
#[ORM\Table(name: '`user`')]
2119
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_UUID', fields: ['uuid'])]
2220
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_EMAIL', fields: ['email'])]
23-
class User implements PasswordAuthenticatedUserInterface, TwoFactorInterfaceEmail, TwoFactorInterfaceTotp, UserInterface
21+
class User implements PasswordAuthenticatedUserInterface, TwoFactorInterfaceTotp, UserInterface
2422
{
2523
#[ORM\Id]
2624
#[ORM\GeneratedValue]
@@ -45,15 +43,9 @@ class User implements PasswordAuthenticatedUserInterface, TwoFactorInterfaceEmai
4543
#[ORM\Column(nullable: true)]
4644
private ?DateTimeImmutable $lastLoginAt = null;
4745

48-
#[ORM\Column]
49-
private bool $twoFactorsAuthenticationEmailEnabled = false;
50-
5146
#[ORM\Column]
5247
private bool $twoFactorsAuthenticationTotpEnabled = false;
5348

54-
#[ORM\Column(nullable: true)]
55-
private ?string $twoFactorsAuthenticationEmailCode = null;
56-
5749
#[ORM\Column(nullable: true)]
5850
private ?string $twoFactorsAuthenticationTotpSecret = null;
5951

@@ -143,15 +135,6 @@ public function setLastLoginAt(): self
143135
return $this;
144136
}
145137

146-
public function getEmailAuthCode(): ?string
147-
{
148-
if (null === $this->twoFactorsAuthenticationEmailCode) {
149-
throw new LogicException('The email authentication code was not set');
150-
}
151-
152-
return $this->twoFactorsAuthenticationEmailCode;
153-
}
154-
155138
public function isTotpAuthenticationEnabled(): bool
156139
{
157140
return $this->twoFactorsAuthenticationTotpEnabled && null !== $this->twoFactorsAuthenticationTotpSecret;
@@ -176,21 +159,6 @@ public function getTotpAuthenticationConfiguration(): ?TotpConfigurationInterfac
176159
);
177160
}
178161

179-
public function hasTwoFactorsAuthentication(): bool
180-
{
181-
return $this->twoFactorsAuthenticationEmailEnabled;
182-
}
183-
184-
public function getEmailAuthRecipient(): string
185-
{
186-
return $this->email;
187-
}
188-
189-
public function setEmailAuthCode(string $authCode): void
190-
{
191-
$this->twoFactorsAuthenticationEmailCode = $authCode;
192-
}
193-
194162
public function setTwoFactorsAuthenticationTotpSecret(?string $secret): self
195163
{
196164
$this->twoFactorsAuthenticationTotpSecret = $secret;
@@ -208,9 +176,4 @@ public function enableTwoFactorsAuthenticationTotp(): void
208176
{
209177
$this->twoFactorsAuthenticationTotpEnabled = true;
210178
}
211-
212-
public function enableTwoFactorsAuthenticationEmail(): void
213-
{
214-
$this->twoFactorsAuthenticationEmailEnabled = true;
215-
}
216179
}

tests/Entity/UserTest.php

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use PHPUnit\Framework\Attributes\CoversClass;
99
use PHPUnit\Framework\TestCase;
1010
use Scheb\TwoFactorBundle\Model\Totp\TotpConfiguration;
11-
use LogicException;
1211

1312
#[CoversClass(User::class)]
1413
final class UserTest extends TestCase
@@ -32,15 +31,6 @@ public function testShouldSupportUserProperties(): void
3231
self::assertSame(['ROLE_GUEST', 'ROLE_USER'], $user->getRoles());
3332
}
3433

35-
public function testShouldThrowAnExceptionWithoutEmailAuthCode(): void
36-
{
37-
$user = new User();
38-
39-
$this->expectException(LogicException::class);
40-
41-
$user->getEmailAuthCode();
42-
}
43-
4434
public function testShouldEnableTwoFactorsAuthenticationTotp(): void
4535
{
4636
$user = new User();
@@ -69,16 +59,4 @@ public function testShouldDisableTwoFactorsAuthenticationTotp(): void
6959
self::assertFalse($user->isTotpAuthenticationEnabled());
7060
self::assertNull($totpConfiguration);
7161
}
72-
73-
public function testShouldEnableTwoFactorsAuthenticationEmail(): void
74-
{
75-
$user = new User();
76-
$user->setEmail('[email protected]');
77-
$user->setEmailAuthCode('test');
78-
$user->enableTwoFactorsAuthenticationEmail();
79-
80-
self::assertTrue($user->hasTwoFactorsAuthentication());
81-
self::assertSame('[email protected]', $user->getEmailAuthRecipient());
82-
self::assertSame('test', $user->getEmailAuthCode());
83-
}
8462
}

0 commit comments

Comments
 (0)