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

OAuthServerException   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 332
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 0

Test Coverage

Coverage 94.94%

Importance

Changes 0
Metric Value
wmc 29
lcom 2
cbo 0
dl 0
loc 332
ccs 75
cts 79
cp 0.9494
rs 10
c 0
b 0
f 0

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 2
A getPayload() 0 4 1
A setPayload() 0 4 1
A unsupportedGrantType() 0 7 1
A invalidRequest() 0 8 2
A invalidClient() 0 6 1
A invalidScope() 0 15 2
A invalidCredentials() 0 4 1
A serverError() 0 11 1
A invalidRefreshToken() 0 4 1
A accessDenied() 0 12 1
A invalidGrant() 0 12 1
A getErrorType() 0 4 1
B generateHttpResponse() 0 24 6
A getHttpHeaders() 0 23 4
A hasRedirect() 0 4 1
A getHttpStatusCode() 0 4 1
A getHint() 0 4 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
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
     * Throw a new exception.
44
     *
45
     * @param string      $message        Error message
46
     * @param int         $code           Error code
47
     * @param string      $errorType      Error type
48
     * @param int         $httpStatusCode HTTP status code to send (default = 400)
49
     * @param null|string $hint           A helper hint
50
     * @param null|string $redirectUri    A HTTP URI to redirect the user back to
51
     * @param \Throwable  $previous       Previous exception
52
     */
53 70
    public function __construct($message, $code, $errorType, $httpStatusCode = 400, $hint = null, $redirectUri = null, \Throwable $previous = null)
54
    {
55 70
        parent::__construct($message, $code, $previous);
56 70
        $this->httpStatusCode = $httpStatusCode;
57 70
        $this->errorType = $errorType;
58 70
        $this->hint = $hint;
59 70
        $this->redirectUri = $redirectUri;
60 70
        $this->payload = [
61 70
            'error'   => $errorType,
62 70
            'message' => $message,
63
        ];
64 70
        if ($hint !== null) {
65 45
            $this->payload['hint'] = $hint;
66
        }
67 70
    }
68
69
    /**
70
     * Returns the current payload.
71
     *
72
     * @return array
73
     */
74 5
    public function getPayload()
75
    {
76 5
        return $this->payload;
77
    }
78
79
    /**
80
     * Updates the current payload.
81
     *
82
     * @param array $payload
83
     */
84
    public function setPayload(array $payload)
85
    {
86
        $this->payload = $payload;
87
    }
88
89
    /**
90
     * Unsupported grant type error.
91
     *
92
     * @return static
93
     */
94 2
    public static function unsupportedGrantType()
95
    {
96 2
        $errorMessage = 'The authorization grant type is not supported by the authorization server.';
97 2
        $hint = 'Check that all required parameters have been provided';
98
99 2
        return new static($errorMessage, 2, 'unsupported_grant_type', 400, $hint);
100
    }
101
102
    /**
103
     * Invalid request error.
104
     *
105
     * @param string      $parameter The invalid parameter
106
     * @param null|string $hint
107
     * @param \Throwable  $previous  Previous exception
108
     *
109
     * @return static
110
     */
111 22
    public static function invalidRequest($parameter, $hint = null, \Throwable $previous = null)
112
    {
113
        $errorMessage = 'The request is missing a required parameter, includes an invalid parameter value, ' .
114 22
            'includes a parameter more than once, or is otherwise malformed.';
115 22
        $hint = ($hint === null) ? sprintf('Check the `%s` parameter', $parameter) : $hint;
116
117 22
        return new static($errorMessage, 3, 'invalid_request', 400, $hint, null, $previous);
118
    }
119
120
    /**
121
     * Invalid client error.
122
     *
123
     * @return static
124
     */
125 13
    public static function invalidClient()
126
    {
127 13
        $errorMessage = 'Client authentication failed';
128
129 13
        return new static($errorMessage, 4, 'invalid_client', 401);
130
    }
131
132
    /**
133
     * Invalid scope error.
134
     *
135
     * @param string      $scope       The bad scope
136
     * @param null|string $redirectUri A HTTP URI to redirect the user back to
137
     *
138
     * @return static
139
     */
140 4
    public static function invalidScope($scope, $redirectUri = null)
141
    {
142 4
        $errorMessage = 'The requested scope is invalid, unknown, or malformed';
143
144 4
        if (empty($scope)) {
145
            $hint = 'Specify a scope in the request or set a default scope';
146
        } else {
147 4
            $hint = sprintf(
148 4
                'Check the `%s` scope',
149 4
                htmlspecialchars($scope, ENT_QUOTES, 'UTF-8', false)
150
            );
151
        }
152
153 4
        return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri);
154
    }
155
156
    /**
157
     * Invalid credentials error.
158
     *
159
     * @return static
160
     */
161 1
    public static function invalidCredentials()
162
    {
163 1
        return new static('The user credentials were incorrect.', 6, 'invalid_credentials', 401);
164
    }
165
166
    /**
167
     * Server error.
168
     *
169
     * @param string     $hint
170
     * @param \Throwable $previous
171
     *
172
     * @return static
173
     *
174
     * @codeCoverageIgnore
175
     */
176
    public static function serverError($hint, \Throwable $previous = null)
177
    {
178
        return new static(
179
            'The authorization server encountered an unexpected condition which prevented it from fulfilling'
180
            . ' the request: ' . $hint,
181
            7,
182
            'server_error',
183
            500,
184
            $previous
0 ignored issues
show
Bug introduced by
It seems like $previous defined by parameter $previous on line 176 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...
185
        );
186
    }
187
188
    /**
189
     * Invalid refresh token.
190
     *
191
     * @param null|string $hint
192
     * @param \Throwable  $previous
193
     *
194
     * @return static
195
     */
196 4
    public static function invalidRefreshToken($hint = null, \Throwable $previous = null)
197
    {
198 4
        return new static('The refresh token is invalid.', 8, 'invalid_request', 401, $hint, null, $previous);
199
    }
200
201
    /**
202
     * Access denied.
203
     *
204
     * @param null|string $hint
205
     * @param null|string $redirectUri
206
     * @param \Throwable  $previous
207
     *
208
     * @return static
209
     */
210 14
    public static function accessDenied($hint = null, $redirectUri = null, \Throwable $previous = null)
211
    {
212 14
        return new static(
213 14
            'The resource owner or authorization server denied the request.',
214 14
            9,
215 14
            'access_denied',
216 14
            401,
217 14
            $hint,
218 14
            $redirectUri,
219 14
            $previous
220
        );
221
    }
222
223
    /**
224
     * Invalid grant.
225
     *
226
     * @param string $hint
227
     *
228
     * @return static
229
     */
230 1
    public static function invalidGrant($hint = '')
231
    {
232 1
        return new static(
233
            'The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token '
234
                . 'is invalid, expired, revoked, does not match the redirection URI used in the authorization request, '
235 1
                . 'or was issued to another client.',
236 1
            10,
237 1
            'invalid_grant',
238 1
            400,
239 1
            $hint
240
        );
241
    }
242
243
    /**
244
     * @return string
245
     */
246 2
    public function getErrorType()
247
    {
248 2
        return $this->errorType;
249
    }
250
251
    /**
252
     * Generate a HTTP response.
253
     *
254
     * @param ResponseInterface $response
255
     * @param bool              $useFragment True if errors should be in the URI fragment instead of query string
256
     * @param int               $jsonOptions options passed to json_encode
257
     *
258
     * @return ResponseInterface
259
     */
260 5
    public function generateHttpResponse(ResponseInterface $response, $useFragment = false, $jsonOptions = 0)
261
    {
262 5
        $headers = $this->getHttpHeaders();
263
264 5
        $payload = $this->getPayload();
265
266 5
        if ($this->redirectUri !== null) {
267 2
            if ($useFragment === true) {
268 1
                $this->redirectUri .= (strstr($this->redirectUri, '#') === false) ? '#' : '&';
269
            } else {
270 1
                $this->redirectUri .= (strstr($this->redirectUri, '?') === false) ? '?' : '&';
271
            }
272
273 2
            return $response->withStatus(302)->withHeader('Location', $this->redirectUri . http_build_query($payload));
274
        }
275
276 3
        foreach ($headers as $header => $content) {
277 3
            $response = $response->withHeader($header, $content);
278
        }
279
280 3
        $response->getBody()->write(json_encode($payload, $jsonOptions));
281
282 3
        return $response->withStatus($this->getHttpStatusCode());
283
    }
284
285
    /**
286
     * Get all headers that have to be send with the error response.
287
     *
288
     * @return array Array with header values
289
     */
290 5
    public function getHttpHeaders()
291
    {
292
        $headers = [
293 5
            'Content-type' => 'application/json',
294
        ];
295
296
        // Add "WWW-Authenticate" header
297
        //
298
        // RFC 6749, section 5.2.:
299
        // "If the client attempted to authenticate via the 'Authorization'
300
        // request header field, the authorization server MUST
301
        // respond with an HTTP 401 (Unauthorized) status code and
302
        // include the "WWW-Authenticate" response header field
303
        // matching the authentication scheme used by the client.
304
        // @codeCoverageIgnoreStart
305
        if ($this->errorType === 'invalid_client' && array_key_exists('HTTP_AUTHORIZATION', $_SERVER) !== false) {
306
            $authScheme = strpos($_SERVER['HTTP_AUTHORIZATION'], 'Bearer') === 0 ? 'Bearer' : 'Basic';
307
308
            $headers['WWW-Authenticate'] = $authScheme . ' realm="OAuth"';
309
        }
310
        // @codeCoverageIgnoreEnd
311 5
        return $headers;
312
    }
313
314
    /**
315
     * Check if the exception has an associated redirect URI.
316
     *
317
     * Returns whether the exception includes a redirect, since
318
     * getHttpStatusCode() doesn't return a 302 when there's a
319
     * redirect enabled. This helps when you want to override local
320
     * error pages but want to let redirects through.
321
     *
322
     * @return bool
323
     */
324 2
    public function hasRedirect()
325
    {
326 2
        return $this->redirectUri !== null;
327
    }
328
329
    /**
330
     * Returns the HTTP status code to send when the exceptions is output.
331
     *
332
     * @return int
333
     */
334 5
    public function getHttpStatusCode()
335
    {
336 5
        return $this->httpStatusCode;
337
    }
338
339
    /**
340
     * @return null|string
341
     */
342 14
    public function getHint()
343
    {
344 14
        return $this->hint;
345
    }
346
}
347