diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index bc26eb02..ac93686a 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -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\\: @@ -2474,7 +2509,7 @@ parameters: - message: "#^Cannot access offset 'clientDataJSON' on mixed\\.$#" - count: 3 + count: 2 path: src/webauthn/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php - @@ -2484,7 +2519,7 @@ parameters: - message: "#^Cannot access offset 'userHandle' on mixed\\.$#" - count: 3 + count: 1 path: src/webauthn/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php - @@ -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 @@ -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 @@ -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 @@ -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\\, array given\\.$#" + count: 1 + path: src/webauthn/src/TrustPath/TrustPathLoader.php diff --git a/src/symfony/src/DataCollector/WebauthnCollector.php b/src/symfony/src/DataCollector/WebauthnCollector.php index 3f4d3d73..2f7c4366 100644 --- a/src/symfony/src/DataCollector/WebauthnCollector.php +++ b/src/symfony/src/DataCollector/WebauthnCollector.php @@ -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; @@ -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 = [ @@ -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, + ] ), ]; } @@ -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), ]; @@ -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), ]; @@ -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, + ] ), ]; } @@ -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), ]; @@ -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), ]; diff --git a/src/symfony/src/Resources/config/dev_services.php b/src/symfony/src/Resources/config/dev_services.php index a472ffcd..2833b492 100644 --- a/src/symfony/src/Resources/config/dev_services.php +++ b/src/symfony/src/Resources/config/dev_services.php @@ -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() @@ -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', diff --git a/src/symfony/src/Resources/config/security.php b/src/symfony/src/Resources/config/security.php index 3e7c2ce1..2f664f75 100644 --- a/src/symfony/src/Resources/config/security.php +++ b/src/symfony/src/Resources/config/security.php @@ -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() diff --git a/src/symfony/src/Resources/config/services.php b/src/symfony/src/Resources/config/services.php index 45e93941..7f337d61 100644 --- a/src/symfony/src/Resources/config/services.php +++ b/src/symfony/src/Resources/config/services.php @@ -32,6 +32,8 @@ 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; @@ -39,6 +41,7 @@ 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; @@ -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', [ diff --git a/src/symfony/src/Security/Handler/DefaultCreationOptionsHandler.php b/src/symfony/src/Security/Handler/DefaultCreationOptionsHandler.php index b4e5a0c9..6a8fdb93 100644 --- a/src/symfony/src/Security/Handler/DefaultCreationOptionsHandler.php +++ b/src/symfony/src/Security/Handler/DefaultCreationOptionsHandler.php @@ -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'] = ''; diff --git a/src/symfony/src/Security/Handler/DefaultRequestOptionsHandler.php b/src/symfony/src/Security/Handler/DefaultRequestOptionsHandler.php index 3fdbad46..3c790e8e 100644 --- a/src/symfony/src/Security/Handler/DefaultRequestOptionsHandler.php +++ b/src/symfony/src/Security/Handler/DefaultRequestOptionsHandler.php @@ -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'] = ''; diff --git a/src/webauthn/src/AttestationStatement/AttestationStatement.php b/src/webauthn/src/AttestationStatement/AttestationStatement.php index 6f216783..4f300447 100644 --- a/src/webauthn/src/AttestationStatement/AttestationStatement.php +++ b/src/webauthn/src/AttestationStatement/AttestationStatement.php @@ -174,6 +174,12 @@ public static function createFromArray(array $data): self */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); return [ 'fmt' => $this->fmt, 'attStmt' => $this->attStmt, diff --git a/src/webauthn/src/AttestedCredentialData.php b/src/webauthn/src/AttestedCredentialData.php index a0d589d2..2f5d74f4 100644 --- a/src/webauthn/src/AttestedCredentialData.php +++ b/src/webauthn/src/AttestedCredentialData.php @@ -108,6 +108,12 @@ public static function createFromArray(array $json): self */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); $result = [ 'aaguid' => $this->aaguid->__toString(), 'credentialId' => base64_encode($this->credentialId), diff --git a/src/webauthn/src/AuthenticationExtensions/AuthenticationExtension.php b/src/webauthn/src/AuthenticationExtensions/AuthenticationExtension.php index 3f9ff6a2..3ed9dc0c 100644 --- a/src/webauthn/src/AuthenticationExtensions/AuthenticationExtension.php +++ b/src/webauthn/src/AuthenticationExtensions/AuthenticationExtension.php @@ -39,6 +39,12 @@ public function value(): mixed public function jsonSerialize(): mixed { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); return $this->value; } } diff --git a/src/webauthn/src/AuthenticationExtensions/AuthenticationExtensions.php b/src/webauthn/src/AuthenticationExtensions/AuthenticationExtensions.php index bedabbb5..9d7b2bed 100644 --- a/src/webauthn/src/AuthenticationExtensions/AuthenticationExtensions.php +++ b/src/webauthn/src/AuthenticationExtensions/AuthenticationExtensions.php @@ -109,6 +109,12 @@ public function get(string $key): AuthenticationExtension */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); return $this->extensions; } diff --git a/src/webauthn/src/AuthenticatorSelectionCriteria.php b/src/webauthn/src/AuthenticatorSelectionCriteria.php index 0bbad86f..8e47e92e 100644 --- a/src/webauthn/src/AuthenticatorSelectionCriteria.php +++ b/src/webauthn/src/AuthenticatorSelectionCriteria.php @@ -229,6 +229,12 @@ public static function createFromArray(array $json): self */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); $json = [ 'requireResidentKey' => $this->requireResidentKey, 'userVerification' => $this->userVerification, diff --git a/src/webauthn/src/Denormalizer/AttestedCredentialDataNormalizer.php b/src/webauthn/src/Denormalizer/AttestedCredentialDataNormalizer.php new file mode 100644 index 00000000..b46c57c3 --- /dev/null +++ b/src/webauthn/src/Denormalizer/AttestedCredentialDataNormalizer.php @@ -0,0 +1,42 @@ + $this->normalizer->normalize($data->aaguid, $format, $context), + 'credentialId' => base64_encode($data->credentialId), + ]; + if ($data->credentialPublicKey !== null) { + $result['credentialPublicKey'] = base64_encode($data->credentialPublicKey); + } + + return $result; + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof AttestedCredentialData; + } + + public function getSupportedTypes(?string $format): array + { + return [ + AttestedCredentialData::class => true, + ]; + } +} diff --git a/src/webauthn/src/Denormalizer/AuthenticationExtensionNormalizer.php b/src/webauthn/src/Denormalizer/AuthenticationExtensionNormalizer.php new file mode 100644 index 00000000..26102f55 --- /dev/null +++ b/src/webauthn/src/Denormalizer/AuthenticationExtensionNormalizer.php @@ -0,0 +1,34 @@ + + */ + public function getSupportedTypes(?string $format): array + { + return [ + AuthenticationExtension::class => true, + ]; + } + + public function normalize(mixed $data, ?string $format = null, array $context = []): array + { + assert($data instanceof AuthenticationExtension); + + return $data->value; + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof AuthenticationExtension; + } +} diff --git a/src/webauthn/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php b/src/webauthn/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php index 1f017ca2..613331c7 100644 --- a/src/webauthn/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php +++ b/src/webauthn/src/Denormalizer/AuthenticatorAssertionResponseDenormalizer.php @@ -25,14 +25,14 @@ public function denormalize(mixed $data, string $type, string $format = null, ar $data['clientDataJSON'] = Base64UrlSafe::decodeNoPadding($data['clientDataJSON']); $userHandle = $data['userHandle'] ?? null; if ($userHandle !== '' && $userHandle !== null) { - $data['userHandle'] = Base64::decode($userHandle); + $userHandle = Base64::decode($userHandle); } return AuthenticatorAssertionResponse::create( $this->denormalizer->denormalize($data['clientDataJSON'], CollectedClientData::class, $format, $context), $this->denormalizer->denormalize($data['authenticatorData'], AuthenticatorData::class, $format, $context), $data['signature'], - $data['userHandle'] ?? null, + $userHandle ?? null, ! isset($data['attestationObject']) ? null : $this->denormalizer->denormalize( $data['attestationObject'], AttestationObject::class, diff --git a/src/webauthn/src/Denormalizer/PublicKeyCredentialDescriptorNormalizer.php b/src/webauthn/src/Denormalizer/PublicKeyCredentialDescriptorNormalizer.php new file mode 100644 index 00000000..2accc307 --- /dev/null +++ b/src/webauthn/src/Denormalizer/PublicKeyCredentialDescriptorNormalizer.php @@ -0,0 +1,44 @@ + $data->type, + 'id' => Base64UrlSafe::encodeUnpadded($data->id), + ]; + if (count($data->transports) !== 0) { + $result['transports'] = $data->transports; + } + + return $result; + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof PublicKeyCredentialDescriptor; + } + + public function getSupportedTypes(?string $format): array + { + return [ + PublicKeyCredentialDescriptor::class => true, + ]; + } +} diff --git a/src/webauthn/src/Denormalizer/PublicKeyCredentialOptionsDenormalizer.php b/src/webauthn/src/Denormalizer/PublicKeyCredentialOptionsDenormalizer.php index fc35aff6..06657613 100644 --- a/src/webauthn/src/Denormalizer/PublicKeyCredentialOptionsDenormalizer.php +++ b/src/webauthn/src/Denormalizer/PublicKeyCredentialOptionsDenormalizer.php @@ -136,14 +136,18 @@ public function normalize(mixed $data, ?string $format = null, array $context = $json = [ 'challenge' => Base64UrlSafe::encodeUnpadded($data->challenge), 'timeout' => $data->timeout, - 'extensions' => $this->normalizer->normalize($data->extensions, $format, $context), + 'extensions' => $data->extensions->count() === 0 ? null : $this->normalizer->normalize( + $data->extensions, + $format, + $context + ), ]; if ($data instanceof PublicKeyCredentialCreationOptions) { $json = [ ...$json, - 'rp' => $this->normalizer->normalize($data->rp, PublicKeyCredentialRpEntity::class, $context), - 'user' => $this->normalizer->normalize($data->user, PublicKeyCredentialUserEntity::class, $context), + 'rp' => $this->normalizer->normalize($data->rp, $format, $context), + 'user' => $this->normalizer->normalize($data->user, $format, $context), 'pubKeyCredParams' => $this->normalizer->normalize( $data->pubKeyCredParams, PublicKeyCredentialParameters::class . '[]', @@ -151,26 +155,18 @@ public function normalize(mixed $data, ?string $format = null, array $context = ), 'authenticatorSelection' => $data->authenticatorSelection === null ? null : $this->normalizer->normalize( $data->authenticatorSelection, - AuthenticatorSelectionCriteria::class, + $format, $context ), 'attestation' => $data->attestation, - 'excludeCredentials' => $this->normalizer->normalize( - $data->excludeCredentials, - PublicKeyCredentialDescriptor::class . '[]', - $context - ), + 'excludeCredentials' => $this->normalizer->normalize($data->excludeCredentials, $format, $context), ]; } if ($data instanceof PublicKeyCredentialRequestOptions) { $json = [ ...$json, 'rpId' => $data->rpId, - 'allowCredentials' => $this->normalizer->normalize( - $data->allowCredentials, - PublicKeyCredentialDescriptor::class . '[]', - $context - ), + 'allowCredentials' => $this->normalizer->normalize($data->allowCredentials, $format, $context), 'userVerification' => $data->userVerification, ]; } diff --git a/src/webauthn/src/Denormalizer/PublicKeyCredentialSourceDenormalizer.php b/src/webauthn/src/Denormalizer/PublicKeyCredentialSourceDenormalizer.php index df599248..51018d8f 100644 --- a/src/webauthn/src/Denormalizer/PublicKeyCredentialSourceDenormalizer.php +++ b/src/webauthn/src/Denormalizer/PublicKeyCredentialSourceDenormalizer.php @@ -4,18 +4,24 @@ namespace Webauthn\Denormalizer; +use ParagonIE\ConstantTime\Base64UrlSafe; use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface; use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Uid\Uuid; use Webauthn\Exception\InvalidDataException; use Webauthn\PublicKeyCredentialSource; use Webauthn\TrustPath\TrustPath; use Webauthn\Util\Base64; use function array_key_exists; +use function assert; -final class PublicKeyCredentialSourceDenormalizer implements DenormalizerInterface, DenormalizerAwareInterface +final class PublicKeyCredentialSourceDenormalizer implements DenormalizerInterface, DenormalizerAwareInterface, NormalizerInterface, NormalizerAwareInterface { + use NormalizerAwareTrait; use DenormalizerAwareTrait; public function denormalize(mixed $data, string $type, string $format = null, array $context = []): mixed @@ -57,4 +63,31 @@ public function getSupportedTypes(?string $format): array PublicKeyCredentialSource::class => true, ]; } + + public function normalize(mixed $data, ?string $format = null, array $context = []): array + { + assert($data instanceof PublicKeyCredentialSource); + $result = [ + 'publicKeyCredentialId' => Base64UrlSafe::encodeUnpadded($data->publicKeyCredentialId), + 'type' => $data->type, + 'transports' => $data->transports, + 'attestationType' => $data->attestationType, + 'trustPath' => $this->normalizer->normalize($data->trustPath, $format, $context), + 'aaguid' => $this->normalizer->normalize($data->aaguid, $format, $context), + 'credentialPublicKey' => Base64UrlSafe::encodeUnpadded($data->credentialPublicKey), + 'userHandle' => Base64UrlSafe::encodeUnpadded($data->userHandle), + 'counter' => $data->counter, + 'otherUI' => $data->otherUI, + 'backupEligible' => $data->backupEligible, + 'backupStatus' => $data->backupStatus, + 'uvInitialized' => $data->uvInitialized, + ]; + + return array_filter($result, static fn ($value): bool => $value !== null); + } + + public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool + { + return $data instanceof PublicKeyCredentialSource; + } } diff --git a/src/webauthn/src/Denormalizer/WebauthnSerializerFactory.php b/src/webauthn/src/Denormalizer/WebauthnSerializerFactory.php index 304cd035..694039a0 100644 --- a/src/webauthn/src/Denormalizer/WebauthnSerializerFactory.php +++ b/src/webauthn/src/Denormalizer/WebauthnSerializerFactory.php @@ -42,6 +42,9 @@ public function create(): SerializerInterface } $denormalizers = [ + new AuthenticationExtensionNormalizer(), + new PublicKeyCredentialDescriptorNormalizer(), + new AttestedCredentialDataNormalizer(), new AttestationObjectDenormalizer(), new AttestationStatementDenormalizer($this->attestationStatementSupportManager), new AuthenticationExtensionsDenormalizer(), diff --git a/src/webauthn/src/PublicKeyCredential.php b/src/webauthn/src/PublicKeyCredential.php index 778d138b..8e09ad65 100644 --- a/src/webauthn/src/PublicKeyCredential.php +++ b/src/webauthn/src/PublicKeyCredential.php @@ -23,7 +23,7 @@ public function __construct( } /** - * @deprecated since 4.8.0. Please use the PublicKeyCredentialDescriptor ({self::getPublicKeyCredentialDescriptor}) instead. + * @deprecated since 4.8.0. * @infection-ignore-all */ public function __toString(): string diff --git a/src/webauthn/src/PublicKeyCredentialCreationOptions.php b/src/webauthn/src/PublicKeyCredentialCreationOptions.php index 1a20ee5e..d6088e97 100644 --- a/src/webauthn/src/PublicKeyCredentialCreationOptions.php +++ b/src/webauthn/src/PublicKeyCredentialCreationOptions.php @@ -313,6 +313,12 @@ public static function createFromArray(array $json): static */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); $json = [ 'rp' => $this->rp, 'user' => $this->user, diff --git a/src/webauthn/src/PublicKeyCredentialDescriptor.php b/src/webauthn/src/PublicKeyCredentialDescriptor.php index ba38446e..eac25690 100644 --- a/src/webauthn/src/PublicKeyCredentialDescriptor.php +++ b/src/webauthn/src/PublicKeyCredentialDescriptor.php @@ -107,6 +107,12 @@ public static function createFromArray(array $json): self */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); $json = [ 'type' => $this->type, 'id' => Base64UrlSafe::encodeUnpadded($this->id), diff --git a/src/webauthn/src/PublicKeyCredentialParameters.php b/src/webauthn/src/PublicKeyCredentialParameters.php index 62cfa053..1eab10d5 100644 --- a/src/webauthn/src/PublicKeyCredentialParameters.php +++ b/src/webauthn/src/PublicKeyCredentialParameters.php @@ -83,6 +83,12 @@ public static function createFromArray(array $json): self */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); return [ 'type' => $this->type, 'alg' => $this->alg, diff --git a/src/webauthn/src/PublicKeyCredentialRequestOptions.php b/src/webauthn/src/PublicKeyCredentialRequestOptions.php index 4016f34f..a74d97b3 100644 --- a/src/webauthn/src/PublicKeyCredentialRequestOptions.php +++ b/src/webauthn/src/PublicKeyCredentialRequestOptions.php @@ -204,6 +204,12 @@ public static function createFromArray(array $json): static */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); $json = [ 'challenge' => Base64UrlSafe::encodeUnpadded($this->challenge), ]; diff --git a/src/webauthn/src/PublicKeyCredentialRpEntity.php b/src/webauthn/src/PublicKeyCredentialRpEntity.php index 1720462b..bb40b539 100644 --- a/src/webauthn/src/PublicKeyCredentialRpEntity.php +++ b/src/webauthn/src/PublicKeyCredentialRpEntity.php @@ -51,6 +51,12 @@ public static function createFromArray(array $json): self */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); $json = parent::jsonSerialize(); if ($this->id !== null) { $json['id'] = $this->id; diff --git a/src/webauthn/src/PublicKeyCredentialSource.php b/src/webauthn/src/PublicKeyCredentialSource.php index de55bb10..ca94d8a5 100644 --- a/src/webauthn/src/PublicKeyCredentialSource.php +++ b/src/webauthn/src/PublicKeyCredentialSource.php @@ -248,7 +248,13 @@ public static function createFromArray(array $data): self */ public function jsonSerialize(): array { - return [ + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); + $result = [ 'publicKeyCredentialId' => Base64UrlSafe::encodeUnpadded($this->publicKeyCredentialId), 'type' => $this->type, 'transports' => $this->transports, @@ -263,5 +269,7 @@ public function jsonSerialize(): array 'backupStatus' => $this->backupStatus, 'uvInitialized' => $this->uvInitialized, ]; + + return array_filter($result, static fn ($value): bool => $value !== null); } } diff --git a/src/webauthn/src/PublicKeyCredentialUserEntity.php b/src/webauthn/src/PublicKeyCredentialUserEntity.php index 53f147d8..b5c75ee3 100644 --- a/src/webauthn/src/PublicKeyCredentialUserEntity.php +++ b/src/webauthn/src/PublicKeyCredentialUserEntity.php @@ -87,6 +87,12 @@ public static function createFromArray(array $json): self */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); $json = parent::jsonSerialize(); $json['id'] = Base64UrlSafe::encodeUnpadded($this->id); $json['displayName'] = $this->displayName; diff --git a/src/webauthn/src/TrustPath/CertificateTrustPath.php b/src/webauthn/src/TrustPath/CertificateTrustPath.php index 796511c5..5bc39fbf 100644 --- a/src/webauthn/src/TrustPath/CertificateTrustPath.php +++ b/src/webauthn/src/TrustPath/CertificateTrustPath.php @@ -56,6 +56,12 @@ public static function createFromArray(array $data): static */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); return [ 'type' => self::class, 'x5c' => $this->certificates, diff --git a/src/webauthn/src/TrustPath/EmptyTrustPath.php b/src/webauthn/src/TrustPath/EmptyTrustPath.php index 74410336..a91a6121 100644 --- a/src/webauthn/src/TrustPath/EmptyTrustPath.php +++ b/src/webauthn/src/TrustPath/EmptyTrustPath.php @@ -16,6 +16,12 @@ public static function create(): self */ public function jsonSerialize(): array { + trigger_deprecation( + 'web-auth/webauthn-bundle', + '4.9.0', + 'The "%s" method is deprecated and will be removed in 5.0. The serializer instead.', + __METHOD__ + ); return [ 'type' => self::class, ]; diff --git a/src/webauthn/src/TrustPath/TrustPathLoader.php b/src/webauthn/src/TrustPath/TrustPathLoader.php index e06b1551..b79675bc 100644 --- a/src/webauthn/src/TrustPath/TrustPathLoader.php +++ b/src/webauthn/src/TrustPath/TrustPathLoader.php @@ -6,8 +6,8 @@ use Webauthn\Exception\InvalidTrustPathException; use function array_key_exists; -use function class_implements; -use function in_array; +use function is_array; +use function is_string; final class TrustPathLoader { @@ -16,18 +16,15 @@ final class TrustPathLoader */ public static function loadTrustPath(array $data): TrustPath { - array_key_exists('type', $data) || throw InvalidTrustPathException::create('The trust path type is missing'); - $type = $data['type']; - if (class_exists($type) !== true) { - throw InvalidTrustPathException::create( - sprintf('The trust path type "%s" is not supported', $data['type']) - ); - } - - $implements = class_implements($type); - if (in_array(TrustPath::class, $implements, true)) { - return $type::createFromArray($data); - } - throw InvalidTrustPathException::create(sprintf('The trust path type "%s" is not supported', $data['type'])); + return match (true) { + $data === [] || $data === [ + 'type' => EmptyTrustPath::class, + ] => EmptyTrustPath::create(), + array_key_exists('x5c', $data) && is_array($data['x5c']) => CertificateTrustPath::create($data['x5c']), + array_key_exists('ecdaaKeyId', $data) && is_string($data['ecdaaKeyId']) => new EcdaaKeyIdTrustPath( + $data['ecdaaKeyId'] + ), + default => throw InvalidTrustPathException::create('Unsupported trust path'), + }; } } diff --git a/tests/library/AbstractTestCase.php b/tests/library/AbstractTestCase.php index f90b2928..48fc750e 100644 --- a/tests/library/AbstractTestCase.php +++ b/tests/library/AbstractTestCase.php @@ -20,6 +20,7 @@ use Webauthn\AttestationStatement\AndroidKeyAttestationStatementSupport; use Webauthn\AttestationStatement\AndroidSafetyNetAttestationStatementSupport; use Webauthn\AttestationStatement\AppleAttestationStatementSupport; +use Webauthn\AttestationStatement\AttestationObjectLoader; use Webauthn\AttestationStatement\AttestationStatementSupportManager; use Webauthn\AttestationStatement\FidoU2FAttestationStatementSupport; use Webauthn\AttestationStatement\NoneAttestationStatementSupport; @@ -36,6 +37,7 @@ use Webauthn\MetadataService\Service\ChainedMetadataServices; use Webauthn\MetadataService\Service\JsonMetadataService; use Webauthn\MetadataService\Service\LocalResourceMetadataService; +use Webauthn\PublicKeyCredentialLoader; use Webauthn\Tests\Bundle\Functional\MockClock; use Webauthn\Tests\Functional\MetadataStatementRepository; use Webauthn\Tests\Functional\StatusReportRepository; @@ -152,6 +154,13 @@ protected function getSerializer(): SerializerInterface return $this->webauthnSerializer; } + protected function getLegacyLoader(): PublicKeyCredentialLoader + { + return new PublicKeyCredentialLoader(new AttestationObjectLoader( + $this->getAttestationStatementSupportManager() + )); + } + private function getAttestationStatementSupportManager(): AttestationStatementSupportManager { $attestationStatementSupportManager = new AttestationStatementSupportManager(); diff --git a/tests/library/Functional/AssertionTest.php b/tests/library/Functional/AssertionTest.php index 605ffc74..62e392b4 100644 --- a/tests/library/Functional/AssertionTest.php +++ b/tests/library/Functional/AssertionTest.php @@ -69,6 +69,23 @@ public function anAssertionCanBeVerified(): void static::assertSame(123, $publicKeyCredentialSource->counter); } + #[Test] + public function serializerAndLegacyMethodGiveTheSameResult(): void + { + // Given + $input = '{"id":"ADqYfFWXiscOCOPCd9OLiBtSGhletNPKlSOELS0Nuwj_uCzf9s3trLUK9ockO8xa8jBAYdKixLZYOAezy0FJiV1bnTCty_LiInWWJlov","type":"public-key","rawId":"ADqYfFWXiscOCOPCd9OLiBtSGhletNPKlSOELS0Nuwj/uCzf9s3trLUK9ockO8xa8jBAYdKixLZYOAezy0FJiV1bnTCty/LiInWWJlov","response":{"authenticatorData":"tIXbbgSILsWHHbR0Fjkl96X4ROZYLvVtOopBWCQoAqpFXFBJyQAAAAAAAAAAAAAAAAAAAAAATgA6mHxVl4rHDgjjwnfTi4gbUhoZXrTTypUjhC0tDbsI_7gs3_bN7ay1CvaHJDvMWvIwQGHSosS2WDgHs8tBSYldW50wrcvy4iJ1liZaL6UBAgMmIAEhWCAIpUDJSoLScguLRDKBEc32v682i6RPjy6SFZnFTBj2QSJYIG8DS0CpphjyFyZB9xyCTrKDsr_S5iX5hhidWLRdP_7B","clientDataJSON":"eyJjaGFsbGVuZ2UiOiJ3S2xXN1MzRUVOSGxjRjJOZ1loZFVKZlJKZUN2QXZsYmstTWxsdnhvMEhBIiwib3JpZ2luIjoiaHR0cHM6Ly9zcG9ta3ktd2ViYXV0aG4uaGVyb2t1YXBwLmNvbSIsInR5cGUiOiJ3ZWJhdXRobi5nZXQifQ","signature":"MEQCIBnVPX8inAXIxXAsMdF6nW6nZJa36G1O+G9JXiauenxBAiBU4MQoRWxiXGn0TcKTkRJafZ58KLqeCJiB2VFAplwPJA==","userHandle":"YWJmYzhmZGYtMDdmNi00NWE5LWFiZWMtZmExOTIyNzViMjc2"}}'; + + //When + $publicKeyCredential1 = $this->getSerializer() + ->deserialize($input, PublicKeyCredential::class, 'json'); + $publicKeyCredential2 = $this->getLegacyLoader() + ->load($input); + + //Then + static::assertEquals($publicKeyCredential1, $publicKeyCredential2); + + } + #[Test] public function anAssertionWithTokenBindingCanBeVerified(): void { diff --git a/tests/library/Unit/AttestedCredentialDataTest.php b/tests/library/Unit/AttestedCredentialDataTest.php index 6a863a65..be8a13ef 100644 --- a/tests/library/Unit/AttestedCredentialDataTest.php +++ b/tests/library/Unit/AttestedCredentialDataTest.php @@ -6,20 +6,21 @@ use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; -use PHPUnit\Framework\TestCase; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Symfony\Component\Uid\Uuid; use Webauthn\AttestedCredentialData; -use const JSON_UNESCAPED_SLASHES; +use Webauthn\Tests\AbstractTestCase; /** * @internal */ -final class AttestedCredentialDataTest extends TestCase +final class AttestedCredentialDataTest extends AbstractTestCase { #[Test] #[DataProvider('dataAAGUID')] public function anAttestedCredentialDataCanBeCreatedAndValueAccessed(string $uuid): void { + // Given $attestedCredentialData = AttestedCredentialData::create(Uuid::fromString( $uuid ), 'credential_id', 'credential_public_key'); @@ -29,7 +30,10 @@ public function anAttestedCredentialDataCanBeCreatedAndValueAccessed(string $uui static::assertSame('credential_public_key', $attestedCredentialData->credentialPublicKey); static::assertSame( '{"aaguid":"' . $uuid . '","credentialId":"Y3JlZGVudGlhbF9pZA==","credentialPublicKey":"Y3JlZGVudGlhbF9wdWJsaWNfa2V5"}', - json_encode($attestedCredentialData, JSON_UNESCAPED_SLASHES) + $this->getSerializer() + ->serialize($attestedCredentialData, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]) ); json_decode( diff --git a/tests/library/Unit/AuthenticationExtensions/AuthenticationExtensionsClientOutputsLoaderTest.php b/tests/library/Unit/AuthenticationExtensions/AuthenticationExtensionsClientOutputsLoaderTest.php index 1fb97af2..1ea8e2cd 100644 --- a/tests/library/Unit/AuthenticationExtensions/AuthenticationExtensionsClientOutputsLoaderTest.php +++ b/tests/library/Unit/AuthenticationExtensions/AuthenticationExtensionsClientOutputsLoaderTest.php @@ -9,16 +9,16 @@ use CBOR\MapObject; use CBOR\OtherObject\TrueObject; use PHPUnit\Framework\Attributes\Test; -use PHPUnit\Framework\TestCase; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientOutputs; use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientOutputsLoader; use Webauthn\Exception\AuthenticationExtensionException; -use const JSON_THROW_ON_ERROR; +use Webauthn\Tests\AbstractTestCase; /** * @internal */ -final class AuthenticationExtensionsClientOutputsLoaderTest extends TestCase +final class AuthenticationExtensionsClientOutputsLoaderTest extends AbstractTestCase { #[Test] public function theExtensionsCanBeLoaded(): void @@ -29,7 +29,9 @@ public function theExtensionsCanBeLoaded(): void static::assertInstanceOf(AuthenticationExtensionsClientOutputs::class, $extensions); static::assertCount(1, $extensions); - static::assertSame('{"loc":true}', json_encode($extensions, JSON_THROW_ON_ERROR)); + static::assertSame('{"loc":true}', $this->getSerializer()->serialize($extensions, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ])); } #[Test] diff --git a/tests/library/Unit/AuthenticationExtensions/AuthenticationExtensionsClientTest.php b/tests/library/Unit/AuthenticationExtensions/AuthenticationExtensionsClientTest.php index 18ad55d6..dc8118f7 100644 --- a/tests/library/Unit/AuthenticationExtensions/AuthenticationExtensionsClientTest.php +++ b/tests/library/Unit/AuthenticationExtensions/AuthenticationExtensionsClientTest.php @@ -5,16 +5,16 @@ namespace Webauthn\Tests\Unit\AuthenticationExtensions; use PHPUnit\Framework\Attributes\Test; -use PHPUnit\Framework\TestCase; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Webauthn\AuthenticationExtensions\AuthenticationExtension; use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs; use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientOutputs; -use const JSON_THROW_ON_ERROR; +use Webauthn\Tests\AbstractTestCase; /** * @internal */ -final class AuthenticationExtensionsClientTest extends TestCase +final class AuthenticationExtensionsClientTest extends AbstractTestCase { #[Test] public function anAuthenticationExtensionsClientCanBeCreatedAndValueAccessed(): void @@ -23,7 +23,9 @@ public function anAuthenticationExtensionsClientCanBeCreatedAndValueAccessed(): static::assertSame('name', $extension->name); static::assertSame(['value'], $extension->value); - static::assertSame('["value"]', json_encode($extension, JSON_THROW_ON_ERROR)); + static::assertSame('["value"]', $this->getSerializer()->serialize($extension, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ])); } #[Test] @@ -34,7 +36,9 @@ public function theAuthenticationExtensionsClientInputsCanManageExtensions(): vo ]); static::assertSame(1, $inputs->count()); - static::assertSame('{"name":["value"]}', json_encode($inputs, JSON_THROW_ON_ERROR)); + static::assertSame('{"name":["value"]}', $this->getSerializer()->serialize($inputs, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ])); static::assertContainsOnlyInstancesOf(AuthenticationExtension::class, $inputs); } @@ -46,7 +50,9 @@ public function theAuthenticationExtensionsClientOutputsCanManageExtensions(): v ]); static::assertSame(1, $inputs->count()); - static::assertSame('{"name":["value"]}', json_encode($inputs, JSON_THROW_ON_ERROR)); + static::assertSame('{"name":["value"]}', $this->getSerializer()->serialize($inputs, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ])); static::assertContainsOnlyInstancesOf(AuthenticationExtension::class, $inputs); } } diff --git a/tests/library/Unit/AuthenticatorSelectionCriteriaTest.php b/tests/library/Unit/AuthenticatorSelectionCriteriaTest.php index f03aae89..4ea84046 100644 --- a/tests/library/Unit/AuthenticatorSelectionCriteriaTest.php +++ b/tests/library/Unit/AuthenticatorSelectionCriteriaTest.php @@ -5,9 +5,9 @@ namespace Webauthn\Tests\Unit; use PHPUnit\Framework\Attributes\Test; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Webauthn\AuthenticatorSelectionCriteria; use Webauthn\Tests\AbstractTestCase; -use const JSON_THROW_ON_ERROR; /** * @internal @@ -27,7 +27,9 @@ public function anAuthenticatorSelectionCriteriaCanBeCreatedAndValueAccessed(): //When $data = $this->getSerializer() - ->deserialize($expectedJson, AuthenticatorSelectionCriteria::class, 'json'); + ->deserialize($expectedJson, AuthenticatorSelectionCriteria::class, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]); //Then static::assertSame( @@ -40,15 +42,23 @@ public function anAuthenticatorSelectionCriteriaCanBeCreatedAndValueAccessed(): ); static::assertNull($data->requireResidentKey); static::assertSame(AuthenticatorSelectionCriteria::RESIDENT_KEY_REQUIREMENT_NO_PREFERENCE, $data->residentKey); - static::assertSame($expectedJson, json_encode($data, JSON_THROW_ON_ERROR)); - static::assertSame($expectedJson, json_encode($authenticatorSelectionCriteria, JSON_THROW_ON_ERROR)); + static::assertJsonStringEqualsJsonString($expectedJson, $this->getSerializer()->serialize($data, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ])); + static::assertJsonStringEqualsJsonString( + $expectedJson, + $this->getSerializer() + ->serialize($authenticatorSelectionCriteria, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]) + ); } #[Test] public function anAuthenticatorSelectionCriteriaWithResidentKeyCanBeCreatedAndValueAccessed(): void { // Given - $expectedJson = '{"requireResidentKey":true,"userVerification":"required","residentKey":"required","authenticatorAttachment":"platform"}'; + $expectedJson = '{"authenticatorAttachment":"platform","requireResidentKey":true,"userVerification":"required","residentKey":"required"}'; $authenticatorSelectionCriteria = AuthenticatorSelectionCriteria::create( AuthenticatorSelectionCriteria::AUTHENTICATOR_ATTACHMENT_PLATFORM, AuthenticatorSelectionCriteria::USER_VERIFICATION_REQUIREMENT_REQUIRED, @@ -58,7 +68,9 @@ public function anAuthenticatorSelectionCriteriaWithResidentKeyCanBeCreatedAndVa //When $data = $this->getSerializer() - ->deserialize($expectedJson, AuthenticatorSelectionCriteria::class, 'json'); + ->deserialize($expectedJson, AuthenticatorSelectionCriteria::class, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]); //Then static::assertSame( @@ -71,7 +83,11 @@ public function anAuthenticatorSelectionCriteriaWithResidentKeyCanBeCreatedAndVa ); static::assertTrue($data->requireResidentKey); static::assertSame(AuthenticatorSelectionCriteria::RESIDENT_KEY_REQUIREMENT_REQUIRED, $data->residentKey); - static::assertSame($expectedJson, json_encode($data, JSON_THROW_ON_ERROR)); - static::assertSame($expectedJson, json_encode($authenticatorSelectionCriteria, JSON_THROW_ON_ERROR)); + static::assertSame($expectedJson, $this->getSerializer()->serialize($data, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ])); + static::assertSame($expectedJson, $this->getSerializer()->serialize($authenticatorSelectionCriteria, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ])); } } diff --git a/tests/library/Unit/EntityTest.php b/tests/library/Unit/EntityTest.php index 4363f96f..9b5661f6 100644 --- a/tests/library/Unit/EntityTest.php +++ b/tests/library/Unit/EntityTest.php @@ -5,15 +5,15 @@ namespace Webauthn\Tests\Unit; use PHPUnit\Framework\Attributes\Test; -use PHPUnit\Framework\TestCase; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Webauthn\PublicKeyCredentialRpEntity; use Webauthn\PublicKeyCredentialUserEntity; -use const JSON_THROW_ON_ERROR; +use Webauthn\Tests\AbstractTestCase; /** * @internal */ -final class EntityTest extends TestCase +final class EntityTest extends AbstractTestCase { #[Test] public function anPublicKeyCredentialUserEntityCanBeCreatedAndValueAccessed(): void @@ -25,8 +25,11 @@ public function anPublicKeyCredentialUserEntityCanBeCreatedAndValueAccessed(): v static::assertSame('icon', $user->icon); static::assertSame('id', $user->id); static::assertSame( - '{"name":"name","icon":"icon","id":"aWQ","displayName":"display_name"}', - json_encode($user, JSON_THROW_ON_ERROR) + '{"id":"aWQ","name":"name","displayName":"display_name","icon":"icon"}', + $this->getSerializer() + ->serialize($user, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]) ); } @@ -38,6 +41,8 @@ public function anPublicKeyCredentialRpEntityCanBeCreatedAndValueAccessed(): voi static::assertSame('name', $rp->name); static::assertSame('icon', $rp->icon); static::assertSame('id', $rp->id); - static::assertSame('{"name":"name","icon":"icon","id":"id"}', json_encode($rp, JSON_THROW_ON_ERROR)); + static::assertSame('{"id":"id","name":"name","icon":"icon"}', $this->getSerializer()->serialize($rp, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ])); } } diff --git a/tests/library/Unit/PublicKeyCredentialCreationOptionsTest.php b/tests/library/Unit/PublicKeyCredentialCreationOptionsTest.php index 0f60119f..2164f342 100644 --- a/tests/library/Unit/PublicKeyCredentialCreationOptionsTest.php +++ b/tests/library/Unit/PublicKeyCredentialCreationOptionsTest.php @@ -5,13 +5,13 @@ namespace Webauthn\Tests\Unit; use PHPUnit\Framework\Attributes\Test; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Webauthn\PublicKeyCredentialCreationOptions; use Webauthn\PublicKeyCredentialDescriptor; use Webauthn\PublicKeyCredentialParameters; use Webauthn\PublicKeyCredentialRpEntity; use Webauthn\PublicKeyCredentialUserEntity; use Webauthn\Tests\AbstractTestCase; -use const JSON_THROW_ON_ERROR; /** * @internal @@ -42,9 +42,12 @@ public function anPublicKeyCredentialCreationOptionsCanBeCreatedAndValueAccessed static::assertSame([$credentialParameters], $options->pubKeyCredParams); static::assertSame('direct', $options->attestation); static::assertSame(1000, $options->timeout); - static::assertSame( + static::assertJsonStringEqualsJsonString( '{"rp":{"name":"RP"},"user":{"name":"USER","id":"aWQ","displayName":"FOO BAR"},"challenge":"Y2hhbGxlbmdl","pubKeyCredParams":[{"type":"type","alg":-100}],"timeout":1000,"excludeCredentials":[{"type":"type","id":"aWQ","transports":["transport"]}],"attestation":"direct"}', - json_encode($options, JSON_THROW_ON_ERROR) + $this->getSerializer() + ->serialize($options, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]) ); $data = $this->getSerializer() @@ -56,9 +59,12 @@ public function anPublicKeyCredentialCreationOptionsCanBeCreatedAndValueAccessed static::assertSame('challenge', $data->challenge); static::assertSame('direct', $data->attestation); static::assertSame(1000, $data->timeout); - static::assertSame( + static::assertJsonStringEqualsJsonString( '{"rp":{"name":"RP"},"user":{"name":"USER","id":"aWQ","displayName":"FOO BAR"},"challenge":"Y2hhbGxlbmdl","pubKeyCredParams":[{"type":"type","alg":-100}],"timeout":1000,"excludeCredentials":[{"type":"type","id":"aWQ","transports":["transport"]}],"authenticatorSelection":{"requireResidentKey":false,"userVerification":"preferred","residentKey":"preferred"},"attestation":"direct"}', - json_encode($data, JSON_THROW_ON_ERROR) + $this->getSerializer() + ->serialize($data, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]) ); } @@ -79,15 +85,19 @@ public function anPublicKeyCredentialCreationOptionsWithoutExcludeCredentialsCan timeout: 1000 ); - $json = json_encode($options, JSON_THROW_ON_ERROR); - static::assertSame( - // '{"rp":{"name":"RP"},"pubKeyCredParams":[{"type":"type","alg":-100}],"challenge":"Y2hhbGxlbmdl","attestation":"indirect","user":{"name":"USER","id":"aWQ","displayName":"FOO BAR"},"authenticatorSelection":{"requireResidentKey":false,"userVerification":"preferred","residentKey":"preferred"},"excludeCredentials":[],"timeout":1000}', // TODO: On hold. Waiting for issue clarification. See https://github.com/fido-alliance/conformance-test-tools-resources/issues/676 + $json = $this->getSerializer() + ->serialize($options, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]); + static::assertJsonStringEqualsJsonString( '{"rp":{"name":"RP"},"user":{"name":"USER","id":"aWQ","displayName":"FOO BAR"},"challenge":"Y2hhbGxlbmdl","pubKeyCredParams":[{"type":"type","alg":-100}],"timeout":1000,"attestation":"indirect"}', $json ); $data = $this->getSerializer() - ->deserialize($json, PublicKeyCredentialCreationOptions::class, 'json'); + ->deserialize($json, PublicKeyCredentialCreationOptions::class, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]); static::assertSame([], $data->excludeCredentials); } } diff --git a/tests/library/Unit/PublicKeyCredentialDescriptorTest.php b/tests/library/Unit/PublicKeyCredentialDescriptorTest.php index 77d6c294..99ab9b7e 100644 --- a/tests/library/Unit/PublicKeyCredentialDescriptorTest.php +++ b/tests/library/Unit/PublicKeyCredentialDescriptorTest.php @@ -5,14 +5,14 @@ namespace Webauthn\Tests\Unit; use PHPUnit\Framework\Attributes\Test; -use PHPUnit\Framework\TestCase; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Webauthn\PublicKeyCredentialDescriptor; -use const JSON_THROW_ON_ERROR; +use Webauthn\Tests\AbstractTestCase; /** * @internal */ -final class PublicKeyCredentialDescriptorTest extends TestCase +final class PublicKeyCredentialDescriptorTest extends AbstractTestCase { #[Test] public function anPublicKeyCredentialDescriptorCanBeCreatedAndValueAccessed(): void @@ -24,7 +24,10 @@ public function anPublicKeyCredentialDescriptorCanBeCreatedAndValueAccessed(): v static::assertSame(['transport'], $descriptor->transports); static::assertSame( '{"type":"type","id":"aWQ","transports":["transport"]}', - json_encode($descriptor, JSON_THROW_ON_ERROR) + $this->getSerializer() + ->serialize($descriptor, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]) ); } } diff --git a/tests/library/Unit/PublicKeyCredentialParametersTest.php b/tests/library/Unit/PublicKeyCredentialParametersTest.php index 01632248..7ba1789f 100644 --- a/tests/library/Unit/PublicKeyCredentialParametersTest.php +++ b/tests/library/Unit/PublicKeyCredentialParametersTest.php @@ -5,9 +5,9 @@ namespace Webauthn\Tests\Unit; use PHPUnit\Framework\Attributes\Test; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Webauthn\PublicKeyCredentialParameters; use Webauthn\Tests\AbstractTestCase; -use const JSON_THROW_ON_ERROR; /** * @internal @@ -21,12 +21,16 @@ public function aPublicKeyCredentialParametersCanBeCreatedAndValueAccessed(): vo static::assertSame('type', $parameters->type); static::assertSame(100, $parameters->alg); - static::assertSame('{"type":"type","alg":100}', json_encode($parameters, JSON_THROW_ON_ERROR)); + static::assertSame('{"type":"type","alg":100}', $this->getSerializer()->serialize($parameters, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ])); $data = $this->getSerializer() ->deserialize('{"type":"type","alg":100}', PublicKeyCredentialParameters::class, 'json'); static::assertSame('type', $data->type); static::assertSame(100, $data->alg); - static::assertSame('{"type":"type","alg":100}', json_encode($data, JSON_THROW_ON_ERROR)); + static::assertSame('{"type":"type","alg":100}', $this->getSerializer()->serialize($data, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ])); } } diff --git a/tests/library/Unit/PublicKeyCredentialRequestOptionsTest.php b/tests/library/Unit/PublicKeyCredentialRequestOptionsTest.php index 808a5d0c..0ed8a85d 100644 --- a/tests/library/Unit/PublicKeyCredentialRequestOptionsTest.php +++ b/tests/library/Unit/PublicKeyCredentialRequestOptionsTest.php @@ -5,13 +5,13 @@ namespace Webauthn\Tests\Unit; use PHPUnit\Framework\Attributes\Test; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Webauthn\AuthenticationExtensions\AuthenticationExtension; use Webauthn\AuthenticationExtensions\AuthenticationExtensions; use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs; use Webauthn\PublicKeyCredentialDescriptor; use Webauthn\PublicKeyCredentialRequestOptions; use Webauthn\Tests\AbstractTestCase; -use const JSON_THROW_ON_ERROR; /** * @internal @@ -24,7 +24,10 @@ public function authenticatorExtensionSerialization(): void // Given $extensions = AuthenticationExtensions::create([AuthenticationExtension::create('foo', 'bar')]); $extensions['baz'] = 'New era'; - $json = json_encode($extensions, JSON_THROW_ON_ERROR); + $json = $this->getSerializer() + ->serialize($extensions, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]); // When $data = $this->getSerializer() @@ -35,7 +38,9 @@ public function authenticatorExtensionSerialization(): void static::assertSame('bar', $data->get('foo')->value); static::assertSame('bar', $data['foo']->value); static::assertSame('New era', $data['baz']->value); - static::assertSame($json, json_encode($data, JSON_THROW_ON_ERROR)); + static::assertSame($json, $this->getSerializer()->serialize($data, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ])); } #[Test] @@ -59,9 +64,12 @@ public function aPublicKeyCredentialRequestOptionsCanBeCreatedAndValueAccessed() static::assertSame([$credential], $publicKeyCredentialRequestOptions->allowCredentials); static::assertSame('preferred', $publicKeyCredentialRequestOptions->userVerification); static::assertInstanceOf(AuthenticationExtensions::class, $publicKeyCredentialRequestOptions->extensions); - static::assertSame( + static::assertJsonStringEqualsJsonString( '{"challenge":"Y2hhbGxlbmdl","rpId":"rp_id","userVerification":"preferred","allowCredentials":[{"type":"type","id":"aWQ","transports":["transport"]}],"extensions":{"foo":"bar"},"timeout":1000}', - json_encode($publicKeyCredentialRequestOptions, JSON_THROW_ON_ERROR) + $this->getSerializer() + ->serialize($publicKeyCredentialRequestOptions, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]) ); $data = $this->getSerializer() @@ -75,9 +83,12 @@ public function aPublicKeyCredentialRequestOptionsCanBeCreatedAndValueAccessed() static::assertSame('rp_id', $data->rpId); static::assertSame('preferred', $data->userVerification); static::assertInstanceOf(AuthenticationExtensions::class, $data->extensions); - static::assertSame( + static::assertJsonStringEqualsJsonString( '{"challenge":"Y2hhbGxlbmdl","rpId":"rp_id","userVerification":"preferred","allowCredentials":[{"type":"type","id":"aWQ","transports":["transport"]}],"extensions":{"foo":"bar"},"timeout":1000}', - json_encode($data, JSON_THROW_ON_ERROR) + $this->getSerializer() + ->serialize($data, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]) ); } } diff --git a/tests/library/Unit/PublicKeyCredentialSourceTest.php b/tests/library/Unit/PublicKeyCredentialSourceTest.php index d8955aca..cde05124 100644 --- a/tests/library/Unit/PublicKeyCredentialSourceTest.php +++ b/tests/library/Unit/PublicKeyCredentialSourceTest.php @@ -5,12 +5,11 @@ namespace Webauthn\Tests\Unit; use PHPUnit\Framework\Attributes\Test; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Symfony\Component\Uid\Uuid; use Webauthn\PublicKeyCredentialSource; use Webauthn\Tests\AbstractTestCase; use Webauthn\TrustPath\EmptyTrustPath; -use const JSON_UNESCAPED_SLASHES; -use const JSON_UNESCAPED_UNICODE; /** * @internal @@ -20,11 +19,45 @@ final class PublicKeyCredentialSourceTest extends AbstractTestCase #[Test] public function backwardCompatibilityIsEnsured(): void { - $data = '{"publicKeyCredentialId":"cHVibGljS2V5Q3JlZGVudGlhbElk","type":"type","transports":["transport1","transport2"],"attestationType":"attestationType","trustPath":{"type":"Webauthn\\\\TrustPath\\\\EmptyTrustPath"},"aaguid":"014c0f17-f86f-4586-9914-2779922ba877","credentialPublicKey":"cHVibGljS2V5","userHandle":"dXNlckhhbmRsZQ","counter":123456789}'; - $source = $this->getSerializer() + // Given + $data = '{"publicKeyCredentialId":"cHVibGljS2V5Q3JlZGVudGlhbElk","type":"type","transports":["transport1","transport2"],"attestationType":"attestationType","trustPath":[],"aaguid":"014c0f17-f86f-4586-9914-2779922ba877","credentialPublicKey":"cHVibGljS2V5","userHandle":"dXNlckhhbmRsZQ","counter":123456789}'; + + //When + $source1 = $this->getSerializer() ->deserialize($data, PublicKeyCredentialSource::class, 'json'); + $source2 = PublicKeyCredentialSource::createFromArray(json_decode($data, true)); + + static::assertSame('publicKeyCredentialId', $source1->publicKeyCredentialId); + static::assertEquals($source1, $source2); + static::assertJsonStringEqualsJsonString($data, $this->getSerializer()->serialize($source2, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ])); + } + + #[Test] + public function jsonObject(): void + { + $serializer = $this->getSerializer(); + $source = publicKeyCredentialSource::create( + 'publicKeyCredentialId', + 'type', + ['transport1', 'transport2'], + 'attestationType', + EmptyTrustPath::create(), + Uuid::fromString('02ffd35d-7f0c-46b5-9eae-851ee4807b25'), + 'publicKey', + 'userHandle', + 123_456_789 + ); + $asJson = $this->getSerializer() + ->serialize($source, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]); + + $object1 = $serializer->deserialize($asJson, PublicKeyCredentialSource::class, 'json'); + $object2 = PublicKeyCredentialSource::createFromArray(json_decode($asJson, true)); - static::assertSame('publicKeyCredentialId', $source->publicKeyCredentialId); + static::assertEquals($object1, $object2); } #[Test] @@ -46,9 +79,12 @@ public function objectSerialization(): void false ); - static::assertSame( - '{"publicKeyCredentialId":"cHVibGljS2V5Q3JlZGVudGlhbElk","type":"type","transports":["transport1","transport2"],"attestationType":"attestationType","trustPath":{"type":"Webauthn\\\\TrustPath\\\\EmptyTrustPath"},"aaguid":"02ffd35d-7f0c-46b5-9eae-851ee4807b25","credentialPublicKey":"cHVibGljS2V5","userHandle":"dXNlckhhbmRsZQ","counter":123456789,"otherUI":null,"backupEligible":true,"backupStatus":true,"uvInitialized":false}', - json_encode($source, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) + static::assertJsonStringEqualsJsonString( + '{"publicKeyCredentialId":"cHVibGljS2V5Q3JlZGVudGlhbElk","type":"type","transports":["transport1","transport2"],"attestationType":"attestationType","trustPath":[],"aaguid":"02ffd35d-7f0c-46b5-9eae-851ee4807b25","credentialPublicKey":"cHVibGljS2V5","userHandle":"dXNlckhhbmRsZQ","counter":123456789,"backupEligible":true,"backupStatus":true,"uvInitialized":false}', + $this->getSerializer() + ->serialize($source, 'json', [ + AbstractObjectNormalizer::SKIP_NULL_VALUES => true, + ]) ); } } diff --git a/tests/library/Unit/TrustPath/TrustPathTest.php b/tests/library/Unit/TrustPath/TrustPathTest.php index 76914994..5a797d06 100644 --- a/tests/library/Unit/TrustPath/TrustPathTest.php +++ b/tests/library/Unit/TrustPath/TrustPathTest.php @@ -46,7 +46,7 @@ public function anEcdaaKeyIdTrustPathCanBeCreated(): void public function theLoaderCannotLoadUnsupportedTypeName(): void { $this->expectException(InvalidTrustPathException::class); - $this->expectExceptionMessage('The trust path type "foo" is not supported'); + $this->expectExceptionMessage('Unsupported trust path'); TrustPathLoader::loadTrustPath([ 'type' => 'foo', ]); @@ -59,9 +59,7 @@ public function theLoaderCannotLoadUnsupportedTypeName(): void public function theLoaderCannotLoadUnsupportedTypeNameBasedOnClass(): void { $this->expectException(InvalidTrustPathException::class); - $this->expectExceptionMessage( - 'The trust path type "Webauthn\Tests\Unit\TrustPath\NotAValidTrustPath" is not supported' - ); + $this->expectExceptionMessage('Unsupported trust path'); TrustPathLoader::loadTrustPath([ 'type' => NotAValidTrustPath::class, ]); diff --git a/tests/symfony/functional/Attestation/AdditionalAuthenticatorTest.php b/tests/symfony/functional/Attestation/AdditionalAuthenticatorTest.php index ef91ea58..afa63586 100644 --- a/tests/symfony/functional/Attestation/AdditionalAuthenticatorTest.php +++ b/tests/symfony/functional/Attestation/AdditionalAuthenticatorTest.php @@ -54,7 +54,6 @@ public function anExistingUserCanAskForOptionsUsingTheDedicatedController(): voi 'status', 'errorMessage', 'rp', - 'pubKeyCredParams', 'challenge', 'attestation', 'user', diff --git a/tests/symfony/functional/Firewall/RegistrationAreaTest.php b/tests/symfony/functional/Firewall/RegistrationAreaTest.php index 473830a2..9bd96006 100644 --- a/tests/symfony/functional/Firewall/RegistrationAreaTest.php +++ b/tests/symfony/functional/Firewall/RegistrationAreaTest.php @@ -103,10 +103,10 @@ public function aValidRequestProcessed(): void static::assertArrayHasKey('authenticatorSelection', $data); static::assertSame([ + 'authenticatorAttachment' => 'cross-platform', 'requireResidentKey' => true, 'userVerification' => 'required', 'residentKey' => 'required', - 'authenticatorAttachment' => 'cross-platform', ], $data['authenticatorSelection']); } @@ -188,10 +188,10 @@ public function aValidRequestProcessedWithExtensions(): void static::assertArrayHasKey('authenticatorSelection', $data); static::assertSame([ + 'authenticatorAttachment' => 'platform', 'requireResidentKey' => true, 'userVerification' => 'required', 'residentKey' => 'required', - 'authenticatorAttachment' => 'platform', ], $data['authenticatorSelection']); }