RefreshTokenGrantType::handleAccessTokenRequest()   C
last analyzed

Complexity

Conditions 11
Paths 20

Size

Total Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
nc 20
nop 2
dl 0
loc 67
rs 6.5733
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: GCC-MED
5
 * Date: 12/03/2018
6
 * Time: 14:36
7
 */
8
9
namespace OAuth2\AuthorizationGrantTypes;
10
11
12
use OAuth2\Config;
13
use OAuth2\Endpoints\TokenEndpoint;
14
use OAuth2\Exceptions\OAuthException;
15
use OAuth2\Helper;
16
use OAuth2\ScopePolicy\ScopePolicyManager;
17
use OAuth2\Storages\AccessTokenStorageInterface;
18
use OAuth2\Storages\RefreshTokenStorageInterface;
19
20
/**
21
 * Class RefreshTokenGrantType
22
 * @package OAuth2\AuthorizationGrantTypes
23
 *
24
 * @see https://tools.ietf.org/html/rfc6749#section-6
25
 * If the authorization server issued a refresh token to the client, the
26
 * client makes a refresh request to the token endpoint by adding the
27
 * following parameters using the "application/x-www-form-urlencoded"
28
 * format per Appendix B with a character encoding of UTF-8 in the HTTP
29
 * request entity-body:
30
 *
31
 * grant_type
32
 * REQUIRED.  Value MUST be set to "refresh_token".
33
 *
34
 * refresh_token
35
 * REQUIRED.  The refresh token issued to the client.
36
 *
37
 * scope
38
 * OPTIONAL.  The scope of the access request as described by
39
 * Section 3.3.  The requested scope MUST NOT include any scope
40
 * not originally granted by the resource owner, and if omitted is
41
 * treated as equal to the scope originally granted by the
42
 * resource owner.
43
 *
44
 * Because refresh tokens are typically long-lasting credentials used to
45
 * request additional access tokens, the refresh token is bound to the
46
 * client to which it was issued.  If the client type is confidential or
47
 * the client was issued client credentials (or assigned other
48
 * authentication requirements), the client MUST authenticate with the
49
 * authorization server as described in Section 3.2.1.
50
 *
51
 * For example, the client makes the following HTTP request using
52
 * transport-layer security (with extra line breaks for display purposes
53
 * only):
54
 *
55
 * POST /token HTTP/1.1
56
 * Host: server.example.com
57
 * Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
58
 * Content-Type: application/x-www-form-urlencoded
59
 *
60
 * grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
61
 *
62
 * The authorization server MUST:
63
 *
64
 * o  require client authentication for confidential clients or for any
65
 * client that was issued client credentials (or with other
66
 * authentication requirements),
67
 *
68
 * o  authenticate the client if client authentication is included and
69
 * ensure that the refresh token was issued to the authenticated
70
 * client, and
71
 *
72
 * o  validate the refresh token.
73
 *
74
 * If valid and authorized, the authorization server issues an access
75
 * token as described in Section 5.1.  If the request failed
76
 * verification or is invalid, the authorization server returns an error
77
 * response as described in Section 5.2.
78
 *
79
 * The authorization server MAY issue a new refresh token, in which case
80
 * the client MUST discard the old refresh token and replace it with the
81
 * new refresh token.  The authorization server MAY revoke the old
82
 * refresh token after issuing a new refresh token to the client.  If a
83
 * new refresh token is issued, the refresh token scope MUST be
84
 * identical to that of the refresh token included by the client in the
85
 * request.
86
 */
87
class RefreshTokenGrantType extends AbstractGrantType implements GrantTypeInterface
88
{
89
    /**
90
     * @var Config
91
     */
92
    private $config;
93
    /**
94
     * @var ScopePolicyManager
95
     */
96
    private $scopePolicyManager;
97
98
    public function __construct(AccessTokenStorageInterface $accessTokenStorage,
99
                                RefreshTokenStorageInterface $refreshTokenStorage,
100
                                Config $config,
101
                                ScopePolicyManager $scopePolicyManager)
102
    {
103
        parent::__construct($accessTokenStorage, $refreshTokenStorage);
104
        $this->config = $config;
105
        $this->scopePolicyManager = $scopePolicyManager;
106
    }
107
108
    /**
109
     * @param TokenEndpoint $tokenEndpoint
110
     * @param array $requestData
111
     * @return array
112
     * @throws OAuthException
113
     */
114
    public function handleAccessTokenRequest(TokenEndpoint $tokenEndpoint, array $requestData): array
115
    {
116
        if (empty($requestData['refresh_token'])) {
117
            throw new OAuthException('invalid_request',
118
                'The request is missing the required parameter refresh_token.',
119
                'https://tools.ietf.org/html/rfc7636#section-4.4');
120
        }
121
122
        $refreshToken = $this->refreshTokenStorage->get($requestData['refresh_token']);
123
124
        if (!$refreshToken || $refreshToken->getClientIdentifier() !== $tokenEndpoint->getClient()->getIdentifier()) {
125
            throw new OAuthException('invalid_grant',
126
                'The request includes the invalid parameter refresh_token.',
127
                'https://tools.ietf.org/html/rfc7636#section-4.4');
128
        }
129
130
        if ($this->refreshTokenStorage->hasExpired($refreshToken)) {
131
            throw new OAuthException('invalid_grant',
132
                'The request includes the invalid parameter refresh_token. The token has expired.',
133
                'https://tools.ietf.org/html/rfc7636#section-4.4');
134
        }
135
136
        $scopes = $refreshToken->getScopes();
137
        $requestedScopes = $this->scopePolicyManager->scopeStringToArray($requestData['scope'] ?? null);
138
139
        if (!empty($requestedScopes)) {
140
            if (!empty(array_diff($requestedScopes, $refreshToken->getScopes()))) {
141
                throw new OAuthException('invalid_request',
142
                    'The request includes the invalid parameter scope.',
143
                    'https://tools.ietf.org/html/rfc7636#section-4.4');
144
            }
145
            $scopes = $requestedScopes;
146
        }
147
148
        $responseData = $this->issueAccessToken(
149
            $scopes,
150
            $refreshToken->getClientIdentifier(),
151
            $refreshToken->getResourceOwnerIdentifier(),
152
            $refreshToken->getAuthorizationCode()
153
        );
154
155
        /**
156
         * @see https://tools.ietf.org/html/rfc6749#section-3.3
157
         * The authorization and token endpoints allow the client to specify the
158
         * scope of the access request using the "scope" request parameter.  In
159
         * turn, the authorization server uses the "scope" response parameter to
160
         * inform the client of the scope of the access token issued.
161
         */
162
        if (Helper::array_equals($requestedScopes, $scopes)) {
163
            $responseData['scope'] = implode(' ', $scopes);
164
        }
165
166
        if ($this->config->mayRevokeOldRefreshToken() || $this->config->mayIssueNewRefreshToken()) {
167
            $this->refreshTokenStorage->revoke($refreshToken);
168
        }
169
170
        if ($this->config->mayIssueNewRefreshToken()) {
171
            $refreshToken = $this->refreshTokenStorage->generate(
172
                $refreshToken->getScopes(),
173
                $refreshToken->getClientIdentifier(),
174
                $refreshToken->getResourceOwnerIdentifier(),
175
                $refreshToken->getAuthorizationCode()
176
            );
177
            $responseData['refresh_token'] = $refreshToken->getToken();
178
        }
179
180
        return $responseData;
181
    }
182
}