Passed
Push — master ( 54948a...430c6d )
by Bukashk0zzz
01:11 queued 14s
created

JWTUserProvider::loadUserByIdentifier()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 9
rs 10
c 1
b 0
f 0
1
<?php declare(strict_types = 1);
2
3
namespace AtlassianConnectBundle\Security;
4
5
use AtlassianConnectBundle\Entity\TenantInterface;
6
use Doctrine\ORM\EntityManager;
7
use Doctrine\ORM\EntityManagerInterface;
8
use Firebase\JWT\JWT;
9
use Symfony\Component\Security\Core\Exception\AuthenticationException;
10
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
11
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
12
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
13
use Symfony\Component\Security\Core\User\UserInterface;
14
15
/**
16
 * Class JWTUserProvider
17
 */
18
class JWTUserProvider implements JWTUserProviderInterface
19
{
20
    /**
21
     * @var EntityManager
22
     */
23
    protected $em;
24
25
    /**
26
     * @var string
27
     */
28
    protected $tenantClass;
29
30
    /**
31
     * JWTUserProvider constructor.
32
     *
33
     * @param EntityManagerInterface $entityManager
34
     * @param string                 $tenantClass
35
     */
36
    public function __construct(EntityManagerInterface $entityManager, string $tenantClass)
37
    {
38
        $this->em = $entityManager;
0 ignored issues
show
Documentation Bug introduced by
$entityManager is of type Doctrine\ORM\EntityManagerInterface, but the property $em was declared to be of type Doctrine\ORM\EntityManager. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
39
        $this->tenantClass = $tenantClass;
40
    }
41
42
    /**
43
     * @param string $jwt
44
     *
45
     * @return object|mixed
46
     */
47
    public function getDecodedToken(string $jwt)
48
    {
49
        try {
50
            /** @noinspection PhpUnusedLocalVariableInspection */
51
            $bodyb64 = \explode('.', $jwt)[1];
52
            $decodedToken = \json_decode(JWT::urlsafeB64Decode($bodyb64));
53
54
            /** @noinspection NullPointerExceptionInspection */
55
            JWT::decode($jwt, $this->findTenant($decodedToken->iss)->getSharedSecret(), ['HS256']);
56
57
            return $decodedToken;
58
        } catch (\Throwable $e) {
59
            throw new AuthenticationException($e->getMessage());
60
        }
61
    }
62
63
    /**
64
     * @param mixed $clientKey
65
     *
66
     * @return TenantInterface|UserInterface
67
     */
68
    public function loadUserByUsername($clientKey): TenantInterface
69
    {
70
        $tenant = $this->findTenant($clientKey);
71
72
        if (!$tenant) {
73
            throw new UsernameNotFoundException('Can\'t find tenant with such username');
0 ignored issues
show
Deprecated Code introduced by
The class Symfony\Component\Securi...ernameNotFoundException has been deprecated: since Symfony 5.3 to be removed in 6.0, use UserNotFoundException instead. ( Ignorable by Annotation )

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

73
            throw /** @scrutinizer ignore-deprecated */ new UsernameNotFoundException('Can\'t find tenant with such username');
Loading history...
74
        }
75
76
        return $tenant;
77
    }
78
79
    /**
80
     * @param UserInterface $user
81
     */
82
    public function refreshUser(UserInterface $user): void
83
    {
84
        throw new UnsupportedUserException('Refresh prohibited');
85
    }
86
87
    /**
88
     * @param string|mixed $class
89
     *
90
     * @return bool
91
     */
92
    public function supportsClass($class): bool
93
    {
94
        return \is_subclass_of($class, TenantInterface::class);
95
    }
96
97
    /**
98
     * @param string $identifier
99
     *
100
     * @return UserInterface
101
     */
102
    public function loadUserByIdentifier(string $identifier): UserInterface
103
    {
104
        $tenant = $this->findTenant($identifier);
105
106
        if (!$tenant) {
107
            throw new UserNotFoundException('Can\'t find tenant with such identifier');
108
        }
109
110
        return $tenant;
111
    }
112
113
    /**
114
     * @param string $clientKey
115
     *
116
     * @return TenantInterface|object|null
117
     */
118
    private function findTenant(string $clientKey): ?TenantInterface
119
    {
120
        /** @noinspection PhpUndefinedMethodInspection */
121
122
        return $this->em
123
            ->getRepository($this->tenantClass)
124
            ->findOneBy(['clientKey' => $clientKey]);
125
    }
126
}
127