This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php declare(strict_types=1); |
||
2 | |||
3 | namespace Limoncello\Passport; |
||
4 | |||
5 | /** |
||
6 | * Copyright 2015-2019 [email protected] |
||
7 | * |
||
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
||
9 | * you may not use this file except in compliance with the License. |
||
10 | * You may obtain a copy of the License at |
||
11 | * |
||
12 | * http://www.apache.org/licenses/LICENSE-2.0 |
||
13 | * |
||
14 | * Unless required by applicable law or agreed to in writing, software |
||
15 | * distributed under the License is distributed on an "AS IS" BASIS, |
||
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||
17 | * See the License for the specific language governing permissions and |
||
18 | * limitations under the License. |
||
19 | */ |
||
20 | |||
21 | use Limoncello\OAuthServer\BaseAuthorizationServer; |
||
22 | use Limoncello\OAuthServer\Contracts\AuthorizationCodeInterface; |
||
23 | use Limoncello\OAuthServer\Contracts\ClientInterface; |
||
24 | use Limoncello\OAuthServer\Contracts\GrantTypes; |
||
25 | use Limoncello\OAuthServer\Contracts\ResponseTypes; |
||
26 | use Limoncello\OAuthServer\Exceptions\OAuthCodeRedirectException; |
||
27 | use Limoncello\OAuthServer\Exceptions\OAuthRedirectException; |
||
28 | use Limoncello\OAuthServer\Exceptions\OAuthTokenBodyException; |
||
29 | use Limoncello\Passport\Contracts\Entities\TokenInterface; |
||
30 | use Limoncello\Passport\Contracts\PassportServerIntegrationInterface; |
||
31 | use Limoncello\Passport\Contracts\PassportServerInterface; |
||
32 | use Limoncello\Passport\Entities\Token; |
||
33 | use Psr\Http\Message\ResponseInterface; |
||
34 | use Psr\Http\Message\ServerRequestInterface; |
||
35 | use Psr\Log\LoggerAwareInterface as LAI; |
||
36 | use Psr\Log\LoggerAwareTrait; |
||
37 | use Zend\Diactoros\Response\JsonResponse; |
||
38 | use Zend\Diactoros\Response\RedirectResponse; |
||
39 | use Zend\Diactoros\Uri; |
||
40 | use function array_filter; |
||
41 | use function assert; |
||
42 | use function in_array; |
||
43 | use function is_int; |
||
44 | use function is_string; |
||
45 | |||
46 | /** |
||
47 | * @package Limoncello\Passport |
||
48 | * |
||
49 | * @SuppressWarnings(PHPMD.TooManyPublicMethods) |
||
50 | * @SuppressWarnings(PHPMD.CouplingBetweenObjects) |
||
51 | * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) |
||
52 | */ |
||
53 | abstract class BasePassportServer extends BaseAuthorizationServer implements PassportServerInterface, LAI |
||
54 | { |
||
55 | use LoggerAwareTrait; |
||
56 | |||
57 | /** |
||
58 | * @param PassportServerIntegrationInterface $integration |
||
59 | * @param ServerRequestInterface $request |
||
60 | * @param array $parameters |
||
61 | * @param string $realm |
||
62 | * |
||
63 | * @return ClientInterface|null |
||
64 | * |
||
65 | * @SuppressWarnings(PHPMD.NPathComplexity) |
||
66 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
||
67 | */ |
||
68 | abstract protected function determineClient( |
||
69 | PassportServerIntegrationInterface $integration, |
||
70 | ServerRequestInterface $request, |
||
71 | array $parameters, |
||
72 | $realm = 'OAuth' |
||
73 | ): ?ClientInterface; |
||
74 | |||
75 | /** |
||
76 | * @var PassportServerIntegrationInterface |
||
77 | */ |
||
78 | private $integration; |
||
79 | |||
80 | /** |
||
81 | * @param PassportServerIntegrationInterface $integration |
||
82 | */ |
||
83 | 17 | public function __construct(PassportServerIntegrationInterface $integration) |
|
84 | { |
||
85 | 17 | parent::__construct(); |
|
86 | |||
87 | 17 | $this->setIntegration($integration); |
|
88 | } |
||
89 | |||
90 | /** |
||
91 | * @inheritdoc |
||
92 | * |
||
93 | * @SuppressWarnings(PHPMD.CyclomaticComplexity) |
||
94 | */ |
||
95 | 9 | protected function createAuthorization(array $parameters): ResponseInterface |
|
96 | { |
||
97 | try { |
||
98 | 9 | list($client, $redirectUri) = $this->getValidClientAndRedirectUri( |
|
99 | 9 | $this->codeGetClientId($parameters), |
|
100 | 9 | $this->codeGetRedirectUri($parameters) |
|
101 | ); |
||
102 | 9 | if ($client === null || $redirectUri === null) { |
|
103 | 3 | return $this->getIntegration()->createInvalidClientAndRedirectUriErrorResponse(); |
|
104 | } |
||
105 | |||
106 | 6 | $maxStateLength = $this->getMaxStateLength(); |
|
107 | 6 | switch ($responseType = $this->getResponseType($parameters)) { |
|
108 | 6 | case ResponseTypes::AUTHORIZATION_CODE: |
|
109 | 3 | $this->logDebug('Handling code authorization.'); |
|
110 | $response = $this |
||
111 | 3 | ->codeAskResourceOwnerForApproval($parameters, $client, $redirectUri, $maxStateLength); |
|
112 | 3 | break; |
|
113 | 3 | case ResponseTypes::IMPLICIT: |
|
114 | 2 | $this->logDebug('Handling implicit authorization.'); |
|
115 | $response = $this |
||
116 | 2 | ->implicitAskResourceOwnerForApproval($parameters, $client, $redirectUri, $maxStateLength); |
|
117 | 2 | break; |
|
118 | default: |
||
119 | // @link https://tools.ietf.org/html/rfc6749#section-3.1.1 -> |
||
120 | // @link https://tools.ietf.org/html/rfc6749#section-4.1.2.1 |
||
121 | 1 | $this->logInfo('Unsupported response type in request.', ['response_type' => $responseType]); |
|
122 | 1 | $errorCode = OAuthCodeRedirectException::ERROR_UNSUPPORTED_RESPONSE_TYPE; |
|
123 | 6 | throw new OAuthCodeRedirectException($errorCode, $redirectUri); |
|
124 | } |
||
125 | 1 | } catch (OAuthRedirectException $exception) { |
|
126 | 1 | $response = $this->createRedirectErrorResponse($exception); |
|
127 | } |
||
128 | |||
129 | 6 | return $response; |
|
130 | } |
||
131 | |||
132 | /** |
||
133 | * @inheritdoc |
||
134 | */ |
||
135 | 8 | public function postCreateToken(ServerRequestInterface $request): ResponseInterface |
|
136 | { |
||
137 | try { |
||
138 | 8 | $parameters = $request->getParsedBody(); |
|
139 | 8 | $determinedClient = $this->determineClient($this->getIntegration(), $request, $parameters); |
|
0 ignored issues
–
show
|
|||
140 | |||
141 | 8 | switch ($grantType = $this->getGrantType($parameters)) { |
|
0 ignored issues
–
show
$parameters is of type null|array|object , but the function expects a array<integer,string> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
142 | 8 | case GrantTypes::AUTHORIZATION_CODE: |
|
143 | 1 | $this->logDebug('Handling code grant.'); |
|
144 | 1 | $response = $this->codeIssueToken($parameters, $determinedClient); |
|
0 ignored issues
–
show
$parameters is of type null|array|object , but the function expects a array<integer,string> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
145 | 1 | break; |
|
146 | 7 | case GrantTypes::RESOURCE_OWNER_PASSWORD_CREDENTIALS: |
|
147 | 4 | $this->logDebug('Handling resource owner password grant.'); |
|
148 | 4 | $response = $this->passIssueToken($parameters, $determinedClient); |
|
0 ignored issues
–
show
$parameters is of type null|array|object , but the function expects a array<integer,string> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
149 | 3 | break; |
|
150 | 5 | case GrantTypes::CLIENT_CREDENTIALS: |
|
151 | 2 | $this->logDebug('Handling client credentials grant.'); |
|
152 | 2 | if ($determinedClient === null) { |
|
153 | 1 | $this->logInfo('Client identification failed.'); |
|
154 | 1 | throw new OAuthTokenBodyException(OAuthTokenBodyException::ERROR_INVALID_CLIENT); |
|
155 | } |
||
156 | 1 | $response = $this->clientIssueToken($parameters, $determinedClient); |
|
0 ignored issues
–
show
$parameters is of type null|array|object , but the function expects a array<integer,string> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
157 | 1 | break; |
|
158 | 3 | case GrantTypes::REFRESH_TOKEN: |
|
159 | 2 | $this->logDebug('Handling refresh token grant.'); |
|
160 | 2 | $response = $this->refreshIssueToken($parameters, $determinedClient); |
|
0 ignored issues
–
show
$parameters is of type null|array|object , but the function expects a array<integer,string> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
161 | 2 | break; |
|
162 | default: |
||
163 | 1 | $this->logInfo('Unknown grant type.', ['grant_type' => $grantType]); |
|
164 | 6 | throw new OAuthTokenBodyException(OAuthTokenBodyException::ERROR_UNSUPPORTED_GRANT_TYPE); |
|
165 | } |
||
166 | 4 | } catch (OAuthTokenBodyException $exception) { |
|
167 | 4 | $response = $this->createBodyErrorResponse($exception); |
|
168 | } |
||
169 | |||
170 | 8 | return $response; |
|
171 | } |
||
172 | |||
173 | /** |
||
174 | * @inheritdoc |
||
175 | */ |
||
176 | 2 | public function createCodeResponse(TokenInterface $code, string $state = null): ResponseInterface |
|
177 | { |
||
178 | 2 | $client = $this->readClientByIdentifier($code->getClientIdentifier()); |
|
179 | 2 | if ($code->getRedirectUriString() === null || |
|
180 | 2 | in_array($code->getRedirectUriString(), $client->getRedirectUriStrings()) === false |
|
181 | ) { |
||
182 | 1 | $this->logInfo( |
|
183 | 1 | 'Code has invalid redirect URI which do not match any redirect URI for its client.', |
|
184 | 1 | ['id' => $code->getIdentifier()] |
|
185 | ); |
||
186 | 1 | return $this->getIntegration()->createInvalidClientAndRedirectUriErrorResponse(); |
|
187 | } |
||
188 | |||
189 | 1 | $code->setCode($this->getIntegration()->generateCodeValue($code)); |
|
190 | |||
191 | 1 | $tokenRepo = $this->getIntegration()->getTokenRepository(); |
|
192 | 1 | $createdCode = $tokenRepo->createCode($code); |
|
193 | |||
194 | 1 | $response = $this->createRedirectCodeResponse($createdCode, $state); |
|
195 | |||
196 | 1 | return $response; |
|
197 | } |
||
198 | |||
199 | /** |
||
200 | * @inheritdoc |
||
201 | */ |
||
202 | 2 | public function createTokenResponse(TokenInterface $token, string $state = null): ResponseInterface |
|
203 | { |
||
204 | 2 | $client = $this->readClientByIdentifier($token->getClientIdentifier()); |
|
205 | 2 | if ($token->getRedirectUriString() === null || |
|
206 | 2 | in_array($token->getRedirectUriString(), $client->getRedirectUriStrings()) === false |
|
207 | ) { |
||
208 | 1 | $this->logInfo( |
|
209 | 1 | 'Token has invalid redirect URI which do not match any redirect URI for its client.', |
|
210 | 1 | ['id' => $token->getIdentifier()] |
|
211 | ); |
||
212 | 1 | return $this->getIntegration()->createInvalidClientAndRedirectUriErrorResponse(); |
|
213 | } |
||
214 | |||
215 | 1 | list($tokenValue, $tokenType, $tokenExpiresIn) = $this->getIntegration()->generateTokenValues($token); |
|
216 | |||
217 | // refresh value must be null by the spec |
||
218 | 1 | $refreshValue = null; |
|
219 | 1 | $token->setValue($tokenValue)->setType($tokenType)->setRefreshValue($refreshValue); |
|
220 | 1 | $savedToken = $this->getIntegration()->getTokenRepository()->createToken($token); |
|
221 | |||
222 | 1 | $response = $this->createRedirectTokenResponse($savedToken, $tokenExpiresIn, $state); |
|
223 | |||
224 | 1 | return $response; |
|
225 | } |
||
226 | |||
227 | /** @noinspection PhpTooManyParametersInspection |
||
228 | * @inheritdoc |
||
229 | * |
||
230 | * @SuppressWarnings(PHPMD.BooleanArgumentFlag) |
||
231 | */ |
||
232 | 3 | public function codeCreateAskResourceOwnerForApprovalResponse( |
|
233 | ClientInterface $client, |
||
234 | string $redirectUri = null, |
||
235 | bool $isScopeModified = false, |
||
236 | array $scopeList = null, |
||
237 | string $state = null, |
||
238 | array $extraParameters = [] |
||
239 | ): ResponseInterface { |
||
240 | 3 | $this->logDebug('Asking resource owner for scope approval (code grant).'); |
|
241 | 3 | return $this->getIntegration()->createAskResourceOwnerForApprovalResponse( |
|
242 | 3 | ResponseTypes::AUTHORIZATION_CODE, |
|
243 | 3 | $client, |
|
244 | 3 | $redirectUri, |
|
245 | 3 | $isScopeModified, |
|
246 | 3 | $scopeList, |
|
0 ignored issues
–
show
It seems like
$scopeList defined by parameter $scopeList on line 236 can also be of type array ; however, Limoncello\Passport\Cont...erForApprovalResponse() does only seem to accept null|array<integer,string> , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
247 | 3 | $state, |
|
248 | 3 | $extraParameters |
|
249 | ); |
||
250 | } |
||
251 | |||
252 | /** |
||
253 | * @inheritdoc |
||
254 | */ |
||
255 | 1 | public function codeReadAuthenticationCode(string $code): ?AuthorizationCodeInterface |
|
256 | { |
||
257 | 1 | return $this->getIntegration()->getTokenRepository() |
|
258 | 1 | ->readByCode($code, $this->getIntegration()->getCodeExpirationPeriod()); |
|
259 | } |
||
260 | |||
261 | /** |
||
262 | * @inheritdoc |
||
263 | */ |
||
264 | 1 | public function codeCreateAccessTokenResponse( |
|
265 | AuthorizationCodeInterface $code, |
||
266 | array $extraParameters = [] |
||
267 | ): ResponseInterface { |
||
268 | /** @var Token $code */ |
||
269 | 1 | assert($code instanceof Token); |
|
270 | 1 | $updatedToken = clone $code; |
|
271 | |||
272 | 1 | $tokenExpiresIn = $this->setUpTokenValues($updatedToken); |
|
273 | 1 | $this->getIntegration()->getTokenRepository()->assignValuesToCode($updatedToken, $tokenExpiresIn); |
|
274 | |||
275 | 1 | $response = $this->createBodyTokenResponse($updatedToken, $tokenExpiresIn); |
|
276 | |||
277 | 1 | $this->logInfo('Authorization code successfully exchanged for a token (code grant).'); |
|
278 | |||
279 | 1 | return $response; |
|
280 | } |
||
281 | |||
282 | /** |
||
283 | * @inheritdoc |
||
284 | */ |
||
285 | 1 | public function codeRevokeTokens(AuthorizationCodeInterface $code): void |
|
286 | { |
||
287 | 1 | assert($code instanceof TokenInterface); |
|
288 | |||
289 | /** @var TokenInterface $code */ |
||
290 | |||
291 | 1 | $identifier = $code->getIdentifier(); |
|
292 | 1 | $this->logInfo('Revoking token.', ['token_id' => $identifier]); |
|
293 | 1 | $this->getIntegration()->getTokenRepository()->disable($identifier); |
|
294 | } |
||
295 | |||
296 | /** @noinspection PhpTooManyParametersInspection |
||
297 | * @inheritdoc |
||
298 | * |
||
299 | * @SuppressWarnings(PHPMD.BooleanArgumentFlag) |
||
300 | */ |
||
301 | 2 | public function implicitCreateAskResourceOwnerForApprovalResponse( |
|
302 | ClientInterface $client, |
||
303 | string $redirectUri = null, |
||
304 | bool $isScopeModified = false, |
||
305 | array $scopeList = null, |
||
306 | string $state = null, |
||
307 | array $extraParameters = [] |
||
308 | ): ResponseInterface { |
||
309 | 2 | $response = $this->getIntegration()->createAskResourceOwnerForApprovalResponse( |
|
310 | 2 | ResponseTypes::IMPLICIT, |
|
311 | 2 | $client, |
|
312 | 2 | $redirectUri, |
|
313 | 2 | $isScopeModified, |
|
314 | 2 | $scopeList, |
|
0 ignored issues
–
show
It seems like
$scopeList defined by parameter $scopeList on line 305 can also be of type array ; however, Limoncello\Passport\Cont...erForApprovalResponse() does only seem to accept null|array<integer,string> , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
315 | 2 | $state, |
|
316 | 2 | $extraParameters |
|
317 | ); |
||
318 | |||
319 | 2 | $this->logInfo('Created response asking resource owner for scope approval (implicit grant).'); |
|
320 | |||
321 | 2 | return $response; |
|
322 | } |
||
323 | |||
324 | /** @noinspection PhpTooManyParametersInspection |
||
325 | * @inheritdoc |
||
326 | * |
||
327 | * @SuppressWarnings(PHPMD.BooleanArgumentFlag) |
||
328 | */ |
||
329 | 4 | public function passValidateCredentialsAndCreateAccessTokenResponse( |
|
330 | string $userName, |
||
331 | string $password, |
||
332 | ClientInterface $client = null, |
||
333 | bool $isScopeModified = false, |
||
334 | array $scope = null, |
||
335 | array $extraParameters = [] |
||
336 | ): ResponseInterface { |
||
337 | 4 | assert($client !== null); |
|
338 | |||
339 | 4 | if (($userIdentifier = $this->getIntegration()->validateUserId($userName, $password)) === null) { |
|
340 | 1 | $this->logDebug('User not found with provided username and password.', ['username' => $userName]); |
|
341 | 1 | throw new OAuthTokenBodyException(OAuthTokenBodyException::ERROR_INVALID_GRANT); |
|
342 | } |
||
343 | 3 | assert(is_int($userIdentifier) === true); |
|
344 | 3 | $this->logInfo('User authenticated with provided username and password.', ['username' => $userName]); |
|
345 | |||
346 | 3 | $changedScopeOrNull = $this->getIntegration()->verifyAllowedUserScope($userIdentifier, $scope); |
|
347 | 3 | if ($changedScopeOrNull !== null) { |
|
348 | 3 | assert(is_array($changedScopeOrNull)); |
|
349 | 3 | $isScopeModified = true; |
|
350 | 3 | $scope = $changedScopeOrNull; |
|
351 | } |
||
352 | |||
353 | 3 | $unsavedToken = $this->getIntegration()->createTokenInstance(); |
|
354 | $unsavedToken |
||
355 | 3 | ->setClientIdentifier($client->getIdentifier()) |
|
356 | 3 | ->setScopeIdentifiers($scope) |
|
0 ignored issues
–
show
$scope is of type null|array , but the function expects a array<integer,string> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
357 | 3 | ->setUserIdentifier($userIdentifier); |
|
358 | 3 | $isScopeModified === true ? $unsavedToken->setScopeModified() : $unsavedToken->setScopeUnmodified(); |
|
359 | |||
360 | 3 | $tokenExpiresIn = $this->setUpTokenValues($unsavedToken); |
|
361 | 3 | $savedToken = $this->getIntegration()->getTokenRepository()->createToken($unsavedToken); |
|
362 | |||
363 | 3 | $response = $this->createBodyTokenResponse($savedToken, $tokenExpiresIn); |
|
364 | |||
365 | 3 | return $response; |
|
366 | } |
||
367 | |||
368 | /** |
||
369 | * @inheritdoc |
||
370 | */ |
||
371 | 4 | public function passReadDefaultClient(): ClientInterface |
|
372 | { |
||
373 | 4 | $defaultClientId = $this->getIntegration()->getDefaultClientIdentifier(); |
|
374 | |||
375 | 4 | assert(is_string($defaultClientId) === true && empty($defaultClientId) === false); |
|
376 | |||
377 | 4 | $defaultClient = $this->readClientByIdentifier($defaultClientId); |
|
378 | |||
379 | 4 | assert($defaultClient !== null); |
|
380 | |||
381 | 4 | return $defaultClient; |
|
382 | } |
||
383 | |||
384 | /** |
||
385 | * @inheritdoc |
||
386 | */ |
||
387 | 1 | public function clientCreateAccessTokenResponse( |
|
388 | ClientInterface $client, |
||
389 | bool $isScopeModified, |
||
390 | array $scope = null, |
||
391 | array $extraParameters = [] |
||
392 | ): ResponseInterface { |
||
393 | 1 | $this->logDebug('Prepare token for client.'); |
|
394 | 1 | assert($client !== null); |
|
395 | |||
396 | 1 | $unsavedToken = $this->getIntegration()->createTokenInstance(); |
|
397 | $unsavedToken |
||
398 | 1 | ->setClientIdentifier($client->getIdentifier()) |
|
399 | 1 | ->setScopeIdentifiers($scope); |
|
0 ignored issues
–
show
$scope is of type null|array , but the function expects a array<integer,string> .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
![]() |
|||
400 | 1 | $isScopeModified === true ? $unsavedToken->setScopeModified() : $unsavedToken->setScopeUnmodified(); |
|
401 | |||
402 | |||
403 | 1 | $tokenExpiresIn = $this->setUpTokenValue($unsavedToken); |
|
404 | 1 | $savedToken = $this->getIntegration()->getTokenRepository()->createToken($unsavedToken); |
|
405 | |||
406 | 1 | $response = $this->createBodyTokenResponse($savedToken, $tokenExpiresIn); |
|
407 | |||
408 | 1 | return $response; |
|
409 | } |
||
410 | |||
411 | /** |
||
412 | * @inheritdoc |
||
413 | * |
||
414 | * @return TokenInterface|null |
||
415 | */ |
||
416 | 2 | public function readTokenByRefreshValue(string $refreshValue): ?\Limoncello\OAuthServer\Contracts\TokenInterface |
|
417 | { |
||
418 | 2 | return $this->getIntegration()->getTokenRepository()->readByRefresh( |
|
419 | 2 | $refreshValue, |
|
420 | 2 | $this->getIntegration()->getTokenExpirationPeriod() |
|
421 | ); |
||
422 | } |
||
423 | |||
424 | /** |
||
425 | * @inheritdoc |
||
426 | * |
||
427 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
428 | */ |
||
429 | 2 | public function refreshCreateAccessTokenResponse( |
|
430 | ClientInterface $client, |
||
431 | \Limoncello\OAuthServer\Contracts\TokenInterface $token, |
||
432 | bool $isScopeModified, |
||
433 | array $scope = null, |
||
434 | array $extraParameters = [] |
||
435 | ): ResponseInterface { |
||
436 | 2 | $this->logDebug('Prepare refresh token.'); |
|
437 | |||
438 | /** @var TokenInterface $token */ |
||
439 | 2 | assert($token instanceof TokenInterface); |
|
440 | |||
441 | 2 | $updatedToken = clone $token; |
|
442 | 2 | $tokenExpiresIn = $this->getIntegration()->isRenewRefreshValue() === false ? |
|
443 | 2 | $this->setUpTokenValue($updatedToken) : $this->setUpTokenValues($updatedToken); |
|
444 | |||
445 | 2 | $tokenRepo = $this->getIntegration()->getTokenRepository(); |
|
446 | 2 | if ($isScopeModified === false) { |
|
447 | 1 | $tokenRepo->updateValues($updatedToken); |
|
448 | } else { |
||
449 | 1 | assert(is_array($scope)); |
|
450 | $tokenRepo->inTransaction(function () use ($tokenRepo, $updatedToken, $scope) { |
||
451 | 1 | $tokenRepo->updateValues($updatedToken); |
|
452 | 1 | $tokenRepo->unbindScopes($updatedToken->getIdentifier()); |
|
453 | 1 | $tokenRepo->bindScopeIdentifiers($updatedToken->getIdentifier(), $scope); |
|
454 | 1 | }); |
|
455 | 1 | $updatedToken->setScopeModified()->setScopeIdentifiers($scope); |
|
456 | } |
||
457 | 2 | $response = $this->createBodyTokenResponse($updatedToken, $tokenExpiresIn); |
|
458 | |||
459 | 2 | return $response; |
|
460 | } |
||
461 | |||
462 | /** |
||
463 | * @inheritdoc |
||
464 | */ |
||
465 | 13 | public function readClientByIdentifier(string $clientIdentifier): ?ClientInterface |
|
466 | { |
||
467 | 13 | return $this->getIntegration()->getClientRepository()->read($clientIdentifier); |
|
468 | } |
||
469 | |||
470 | /** |
||
471 | * @param string|null $clientId |
||
472 | * @param string|null $redirectFromQuery |
||
473 | * |
||
474 | * @return array [client|null, uri|null] |
||
475 | * |
||
476 | * @SuppressWarnings(PHPMD.ElseExpression) |
||
477 | */ |
||
478 | 9 | protected function getValidClientAndRedirectUri(string $clientId = null, string $redirectFromQuery = null): array |
|
479 | { |
||
480 | 9 | $client = null; |
|
481 | 9 | $validRedirectUri = null; |
|
482 | |||
483 | 9 | if ($clientId !== null && |
|
484 | 9 | ($client = $this->readClientByIdentifier($clientId)) !== null |
|
485 | ) { |
||
486 | 7 | $validRedirectUri = $this->selectValidRedirectUri($client, $redirectFromQuery); |
|
487 | 7 | if ($validRedirectUri === null) { |
|
488 | 1 | $this->logDebug( |
|
489 | 1 | 'Choosing valid redirect URI for client failed.', |
|
490 | 7 | ['client_id' => $clientId, 'redirect_uri_from_query' => $redirectFromQuery] |
|
491 | ); |
||
492 | } |
||
493 | } else { |
||
494 | 2 | $this->logDebug('Client is not found.', ['client_id' => $clientId]); |
|
495 | } |
||
496 | |||
497 | 9 | return [$client, $validRedirectUri]; |
|
498 | } |
||
499 | |||
500 | /** |
||
501 | * @param TokenInterface $token |
||
502 | * @param int $tokenExpiresIn |
||
503 | * |
||
504 | * @return ResponseInterface |
||
505 | */ |
||
506 | 5 | protected function createBodyTokenResponse(TokenInterface $token, int $tokenExpiresIn): ResponseInterface |
|
507 | { |
||
508 | 5 | $this->logDebug('Sending token as JSON response.'); |
|
509 | |||
510 | 5 | $scopeList = $token->isScopeModified() === false || empty($token->getScopeIdentifiers()) === true ? |
|
511 | 5 | null : $token->getScopeList(); |
|
512 | |||
513 | // for access token format @link https://tools.ietf.org/html/rfc6749#section-5.1 |
||
514 | 5 | $parameters = $this->filterNulls([ |
|
515 | 5 | 'access_token' => $token->getValue(), |
|
516 | 5 | 'token_type' => $token->getType(), |
|
517 | 5 | 'expires_in' => $tokenExpiresIn, |
|
518 | 5 | 'refresh_token' => $token->getRefreshValue(), |
|
519 | 5 | 'scope' => $scopeList, |
|
520 | ]); |
||
521 | |||
522 | // extra parameters |
||
523 | // https://tools.ietf.org/html/rfc6749#section-4.1.4 |
||
524 | // https://tools.ietf.org/html/rfc6749#section-4.3.3 |
||
525 | // https://tools.ietf.org/html/rfc6749#section-4.4.3 |
||
526 | 5 | $extraParameters = $this->getIntegration()->getBodyTokenExtraParameters($token); |
|
527 | |||
528 | 5 | $response = new JsonResponse($parameters + $extraParameters, 200, [ |
|
529 | 5 | 'Cache-Control' => 'no-store', |
|
530 | 'Pragma' => 'no-cache' |
||
531 | ]); |
||
532 | |||
533 | 5 | return $response; |
|
534 | } |
||
535 | |||
536 | /** |
||
537 | * @param TokenInterface $code |
||
538 | * @param string|null $state |
||
539 | * |
||
540 | * @return ResponseInterface |
||
541 | */ |
||
542 | 1 | protected function createRedirectCodeResponse(TokenInterface $code, string $state = null): ResponseInterface |
|
543 | { |
||
544 | 1 | $this->logDebug('Sending code as redirect response.'); |
|
545 | |||
546 | // for access token format @link https://tools.ietf.org/html/rfc6749#section-4.1.3 |
||
547 | 1 | $parameters = $this->filterNulls([ |
|
548 | 1 | 'code' => $code->getCode(), |
|
549 | 1 | 'state' => $state, |
|
550 | ]); |
||
551 | |||
552 | 1 | $redirectUri = $code->getRedirectUriString(); |
|
553 | 1 | $query = $this->encodeAsXWwwFormUrlencoded($parameters); |
|
554 | |||
555 | 1 | $response = new RedirectResponse((new Uri($redirectUri))->withQuery($query)); |
|
556 | |||
557 | 1 | return $response; |
|
558 | } |
||
559 | |||
560 | /** |
||
561 | * @param TokenInterface $token |
||
562 | * @param int $tokenExpiresIn |
||
563 | * @param string|null $state |
||
564 | * |
||
565 | * @return ResponseInterface |
||
566 | */ |
||
567 | 1 | protected function createRedirectTokenResponse( |
|
568 | TokenInterface $token, |
||
569 | int $tokenExpiresIn, |
||
570 | string $state = null |
||
571 | ): ResponseInterface { |
||
572 | 1 | $this->logDebug('Sending token as redirect response.'); |
|
573 | |||
574 | 1 | $scopeList = $token->isScopeModified() === false || empty($token->getScopeIdentifiers()) === true ? |
|
575 | 1 | null : $token->getScopeList(); |
|
576 | |||
577 | // for access token format @link https://tools.ietf.org/html/rfc6749#section-5.1 |
||
578 | 1 | $parameters = $this->filterNulls([ |
|
579 | 1 | 'access_token' => $token->getValue(), |
|
580 | 1 | 'token_type' => $token->getType(), |
|
581 | 1 | 'expires_in' => $tokenExpiresIn, |
|
582 | 1 | 'scope' => $scopeList, |
|
583 | 1 | 'state' => $state, |
|
584 | ]); |
||
585 | |||
586 | 1 | $fragment = $this->encodeAsXWwwFormUrlencoded($parameters); |
|
587 | |||
588 | 1 | $response = new RedirectResponse((new Uri($token->getRedirectUriString()))->withFragment($fragment)); |
|
589 | |||
590 | 1 | return $response; |
|
591 | } |
||
592 | |||
593 | /** |
||
594 | * @param OAuthTokenBodyException $exception |
||
595 | * |
||
596 | * @return ResponseInterface |
||
597 | */ |
||
598 | 4 | protected function createBodyErrorResponse(OAuthTokenBodyException $exception): ResponseInterface |
|
599 | { |
||
600 | 4 | $data = $this->filterNulls([ |
|
601 | 4 | 'error' => $exception->getErrorCode(), |
|
602 | 4 | 'error_description' => $exception->getErrorDescription(), |
|
603 | 4 | 'error_uri' => $this->getBodyErrorUri($exception), |
|
604 | ]); |
||
605 | |||
606 | 4 | $this->logDebug('Sending OAuth error as JSON response.', $data); |
|
607 | |||
608 | 4 | $response = new JsonResponse($data, $exception->getHttpCode(), $exception->getHttpHeaders()); |
|
609 | |||
610 | 4 | return $response; |
|
611 | } |
||
612 | |||
613 | /** |
||
614 | * @param OAuthRedirectException $exception |
||
615 | * |
||
616 | * @return ResponseInterface |
||
617 | */ |
||
618 | 1 | protected function createRedirectErrorResponse(OAuthRedirectException $exception): ResponseInterface |
|
619 | { |
||
620 | 1 | $parameters = $this->filterNulls([ |
|
621 | 1 | 'error' => $exception->getErrorCode(), |
|
622 | 1 | 'error_description' => $exception->getErrorDescription(), |
|
623 | 1 | 'error_uri' => $exception->getErrorUri(), |
|
624 | 1 | 'state' => $exception->getState(), |
|
625 | ]); |
||
626 | |||
627 | 1 | $this->logDebug('Sending OAuth error via redirect.', $parameters); |
|
628 | |||
629 | 1 | $fragment = $this->encodeAsXWwwFormUrlencoded($parameters); |
|
630 | 1 | $uri = (new Uri($exception->getRedirectUri()))->withFragment($fragment); |
|
631 | |||
632 | 1 | $response = new RedirectResponse($uri, 302, $exception->getHttpHeaders()); |
|
633 | |||
634 | 1 | return $response; |
|
635 | } |
||
636 | |||
637 | /** |
||
638 | * @param TokenInterface $token |
||
639 | * |
||
640 | * @return int |
||
641 | */ |
||
642 | 1 | protected function setUpTokenValue(TokenInterface $token): int |
|
643 | { |
||
644 | list($tokenValue, $tokenType, $tokenExpiresIn) = |
||
645 | 1 | $this->getIntegration()->generateTokenValues($token); |
|
646 | 1 | $token->setValue($tokenValue)->setType($tokenType); |
|
647 | |||
648 | 1 | return $tokenExpiresIn; |
|
649 | } |
||
650 | |||
651 | /** |
||
652 | * @param TokenInterface $token |
||
653 | * |
||
654 | * @return int |
||
655 | */ |
||
656 | 4 | protected function setUpTokenValues(TokenInterface $token): int |
|
657 | { |
||
658 | list($tokenValue, $tokenType, $tokenExpiresIn, $refreshValue) = |
||
659 | 4 | $this->getIntegration()->generateTokenValues($token); |
|
660 | 4 | $token->setValue($tokenValue)->setType($tokenType)->setRefreshValue($refreshValue); |
|
661 | |||
662 | 4 | return $tokenExpiresIn; |
|
663 | } |
||
664 | |||
665 | /** |
||
666 | * @return PassportServerIntegrationInterface |
||
667 | */ |
||
668 | 16 | protected function getIntegration(): PassportServerIntegrationInterface |
|
669 | { |
||
670 | 16 | return $this->integration; |
|
671 | } |
||
672 | |||
673 | /** |
||
674 | * @param PassportServerIntegrationInterface $integration |
||
675 | * |
||
676 | * @return self |
||
677 | */ |
||
678 | 17 | protected function setIntegration(PassportServerIntegrationInterface $integration): self |
|
679 | { |
||
680 | 17 | $this->integration = $integration; |
|
681 | |||
682 | 17 | return $this; |
|
683 | } |
||
684 | |||
685 | /** |
||
686 | * @param OAuthTokenBodyException $exception |
||
687 | * |
||
688 | * @return null|string |
||
689 | */ |
||
690 | 4 | protected function getBodyErrorUri(OAuthTokenBodyException $exception) |
|
691 | { |
||
692 | 4 | assert($exception !== null); |
|
693 | |||
694 | 4 | return null; |
|
695 | } |
||
696 | |||
697 | /** |
||
698 | * @param string $message |
||
699 | * @param array $context |
||
700 | * |
||
701 | * @return void |
||
702 | */ |
||
703 | 16 | protected function logDebug(string $message, array $context = []): void |
|
704 | { |
||
705 | 16 | if ($this->logger !== null) { |
|
706 | 16 | $this->logger->debug($message, $context); |
|
707 | } |
||
708 | } |
||
709 | |||
710 | /** |
||
711 | * @param string $message |
||
712 | * @param array $context |
||
713 | * |
||
714 | * @return void |
||
715 | */ |
||
716 | 10 | protected function logInfo(string $message, array $context = []): void |
|
717 | { |
||
718 | 10 | if ($this->logger !== null) { |
|
719 | 10 | $this->logger->info($message, $context); |
|
720 | } |
||
721 | } |
||
722 | |||
723 | /** |
||
724 | * @param array $array |
||
725 | * |
||
726 | * @return array |
||
727 | */ |
||
728 | 10 | private function filterNulls(array $array): array |
|
729 | { |
||
730 | return array_filter($array, function ($value) { |
||
731 | 10 | return $value !== null; |
|
732 | 10 | }); |
|
733 | } |
||
734 | } |
||
735 |
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.