Skip to content

Commit dd86183

Browse files
committed
OXDEV-9078 Add TwoFactorAuthentication factory and register otp placeholder
1 parent fd4d8a0 commit dd86183

9 files changed

Lines changed: 214 additions & 0 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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\Exception;
11+
12+
class AuthenticationTypeNotFoundException extends \Exception
13+
{
14+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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\Factory;
11+
12+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Exception\AuthenticationTypeNotFoundException;
13+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Service\ModuleSettingsServiceInterface;
14+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Service\TwoFAServiceInterface;
15+
16+
class TwoFAServiceFactory implements TwoFAServiceFactoryInterface
17+
{
18+
public function __construct(
19+
private ModuleSettingsServiceInterface $settings,
20+
private array $implementations,
21+
) {
22+
}
23+
24+
public function create(): TwoFAServiceInterface
25+
{
26+
$type = $this->settings->getTwoFactorAuthType();
27+
28+
return $this->implementations[$type] ?? throw new AuthenticationTypeNotFoundException();
29+
}
30+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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\Factory;
11+
12+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Service\TwoFAServiceInterface;
13+
14+
interface TwoFAServiceFactoryInterface
15+
{
16+
public function create(): TwoFAServiceInterface;
17+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
services:
2+
_defaults:
3+
autowire: true
4+
public: false
5+
6+
OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Factory\TwoFAServiceFactoryInterface:
7+
class: OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Factory\TwoFAServiceFactory
8+
arguments:
9+
$implementations:
10+
otp: '@OxidEsales\SecurityModule\Authentication\TwoFactorAuth\OTP\OTPService'
11+
12+
OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Service\TwoFAServiceInterface:
13+
factory: ['@OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Factory\TwoFAServiceFactoryInterface', 'create']
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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\OTP;
11+
12+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Service\TwoFAServiceInterface;
13+
14+
class OTPService implements TwoFAServiceInterface
15+
{
16+
public function hasPendingChallenge(string $userId): bool
17+
{
18+
}
19+
20+
public function triggerChallenge(string $userId): void
21+
{
22+
}
23+
24+
public function clearChallenge(): void
25+
{
26+
}
27+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
services:
2+
_defaults:
3+
autowire: true
4+
public: false
5+
6+
OxidEsales\SecurityModule\Authentication\TwoFactorAuth\OTP\OTPService: ~

src/Authentication/TwoFactorAuth/services.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ imports:
33
- { resource: Service/services.yaml }
44
- { resource: Transput/services.yaml }
55
- { resource: Controller/services.yaml }
6+
- { resource: Factory/services.yaml }
7+
- { resource: OTP/services.yaml }
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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\Tests\Integration;
11+
12+
use OxidEsales\EshopCommunity\Internal\Container\ContainerBuilderFactory;
13+
use OxidEsales\EshopCommunity\Tests\Integration\IntegrationTestCase;
14+
use PHPUnit\Framework\Attributes\DataProvider;
15+
use Symfony\Component\DependencyInjection\ContainerInterface;
16+
17+
final class ServiceAvailabilityTest extends IntegrationTestCase
18+
{
19+
private static ContainerInterface $cachedContainer;
20+
21+
public static function setUpBeforeClass(): void
22+
{
23+
$containerBuilder = (new ContainerBuilderFactory())->create();
24+
$container = $containerBuilder->getContainer();
25+
foreach ($container->getDefinitions() as $definition) {
26+
$definition->setPublic(true);
27+
}
28+
$container->compile(true);
29+
30+
self::$cachedContainer = $container;
31+
}
32+
33+
#[DataProvider('serviceAvailabilityDataProvider')]
34+
public function testServicesAvailable(string $serviceId): void
35+
{
36+
self::assertIsObject(self::$cachedContainer->get($serviceId));
37+
}
38+
39+
public static function serviceAvailabilityDataProvider(): array
40+
{
41+
return [
42+
[\OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Factory\TwoFAServiceFactoryInterface::class],
43+
[\OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Service\TwoFAServiceInterface::class],
44+
];
45+
}
46+
}
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\Tests\Unit\Authentication\TwoFactorAuth\Factory;
11+
12+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Factory\TwoFAServiceFactory;
13+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Factory\TwoFAServiceFactoryInterface;
14+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Service\ModuleSettingsServiceInterface;
15+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Exception\AuthenticationTypeNotFoundException;
16+
use OxidEsales\SecurityModule\Authentication\TwoFactorAuth\Service\TwoFAServiceInterface;
17+
use PHPUnit\Framework\TestCase;
18+
19+
class TwoFAServiceFactoryTest extends TestCase
20+
{
21+
public function testCreateReturnsServiceMatchingConfiguredType(): void
22+
{
23+
$otpServiceStub = $this->createStub(TwoFAServiceInterface::class);
24+
$totpServiceStub = $this->createStub(TwoFAServiceInterface::class);
25+
26+
$settingsStub = $this->createStub(ModuleSettingsServiceInterface::class);
27+
$settingsStub->method('getTwoFactorAuthType')->willReturn('otp');
28+
29+
$sut = $this->getSut(
30+
settings: $settingsStub,
31+
implementations: ['otp' => $otpServiceStub, 'totp' => $totpServiceStub],
32+
);
33+
34+
$this->assertSame($otpServiceStub, $sut->create());
35+
}
36+
37+
public function testCreateThrowsForUnknownType(): void
38+
{
39+
$settingsStub = $this->createStub(ModuleSettingsServiceInterface::class);
40+
$settingsStub->method('getTwoFactorAuthType')->willReturn('unknown');
41+
42+
$sut = $this->getSut(
43+
settings: $settingsStub,
44+
);
45+
46+
$this->expectException(AuthenticationTypeNotFoundException::class);
47+
$sut->create();
48+
}
49+
50+
private function getSut(
51+
ModuleSettingsServiceInterface $settings = null,
52+
array $implementations = [],
53+
): TwoFAServiceFactoryInterface {
54+
return new TwoFAServiceFactory(
55+
settings: $settings ?? $this->createStub(ModuleSettingsServiceInterface::class),
56+
implementations: $implementations,
57+
);
58+
}
59+
}

0 commit comments

Comments
 (0)