Skip to content

Commit

Permalink
PublicKeyCredentialSourceRepository is now deprecated (#384)
Browse files Browse the repository at this point in the history
* PublicKeyCredentialSourceRepository is now deprecated
* CS fixed
* Split Credential Registration
* Deptrac issue fixed
  • Loading branch information
Spomky authored Apr 14, 2023
1 parent 69817f4 commit 81dfb98
Show file tree
Hide file tree
Showing 45 changed files with 394 additions and 290 deletions.
2 changes: 2 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ parameters:
message: '#Strict comparison using === between mixed and null will always evaluate to false\.#'
path: src/metadata-service/src/Statement/StatusReport.php
count: 1
- '#Fetching class constant class of deprecated class Webauthn\\PublicKeyCredentialSourceRepository\.#'
- '#Fetching class constant class of deprecated class Webauthn\\Bundle\\Repository\\PublicKeyCredentialUserEntityRepository.*#'
- '#.*Binding.*#'
- '#Parameter .* of method .* has typehint with deprecated interface Webauthn\\PublicKeyCredentialSourceRepository\.#'
- '#Parameter \#\d+ \$.* of .* expects .*, .* given\.#'
- '#Property .* does not accept .*\|false\.#'
- '#Cannot access offset \d+ on array\|false\.#'
Expand Down
6 changes: 4 additions & 2 deletions src/symfony/src/Controller/AssertionControllerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Webauthn\AuthenticatorAssertionResponseValidator;
use Webauthn\Bundle\CredentialOptionsBuilder\ProfileBasedRequestOptionsBuilder;
use Webauthn\Bundle\CredentialOptionsBuilder\PublicKeyCredentialRequestOptionsBuilder;
use Webauthn\Bundle\Repository\PublicKeyCredentialSourceRepositoryInterface;
use Webauthn\Bundle\Repository\PublicKeyCredentialUserEntityRepositoryInterface;
use Webauthn\Bundle\Security\Handler\FailureHandler;
use Webauthn\Bundle\Security\Handler\RequestOptionsHandler;
Expand All @@ -33,7 +34,7 @@ public function __construct(
private readonly PublicKeyCredentialLoader $publicKeyCredentialLoader,
private readonly AuthenticatorAssertionResponseValidator $attestationResponseValidator,
private readonly PublicKeyCredentialUserEntityRepositoryInterface $publicKeyCredentialUserEntityRepository,
private readonly PublicKeyCredentialSourceRepository $publicKeyCredentialSourceRepository
private readonly PublicKeyCredentialSourceRepository|PublicKeyCredentialSourceRepositoryInterface $publicKeyCredentialSourceRepository
) {
$this->logger = new NullLogger();
}
Expand Down Expand Up @@ -113,7 +114,8 @@ public function createResponseController(
$optionStorage,
$successHandler,
$failureHandler,
$securedRelyingPartyIds
$securedRelyingPartyIds,
$this->publicKeyCredentialSourceRepository
);
}
}
12 changes: 11 additions & 1 deletion src/symfony/src/Controller/AssertionResponseController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
use Throwable;
use Webauthn\AuthenticatorAssertionResponse;
use Webauthn\AuthenticatorAssertionResponseValidator;
use Webauthn\Bundle\Repository\PublicKeyCredentialSourceRepositoryInterface;
use Webauthn\Bundle\Security\Handler\FailureHandler;
use Webauthn\Bundle\Security\Handler\SuccessHandler;
use Webauthn\Bundle\Security\Storage\OptionsStorage;
use Webauthn\Exception\AuthenticatorResponseVerificationException;
use Webauthn\PublicKeyCredentialLoader;
use Webauthn\PublicKeyCredentialRequestOptions;

Expand All @@ -32,6 +34,7 @@ public function __construct(
private readonly SuccessHandler $successHandler,
private readonly FailureHandler|AuthenticationFailureHandlerInterface $failureHandler,
private readonly array $securedRelyingPartyIds,
private readonly ?PublicKeyCredentialSourceRepositoryInterface $publicKeyCredentialSourceRepository = null
) {
}

Expand All @@ -55,8 +58,15 @@ public function __invoke(Request $request): Response
'Invalid response'
);
$userEntity = $data->getPublicKeyCredentialUserEntity();
$publicKeyCredentialSource = $this->publicKeyCredentialSourceRepository === null ? $publicKeyCredential->getRawId() : $this->publicKeyCredentialSourceRepository->findOneByCredentialId(
$publicKeyCredential->getRawId()
);
$publicKeyCredentialSource !== null || throw AuthenticatorResponseVerificationException::create(
'The credential ID is invalid.'
);

$this->assertionResponseValidator->check(
$publicKeyCredential->getRawId(),
$publicKeyCredentialSource,
$response,
$publicKeyCredentialRequestOptions,
$request->getHost(),
Expand Down
3 changes: 2 additions & 1 deletion src/symfony/src/Controller/AttestationControllerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Webauthn\AuthenticatorAttestationResponseValidator;
use Webauthn\Bundle\CredentialOptionsBuilder\ProfileBasedCreationOptionsBuilder;
use Webauthn\Bundle\CredentialOptionsBuilder\PublicKeyCredentialCreationOptionsBuilder;
use Webauthn\Bundle\Repository\PublicKeyCredentialSourceRepositoryInterface;
use Webauthn\Bundle\Security\Guesser\UserEntityGuesser;
use Webauthn\Bundle\Security\Handler\CreationOptionsHandler;
use Webauthn\Bundle\Security\Handler\FailureHandler;
Expand All @@ -27,7 +28,7 @@ public function __construct(
private readonly PublicKeyCredentialCreationOptionsFactory $publicKeyCredentialCreationOptionsFactory,
private readonly PublicKeyCredentialLoader $publicKeyCredentialLoader,
private readonly AuthenticatorAttestationResponseValidator $attestationResponseValidator,
private readonly PublicKeyCredentialSourceRepository $publicKeyCredentialSourceRepository
private readonly PublicKeyCredentialSourceRepository|PublicKeyCredentialSourceRepositoryInterface $publicKeyCredentialSourceRepository
) {
}

Expand Down
31 changes: 25 additions & 6 deletions src/symfony/src/Controller/AttestationResponseController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
use Throwable;
use Webauthn\AuthenticatorAttestationResponse;
use Webauthn\AuthenticatorAttestationResponseValidator;
use Webauthn\Bundle\Exception\HttpNotImplementedException;
use Webauthn\Bundle\Exception\MissingFeatureException;
use Webauthn\Bundle\Repository\CanSaveCredentialSource;
use Webauthn\Bundle\Repository\PublicKeyCredentialSourceRepositoryInterface;
use Webauthn\Bundle\Security\Handler\FailureHandler;
use Webauthn\Bundle\Security\Handler\SuccessHandler;
use Webauthn\Bundle\Security\Storage\OptionsStorage;
Expand All @@ -28,17 +32,31 @@ final class AttestationResponseController
public function __construct(
private readonly PublicKeyCredentialLoader $publicKeyCredentialLoader,
private readonly AuthenticatorAttestationResponseValidator $attestationResponseValidator,
private readonly PublicKeyCredentialSourceRepository $credentialSourceRepository,
private readonly PublicKeyCredentialSourceRepository|PublicKeyCredentialSourceRepositoryInterface $credentialSourceRepository,
private readonly OptionsStorage $optionStorage,
private readonly SuccessHandler $successHandler,
private readonly FailureHandler|AuthenticationFailureHandlerInterface $failureHandler,
private readonly array $securedRelyingPartyIds,
) {
if (! $this->credentialSourceRepository instanceof PublicKeyCredentialSourceRepositoryInterface) {
trigger_deprecation(
'web-auth/webauthn-symfony-bundle',
'4.6.0',
sprintf(
'Since 4.6.0, the parameter "$credentialSourceRepository" expects an instance of "%s". Please implement that interface instead of "%s".',
PublicKeyCredentialSourceRepositoryInterface::class,
PublicKeyCredentialSourceRepository::class
)
);
}
}

public function __invoke(Request $request): Response
{
try {
if (! $this->credentialSourceRepository instanceof CanSaveCredentialSource) {
throw MissingFeatureException::create('Unable to register the credential.');
}
$format = method_exists(
$request,
'getContentTypeFormat'
Expand Down Expand Up @@ -73,13 +91,14 @@ public function __invoke(Request $request): Response
$this->credentialSourceRepository->saveCredentialSource($credentialSource);
return $this->successHandler->onSuccess($request);
} catch (Throwable $throwable) {
$exception = new AuthenticationException($throwable->getMessage(), 401, $throwable);
if ($throwable instanceof MissingFeatureException) {
$exception = new HttpNotImplementedException($throwable->getMessage(), $throwable);
}
if ($this->failureHandler instanceof AuthenticationFailureHandlerInterface) {
return $this->failureHandler->onAuthenticationFailure(
$request,
new AuthenticationException($throwable->getMessage(), $throwable->getCode(), $throwable)
);
return $this->failureHandler->onAuthenticationFailure($request, $exception);
}
return $this->failureHandler->onFailure($request, $throwable);
return $this->failureHandler->onFailure($request, $exception);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs;
use Webauthn\AuthenticatorSelectionCriteria;
use Webauthn\Bundle\Dto\PublicKeyCredentialCreationOptionsRequest;
use Webauthn\Bundle\Repository\PublicKeyCredentialSourceRepositoryInterface;
use Webauthn\Bundle\Service\PublicKeyCredentialCreationOptionsFactory;
use Webauthn\PublicKeyCredentialCreationOptions;
use Webauthn\PublicKeyCredentialDescriptor;
Expand All @@ -27,10 +28,21 @@ final class ProfileBasedCreationOptionsBuilder implements PublicKeyCredentialCre
public function __construct(
private readonly SerializerInterface $serializer,
private readonly ValidatorInterface $validator,
private readonly PublicKeyCredentialSourceRepository $credentialSourceRepository,
private readonly PublicKeyCredentialSourceRepository|PublicKeyCredentialSourceRepositoryInterface $credentialSourceRepository,
private readonly PublicKeyCredentialCreationOptionsFactory $publicKeyCredentialCreationOptionsFactory,
private readonly string $profile,
) {
if (! $this->credentialSourceRepository instanceof PublicKeyCredentialSourceRepositoryInterface) {
trigger_deprecation(
'web-auth/webauthn-symfony-bundle',
'4.6.0',
sprintf(
'Since 4.6.0, the parameter "$credentialSourceRepository" expects an instance of "%s". Please implement that interface instead of "%s".',
PublicKeyCredentialSourceRepositoryInterface::class,
PublicKeyCredentialSourceRepository::class
)
);
}
}

public function getFromRequest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs;
use Webauthn\Bundle\Dto\ServerPublicKeyCredentialRequestOptionsRequest;
use Webauthn\Bundle\Repository\PublicKeyCredentialSourceRepositoryInterface;
use Webauthn\Bundle\Repository\PublicKeyCredentialUserEntityRepositoryInterface;
use Webauthn\Bundle\Service\PublicKeyCredentialRequestOptionsFactory;
use Webauthn\PublicKeyCredentialDescriptor;
Expand All @@ -26,10 +27,21 @@ public function __construct(
private readonly SerializerInterface $serializer,
private readonly ValidatorInterface $validator,
private readonly PublicKeyCredentialUserEntityRepositoryInterface $userEntityRepository,
private readonly PublicKeyCredentialSourceRepository $credentialSourceRepository,
private readonly PublicKeyCredentialSourceRepository|PublicKeyCredentialSourceRepositoryInterface $credentialSourceRepository,
private readonly PublicKeyCredentialRequestOptionsFactory $publicKeyCredentialRequestOptionsFactory,
private readonly string $profile,
) {
if (! $this->credentialSourceRepository instanceof PublicKeyCredentialSourceRepositoryInterface) {
trigger_deprecation(
'web-auth/webauthn-symfony-bundle',
'4.6.0',
sprintf(
'Since 4.6.0, the parameter "$credentialSourceRepository" expects an instance of "%s". Please implement that interface instead of "%s".',
PublicKeyCredentialSourceRepositoryInterface::class,
PublicKeyCredentialSourceRepository::class
)
);
}
}

public function getFromRequest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use Webauthn\Bundle\CredentialOptionsBuilder\ProfileBasedCreationOptionsBuilder;
use Webauthn\Bundle\CredentialOptionsBuilder\ProfileBasedRequestOptionsBuilder;
use Webauthn\Bundle\DependencyInjection\Compiler\DynamicRouteCompilerPass;
use Webauthn\Bundle\Repository\PublicKeyCredentialSourceRepositoryInterface;
use Webauthn\Bundle\Repository\PublicKeyCredentialUserEntityRepositoryInterface;
use Webauthn\Bundle\Security\Guesser\RequestBodyUserEntityGuesser;
use Webauthn\Bundle\Security\Handler\DefaultCreationOptionsHandler;
Expand All @@ -35,7 +36,6 @@
use Webauthn\Bundle\Security\Storage\SessionStorage;
use Webauthn\Bundle\Service\PublicKeyCredentialCreationOptionsFactory;
use Webauthn\Bundle\Service\PublicKeyCredentialRequestOptionsFactory;
use Webauthn\PublicKeyCredentialSourceRepository;

final class WebauthnFactory implements FirewallListenerFactoryInterface, AuthenticatorFactoryInterface
{
Expand Down Expand Up @@ -466,7 +466,7 @@ private function getAssertionOptionsBuilderId(
new Reference(SerializerInterface::class),
new Reference(ValidatorInterface::class),
new Reference(PublicKeyCredentialUserEntityRepositoryInterface::class),
new Reference(PublicKeyCredentialSourceRepository::class),
new Reference(PublicKeyCredentialSourceRepositoryInterface::class),
new Reference(PublicKeyCredentialRequestOptionsFactory::class),
$config['profile'],
]);
Expand All @@ -489,7 +489,7 @@ private function getAttestationOptionsBuilderId(
->setArguments([
new Reference(SerializerInterface::class),
new Reference(ValidatorInterface::class),
new Reference(PublicKeyCredentialSourceRepository::class),
new Reference(PublicKeyCredentialSourceRepositoryInterface::class),
new Reference(PublicKeyCredentialCreationOptionsFactory::class),
$config['profile'],
]);
Expand Down
6 changes: 4 additions & 2 deletions src/symfony/src/DependencyInjection/WebauthnExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
use Webauthn\Bundle\DependencyInjection\Compiler\ExtensionOutputCheckerCompilerPass;
use Webauthn\Bundle\DependencyInjection\Compiler\LoggerSetterCompilerPass;
use Webauthn\Bundle\Doctrine\Type as DbalType;
use Webauthn\Bundle\Repository\PublicKeyCredentialSourceRepositoryInterface;
use Webauthn\Bundle\Repository\PublicKeyCredentialUserEntityRepository;
use Webauthn\Bundle\Repository\PublicKeyCredentialUserEntityRepositoryInterface;
use Webauthn\Bundle\Service\PublicKeyCredentialCreationOptionsFactory;
Expand Down Expand Up @@ -92,6 +93,7 @@ public function load(array $configs, ContainerBuilder $container): void
$container->setAlias('webauthn.logger', $config['logger']);

$container->setAlias(PublicKeyCredentialSourceRepository::class, $config['credential_repository']);
$container->setAlias(PublicKeyCredentialSourceRepositoryInterface::class, $config['credential_repository']);
$container->setAlias(PublicKeyCredentialUserEntityRepository::class, $config['user_repository']);
$container->setAlias(PublicKeyCredentialUserEntityRepositoryInterface::class, $config['user_repository']);

Expand Down Expand Up @@ -184,7 +186,7 @@ private function loadCreationControllersSupport(ContainerBuilder $container, arr
->setArguments([
new Reference(SerializerInterface::class),
new Reference(ValidatorInterface::class),
new Reference(PublicKeyCredentialSourceRepository::class),
new Reference(PublicKeyCredentialSourceRepositoryInterface::class),
new Reference(PublicKeyCredentialCreationOptionsFactory::class),
$creationConfig['profile'],
]);
Expand Down Expand Up @@ -245,7 +247,7 @@ private function loadRequestControllersSupport(ContainerBuilder $container, arra
new Reference(SerializerInterface::class),
new Reference(ValidatorInterface::class),
new Reference(PublicKeyCredentialUserEntityRepositoryInterface::class),
new Reference(PublicKeyCredentialSourceRepository::class),
new Reference(PublicKeyCredentialSourceRepositoryInterface::class),
new Reference(PublicKeyCredentialRequestOptionsFactory::class),
$requestConfig['profile'],
]);
Expand Down
19 changes: 19 additions & 0 deletions src/symfony/src/Exception/HttpNotImplementedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Webauthn\Bundle\Exception;

use Symfony\Component\HttpKernel\Exception\HttpException;
use Throwable;

class HttpNotImplementedException extends HttpException
{
/**
* @param array<string, mixed> $headers
*/
public function __construct(string $message = '', Throwable $previous = null, int $code = 0, array $headers = [])
{
parent::__construct(501, $message, $previous, $headers, $code);
}
}
16 changes: 16 additions & 0 deletions src/symfony/src/Exception/MissingFeatureException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Webauthn\Bundle\Exception;

use Throwable;
use Webauthn\Exception\WebauthnException;

final class MissingFeatureException extends WebauthnException
{
public static function create(string $message, ?Throwable $previous = null): self
{
return new self($message, $previous);
}
}
12 changes: 12 additions & 0 deletions src/symfony/src/Repository/CanSaveCredentialSource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Webauthn\Bundle\Repository;

use Webauthn\PublicKeyCredentialSource;

interface CanSaveCredentialSource
{
public function saveCredentialSource(PublicKeyCredentialSource $publicKeyCredentialSource): void;
}
Loading

0 comments on commit 81dfb98

Please sign in to comment.