Passed
Push — master ( 03ea2f...d61ccd )
by Alexandre
03:09
created

AuthorizationRequestBuilder   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 185
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 185
rs 10
c 0
b 0
f 0
wmc 28

6 Methods

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