Passed
Pull Request — master (#94)
by Daniel
08:24 queued 01:42
created

JWTManager::getUserIdClaim()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the Silverback API Components Bundle Project
5
 *
6
 * (c) Daniel West <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Silverback\ApiComponentsBundle\Security;
15
16
use Lexik\Bundle\JWTAuthenticationBundle\Exception\InvalidPayloadException;
17
use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTDecodeFailureException;
18
use Lexik\Bundle\JWTAuthenticationBundle\Exception\UserNotFoundException;
19
use Lexik\Bundle\JWTAuthenticationBundle\Security\Authentication\Token\PreAuthenticationJWTUserToken;
20
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWSProvider\JWSProviderInterface;
21
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
22
use Silverback\ApiComponentsBundle\Event\JWTRefreshedEvent;
23
use Silverback\ApiComponentsBundle\RefreshToken\Storage\RefreshTokenStorageInterface;
24
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
25
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
26
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
27
use Symfony\Component\Security\Core\User\UserInterface;
28
use Symfony\Component\Security\Core\User\UserProviderInterface;
29
30
/**
31
 * @author Vincent Chalamon <[email protected]>
32
 */
33
final class JWTManager implements JWTTokenManagerInterface
34
{
35
    private JWTTokenManagerInterface $decorated;
36
    private JWSProviderInterface $jwsProvider;
37
    private EventDispatcherInterface $dispatcher;
38
    private UserProviderInterface $userProvider;
39
    private RefreshTokenStorageInterface $storage;
40
41
    public function __construct(JWTTokenManagerInterface $decorated, JWSProviderInterface $jwsProvider, EventDispatcherInterface $dispatcher, UserProviderInterface $userProvider, RefreshTokenStorageInterface $storage)
42
    {
43
        $this->decorated = $decorated;
44
        $this->jwsProvider = $jwsProvider;
45
        $this->dispatcher = $dispatcher;
46
        $this->userProvider = $userProvider;
47
        $this->storage = $storage;
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function create(UserInterface $user): string
54
    {
55
        $this->storage->create($user);
56
57
        return $this->decorated->create($user);
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function decode(TokenInterface $token)
64
    {
65
        try {
66
            return $this->decorated->decode($token);
67
        } catch (JWTDecodeFailureException $exception) {
68
            if (JWTDecodeFailureException::EXPIRED_TOKEN !== $exception->getReason()) {
69
                throw $exception;
70
            }
71
72
            $jws = $this->jwsProvider->load($token->getCredentials());
73
            $payload = $jws->getPayload();
74
            $idClaim = $this->getUserIdClaim();
75
76
            if (!isset($payload[$idClaim])) {
77
                throw new InvalidPayloadException($idClaim);
78
            }
79
80
            $identity = $payload[$idClaim];
81
82
            try {
83
                $user = $this->userProvider->loadUserByUsername($identity);
84
            } catch (UsernameNotFoundException $e) {
85
                throw new UserNotFoundException($idClaim, $identity);
86
            }
87
88
            $refreshToken = $this->storage->findOneByUser($user);
89
            if (!$refreshToken || $refreshToken->isExpired()) {
90
                throw $exception;
91
            }
92
93
            $this->storage->expireAll($user);
94
95
            $this->storage->create($user);
96
97
            $accessToken = $this->create($user);
98
99
            $this->dispatcher->dispatch(new JWTRefreshedEvent($accessToken));
100
101
            return $this->decorated->decode(new PreAuthenticationJWTUserToken($accessToken));
102
        }
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     */
108
    public function setUserIdentityField($field)
109
    {
110
        return $this->decorated->setUserIdentityField($field);
111
    }
112
113
    /**
114
     * {@inheritdoc}
115
     */
116
    public function getUserIdentityField(): string
117
    {
118
        return $this->decorated->getUserIdentityField();
119
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124
    public function getUserIdClaim(): string
125
    {
126
        return $this->decorated->getUserIdClaim();
127
    }
128
}
129