With Doctrine, you have to indicate how to store the Credential Source objects. Hereafter an example an entity. In this example we add an entity id and a custom field created_at. We also indicate the repository as we will have a custom one.
As the ID must have a fixed length and because the credentialId field of Webauthn\PublicKeyCredentialSource haven’t such requirement and is a binary string, we need to declare our own id field.
App/Entity/PublicKeyCredentialSource.php
<?phpdeclare(strict_types=1);/* * The MIT License (MIT) * * Copyright (c) 2014-2019 Spomky-Labs * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */namespaceApp\Entity;useDoctrine\ORM\Mappingas ORM;useRamsey\Uuid\Uuid;useRamsey\Uuid\UuidInterface;useWebauthn\PublicKeyCredentialSourceas BasePublicKeyCredentialSource;useWebauthn\TrustPath\TrustPath;/** * @ORM\Table(name="public_key_credential_sources") * @ORM\Entity(repositoryClass="App\Repository\PublicKeyCredentialSourceRepository") */classPublicKeyCredentialSourceextendsBasePublicKeyCredentialSource{/** * @varstring * @ORM\Id * @ORM\Column(type="string", length=100) * @ORM\GeneratedValue(strategy="NONE") */private $id;/** * @var\DateTimeImmutable * @ORM\Column(type="datetime_immutable") */private $createdAt; public function __construct(string $publicKeyCredentialId, string $type, array $transports, string $attestationType, TrustPath $trustPath, UuidInterface $aaguid, string $credentialPublicKey, string $userHandle, int $counter)
{$this->id =Uuid::uuid4()->toString();$this->createdAt =new\DateTimeImmutable(); parent::__construct($publicKeyCredentialId, $type, $transports, $attestationType, $trustPath, $aaguid, $credentialPublicKey, $userHandle, $counter);
}publicfunctiongetId():string {return$this->id; }publicfunctiongetCreatedAt():\DateTimeImmutable {return$this->createdAt; }}
The Repository
To ease the integration into your application, the bundle provides a concrete class that you can extend.
In this following example, we extend that class and add a method to get all credentials for a specific user handle. Feel free to add your own methods.
We must override the method saveCredentialSource because we may receive Webauthn\PublicKeyCredentialSource objects instead of App\Entity\PublicKeyCredentialSource.
In a Symfony application context, you usually have to manage several user entities. Thus, in the following example, the user entity class will extend the required calls and implements the interface provided by the Symfony Security component.
Feel free to add the necessary setters as well as other fields you need (creation date, last update at…).
Please note that the ID of the user IS NOT generated by Doctrine and must be a string. We highly recommend you to use UUIDs.
The following example uses Doctrine to create, persist or perform queries using the User objects created above.
app/Repository/UserRepository.php
<?phpdeclare(strict_types=1);/* * The MIT License (MIT) * * Copyright (c) 2014-2019 Spomky-Labs * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */namespaceApp\Repository;useApp\Entity\User;useDoctrine\Common\Persistence\ManagerRegistry;useWebauthn\Bundle\Repository\AbstractPublicKeyCredentialUserEntityRepository;useWebauthn\PublicKeyCredentialUserEntity;finalclassPublicKeyCredentialUserEntityRepositoryextendsAbstractPublicKeyCredentialUserEntityRepository{publicfunction__construct(ManagerRegistry $registry) {parent::__construct($registry,User::class); } public function createUserEntity(string $username, string $displayName, ?string $icon): PublicKeyCredentialUserEntity
{returnnewUser($username, $displayName, [], $icon); }publicfunctionsaveUserEntity(PublicKeyCredentialUserEntity $userEntity):void {if (!$userEntity instanceofUser) { $userEntity =$this->createUserEntity( $userEntity->getName(), $userEntity->getDisplayName(), [], $userEntity->getIcon()); }parent::saveUserEntity($userEntity); }publicfunctionfind(string $username):?User { $qb =$this->getEntityManager()->createQueryBuilder();return $qb->select('u')->from(User::class,'u')->where('u.name = :name')->setParameter(':name', $username)->setMaxResults(1)->getQuery()->getOneOrNullResult() ; }}
This repository should be declared as a Symfony service.
With Symfony 4, this is usually done automatically