Failed Conditions
Push — ng ( 68a719...06acb0 )
by Florent
23:02
created

ClientSecretBasic::getSupportedMethods()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
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\Server\TokenEndpoint\AuthenticationMethod;
15
16
use OAuth2Framework\Component\Server\Core\Client\Client;
17
use OAuth2Framework\Component\Server\Core\Client\ClientId;
18
use OAuth2Framework\Component\Server\Core\DataBag\DataBag;
19
use Psr\Http\Message\ServerRequestInterface;
20
21
final class ClientSecretBasic implements AuthenticationMethod
22
{
23
    /**
24
     * @var string
25
     */
26
    private $realm;
27
28
    /**
29
     * @var int
30
     */
31
    private $secretLifetime;
32
33
    /**
34
     * ClientSecretBasic constructor.
35
     *
36
     * @param string $realm
37
     * @param int    $secretLifetime
38
     */
39
    public function __construct(string $realm, int $secretLifetime = 0)
40
    {
41
        if ($secretLifetime < 0) {
42
            throw new \InvalidArgumentException('The secret lifetime must be at least 0 (= unlimited).');
43
        }
44
45
        $this->realm = $realm;
46
        $this->secretLifetime = $secretLifetime;
47
    }
48
49
    /**
50
     * {@inheritdoc}
51
     */
52
    public function getSchemesParameters(): array
53
    {
54
        return [
55
            sprintf('Basic realm="%s",charset="UTF-8"', $this->realm),
56
        ];
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    public function findClientIdAndCredentials(ServerRequestInterface $request, &$client_credentials = null): ? ClientId
63
    {
64
        $authorization_headers = $request->getHeader('Authorization');
65
        if (0 < count($authorization_headers)) {
66
            foreach ($authorization_headers as $authorization_header) {
67
                $clientId = $this->findClientIdAndCredentialsInAuthorizationHeader($authorization_header, $client_credentials);
68
                if (null !== $clientId) {
69
                    return $clientId;
70
                }
71
            }
72
        }
73
74
        return null;
75
    }
76
77
    /**
78
     * @param $authorization_header
79
     * @param null $client_credentials
80
     *
81
     * @return ClientId|null
82
     */
83
    private function findClientIdAndCredentialsInAuthorizationHeader($authorization_header, &$client_credentials = null)
84
    {
85
        if ('basic ' === mb_strtolower(mb_substr($authorization_header, 0, 6, '8bit'), '8bit')) {
86
            list($client_id, $client_secret) = explode(':', base64_decode(mb_substr($authorization_header, 6, mb_strlen($authorization_header, '8bit') - 6, '8bit')));
87
            if (!empty($client_id) && !empty($client_secret)) {
88
                $client_credentials = $client_secret;
89
90
                return ClientId::create($client_id);
91
            }
92
        }
93
94
        return null;
95
    }
96
97
    /**
98
     * {@inheritdoc}
99
     */
100
    public function checkClientConfiguration(DataBag $command_parameters, DataBag $validated_parameters): DataBag
101
    {
102
        $validated_parameters = $validated_parameters->with('client_secret', $this->createClientSecret());
103
        $validated_parameters = $validated_parameters->with('client_secret_expires_at', (0 === $this->secretLifetime ? 0 : time() + $this->secretLifetime));
104
105
        return $validated_parameters;
106
    }
107
108
    /**
109
     * {@inheritdoc}
110
     */
111
    public function isClientAuthenticated(Client $client, $client_credentials, ServerRequestInterface $request): bool
112
    {
113
        return hash_equals($client->get('client_secret'), $client_credentials);
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119
    public function getSupportedMethods(): array
120
    {
121
        return ['client_secret_basic'];
122
    }
123
124
    /**
125
     * @return string
126
     */
127
    private function createClientSecret(): string
128
    {
129
        return bin2hex(random_bytes(128));
130
    }
131
}
132