Completed
Pull Request — master (#995)
by
unknown
02:16
created

RevokeTokenHandler::respondToRevokeTokenRequest()   B

Complexity

Conditions 10
Paths 22

Size

Total Lines 49

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 10.0328

Importance

Changes 0
Metric Value
dl 0
loc 49
ccs 27
cts 29
cp 0.931
rs 7.246
c 0
b 0
f 0
cc 10
nc 22
nop 2
crap 10.0328

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @author      Alex Bilbie <[email protected]>
4
 * @copyright   Copyright (c) Alex Bilbie
5
 * @license     http://mit-license.org/
6
 *
7
 * @link        https://github.com/thephpleague/oauth2-server
8
 */
9
10
namespace League\OAuth2\Server;
11
12
use Exception;
13
use Lcobucci\JWT\Parser;
14
use Lcobucci\JWT\Signer\Rsa\Sha256;
15
use Lcobucci\JWT\Token;
16
use League\Event\EmitterAwareInterface;
17
use League\Event\EmitterAwareTrait;
18
use League\OAuth2\Server\Exception\OAuthServerException;
19
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
20
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
21
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
22
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
23
use Psr\Http\Message\ServerRequestInterface;
24
25
class RevokeTokenHandler implements EmitterAwareInterface
0 ignored issues
show
Bug introduced by
There is one abstract method getEmitter in this class; you could implement it, or declare this class as abstract.
Loading history...
26
{
27
    use EmitterAwareTrait, CryptTrait, RequestValidatorTrait;
28
29
    /**
30
     * @var ClientRepositoryInterface
31
     */
32
    protected $clientRepository;
33
34
    /**
35
     * @var AccessTokenRepositoryInterface
36
     */
37
    private $accessTokenRepository;
38
39
    /**
40
     * @var RefreshTokenRepositoryInterface
41
     */
42
    private $refreshTokenRepository;
43
44
    /**
45
     * @var bool
46
     */
47
    private $canRevokeAccessTokens;
48
49
    /**
50
     * @var CryptKey
51
     */
52
    protected $publicKey;
53
54
    /**
55
     * New handler instance.
56
     *
57
     * @param RefreshTokenRepositoryInterface $refreshTokenRepository
58
     * @param CryptKey|string                 $publicKey
59
     * @param bool                            $canRevokeAccessTokens
60
     */
61 12
    public function __construct(
62
        RefreshTokenRepositoryInterface $refreshTokenRepository,
63
        $publicKey,
64
        $canRevokeAccessTokens = true
65
    ) {
66 12
        $this->setRefreshTokenRepository($refreshTokenRepository);
67
68 12
        if ($publicKey instanceof CryptKey === false) {
69 1
            $publicKey = new CryptKey($publicKey);
70
        }
71 12
        $this->publicKey = $publicKey;
72
73 12
        $this->canRevokeAccessTokens = $canRevokeAccessTokens;
74 12
    }
75
76
    /**
77
     * @return ClientRepositoryInterface
78
     */
79 12
    public function getClientRepository()
80
    {
81 12
        return $this->clientRepository;
82
    }
83
84
    /**
85
     * @param ClientRepositoryInterface $clientRepository
86
     */
87 12
    public function setClientRepository(ClientRepositoryInterface $clientRepository)
88
    {
89 12
        $this->clientRepository = $clientRepository;
90 12
    }
91
92
    /**
93
     * @param AccessTokenRepositoryInterface $accessTokenRepository
94
     */
95 12
    public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository)
96
    {
97 12
        $this->accessTokenRepository = $accessTokenRepository;
98 12
    }
99
100
    /**
101
     * @param RefreshTokenRepositoryInterface $refreshTokenRepository
102
     */
103 12
    public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository)
104
    {
105 12
        $this->refreshTokenRepository = $refreshTokenRepository;
106 12
    }
107
108
    /**
109
     * Set the public key
110
     *
111
     * @param CryptKey $key
112
     */
113
    public function setPublicKey(CryptKey $key)
114
    {
115
        $this->publicKey = $key;
116
    }
117
118
    /**
119
     * Return the grant identifier that can be used in matching up requests.
120
     *
121
     * @return string
122
     */
123 12
    public function getIdentifier()
124
    {
125 12
        return '';
126
    }
127
128
    /**
129
     * Return a revoke token response.
130
     * https://tools.ietf.org/html/rfc7009
131
     *
132
     * @param ServerRequestInterface $request
133
     * @param ResponseTypeInterface  $response
134
     *
135
     * @throws OAuthServerException
136
     *
137
     * @return ResponseTypeInterface
138
     */
139 12
    public function respondToRevokeTokenRequest(ServerRequestInterface $request, ResponseTypeInterface $response)
140
    {
141 12
        if ($request->getMethod() !== 'POST') {
142
            $errorMessage = 'POST method required.';
143
            throw new OAuthServerException($errorMessage, 3, 'invalid_request', 400);
144
        }
145
146 12
        $token = $this->getRequestParameter('token', $request);
147 12
        $hint = $this->getRequestParameter('token_type_hint', $request);
148
149
        // Validate request
150 12
        $client = $this->validateClient($request);
151 12
        $clientId = $client->getIdentifier();
152
153 12
        if (is_null($token)) {
154 1
            return $response;
155
        }
156
157
        // Attempt to read token
158 11
        $accessToken = null;
159 11
        $refreshToken = null;
160 11
        if ($hint === 'refresh_token') {
161 6
            $refreshToken = $this->readAsRefreshToken($token, $clientId);
162 5
            if ($refreshToken === null) {
163 5
                $accessToken = $this->readAsAccessToken($token, $clientId);
164
            }
165
        } else {
166 5
            $accessToken = $this->readAsAccessToken($token, $clientId);
167 5
            if ($accessToken === null) {
168 2
                $refreshToken = $this->readAsRefreshToken($token, $clientId);
169
            }
170
        }
171
172
        // Revoke tokens
173 10
        if ($accessToken !== null) {
174 3
            if (!$this->canRevokeAccessTokens) {
175 1
                $errorMessage = 'The authorization server does not support the revocation of the presented token type';
176 1
                throw new OAuthServerException($errorMessage, 2, 'unsupported_token_type', 400);
177
            }
178 2
            $this->accessTokenRepository->revokeAccessToken($accessToken->getClaim('jti'));
179 7
        } elseif ($refreshToken !== null) {
180 5
            $this->refreshTokenRepository->revokeRefreshToken($refreshToken['refresh_token_id']);
181 5
            if ($this->canRevokeAccessTokens) {
182 4
                $this->accessTokenRepository->revokeAccessToken($refreshToken['access_token_id']);
183
            }
184
        }
185
186 9
        return $response;
187
    }
188
189
    /**
190
     * @param string $tokenParam
191
     * @param string $clientId
192
     *
193
     * @return null|Token
194
     */
195 6
    protected function readAsAccessToken($tokenParam, $clientId)
196
    {
197 6
        $token = null;
198
        try {
199 6
            $token = (new Parser())->parse($tokenParam);
200
201 3
            if ($token->verify(new Sha256(), $this->publicKey->getKeyPath()) === false) {
202 3
                return null;
203
            }
204 3
        } catch (Exception $exception) {
205
            // JWT couldn't be parsed so ignore
206 3
            return null;
207
        }
208
209 3
        $clientId = $token->getClaim('aud');
210 3
        if ($clientId !== $clientId) {
211
            throw OAuthServerException::invalidClient();
212
        }
213
214 3
        return $token;
215
    }
216
217
    /**
218
     * @param string $tokenParam
219
     * @param string $clientId
220
     *
221
     * @return null|array
222
     */
223 8
    protected function readAsRefreshToken($tokenParam, $clientId)
224
    {
225 8
        $refreshTokenData = null;
226
        try {
227 8
            $refreshToken = $this->decrypt($tokenParam);
228 6
            $refreshTokenData = json_decode($refreshToken, true);
229 2
        } catch (Exception $e) {
230
            // token couldn't be decrypted so ignore
231 2
            return null;
232
        }
233
234 6
        if ($refreshTokenData['client_id'] !== $clientId) {
235 1
            throw OAuthServerException::invalidClient();
236
        }
237
238 5
        return $refreshTokenData;
239
    }
240
}
241