Passed
Push — master ( 289fb4...04efa9 )
by Andrew
08:43
created

BearerTokenValidator::setPublicKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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

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