From c2c3b8058f371c3ff3eda2a802f0225b8ae1d5bd Mon Sep 17 00:00:00 2001 From: Iwona Just Date: Wed, 3 Apr 2024 10:19:49 +0100 Subject: [PATCH] changes needed after webauthn-lib update --- composer.json | 6 +- composer.lock | 477 ++++++++++++++++----- src/auth/passkeys/CredentialRepository.php | 28 +- src/auth/passkeys/WebauthnServer.php | 28 +- src/services/Auth.php | 54 ++- 5 files changed, 450 insertions(+), 143 deletions(-) diff --git a/composer.json b/composer.json index 026aeacae4e..58434338699 100644 --- a/composer.json +++ b/composer.json @@ -47,6 +47,7 @@ "mikehaertl/php-shellcommand": "^1.6.3", "moneyphp/money": "^4.0", "monolog/monolog": "^3.0", + "phpdocumentor/reflection-docblock": "^5.3", "pixelandtonic/imagine": "~1.3.3.1", "pragmarx/google2fa": "^8.0", "pragmarx/recovery": "^0.2.1", @@ -54,12 +55,15 @@ "seld/cli-prompt": "^1.0.4", "symfony/filesystem": "^6.3", "symfony/http-client": "^6.0.3", + "symfony/property-access": "^7.0", + "symfony/property-info": "^7.0", + "symfony/serializer": "^6.4", "symfony/var-dumper": "^5.0|^6.0", "symfony/yaml": "^5.2.3", "theiconic/name-parser": "^1.2", "twig/twig": "~3.8.0", "voku/stringy": "^6.4.0", - "web-auth/webauthn-lib": "^4.7.0", + "web-auth/webauthn-lib": "~4.8.0", "webonyx/graphql-php": "~14.11.5", "yiisoft/yii2": "~2.0.48.1", "yiisoft/yii2-debug": "~2.1.22.0", diff --git a/composer.lock b/composer.lock index c012cfb3ea5..781fdb20ecc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "02f287c334256938d667952963f250cd", + "content-hash": "c6c7d665db925181ddf18eeceabbfd00", "packages": [ { "name": "bacon/bacon-qr-code", @@ -3069,16 +3069,16 @@ }, { "name": "spomky-labs/pki-framework", - "version": "1.1.1", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/Spomky-Labs/pki-framework.git", - "reference": "86102bdd19379b2c6e5b0feb94fd490d40e7d133" + "reference": "0b10c8b53366729417d6226ae89a665f9e2d61b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/86102bdd19379b2c6e5b0feb94fd490d40e7d133", - "reference": "86102bdd19379b2c6e5b0feb94fd490d40e7d133", + "url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/0b10c8b53366729417d6226ae89a665f9e2d61b6", + "reference": "0b10c8b53366729417d6226ae89a665f9e2d61b6", "shasum": "" }, "require": { @@ -3090,7 +3090,7 @@ "ekino/phpstan-banned-code": "^1.0", "ext-gmp": "*", "ext-openssl": "*", - "infection/infection": "^0.27", + "infection/infection": "^0.28", "php-parallel-lint/php-parallel-lint": "^1.3", "phpstan/extension-installer": "^1.3", "phpstan/phpstan": "^1.8", @@ -3098,8 +3098,8 @@ "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.3", - "phpunit/phpunit": "^10.1", - "rector/rector": "^0.19", + "phpunit/phpunit": "^10.1|^11.0", + "rector/rector": "^1.0", "roave/security-advisories": "dev-latest", "symfony/phpunit-bridge": "^6.4|^7.0", "symfony/string": "^6.4|^7.0", @@ -3164,7 +3164,7 @@ ], "support": { "issues": "https://github.com/Spomky-Labs/pki-framework/issues", - "source": "https://github.com/Spomky-Labs/pki-framework/tree/1.1.1" + "source": "https://github.com/Spomky-Labs/pki-framework/tree/1.2.1" }, "funding": [ { @@ -3176,7 +3176,7 @@ "type": "patreon" } ], - "time": "2024-02-05T20:37:46+00:00" + "time": "2024-03-30T18:03:49+00:00" }, { "name": "symfony/deprecation-contracts", @@ -4573,6 +4573,263 @@ ], "time": "2024-01-23T14:51:35+00:00" }, + { + "name": "symfony/property-access", + "version": "v7.0.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "1c268ba954ccc5e78cf035b391abb67759e24423" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/1c268ba954ccc5e78cf035b391abb67759e24423", + "reference": "1c268ba954ccc5e78cf035b391abb67759e24423", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/property-info": "^6.4|^7.0" + }, + "require-dev": { + "symfony/cache": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property-path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v7.0.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-03-19T11:57:22+00:00" + }, + { + "name": "symfony/property-info", + "version": "v7.0.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-info.git", + "reference": "b8844ddce7d53f78b57ec9be59da80fceddf3167" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-info/zipball/b8844ddce7d53f78b57ec9be59da80fceddf3167", + "reference": "b8844ddce7d53f78b57ec9be59da80fceddf3167", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/string": "^6.4|^7.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<5.2", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/dependency-injection": "<6.4", + "symfony/serializer": "<6.4" + }, + "require-dev": { + "phpdocumentor/reflection-docblock": "^5.2", + "phpstan/phpdoc-parser": "^1.0", + "symfony/cache": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts information about PHP class' properties using metadata of popular sources", + "homepage": "https://symfony.com", + "keywords": [ + "doctrine", + "phpdoc", + "property", + "symfony", + "type", + "validator" + ], + "support": { + "source": "https://github.com/symfony/property-info/tree/v7.0.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-03-28T09:20:36+00:00" + }, + { + "name": "symfony/serializer", + "version": "v6.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/serializer.git", + "reference": "3697adf91f83516c86b4912c08c28084711ed560" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/serializer/zipball/3697adf91f83516c86b4912c08c28084711ed560", + "reference": "3697adf91f83516c86b4912c08c28084711ed560", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "doctrine/annotations": "<1.12", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/dependency-injection": "<5.4", + "symfony/property-access": "<5.4", + "symfony/property-info": "<5.4.24|>=6,<6.2.11", + "symfony/uid": "<5.4", + "symfony/validator": "<6.4", + "symfony/yaml": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.12|^2", + "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", + "seld/jsonlint": "^1.10", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/form": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4.26|^6.3|^7.0", + "symfony/property-info": "^5.4.24|^6.2.11|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^5.4|^6.0|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0", + "symfony/var-exporter": "^5.4|^6.0|^7.0", + "symfony/yaml": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Serializer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/serializer/tree/v6.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-03-27T22:00:14+00:00" + }, { "name": "symfony/service-contracts", "version": "v3.4.1", @@ -4655,6 +4912,92 @@ ], "time": "2023-12-26T14:02:43+00:00" }, + { + "name": "symfony/string", + "version": "v7.0.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "524aac4a280b90a4420d8d6a040718d0586505ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/524aac4a280b90a4420d8d6a040718d0586505ac", + "reference": "524aac4a280b90a4420d8d6a040718d0586505ac", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.0.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-01-29T15:41:16+00:00" + }, { "name": "symfony/uid", "version": "v7.0.3", @@ -5737,16 +6080,16 @@ }, { "name": "web-auth/metadata-service", - "version": "4.8.1", + "version": "4.8.3", "source": { "type": "git", "url": "https://github.com/web-auth/webauthn-metadata-service.git", - "reference": "024df5fb26166adf388dea697d2826ae5a6001cf" + "reference": "fb7c1f107639285fab90f870aab38360252c82f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-auth/webauthn-metadata-service/zipball/024df5fb26166adf388dea697d2826ae5a6001cf", - "reference": "024df5fb26166adf388dea697d2826ae5a6001cf", + "url": "https://api.github.com/repos/web-auth/webauthn-metadata-service/zipball/fb7c1f107639285fab90f870aab38360252c82f5", + "reference": "fb7c1f107639285fab90f870aab38360252c82f5", "shasum": "" }, "require": { @@ -5805,7 +6148,7 @@ "webauthn" ], "support": { - "source": "https://github.com/web-auth/webauthn-metadata-service/tree/4.8.1" + "source": "https://github.com/web-auth/webauthn-metadata-service/tree/4.8.3" }, "funding": [ { @@ -5817,20 +6160,20 @@ "type": "patreon" } ], - "time": "2024-02-26T07:58:15+00:00" + "time": "2024-03-13T07:16:02+00:00" }, { "name": "web-auth/webauthn-lib", - "version": "4.8.1", + "version": "4.8.3", "source": { "type": "git", "url": "https://github.com/web-auth/webauthn-lib.git", - "reference": "ac1be6bba06f78f1d58ac75eefcedd32ef8093c7" + "reference": "d296fde8450ce6972c54315a70e32159cad7e35b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/ac1be6bba06f78f1d58ac75eefcedd32ef8093c7", - "reference": "ac1be6bba06f78f1d58ac75eefcedd32ef8093c7", + "url": "https://api.github.com/repos/web-auth/webauthn-lib/zipball/d296fde8450ce6972c54315a70e32159cad7e35b", + "reference": "d296fde8450ce6972c54315a70e32159cad7e35b", "shasum": "" }, "require": { @@ -5849,8 +6192,12 @@ "web-auth/metadata-service": "self.version" }, "suggest": { + "phpdocumentor/reflection-docblock": "As of 4.5.x, the phpdocumentor/reflection-docblock component will become mandatory for converting objects such as the Metadata Statement", "psr/log-implementation": "Recommended to receive logs from the library", "symfony/event-dispatcher": "Recommended to use dispatched events", + "symfony/property-access": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "symfony/property-info": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", + "symfony/serializer": "As of 4.5.x, the symfony/serializer component will become mandatory for converting objects such as the Metadata Statement", "web-token/jwt-library": "Mandatory for the AndroidSafetyNet Attestation Statement support" }, "type": "library", @@ -5887,7 +6234,7 @@ "webauthn" ], "support": { - "source": "https://github.com/web-auth/webauthn-lib/tree/4.8.1" + "source": "https://github.com/web-auth/webauthn-lib/tree/4.8.3" }, "funding": [ { @@ -5899,7 +6246,7 @@ "type": "patreon" } ], - "time": "2024-02-25T20:08:25+00:00" + "time": "2024-03-22T20:51:36+00:00" }, { "name": "webmozart/assert", @@ -9883,92 +10230,6 @@ ], "time": "2023-10-31T17:59:56+00:00" }, - { - "name": "symfony/string", - "version": "v7.0.3", - "source": { - "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "524aac4a280b90a4420d8d6a040718d0586505ac" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/524aac4a280b90a4420d8d6a040718d0586505ac", - "reference": "524aac4a280b90a4420d8d6a040718d0586505ac", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/translation-contracts": "<2.5" - }, - "require-dev": { - "symfony/error-handler": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", - "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "files": [ - "Resources/functions.php" - ], - "psr-4": { - "Symfony\\Component\\String\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", - "homepage": "https://symfony.com", - "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" - ], - "support": { - "source": "https://github.com/symfony/string/tree/v7.0.3" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-01-29T15:41:16+00:00" - }, { "name": "symplify/easy-coding-standard", "version": "10.3.3", diff --git a/src/auth/passkeys/CredentialRepository.php b/src/auth/passkeys/CredentialRepository.php index efdbe4887d6..18292a997ed 100644 --- a/src/auth/passkeys/CredentialRepository.php +++ b/src/auth/passkeys/CredentialRepository.php @@ -25,6 +25,17 @@ */ class CredentialRepository implements PublicKeyCredentialSourceRepository { + /** + * @var WebauthnServer + */ + private WebauthnServer $_webauthnServer; + + + public function __construct() + { + $this->_webauthnServer = new WebauthnServer(); + } + /** * @inheritdoc */ @@ -33,7 +44,13 @@ public function findOneByCredentialId(string $publicKeyCredentialId): ?PublicKey $record = $this->_findByCredentialId($publicKeyCredentialId); if ($record) { - return PublicKeyCredentialSource::createFromArray(Json::decodeIfJson($record->credential)); + $serializer = $this->_webauthnServer->getSerializer(); + + return $serializer->deserialize( + $record->credential, + PublicKeyCredentialSource::class, + 'json', + ); } return null; @@ -50,8 +67,13 @@ public function findAllForUserEntity(PublicKeyCredentialUserEntity $publicKeyCre $keySources = []; if ($user && $user->id) { $records = WebAuthn::findAll(['userId' => $user->id]); + $serializer = $this->_webauthnServer->getSerializer(); foreach ($records as $record) { - $keySources[] = PublicKeyCredentialSource::createFromArray(Json::decodeIfJson($record->credential)); + $keySources[] = $serializer->deserialize( + $record->credential, + PublicKeyCredentialSource::class, + 'json', + ); } } @@ -66,7 +88,7 @@ public function findAllForUserEntity(PublicKeyCredentialUserEntity $publicKeyCre */ public function savedNamedCredentialSource(PublicKeyCredentialSource $publicKeyCredentialSource, ?string $credentialName = null): void { - $publicKeyCredentialId = $publicKeyCredentialSource->getPublicKeyCredentialId(); + $publicKeyCredentialId = $publicKeyCredentialSource->publicKeyCredentialId; $record = $this->_findByCredentialId($publicKeyCredentialId); if (!$record) { diff --git a/src/auth/passkeys/WebauthnServer.php b/src/auth/passkeys/WebauthnServer.php index c660f45bf04..63f73448cac 100644 --- a/src/auth/passkeys/WebauthnServer.php +++ b/src/auth/passkeys/WebauthnServer.php @@ -16,6 +16,7 @@ use Cose\Algorithm\Signature\RSA\RS384; use Cose\Algorithm\Signature\RSA\RS512; use Cose\Algorithms; +use Symfony\Component\Serializer\SerializerInterface; use Webauthn\AttestationStatement\AttestationObjectLoader; use Webauthn\AttestationStatement\AttestationStatementSupportManager; use Webauthn\AttestationStatement\NoneAttestationStatementSupport; @@ -23,7 +24,7 @@ use Webauthn\AuthenticatorAssertionResponseValidator; use Webauthn\AuthenticatorAttestationResponseValidator; use Webauthn\AuthenticatorSelectionCriteria; -use Webauthn\PublicKeyCredentialLoader; +use Webauthn\Denormalizer\WebauthnSerializerFactory; use Webauthn\PublicKeyCredentialParameters; use Webauthn\TokenBinding\IgnoreTokenBindingHandler; @@ -43,6 +44,7 @@ class WebauthnServer * * @return IgnoreTokenBindingHandler * @see https://webauthn-doc.spomky-labs.com/v/v4.5/pure-php/the-hard-way#token-binding-handler + * todo: remove when updating to web-auth 5.0 */ public function getTokenBindingHandler(): IgnoreTokenBindingHandler { @@ -80,16 +82,18 @@ public function getAttestationObjectLoader(): AttestationObjectLoader } /** - * Returns the object that will load the Public Key. + * Return the Symphony Serializer that will deal with serialization/deserialization of data. * - * @return PublicKeyCredentialLoader - * @see https://webauthn-doc.spomky-labs.com/pure-php/the-hard-way#public-key-credential-loader + * @return SerializerInterface + * @see https://webauthn-doc.spomky-labs.com/v/v4.8/pure-php/input-loading#the-serializer */ - public function getPublicKeyCredentialLoader(): PublicKeyCredentialLoader + public function getSerializer(): SerializerInterface { - return PublicKeyCredentialLoader::create( - $this->getAttestationObjectLoader() - ); + $attestationStatementSupportManager = AttestationStatementSupportManager::create(); + $attestationStatementSupportManager->add(NoneAttestationStatementSupport::create()); + $factory = new WebauthnSerializerFactory($attestationStatementSupportManager); + + return $factory->create(); } /** @@ -141,8 +145,8 @@ public function getAuthenticatorAttestationResponseValidator(): AuthenticatorAtt { return AuthenticatorAttestationResponseValidator::create( $this->getAttestationStatementManager(), - new CredentialRepository(), - $this->getTokenBindingHandler(), + new CredentialRepository(), // todo: set to null when updating to web-auth 5.0 + $this->getTokenBindingHandler(), // todo: set to null when updating to web-auth 5.0 $this->getExtensionOutputCheckerHandler(), ); } @@ -157,8 +161,8 @@ public function getAuthenticatorAssertionResponseValidator(): AuthenticatorAsser { return AuthenticatorAssertionResponseValidator::create( new CredentialRepository(), - $this->getTokenBindingHandler(), - $this->getExtensionOutputCheckerHandler(), + $this->getTokenBindingHandler(), // todo: set to null when updating to web-auth 5.0 + $this->getExtensionOutputCheckerHandler(), // todo: set to null when updating to web-auth 5.0 $this->getAlgorithmManager(), ); } diff --git a/src/services/Auth.php b/src/services/Auth.php index f2c038dd10a..b54e98ee415 100644 --- a/src/services/Auth.php +++ b/src/services/Auth.php @@ -29,6 +29,7 @@ use Throwable; use Webauthn\AuthenticatorAssertionResponse; use Webauthn\AuthenticatorAttestationResponse; +use Webauthn\PublicKeyCredential; use Webauthn\PublicKeyCredentialCreationOptions; use Webauthn\PublicKeyCredentialOptions; use Webauthn\PublicKeyCredentialRequestOptions; @@ -445,8 +446,19 @@ public function verifyPasskeyCreationResponse(string $credentials, ?string $cred return false; } - $publicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions::createFromArray(Json::decode($optionsJson)); - $publicKeyCredential = $this->webauthnServer()->getPublicKeyCredentialLoader()->load($credentials); + $serializer = $this->webauthnServer()->getSerializer(); + + $publicKeyCredentialCreationOptions = $serializer->deserialize( + $optionsJson, + PublicKeyCredentialCreationOptions::class, + 'json', + ); + + $publicKeyCredential = $serializer->deserialize( + $credentials, + PublicKeyCredential::class, + 'json', + ); $authenticatorAttestationResponse = $publicKeyCredential->response; if (!$authenticatorAttestationResponse instanceof AuthenticatorAttestationResponse) { @@ -497,14 +509,20 @@ public function verifyPasskey( PublicKeyCredentialRequestOptions|array|string $requestOptions, string $response, ): bool { - if (is_array($requestOptions)) { - $requestOptions = PublicKeyCredentialRequestOptions::createFromArray($requestOptions); - } elseif (is_string($requestOptions)) { - $requestOptions = PublicKeyCredentialRequestOptions::createFromString($requestOptions); - } + $serializer = $this->webauthnServer()->getSerializer(); + + $requestOptions = $serializer->deserialize( + $requestOptions, + PublicKeyCredentialRequestOptions::class, + 'json', + ); $userEntity = $this->passkeyUserEntity($user); - $publicKeyCredential = $this->webauthnServer()->getPublicKeyCredentialLoader()->load($response); + $publicKeyCredential = $serializer->deserialize( + $response, + PublicKeyCredential::class, + 'json', + ); $authenticatorAssertionResponse = $publicKeyCredential->response; if (!$authenticatorAssertionResponse instanceof AuthenticatorAssertionResponse) { @@ -562,13 +580,11 @@ private function webauthnServer(): WebauthnServer */ private function passkeyUserEntity(User $user): PublicKeyCredentialUserEntity { - $data = [ - 'name' => $user->email, - 'id' => Base64UrlSafe::encodeUnpadded($user->uid), - 'displayName' => $user->getName(), - ]; - - return PublicKeyCredentialUserEntity::createFromArray($data); + return PublicKeyCredentialUserEntity::create( + $user->email, + Base64UrlSafe::encodeUnpadded($user->uid), + $user->getName(), + ); } /** @@ -578,9 +594,9 @@ private function passkeyUserEntity(User $user): PublicKeyCredentialUserEntity */ private function passkeyRpEntity(): PublicKeyCredentialRpEntity { - return PublicKeyCredentialRpEntity::createFromArray([ - 'name' => Craft::$app->getSystemName(), - 'id' => Craft::$app->getRequest()->getHostName(), - ]); + return PublicKeyCredentialRpEntity::create( + Craft::$app->getSystemName(), + Craft::$app->getRequest()->getHostName(), + ); } }