Failed Conditions
Push — ng ( ada769...ebc492 )
by Florent
08:29 queued 40s
created

TokenEndpoint::createResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2018 Spomky-Labs
9
 *
10
 * This software may be modified and distributed under the terms
11
 * of the MIT license.  See the LICENSE file for details.
12
 */
13
14
namespace OAuth2Framework\Component\Server\TokenEndpoint;
15
16
use Http\Message\ResponseFactory;
17
use Interop\Http\Server\RequestHandlerInterface;
18
use Interop\Http\Server\MiddlewareInterface;
19
use OAuth2Framework\Component\Server\TokenEndpoint\Processor\ProcessorManager;
20
use OAuth2Framework\Component\Server\Core\AccessToken\AccessToken;
21
use OAuth2Framework\Component\Server\Core\AccessToken\AccessTokenRepository;
22
use OAuth2Framework\Component\Server\Core\Client\ClientId;
23
use OAuth2Framework\Component\Server\Core\Client\ClientRepository;
24
use OAuth2Framework\Component\Server\RefreshTokenGrant\RefreshTokenRepository;
25
use OAuth2Framework\Component\Server\Core\ResourceOwner\ResourceOwnerId;
26
use OAuth2Framework\Component\Server\Core\ResourceOwner\ResourceOwner;
27
use OAuth2Framework\Component\Server\Core\UserAccount\UserAccountId;
28
use OAuth2Framework\Component\Server\Core\UserAccount\UserAccountRepository;
29
use OAuth2Framework\Component\Server\Core\Response\OAuth2Exception;
30
use Psr\Http\Message\ResponseInterface;
31
use Psr\Http\Message\ServerRequestInterface;
32
33
final class TokenEndpoint implements MiddlewareInterface
34
{
35
    /**
36
     * @var TokenEndpointExtensionManager
37
     */
38
    private $tokenEndpointExtensionManager;
39
40
    /**
41
     * @var ProcessorManager
42
     */
43
    private $processorManager;
44
45
    /**
46
     * @var ClientRepository
47
     */
48
    private $clientRepository;
49
50
    /**
51
     * @var UserAccountRepository
52
     */
53
    private $userAccountRepository;
54
55
    /**
56
     * @var ResponseFactory
57
     */
58
    private $responseFactory;
59
60
    /**
61
     * @var AccessTokenRepository
62
     */
63
    private $accessTokenRepository;
64
65
    /**
66
     * @var null|RefreshTokenRepository
67
     */
68
    private $refreshTokenRepository;
69
70
    /**
71
     * TokenEndpoint constructor.
72
     *
73
     * @param ProcessorManager              $processorManager
74
     * @param ClientRepository              $clientRepository
75
     * @param UserAccountRepository         $userAccountRepository
76
     * @param TokenEndpointExtensionManager $tokenEndpointExtensionManager
77
     * @param ResponseFactory               $responseFactory
78
     * @param AccessTokenRepository         $accessTokenRepository
79
     * @param RefreshTokenRepository|null   $refreshTokenRepository
80
     */
81
    public function __construct(ProcessorManager $processorManager, ClientRepository $clientRepository, UserAccountRepository $userAccountRepository, TokenEndpointExtensionManager $tokenEndpointExtensionManager, ResponseFactory $responseFactory, AccessTokenRepository $accessTokenRepository, ?RefreshTokenRepository $refreshTokenRepository)
82
    {
83
        $this->processorManager = $processorManager;
84
        $this->clientRepository = $clientRepository;
85
        $this->userAccountRepository = $userAccountRepository;
86
        $this->tokenEndpointExtensionManager = $tokenEndpointExtensionManager;
87
        $this->responseFactory = $responseFactory;
88
        $this->accessTokenRepository = $accessTokenRepository;
89
        $this->refreshTokenRepository = $refreshTokenRepository;
90
    }
91
92
    /**
93
     * {@inheritdoc}
94
     */
95
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
96
    {
97
        // We prepare the Grant Type Data.
98
        // The client may be null (authenticated by other means).
99
        $grantTypeData = GrantTypeData::create($request->getAttribute('client'));
100
101
        // We retrieve the Grant Type.
102
        // This middleware must be behind the GrantTypeMiddleware
103
        $grantType = $request->getAttribute('grant_type');
104
        if (!$grantType instanceof GrantType) {
105
            throw new OAuth2Exception(500, OAuth2Exception::ERROR_INTERNAL, null);
106
        }
107
108
        // We check that the request has all parameters needed for the selected grant type
109
        $grantType->checkTokenRequest($request);
110
111
        // The grant type prepare the token response
112
        // The grant type data should be updated accordingly
113
        $grantTypeData = $grantType->prepareTokenResponse($request, $grantTypeData);
114
115
        // At this stage, the client should be authenticated
116
        // If not, we stop the authorization grant
117
        if (null === $grantTypeData->getClient() || $grantTypeData->getClient()->isDeleted()) {
118
            throw new OAuth2Exception(401, OAuth2Exception::ERROR_INVALID_CLIENT, 'Client authentication failed.');
119
        }
120
121
        // This occurs now because the client may be found during the preparation process
122
        if (!$grantTypeData->getClient()->isGrantTypeAllowed($grantType->getGrantType())) {
123
            throw new OAuth2Exception(400, OAuth2Exception::ERROR_UNAUTHORIZED_CLIENT, sprintf('The grant type "%s" is unauthorized for this client.', $grantType));
124
        }
125
126
        // Should be token extension pre-processing
127
        $grantTypeData = $this->processorManager->handle($request, $grantTypeData, $grantType);
128
129
        // Everything is fine so we can issue the access token
130
        $accessToken = $this->issueAccessToken($grantTypeData);
131
        $resourceOwner = $this->getResourceOwner($grantTypeData->getResourceOwnerId());
132
        $data = $this->tokenEndpointExtensionManager->process($grantTypeData->getClient(), $resourceOwner, $accessToken);
133
134
        return $this->createResponse($data);
135
    }
136
137
    /**
138
     * @param array $data
139
     *
140
     * @return ResponseInterface
141
     */
142
    private function createResponse(array $data): ResponseInterface
143
    {
144
        $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Cache-Control' => 'no-cache, no-store, max-age=0, must-revalidate, private', 'Pragma' => 'no-cache'];
145
        $response = $this->responseFactory->createResponse(200, null, $headers);
146
        $response->getBody()->write(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
147
148
        return $response;
149
    }
150
151
    /**
152
     * @param GrantTypeData $grantTypeData
153
     *
154
     * @return AccessToken
155
     */
156
    private function issueAccessToken(GrantTypeData $grantTypeData): AccessToken
157
    {
158
        $parameters = $grantTypeData->getParameters();
159
        if (in_array('offline_access', $grantTypeData->getScopes()) && null !== $this->refreshTokenRepository) {
160
            $refreshToken = $this->refreshTokenRepository->create(
0 ignored issues
show
Bug introduced by
The method create() does not seem to exist on object<OAuth2Framework\C...RefreshTokenRepository>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
161
                $grantTypeData->getClient()->getPublicId(),
162
                $grantTypeData->getParameters(),
163
                $grantTypeData->getMetadatas(),
164
                $grantTypeData->getScopes(),
165
                null,
166
                null
167
            );
168
            $parameters = $parameters->with('refresh_token', $refreshToken->getTokenId());
169
        } else {
170
            $refreshToken = null;
171
        }
172
173
        $accessToken = $this->accessTokenRepository->create(
174
            $grantTypeData->getResourceOwnerId(),
175
            $grantTypeData->getClient()->getPublicId(),
176
            $parameters,
177
            $grantTypeData->getMetadatas(),
178
            $grantTypeData->getScopes(),
179
            null,
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<DateTimeImmutable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
180
            null
181
        );
182
183
        if (null !== $refreshToken) {
184
            $refreshToken = $refreshToken->addAccessToken($accessToken->getTokenId());
185
            $this->refreshTokenRepository->save($refreshToken);
186
        }
187
        $this->accessTokenRepository->save($accessToken);
188
189
        return $accessToken;
190
    }
191
192
    /**
193
     * @param ResourceOwnerId $resourceOwnerId
194
     *
195
     * @throws OAuth2Exception
196
     *
197
     * @return ResourceOwner
198
     */
199
    private function getResourceOwner(ResourceOwnerId $resourceOwnerId): ResourceOwner
200
    {
201
        $resourceOwner = $this->clientRepository->find(ClientId::create($resourceOwnerId->getValue()));
202
        if (null === $resourceOwner) {
203
            $resourceOwner = $this->userAccountRepository->find(UserAccountId::create($resourceOwnerId->getValue()));
204
        }
205
206
        if (null === $resourceOwner) {
207
            throw new OAuth2Exception(400, OAuth2Exception::ERROR_INVALID_REQUEST, 'Unable to find the associated resource owner.');
208
        }
209
210
        return $resourceOwner;
211
    }
212
}
213