Completed
Push — master ( 6e52f0...d9a404 )
by Alexandre
02:29
created

AuthorizationEndpoint::verify()   D

Complexity

Conditions 23
Paths 71

Size

Total Lines 118
Code Lines 76

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 38
CRAP Score 63.3801

Importance

Changes 0
Metric Value
dl 0
loc 118
c 0
b 0
f 0
ccs 38
cts 66
cp 0.5758
rs 4.6303
cc 23
eloc 76
nc 71
nop 1
crap 63.3801

3 Methods

Rating   Name   Duplication   Size   Complexity  
A AuthorizationEndpoint::getResponseMode() 0 3 1
A AuthorizationEndpoint::getResponseType() 0 3 1
B AuthorizationEndpoint::verifyRequestData() 0 22 5

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: Alexandre
5
 * Date: 18/02/2018
6
 * Time: 18:14
7
 */
8
9
namespace OAuth2\Endpoints;
10
11
12
use GuzzleHttp\Psr7\Response;
13
use OAuth2\Exceptions\OAuthException;
14
use OAuth2\Flows\AuthorizationCodeFlow;
15
use OAuth2\Flows\FlowInterface;
16
use OAuth2\Flows\FlowManager;
17
use OAuth2\ResponseModes\ResponseModeInterface;
18
use OAuth2\ResponseModes\ResponseModeManager;
19
use OAuth2\ResponseTypes\ResponseTypeInterface;
20
use OAuth2\ResponseTypes\ResponseTypeManager;
21
use Psr\Http\Message\ResponseInterface;
22
use Psr\Http\Message\ServerRequestInterface;
23
24
class AuthorizationEndpoint implements EndpointInterface
25
{
26
    /**
27
     * @var ResponseTypeManager
28
     */
29
    protected $responseTypeManager;
30
    /**
31
     * @var ResponseTypeInterface|null
32
     */
33
    private $responseType;
34
    /**
35
     * @var ResponseModeManager
36
     */
37
    protected $responseModeManager;
38
    /**
39
     * @var ResponseModeInterface|null
40
     */
41 4
    private $responseMode;
42
43
    public function __construct(ResponseTypeManager $responseTypeManager,
44
                                ResponseModeManager $responseModeManager)
45
    {
46
        $this->responseTypeManager = $responseTypeManager;
47 4
        $this->responseModeManager = $responseModeManager;
48 4
    }
49 1
50
    function handleRequest(ServerRequestInterface $request): ResponseInterface
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
51
    {
52
        $requestData = $request->getMethod() == 'GET' ? $request->getQueryParams() : $request->getParsedBody();
53
54
        try {
55
            /**
56
             * The Authorization Server MUST validate all the OAuth 2.0 parameters according to the OAuth 2.0 specification
57
             */
58
            $this->verifyRequestData($requestData);
0 ignored issues
show
Bug introduced by
It seems like $requestData can also be of type object and null; however, parameter $requestData of OAuth2\Endpoints\Authori...nt::verifyRequestData() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

58
            $this->verifyRequestData(/** @scrutinizer ignore-type */ $requestData);
Loading history...
59
            $responseData = $this->getResponseType()->handle($requestData);
60 3
            return $this->getResponseMode()->buildResponse($requestData, $responseData);
61
62 3
            // oauth :
63
            // response_type required
64
            // client_id required
65
            // redirect_uri
66 3
            // scope
67
            // state
68
69
            // openid :
70
            // response_mode
71
            // nonce
72 3
            // display
73 3
            // prompt
74
            // max_age
75
            // ui_locales
76
            // id_token_hint
77
            // login_hint
78
            // acr_values
79 3
80 3
81
            /**
82 3
             * Verify that a scope parameter is present and contains the openid scope value.
83
             * (If no openid scope value is present, the request may still be a valid OAuth 2.0 request, but is not an OpenID Connect request.)
84
             */
85
86
            /**
87
             * If the sub (subject) Claim is requested with a specific value for the ID Token,
88
             * the Authorization Server MUST only send a positive response
89
             * if the End-User identified by that sub value has an active session with the Authorization Server
90
             * or has been Authenticated as a result of the request.
91 3
             * The Authorization Server MUST NOT reply with an ID Token or Access Token for a different user,
92
             * even if they have an active session with the Authorization Server.
93
             * Such a request can be made either using an id_token_hint parameter
94
             * or by requesting a specific Claim Value as described in Section 5.5.1,
95 3
             * if the claims parameter is supported by the implementation.
96 2
             */
97 2
98
            /**
99
             * If the Authorization Server encounters any error, it MUST return an error response, per Section 3.1.2.6.
100 1
             */
101
102
            /**
103 3
             * The Authorization Server MUST verify that all the REQUIRED parameters are present and their usage conforms to this specification.
104
             */
105
106
            /**
107
             * Authorization Server Authenticates the End-User.
108
             *
109
             * If the request is valid, the Authorization Server attempts to Authenticate the End-User
110
             * or determines whether the End-User is Authenticated, depending upon the request parameter values used.
111
             * The methods used by the Authorization Server to Authenticate the End-User
112 4
             * (e.g. username and password, session cookies, etc.) are beyond the scope of this specification.
113
             * An Authentication user interface MAY be displayed by the Authorization Server,
114 4
             * depending upon the request parameter values used and the authentication methods used.
115
             *
116 4
             * The Authorization Server MUST attempt to Authenticate the End-User in the following cases:
117
             *
118
             * The End-User is not already Authenticated.
119
             * The Authentication Request contains the prompt parameter with the value login.
120
             * In this case, the Authorization Server MUST reauthenticate the End-User
121
             * even if the End-User is already authenticated.
122
             *
123
             * The Authorization Server MUST NOT interact with the End-User in the following case:
124 4
             *
125
             * The Authentication Request contains the prompt parameter with the value none.
126
             * In this case, the Authorization Server MUST return an error if an End-User is not already Authenticated
127
             * or could not be silently Authenticated.
128
             *
129
             * When interacting with the End-User, the Authorization Server MUST employ appropriate measures
130
             * against Cross-Site Request Forgery and Clickjacking as, described in Sections 10.12 and 10.13 of OAuth 2.0 [RFC6749].
131
             */
132
133
            /**
134
             * Authorization Server obtains End-User Consent/Authorization.
135 4
             *
136
             * Once the End-User is authenticated, the Authorization Server MUST obtain an authorization decision
137 4
             * before releasing information to the Relying Party.
138 4
             * When permitted by the request parameters used,
139
             * this MAY be done through an interactive dialogue with the End-User
140
             * that makes it clear what is being consented to or by establishing consent
141
             * via conditions for processing the request or other means (for example, via previous administrative consent).
142
             * Sections 2 and 5.3 describe information release mechanisms.
143
             */
144
145 4
            /**
146
             * Authorization Server sends the End-User back to the Client with an Authorization Code.
147
             *
148
             * An Authentication Response is an OAuth 2.0 Authorization Response message
149
             * returned from the OP's Authorization Endpoint in response to the Authorization Request message sent by the RP.
150
             *
151
             * When using the Authorization Code Flow, the Authorization Response MUST return the parameters
152
             * defined in Section 4.1.2 of OAuth 2.0 [RFC6749] by adding them as query parameters to the redirect_uri
153
             * specified in the Authorization Request using the application/x-www-form-urlencoded format,
154 4
             * unless a different Response Mode was specified.
155
             */
156
            $flow = $this->getFlow($requestData['response_type']);
0 ignored issues
show
Unused Code introduced by
$flow = $this->getFlow($...tData['response_type']) 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...
157
            $responseData = $flow->handle($requestData);
158
            return $this->buildResponse($flow, $requestData, $responseData);
159
        } catch (OAuthException $e) {
160
            /**
161
             * If the Authorization Server encounters any error, it MUST return an error response, per Section 3.1.2.6.
162
             */
163
164 4
            return new Response(400, ['content-type' => 'application/json'], $e->jsonSerialize());
165
        }
166
    }
167
168
169
    /**
170
     * @param array $requestData
171 4
     * @throws OAuthException
172 4
     */
173
    protected function verifyRequestData(array $requestData)
174
    {
175
        // response_type required
176
        if (!($requestData['response_type'] ?? null)) {
177
            throw new OAuthException('invalid_request', 'response_type required');
178
        }
179 4
180 4
        if (!($responseType = $this->responseTypeManager->getResponseType($requestData['response_type']))) {
181 4
            throw new OAuthException('invalid_request', 'response_type invalid');
182 4
        }
183 4
        $this->responseType = $responseType;
184 4
185 4
186 4
        $responseModeIdentifier = $requestData['response_mode'] ?? $this->getResponseType()->getDefaultResponseMode();
187 1
        if(!($responseMode = $this->responseModeManager->getResponseMode($responseModeIdentifier))) {
188 1
            throw new OAuthException('invalid_request', 'response_mode invalid');
189 1
        }
190
191
        if(in_array($responseModeIdentifier, $this->getResponseType()->getUnsupportedResponseModes())) {
192 3
            throw new OAuthException('invalid_request', 'response_mode unsupported');
193 3
        }
194 3
        $this->responseMode = $responseMode;
195 3
        // client_id required
196
        // redirect_uri
197
        // scope
198
        // state
199
200
    }
201
202
203 3
    /**
204 3
     * @return null|ResponseTypeInterface
205
     */
206 3
    public function getResponseType(): ?ResponseTypeInterface
207 1
    {
208
        return $this->responseType;
209
    }
210 3
211 3
    /**
212
     * @return null|ResponseModeInterface
213
     */
214
    public function getResponseMode(): ?ResponseModeInterface
215 3
    {
216
        return $this->responseMode;
217
    }
218
}