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