Passed
Push — master ( a8d522...c97e91 )
by Alexandre
02:40
created

TokenEndpoint::issueRefreshToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 5
ccs 0
cts 0
cp 0
crap 2
rs 9.4285
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;
0 ignored issues
show
Bug introduced by
The type OAuth2\ClientAuthenticat...enticationMethodManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
use OAuth2\Exceptions\OAuthException;
15
use OAuth2\GrantTypes\GrantTypeInterface;
16
use OAuth2\GrantTypes\GrantTypeManager;
17
use OAuth2\Roles\ClientInterface;
18
use OAuth2\Roles\Clients\ConfidentialClient;
19
use OAuth2\Storages\AccessTokenStorageInterface;
20
use OAuth2\Storages\ClientStorageInterface;
21
use OAuth2\Storages\RefreshTokenStorageInterface;
22
use Psr\Http\Message\ResponseInterface;
23
use Psr\Http\Message\ServerRequestInterface;
24
25
class TokenEndpoint implements EndpointInterface
26 1
{
27
28 1
    /**
29
     * @var ClientStorageInterface
30
     */
31
    private $clientStorage;
32
    /**
33
     * @var GrantTypeManager
34
     */
35 1
    private $grantTypeManager;
36 1
    /**
37 1
     * @var ClientAuthenticationMethodManager
38
     */
39
    private $clientAuthenticationMethodManager;
40
    /**
41
     * @var AccessTokenStorageInterface
42
     */
43
    private $accessTokenStorage;
44
    /**
45
     * @var RefreshTokenStorageInterface
46 1
     */
47 1
    private $refreshTokenStorage;
48 1
49
    /**
50
     * @var ClientInterface|null
51 1
     */
52 1
    protected $client;
53
    /**
54
     * @var GrantTypeInterface|null
55
     */
56
    protected $grantType;
57
58
    public function __construct(ClientStorageInterface $clientStorage, GrantTypeManager $grantTypeManager,
59
                                ClientAuthenticationMethodManager $clientAuthenticationMethodManager,
60
                                AccessTokenStorageInterface $accessTokenStorage,
61
                                RefreshTokenStorageInterface $refreshTokenStorage)
62
    {
63
        $this->clientStorage = $clientStorage;
64
        $this->grantTypeManager = $grantTypeManager;
65
        $this->clientAuthenticationMethodManager = $clientAuthenticationMethodManager;
66
        $this->accessTokenStorage = $accessTokenStorage;
67
        $this->refreshTokenStorage = $refreshTokenStorage;
68 1
    }
69
70
    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...
71
    {
72
        if ($request->getMethod() === 'POST') {
73
            $requestData = $request->getParsedBody();
74
        } else {
75
            return new Response(404);
76
        }
77
78
        try {
79
            // Authentication Request Validation
80
            // The Authorization Server MUST validate all the OAuth 2.0 parameters according to the OAuth 2.0 specification.
81
            $this->verifyRequestData($request, $requestData);
82
83
            $responseData = $this->getGrantType()->handleAccessTokenRequest($this, $requestData);
84
85
        } catch (OAuthException $e) {
86
            /**
87
             * If the Authorization Server encounters any error, it MUST return an error response, per Section 5.2
88
             */
89
            $status = 400;
90
            $headers = ['Content-Type' => 'application/json'];
91 1
            if($e->getError() === 'invalid_client') {
92
                $status = 401;
93
                    if($request->hasHeader('Authorization')) {
94
                        $headers['WWW-Authenticate'] = 'Basic';
95
                }
96
            }
97
            return new Response($status, $headers, $e->jsonSerialize());
98 1
        }
99
100
        return new Response(200, [
101
            'Content-Type' => 'application/json',
102
            'Cache-Control' => 'no-store',
103
            'Pragma' => 'no-cache'
104
        ], json_encode($responseData));
105
    }
106
107
    /**
108
     * @param ServerRequestInterface $request
109
     * @param array                  $requestData
110
     * @throws OAuthException
111
     */
112
    protected function verifyRequestData(ServerRequestInterface $request, array $requestData)
113
    {
114
        if (empty($requestData['grant_type'])) {
115
            throw new OAuthException('invalid_request', 'The request is missing the required parameter grant_type.',
116
                'https://tools.ietf.org/html/rfc6749#section-4.1');
117
        }
118
119
        if (!($grantType = $this->grantTypeManager->getGrantType($requestData['grant_type']))) {
120
            throw new OAuthException('unsupported_grant_type',
121
                'The authorization grant type is not supported by the authorization server',
122
                'https://tools.ietf.org/html/rfc6749#section-4.1');
123
        }
124
        $this->grantType = $grantType;
125
126
        $this->verifyClient($request, $requestData);
127
128
        $supportedGrantTypes = $this->client->getMetadata()->getGrantTypes() ?: ['authorization_code'];
129
        if (!in_array($requestData['grant_type'], $supportedGrantTypes)) {
130
            throw new OAuthException('unauthorized_client',
131
                'The authenticated client is not authorized to use this authorization grant type.',
132
                'https://tools.ietf.org/html/rfc6749#section-4.1');
133
        }
134
135
    }
136
137
    protected function verifyClient(ServerRequestInterface $request, array $requestData)
138
    {
139
        // TODO authenticate if client is confidential
140
        // http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
141
142
        /**
143
         * require client authentication for confidential clients or for any
144
         * client that was issued client credentials (or with other
145
         * authentication requirements)
146
         */
147
        $this->client = $this->clientAuthenticationMethodManager->authenticate($request, $requestData);
148
149
        $this->getGrantType();
150
    }
151
152
    /**
153
     * @return null|GrantTypeInterface
154
     */
155
    public function getGrantType()
156
    {
157
        return $this->grantType;
158
    }
159
160
    /**
161
     * @return null|ClientInterface
162
     */
163
    public function getClient(): ?ClientInterface
164
    {
165
        return $this->client;
166
    }
167
168
    public function issueTokens(string $scope, string $resourceOwnerIdentifier, ?string $authorizationCode = null)
169
    {
170
        return array_merge(
171
            $this->issueAccessToken($scope, $resourceOwnerIdentifier, $authorizationCode),
172
            $this->issueRefreshToken($scope, $resourceOwnerIdentifier)
173
        );
174
    }
175
176
    public function issueAccessToken(string $scope, string $resourceOwnerIdentifier, ?string $authorizationCode = null): array
177
    {
178
        $accessToken = $this->accessTokenStorage->generate($scope, $this->client->getIdentifier(),
0 ignored issues
show
Bug introduced by
The method getIdentifier() does not exist on null. ( Ignorable by Annotation )

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

178
        $accessToken = $this->accessTokenStorage->generate($scope, $this->client->/** @scrutinizer ignore-call */ getIdentifier(),

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...
179
            $resourceOwnerIdentifier, $authorizationCode);
180
        return [
181
            'access_token' => $accessToken->getToken(),
182
            'token_type' => $accessToken->getType(),
183
            'expires_in' => $this->accessTokenStorage->getLifetime()
184
        ];
185
    }
186
187
    public function issueRefreshToken(string $scope, string $resourceOwnerIdentifier)
188
    {
189
        $accessToken = $this->refreshTokenStorage->generate($scope, $this->client->getIdentifier(), $resourceOwnerIdentifier);
190
        return [
191
            'refresh_token' => $accessToken->getToken()
192
        ];
193
    }
194
}