TokenManager::getGrants()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 12
cts 12
cp 1
rs 9.7
c 0
b 0
f 0
cc 3
nc 3
nop 3
crap 3
1
<?php
2
declare(strict_types=1);
3
4
namespace SlayerBirden\DataFlowServer\Authentication\Service;
5
6
use Doctrine\Common\Collections\ArrayCollection;
7
use Doctrine\Common\Collections\Criteria;
8
use Doctrine\Common\Collections\Selectable;
9
use Doctrine\Common\Persistence\ManagerRegistry;
10
use SlayerBirden\DataFlowServer\Authentication\Entities\Grant;
11
use SlayerBirden\DataFlowServer\Authentication\Entities\Token;
12
use SlayerBirden\DataFlowServer\Authentication\Exception\InvalidCredentialsException;
13
use SlayerBirden\DataFlowServer\Authentication\Exception\PermissionDeniedException;
14
use SlayerBirden\DataFlowServer\Authentication\PasswordManagerInterface;
15
use SlayerBirden\DataFlowServer\Authentication\TokenManagerInterface;
16
use SlayerBirden\DataFlowServer\Authorization\PermissionManagerInterface;
17
use SlayerBirden\DataFlowServer\Domain\Entities\User;
18
19
final class TokenManager implements TokenManagerInterface
20
{
21
    /**
22
     * @var PasswordManagerInterface
23
     */
24
    private $passwordManager;
25
    /**
26
     * @var PermissionManagerInterface
27
     */
28
    private $permissionManager;
29
    /**
30
     * @var ManagerRegistry
31
     */
32
    private $managerRegistry;
33
    /**
34
     * @var Selectable
35
     */
36
    private $userRepository;
37
38 38
    public function __construct(
39
        ManagerRegistry $managerRegistry,
40
        Selectable $userRepository,
41
        PasswordManagerInterface $passwordManager,
42
        PermissionManagerInterface $permissionManager
43
    ) {
44 38
        $this->managerRegistry = $managerRegistry;
45 38
        $this->userRepository = $userRepository;
46 38
        $this->passwordManager = $passwordManager;
47 38
        $this->permissionManager = $permissionManager;
48 38
    }
49
50
    /**
51
     * @inheritdoc
52
     * @throws \Exception
53
     */
54 6
    public function getToken(string $user, string $password, array $resources): Token
55
    {
56 6
        $em = $this->managerRegistry->getManagerForClass(Token::class);
57 6
        $user = $this->getByUsername($user);
58 6
        if ($this->passwordManager->isValidForUser($password, $user)) {
59 4
            $token = new Token();
60 4
            $now = new \DateTime();
61
            // default token for 1 month
62 4
            $due = (new \DateTime())->add(new \DateInterval('P1M'));
63
64 4
            $token->setActive(true);
65 4
            $token->setCreatedAt($now);
66 4
            $token->setOwner($user);
67 4
            $token->setDue($due);
68 4
            $token->setGrants($this->getGrants($token, $resources, $user));
69 2
            $token->setToken($this->generateToken());
70
71 2
            $em->persist($token);
72 2
            $em->flush();
73
74 2
            return $token;
75
        }
76
77 2
        throw new InvalidCredentialsException('Could not validate credentials.');
78
    }
79
80 6
    private function getByUsername(string $user): User
81
    {
82 6
        $criteria = Criteria::create();
83 6
        $criteria->where(Criteria::expr()->eq('email', $user));
84 6
        $users = $this->userRepository->matching($criteria);
85
86 6
        if ($users->count()) {
87 6
            return $users->first();
88
        } else {
89
            throw new InvalidCredentialsException('Could not find user by provided email.');
90
        }
91
    }
92
93
    /**
94
     * UUIDv4
95
     * https://stackoverflow.com/a/15875555/927404
96
     *
97
     * @return string
98
     * @throws \Exception
99
     */
100 24
    private function generateToken(): string
101
    {
102 24
        $data = random_bytes(16);
103
104 24
        $data[6] = chr(ord($data[6]) & 0x0f | 0x40);
105 24
        $data[8] = chr(ord($data[8]) & 0x3f | 0x80);
106
107 24
        return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
108
    }
109
110
    /**
111
     * @param Token $token
112
     * @param array $resources
113
     * @param User $user
114
     * @return ArrayCollection
115
     * @throws PermissionDeniedException
116
     */
117 28
    private function getGrants(Token $token, array $resources, User $user): ArrayCollection
118
    {
119 28
        $grants = [];
120 28
        $em = $this->managerRegistry->getManagerForClass(Token::class);
121 28
        foreach ($resources as $resource) {
122 28
            if (!$this->permissionManager->isAllowed($resource, $user)) {
123 4
                throw new PermissionDeniedException(sprintf('%s is not allowed for provided user.', $resource));
124
            }
125 24
            $grant = new Grant();
126 24
            $grant->setToken($token);
127 24
            $grant->setResource($resource);
128 24
            $em->persist($grant);
129 24
            $grants[] = $grant;
130
        }
131
132 24
        return new ArrayCollection($grants);
133
    }
134
135
    /**
136
     * @param User $user
137
     * @param array $resources
138
     * @return Token
139
     * @throws \Exception
140
     */
141 24
    public function getTmpToken(User $user, array $resources): Token
142
    {
143 24
        $token = new Token();
144 24
        $now = new \DateTime();
145
        // tmp token for 1 hour
146 24
        $due = (new \DateTime())->add(new \DateInterval('PT1H'));
147
148 24
        $token->setActive(true);
149 24
        $token->setCreatedAt($now);
150 24
        $token->setOwner($user);
151 24
        $token->setDue($due);
152 24
        $token->setGrants($this->getGrants($token, $resources, $user));
153 22
        $token->setToken($this->generateToken());
154
155 22
        $em = $this->managerRegistry->getManagerForClass(Token::class);
156 22
        $em->persist($token);
157 22
        $em->flush();
158
159 22
        return $token;
160
    }
161
}
162