Passed
Push — develop ( 054886...bd89ad )
by nguereza
01:41
created

RefreshTokenGrant::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 8
rs 10
1
<?php
2
3
/**
4
 * Platine OAuth2
5
 *
6
 * Platine OAuth2 is a library that implements the OAuth2 specification
7
 *
8
 * This content is released under the MIT License (MIT)
9
 *
10
 * Copyright (c) 2020 Platine OAuth2
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a copy
13
 * of this software and associated documentation files (the "Software"), to deal
14
 * in the Software without restriction, including without limitation the rights
15
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
 * copies of the Software, and to permit persons to whom the Software is
17
 * furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in all
20
 * copies or substantial portions of the Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
 * SOFTWARE.
29
 */
30
31
declare(strict_types=1);
32
33
namespace Platine\OAuth2\Grant;
34
35
use Platine\Http\ResponseInterface;
36
use Platine\Http\ServerRequestInterface;
37
use Platine\OAuth2\Configuration;
38
use Platine\OAuth2\Entity\Client;
39
use Platine\OAuth2\Entity\TokenOwnerInterface;
40
use Platine\OAuth2\Exception\OAuth2Exception;
41
use Platine\OAuth2\Service\AccessTokenService;
42
use Platine\OAuth2\Service\RefreshTokenService;
43
44
/**
45
 * @class RefreshTokenGrant
46
 * @package Platine\OAuth2\Grant
47
 */
48
class RefreshTokenGrant extends BaseGrant
49
{
50
    public const GRANT_TYPE = 'refresh_token';
51
    public const GRANT_RESPONSE_TYPE = '';
52
53
    /**
54
     * The AccessTokenService
55
     * @var AccessTokenService
56
     */
57
    protected AccessTokenService $accessTokenService;
58
59
    /**
60
     * The RefreshTokenService
61
     * @var RefreshTokenService
62
     */
63
    protected RefreshTokenService $refreshTokenService;
64
65
    /**
66
     * The Configuration instance
67
     * @var Configuration
68
     */
69
    protected Configuration $configuration;
70
71
    /**
72
     * Create new instance
73
     * @param AccessTokenService $accessTokenService
74
     * @param RefreshTokenService $refreshTokenService
75
     * @param Configuration $configuration
76
     */
77
    public function __construct(
78
        AccessTokenService $accessTokenService,
79
        RefreshTokenService $refreshTokenService,
80
        Configuration $configuration
81
    ) {
82
        $this->accessTokenService = $accessTokenService;
83
        $this->refreshTokenService = $refreshTokenService;
84
        $this->configuration = $configuration;
85
    }
86
87
        /**
88
     * {@inheritdoc}
89
     */
90
    public function createAuthorizationResponse(
91
        ServerRequestInterface $request,
92
        Client $client,
93
        ?TokenOwnerInterface $owner = null
94
    ): ResponseInterface {
95
        throw OAuth2Exception::invalidRequest('Refresh token grant does not support authorization');
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101
    public function createTokenResponse(
102
        ServerRequestInterface $request,
103
        ?Client $client = null,
104
        ?TokenOwnerInterface $owner = null
105
    ): ResponseInterface {
106
        $postParams = $request->getParsedBody();
107
        $refreshTokenValue = $postParams['refresh_token'] ?? null;
108
        if ($refreshTokenValue === null) {
109
            throw OAuth2Exception::invalidRequest('Refresh token is missin in request');
110
        }
111
112
        // We can fetch the actual token, and validate it
113
        $refreshToken = $this->refreshTokenService->getToken((string) $refreshTokenValue);
114
        if ($refreshToken === null || $refreshToken->isExpired()) {
115
            throw OAuth2Exception::invalidGrant('Refresh token is expired');
116
        }
117
118
        // We can now create a new access token! First, we need to make some checks on the asked scopes,
119
        // because according to the spec, a refresh token can create an access token
120
        // with an equal or lesser scope, but not more
121
        $scope = $postParams['scope'] ?? null;
122
        $scopes = is_string($scope) ? explode(' ', $scope) : $refreshToken->getScopes();
123
        if ($refreshToken->matchScopes($scopes) === false) {
124
            throw OAuth2Exception::invalidScope(
125
                'The scope of the new access token exceeds the scope(s) of the refresh token'
126
            );
127
        }
128
129
        $refreshTokenOwner = $refreshToken->getOwner();
130
        $accessToken = $this->accessTokenService->createToken($refreshTokenOwner, $client, $scopes);
0 ignored issues
show
Bug introduced by
It seems like $client can also be of type null; however, parameter $client of Platine\OAuth2\Service\A...nService::createToken() does only seem to accept Platine\OAuth2\Entity\Client, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

130
        $accessToken = $this->accessTokenService->createToken($refreshTokenOwner, /** @scrutinizer ignore-type */ $client, $scopes);
Loading history...
Bug introduced by
It seems like $refreshTokenOwner can also be of type null; however, parameter $owner of Platine\OAuth2\Service\A...nService::createToken() does only seem to accept Platine\OAuth2\Entity\TokenOwnerInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

130
        $accessToken = $this->accessTokenService->createToken(/** @scrutinizer ignore-type */ $refreshTokenOwner, $client, $scopes);
Loading history...
131
        // We may want to revoke the old refresh token
132
        if ($this->configuration->isRotateRefreshToken()) {
133
            if ($this->configuration->isRevokeRotatedRefreshToken()) {
134
                $this->refreshTokenService->delete($refreshToken);
135
            }
136
137
            $refreshToken = $this->refreshTokenService->createToken($refreshTokenOwner, $client, $scopes);
0 ignored issues
show
Bug introduced by
It seems like $refreshTokenOwner can also be of type null; however, parameter $owner of Platine\OAuth2\Service\R...nService::createToken() does only seem to accept Platine\OAuth2\Entity\TokenOwnerInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

137
            $refreshToken = $this->refreshTokenService->createToken(/** @scrutinizer ignore-type */ $refreshTokenOwner, $client, $scopes);
Loading history...
138
        }
139
140
        return $this->generateTokenResponse($accessToken, $refreshToken, true);
141
    }
142
143
144
    /**
145
     * {@inheritdoc}
146
     */
147
    public function allowPublicClients(): bool
148
    {
149
        return true;
150
    }
151
}
152