Failed Conditions
Push — master ( 4fec28...cca42a )
by Florent
04:20
created

Client::getClientId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 5
nc 2
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 ClientId
103
     */
104
    public function getClientId(): ClientId
105
    {
106
        $id = $this->getPublicId();
107
        if (!$id instanceof ClientId) {
108
            throw new \RuntimeException('Client not initialized.');
109
        }
110
111
        return $id;
112
     }
113
114
    /**
115
     * @return UserAccountId|null
116
     */
117
    public function getOwnerId(): ? UserAccountId
118
    {
119
        return $this->ownerId;
120
    }
121
122
    /**
123
     * @param UserAccountId $ownerId
124
     *
125
     * @return Client
126
     */
127
    public function withOwnerId(UserAccountId $ownerId): self
128
    {
129
        if ($this->getOwnerId()->getValue() === $ownerId->getValue()) {
130
            return $this;
131
        }
132
133
        $clone = clone $this;
134
        $clone->ownerId = $ownerId;
135
        $event = ClientEvent\ClientOwnerChangedEvent::create($clone->getClientId(), $ownerId);
136
        $clone->record($event);
137
138
        return $clone;
139
    }
140
141
    /**
142
     * @param DataBag $parameters
143
     *
144
     * @return Client
145
     */
146
    public function withParameters(DataBag $parameters): self
147
    {
148
        $clone = clone $this;
149
        $clone->parameters = $parameters;
150
        $event = ClientEvent\ClientParametersUpdatedEvent::create($clone->getClientId(), $parameters);
151
        $clone->record($event);
152
153
        return $clone;
154
    }
155
156
    /**
157
     * @return Client
158
     */
159
    public function markAsDeleted(): self
160
    {
161
        $clone = clone $this;
162
        $clone->deleted = true;
163
        $event = ClientEvent\ClientDeletedEvent::create($clone->getClientId());
164
        $clone->record($event);
165
166
        return $clone;
167
    }
168
169
    /**
170
     * @return bool
171
     */
172
    public function isDeleted(): bool
173
    {
174
        return $this->deleted;
175
    }
176
177
    /**
178
     * @param string $grant_type
179
     *
180
     * @return bool
181
     */
182
    public function isGrantTypeAllowed(string $grant_type): bool
183
    {
184
        $grant_types = $this->has('grant_types') ? $this->get('grant_types') : [];
185
        if (!is_array($grant_types)) {
186
            throw new \InvalidArgumentException('The metadata "grant_types" must be an array.');
187
        }
188
189
        return in_array($grant_type, $grant_types);
190
    }
191
192
    /**
193
     * @param string $response_type
194
     *
195
     * @return bool
196
     */
197
    public function isResponseTypeAllowed(string $response_type): bool
198
    {
199
        $response_types = $this->has('response_types') ? $this->get('response_types') : [];
200
        if (!is_array($response_types)) {
201
            throw new \InvalidArgumentException('The metadata "response_types" must be an array.');
202
        }
203
204
        return in_array($response_type, $response_types);
205
    }
206
207
    /**
208
     * @return bool
209
     */
210
    public function isPublic(): bool
211
    {
212
        return 'none' === $this->getTokenEndpointAuthenticationMethod();
213
    }
214
215
    /**
216
     * @return string
217
     */
218
    public function getTokenEndpointAuthenticationMethod(): string
219
    {
220
        if ($this->has('token_endpoint_auth_method')) {
221
            return $this->get('token_endpoint_auth_method');
222
        }
223
224
        return 'client_secret_basic';
225
    }
226
227
    /**
228
     * @return int
229
     */
230
    public function getClientCredentialsExpiresAt(): int
231
    {
232
        if ($this->has('client_secret_expires_at')) {
233
            return $this->get('client_secret_expires_at');
234
        }
235
236
        return 0;
237
    }
238
239
    /**
240
     * @return bool
241
     */
242
    public function areClientCredentialsExpired(): bool
243
    {
244
        if (0 === $this->getClientCredentialsExpiresAt()) {
245
            return false;
246
        }
247
248
        return time() > $this->getClientCredentialsExpiresAt();
249
    }
250
251
    /**
252
     * {@inheritdoc}
253
     */
254
    public function getPublicId(): ResourceOwnerId
255
    {
256
        if (null === $this->clientId) {
257
            throw new \RuntimeException('Client not initialized.');
258
        }
259
260
        return $this->clientId;
261
    }
262
263
    /**
264
     * {@inheritdoc}
265
     */
266
    public function has(string $key): bool
267
    {
268
        return $this->parameters->has($key);
269
    }
270
271
    /**
272
     * {@inheritdoc}
273
     */
274
    public function get(string $key)
275
    {
276
        if (!$this->has($key)) {
277
            throw new \InvalidArgumentException(sprintf('Configuration value with key "%s" does not exist.', $key));
278
        }
279
280
        return $this->parameters->get($key);
281
    }
282
283
    /**
284
     * @return array
285
     */
286
    public function all(): array
287
    {
288
        $all = $this->parameters->all();
289
        $all['client_id'] = $this->getPublicId()->getValue();
290
291
        return $all;
292
    }
293
294
    /**
295
     * {@inheritdoc}
296
     */
297
    public function jsonSerialize()
298
    {
299
        $data = [
300
            '$schema' => $this->getSchema(),
301
            'type' => get_class($this),
302
            'client_id' => $this->getPublicId()->getValue(),
303
            'owner_id' => $this->getOwnerId() ? $this->getOwnerId()->getValue() : null,
304
            'parameters' => (object) $this->all(),
305
            'is_deleted' => $this->isDeleted(),
306
        ];
307
308
        return $data;
309
    }
310
311
    /**
312
     * {@inheritdoc}
313
     */
314
    public static function createFromJson(\stdClass $json): DomainObject
315
    {
316
        $clientId = ClientId::create($json->client_id);
317
        $ownerId = null !== $json->owner_id ? UserAccountId::create($json->owner_id) : null;
318
        $parameters = DataBag::create((array) $json->parameters);
319
        $deleted = $json->is_deleted;
320
321
        $client = new self();
322
        $client->clientId = $clientId;
323
        $client->ownerId = $ownerId;
324
        $client->parameters = $parameters;
325
        $client->deleted = $deleted;
326
327
        return $client;
328
    }
329
330
    /**
331
     * @param Event $event
332
     *
333
     * @return Client
334
     */
335
    public function apply(Event $event): self
336
    {
337
        $map = $this->getEventMap();
338
        if (!array_key_exists($event->getType(), $map)) {
339
            throw new \InvalidArgumentException('Unsupported event.');
340
        }
341
        if (null !== $this->clientId && $this->clientId->getValue() !== $event->getDomainId()->getValue()) {
342
            throw new \InvalidArgumentException('Event not applicable for this client.');
343
        }
344
        $method = $map[$event->getType()];
345
346
        return $this->$method($event);
347
    }
348
349
    /**
350
     * @return array
351
     */
352
    private function getEventMap(): array
353
    {
354
        return [
355
            ClientEvent\ClientCreatedEvent::class => 'applyClientCreatedEvent',
356
            ClientEvent\ClientOwnerChangedEvent::class => 'applyClientOwnerChangedEvent',
357
            ClientEvent\ClientDeletedEvent::class => 'applyClientDeletedEvent',
358
            ClientEvent\ClientParametersUpdatedEvent::class => 'applyClientParametersUpdatedEvent',
359
        ];
360
    }
361
362
    /**
363
     * @param ClientEvent\ClientCreatedEvent $event
364
     *
365
     * @return Client
366
     */
367
    protected function applyClientCreatedEvent(ClientEvent\ClientCreatedEvent $event): self
368
    {
369
        $clone = clone $this;
370
        $clone->clientId = $event->getClientId();
371
        $clone->ownerId = $event->getOwnerId();
372
        $clone->parameters = $event->getParameters();
373
374
        return $clone;
375
    }
376
377
    /**
378
     * @param ClientEvent\ClientOwnerChangedEvent $event
379
     *
380
     * @return Client
381
     */
382
    protected function applyClientOwnerChangedEvent(ClientEvent\ClientOwnerChangedEvent $event): self
383
    {
384
        $clone = clone $this;
385
        $clone->ownerId = $event->getNewOwnerId();
386
387
        return $clone;
388
    }
389
390
    /**
391
     * @param ClientEvent\ClientDeletedEvent $event
392
     *
393
     * @return Client
394
     */
395
    protected function applyClientDeletedEvent(ClientEvent\ClientDeletedEvent $event): self
396
    {
397
        $clone = clone $this;
398
        $clone->deleted = true;
399
400
        return $clone;
401
    }
402
403
    /**
404
     * @param ClientEvent\ClientParametersUpdatedEvent $event
405
     *
406
     * @return Client
407
     */
408
    protected function applyClientParametersUpdatedEvent(ClientEvent\ClientParametersUpdatedEvent $event): self
409
    {
410
        $clone = clone $this;
411
        $clone->parameters = $event->getParameters();
412
413
        return $clone;
414
    }
415
}
416