Completed
Pull Request — master (#899)
by Andrew
01:39
created

OAuthServerException::invalidGrant()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
ccs 7
cts 7
cp 1
rs 9.4285
cc 1
eloc 9
nc 1
nop 1
crap 1
1
<?php
2
/**
3
 * @author      Alex Bilbie <[email protected]>
4
 * @copyright   Copyright (c) Alex Bilbie
5
 * @license     http://mit-license.org/
6
 *
7
 * @link        https://github.com/thephpleague/oauth2-server
8
 */
9
10
namespace League\OAuth2\Server\Exception;
11
12
use Psr\Http\Message\ResponseInterface;
13
use Psr\Http\Message\ServerRequest;
14
15
class OAuthServerException extends \Exception
16
{
17
    /**
18
     * @var int
19
     */
20
    private $httpStatusCode;
21
22
    /**
23
     * @var string
24
     */
25
    private $errorType;
26
27
    /**
28
     * @var null|string
29
     */
30
    private $hint;
31
32
    /**
33
     * @var null|string
34
     */
35
    private $redirectUri;
36
37
    /**
38
     * @var array
39
     */
40
    private $payload;
41
42
    /**
43
     * @var ServerRequest
44
     */
45
    private $serverRequest;
0 ignored issues
show
Unused Code introduced by
The property $serverRequest is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
46
47
    /**
48
     * Throw a new exception.
49
     *
50
     * @param string      $message        Error message
51
     * @param int         $code           Error code
52
     * @param string      $errorType      Error type
53
     * @param int         $httpStatusCode HTTP status code to send (default = 400)
54
     * @param null|string $hint           A helper hint
55
     * @param null|string $redirectUri    A HTTP URI to redirect the user back to
56
     */
57 67
    public function __construct($message, $code, $errorType, $httpStatusCode = 400, $hint = null, $redirectUri = null)
58
    {
59 67
        parent::__construct($message, $code);
60 67
        $this->httpStatusCode = $httpStatusCode;
61 67
        $this->errorType = $errorType;
62 67
        $this->hint = $hint;
63 67
        $this->redirectUri = $redirectUri;
64 67
        $this->payload = [
65 67
            'error'   => $errorType,
66 67
            'message' => $message,
67
        ];
68 67
        if ($hint !== null) {
69 42
            $this->payload['hint'] = $hint;
70
        }
71 67
    }
72
73
    /**
74
     * Returns the current payload.
75
     *
76
     * @return array
77
     */
78 7
    public function getPayload()
79
    {
80 7
        return $this->payload;
81
    }
82
83
    /**
84
     * Updates the current payload.
85
     *
86
     * @param array $payload
87
     */
88
    public function setPayload(array $payload)
89
    {
90
        $this->payload = $payload;
91
    }
92
93
    /**
94
     * Set the server request that is responsible for generating the exception
95
     *
96
     * @return void
97
     */
98 15
    public function setServerRequest($serverRequest)
99
    {
100 15
        $this->ServerRequest = $serverRequest;
0 ignored issues
show
Bug introduced by
The property ServerRequest does not seem to exist. Did you mean serverRequest?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
101 15
    }
102
103
    /**
104
     * Unsupported grant type error.
105
     *
106
     * @return static
107
     */
108 2
    public static function unsupportedGrantType()
109
    {
110 2
        $errorMessage = 'The authorization grant type is not supported by the authorization server.';
111 2
        $hint = 'Check that all required parameters have been provided';
112
113 2
        return new static($errorMessage, 2, 'unsupported_grant_type', 400, $hint);
114
    }
115
116
    /**
117
     * Invalid request error.
118
     *
119
     * @param string      $parameter The invalid parameter
120
     * @param null|string $hint
121
     *
122
     * @return static
123
     */
124 22
    public static function invalidRequest($parameter, $hint = null)
125
    {
126
        $errorMessage = 'The request is missing a required parameter, includes an invalid parameter value, ' .
127 22
            'includes a parameter more than once, or is otherwise malformed.';
128 22
        $hint = ($hint === null) ? sprintf('Check the `%s` parameter', $parameter) : $hint;
129
130 22
        return new static($errorMessage, 3, 'invalid_request', 400, $hint);
131
    }
132
133
    /**
134
     * Invalid client error.
135
     *
136
     * @param ServerRequest $serverRequest
137
     *
138
     * @return static
139
     */
140 15
    public static function invalidClient($serverRequest)
141
    {
142 15
        $errorMessage = 'Client authentication failed';
0 ignored issues
show
Unused Code introduced by
$errorMessage is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
143
144 15
        $exception = new static('Client authentication failed', 4, 'invalid_client', 401);
145
146 15
        $exception->setServerRequest($serverRequest);
147
148 15
        return $exception;
149
    }
150
151
    /**
152
     * Invalid scope error.
153
     *
154
     * @param string      $scope       The bad scope
155
     * @param null|string $redirectUri A HTTP URI to redirect the user back to
156
     *
157
     * @return static
158
     */
159 4
    public static function invalidScope($scope, $redirectUri = null)
160
    {
161 4
        $errorMessage = 'The requested scope is invalid, unknown, or malformed';
162
163 4
        if (empty($scope)) {
164
            $hint = 'Specify a scope in the request or set a default scope';
165
        } else {
166 4
            $hint = sprintf(
167 4
                'Check the `%s` scope',
168 4
                htmlspecialchars($scope, ENT_QUOTES, 'UTF-8', false)
169
            );
170
        }
171
172 4
        return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri);
173
    }
174
175
    /**
176
     * Invalid credentials error.
177
     *
178
     * @return static
179
     */
180 1
    public static function invalidCredentials()
181
    {
182 1
        return new static('The user credentials were incorrect.', 6, 'invalid_credentials', 401);
183
    }
184
185
    /**
186
     * Server error.
187
     *
188
     * @param string $hint
189
     *
190
     * @return static
191
     *
192
     * @codeCoverageIgnore
193
     */
194
    public static function serverError($hint)
195
    {
196
        return new static(
197
            'The authorization server encountered an unexpected condition which prevented it from fulfilling'
198
            . ' the request: ' . $hint,
199
            7,
200
            'server_error',
201
            500
202
        );
203
    }
204
205
    /**
206
     * Invalid refresh token.
207
     *
208
     * @param null|string $hint
209
     *
210
     * @return static
211
     */
212 4
    public static function invalidRefreshToken($hint = null)
213
    {
214 4
        return new static('The refresh token is invalid.', 8, 'invalid_request', 401, $hint);
215
    }
216
217
    /**
218
     * Access denied.
219
     *
220
     * @param null|string $hint
221
     * @param null|string $redirectUri
222
     *
223
     * @return static
224
     */
225 9
    public static function accessDenied($hint = null, $redirectUri = null)
226
    {
227 9
        return new static(
228 9
            'The resource owner or authorization server denied the request.',
229 9
            9,
230 9
            'access_denied',
231 9
            401,
232 9
            $hint,
233 9
            $redirectUri
234
        );
235
    }
236
237
    /**
238
     * Invalid grant.
239
     *
240
     * @param string $hint
241
     *
242
     * @return static
243
     */
244 1
    public static function invalidGrant($hint = '')
245
    {
246 1
        return new static(
247
            'The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token '
248
                . 'is invalid, expired, revoked, does not match the redirection URI used in the authorization request, '
249 1
                . 'or was issued to another client.',
250 1
            10,
251 1
            'invalid_grant',
252 1
            400,
253 1
            $hint
254
        );
255
    }
256
257
    /**
258
     * @return string
259
     */
260 2
    public function getErrorType()
261
    {
262 2
        return $this->errorType;
263
    }
264
265
    /**
266
     * Generate a HTTP response.
267
     *
268
     * @param ResponseInterface $response
269
     * @param bool              $useFragment True if errors should be in the URI fragment instead of query string
270
     * @param int               $jsonOptions options passed to json_encode
271
     *
272
     * @return ResponseInterface
273
     */
274 7
    public function generateHttpResponse(ResponseInterface $response, $useFragment = false, $jsonOptions = 0)
275
    {
276 7
        $headers = $this->getHttpHeaders();
277
278 7
        $payload = $this->getPayload();
279
280 7
        if ($this->redirectUri !== null) {
281 2
            if ($useFragment === true) {
282 1
                $this->redirectUri .= (strstr($this->redirectUri, '#') === false) ? '#' : '&';
283
            } else {
284 1
                $this->redirectUri .= (strstr($this->redirectUri, '?') === false) ? '?' : '&';
285
            }
286
287 2
            return $response->withStatus(302)->withHeader('Location', $this->redirectUri . http_build_query($payload));
288
        }
289
290 5
        foreach ($headers as $header => $content) {
291 5
            $response = $response->withHeader($header, $content);
292
        }
293
294 5
        $response->getBody()->write(json_encode($payload, $jsonOptions));
295
296 5
        return $response->withStatus($this->getHttpStatusCode());
297
    }
298
299
    /**
300
     * Get all headers that have to be send with the error response.
301
     *
302
     * @return array Array with header values
303
     */
304 7
    public function getHttpHeaders()
305
    {
306
        $headers = [
307 7
            'Content-type' => 'application/json',
308
        ];
309
310
        // Add "WWW-Authenticate" header
311
        //
312
        // RFC 6749, section 5.2.:
313
        // "If the client attempted to authenticate via the 'Authorization'
314
        // request header field, the authorization server MUST
315
        // respond with an HTTP 401 (Unauthorized) status code and
316
        // include the "WWW-Authenticate" response header field
317
        // matching the authentication scheme used by the client.
318
        // @codeCoverageIgnoreStart
319
        if ($this->errorType === 'invalid_client' && $this->ServerRequest->hasHeader('Authorization') === true) {
0 ignored issues
show
Bug introduced by
The property ServerRequest does not seem to exist. Did you mean serverRequest?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
320
            $authScheme = strpos($this->ServerRequest->getHeader('Authorization')[0], 'Bearer') === 0 ? 'Bearer' : 'Basic';
0 ignored issues
show
Bug introduced by
The property ServerRequest does not seem to exist. Did you mean serverRequest?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
321
322
            $headers['WWW-Authenticate'] = $authScheme . ' realm="OAuth"';
323
        }
324
        // @codeCoverageIgnoreEnd
325 7
        return $headers;
326
    }
327
328
    /**
329
     * Returns the HTTP status code to send when the exceptions is output.
330
     *
331
     * @return int
332
     */
333 7
    public function getHttpStatusCode()
334
    {
335 7
        return $this->httpStatusCode;
336
    }
337
338
    /**
339
     * @return null|string
340
     */
341 14
    public function getHint()
342
    {
343 14
        return $this->hint;
344
    }
345
}
346