Completed
Pull Request — master (#902)
by Andrew
04:57
created

OAuthServerException::setPayload()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
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
14
class OAuthServerException extends \Exception
15
{
16
    /**
17
     * @var int
18
     */
19
    private $httpStatusCode;
20
21
    /**
22
     * @var string
23
     */
24
    private $errorType;
25
26
    /**
27
     * @var null|string
28
     */
29
    private $hint;
30
31
    /**
32
     * @var null|string
33
     */
34
    private $redirectUri;
35
36
    /**
37
     * @var array
38
     */
39
    private $payload;
40
41
    /**
42
     * Throw a new exception.
43
     *
44
     * @param string      $message        Error message
45
     * @param int         $code           Error code
46
     * @param string      $errorType      Error type
47
     * @param int         $httpStatusCode HTTP status code to send (default = 400)
48
     * @param null|string $hint           A helper hint
49
     * @param null|string $redirectUri    A HTTP URI to redirect the user back to
50
     */
51 65
    public function __construct($message, $code, $errorType, $httpStatusCode = 400, $hint = null, $redirectUri = null)
52
    {
53 65
        parent::__construct($message, $code);
54 65
        $this->httpStatusCode = $httpStatusCode;
55 65
        $this->errorType = $errorType;
56 65
        $this->hint = $hint;
57 65
        $this->redirectUri = $redirectUri;
58 65
        $this->payload = [
59 65
            'error'   => $errorType,
60 65
            'message' => $message,
61
        ];
62 65
        if ($hint !== null) {
63 42
            $this->payload['hint'] = $hint;
64
        }
65 65
    }
66
67
    /**
68
     * Returns the current payload.
69
     *
70
     * @return array
71
     */
72 5
    public function getPayload()
73
    {
74 5
        return $this->payload;
75
    }
76
77
    /**
78
     * Updates the current payload.
79
     *
80
     * @param array $payload
81
     */
82
    public function setPayload(array $payload)
83
    {
84
        $this->payload = $payload;
85
    }
86
87
    /**
88
     * Unsupported grant type error.
89
     *
90
     * @return static
91
     */
92 2
    public static function unsupportedGrantType()
93
    {
94 2
        $errorMessage = 'The authorization grant type is not supported by the authorization server.';
95 2
        $hint = 'Check that all required parameters have been provided';
96
97 2
        return new static($errorMessage, 2, 'unsupported_grant_type', 400, $hint);
98
    }
99
100
    /**
101
     * Invalid request error.
102
     *
103
     * @param string      $parameter The invalid parameter
104
     * @param null|string $hint
105
     *
106
     * @return static
107
     */
108 22
    public static function invalidRequest($parameter, $hint = null)
109
    {
110
        $errorMessage = 'The request is missing a required parameter, includes an invalid parameter value, ' .
111 22
            'includes a parameter more than once, or is otherwise malformed.';
112 22
        $hint = ($hint === null) ? sprintf('Check the `%s` parameter', $parameter) : $hint;
113
114 22
        return new static($errorMessage, 3, 'invalid_request', 400, $hint);
115
    }
116
117
    /**
118
     * Invalid client error.
119
     *
120
     * @return static
121
     */
122 13
    public static function invalidClient()
123
    {
124 13
        $errorMessage = 'Client authentication failed';
125
126 13
        return new static($errorMessage, 4, 'invalid_client', 401);
127
    }
128
129
    /**
130
     * Invalid scope error.
131
     *
132
     * @param string      $scope       The bad scope
133
     * @param null|string $redirectUri A HTTP URI to redirect the user back to
134
     *
135
     * @return static
136
     */
137 4
    public static function invalidScope($scope, $redirectUri = null)
138
    {
139 4
        $errorMessage = 'The requested scope is invalid, unknown, or malformed';
140
141 4
        if (empty($scope)) {
142
            $hint = 'Specify a scope in the request or set a default scope';
143
        } else {
144 4
            $hint = sprintf(
145 4
                'Check the `%s` scope',
146 4
                htmlspecialchars($scope, ENT_QUOTES, 'UTF-8', false)
147
            );
148
        }
149
150 4
        return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri);
151
    }
152
153
    /**
154
     * Invalid credentials error.
155
     *
156
     * @return static
157
     */
158 1
    public static function invalidCredentials()
159
    {
160 1
        return new static('The user credentials were incorrect.', 6, 'invalid_credentials', 401);
161
    }
162
163
    /**
164
     * Server error.
165
     *
166
     * @param string $hint
167
     *
168
     * @return static
169
     *
170
     * @codeCoverageIgnore
171
     */
172
    public static function serverError($hint)
173
    {
174
        return new static(
175
            'The authorization server encountered an unexpected condition which prevented it from fulfilling'
176
            . ' the request: ' . $hint,
177
            7,
178
            'server_error',
179
            500
180
        );
181
    }
182
183
    /**
184
     * Invalid refresh token.
185
     *
186
     * @param null|string $hint
187
     *
188
     * @return static
189
     */
190 4
    public static function invalidRefreshToken($hint = null)
191
    {
192 4
        return new static('The refresh token is invalid.', 8, 'invalid_request', 401, $hint);
193
    }
194
195
    /**
196
     * Access denied.
197
     *
198
     * @param null|string $hint
199
     * @param null|string $redirectUri
200
     *
201
     * @return static
202
     */
203 9
    public static function accessDenied($hint = null, $redirectUri = null)
204
    {
205 9
        return new static(
206 9
            'The resource owner or authorization server denied the request.',
207 9
            9,
208 9
            'access_denied',
209 9
            401,
210 9
            $hint,
211 9
            $redirectUri
212
        );
213
    }
214
215
    /**
216
     * Invalid grant.
217
     *
218
     * @param string $hint
219
     *
220
     * @return static
221
     */
222 1
    public static function invalidGrant($hint = '')
223
    {
224 1
        return new static(
225
            'The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token '
226
                . 'is invalid, expired, revoked, does not match the redirection URI used in the authorization request, '
227 1
                . 'or was issued to another client.',
228 1
            10,
229 1
            'invalid_grant',
230 1
            400,
231 1
            $hint
232
        );
233
    }
234
235
    /**
236
     * @return string
237
     */
238 2
    public function getErrorType()
239
    {
240 2
        return $this->errorType;
241
    }
242
243
    /**
244
     * Generate a HTTP response.
245
     *
246
     * @param ResponseInterface $response
247
     * @param bool              $useFragment True if errors should be in the URI fragment instead of query string
248
     * @param int               $jsonOptions options passed to json_encode
249
     *
250
     * @return ResponseInterface
251
     */
252 5
    public function generateHttpResponse(ResponseInterface $response, $useFragment = false, $jsonOptions = 0)
253
    {
254 5
        $headers = $this->getHttpHeaders();
255
256 5
        $payload = $this->getPayload();
257
258 5
        if ($this->redirectUri !== null) {
259 2
            if ($useFragment === true) {
260 1
                $this->redirectUri .= (strstr($this->redirectUri, '#') === false) ? '#' : '&';
261
            } else {
262 1
                $this->redirectUri .= (strstr($this->redirectUri, '?') === false) ? '?' : '&';
263
            }
264
265 2
            return $response->withStatus(302)->withHeader('Location', $this->redirectUri . http_build_query($payload));
266
        }
267
268 3
        foreach ($headers as $header => $content) {
269 3
            $response = $response->withHeader($header, $content);
270
        }
271
272 3
        $response->getBody()->write(json_encode($payload, $jsonOptions));
273
274 3
        return $response->withStatus($this->getHttpStatusCode());
275
    }
276
277
    /**
278
     * Get all headers that have to be send with the error response.
279
     *
280
     * @return array Array with header values
281
     */
282 5
    public function getHttpHeaders()
0 ignored issues
show
Coding Style introduced by
getHttpHeaders uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
283
    {
284
        $headers = [
285 5
            'Content-type' => 'application/json',
286
        ];
287
288
        // Add "WWW-Authenticate" header
289
        //
290
        // RFC 6749, section 5.2.:
291
        // "If the client attempted to authenticate via the 'Authorization'
292
        // request header field, the authorization server MUST
293
        // respond with an HTTP 401 (Unauthorized) status code and
294
        // include the "WWW-Authenticate" response header field
295
        // matching the authentication scheme used by the client.
296
        // @codeCoverageIgnoreStart
297
        if ($this->errorType === 'invalid_client' && array_key_exists('HTTP_AUTHORIZATION', $_SERVER) !== false) {
298
           $headers['WWW-Authenticate'] = $authScheme . ' realm="OAuth"';
0 ignored issues
show
Bug introduced by
The variable $authScheme does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
299
        }
300
        // @codeCoverageIgnoreEnd
301 5
        return $headers;
302
    }
303
304
    /**
305
     * Returns the HTTP status code to send when the exceptions is output.
306
     *
307
     * @return int
308
     */
309 5
    public function getHttpStatusCode()
310
    {
311 5
        return $this->httpStatusCode;
312
    }
313
314
    /**
315
     * @return null|string
316
     */
317 14
    public function getHint()
318
    {
319 14
        return $this->hint;
320
    }
321
}
322