Completed
Pull Request — master (#997)
by TEst
02:35 queued 48s
created

OAuthServerException   A

Complexity

Total Complexity 29

Size/Duplication

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