262 lines
9.0 KiB
PHP
262 lines
9.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2014-2021 Spomky-Labs
|
|
*
|
|
* This software may be modified and distributed under the terms
|
|
* of the MIT license. See the LICENSE file for details.
|
|
*/
|
|
|
|
namespace Webauthn;
|
|
|
|
use Assert\Assertion;
|
|
use Base64Url\Base64Url;
|
|
use function count;
|
|
use function Safe\json_decode;
|
|
use Webauthn\AuthenticationExtensions\AuthenticationExtensionsClientInputs;
|
|
|
|
class PublicKeyCredentialCreationOptions extends PublicKeyCredentialOptions
|
|
{
|
|
public const ATTESTATION_CONVEYANCE_PREFERENCE_NONE = 'none';
|
|
public const ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT = 'indirect';
|
|
public const ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT = 'direct';
|
|
public const ATTESTATION_CONVEYANCE_PREFERENCE_ENTERPRISE = 'enterprise';
|
|
|
|
/**
|
|
* @var PublicKeyCredentialRpEntity
|
|
*/
|
|
private $rp;
|
|
|
|
/**
|
|
* @var PublicKeyCredentialUserEntity
|
|
*/
|
|
private $user;
|
|
|
|
/**
|
|
* @var PublicKeyCredentialParameters[]
|
|
*/
|
|
private $pubKeyCredParams = [];
|
|
|
|
/**
|
|
* @var PublicKeyCredentialDescriptor[]
|
|
*/
|
|
private $excludeCredentials = [];
|
|
|
|
/**
|
|
* @var AuthenticatorSelectionCriteria
|
|
*/
|
|
private $authenticatorSelection;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
private $attestation;
|
|
|
|
/**
|
|
* @param PublicKeyCredentialParameters[] $pubKeyCredParams
|
|
* @param PublicKeyCredentialDescriptor[] $excludeCredentials
|
|
*/
|
|
public function __construct(PublicKeyCredentialRpEntity $rp, PublicKeyCredentialUserEntity $user, string $challenge, array $pubKeyCredParams, ?int $timeout = null, array $excludeCredentials = [], ?AuthenticatorSelectionCriteria $authenticatorSelection = null, ?string $attestation = null, ?AuthenticationExtensionsClientInputs $extensions = null)
|
|
{
|
|
if (0 !== count($excludeCredentials)) {
|
|
@trigger_error('The argument "excludeCredentials" is deprecated since version 3.3 and will be removed in 4.0. Please use the method "excludeCredentials" or "excludeCredential".', E_USER_DEPRECATED);
|
|
}
|
|
if (null !== $authenticatorSelection) {
|
|
@trigger_error('The argument "authenticatorSelection" is deprecated since version 3.3 and will be removed in 4.0. Please use the method "setAuthenticatorSelection".', E_USER_DEPRECATED);
|
|
}
|
|
if (null !== $attestation) {
|
|
@trigger_error('The argument "attestation" is deprecated since version 3.3 and will be removed in 4.0. Please use the method "setAttestation".', E_USER_DEPRECATED);
|
|
}
|
|
parent::__construct($challenge, $timeout, $extensions);
|
|
$this->rp = $rp;
|
|
$this->user = $user;
|
|
$this->pubKeyCredParams = $pubKeyCredParams;
|
|
$this->authenticatorSelection = $authenticatorSelection ?? new AuthenticatorSelectionCriteria();
|
|
$this->attestation = $attestation ?? self::ATTESTATION_CONVEYANCE_PREFERENCE_NONE;
|
|
$this->excludeCredentials($excludeCredentials)
|
|
;
|
|
}
|
|
|
|
/**
|
|
* @param PublicKeyCredentialParameters[] $pubKeyCredParams
|
|
*/
|
|
public static function create(PublicKeyCredentialRpEntity $rp, PublicKeyCredentialUserEntity $user, string $challenge, array $pubKeyCredParams): self
|
|
{
|
|
return new self($rp, $user, $challenge, $pubKeyCredParams);
|
|
}
|
|
|
|
public function addPubKeyCredParam(PublicKeyCredentialParameters $pubKeyCredParam): self
|
|
{
|
|
$this->pubKeyCredParams[] = $pubKeyCredParam;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param PublicKeyCredentialParameters[] $pubKeyCredParams
|
|
*/
|
|
public function addPubKeyCredParams(array $pubKeyCredParams): self
|
|
{
|
|
foreach ($pubKeyCredParams as $pubKeyCredParam) {
|
|
$this->addPubKeyCredParam($pubKeyCredParam);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function excludeCredential(PublicKeyCredentialDescriptor $excludeCredential): self
|
|
{
|
|
$this->excludeCredentials[] = $excludeCredential;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* @param PublicKeyCredentialDescriptor[] $excludeCredentials
|
|
*/
|
|
public function excludeCredentials(array $excludeCredentials): self
|
|
{
|
|
foreach ($excludeCredentials as $excludeCredential) {
|
|
$this->excludeCredential($excludeCredential);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setAuthenticatorSelection(AuthenticatorSelectionCriteria $authenticatorSelection): self
|
|
{
|
|
$this->authenticatorSelection = $authenticatorSelection;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function setAttestation(string $attestation): self
|
|
{
|
|
Assertion::inArray($attestation, [
|
|
self::ATTESTATION_CONVEYANCE_PREFERENCE_NONE,
|
|
self::ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT,
|
|
self::ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT,
|
|
self::ATTESTATION_CONVEYANCE_PREFERENCE_ENTERPRISE,
|
|
], 'Invalid attestation conveyance mode');
|
|
$this->attestation = $attestation;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getRp(): PublicKeyCredentialRpEntity
|
|
{
|
|
return $this->rp;
|
|
}
|
|
|
|
public function getUser(): PublicKeyCredentialUserEntity
|
|
{
|
|
return $this->user;
|
|
}
|
|
|
|
/**
|
|
* @return PublicKeyCredentialParameters[]
|
|
*/
|
|
public function getPubKeyCredParams(): array
|
|
{
|
|
return $this->pubKeyCredParams;
|
|
}
|
|
|
|
/**
|
|
* @return PublicKeyCredentialDescriptor[]
|
|
*/
|
|
public function getExcludeCredentials(): array
|
|
{
|
|
return $this->excludeCredentials;
|
|
}
|
|
|
|
public function getAuthenticatorSelection(): AuthenticatorSelectionCriteria
|
|
{
|
|
return $this->authenticatorSelection;
|
|
}
|
|
|
|
public function getAttestation(): string
|
|
{
|
|
return $this->attestation;
|
|
}
|
|
|
|
public static function createFromString(string $data): PublicKeyCredentialOptions
|
|
{
|
|
$data = json_decode($data, true);
|
|
Assertion::isArray($data, 'Invalid data');
|
|
|
|
return self::createFromArray($data);
|
|
}
|
|
|
|
public static function createFromArray(array $json): PublicKeyCredentialOptions
|
|
{
|
|
Assertion::keyExists($json, 'rp', 'Invalid input. "rp" is missing.');
|
|
Assertion::keyExists($json, 'pubKeyCredParams', 'Invalid input. "pubKeyCredParams" is missing.');
|
|
Assertion::isArray($json['pubKeyCredParams'], 'Invalid input. "pubKeyCredParams" is not an array.');
|
|
Assertion::keyExists($json, 'challenge', 'Invalid input. "challenge" is missing.');
|
|
Assertion::keyExists($json, 'attestation', 'Invalid input. "attestation" is missing.');
|
|
Assertion::keyExists($json, 'user', 'Invalid input. "user" is missing.');
|
|
Assertion::keyExists($json, 'authenticatorSelection', 'Invalid input. "authenticatorSelection" is missing.');
|
|
|
|
$pubKeyCredParams = [];
|
|
foreach ($json['pubKeyCredParams'] as $pubKeyCredParam) {
|
|
$pubKeyCredParams[] = PublicKeyCredentialParameters::createFromArray($pubKeyCredParam);
|
|
}
|
|
$excludeCredentials = [];
|
|
if (isset($json['excludeCredentials'])) {
|
|
foreach ($json['excludeCredentials'] as $excludeCredential) {
|
|
$excludeCredentials[] = PublicKeyCredentialDescriptor::createFromArray($excludeCredential);
|
|
}
|
|
}
|
|
|
|
return self::create(
|
|
PublicKeyCredentialRpEntity::createFromArray($json['rp']),
|
|
PublicKeyCredentialUserEntity::createFromArray($json['user']),
|
|
Base64Url::decode($json['challenge']),
|
|
$pubKeyCredParams
|
|
)
|
|
->excludeCredentials($excludeCredentials)
|
|
->setAuthenticatorSelection(AuthenticatorSelectionCriteria::createFromArray($json['authenticatorSelection']))
|
|
->setAttestation($json['attestation'])
|
|
->setTimeout($json['timeout'] ?? null)
|
|
->setExtensions(isset($json['extensions']) ? AuthenticationExtensionsClientInputs::createFromArray($json['extensions']) : new AuthenticationExtensionsClientInputs())
|
|
;
|
|
}
|
|
|
|
/**
|
|
* @return mixed[]
|
|
*/
|
|
public function jsonSerialize(): array
|
|
{
|
|
$json = [
|
|
'rp' => $this->rp->jsonSerialize(),
|
|
'pubKeyCredParams' => array_map(static function (PublicKeyCredentialParameters $object): array {
|
|
return $object->jsonSerialize();
|
|
}, $this->pubKeyCredParams),
|
|
'challenge' => Base64Url::encode($this->challenge),
|
|
'attestation' => $this->attestation,
|
|
'user' => $this->user->jsonSerialize(),
|
|
'authenticatorSelection' => $this->authenticatorSelection->jsonSerialize(),
|
|
];
|
|
|
|
if (0 !== count($this->excludeCredentials)) {
|
|
$json['excludeCredentials'] = array_map(static function (PublicKeyCredentialDescriptor $object): array {
|
|
return $object->jsonSerialize();
|
|
}, $this->excludeCredentials);
|
|
}
|
|
|
|
if (0 !== $this->extensions->count()) {
|
|
$json['extensions'] = $this->extensions;
|
|
}
|
|
|
|
if (null !== $this->timeout) {
|
|
$json['timeout'] = $this->timeout;
|
|
}
|
|
|
|
return $json;
|
|
}
|
|
}
|