Completed
Push — master ( d61ccd...74eea6 )
by Alexandre
03:47
created

AuthorizationRequestBuilder::getResponseMode()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 8
nc 6
nop 2
dl 0
loc 16
rs 9.2
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: Alexandre
5
 * Date: 24/05/2018
6
 * Time: 22:06
7
 */
8
9
namespace OAuth2\Endpoints;
10
11
12
use GuzzleHttp\Psr7\Uri;
13
use OAuth2\AuthorizationEndpointResponseTypes\ResponseTypeInterface;
14
use OAuth2\AuthorizationEndpointResponseTypes\ResponseTypeManager;
15
use OAuth2\Exceptions\InvalidAuthorizationRequest;
16
use OAuth2\Exceptions\InvalidRequestMethod;
17
use OAuth2\Exceptions\OAuthException;
18
use OAuth2\ResponseModes\ResponseModeInterface;
19
use OAuth2\ResponseModes\ResponseModeManager;
20
use OAuth2\Roles\ClientTypes\ConfidentialClientInterface;
21
use OAuth2\Roles\ClientTypes\PublicClientInterface;
22
use OAuth2\Roles\ClientTypes\RegisteredClient;
23
use OAuth2\Roles\ResourceOwnerInterface;
24
use OAuth2\ScopePolicy\ScopePolicyManager;
25
use OAuth2\Storages\ClientStorageInterface;
26
use Psr\Http\Message\ServerRequestInterface;
27
28
29
class AuthorizationRequestBuilder
30
{
31
    /**
32
     * @var ClientStorageInterface
33
     */
34
    private $clientStorage;
35
    /**
36
     * @var ResponseTypeManager
37
     */
38
    private $responseTypeManager;
39
    /**
40
     * @var ResponseModeManager
41
     */
42
    private $responseModeManager;
43
    /**
44
     * @var ScopePolicyManager
45
     */
46
    private $scopePolicyManager;
47
48
    public function __construct(ClientStorageInterface $clientStorage,
49
                                ResponseTypeManager $responseTypeManager,
50
                                ResponseModeManager $responseModeManager,
51
                                ScopePolicyManager $scopePolicyManager)
52
    {
53
        $this->clientStorage = $clientStorage;
54
        $this->responseTypeManager = $responseTypeManager;
55
        $this->responseModeManager = $responseModeManager;
56
        $this->scopePolicyManager = $scopePolicyManager;
57
    }
58
59
    /**
60
     * @param ServerRequestInterface $request
61
     * @param ResourceOwnerInterface $resourceOwner
62
     * @return AuthorizationRequest
63
     * @throws InvalidRequestMethod
64
     * @throws OAuthException
65
     * @throws InvalidAuthorizationRequest
66
     */
67
    public function build(ServerRequestInterface $request, ResourceOwnerInterface $resourceOwner)
68
    {
69
        if ($request->getMethod() === 'GET') {
70
            $data = $request->getQueryParams();
71
        } else if ($request->getMethod() === 'POST') {
72
            $data = is_array($request->getParsedBody()) ? $request->getParsedBody() : [];
73
        } else {
74
            throw new InvalidRequestMethod();
75
        }
76
77
        $client = $this->getClient($data['client_id'] ?? null);
78
        $responseType = $this->getResponseType($client, $data['response_type'] ?? null);
79
        $redirectUri = $this->getRedirectUri($client, $responseType, $data['redirect_uri'] ?? null);
80
        $responseMode = $this->getResponseMode($responseType, $data['response_mode'] ?? null);
81
        $state = $requestData['state'] ?? null;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $requestData does not exist. Did you maybe mean $request?
Loading history...
82
83
        try {
84
            $requestedScopes = $this->scopePolicyManager->scopeStringToArray($data['scope'] ?? null);
85
            $scopes = $this->scopePolicyManager->getScopes($client, $requestedScopes);
86
        } catch (OAuthException $e) {
87
            throw new InvalidAuthorizationRequest($e, $redirectUri, $responseMode, $state);
88
        }
89
90
        return new AuthorizationRequest($data, $resourceOwner, $client, $redirectUri, $responseType, $responseMode,
91
            $scopes, $requestedScopes, $state);
92
    }
93
94
    /**
95
     * @param null|string $clientIdentifier
96
     * @return RegisteredClient
97
     * @throws OAuthException
98
     */
99
    protected function getClient(?string $clientIdentifier): RegisteredClient
100
    {
101
        if (empty($clientIdentifier)) {
102
            throw new OAuthException('invalid_request', 'The request is missing the required parameter client_id.',
103
                'https://tools.ietf.org/html/rfc6749#section-4.1');
104
        }
105
106
        if (!($client = $this->clientStorage->get($clientIdentifier))) {
107
            throw new OAuthException('invalid_request', 'The request includes the invalid parameter client_id.',
108
                'https://tools.ietf.org/html/rfc6749#section-4.1');
109
        }
110
111
        return $client;
112
    }
113
114
    protected function isRedirectUriRegistrationRequired(RegisteredClient $client, ResponseTypeInterface $responseType)
115
    {
116
        if ($client instanceof PublicClientInterface ||
117
            ($client instanceof ConfidentialClientInterface && $responseType->isRegistrationOfRedirectUriRequired())) {
118
            return true;
119
        }
120
        return false;
121
    }
122
123
    /**
124
     * @param RegisteredClient $client
125
     * @param ResponseTypeInterface $responseType
126
     * @return array|null
127
     * @throws OAuthException
128
     */
129
    protected function getRegisteredRedirectUris(RegisteredClient $client, ResponseTypeInterface $responseType)
130
    {
131
        $redirectUris = $client->getMetadata()->getRedirectUris();
132
133
        if (empty($redirectUris) && $this->isRedirectUriRegistrationRequired($client, $responseType)) {
134
            throw new OAuthException('invalid_request',
135
                'Clients using flows with redirection MUST register their redirection URI values',
136
                'https://tools.ietf.org/html/rfc7591#section-2.1');
137
        }
138
139
        return $redirectUris;
140
    }
141
142
    /**
143
     * @param RegisteredClient $client
144
     * @param ResponseTypeInterface $responseType
145
     * @param null|string $requestRedirectUri
146
     * @return Uri
147
     * @throws OAuthException
148
     */
149
    protected function getRedirectUri(RegisteredClient $client, ResponseTypeInterface $responseType,
150
                                      ?string $requestRedirectUri = null)
151
    {
152
        $registeredRedirectUris = $this->getRegisteredRedirectUris($client, $responseType);
153
154
        if (!$requestRedirectUri) {
155
            if (count($registeredRedirectUris) != 1) {
156
                throw new OAuthException('invalid_request',
157
                    'The request is missing the required parameter redirect_uri.',
158
                    'https://tools.ietf.org/html/rfc6749#section-4.1');
159
            }
160
161
            $requestRedirectUri = $registeredRedirectUris[0];
162
        } else if (!empty($registeredRedirectUris) && !in_array($requestRedirectUri, $registeredRedirectUris)) {
163
            throw new OAuthException('invalid_request',
164
                'The request is missing the required parameter redirect_uri.',
165
                'https://tools.ietf.org/html/rfc6749#section-4.1');
166
        }
167
168
        try {
169
            $redirectUri = new Uri($requestRedirectUri);
170
            if ($redirectUri->getFragment()) {
171
                throw new \InvalidArgumentException('The endpoint URI must not include a fragment component.');
172
            }
173
        } catch (\InvalidArgumentException $e) {
174
            throw new OAuthException('invalid_request',
175
                'The request includes the malformed parameter redirect_uri. ' . $e->getMessage(),
176
                'https://tools.ietf.org/html/rfc6749#section-4.1');
177
        }
178
179
        return $redirectUri;
180
    }
181
182
    /**
183
     * @param RegisteredClient $client
184
     * @param null|string $requestResponseType
185
     * @return ResponseTypeInterface
186
     * @throws OAuthException
187
     */
188
    protected function getResponseType(RegisteredClient $client, ?string $requestResponseType = null): ResponseTypeInterface
189
    {
190
        if (empty($requestResponseType)) {
191
            throw new OAuthException('invalid_request',
192
                'The request is missing the required parameter response_type.',
193
                'https://tools.ietf.org/html/rfc6749#section-4.1');
194
        }
195
196
        if (!($responseType = $this->responseTypeManager->getResponseType($requestResponseType))) {
197
            throw new OAuthException('invalid_request',
198
                'The request includes the invalid parameter response_type.',
199
                'https://tools.ietf.org/html/rfc6749#section-4.1');
200
        }
201
202
        $supportedResponseTypes = $client->getMetadata()->getResponseTypes() ?: ['code'];
203
        foreach (explode(' ', $requestResponseType) as $type) {
204
            if (!in_array($type, $supportedResponseTypes)) {
205
                throw new OAuthException('unsupported_response_type',
206
                    'The authorization server does not support obtaining an authorization code using this method.',
207
                    'https://tools.ietf.org/html/rfc6749#section-4.1');
208
            }
209
        }
210
211
        return $responseType;
212
    }
213
214
    /**
215
     * @param ResponseTypeInterface $responseType
216
     * @param null|string $requestResponseMode
217
     * @return ResponseModeInterface
218
     * @throws OAuthException
219
     */
220
    protected function getResponseMode(ResponseTypeInterface $responseType, ?string $requestResponseMode = null): ResponseModeInterface
221
    {
222
        $responseModeIdentifier = $responseType->getDefaultResponseMode();
223
        if (!empty($requestResponseMode)) {
224
            $responseModeIdentifier = $requestResponseMode;
225
        }
226
227
        if (!($responseMode = $this->responseModeManager->getResponseMode($responseModeIdentifier))) {
228
            throw new OAuthException('invalid_request', 'response_mode invalid');
229
        }
230
231
        if (in_array($responseModeIdentifier, $responseType->getUnsupportedResponseModes())) {
232
            throw new OAuthException('invalid_request', 'response_mode unsupported');
233
        }
234
235
        return $responseMode;
236
    }
237
}