Passed
Pull Request — master (#1328)
by
unknown
32:37
created

BearerTokenValidator::validateAuthorization()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 45
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 7.0071

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 7
eloc 25
c 3
b 0
f 0
nc 8
nop 1
dl 0
loc 45
ccs 18
cts 19
cp 0.9474
crap 7.0071
rs 8.5866
1
<?php
2
3
/**
4
 * @author      Alex Bilbie <[email protected]>
5
 * @copyright   Copyright (c) Alex Bilbie
6
 * @license     http://mit-license.org/
7
 *
8
 * @link        https://github.com/thephpleague/oauth2-server
9
 */
10
11
declare(strict_types=1);
12
13
namespace League\OAuth2\Server\AuthorizationValidators;
14
15
use DateInterval;
16
use DateTimeZone;
17
use Lcobucci\Clock\SystemClock;
18
use Lcobucci\JWT\Configuration;
19
use Lcobucci\JWT\Exception;
20
use Lcobucci\JWT\Signer\Key\InMemory;
21
use Lcobucci\JWT\Signer\Rsa\Sha256;
22
use Lcobucci\JWT\Token\Plain;
23
use Lcobucci\JWT\UnencryptedToken;
24
use Lcobucci\JWT\Validation\Constraint\LooseValidAt;
25
use Lcobucci\JWT\Validation\Constraint\SignedWith;
26
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
27
use League\OAuth2\Server\CryptKeyInterface;
28
use League\OAuth2\Server\CryptTrait;
29
use League\OAuth2\Server\Exception\OAuthServerException;
30
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
31
use Psr\Http\Message\ServerRequestInterface;
32
use RuntimeException;
33
34
use function date_default_timezone_get;
35
use function preg_replace;
36
use function trim;
37
38
class BearerTokenValidator implements AuthorizationValidatorInterface
39
{
40
    use CryptTrait;
41
42
    protected CryptKeyInterface $publicKey;
43
44
    private Configuration $jwtConfiguration;
45 13
46
    public function __construct(private AccessTokenRepositoryInterface $accessTokenRepository, private ?DateInterval $jwtValidAtDateLeeway = null)
47 13
    {
48
    }
49
50
    /**
51
     * Set the public key
52 13
     */
53
    public function setPublicKey(CryptKeyInterface $key): void
54 13
    {
55
        $this->publicKey = $key;
56 13
57
        $this->initJwtConfiguration();
58
    }
59
60
    /**
61
     * Initialise the JWT configuration.
62 13
     */
63
    private function initJwtConfiguration(): void
64 13
    {
65 13
        $this->jwtConfiguration = Configuration::forSymmetricSigner(
66 13
            new Sha256(),
67 13
            InMemory::plainText('empty', 'empty')
68
        );
69 13
70
        $clock = new SystemClock(new DateTimeZone(date_default_timezone_get()));
71 13
72
        $publicKeyContents = $this->publicKey->getKeyContents();
73 13
74
        if ($publicKeyContents === '') {
75
            throw new RuntimeException('Public key is empty');
76
        }
77 13
78 13
        $this->jwtConfiguration->setValidationConstraints(
79 13
            new LooseValidAt($clock, $this->jwtValidAtDateLeeway),
80 13
            new SignedWith(
81 13
                new Sha256(),
82 13
                InMemory::plainText($publicKeyContents, $this->publicKey->getPassPhrase() ?? '')
83 13
            )
84
        );
85
    }
86
87
    /**
88
     * Configure the request instance.
89 13
     */
90
    protected function withRequest(ServerRequestInterface $request, Plain $token): ServerRequestInterface
0 ignored issues
show
Unused Code introduced by
The parameter $token is not used and could be removed. ( Ignorable by Annotation )

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

90
    protected function withRequest(ServerRequestInterface $request, /** @scrutinizer ignore-unused */ Plain $token): ServerRequestInterface

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
91 13
    {
92 1
        return $request;
93
    }
94
95 12
    /**
96 12
     * {@inheritdoc}
97
     */
98 12
    public function validateAuthorization(ServerRequestInterface $request): ServerRequestInterface
99 1
    {
100
        if ($request->hasHeader('authorization') === false) {
101
            throw OAuthServerException::accessDenied('Missing "Authorization" header');
102
        }
103
104 11
        $header = $request->getHeader('authorization');
105 2
        $jwt = trim((string) preg_replace('/^\s*Bearer\s/', '', $header[0]));
106 2
107
        if ($jwt === '') {
108
            throw OAuthServerException::accessDenied('Missing "Bearer" token');
109
        }
110
111 9
        try {
112 9
            // Attempt to parse the JWT
113 4
            $token = $this->jwtConfiguration->parser()->parse($jwt);
114 4
        } catch (Exception $exception) {
115
            throw OAuthServerException::accessDenied($exception->getMessage(), null, $exception);
116
        }
117 5
118
        try {
119
            // Attempt to validate the JWT
120
            $constraints = $this->jwtConfiguration->validationConstraints();
121 5
            $this->jwtConfiguration->validator()->assert($token, ...$constraints);
122
        } catch (RequiredConstraintsViolated $exception) {
123
            throw OAuthServerException::accessDenied('Access token could not be verified', null, $exception);
124 5
        }
125 1
126
        if (!$token instanceof UnencryptedToken) {
127
            throw OAuthServerException::accessDenied('Access token is not an instance of UnencryptedToken');
128
        }
129 4
130 4
        $claims = $token->claims();
131 4
132 4
        // Check if token has been revoked
133 4
        if ($this->accessTokenRepository->isAccessTokenRevoked($claims->get('jti'))) {
134
            throw OAuthServerException::accessDenied('Access token has been revoked');
135
        }
136
137
        // Return the request with additional attributes
138
        return $this->withRequest($request
139
            ->withAttribute('oauth_access_token_id', $claims->get('jti'))
140
            ->withAttribute('oauth_client_id', $claims->get('aud')[0])
141
            ->withAttribute('oauth_user_id', $claims->get('sub'))
142
            ->withAttribute('oauth_scopes', $claims->get('scopes')), $token);
143
    }
144
}
145