Passed
Push — master ( 0b32d7...4677b2 )
by Andrew
01:46 queued 12s
created

convertSingleRecordAudToString()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 1
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 3
rs 10
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\AuthorizationValidators;
11
12
use DateTimeZone;
13
use Lcobucci\Clock\SystemClock;
14
use Lcobucci\JWT\Configuration;
15
use Lcobucci\JWT\Signer\Key\InMemory;
16
use Lcobucci\JWT\Signer\Rsa\Sha256;
17
use Lcobucci\JWT\Validation\Constraint\LooseValidAt;
18
use Lcobucci\JWT\Validation\Constraint\SignedWith;
19
use Lcobucci\JWT\Validation\Constraint\ValidAt;
20
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
21
use League\OAuth2\Server\CryptKey;
22
use League\OAuth2\Server\CryptTrait;
23
use League\OAuth2\Server\Exception\OAuthServerException;
24
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
25
use Psr\Http\Message\ServerRequestInterface;
26
27
class BearerTokenValidator implements AuthorizationValidatorInterface
28
{
29
    use CryptTrait;
30
31
    /**
32
     * @var AccessTokenRepositoryInterface
33
     */
34
    private $accessTokenRepository;
35
36
    /**
37
     * @var CryptKey
38
     */
39
    protected $publicKey;
40
41
    /**
42
     * @var Configuration
43
     */
44
    private $jwtConfiguration;
45
46
    /**
47
     * @var \DateInterval|null
48
     */
49
    private $jwtValidAtDateLeeway;
50
51
    /**
52
     * @param AccessTokenRepositoryInterface $accessTokenRepository
53
     * @param \DateInterval|null             $jwtValidAtDateLeeway
54
     */
55 13
    public function __construct(AccessTokenRepositoryInterface $accessTokenRepository, \DateInterval $jwtValidAtDateLeeway = null)
56
    {
57 13
        $this->accessTokenRepository = $accessTokenRepository;
58 13
        $this->jwtValidAtDateLeeway = $jwtValidAtDateLeeway;
59 13
    }
60
61
    /**
62
     * Set the public key
63
     *
64
     * @param CryptKey $key
65
     */
66 13
    public function setPublicKey(CryptKey $key)
67
    {
68 13
        $this->publicKey = $key;
69
70 13
        $this->initJwtConfiguration();
71 13
    }
72
73
    /**
74
     * Initialise the JWT configuration.
75
     */
76 13
    private function initJwtConfiguration()
77
    {
78 13
        $this->jwtConfiguration = Configuration::forSymmetricSigner(
79 13
            new Sha256(),
80 13
            InMemory::plainText('empty', 'empty')
81
        );
82
83 13
        $clock = new SystemClock(new DateTimeZone(\date_default_timezone_get()));
84 13
        $this->jwtConfiguration->setValidationConstraints(
85 13
            \class_exists(LooseValidAt::class)
86
                ? new LooseValidAt($clock, $this->jwtValidAtDateLeeway)
87 13
                : new ValidAt($clock, $this->jwtValidAtDateLeeway),
0 ignored issues
show
Deprecated Code introduced by
The class Lcobucci\JWT\Validation\Constraint\ValidAt has been deprecated: Use \Lcobucci\JWT\Validation\Constraint\LooseValidAt ( Ignorable by Annotation )

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

87
                : /** @scrutinizer ignore-deprecated */ new ValidAt($clock, $this->jwtValidAtDateLeeway),
Loading history...
88 13
            new SignedWith(
89 13
                new Sha256(),
90 13
                InMemory::plainText($this->publicKey->getKeyContents(), $this->publicKey->getPassPhrase() ?? '')
91
            )
92
        );
93 13
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98 13
    public function validateAuthorization(ServerRequestInterface $request)
99
    {
100 13
        if ($request->hasHeader('authorization') === false) {
101 1
            throw OAuthServerException::accessDenied('Missing "Authorization" header');
102
        }
103
104 12
        $header = $request->getHeader('authorization');
105 12
        $jwt = \trim((string) \preg_replace('/^\s*Bearer\s/', '', $header[0]));
106
107
        try {
108
            // Attempt to parse the JWT
109 12
            $token = $this->jwtConfiguration->parser()->parse($jwt);
110 3
        } catch (\Lcobucci\JWT\Exception $exception) {
111 3
            throw OAuthServerException::accessDenied($exception->getMessage(), null, $exception);
112
        }
113
114
        try {
115
            // Attempt to validate the JWT
116 9
            $constraints = $this->jwtConfiguration->validationConstraints();
117 9
            $this->jwtConfiguration->validator()->assert($token, ...$constraints);
118 4
        } catch (RequiredConstraintsViolated $exception) {
119 4
            throw OAuthServerException::accessDenied('Access token could not be verified');
120
        }
121
122 5
        $claims = $token->claims();
123
124
        // Check if token has been revoked
125 5
        if ($this->accessTokenRepository->isAccessTokenRevoked($claims->get('jti'))) {
126 1
            throw OAuthServerException::accessDenied('Access token has been revoked');
127
        }
128
129
        // Return the request with additional attributes
130
        return $request
131 4
            ->withAttribute('oauth_access_token_id', $claims->get('jti'))
132 4
            ->withAttribute('oauth_client_id', $this->convertSingleRecordAudToString($claims->get('aud')))
133 4
            ->withAttribute('oauth_user_id', $claims->get('sub'))
134 4
            ->withAttribute('oauth_scopes', $claims->get('scopes'));
135
    }
136
137
    /**
138
     * Convert single record arrays into strings to ensure backwards compatibility between v4 and v3.x of lcobucci/jwt
139
     *
140
     * @param mixed $aud
141
     *
142
     * @return array|string
143
     */
144 4
    private function convertSingleRecordAudToString($aud)
145
    {
146 4
        return \is_array($aud) && \count($aud) === 1 ? $aud[0] : $aud;
147
    }
148
}
149