TokenEndpoint::getClient()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: Alexandre
5
 * Date: 08/03/2018
6
 * Time: 22:22
7
 */
8
9
namespace OAuth2\Endpoints;
10
11
12
use GuzzleHttp\Psr7\Response;
13
use OAuth2\ClientAuthentication\ClientAuthenticationMethodManager;
14
use OAuth2\Exceptions\OAuthException;
15
use OAuth2\AuthorizationGrantTypes\GrantTypeInterface;
16
use OAuth2\AuthorizationGrantTypes\GrantTypeManager;
17
use OAuth2\Roles\ClientTypes\RegisteredClient;
18
use Psr\Http\Message\ResponseInterface;
19
use Psr\Http\Message\ServerRequestInterface;
20
21
/**
22
 * Class TokenEndpoint
23
 * @package OAuth2\Endpoints
24
 *
25
 * @see https://tools.ietf.org/html/rfc6749#section-3.2
26
 * The token endpoint is used by the client to obtain an access token by
27
 * presenting its authorization grant or refresh token.  The token
28
 * endpoint is used with every authorization grant except for the
29
 * implicit grant type (since an access token is issued directly).
30
 *
31
 * The means through which the client obtains the location of the token
32
 * endpoint are beyond the scope of this specification, but the location
33
 * is typically provided in the service documentation.
34
 *
35
 * The endpoint URI MAY include an "application/x-www-form-urlencoded"
36
 * formatted (per Appendix B) query component ([RFC3986] Section 3.4),
37
 * which MUST be retained when adding additional query parameters.  The
38
 * endpoint URI MUST NOT include a fragment component.
39
 *
40
 * Since requests to the token endpoint result in the transmission of
41
 * clear-text credentials (in the HTTP request and response), the
42
 * authorization server MUST require the use of TLS as described in
43
 * Section 1.6 when sending requests to the token endpoint.
44
 *
45
 * The client MUST use the HTTP "POST" method when making access token
46
 * requests.
47
 *
48
 * Parameters sent without a value MUST be treated as if they were
49
 * omitted from the request.  The authorization server MUST ignore
50
 * unrecognized request parameters.  Request and response parameters
51
 * MUST NOT be included more than once.
52
 */
53
class TokenEndpoint implements EndpointInterface
54
{
55
    /**
56
     * @var GrantTypeManager
57
     */
58
    private $grantTypeManager;
59
    /**
60
     * @var ClientAuthenticationMethodManager
61
     */
62
    private $clientAuthenticationMethodManager;
63
64
    /**
65
     * @var RegisteredClient|null
66
     */
67
    protected $client;
68
    /**
69
     * @var GrantTypeInterface|null
70
     */
71
    protected $grantType;
72
73
    public function __construct(GrantTypeManager $grantTypeManager,
74
                                ClientAuthenticationMethodManager $clientAuthenticationMethodManager)
75
    {
76
        $this->grantTypeManager = $grantTypeManager;
77
        $this->clientAuthenticationMethodManager = $clientAuthenticationMethodManager;
78
    }
79
80
    /**
81
     * @param ServerRequestInterface $request
82
     * @return ResponseInterface
83
     *
84
     * @see https://tools.ietf.org/html/rfc6749#section-4.1.3
85
     * The client makes a request to the token endpoint by sending the
86
     * following parameters using the "application/x-www-form-urlencoded"
87
     * format per Appendix B with a character encoding of UTF-8 in the HTTP
88
     * request entity-body:
89
     *
90
     * grant_type
91
     * REQUIRED.  Value MUST be set to "authorization_code".
92
     *
93
     * code
94
     * REQUIRED.  The authorization code received from the
95
     * authorization server.
96
     *
97
     * redirect_uri
98
     * REQUIRED, if the "redirect_uri" parameter was included in the
99
     * authorization request as described in Section 4.1.1, and their
100
     * values MUST be identical.
101
     *
102
     * client_id
103
     * REQUIRED, if the client is not authenticating with the
104
     * authorization server as described in Section 3.2.1.
105
     *
106
     * If the client type is confidential or the client was issued client
107
     * credentials (or assigned other authentication requirements), the
108
     * client MUST authenticate with the authorization server as described
109
     * in Section 3.2.1.
110
     *
111
     *  The authorization server MUST:
112
     *
113
     * o  require client authentication for confidential clients or for any
114
     * client that was issued client credentials (or with other
115
     * authentication requirements),
116
     *
117
     * o  authenticate the client if client authentication is included,
118
     *
119
     * o  ensure that the authorization code was issued to the authenticated
120
     * confidential client, or if the client is public, ensure that the
121
     * code was issued to "client_id" in the request,
122
     *
123
     * o  verify that the authorization code is valid, and
124
     *
125
     * o  ensure that the "redirect_uri" parameter is present if the
126
     * "redirect_uri" parameter was included in the initial authorization
127
     * request as described in Section 4.1.1, and if included ensure that
128
     * their values are identical.
129
     */
130
    public function handle(ServerRequestInterface $request): ResponseInterface
131
    {
132
        if ($request->getMethod() === 'POST') {
133
            $requestData = $request->getParsedBody();
134
        } else {
135
            return new Response(405);
136
        }
137
138
        try {
139
            // Authentication Request Validation
140
            // The Authorization Server MUST validate all the OAuth 2.0 parameters according to the OAuth 2.0 specification.
141
            $this->verifyRequestData($request, $requestData);
142
143
            $responseData = $this->getGrantType()->handleAccessTokenRequest($this, $requestData);
144
145
        } catch (OAuthException $e) {
146
            /**
147
             * If the Authorization Server encounters any error, it MUST return an error response, per Section 5.2
148
             */
149
            $status = 400;
150
            $headers = ['Content-Type' => 'application/json'];
151
            if ($e->getError() === 'invalid_client') {
152
                $status = 401;
153
                if ($request->hasHeader('Authorization')) {
154
                    $headers['WWW-Authenticate'] = 'Basic';
155
                }
156
            }
157
            return new Response($status, $headers, $e->jsonSerialize());
158
        }
159
160
        return new Response(200, [
161
            'Content-Type' => 'application/json',
162
            'Cache-Control' => 'no-store',
163
            'Pragma' => 'no-cache'
164
        ], json_encode($responseData));
165
    }
166
167
    /**
168
     * @param ServerRequestInterface $request
169
     * @param array $requestData
170
     * @throws OAuthException
171
     */
172
    protected function verifyRequestData(ServerRequestInterface $request, array $requestData)
173
    {
174
        if (empty($requestData['grant_type'])) {
175
            throw new OAuthException('invalid_request', 'The request is missing the required parameter grant_type.',
176
                'https://tools.ietf.org/html/rfc6749#section-4.1');
177
        }
178
179
        if (!($grantType = $this->grantTypeManager->getGrantType($requestData['grant_type']))) {
180
            throw new OAuthException('unsupported_grant_type',
181
                'The authorization grant type is not supported by the authorization server',
182
                'https://tools.ietf.org/html/rfc6749#section-4.1');
183
        }
184
185
        $this->grantType = $grantType;
186
187
        $this->verifyClient($request, $requestData);
188
189
        $supportedGrantTypes = $this->client->getMetadata()->getGrantTypes() ?: ['authorization_code'];
190
        if (!in_array($requestData['grant_type'], $supportedGrantTypes)) {
191
            throw new OAuthException('unauthorized_client',
192
                'The authenticated client is not authorized to use this authorization grant type.',
193
                'https://tools.ietf.org/html/rfc6749#section-4.1');
194
        }
195
196
    }
197
198
    /**
199
     * @param ServerRequestInterface $request
200
     * @param array $requestData
201
     * @throws OAuthException
202
     */
203
    protected function verifyClient(ServerRequestInterface $request, array $requestData)
204
    {
205
        $this->client = $this->clientAuthenticationMethodManager->authenticate($request, $requestData);
206
        $this->getGrantType();
207
    }
208
209
    /**
210
     * @return null|GrantTypeInterface
211
     */
212
    public function getGrantType()
213
    {
214
        return $this->grantType;
215
    }
216
217
    /**
218
     * @return null|RegisteredClient
219
     */
220
    public function getClient(): ?RegisteredClient
221
    {
222
        return $this->client;
223
    }
224
}