Skip to content

Commit

Permalink
Add new denormalizers and deprecate old JSON methods (#618)
Browse files Browse the repository at this point in the history
* Add new denormalizers and deprecate old JSON methods

Added new Denormalizer classes for AttestedCredentialData, AuthenticationExtensions, and others. Deprecated JSON serialization methods in several classes, scheduled to be removed in version 5.0. Now serialization relies fully on the Symfony Serializer component. Various minor amendments in other classes to support these changes.
  • Loading branch information
Spomky authored Jul 6, 2024
1 parent a9d1352 commit abd4ca4
Show file tree
Hide file tree
Showing 45 changed files with 626 additions and 135 deletions.
87 changes: 80 additions & 7 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -2421,6 +2421,41 @@ parameters:
count: 1
path: src/webauthn/src/Denormalizer/AttestationStatementDenormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\AttestedCredentialDataNormalizer\\:\\:normalize\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/AttestedCredentialDataNormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\AttestedCredentialDataNormalizer\\:\\:normalize\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/AttestedCredentialDataNormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\AttestedCredentialDataNormalizer\\:\\:supportsNormalization\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/AttestedCredentialDataNormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\AuthenticationExtensionNormalizer\\:\\:normalize\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/AuthenticationExtensionNormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\AuthenticationExtensionNormalizer\\:\\:normalize\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/AuthenticationExtensionNormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\AuthenticationExtensionNormalizer\\:\\:normalize\\(\\) should return array but returns mixed\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/AuthenticationExtensionNormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\AuthenticationExtensionNormalizer\\:\\:supportsNormalization\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/AuthenticationExtensionNormalizer.php

-
message: """
#^Fetching class constant class of deprecated class Webauthn\\\\AuthenticationExtensions\\\\AuthenticationExtensionsClientInputs\\:
Expand Down Expand Up @@ -2474,7 +2509,7 @@ parameters:

-
message: "#^Cannot access offset 'clientDataJSON' on mixed\\.$#"
count: 3
count: 2
path: src/webauthn/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php

-
Expand All @@ -2484,7 +2519,7 @@ parameters:

-
message: "#^Cannot access offset 'userHandle' on mixed\\.$#"
count: 3
count: 1
path: src/webauthn/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php

-
Expand Down Expand Up @@ -2522,11 +2557,6 @@ parameters:
count: 1
path: src/webauthn/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php

-
message: "#^Parameter \\#4 \\$userHandle of static method Webauthn\\\\AuthenticatorAssertionResponse\\:\\:create\\(\\) expects string\\|null, mixed given\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php

-
message: "#^Parameter \\#5 \\$attestationObject of static method Webauthn\\\\AuthenticatorAssertionResponse\\:\\:create\\(\\) expects Webauthn\\\\AttestationStatement\\\\AttestationObject\\|null, mixed given\\.$#"
count: 1
Expand Down Expand Up @@ -2687,6 +2717,21 @@ parameters:
count: 1
path: src/webauthn/src/Denormalizer/PublicKeyCredentialDenormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\PublicKeyCredentialDescriptorNormalizer\\:\\:normalize\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/PublicKeyCredentialDescriptorNormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\PublicKeyCredentialDescriptorNormalizer\\:\\:normalize\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/PublicKeyCredentialDescriptorNormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\PublicKeyCredentialDescriptorNormalizer\\:\\:supportsNormalization\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/PublicKeyCredentialDescriptorNormalizer.php

-
message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#"
count: 1
Expand Down Expand Up @@ -2962,11 +3007,26 @@ parameters:
count: 1
path: src/webauthn/src/Denormalizer/PublicKeyCredentialSourceDenormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\PublicKeyCredentialSourceDenormalizer\\:\\:normalize\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/PublicKeyCredentialSourceDenormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\PublicKeyCredentialSourceDenormalizer\\:\\:normalize\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/PublicKeyCredentialSourceDenormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\PublicKeyCredentialSourceDenormalizer\\:\\:supportsDenormalization\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/PublicKeyCredentialSourceDenormalizer.php

-
message: "#^Method Webauthn\\\\Denormalizer\\\\PublicKeyCredentialSourceDenormalizer\\:\\:supportsNormalization\\(\\) has parameter \\$context with no value type specified in iterable type array\\.$#"
count: 1
path: src/webauthn/src/Denormalizer/PublicKeyCredentialSourceDenormalizer.php

-
message: "#^Parameter \\#1 \\$data of static method Webauthn\\\\Util\\\\Base64\\:\\:decode\\(\\) expects string, mixed given\\.$#"
count: 1
Expand Down Expand Up @@ -3292,3 +3352,16 @@ parameters:
message: "#^Parameter \\#1 \\$ecdaaKeyId of class Webauthn\\\\TrustPath\\\\EcdaaKeyIdTrustPath constructor expects string, mixed given\\.$#"
count: 1
path: src/webauthn/src/TrustPath/EcdaaKeyIdTrustPath.php

-
message: """
#^Instantiation of deprecated class Webauthn\\\\TrustPath\\\\EcdaaKeyIdTrustPath\\:
since 4\\.2\\.0 and will be removed in 5\\.0\\.0\\. The ECDAA Trust Anchor does no longer exist in Webauthn specification\\.$#
"""
count: 1
path: src/webauthn/src/TrustPath/TrustPathLoader.php

-
message: "#^Parameter \\#1 \\$certificates of static method Webauthn\\\\TrustPath\\\\CertificateTrustPath\\:\\:create\\(\\) expects array\\<string\\>, array given\\.$#"
count: 1
path: src/webauthn/src/TrustPath/TrustPathLoader.php
57 changes: 45 additions & 12 deletions src/symfony/src/DataCollector/WebauthnCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
use Symfony\Component\Serializer\Encoder\JsonEncode;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Throwable;
Expand Down Expand Up @@ -52,6 +56,11 @@ class WebauthnCollector extends DataCollector implements EventSubscriberInterfac
*/
private array $authenticatorAssertionResponseValidationFailed = [];

public function __construct(
private readonly SerializerInterface $serializer
) {
}

public function collect(Request $request, Response $response, ?Throwable $exception = null): void
{
$this->data = [
Expand Down Expand Up @@ -110,9 +119,13 @@ public function addPublicKeyCredentialCreationOptions(PublicKeyCredentialCreatio
$cloner = new VarCloner();
$this->publicKeyCredentialCreationOptions[] = [
'options' => $cloner->cloneVar($event->publicKeyCredentialCreationOptions),
'json' => json_encode(
'json' => $this->serializer->serialize(
$event->publicKeyCredentialCreationOptions,
JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT
JsonEncoder::FORMAT,
[
AbstractObjectNormalizer::SKIP_NULL_VALUES => true,
JsonEncode::OPTIONS => JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT,
]
),
];
}
Expand All @@ -124,9 +137,13 @@ public function addAuthenticatorAttestationResponseValidationSucceeded(
$this->authenticatorAttestationResponseValidationSucceeded[] = [
'attestation_response' => $cloner->cloneVar($event->authenticatorAttestationResponse),
'options' => $cloner->cloneVar($event->publicKeyCredentialCreationOptions),
'options_json' => json_encode(
'options_json' => $this->serializer->serialize(
$event->publicKeyCredentialCreationOptions,
JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT
JsonEncoder::FORMAT,
[
AbstractObjectNormalizer::SKIP_NULL_VALUES => true,
JsonEncode::OPTIONS => JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT,
]
),
'credential_source' => $cloner->cloneVar($event->publicKeyCredentialSource),
];
Expand All @@ -139,9 +156,13 @@ public function addAuthenticatorAttestationResponseValidationFailed(
$this->authenticatorAttestationResponseValidationFailed[] = [
'attestation_response' => $cloner->cloneVar($event->authenticatorAttestationResponse),
'options' => $cloner->cloneVar($event->publicKeyCredentialCreationOptions),
'options_json' => json_encode(
'options_json' => $this->serializer->serialize(
$event->publicKeyCredentialCreationOptions,
JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT
JsonEncoder::FORMAT,
[
AbstractObjectNormalizer::SKIP_NULL_VALUES => true,
JsonEncode::OPTIONS => JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT,
]
),
'exception' => $cloner->cloneVar($event->throwable),
];
Expand All @@ -152,9 +173,13 @@ public function addPublicKeyCredentialRequestOptions(PublicKeyCredentialRequestO
$cloner = new VarCloner();
$this->publicKeyCredentialRequestOptions[] = [
'options' => $cloner->cloneVar($event->publicKeyCredentialRequestOptions),
'json' => json_encode(
'json' => $this->serializer->serialize(
$event->publicKeyCredentialRequestOptions,
JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT
JsonEncoder::FORMAT,
[
AbstractObjectNormalizer::SKIP_NULL_VALUES => true,
JsonEncode::OPTIONS => JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT,
]
),
];
}
Expand All @@ -168,9 +193,13 @@ public function addAuthenticatorAssertionResponseValidationSucceeded(
'credential_id' => $cloner->cloneVar($event->credentialId),
'assertion_response' => $cloner->cloneVar($event->authenticatorAssertionResponse),
'options' => $cloner->cloneVar($event->publicKeyCredentialRequestOptions),
'options_json' => json_encode(
'options_json' => $this->serializer->serialize(
$event->publicKeyCredentialRequestOptions,
JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT
JsonEncoder::FORMAT,
[
AbstractObjectNormalizer::SKIP_NULL_VALUES => true,
JsonEncode::OPTIONS => JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT,
]
),
'credential_source' => $cloner->cloneVar($event->publicKeyCredentialSource),
];
Expand All @@ -185,9 +214,13 @@ public function addAuthenticatorAssertionResponseValidationFailed(
'credential_id' => $cloner->cloneVar($event->getCredential()?->publicKeyCredentialId),
'assertion_response' => $cloner->cloneVar($event->authenticatorAssertionResponse),
'options' => $cloner->cloneVar($event->publicKeyCredentialRequestOptions),
'options_json' => json_encode(
'options_json' => $this->serializer->serialize(
$event->publicKeyCredentialRequestOptions,
JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT
JsonEncoder::FORMAT,
[
AbstractObjectNormalizer::SKIP_NULL_VALUES => true,
JsonEncode::OPTIONS => JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT,
]
),
'exception' => $cloner->cloneVar($event->throwable),
];
Expand Down
2 changes: 2 additions & 0 deletions src/symfony/src/Resources/config/dev_services.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Webauthn\Bundle\DataCollector;

use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;

return static function (ContainerConfigurator $container): void {
$container = $container->services()
Expand All @@ -13,6 +14,7 @@
->autoconfigure();

$container->set(WebauthnCollector::class)
->args([service('serializer')])
->tag('data_collector', [
'id' => 'webauthn_collector',
'template' => '@Webauthn/data_collector/template.html.twig',
Expand Down
6 changes: 4 additions & 2 deletions src/symfony/src/Resources/config/security.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@
$container->set(DefaultFailureHandler::class);
$container->set(SessionStorage::class)->args([service('request_stack')]);
$container->set(CacheStorage::class)->args([service(CacheItemPoolInterface::class)]);
$container->set(DefaultCreationOptionsHandler::class);
$container->set(DefaultRequestOptionsHandler::class);
$container->set(DefaultCreationOptionsHandler::class)
->args([service('serializer')]);
$container->set(DefaultRequestOptionsHandler::class)
->args([service('serializer')]);
$container
->set(WebauthnFactory::AUTHENTICATOR_DEFINITION_ID, WebauthnAuthenticator::class)
->abstract()
Expand Down
18 changes: 18 additions & 0 deletions src/symfony/src/Resources/config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@
use Webauthn\Counter\ThrowExceptionIfInvalid;
use Webauthn\Denormalizer\AttestationObjectDenormalizer;
use Webauthn\Denormalizer\AttestationStatementDenormalizer;
use Webauthn\Denormalizer\AttestedCredentialDataNormalizer;
use Webauthn\Denormalizer\AuthenticationExtensionNormalizer;
use Webauthn\Denormalizer\AuthenticationExtensionsDenormalizer;
use Webauthn\Denormalizer\AuthenticatorAssertionResponseDenormalizer;
use Webauthn\Denormalizer\AuthenticatorAttestationResponseDenormalizer;
use Webauthn\Denormalizer\AuthenticatorDataDenormalizer;
use Webauthn\Denormalizer\AuthenticatorResponseDenormalizer;
use Webauthn\Denormalizer\CollectedClientDataDenormalizer;
use Webauthn\Denormalizer\PublicKeyCredentialDenormalizer;
use Webauthn\Denormalizer\PublicKeyCredentialDescriptorNormalizer;
use Webauthn\Denormalizer\PublicKeyCredentialOptionsDenormalizer;
use Webauthn\Denormalizer\PublicKeyCredentialSourceDenormalizer;
use Webauthn\Denormalizer\PublicKeyCredentialUserEntityDenormalizer;
Expand Down Expand Up @@ -209,6 +212,21 @@
->tag('serializer.normalizer', [
'priority' => 1024,
]);
$container
->set(AuthenticationExtensionNormalizer::class)
->tag('serializer.normalizer', [
'priority' => 1024,
]);
$container
->set(PublicKeyCredentialDescriptorNormalizer::class)
->tag('serializer.normalizer', [
'priority' => 1024,
]);
$container
->set(AttestedCredentialDataNormalizer::class)
->tag('serializer.normalizer', [
'priority' => 1024,
]);
$container
->set(AuthenticationExtensionsDenormalizer::class)
->tag('serializer.normalizer', [
Expand Down
18 changes: 11 additions & 7 deletions src/symfony/src/Security/Handler/DefaultCreationOptionsHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,27 @@
use RuntimeException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Webauthn\PublicKeyCredentialCreationOptions;
use Webauthn\PublicKeyCredentialUserEntity;
use function is_array;
use const JSON_THROW_ON_ERROR;

final class DefaultCreationOptionsHandler implements CreationOptionsHandler
{
public function __construct(
private readonly NormalizerInterface $normalizer
) {
}

public function onCreationOptions(
PublicKeyCredentialCreationOptions $publicKeyCredentialCreationOptions,
PublicKeyCredentialUserEntity $userEntity
): Response {
$data = json_decode(
json_encode($publicKeyCredentialCreationOptions, JSON_THROW_ON_ERROR),
true,
512,
JSON_THROW_ON_ERROR
);
$data = $this->normalizer->normalize($publicKeyCredentialCreationOptions, JsonEncoder::FORMAT, [
AbstractObjectNormalizer::SKIP_NULL_VALUES => true,
]);
is_array($data) || throw new RuntimeException('Unable to encode the response to JSON.');
$data['status'] = 'ok';
$data['errorMessage'] = '';
Expand Down
18 changes: 11 additions & 7 deletions src/symfony/src/Security/Handler/DefaultRequestOptionsHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,27 @@
use RuntimeException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Webauthn\PublicKeyCredentialRequestOptions;
use Webauthn\PublicKeyCredentialUserEntity;
use function is_array;
use const JSON_THROW_ON_ERROR;

final class DefaultRequestOptionsHandler implements RequestOptionsHandler
{
public function __construct(
private readonly NormalizerInterface $normalizer
) {
}

public function onRequestOptions(
PublicKeyCredentialRequestOptions $publicKeyCredentialRequestOptions,
?PublicKeyCredentialUserEntity $userEntity
): Response {
$data = json_decode(
json_encode($publicKeyCredentialRequestOptions, JSON_THROW_ON_ERROR),
true,
512,
JSON_THROW_ON_ERROR
);
$data = $this->normalizer->normalize($publicKeyCredentialRequestOptions, JsonEncoder::FORMAT, [
AbstractObjectNormalizer::SKIP_NULL_VALUES => true,
]);
is_array($data) || throw new RuntimeException('Unable to encode the response to JSON.');
$data['status'] = 'ok';
$data['errorMessage'] = '';
Expand Down
Loading

0 comments on commit abd4ca4

Please sign in to comment.