Merge pull request #18752 from MauricioFauth/webauthn-lib-v4

Upgrade web-auth/webauthn-lib to version 4
This commit is contained in:
Maurício Meneghini Fauth 2024-08-30 10:54:40 -03:00 committed by GitHub
commit ca2fb1bd4c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 801 additions and 841 deletions

View File

@ -295,7 +295,7 @@ security_checkup() {
echo 'TCPDF should be installed, detection failed !'
exit 1;
fi
if [ ! -f vendor/web-auth/webauthn-lib/src/Server.php ]; then
if [ ! -f vendor/web-auth/webauthn-lib/src/PublicKeyCredential.php ]; then
echo 'Webauthn-lib should be installed, detection failed !'
exit 1;
fi

View File

@ -119,7 +119,7 @@
"symfony/console": "^6.2",
"tecnickcom/tcpdf": "^6.4.4",
"vimeo/psalm": "^5.14",
"web-auth/webauthn-lib": "^3.3.12"
"web-auth/webauthn-lib": "^4.9"
},
"extra": {
"branch-alias": {

1293
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -14050,6 +14050,46 @@ parameters:
count: 1
path: src/WebAuthn/CBORDecoder.php
-
message: "#^Call to static method Webmozart\\\\Assert\\\\Assert\\:\\:isInstanceOf\\(\\) with Webauthn\\\\PublicKeyCredentialCreationOptions and 'Webauthn\\\\\\\\PublicKeyCredentialCreationOptions' will always evaluate to true\\.$#"
count: 1
path: src/WebAuthn/WebauthnLibServer.php
-
message: "#^Call to static method Webmozart\\\\Assert\\\\Assert\\:\\:isInstanceOf\\(\\) with Webauthn\\\\PublicKeyCredentialRequestOptions and 'Webauthn\\\\\\\\PublicKeyCredentialRequestOptions' will always evaluate to true\\.$#"
count: 1
path: src/WebAuthn/WebauthnLibServer.php
-
message: "#^Cannot access offset 'authenticatorData' on mixed\\.$#"
count: 2
path: src/WebAuthn/WebauthnLibServer.php
-
message: "#^Cannot access offset 'clientDataJSON' on mixed\\.$#"
count: 4
path: src/WebAuthn/WebauthnLibServer.php
-
message: "#^Cannot access offset 'response' on mixed\\.$#"
count: 6
path: src/WebAuthn/WebauthnLibServer.php
-
message: "#^Parameter \\#1 \\$haystack of function str_ends_with expects string, mixed given\\.$#"
count: 1
path: src/WebAuthn/WebauthnLibServer.php
-
message: "#^Parameter \\#1 \\$string of function rtrim expects string, mixed given\\.$#"
count: 1
path: src/WebAuthn/WebauthnLibServer.php
-
message: "#^Parameter \\#1 \\$string of function sodium_base642bin expects string, mixed given\\.$#"
count: 3
path: src/WebAuthn/WebauthnLibServer.php
-
message: "#^Method PhpMyAdmin\\\\ZipExtension\\:\\:getContents\\(\\) should return array\\{error\\: string, data\\: string\\} but returns array\\{error\\: '', data\\: string\\|false\\}\\.$#"
count: 1

View File

@ -11989,6 +11989,84 @@
* }]]></code>
</MoreSpecificReturnType>
</file>
<file src="src/WebAuthn/WebauthnLibServer.php">
<DeprecatedClass>
<code><![CDATA[PublicKeyCredentialLoader::create($attestationObjectLoader)]]></code>
<code><![CDATA[PublicKeyCredentialLoader::create($attestationObjectLoader)]]></code>
<code><![CDATA[PublicKeyCredentialLoader::create($attestationObjectLoader)]]></code>
<code><![CDATA[new AuthenticationExtensionsClientInputs()]]></code>
<code><![CDATA[new AuthenticationExtensionsClientInputs()]]></code>
<code><![CDATA[new IgnoreTokenBindingHandler()]]></code>
<code><![CDATA[new IgnoreTokenBindingHandler()]]></code>
</DeprecatedClass>
<DeprecatedInterface>
<code><![CDATA[PublicKeyCredentialSourceRepository]]></code>
<code><![CDATA[class ($this->twofactor) implements PublicKeyCredentialSourceRepository {]]></code>
</DeprecatedInterface>
<DeprecatedMethod>
<code><![CDATA[AuthenticatorSelectionCriteria::createFromArray([
'authenticatorAttachment' => 'cross-platform',
'userVerification' => 'discouraged',
])]]></code>
<code><![CDATA[PublicKeyCredentialCreationOptions::createFromArray($creationOptionsArray)]]></code>
<code><![CDATA[PublicKeyCredentialRequestOptions::createFromArray([
'challenge' => $challenge,
'allowCredentials' => $allowedCredentials,
'rpId' => $host,
'timeout' => 60000,
])]]></code>
<code><![CDATA[PublicKeyCredentialSource::createFromArray($data)]]></code>
<code><![CDATA[PublicKeyCredentialSource::createFromArray($data[base64_encode($publicKeyCredentialId)])]]></code>
<code><![CDATA[allowCredentials]]></code>
<code><![CDATA[getId]]></code>
<code><![CDATA[getId]]></code>
<code><![CDATA[getId]]></code>
<code><![CDATA[getPublicKeyCredentialId]]></code>
<code><![CDATA[getRawId]]></code>
<code><![CDATA[getResponse]]></code>
<code><![CDATA[getResponse]]></code>
<code><![CDATA[getUserHandle]]></code>
<code><![CDATA[setAttestation]]></code>
<code><![CDATA[setAuthenticatorSelection]]></code>
<code><![CDATA[setExtensions]]></code>
<code><![CDATA[setExtensions]]></code>
<code><![CDATA[setRpId]]></code>
<code><![CDATA[setTimeout]]></code>
<code><![CDATA[setTimeout]]></code>
<code><![CDATA[setUserVerification]]></code>
</DeprecatedMethod>
<MixedArgument>
<code><![CDATA[$assertionResponseDecoded['response']['authenticatorData']]]></code>
<code><![CDATA[$assertionResponseDecoded['response']['clientDataJSON']]]></code>
<code><![CDATA[$attestationResponseDecoded['response']['clientDataJSON']]]></code>
<code><![CDATA[$credential['userHandle']]]></code>
</MixedArgument>
<MixedArrayAccess>
<code><![CDATA[$assertionResponseDecoded['response']]]></code>
<code><![CDATA[$assertionResponseDecoded['response']]]></code>
<code><![CDATA[$assertionResponseDecoded['response']['authenticatorData']]]></code>
<code><![CDATA[$assertionResponseDecoded['response']['clientDataJSON']]]></code>
<code><![CDATA[$attestationResponseDecoded['response']]]></code>
<code><![CDATA[$attestationResponseDecoded['response']]]></code>
<code><![CDATA[$attestationResponseDecoded['response']['clientDataJSON']]]></code>
</MixedArrayAccess>
<MixedArrayAssignment>
<code><![CDATA[$assertionResponseDecoded['response']]]></code>
<code><![CDATA[$assertionResponseDecoded['response']]]></code>
<code><![CDATA[$assertionResponseDecoded['response']['authenticatorData']]]></code>
<code><![CDATA[$assertionResponseDecoded['response']['clientDataJSON']]]></code>
<code><![CDATA[$attestationResponseDecoded['response']]]></code>
<code><![CDATA[$attestationResponseDecoded['response']['clientDataJSON']]]></code>
</MixedArrayAssignment>
<MixedAssignment>
<code><![CDATA[$assertionResponseDecoded]]></code>
<code><![CDATA[$attestationResponseDecoded]]></code>
</MixedAssignment>
<RedundantCondition>
<code><![CDATA[isInstanceOf]]></code>
<code><![CDATA[isInstanceOf]]></code>
</RedundantCondition>
</file>
<file src="src/ZipExtension.php">
<ArgumentTypeCoercion>
<code><![CDATA[$regex]]></code>

View File

@ -13,7 +13,7 @@ use PhpMyAdmin\WebAuthn\Server;
use PhpMyAdmin\WebAuthn\WebauthnLibServer;
use SodiumException;
use Throwable;
use Webauthn\Server as WebauthnServer;
use Webauthn\PublicKeyCredential;
use Webmozart\Assert\Assert;
use function __;
@ -61,7 +61,7 @@ class WebAuthn extends TwoFactorPlugin
private function createServer(): Server
{
return class_exists(WebauthnServer::class) ? new WebauthnLibServer($this->twofactor) : new CustomServer();
return class_exists(PublicKeyCredential::class) ? new WebauthnLibServer($this->twofactor) : new CustomServer();
}
public function setServer(Server $server): void

View File

@ -4,33 +4,78 @@ declare(strict_types=1);
namespace PhpMyAdmin\WebAuthn;
use Cose\Algorithm\ManagerFactory;
use Cose\Algorithm\Signature\ECDSA;
use Cose\Algorithm\Signature\EdDSA;
use Cose\Algorithm\Signature\RSA;
use PhpMyAdmin\TwoFactor;
use Psr\Http\Message\ServerRequestInterface;
use Webauthn\AttestationStatement\AttestationObjectLoader;
use Webauthn\AttestationStatement\AttestationStatementSupportManager;
use Webauthn\AttestationStatement\NoneAttestationStatementSupport;
use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs;
use Webauthn\AuthenticationExtensions\ExtensionOutputCheckerHandler;
use Webauthn\AuthenticatorAssertionResponse;
use Webauthn\AuthenticatorAssertionResponseValidator;
use Webauthn\AuthenticatorAttestationResponse;
use Webauthn\AuthenticatorAttestationResponseValidator;
use Webauthn\AuthenticatorSelectionCriteria;
use Webauthn\PublicKeyCredentialCreationOptions;
use Webauthn\PublicKeyCredentialDescriptor;
use Webauthn\PublicKeyCredentialLoader;
use Webauthn\PublicKeyCredentialParameters;
use Webauthn\PublicKeyCredentialRequestOptions;
use Webauthn\PublicKeyCredentialRpEntity;
use Webauthn\PublicKeyCredentialSource;
use Webauthn\PublicKeyCredentialSourceRepository;
use Webauthn\PublicKeyCredentialUserEntity;
use Webauthn\Server as WebauthnServer;
use Webauthn\TokenBinding\IgnoreTokenBindingHandler;
use Webauthn\TrustPath\EmptyTrustPath;
use Webmozart\Assert\Assert;
use function array_map;
use function base64_encode;
use function json_decode;
use function json_encode;
use function random_bytes;
use function rtrim;
use function sodium_base642bin;
use function sodium_bin2base64;
use function str_ends_with;
use const JSON_THROW_ON_ERROR;
use const SODIUM_BASE64_VARIANT_ORIGINAL;
use const SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING;
final class WebauthnLibServer implements Server
{
private int $timeout = 60000;
/** @phpstan-var int<1, max> */
private int $challengeSize = 32;
private ManagerFactory $coseAlgorithmManagerFactory;
/** @var string[] */
private array $selectedAlgorithms;
public function __construct(private TwoFactor $twofactor)
{
$this->coseAlgorithmManagerFactory = new ManagerFactory();
$this->coseAlgorithmManagerFactory->add('RS1', new RSA\RS1());
$this->coseAlgorithmManagerFactory->add('RS256', new RSA\RS256());
$this->coseAlgorithmManagerFactory->add('RS384', new RSA\RS384());
$this->coseAlgorithmManagerFactory->add('RS512', new RSA\RS512());
$this->coseAlgorithmManagerFactory->add('PS256', new RSA\PS256());
$this->coseAlgorithmManagerFactory->add('PS384', new RSA\PS384());
$this->coseAlgorithmManagerFactory->add('PS512', new RSA\PS512());
$this->coseAlgorithmManagerFactory->add('ES256', new ECDSA\ES256());
$this->coseAlgorithmManagerFactory->add('ES256K', new ECDSA\ES256K());
$this->coseAlgorithmManagerFactory->add('ES384', new ECDSA\ES384());
$this->coseAlgorithmManagerFactory->add('ES512', new ECDSA\ES512());
$this->coseAlgorithmManagerFactory->add('Ed25519', new EdDSA\Ed25519());
$this->selectedAlgorithms = ['RS256', 'RS512', 'PS256', 'PS512', 'ES256', 'ES512', 'Ed25519'];
}
/** @inheritDoc */
@ -38,17 +83,31 @@ final class WebauthnLibServer implements Server
{
$userEntity = new PublicKeyCredentialUserEntity($userName, $userId, $userName);
$relyingPartyEntity = new PublicKeyCredentialRpEntity('phpMyAdmin (' . $relyingPartyId . ')', $relyingPartyId);
$publicKeyCredentialSourceRepository = $this->createPublicKeyCredentialSourceRepository();
$server = new WebauthnServer($relyingPartyEntity, $publicKeyCredentialSourceRepository);
$publicKeyCredentialCreationOptions = $server->generatePublicKeyCredentialCreationOptions(
$coseAlgorithmManager = $this->coseAlgorithmManagerFactory->generate(...$this->selectedAlgorithms);
$publicKeyCredentialParametersList = [];
foreach ($coseAlgorithmManager->all() as $algorithm) {
$publicKeyCredentialParametersList[] = new PublicKeyCredentialParameters(
PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY,
$algorithm::identifier(),
);
}
$criteria = AuthenticatorSelectionCriteria::createFromArray([
'authenticatorAttachment' => 'cross-platform',
'userVerification' => 'discouraged',
]);
$publicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions::create(
$relyingPartyEntity,
$userEntity,
PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE,
[],
AuthenticatorSelectionCriteria::createFromArray([
'authenticatorAttachment' => 'cross-platform',
'userVerification' => 'discouraged',
]),
);
random_bytes($this->challengeSize),
$publicKeyCredentialParametersList,
)
->setAuthenticatorSelection($criteria)
->setAttestation(PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE)
->setExtensions(new AuthenticationExtensionsClientInputs())
->setTimeout($this->timeout);
/** @psalm-var array{
* challenge: non-empty-string,
* rp: array{name: non-empty-string, id: non-empty-string},
@ -58,7 +117,7 @@ final class WebauthnLibServer implements Server
* timeout: positive-int,
* attestation: non-empty-string
* } $creationOptions */
$creationOptions = $publicKeyCredentialCreationOptions->jsonSerialize();
$creationOptions = $this->normalize($publicKeyCredentialCreationOptions);
$creationOptions['challenge'] = sodium_bin2base64(
sodium_base642bin($creationOptions['challenge'], SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING),
SODIUM_BASE64_VARIANT_ORIGINAL,
@ -78,7 +137,6 @@ final class WebauthnLibServer implements Server
$userEntity = new PublicKeyCredentialUserEntity($userName, $userId, $userName);
$relyingPartyEntity = new PublicKeyCredentialRpEntity('phpMyAdmin (' . $relyingPartyId . ')', $relyingPartyId);
$publicKeyCredentialSourceRepository = $this->createPublicKeyCredentialSourceRepository();
$server = new WebauthnServer($relyingPartyEntity, $publicKeyCredentialSourceRepository);
$credentialSources = $publicKeyCredentialSourceRepository->findAllForUserEntity($userEntity);
$allowedCredentials = array_map(
static fn (
@ -86,17 +144,22 @@ final class WebauthnLibServer implements Server
): PublicKeyCredentialDescriptor => $credential->getPublicKeyCredentialDescriptor(),
$credentialSources,
);
$publicKeyCredentialRequestOptions = $server->generatePublicKeyCredentialRequestOptions(
'discouraged',
$allowedCredentials,
);
$challenge = random_bytes($this->challengeSize);
$publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::create($challenge)
->setRpId($relyingPartyEntity->getId())
->setUserVerification(PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_DISCOURAGED)
->allowCredentials(...$allowedCredentials)
->setTimeout($this->timeout)
->setExtensions(new AuthenticationExtensionsClientInputs());
/**
* @psalm-var array{
* challenge: string,
* allowCredentials?: list<array{id: non-empty-string, type: non-empty-string}>
* } $requestOptions
*/
$requestOptions = $publicKeyCredentialRequestOptions->jsonSerialize();
$requestOptions = $this->normalize($publicKeyCredentialRequestOptions);
$requestOptions['challenge'] = sodium_bin2base64(
sodium_base642bin($requestOptions['challenge'], SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING),
SODIUM_BASE64_VARIANT_ORIGINAL,
@ -127,9 +190,7 @@ final class WebauthnLibServer implements Server
);
$userEntity = new PublicKeyCredentialUserEntity($this->twofactor->user, $userHandle, $this->twofactor->user);
$host = $request->getUri()->getHost();
$relyingPartyEntity = new PublicKeyCredentialRpEntity('phpMyAdmin (' . $host . ')', $host);
$publicKeyCredentialSourceRepository = $this->createPublicKeyCredentialSourceRepository();
$server = new WebauthnServer($relyingPartyEntity, $publicKeyCredentialSourceRepository);
$requestOptions = PublicKeyCredentialRequestOptions::createFromArray([
'challenge' => $challenge,
'allowCredentials' => $allowedCredentials,
@ -137,7 +198,52 @@ final class WebauthnLibServer implements Server
'timeout' => 60000,
]);
Assert::isInstanceOf($requestOptions, PublicKeyCredentialRequestOptions::class);
$server->loadAndCheckAssertionResponse($assertionResponseJson, $requestOptions, $userEntity, $request);
$attestationStatementSupportManager = new AttestationStatementSupportManager();
$attestationStatementSupportManager->add(new NoneAttestationStatementSupport());
$attestationObjectLoader = AttestationObjectLoader::create($attestationStatementSupportManager);
$publicKeyCredentialLoader = PublicKeyCredentialLoader::create($attestationObjectLoader);
$assertionResponseDecoded = json_decode($assertionResponseJson, true, flags: JSON_THROW_ON_ERROR);
$assertionResponseDecoded['response']['authenticatorData'] = sodium_bin2base64(
sodium_base642bin(
$assertionResponseDecoded['response']['authenticatorData'],
SODIUM_BASE64_VARIANT_ORIGINAL,
),
SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING,
);
$assertionResponseDecoded['response']['clientDataJSON'] = sodium_bin2base64(
sodium_base642bin(
$assertionResponseDecoded['response']['clientDataJSON'],
SODIUM_BASE64_VARIANT_ORIGINAL,
),
SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING,
);
$publicKeyCredential = $publicKeyCredentialLoader->load(
json_encode($assertionResponseDecoded, JSON_THROW_ON_ERROR),
);
$authenticatorResponse = $publicKeyCredential->getResponse();
Assert::isInstanceOf(
$authenticatorResponse,
AuthenticatorAssertionResponse::class,
'Not an authenticator assertion response',
);
$authenticatorAssertionResponseValidator = new AuthenticatorAssertionResponseValidator(
$publicKeyCredentialSourceRepository,
new IgnoreTokenBindingHandler(),
new ExtensionOutputCheckerHandler(),
$this->coseAlgorithmManagerFactory->generate(...$this->selectedAlgorithms),
);
$authenticatorAssertionResponseValidator->check(
$publicKeyCredential->getRawId(),
$authenticatorResponse,
$requestOptions,
$request,
$userEntity->getId(),
);
}
/** @inheritDoc */
@ -146,16 +252,14 @@ final class WebauthnLibServer implements Server
string $credentialCreationOptions,
ServerRequestInterface $request,
): array {
$creationOptions = json_decode($credentialCreationOptions, true);
$creationOptions = json_decode($credentialCreationOptions, true, flags: JSON_THROW_ON_ERROR);
Assert::isArray($creationOptions);
Assert::keyExists($creationOptions, 'challenge');
Assert::keyExists($creationOptions, 'user');
Assert::isArray($creationOptions['user']);
Assert::keyExists($creationOptions['user'], 'id');
$host = $request->getUri()->getHost();
$relyingPartyEntity = new PublicKeyCredentialRpEntity('phpMyAdmin (' . $host . ')', $host);
$publicKeyCredentialSourceRepository = $this->createPublicKeyCredentialSourceRepository();
$server = new WebauthnServer($relyingPartyEntity, $publicKeyCredentialSourceRepository);
$creationOptionsArray = [
'rp' => ['name' => 'phpMyAdmin (' . $host . ')', 'id' => $host],
'pubKeyCredParams' => [
@ -182,13 +286,45 @@ final class WebauthnLibServer implements Server
];
$credentialCreationOptions = PublicKeyCredentialCreationOptions::createFromArray($creationOptionsArray);
Assert::isInstanceOf($credentialCreationOptions, PublicKeyCredentialCreationOptions::class);
$publicKeyCredentialSource = $server->loadAndCheckAttestationResponse(
$attestationResponse,
$attestationStatementSupportManager = new AttestationStatementSupportManager();
$attestationStatementSupportManager->add(new NoneAttestationStatementSupport());
$attestationObjectLoader = AttestationObjectLoader::create($attestationStatementSupportManager);
$publicKeyCredentialLoader = PublicKeyCredentialLoader::create($attestationObjectLoader);
$attestationResponseDecoded = json_decode($attestationResponse, true, flags: JSON_THROW_ON_ERROR);
$attestationResponseDecoded['response']['clientDataJSON'] = sodium_bin2base64(
sodium_base642bin(
$attestationResponseDecoded['response']['clientDataJSON'],
SODIUM_BASE64_VARIANT_ORIGINAL,
),
SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING,
);
$publicKeyCredential = $publicKeyCredentialLoader->load(
json_encode($attestationResponseDecoded, JSON_THROW_ON_ERROR),
);
$authenticatorResponse = $publicKeyCredential->getResponse();
Assert::isInstanceOf(
$authenticatorResponse,
AuthenticatorAttestationResponse::class,
'Not an authenticator attestation response',
);
$authenticatorAttestationResponseValidator = new AuthenticatorAttestationResponseValidator(
$attestationStatementSupportManager,
$publicKeyCredentialSourceRepository,
new IgnoreTokenBindingHandler(),
new ExtensionOutputCheckerHandler(),
);
$publicKeyCredentialSource = $authenticatorAttestationResponseValidator->check(
$authenticatorResponse,
$credentialCreationOptions,
$request,
);
return $publicKeyCredentialSource->jsonSerialize();
return $this->normalize($publicKeyCredentialSource);
}
/** @infection-ignore-all */
@ -229,7 +365,10 @@ final class WebauthnLibServer implements Server
{
$data = $this->read();
$id = $publicKeyCredentialSource->getPublicKeyCredentialId();
$data[base64_encode($id)] = $publicKeyCredentialSource->jsonSerialize();
$encoded = json_encode($publicKeyCredentialSource, JSON_THROW_ON_ERROR);
$normalized = json_decode($encoded, true, flags: JSON_THROW_ON_ERROR);
Assert::isArray($normalized);
$data[base64_encode($id)] = $normalized;
$this->write($data);
}
@ -239,6 +378,10 @@ final class WebauthnLibServer implements Server
/** @psalm-var list<mixed[]> $credentials */
$credentials = $this->twoFactor->config['settings']['credentials'];
foreach ($credentials as &$credential) {
if (str_ends_with($credential['userHandle'], '=')) {
$credential['userHandle'] = rtrim($credential['userHandle'], '=');
}
if (isset($credential['trustPath'])) {
continue;
}
@ -256,4 +399,14 @@ final class WebauthnLibServer implements Server
}
};
}
/** @return mixed[] */
private function normalize(object $object): array
{
$encoded = json_encode($object, JSON_THROW_ON_ERROR);
$normalized = json_decode($encoded, true, flags: JSON_THROW_ON_ERROR);
Assert::isArray($normalized);
return $normalized;
}
}

View File

@ -11,10 +11,9 @@ use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\UriInterface;
use Webauthn\Server as WebauthnServer;
use Webauthn\PublicKeyCredential;
use Webauthn\TrustPath\EmptyTrustPath;
use function base64_encode;
use function class_exists;
#[CoversClass(WebauthnLibServer::class)]
@ -24,7 +23,7 @@ final class WebauthnLibServerTest extends TestCase
{
parent::setUp();
if (class_exists(WebauthnServer::class)) {
if (class_exists(PublicKeyCredential::class)) {
return;
}
@ -45,7 +44,7 @@ final class WebauthnLibServerTest extends TestCase
self::assertSame('test.localhost', $options['rp']['id']);
self::assertSame('user_name', $options['user']['name']);
self::assertSame('user_name', $options['user']['displayName']);
self::assertSame(base64_encode('user_id'), $options['user']['id']);
self::assertSame('dXNlcl9pZA', $options['user']['id']);
self::assertArrayHasKey('authenticatorAttachment', $options['authenticatorSelection']);
self::assertSame('cross-platform', $options['authenticatorSelection']['authenticatorAttachment']);
}
@ -156,7 +155,8 @@ final class WebauthnLibServerTest extends TestCase
'credentialPublicKey' => 'pQECAyYgASFYIJV56vRrFusoDf9hm3iDmllcxxXzzKyO9WruKw4kWx7zIlgg_nq63l8IMJcIdKDJcXRh9hoz0L-nVwP1Oxil3_oNQYs',
'userHandle' => 'Zm9v',
'counter' => 123,
'otherUI' => null,
'backupEligible' => false,
'backupStatus' => false,
],
],
$twoFactor->config['settings']['credentials'],
@ -196,7 +196,9 @@ final class WebauthnLibServerTest extends TestCase
'credentialPublicKey' => 'pQECAyYgASFYIBw_HArIcANWNOBOxq3hH8lrHo9a17nQDxlqwybjDpHEIlggu3QUKIbALqsGuHfJI3LTKJSNmk0YCFb5oz1hjJidRMk',
'userHandle' => 'MJr5sD0WitVwZM0eoSO6kWhyseT67vc3oQdk_k1VdZQ',
'counter' => 0,
'otherUI' => null,
'backupEligible' => false,
'backupStatus' => false,
'uvInitialized' => false,
],
$credential,
);