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

OAuthServerException::getHttpHeaders()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 23
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 4

Importance

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