Credential Source Repository
Authenticator details and how to manage them
After the registration of an authenticator, you will get a Public Key Credential Source object. It contains all the credential data needed to perform user authentication and much more.
Each Credential Source is managed using the Public Key Credential Source Repository.
The library does not provide any concrete implementation. It is up to you to create it depending on your application constraints. This only constraint is that your repository class must implement the interface Webauthn\PublicKeyCredentialSourceRepository.

Examples

Filesystem Repository

Please don’t use this example in production! It will store credential source objects in a temporary folder.
Acme\Repository\PublicKeyCredentialSourceRepository.php
1
<?php
2
/**
3
* EGroupware WebAuthn
4
*
5
* @link https://www.egroupware.org
6
* @author Ralf Becker <rb-At-egroupware.org>
7
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
8
*/
9
10
namespace Acme\Repository;
11
12
use Webauthn\PublicKeyCredentialSourceRepository as PublicKeyCredentialSourceRepositoryInterface;
13
use Webauthn\PublicKeyCredentialSource;
14
use Webauthn\PublicKeyCredentialUserEntity;
15
16
class PublicKeyCredentialSourceRepository implements PublicKeyCredentialSourceRepositoryInterface
17
{
18
private $path = '/tmp/pubkey-repo.json';
19
20
public function findOneByCredentialId(string $publicKeyCredentialId): ?PublicKeyCredentialSource
21
{
22
$data = $this->read();
23
if (isset($data[base64_encode($publicKeyCredentialId)]))
24
{
25
return PublicKeyCredentialSource::createFromArray($data[base64_encode($publicKeyCredentialId)]);
26
}
27
return null;
28
}
29
30
/**
31
* @return PublicKeyCredentialSource[]
32
*/
33
public function findAllForUserEntity(PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity): array
34
{
35
$sources = [];
36
foreach($this->read() as $data)
37
{
38
$source = PublicKeyCredentialSource::createFromArray($data);
39
if ($source->getUserHandle() === $publicKeyCredentialUserEntity->getId())
40
{
41
$sources[] = $source;
42
}
43
}
44
return $sources;
45
}
46
47
public function saveCredentialSource(PublicKeyCredentialSource $publicKeyCredentialSource): void
48
{
49
$data = $this->read();
50
$data[base64_encode($publicKeyCredentialSource->getPublicKeyCredentialId())] = $publicKeyCredentialSource;
51
$this->write($data);
52
}
53
54
private function read(): array
55
{
56
if (file_exists($this->path))
57
{
58
return json_decode(file_get_contents($this->path), true);
59
}
60
return [];
61
}
62
63
private function write(array $data): void
64
{
65
if (!file_exists($this->path))
66
{
67
if (!mkdir($concurrentDirectory = dirname($this->path), 0700, true) && !is_dir($concurrentDirectory)) {
68
throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
69
}
70
}
71
file_put_contents($this->path, json_encode($data), LOCK_EX);
72
}
73
}
Copied!

Doctrine Repository

You must add custom Doctrine types to convert plain PHP objects into your ORM. Please have a look at this folder to find examples.
If you use Symfony, this repository already exists and custom Doctrine types are automatically registered.
Acme\Repository\PublicKeyCredentialSourceRepository.php
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
* The MIT License (MIT)
7
*
8
* Copyright (c) 2014-2019 Spomky-Labs
9
*
10
* This software may be modified and distributed under the terms
11
* of the MIT license. See the LICENSE file for details.
12
*/
13
14
namespace Webauthn\Repository;
15
16
use Assert\Assertion;
17
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface;
18
use Doctrine\Common\Persistence\ManagerRegistry;
19
use Doctrine\ORM\EntityManagerInterface;
20
use Webauthn\PublicKeyCredentialSource;
21
use Webauthn\PublicKeyCredentialSourceRepository as PublicKeyCredentialSourceRepositoryInterface;
22
use Webauthn\PublicKeyCredentialUserEntity;
23
24
class PublicKeyCredentialSourceRepository implements PublicKeyCredentialSourceRepositoryInterface, ServiceEntityRepositoryInterface
25
{
26
/**
27
* @var EntityManagerInterface
28
*/
29
private $manager;
30
31
/**
32
* @var string
33
*/
34
private $class;
35
36
public function __construct(ManagerRegistry $registry, string $class)
37
{
38
Assertion::subclassOf($class, PublicKeyCredentialSource::class, sprintf(
39
'Invalid class. Must be an instance of "Webauthn\PublicKeyCredentialSource", got "%s" instead.',
40
$class
41
));
42
$manager = $registry->getManagerForClass($class);
43
Assertion::isInstanceOf($manager, EntityManagerInterface::class, sprintf(
44
'Could not find the entity manager for class "%s". Check your Doctrine configuration to make sure it is configured to load this entity’s metadata.',
45
$class
46
));
47
48
$this->class = $class;
49
$this->manager = $manager;
50
}
51
52
protected function getClass(): string
53
{
54
return $this->class;
55
}
56
57
protected function getEntityManager(): EntityManagerInterface
58
{
59
return $this->manager;
60
}
61
62
public function saveCredentialSource(PublicKeyCredentialSource $publicKeyCredentialSource, bool $flush = true): void
63
{
64
$this->manager->persist($publicKeyCredentialSource);
65
if ($flush) {
66
$this->manager->flush();
67
}
68
}
69
70
/**
71
* {@inheritdoc}
72
*/
73
public function findAllForUserEntity(PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity): array
74
{
75
$qb = $this->manager->createQueryBuilder();
76
77
return $qb->select('c')
78
->from($this->getClass(), 'c')
79
->where('c.userHandle = :userHandle')
80
->setParameter(':userHandle', $publicKeyCredentialUserEntity->getId())
81
->getQuery()
82
->execute()
83
;
84
}
85
86
public function findOneByCredentialId(string $publicKeyCredentialId): ?PublicKeyCredentialSource
87
{
88
$qb = $this->manager->createQueryBuilder();
89
90
return $qb->select('c')
91
->from($this->getClass(), 'c')
92
->where('c.publicKeyCredentialId = :publicKeyCredentialId')
93
->setParameter(':publicKeyCredentialId', base64_encode($publicKeyCredentialId))
94
->setMaxResults(1)
95
->getQuery()
96
->getOneOrNullResult()
97
;
98
}
99
}
Copied!
Last modified 2mo ago