1
0
mirror of https://github.com/phpmyadmin/phpmyadmin.git synced 2026-10-23 18:29:15 +03:00

Remove PublicKeyCredentialSourceRepository interface

It's deprecated. Uses CeremonyStepManagerFactory instead.

Signed-off-by: Maurício Meneghini Fauth <mauricio@mfauth.com.br>
This commit is contained in:
Maurício Meneghini Fauth
2026-09-19 20:25:02 -03:00
parent 21ef436eff
commit 72ddabe093
3 changed files with 66 additions and 113 deletions

View File

@@ -13878,12 +13878,6 @@ parameters:
count: 1
path: src/WebAuthn/CBORDecoder.php
-
message: '#^Anonymous class implements deprecated interface Webauthn\\PublicKeyCredentialSourceRepository\.$#'
identifier: class.implementsDeprecatedInterface
count: 1
path: src/WebAuthn/WebauthnLibServer.php
-
message: '''
#^Call to deprecated method createFromArray\(\) of class Webauthn\\AuthenticatorSelectionCriteria\:
@@ -13929,12 +13923,6 @@ parameters:
count: 2
path: src/WebAuthn/WebauthnLibServer.php
-
message: '#^Call to method findAllForUserEntity\(\) of deprecated interface Webauthn\\PublicKeyCredentialSourceRepository\.$#'
identifier: method.deprecatedInterface
count: 1
path: src/WebAuthn/WebauthnLibServer.php
-
message: '''
#^Call to method load\(\) of deprecated class Webauthn\\PublicKeyCredentialLoader\:
@@ -13962,15 +13950,6 @@ parameters:
count: 4
path: src/WebAuthn/WebauthnLibServer.php
-
message: '''
#^Instantiation of deprecated class Webauthn\\TokenBinding\\IgnoreTokenBindingHandler\:
Since 4\.3\.0 and will be removed in 5\.0\.0$#
'''
identifier: new.deprecatedClass
count: 2
path: src/WebAuthn/WebauthnLibServer.php
-
message: '#^Parameter \#1 \$haystack of function str_ends_with expects string, mixed given\.$#'
identifier: argument.type
@@ -13989,12 +13968,6 @@ parameters:
count: 3
path: src/WebAuthn/WebauthnLibServer.php
-
message: '#^Return type of method PhpMyAdmin\\WebAuthn\\WebauthnLibServer\:\:createPublicKeyCredentialSourceRepository\(\) has typehint with deprecated interface Webauthn\\PublicKeyCredentialSourceRepository\.$#'
identifier: return.deprecatedInterface
count: 1
path: src/WebAuthn/WebauthnLibServer.php
-
message: '#^Call to function is_array\(\) with array\<string\> will always evaluate to true\.$#'
identifier: function.alreadyNarrowedType

View File

@@ -8146,13 +8146,7 @@
<code><![CDATA[PublicKeyCredentialLoader::create($attestationObjectLoader)]]></code>
<code><![CDATA[PublicKeyCredentialLoader::create($attestationObjectLoader)]]></code>
<code><![CDATA[PublicKeyCredentialLoader::create($attestationObjectLoader)]]></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',

View File

@@ -15,12 +15,12 @@ use Webauthn\AttestationStatement\AttestationObjectLoader;
use Webauthn\AttestationStatement\AttestationStatementSupportManager;
use Webauthn\AttestationStatement\NoneAttestationStatementSupport;
use Webauthn\AuthenticationExtensions\AuthenticationExtensions;
use Webauthn\AuthenticationExtensions\ExtensionOutputCheckerHandler;
use Webauthn\AuthenticatorAssertionResponse;
use Webauthn\AuthenticatorAssertionResponseValidator;
use Webauthn\AuthenticatorAttestationResponse;
use Webauthn\AuthenticatorAttestationResponseValidator;
use Webauthn\AuthenticatorSelectionCriteria;
use Webauthn\CeremonyStep\CeremonyStepManagerFactory;
use Webauthn\PublicKeyCredentialCreationOptions;
use Webauthn\PublicKeyCredentialDescriptor;
use Webauthn\PublicKeyCredentialLoader;
@@ -28,9 +28,7 @@ use Webauthn\PublicKeyCredentialParameters;
use Webauthn\PublicKeyCredentialRequestOptions;
use Webauthn\PublicKeyCredentialRpEntity;
use Webauthn\PublicKeyCredentialSource;
use Webauthn\PublicKeyCredentialSourceRepository;
use Webauthn\PublicKeyCredentialUserEntity;
use Webauthn\TokenBinding\IgnoreTokenBindingHandler;
use Webauthn\TrustPath\EmptyTrustPath;
use Webmozart\Assert\Assert;
@@ -125,8 +123,7 @@ final class WebauthnLibServer implements Server
): array {
$userEntity = new PublicKeyCredentialUserEntity($userName, $userId, $userName);
$relyingPartyEntity = new PublicKeyCredentialRpEntity('phpMyAdmin (' . $relyingPartyId . ')', $relyingPartyId);
$publicKeyCredentialSourceRepository = $this->createPublicKeyCredentialSourceRepository();
$credentialSources = $publicKeyCredentialSourceRepository->findAllForUserEntity($userEntity);
$credentialSources = $this->findCredentialsForUserEntity($userEntity);
$allowedCredentials = array_map(
static fn (
PublicKeyCredentialSource $credential,
@@ -174,7 +171,6 @@ final class WebauthnLibServer implements Server
$userHandle = Base64::decodeUrlSafeNoPadding($this->twofactor->config['settings']['userHandle']);
$userEntity = new PublicKeyCredentialUserEntity($this->twofactor->user, $userHandle, $this->twofactor->user);
$host = $request->getUri()->getHost();
$publicKeyCredentialSourceRepository = $this->createPublicKeyCredentialSourceRepository();
$requestOptions = PublicKeyCredentialRequestOptions::createFromArray([
'challenge' => $challenge,
'allowCredentials' => $allowedCredentials,
@@ -205,20 +201,23 @@ final class WebauthnLibServer implements Server
'Not an authenticator assertion response',
);
$publicKeyCredentialSource = $this->findCredentialByCredentialId($publicKeyCredential->rawId);
Assert::notNull($publicKeyCredentialSource);
$csmFactory = new CeremonyStepManagerFactory();
$authenticatorAssertionResponseValidator = new AuthenticatorAssertionResponseValidator(
$publicKeyCredentialSourceRepository,
new IgnoreTokenBindingHandler(),
new ExtensionOutputCheckerHandler(),
$this->coseAlgorithmManagerFactory->generate(...$this->selectedAlgorithms),
ceremonyStepManager: $csmFactory->requestCeremony(),
);
$authenticatorAssertionResponseValidator->check(
$publicKeyCredential->rawId,
$credential = $authenticatorAssertionResponseValidator->check(
$publicKeyCredentialSource,
$authenticatorResponse,
$requestOptions,
$request,
$host,
$userEntity->id,
);
$this->saveCredentialSource($credential);
}
/** @inheritDoc */
@@ -234,7 +233,6 @@ final class WebauthnLibServer implements Server
Assert::isArray($creationOptions['user']);
Assert::keyExists($creationOptions['user'], 'id');
$host = $request->getUri()->getHost();
$publicKeyCredentialSourceRepository = $this->createPublicKeyCredentialSourceRepository();
$creationOptionsArray = [
'rp' => ['name' => 'phpMyAdmin (' . $host . ')', 'id' => $host],
'pubKeyCredParams' => [
@@ -281,93 +279,81 @@ final class WebauthnLibServer implements Server
'Not an authenticator attestation response',
);
$csmFactory = new CeremonyStepManagerFactory();
$authenticatorAttestationResponseValidator = new AuthenticatorAttestationResponseValidator(
$attestationStatementSupportManager,
$publicKeyCredentialSourceRepository,
new IgnoreTokenBindingHandler(),
new ExtensionOutputCheckerHandler(),
ceremonyStepManager: $csmFactory->creationCeremony(),
);
$publicKeyCredentialSource = $authenticatorAttestationResponseValidator->check(
$authenticatorResponse,
$credentialCreationOptions,
$request,
$host,
);
return $this->normalize($publicKeyCredentialSource);
}
/** @infection-ignore-all */
private function createPublicKeyCredentialSourceRepository(): PublicKeyCredentialSourceRepository
private function findCredentialByCredentialId(string $publicKeyCredentialId): PublicKeyCredentialSource|null
{
return new class ($this->twofactor) implements PublicKeyCredentialSourceRepository {
public function __construct(private TwoFactor $twoFactor)
{
$data = $this->readCredentialsFromConfig();
if (isset($data[Base64::encode($publicKeyCredentialId)])) {
return PublicKeyCredentialSource::createFromArray($data[Base64::encode($publicKeyCredentialId)]);
}
return null;
}
/** @return PublicKeyCredentialSource[] */
private function findCredentialsForUserEntity(PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity): array
{
$sources = [];
foreach ($this->readCredentialsFromConfig() as $data) {
$source = PublicKeyCredentialSource::createFromArray($data);
if ($source->userHandle !== $publicKeyCredentialUserEntity->id) {
continue;
}
public function findOneByCredentialId(string $publicKeyCredentialId): PublicKeyCredentialSource|null
{
$data = $this->read();
if (isset($data[Base64::encode($publicKeyCredentialId)])) {
return PublicKeyCredentialSource::createFromArray($data[Base64::encode($publicKeyCredentialId)]);
}
$sources[] = $source;
}
return null;
return $sources;
}
private function saveCredentialSource(PublicKeyCredentialSource $publicKeyCredentialSource): void
{
$data = $this->readCredentialsFromConfig();
$id = $publicKeyCredentialSource->publicKeyCredentialId;
$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->writeCredentialsToConfig($data);
}
/** @return mixed[][] */
private function readCredentialsFromConfig(): array
{
/** @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'], '=');
}
/** @return PublicKeyCredentialSource[] */
public function findAllForUserEntity(PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity): array
{
$sources = [];
foreach ($this->read() as $data) {
$source = PublicKeyCredentialSource::createFromArray($data);
if ($source->userHandle !== $publicKeyCredentialUserEntity->id) {
continue;
}
$sources[] = $source;
}
return $sources;
if (isset($credential['trustPath'])) {
continue;
}
public function saveCredentialSource(PublicKeyCredentialSource $publicKeyCredentialSource): void
{
$data = $this->read();
$id = $publicKeyCredentialSource->publicKeyCredentialId;
$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);
}
$credential['trustPath'] = ['type' => EmptyTrustPath::class];
}
/** @return mixed[][] */
private function read(): array
{
/** @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'], '=');
}
return $credentials;
}
if (isset($credential['trustPath'])) {
continue;
}
$credential['trustPath'] = ['type' => EmptyTrustPath::class];
}
return $credentials;
}
/** @param mixed[] $data */
private function write(array $data): void
{
$this->twoFactor->config['settings']['credentials'] = $data;
}
};
/** @param mixed[] $data */
private function writeCredentialsToConfig(array $data): void
{
$this->twofactor->config['settings']['credentials'] = $data;
}
/** @return mixed[] */