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 |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Rinvex\Oauth\Grants; |
||
6 | |||
7 | use stdClass; |
||
8 | use DateInterval; |
||
9 | use LogicException; |
||
10 | use League\OAuth2\Server\RequestEvent; |
||
11 | use Psr\Http\Message\ServerRequestInterface; |
||
12 | use League\OAuth2\Server\Entities\ClientEntityInterface; |
||
13 | use League\OAuth2\Server\Exception\OAuthServerException; |
||
14 | use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface; |
||
15 | use League\OAuth2\Server\Grant\AuthCodeGrant as BaseAuthCodeGrant; |
||
16 | use League\OAuth2\Server\CodeChallengeVerifiers\CodeChallengeVerifierInterface; |
||
17 | |||
18 | class AuthCodeGrant extends BaseAuthCodeGrant |
||
19 | { |
||
20 | /** |
||
21 | * @var CodeChallengeVerifierInterface[] |
||
22 | */ |
||
23 | private $codeChallengeVerifiers = []; |
||
0 ignored issues
–
show
Comprehensibility
introduced
by
![]() |
|||
24 | |||
25 | /** |
||
26 | * Respond to an access token request. |
||
27 | * |
||
28 | * @param ServerRequestInterface $request |
||
29 | * @param ResponseTypeInterface $responseType |
||
30 | * @param DateInterval $accessTokenTTL |
||
31 | * |
||
32 | * @throws OAuthServerException |
||
33 | * |
||
34 | * @return ResponseTypeInterface |
||
35 | */ |
||
36 | public function respondToAccessTokenRequest(ServerRequestInterface $request, ResponseTypeInterface $responseType, DateInterval $accessTokenTTL) |
||
37 | { |
||
38 | [$clientId] = $this->getClientCredentials($request); |
||
0 ignored issues
–
show
|
|||
39 | $client = $this->getClientEntityOrFail($clientId, $request); |
||
40 | |||
41 | // Only validate the client if it is confidential |
||
42 | if ($client->isConfidential()) { |
||
43 | $this->validateClient($request); |
||
44 | } |
||
45 | |||
46 | $encryptedAuthCode = $this->getRequestParameter('code', $request, null); |
||
47 | |||
48 | if ($encryptedAuthCode === null) { |
||
49 | throw OAuthServerException::invalidRequest('code'); |
||
50 | } |
||
51 | |||
52 | try { |
||
53 | $authCodePayload = \json_decode($this->decrypt($encryptedAuthCode)); |
||
54 | |||
55 | $this->validateAuthorizationCode($authCodePayload, $client, $request); |
||
56 | |||
57 | $scopes = $this->scopeRepository->finalizeScopes( |
||
58 | $this->validateScopes($authCodePayload->scopes), |
||
59 | $this->getIdentifier(), |
||
60 | $client, |
||
61 | $authCodePayload->user_id |
||
62 | ); |
||
63 | } catch (LogicException $e) { |
||
64 | throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code', $e); |
||
65 | } |
||
66 | |||
67 | // Validate code challenge |
||
68 | if (! empty($authCodePayload->code_challenge)) { |
||
69 | $codeVerifier = $this->getRequestParameter('code_verifier', $request, null); |
||
70 | |||
71 | if ($codeVerifier === null) { |
||
72 | throw OAuthServerException::invalidRequest('code_verifier'); |
||
73 | } |
||
74 | |||
75 | // Validate code_verifier according to RFC-7636 |
||
76 | // @see: https://tools.ietf.org/html/rfc7636#section-4.1 |
||
77 | if (preg_match('/^[A-Za-z0-9-._~]{43,128}$/', $codeVerifier) !== 1) { |
||
78 | throw OAuthServerException::invalidRequest( |
||
79 | 'code_verifier', |
||
80 | 'Code Verifier must follow the specifications of RFC-7636.' |
||
81 | ); |
||
82 | } |
||
83 | |||
84 | if (property_exists($authCodePayload, 'code_challenge_method')) { |
||
85 | if (isset($this->codeChallengeVerifiers[$authCodePayload->code_challenge_method])) { |
||
86 | $codeChallengeVerifier = $this->codeChallengeVerifiers[$authCodePayload->code_challenge_method]; |
||
87 | |||
88 | if ($codeChallengeVerifier->verifyCodeChallenge($codeVerifier, $authCodePayload->code_challenge) === false) { |
||
89 | throw OAuthServerException::invalidGrant('Failed to verify `code_verifier`.'); |
||
90 | } |
||
91 | } else { |
||
92 | throw OAuthServerException::serverError( |
||
93 | sprintf( |
||
94 | 'Unsupported code challenge method `%s`', |
||
95 | $authCodePayload->code_challenge_method |
||
96 | ) |
||
97 | ); |
||
98 | } |
||
99 | } |
||
100 | } |
||
101 | |||
102 | // Issue and persist new access token |
||
103 | $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes); |
||
104 | $this->getEmitter()->emit(new RequestEvent(RequestEvent::ACCESS_TOKEN_ISSUED, $request)); |
||
105 | $responseType->setAccessToken($accessToken); |
||
0 ignored issues
–
show
It seems like
$accessToken defined by $this->issueAccessToken(...load->user_id, $scopes) on line 103 can be null ; however, League\OAuth2\Server\Res...rface::setAccessToken() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
106 | |||
107 | // Issue and persist new refresh token if given |
||
108 | $refreshToken = $this->issueRefreshToken($accessToken); |
||
0 ignored issues
–
show
It seems like
$accessToken defined by $this->issueAccessToken(...load->user_id, $scopes) on line 103 can be null ; however, League\OAuth2\Server\Gra...nt::issueRefreshToken() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
|||
109 | |||
110 | if ($refreshToken !== null) { |
||
111 | $this->getEmitter()->emit(new RequestEvent(RequestEvent::REFRESH_TOKEN_ISSUED, $request)); |
||
112 | $responseType->setRefreshToken($refreshToken); |
||
113 | } |
||
114 | |||
115 | // Revoke used auth code |
||
116 | $this->authCodeRepository->revokeAuthCode($authCodePayload->auth_code_id); |
||
117 | |||
118 | return $responseType; |
||
119 | } |
||
120 | |||
121 | /** |
||
122 | * Validate the authorization code. |
||
123 | * |
||
124 | * @param stdClass $authCodePayload |
||
125 | * @param ClientEntityInterface $client |
||
126 | * @param ServerRequestInterface $request |
||
127 | */ |
||
128 | private function validateAuthorizationCode($authCodePayload, ClientEntityInterface $client, ServerRequestInterface $request) |
||
0 ignored issues
–
show
|
|||
129 | { |
||
130 | if (! property_exists($authCodePayload, 'auth_code_id')) { |
||
131 | throw OAuthServerException::invalidRequest('code', 'Authorization code malformed'); |
||
132 | } |
||
133 | |||
134 | if (time() > $authCodePayload->expire_time) { |
||
135 | throw OAuthServerException::invalidRequest('code', 'Authorization code has expired'); |
||
136 | } |
||
137 | |||
138 | if ($this->authCodeRepository->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) { |
||
139 | throw OAuthServerException::invalidRequest('code', 'Authorization code has been revoked'); |
||
140 | } |
||
141 | |||
142 | if ($authCodePayload->client_id !== $client->getIdentifier()) { |
||
143 | throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client'); |
||
144 | } |
||
145 | |||
146 | $this->validateUser($authCodePayload); |
||
147 | |||
148 | // The redirect URI is required in this request |
||
149 | $redirectUri = $this->getRequestParameter('redirect_uri', $request, null); |
||
150 | if (empty($authCodePayload->redirect_uri) === false && $redirectUri === null) { |
||
151 | throw OAuthServerException::invalidRequest('redirect_uri'); |
||
152 | } |
||
153 | |||
154 | if ($authCodePayload->redirect_uri !== $redirectUri) { |
||
155 | throw OAuthServerException::invalidRequest('redirect_uri', 'Invalid redirect URI'); |
||
156 | } |
||
157 | } |
||
158 | |||
159 | /** |
||
160 | * Validate the authorization code user. |
||
161 | * |
||
162 | * @param stdClass $authCodePayload |
||
163 | */ |
||
164 | protected function validateUser(stdClass $authCodePayload) |
||
165 | { |
||
166 | [$userType, $userId] = explode(':', $authCodePayload->user_id); |
||
0 ignored issues
–
show
|
|||
167 | |||
168 | if ($userType !== request()->user()->getMorphClass() || $userId !== request()->user()->getRouteKey()) { |
||
169 | throw OAuthServerException::invalidRequest('user_id', 'Authorization code was not issued to this user'); |
||
170 | } |
||
171 | } |
||
172 | } |
||
173 |