Skip to content

Commit 4027aae

Browse files
committed
WIP Add code generation on login
1 parent 1f8b065 commit 4027aae

13 files changed

Lines changed: 223 additions & 17 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright © OXID eSales AG. All rights reserved.
7+
* See LICENSE file for license details.
8+
*/
9+
10+
namespace OxidEsales\SecurityModule\Migrations;
11+
12+
use Doctrine\DBAL\Schema\Schema;
13+
use Doctrine\Migrations\AbstractMigration;
14+
15+
final class Version20251128093245 extends AbstractMigration
16+
{
17+
public function up(Schema $schema): void
18+
{
19+
$this->addSql('ALTER TABLE `oxuser` ADD column `OESMOTPCODE` VARCHAR(128) default NULL COMMENT "OTP code"');
20+
$this->addSql('ALTER TABLE `oxuser` ADD column `OESMOTPEXPTIME` DATETIME default NULL COMMENT "OTP code expiration time"');
21+
$this->addSql('ALTER TABLE `oxuser` ADD column `OESMOTPATTEMPTS` INT NOT NULL default 0 COMMENT "OTP code attempts"');
22+
}
23+
24+
public function down(Schema $schema): void
25+
{
26+
}
27+
}

migration/migrations.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
table_storage:
2+
table_name: oxmigrations_oe_security_module
3+
migrations_paths:
4+
'OxidEsales\SecurityModule\Migrations': data

src/Authentication/TwoFactorAuth/DTO/UserDTO.php renamed to src/Authentication/TwoFactorAuth/DataObject/User.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
use DateTimeInterface;
1313

14-
class UserDTO implements UserDTOInterface
14+
class User implements UserInterface
1515
{
1616
public function __construct(
1717
private readonly ?string $code,

src/Authentication/TwoFactorAuth/DTO/UserDTOInterface.php renamed to src/Authentication/TwoFactorAuth/DataObject/UserInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
use DateTimeInterface;
1111

12-
interface UserDTOInterface
12+
interface UserInterface
1313
{
1414
public function getCode(): ?string;
1515

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/**
4+
* Copyright © OXID eSales AG. All rights reserved.
5+
* See LICENSE file for license details.
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Infrastructure;
11+
12+
use OxidEsales\Eshop\Application\Model\User;
13+
14+
class UserFactory implements UserFactoryInterface
15+
{
16+
/**
17+
* @inheritDoc
18+
*/
19+
public function create(): User
20+
{
21+
return oxNew(User::class);
22+
}
23+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
/**
4+
* Copyright © OXID eSales AG. All rights reserved.
5+
* See LICENSE file for license details.
6+
*/
7+
8+
namespace OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Infrastructure;
9+
10+
use OxidEsales\Eshop\Application\Model\User;
11+
12+
interface UserFactoryInterface
13+
{
14+
public function create(): User;
15+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
/**
4+
* Copyright © OXID eSales AG. All rights reserved.
5+
* See LICENSE file for license details.
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Repository;
11+
12+
use OxidEsales\Eshop\Application\Model\User as UserModel;
13+
use OxidEsales\SecurityModule\Authentication\OAuth2\DataObject\UserInterface;
14+
use OxidEsales\SecurityModule\Authentication\OAuth2\Exception\UserNotFoundException;
15+
use OxidEsales\SecurityModule\Authentication\OAuth2\Infrastructure\UserFactoryInterface;
16+
17+
class UserRepository implements UserRepositoryInterface
18+
{
19+
public function __construct(
20+
private UserFactoryInterface $userFactory
21+
) {
22+
}
23+
24+
public function addOTPtoUser(string $userId, string $otp, int $expiresAt): bool
25+
{
26+
$userModel = $this->userFactory->create();
27+
$userModel->load($userId);
28+
$userModel->assign([
29+
'OESMOTPCODE' => $otp,
30+
'OESMOTPEXPTIME' => $expiresAt,
31+
'OESMOTPATTEMPTS' => 0,
32+
]);
33+
$userModel->save();
34+
35+
return true;
36+
}
37+
38+
public function updateAttempts(string $userId, int $attempts): int
39+
{
40+
$userModel = $this->userFactory->create();
41+
$userModel->load($userId);
42+
$userModel->assign([
43+
'OESMOTPATTEMPTS' => $attempts
44+
]);
45+
$userModel->save();
46+
}
47+
48+
public function resetCodeFields(string $userId): void
49+
{
50+
$userModel = $this->userFactory->create();
51+
$userModel->load($userId);
52+
$userModel->assign([
53+
'OESMOTPCODE' => '',
54+
'OESMOTPEXPTIME' => 0,
55+
'OESMOTPATTEMPTS' => 0,
56+
]);
57+
$userModel->save();
58+
}
59+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
/**
4+
* Copyright © OXID eSales AG. All rights reserved.
5+
* See LICENSE file for license details.
6+
*/
7+
8+
namespace OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Repository;
9+
10+
use OxidEsales\SecurityModule\Authentication\OAuth2\DataObject\UserInterface;
11+
12+
interface UserRepositoryInterface
13+
{
14+
public function updateAttempts(string $userId, int $attempts): int;
15+
16+
public function resetCodeFields(string $userId): void;
17+
18+
public function addOTPtoUser(string $userId, string $otp, int $expiresAt): bool;
19+
}

src/Authentication/TwoFactorAuth/Service/AuthorizeService.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,9 @@ public function validate()
1515
{
1616
//todo: call correct provider service to validate the code
1717
}
18+
19+
public function generate($userName)
20+
{
21+
//todo: call correct provider service to generate the code
22+
}
1823
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Service\Provider\OTP\Service;
4+
5+
use OxidEsales\Eshop\Application\Model\User as UserModel;
6+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\DTO\User;
7+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Repository\UserRepositoryInterface;
8+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Service\Provider\OTP\Validator\OTPValidatorInterface;
9+
10+
readonly class OTPGenerator implements OTPGeneratorInterface
11+
{
12+
private const OTP_LENGTH = 6;
13+
private const OTP_EXPIRATION = 300; // 5 minutes
14+
15+
public function __construct(
16+
private UserRepositoryInterface $userRepository,
17+
) {
18+
}
19+
20+
public function generateCode(UserModel $user): User
21+
{
22+
$otp = str_pad(random_int(0, 999999), self::OTP_LENGTH, '0', STR_PAD_LEFT);
23+
$expiresAt = time() + self::OTP_EXPIRATION;
24+
25+
$this->userRepository->addOTPtoUser($user->getId(), $otp, $expiresAt);
26+
27+
return new User($otp, 0, $expiresAt);
28+
}
29+
}

0 commit comments

Comments
 (0)