Completed
Pull Request — master (#965)
by Andrew
01:43
created

OAuthServerException::getHint()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
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 Exception;
13
use Psr\Http\Message\ResponseInterface;
14
use Throwable;
15
16
class OAuthServerException extends Exception
17
{
18
    /**
19
     * @var int
20
     */
21
    private $httpStatusCode;
22
23
    /**
24
     * @var string
25
     */
26
    private $errorType;
27
28
    /**
29
     * @var null|string
30
     */
31
    private $hint;
32
33
    /**
34
     * @var null|string
35
     */
36
    private $redirectUri;
37
38
    /**
39
     * @var array
40
     */
41
    private $payload;
42
43
    /**
44
     * Throw a new exception.
45
     *
46
     * @param string      $message        Error message
47
     * @param int         $code           Error code
48
     * @param string      $errorType      Error type
49
     * @param int         $httpStatusCode HTTP status code to send (default = 400)
50
     * @param null|string $hint           A helper hint
51
     * @param null|string $redirectUri    A HTTP URI to redirect the user back to
52
     * @param Throwable   $previous       Previous exception
53
     */
54 70
    public function __construct($message, $code, $errorType, $httpStatusCode = 400, $hint = null, $redirectUri = null, Throwable $previous = null)
55
    {
56 70
        parent::__construct($message, $code, $previous);
57 70
        $this->httpStatusCode = $httpStatusCode;
58 70
        $this->errorType = $errorType;
59 70
        $this->hint = $hint;
60 70
        $this->redirectUri = $redirectUri;
61 70
        $this->payload = [
62 70
            'error'   => $errorType,
63 70
            'message' => $message,
64
        ];
65 70
        if ($hint !== null) {
66 45
            $this->payload['hint'] = $hint;
67
        }
68 70
    }
69
70
    /**
71
     * Returns the current payload.
72
     *
73
     * @return array
74
     */
75 5
    public function getPayload()
76
    {
77 5
        return $this->payload;
78
    }
79
80
    /**
81
     * Updates the current payload.
82
     *
83
     * @param array $payload
84
     */
85
    public function setPayload(array $payload)
86
    {
87
        $this->payload = $payload;
88
    }
89
90
    /**
91
     * Unsupported grant type error.
92
     *
93
     * @return static
94
     */
95 2
    public static function unsupportedGrantType()
96
    {
97 2
        $errorMessage = 'The authorization grant type is not supported by the authorization server.';
98 2
        $hint = 'Check that all required parameters have been provided';
99
100 2
        return new static($errorMessage, 2, 'unsupported_grant_type', 400, $hint);
101
    }
102
103
    /**
104
     * Invalid request error.
105
     *
106
     * @param string      $parameter The invalid parameter
107
     * @param null|string $hint
108
     * @param Throwable  $previous  Previous exception
109
     *
110
     * @return static
111
     */
112 22
    public static function invalidRequest($parameter, $hint = null, Throwable $previous = null)
113
    {
114
        $errorMessage = 'The request is missing a required parameter, includes an invalid parameter value, ' .
115 22
            'includes a parameter more than once, or is otherwise malformed.';
116 22
        $hint = ($hint === null) ? sprintf('Check the `%s` parameter', $parameter) : $hint;
117
118 22
        return new static($errorMessage, 3, 'invalid_request', 400, $hint, null, $previous);
119
    }
120
121
    /**
122
     * Invalid client error.
123
     *
124
     * @return static
125
     */
126 13
    public static function invalidClient()
127
    {
128 13
        $errorMessage = 'Client authentication failed';
129
130 13
        return new static($errorMessage, 4, 'invalid_client', 401);
131
    }
132
133
    /**
134
     * Invalid scope error.
135
     *
136
     * @param string      $scope       The bad scope
137
     * @param null|string $redirectUri A HTTP URI to redirect the user back to
138
     *
139
     * @return static
140
     */
141 4
    public static function invalidScope($scope, $redirectUri = null)
142
    {
143 4
        $errorMessage = 'The requested scope is invalid, unknown, or malformed';
144
145 4
        if (empty($scope)) {
146
            $hint = 'Specify a scope in the request or set a default scope';
147
        } else {
148 4
            $hint = sprintf(
149 4
                'Check the `%s` scope',
150 4
                htmlspecialchars($scope, ENT_QUOTES, 'UTF-8', false)
151
            );
152
        }
153
154 4
        return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri);
155
    }
156
157
    /**
158
     * Invalid credentials error.
159
     *
160
     * @return static
161
     */
162 1
    public static function invalidCredentials()
163
    {
164 1
        return new static('The user credentials were incorrect.', 6, 'invalid_credentials', 401);
165
    }
166
167
    /**
168
     * Server error.
169
     *
170
     * @param string    $hint
171
     * @param Throwable $previous
172
     *
173
     * @return static
174
     *
175
     * @codeCoverageIgnore
176
     */
177
    public static function serverError($hint, Throwable $previous = null)
178
    {
179
        return new static(
180
            'The authorization server encountered an unexpected condition which prevented it from fulfilling'
181
            . ' the request: ' . $hint,
182
            7,
183
            'server_error',
184
            500,
185
            $previous
0 ignored issues
show
Bug introduced by
It seems like $previous defined by parameter $previous on line 177 can also be of type object<Throwable>; however, League\OAuth2\Server\Exc...xception::__construct() does only seem to accept null|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.

Loading history...
186
        );
187
    }
188
189
    /**
190
     * Invalid refresh token.
191
     *
192
     * @param null|string $hint
193
     * @param Throwable   $previous
194
     *
195
     * @return static
196
     */
197 4
    public static function invalidRefreshToken($hint = null, Throwable $previous = null)
198
    {
199 4
        return new static('The refresh token is invalid.', 8, 'invalid_request', 401, $hint, null, $previous);
200
    }
201
202
    /**
203
     * Access denied.
204
     *
205
     * @param null|string $hint
206
     * @param null|string $redirectUri
207
     * @param Throwable  $previous
208
     *
209
     * @return static
210
     */
211 14
    public static function accessDenied($hint = null, $redirectUri = null, Throwable $previous = null)
212
    {
213 14
        return new static(
214 14
            'The resource owner or authorization server denied the request.',
215 14
            9,
216 14
            'access_denied',
217 14
            401,
218 14
            $hint,
219 14
            $redirectUri,
220 14
            $previous
221
        );
222
    }
223
224
    /**
225
     * Invalid grant.
226
     *
227
     * @param string $hint
228
     *
229
     * @return static
230
     */
231 1
    public static function invalidGrant($hint = '')
232
    {
233 1
        return new static(
234
            'The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token '
235
                . 'is invalid, expired, revoked, does not match the redirection URI used in the authorization request, '
236 1
                . 'or was issued to another client.',
237 1
            10,
238 1
            'invalid_grant',
239 1
            400,
240 1
            $hint
241
        );
242
    }
243
244
    /**
245
     * @return string
246
     */
247 2
    public function getErrorType()
248
    {
249 2
        return $this->errorType;
250
    }
251
252
    /**
253
     * Generate a HTTP response.
254
     *
255
     * @param ResponseInterface $response
256
     * @param bool              $useFragment True if errors should be in the URI fragment instead of query string
257
     * @param int               $jsonOptions options passed to json_encode
258
     *
259
     * @return ResponseInterface
260
     */
261 5
    public function generateHttpResponse(ResponseInterface $response, $useFragment = false, $jsonOptions = 0)
262
    {
263 5
        $headers = $this->getHttpHeaders();
264
265 5
        $payload = $this->getPayload();
266
267 5
        if ($this->redirectUri !== null) {
268 2
            if ($useFragment === true) {
269 1
                $this->redirectUri .= (strstr($this->redirectUri, '#') === false) ? '#' : '&';
270
            } else {
271 1
                $this->redirectUri .= (strstr($this->redirectUri, '?') === false) ? '?' : '&';
272
            }
273
274 2
            return $response->withStatus(302)->withHeader('Location', $this->redirectUri . http_build_query($payload));
275
        }
276
277 3
        foreach ($headers as $header => $content) {
278 3
            $response = $response->withHeader($header, $content);
279
        }
280
281 3
        $response->getBody()->write(json_encode($payload, $jsonOptions));
282
283 3
        return $response->withStatus($this->getHttpStatusCode());
284
    }
285
286
    /**
287
     * Get all headers that have to be send with the error response.
288
     *
289
     * @return array Array with header values
290
     */
291 5
    public function getHttpHeaders()
292
    {
293
        $headers = [
294 5
            'Content-type' => 'application/json',
295
        ];
296
297
        // Add "WWW-Authenticate" header
298
        //
299
        // RFC 6749, section 5.2.:
300
        // "If the client attempted to authenticate via the 'Authorization'
301
        // request header field, the authorization server MUST
302
        // respond with an HTTP 401 (Unauthorized) status code and
303
        // include the "WWW-Authenticate" response header field
304
        // matching the authentication scheme used by the client.
305
        // @codeCoverageIgnoreStart
306
        if ($this->errorType === 'invalid_client' && array_key_exists('HTTP_AUTHORIZATION', $_SERVER) !== false) {
307
            $authScheme = strpos($_SERVER['HTTP_AUTHORIZATION'], 'Bearer') === 0 ? 'Bearer' : 'Basic';
308
309
            $headers['WWW-Authenticate'] = $authScheme . ' realm="OAuth"';
310
        }
311
        // @codeCoverageIgnoreEnd
312 5
        return $headers;
313
    }
314
315
    /**
316
     * Check if the exception has an associated redirect URI.
317
     *
318
     * Returns whether the exception includes a redirect, since
319
     * getHttpStatusCode() doesn't return a 302 when there's a
320
     * redirect enabled. This helps when you want to override local
321
     * error pages but want to let redirects through.
322
     *
323
     * @return bool
324
     */
325 2
    public function hasRedirect()
326
    {
327 2
        return $this->redirectUri !== null;
328
    }
329
330
    /**
331
     * Returns the HTTP status code to send when the exceptions is output.
332
     *
333
     * @return int
334
     */
335 5
    public function getHttpStatusCode()
336
    {
337 5
        return $this->httpStatusCode;
338
    }
339
340
    /**
341
     * @return null|string
342
     */
343 14
    public function getHint()
344
    {
345 14
        return $this->hint;
346
    }
347
}
348