Failed Conditions
Push — ng ( 941bba...49c420 )
by Florent
14:14
created

Client::all()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2018 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 OAuth2Framework\Component\Core\Client;
15
16
use OAuth2Framework\Component\Core\Client\Event as ClientEvent;
17
use OAuth2Framework\Component\Core\DataBag\DataBag;
18
use OAuth2Framework\Component\Core\Event\Event;
19
use OAuth2Framework\Component\Core\ResourceOwner\ResourceOwnerId;
20
use OAuth2Framework\Component\Core\ResourceOwner\ResourceOwner;
21
use OAuth2Framework\Component\Core\UserAccount\UserAccountId;
22
use OAuth2Framework\Component\Core\Domain\DomainObject;
23
use SimpleBus\Message\Recorder\ContainsRecordedMessages;
24
use SimpleBus\Message\Recorder\PrivateMessageRecorderCapabilities;
25
26
/**
27
 * Class ClientCredentials.
28
 *
29
 * This class is used for every client types.
30
 * A client is a resource owner with a set of allowed grant types and can perform requests against
31
 * available endpoints.
32
 */
33
class Client implements ResourceOwner, ContainsRecordedMessages, DomainObject
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
34
{
35
    use PrivateMessageRecorderCapabilities;
36
37
    /**
38
     * @var bool
39
     */
40
    private $deleted = false;
41
42
    /**
43
     * @var UserAccountId|null
44
     */
45
    private $ownerId = null;
46
47
    /**
48
     * @var ClientId|null
49
     */
50
    private $clientId = null;
51
52
    /**
53
     * @var DataBag
54
     */
55
    protected $parameters;
56
57
    /**
58
     * ClientCredentials constructor.
59
     */
60
    private function __construct()
61
    {
62
        $this->parameters = DataBag::create([]);
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68
    public static function getSchema(): string
69
    {
70
        return 'https://oauth2-framework.spomky-labs.com/schemas/model/client/1.0/schema';
71
    }
72
73
    /**
74
     * @return Client
75
     */
76
    public static function createEmpty(): self
77
    {
78
        return new self();
79
    }
80
81
    /**
82
     * @param ClientId           $clientId
83
     * @param DataBag            $parameters
84
     * @param UserAccountId|null $ownerId
85
     *
86
     * @return Client
87
     */
88
    public function create(ClientId $clientId, DataBag $parameters, ? UserAccountId $ownerId): self
89
    {
90
        $clone = clone $this;
91
        $clone->clientId = $clientId;
92
        $clone->parameters = $parameters;
93
        $clone->ownerId = $ownerId;
94
95
        $event = ClientEvent\ClientCreatedEvent::create($clone->clientId, $parameters, $ownerId);
96
        $clone->record($event);
97
98
        return $clone;
99
    }
100
101
    /**
102
     * @return UserAccountId|null
103
     */
104
    public function getOwnerId(): ? UserAccountId
105
    {
106
        return $this->ownerId;
107
    }
108
109
    /**
110
     * @param UserAccountId $ownerId
111
     *
112
     * @return Client
113
     */
114
    public function withOwnerId(UserAccountId $ownerId): self
115
    {
116
        if ($this->getOwnerId()->getValue() === $ownerId->getValue()) {
117
            return $this;
118
        }
119
120
        $clone = clone $this;
121
        $clone->ownerId = $ownerId;
122
        $event = ClientEvent\ClientOwnerChangedEvent::create($clone->getPublicId(), $ownerId);
123
        $clone->record($event);
124
125
        return $clone;
126
    }
127
128
    /**
129
     * @param DataBag $parameters
130
     *
131
     * @return Client
132
     */
133
    public function withParameters(DataBag $parameters): self
134
    {
135
        $clone = clone $this;
136
        $clone->parameters = $parameters;
137
        $event = ClientEvent\ClientParametersUpdatedEvent::create($clone->getPublicId(), $parameters);
138
        $clone->record($event);
139
140
        return $clone;
141
    }
142
143
    /**
144
     * @return Client
145
     */
146
    public function markAsDeleted(): self
147
    {
148
        $clone = clone $this;
149
        $clone->deleted = true;
150
        $event = ClientEvent\ClientDeletedEvent::create($clone->getPublicId());
151
        $clone->record($event);
152
153
        return $clone;
154
    }
155
156
    /**
157
     * @return bool
158
     */
159
    public function isDeleted(): bool
160
    {
161
        return $this->deleted;
162
    }
163
164
    /**
165
     * @param string $grant_type
166
     *
167
     * @return bool
168
     */
169
    public function isGrantTypeAllowed(string $grant_type): bool
170
    {
171
        $grant_types = $this->has('grant_types') ? $this->get('grant_types') : [];
172
        if (!is_array($grant_types)) {
173
            throw new \InvalidArgumentException('The metadata "grant_types" must be an array.');
174
        }
175
176
        return in_array($grant_type, $grant_types);
177
    }
178
179
    /**
180
     * @param string $response_type
181
     *
182
     * @return bool
183
     */
184
    public function isResponseTypeAllowed(string $response_type): bool
185
    {
186
        $response_types = $this->has('response_types') ? $this->get('response_types') : [];
187
        if (!is_array($response_types)) {
188
            throw new \InvalidArgumentException('The metadata "response_types" must be an array.');
189
        }
190
191
        return in_array($response_type, $response_types);
192
    }
193
194
    /**
195
     * @param string $token_type
196
     *
197
     * @return bool
198
     */
199
    public function isTokenTypeAllowed(string $token_type): bool
200
    {
201
        if (!$this->has('token_types')) {
202
            return true;
203
        }
204
        $token_types = $this->get('token_types');
205
        if (!is_array($token_types)) {
206
            throw new \InvalidArgumentException('The metadata "token_types" must be an array.');
207
        }
208
209
        return in_array($token_type, $token_types);
210
    }
211
212
    /**
213
     * @return bool
214
     */
215
    public function isPublic(): bool
216
    {
217
        return 'none' === $this->getTokenEndpointAuthenticationMethod();
218
    }
219
220
    /**
221
     * @return string
222
     */
223
    public function getTokenEndpointAuthenticationMethod(): string
224
    {
225
        if ($this->has('token_endpoint_auth_method')) {
226
            return $this->get('token_endpoint_auth_method');
227
        }
228
229
        return 'client_secret_basic';
230
    }
231
232
    /**
233
     * @return int
234
     */
235
    public function getClientCredentialsExpiresAt(): int
236
    {
237
        if ($this->has('client_secret_expires_at')) {
238
            return $this->get('client_secret_expires_at');
239
        }
240
241
        return 0;
242
    }
243
244
    /**
245
     * @return bool
246
     */
247
    public function areClientCredentialsExpired(): bool
248
    {
249
        if (0 === $this->getClientCredentialsExpiresAt()) {
250
            return false;
251
        }
252
253
        return time() > $this->getClientCredentialsExpiresAt();
254
    }
255
256
    /**
257
     * {@inheritdoc}
258
     */
259
    public function getPublicId(): ResourceOwnerId
260
    {
261
        if (null === $this->clientId) {
262
            throw new \RuntimeException('ClientCredentials not initialized.');
263
        }
264
265
        return $this->clientId;
266
    }
267
268
    /**
269
     * {@inheritdoc}
270
     */
271
    public function has(string $key): bool
272
    {
273
        return $this->parameters->has($key);
274
    }
275
276
    /**
277
     * {@inheritdoc}
278
     */
279
    public function get(string $key)
280
    {
281
        if (!$this->has($key)) {
282
            throw new \InvalidArgumentException(sprintf('Configuration value with key "%s" does not exist.', $key));
283
        }
284
285
        return $this->parameters->get($key);
286
    }
287
288
    /**
289
     * @return array
290
     */
291
    public function all(): array
292
    {
293
        $all = $this->parameters->all();
294
        $all['client_id'] = $this->getPublicId()->getValue();
295
296
        return $all;
297
    }
298
299
    /**
300
     * {@inheritdoc}
301
     */
302
    public function jsonSerialize()
303
    {
304
        $data = [
305
            '$schema' => $this->getSchema(),
306
            'type' => get_class($this),
307
            'client_id' => $this->getPublicId()->getValue(),
308
            'owner_id' => $this->getOwnerId() ? $this->getOwnerId()->getValue() : null,
309
            'parameters' => (object) $this->all(),
310
            'is_deleted' => $this->isDeleted(),
311
        ];
312
313
        return $data;
314
    }
315
316
    /**
317
     * {@inheritdoc}
318
     */
319
    public static function createFromJson(\stdClass $json): DomainObject
320
    {
321
        $clientId = ClientId::create($json->client_id);
322
        $ownerId = null !== $json->owner_id ? UserAccountId::create($json->owner_id) : null;
323
        $parameters = DataBag::create((array) $json->parameters);
324
        $deleted = $json->is_deleted;
325
326
        $client = new self();
327
        $client->clientId = $clientId;
328
        $client->ownerId = $ownerId;
329
        $client->parameters = $parameters;
330
        $client->deleted = $deleted;
331
332
        return $client;
333
    }
334
335
    /**
336
     * @param Event $event
337
     *
338
     * @return Client
339
     */
340
    public function apply(Event $event): self
341
    {
342
        $map = $this->getEventMap();
343
        if (!array_key_exists($event->getType(), $map)) {
344
            throw new \InvalidArgumentException('Unsupported event.');
345
        }
346
        if (null !== $this->clientId && $this->clientId->getValue() !== $event->getDomainId()->getValue()) {
347
            throw new \InvalidArgumentException('Event not applicable for this client.');
348
        }
349
        $method = $map[$event->getType()];
350
351
        return $this->$method($event);
352
    }
353
354
    /**
355
     * @return array
356
     */
357
    private function getEventMap(): array
358
    {
359
        return [
360
            ClientEvent\ClientCreatedEvent::class => 'applyClientCreatedEvent',
361
            ClientEvent\ClientOwnerChangedEvent::class => 'applyClientOwnerChangedEvent',
362
            ClientEvent\ClientDeletedEvent::class => 'applyClientDeletedEvent',
363
            ClientEvent\ClientParametersUpdatedEvent::class => 'applyClientParametersUpdatedEvent',
364
        ];
365
    }
366
367
    /**
368
     * @param ClientEvent\ClientCreatedEvent $event
369
     *
370
     * @return Client
371
     */
372
    protected function applyClientCreatedEvent(ClientEvent\ClientCreatedEvent $event): self
373
    {
374
        $clone = clone $this;
375
        $clone->clientId = $event->getClientId();
376
        $clone->ownerId = $event->getOwnerId();
377
        $clone->parameters = $event->getParameters();
378
379
        return $clone;
380
    }
381
382
    /**
383
     * @param ClientEvent\ClientOwnerChangedEvent $event
384
     *
385
     * @return Client
386
     */
387
    protected function applyClientOwnerChangedEvent(ClientEvent\ClientOwnerChangedEvent $event): self
388
    {
389
        $clone = clone $this;
390
        $clone->ownerId = $event->getNewOwnerId();
391
392
        return $clone;
393
    }
394
395
    /**
396
     * @param ClientEvent\ClientDeletedEvent $event
397
     *
398
     * @return Client
399
     */
400
    protected function applyClientDeletedEvent(ClientEvent\ClientDeletedEvent $event): self
401
    {
402
        $clone = clone $this;
403
        $clone->deleted = true;
404
405
        return $clone;
406
    }
407
408
    /**
409
     * @param ClientEvent\ClientParametersUpdatedEvent $event
410
     *
411
     * @return Client
412
     */
413
    protected function applyClientParametersUpdatedEvent(ClientEvent\ClientParametersUpdatedEvent $event): self
414
    {
415
        $clone = clone $this;
416
        $clone->parameters = $event->getParameters();
417
418
        return $clone;
419
    }
420
}
421