Completed
Push — master ( d7d555...8d86ce )
by Thomas
06:51 queued 03:43
created

ServerBuilder::allowNoneAttestation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
1
<?php
2
3
namespace MadWizard\WebAuthn\Builder;
4
5
use GuzzleHttp\Client;
6
use MadWizard\WebAuthn\Attestation\AttestationType;
7
use MadWizard\WebAuthn\Attestation\TrustAnchor\TrustPathValidator;
8
use MadWizard\WebAuthn\Attestation\TrustAnchor\TrustPathValidatorInterface;
9
use MadWizard\WebAuthn\Cache\CacheProviderInterface;
10
use MadWizard\WebAuthn\Cache\FileCacheProvider;
11
use MadWizard\WebAuthn\Config\RelyingParty;
12
use MadWizard\WebAuthn\Config\RelyingPartyInterface;
13
use MadWizard\WebAuthn\Credential\CredentialStoreInterface;
14
use MadWizard\WebAuthn\Exception\ConfigurationException;
15
use MadWizard\WebAuthn\Metadata\MetadataResolver;
16
use MadWizard\WebAuthn\Metadata\MetadataResolverInterface;
17
use MadWizard\WebAuthn\Metadata\NullMetadataResolver;
18
use MadWizard\WebAuthn\Metadata\Source\MetadataSourceInterface;
19
use MadWizard\WebAuthn\Pki\CertificateStatusResolverInterface;
20
use MadWizard\WebAuthn\Pki\ChainValidator;
21
use MadWizard\WebAuthn\Pki\ChainValidatorInterface;
22
use MadWizard\WebAuthn\Policy\Policy;
23
use MadWizard\WebAuthn\Policy\PolicyInterface;
24
use MadWizard\WebAuthn\Policy\Trust\TrustDecisionManager;
25
use MadWizard\WebAuthn\Policy\Trust\TrustDecisionManagerInterface;
26
use MadWizard\WebAuthn\Policy\Trust\Voter\AllowEmptyMetadataVoter;
27
use MadWizard\WebAuthn\Policy\Trust\Voter\SupportedAttestationTypeVoter;
28
use MadWizard\WebAuthn\Policy\Trust\Voter\TrustAttestationTypeVoter;
29
use MadWizard\WebAuthn\Policy\Trust\Voter\TrustChainVoter;
30
use MadWizard\WebAuthn\Policy\Trust\Voter\UndesiredStatusReportVoter;
31
use MadWizard\WebAuthn\Remote\CachingClientFactory;
32
use MadWizard\WebAuthn\Remote\Downloader;
33
use MadWizard\WebAuthn\Remote\DownloaderInterface;
34
use MadWizard\WebAuthn\Server\ServerInterface;
35
use MadWizard\WebAuthn\Server\WebAuthnServer;
36
use Psr\Log\LoggerAwareInterface;
37
use Psr\Log\LoggerInterface;
38
39
final class ServerBuilder
40
{
41
    use MetadataProviderFactoryTrait;
42
43
    /**
44
     * @var RelyingParty|null
45
     */
46
    private $rp;
47
48
    /**
49
     * @var CredentialStoreInterface|null
50
     */
51
    private $store;
52
53
    /**
54
     * @var string|null;
55
     */
56
    private $cacheDir;
57
58
    /**
59
     * @var callable|PolicyCallbackInterface|null
60
     */
61
    private $policyCallback;
62
63
    /**
64
     * @var MetadataSourceInterface[]
65
     */
66
    private $metadataSources = [];
67
68
    /**
69
     * @var DownloaderInterface|null
70
     */
71
    private $downloader;
72
73
    /**
74
     * @var Client|null
75
     */
76
    private $httpClient;
77
78
    /**
79
     * @var CacheProviderInterface|null
80
     */
81
    private $cacheProvider;
82
83
    /**
84
     * @var ChainValidatorInterface|null
85
     */
86
    private $chainValidator;
87
88
    /**
89
     * @var TrustDecisionManagerInterface|null
90
     */
91
    private $trustDecisionManager;
92
93
    /**
94
     * @var LoggerInterface|null
95
     */
96
    private $logger;
97
98
    /**
99
     * @var bool
100
     */
101
    private $allowNoneAttestation = true;
102
103
    /**
104
     * @var bool
105
     */
106
    private $allowSelfAttestation = true;
107
108
    /**
109
     * @var bool
110
     */
111
    private $trustWithoutMetadata = true;
112
113
    /**
114
     * @var bool
115
     */
116
    private $useMetadata = true;
117
118
    public function __construct()
119
    {
120
    }
121
122
    private function reset()
123
    {
124
        $this->downloader = null;
125
        $this->httpClient = null;
126
        $this->cacheProvider = null;
127
        $this->chainValidator = null;
128
        $this->trustDecisionManager = null;
129
    }
130
131
    public function setRelyingParty(RelyingParty $rp): self
132
    {
133
        $this->rp = $rp;
134
        return $this;
135
    }
136
137
    public function setCredentialStore(CredentialStoreInterface $store): self
138
    {
139
        $this->store = $store;
140
        return $this;
141
    }
142
143
    public function setCacheDirectory(string $directory): self
144
    {
145
        $this->cacheDir = $directory;
146
        return $this;
147
    }
148
149
    public function useSystemTempCache(string $subDirectory = 'webauthn-server-cache'): self
150
    {
151
        $this->cacheDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $subDirectory;
152
        return $this;
153
    }
154
155
    private function getCacheDirectory(): string
156
    {
157
        if ($this->cacheDir === null) {
158
            throw new ConfigurationException('No cache directory configured. Use useCacheDirectory or useSystemTempCache.');
159
        }
160
        return $this->cacheDir;
161
    }
162
163
    private function getCredentialStore(): CredentialStoreInterface
164
    {
165
        if ($this->store === null) {
166
            throw new ConfigurationException('Credential store not configured. Use setCredentialStore.');
167
        }
168
169
        return $this->store;
170
    }
171
172
    /**
173
     * @param callable|PolicyCallbackInterface $policyCallback
174
     *
175
     * @return $this
176
     */
177
    public function configurePolicy(callable $policyCallback): self
178
    {
179
        $this->policyCallback = $policyCallback;
180
        return $this;
181
    }
182
183
//    public function withTrustPreset(string $preset)
184
//    {
185
//    }
186
187
    public function allowNoneAttestation(bool $allow): self
188
    {
189
        $this->allowNoneAttestation = $allow;
190
        return $this;
191
    }
192
193
    public function useMetadata(bool $use): self
194
    {
195
        $this->useMetadata = $use;
196
        return $this;
197
    }
198
199
    public function allowSelfAttestation(bool $allow): self
200
    {
201
        $this->allowSelfAttestation = $allow;
202
        return $this;
203
    }
204
205
    public function trustWithoutMetadata(bool $trust): self
206
    {
207
        $this->trustWithoutMetadata = $trust;
208
        return $this;
209
    }
210
211
    public function withLogger(LoggerInterface $logger): self
212
    {
213
        $this->logger = $logger;
214
        return $this;
215
    }
216
217
    private function assignLogger(LoggerAwareInterface $service): void
218
    {
219
        if ($this->logger !== null) {
220
            $service->setLogger($this->logger);
221
        }
222
    }
223
224
    private function getPolicy(): PolicyInterface
225
    {
226
        $policy = new Policy($this->getRelyingParty(), $this->getMetadataResolver(), $this->getTrustDecisionManager());
227
228
        if ($this->policyCallback !== null) {
229
            ($this->policyCallback)($policy);
230
        }
231
232
        return $policy;
233
    }
234
235
    public function build(): ServerInterface
236
    {
237
        $this->reset();
238
        try {
239
            return new WebAuthnServer($this->getPolicy(), $this->getCredentialStore());
240
        } finally {
241
            $this->reset();
242
        }
243
    }
244
245
    private function getRelyingParty(): RelyingPartyInterface
246
    {
247
        if ($this->rp === null) {
248
            throw new ConfigurationException('Relying party not configured. Use setRelyingParty.');
249
        }
250
251
        return $this->rp;
252
    }
253
254
    public function addMetadataSource(MetadataSourceInterface $metadataSource): self
255
    {
256
        $this->metadataSources[] = $metadataSource;
257
        return $this;
258
    }
259
260
    private function getMetadataResolver(): MetadataResolverInterface
261
    {
262
        if (count($this->metadataSources) === 0) {
263
            return new NullMetadataResolver();
264
        }
265
        $resolver = new MetadataResolver($this->createMetadataProviders($this->metadataSources));
266
        $this->assignLogger($resolver);
267
        return $resolver;
268
    }
269
270
    private function getTrustDecisionManager(): TrustDecisionManagerInterface
271
    {
272
        if ($this->trustDecisionManager === null) {
273
            $tdm = new TrustDecisionManager();
274
275
            if ($this->allowNoneAttestation) {
276
                $tdm->addVoter(new TrustAttestationTypeVoter(AttestationType::NONE));
277
            }
278
            if ($this->allowSelfAttestation) {
279
                $tdm->addVoter(new TrustAttestationTypeVoter(AttestationType::SELF));
280
            }
281
            if ($this->trustWithoutMetadata) {
282
                $tdm->addVoter(new AllowEmptyMetadataVoter());
283
            }
284
            if ($this->useMetadata) {
285
                $tdm->addVoter(new SupportedAttestationTypeVoter());
286
                $tdm->addVoter(new UndesiredStatusReportVoter());
287
                $tdm->addVoter(new TrustChainVoter($this->getTrustPathValidator()));
288
            }
289
            $this->trustDecisionManager = $tdm;
290
        }
291
        return $this->trustDecisionManager;
292
    }
293
294
    private function getTrustPathValidator(): TrustPathValidatorInterface
295
    {
296
        return new TrustPathValidator($this->buildChainValidator());
297
    }
298
299
    private function buildDownloader(): DownloaderInterface
0 ignored issues
show
Unused Code introduced by
The method buildDownloader() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
300
    {
301
        if ($this->downloader === null) {
302
            $this->downloader = new Downloader($this->buildHttpClient());
303
        }
304
        return $this->downloader;
305
    }
306
307
    private function buildCacheProvider(): CacheProviderInterface
308
    {
309
        if ($this->cacheProvider === null) {
310
            $this->cacheProvider = new FileCacheProvider($this->getCacheDirectory());
311
        }
312
        return $this->cacheProvider;
313
    }
314
315
    private function buildChainValidator(): ChainValidatorInterface
316
    {
317
        if ($this->chainValidator === null) {
318
            $this->chainValidator = new ChainValidator($this->buildStatusResolver());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->buildStatusResolver() targeting MadWizard\WebAuthn\Build...::buildStatusResolver() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
319
        }
320
        return $this->chainValidator;
321
    }
322
323
    private function buildHttpClient(): Client
324
    {
325
        if ($this->httpClient === null) {
326
            $factory = new CachingClientFactory($this->buildCacheProvider());
327
            $this->httpClient = $factory->createClient();
328
        }
329
        return $this->httpClient;
330
    }
331
332
    private function buildStatusResolver(): ?CertificateStatusResolverInterface
333
    {
334
        // TODO: IMPLEMENT
335
        return null;
336
    }
337
}
338