Passed
Push — master ( cd0cec...4b3abd )
by Alexandre
06:20
created

AuthorizationEndpoint::getMaxAge()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: Alexandre
5
 * Date: 18/02/2018
6
 * Time: 18:14
7
 */
8
9
namespace OAuth2\Extensions\OpenID\Endpoints;
10
11
12
use GuzzleHttp\Psr7\Response;
13
use OAuth2\Exceptions\OAuthException;
14
use OAuth2\Extensions\OpenID\IdTokenManager;
15
use OAuth2\IdTokenInterface;
16
use OAuth2\ResponseModes\ResponseModeManager;
17
use OAuth2\ResponseTypes\ResponseTypeManager;
18
use OAuth2\Extensions\OpenID\Roles\ResourceOwnerInterface;
19
use OAuth2\ScopePolicy\ScopePolicyManager;
20
use OAuth2\Storages\ClientStorageInterface;
21
use Psr\Http\Message\ResponseInterface;
22
use Psr\Http\Message\ServerRequestInterface;
23
24
class AuthorizationEndpoint extends \OAuth2\Endpoints\AuthorizationEndpoint
25
{
26
    const DISPLAY_PAGE = 'page';
27
    const DISPLAY_POPUP = 'popup';
28
    const DISPLAY_TOUCH = 'touch';
29
    const DISPLAY_WAP = 'wap';
30
31
    const PROMPT_NONE = 'none';
32
    const PROMPT_LOGIN = 'login';
33
    const PROMPT_CONSENT = 'consent';
34
    const PROMPT_SELECT_ACCOUNT = 'select_account';
35
    /**
36
     * @var mixed|null
37
     */
38
    private $nonce;
39
    /**
40
     * @var string|null
41
     */
42
    private $display;
43
    /**
44
     * @var string|null
45
     */
46
    private $prompt;
47
    /**
48
     * @var int|null
49
     */
50
    private $maxAge;
51
    /**
52
     * @var string[]|null
53
     */
54
    private $uiLocales;
55
    /**
56
     * @var IdTokenInterface|null
57
     */
58
    private $idTokenHint;
59
    /**
60
     * @var string|null
61
     */
62
    private $loginHint;
63
    /**
64
     * @var string[]|null
65
     */
66
    private $acrValues;
67
    /**
68
     * @var ResourceOwnerInterface
69
     */
70
    private $resourceOwner;
71
    /**
72
     * @var IdTokenManager
73
     */
74
    private $idTokenManager;
75
76
    public function __construct(ResponseTypeManager $responseTypeManager, ResponseModeManager $responseModeManager,
77
                                ScopePolicyManager $scopePolicyManager, ResourceOwnerInterface $resourceOwner,
78
                                ClientStorageInterface $clientStorage, IdTokenManager $idTokenManager)
79
    {
80
        parent::__construct($responseTypeManager, $responseModeManager, $scopePolicyManager, $resourceOwner, $clientStorage);
81
        $this->resourceOwner = $resourceOwner;
82
        $this->idTokenManager = $idTokenManager;
83
    }
84
85
    public function handleRequest(ServerRequestInterface $request): ResponseInterface
86
    {
87
        if ($request->getMethod() === 'GET') {
88
            $requestData = $request->getQueryParams();
89
        } else if ($request->getMethod() === 'POST') {
90
            $requestData = is_array($request->getParsedBody()) ? $request->getParsedBody() : [];
91
        } else {
92
            return new Response(404);
93
        }
94
95
        // Authentication Request Validation
96
        // The Authorization Server MUST validate all the OAuth 2.0 parameters according to the OAuth 2.0 specification.
97
        try {
98
            $this->verifyClient($requestData['client_id'] ?? null);
99
            $this->verifyRedirectUri($requestData['redirect_uri'] ?? null);
100
        } catch (OAuthException $e) {
101
            /**
102
             * If the Authorization Server encounters any error, it MUST return an error response, per Section 3.1.2.6.
103
             */
104
105
            return new Response(400, ['content-type' => 'application/json'], $e->jsonSerialize());
106
        }
107
108
        try {
109
            parent::verifyRequestData($requestData);
110
111
            if (in_array('openid', $this->getScopes())) {
112
                $this->verifyRequestData($requestData);
113
            }
114
115
            $this->getResponseType()->verifyAuthorizationRequest($this, $requestData);
116
117
            // Authorization Server Authenticates End-User
118
            if (!$this->resourceOwner->isAuthenticated(self::PROMPT_LOGIN)) {
0 ignored issues
show
Bug introduced by
self::PROMPT_LOGIN of type string is incompatible with the type boolean expected by parameter $alwaysAuthenticate of OAuth2\Extensions\OpenID...face::isAuthenticated(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

118
            if (!$this->resourceOwner->isAuthenticated(/** @scrutinizer ignore-type */ self::PROMPT_LOGIN)) {
Loading history...
119
                if ($this->prompt == self::PROMPT_NONE) {
120
                    throw new OAuthException('login_required');
121
                }
122
123
                // may throw interaction_required
124
                return $this->resourceOwner->authenticate($this->prompt == self::PROMPT_SELECT_ACCOUNT, $this->loginHint);
125
            }
126
127
            if($this->idTokenHint) {
128
                //check if user associated to this id token is the current user.
129
                var_dump($this->idTokenHint['sub']);die;
0 ignored issues
show
Security Debugging Code introduced by
var_dump($this->idTokenHint['sub']) looks like debug code. Are you sure you do not want to remove it?
Loading history...
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return Psr\Http\Message\ResponseInterface. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
130
                if($this->idTokenHint['sub'] !== $this->resourceOwner->getIdentifier()) {
0 ignored issues
show
Unused Code introduced by
IfNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
131
                    if($this->prompt == self::PROMPT_NONE) {
132
                        throw new OAuthException('invalid_request');
133
                    }
134
                    else {
135
                        throw new OAuthException('login_required');
136
                    }
137
                }
138
            }
139
140
            if ($this->prompt == self::PROMPT_NONE &&
141
                $this->resourceOwner->isInteractionRequiredForConsent($this)) {
142
                throw new OAuthException('interaction_required');
143
            }
144
145
            $consentGiven = $this->resourceOwner->hasGivenConsent($this->getClient(), $this->getScopes(),
146
                $this->prompt == self::PROMPT_CONSENT);
147
148
            if (is_null($consentGiven)) {
149
                if ($this->prompt == self::PROMPT_NONE) {
150
                    throw new OAuthException('consent_required');
151
                }
152
153
                return $this->resourceOwner->obtainConsent($this->getClient(), $this->getScopes());
154
            }
155
156
            if (empty($consentGiven)) {
157
                throw new OAuthException('access_denied', 'The resource owner denied the request.',
158
                    'https://tools.ietf.org/html/rfc6749#section-4.1');
159
            }
160
161
            $responseData = $this->getResponseType()->handleAuthorizationRequest($this, $requestData);
162
        } catch (OAuthException $e) {
163
            /**
164
             * If the Authorization Server encounters any error, it MUST return an error response, per Section 3.1.2.6.
165
             */
166
            $responseData = [
167
                'error' => $e->getError()
168
            ];
169
            if ($e->getErrorDescription()) {
170
                $responseData['error_description'] = $e->getErrorDescription();
171
            }
172
            if ($e->getErrorUri()) {
173
                $responseData['error_uri'] = $e->getErrorUri();
174
            }
175
        }
176
177
        if (!empty($this->getState())) {
178
            $responseData['state'] = $this->getState();
179
        }
180
181
        return $this->getResponseMode()->buildResponse($this, $requestData, $responseData);
182
    }
183
184
185
    /**
186
     * @param array $requestData
187
     * @throws OAuthException
188
     */
189
    public function verifyRequestData(array $requestData)
190
    {
191
        $this->nonce = empty($requestData['state']) ? null : $requestData['state'];
192
        $this->display = empty($requestData['display']) ? null : $requestData['display'];
193
        $this->prompt = empty($requestData['prompt']) ? null : $requestData['prompt'];
194
        $this->maxAge = empty($requestData['max_age']) ? null : $requestData['max_age'];
195
        $this->uiLocales = empty($requestData['ui_locales']) ? null : explode(' ', $requestData['ui_locales']);
196
197
        if(!empty($requestData['id_token_hint'])) {
198
            try {
199
                $this->idTokenHint = $this->idTokenManager->decode($requestData['id_token_hint']);
200
            } catch (\Exception $exception) {
201
                throw new OAuthException('invalid_request', 'Failed to decode id_token_hint : '.$exception->getMessage());
202
            }
203
        }
204
205
        $this->loginHint = empty($requestData['login_hint']) ? null : $requestData['login_hint'];
206
        $this->acrValues = empty($requestData['acr_values']) ? null : explode(' ', $requestData['acr_values']);
207
    }
208
209
    /**
210
     * @return mixed|null
211
     */
212
    public function getNonce(): ?mixed
0 ignored issues
show
Bug introduced by
The type OAuth2\Extensions\OpenID\Endpoints\mixed was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
213
    {
214
        return $this->nonce;
215
    }
216
217
    /**
218
     * @return null|string
219
     */
220
    public function getDisplay(): ?string
221
    {
222
        return $this->display;
223
    }
224
225
    /**
226
     * @return null|string
227
     */
228
    public function getPrompt(): ?string
229
    {
230
        return $this->prompt;
231
    }
232
233
    /**
234
     * @return int|null
235
     */
236
    public function getMaxAge(): ?int
237
    {
238
        return $this->maxAge;
239
    }
240
241
    /**
242
     * @return null|string[]
243
     */
244
    public function getUiLocales(): ?array
245
    {
246
        return $this->uiLocales;
247
    }
248
249
    /**
250
     * @return null|IdTokenInterface
251
     */
252
    public function getIdTokenHint(): ?IdTokenInterface
253
    {
254
        return $this->idTokenHint;
255
    }
256
257
    /**
258
     * @return null|string
259
     */
260
    public function getLoginHint(): ?string
261
    {
262
        return $this->loginHint;
263
    }
264
265
    /**
266
     * @return null|string[]
267
     */
268
    public function getAcrValues(): ?array
269
    {
270
        return $this->acrValues;
271
    }
272
}