Passed
Pull Request — master (#94)
by Daniel
06:15
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
        return $this->decorated->create($user);
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    public function decode(TokenInterface $token)
63
    {
64
        try {
65
            return $this->decorated->decode($token);
66
        } catch (JWTDecodeFailureException $exception) {
67
            if (JWTDecodeFailureException::EXPIRED_TOKEN !== $exception->getReason()) {
68
                throw $exception;
69
            }
70
71
            $jws = $this->jwsProvider->load($token->getCredentials());
72
            $payload = $jws->getPayload();
73
            $idClaim = $this->getUserIdClaim();
74
75
            if (!isset($payload[$idClaim])) {
76
                throw new InvalidPayloadException($idClaim);
77
            }
78
79
            $identity = $payload[$idClaim];
80
81
            try {
82
                $user = $this->userProvider->loadUserByUsername($identity);
83
            } catch (UsernameNotFoundException $e) {
84
                throw new UserNotFoundException($idClaim, $identity);
85
            }
86
87
            $refreshToken = $this->storage->findOneByUser($user);
88
            if (!$refreshToken || $refreshToken->isExpired()) {
89
                throw $exception;
90
            }
91
92
            $this->storage->expireAll($user);
93
94
            $this->storage->create($user);
95
96
            $accessToken = $this->create($user);
97
98
            $this->dispatcher->dispatch(new JWTRefreshedEvent($accessToken));
99
100
            return $this->decorated->decode(new PreAuthenticationJWTUserToken($accessToken));
101
        }
102
    }
103
104
    /**
105
     * {@inheritdoc}
106
     */
107
    public function setUserIdentityField($field)
108
    {
109
        return $this->decorated->setUserIdentityField($field);
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     */
115
    public function getUserIdentityField(): string
116
    {
117
        return $this->decorated->getUserIdentityField();
118
    }
119
120
    /**
121
     * {@inheritdoc}
122
     */
123
    public function getUserIdClaim(): string
124
    {
125
        return $this->decorated->getUserIdClaim();
126
    }
127
}
128