Passed
Push — master ( d3cc39...f2a84f )
by Melech
03:59
created

JwtAuthenticator   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 71
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 7
eloc 22
dl 0
loc 71
rs 10
c 1
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 1
A getAuthenticatedUsersFromRequest() 0 15 3
A getAuthenticatedUsersFromToken() 0 19 3
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Valkyrja Framework package.
7
 *
8
 * (c) Melech Mizrachi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Valkyrja\Auth;
15
16
use Valkyrja\Auth\Constant\HeaderValue;
0 ignored issues
show
Bug introduced by
The type Valkyrja\Auth\Constant\HeaderValue was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use Valkyrja\Auth\Data\Contract\AuthenticatedUsers;
18
use Valkyrja\Auth\Entity\Contract\User;
19
use Valkyrja\Auth\Exception\InvalidAuthenticationException;
20
use Valkyrja\Auth\Hasher\Contract\PasswordHasher;
21
use Valkyrja\Auth\Store\Contract\Store;
22
use Valkyrja\Http\Message\Constant\HeaderName;
0 ignored issues
show
Bug introduced by
The type Valkyrja\Http\Message\Constant\HeaderName was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use Valkyrja\Http\Message\Request\Contract\ServerRequest;
24
use Valkyrja\Jwt\Contract\Jwt;
25
26
use function is_string;
27
28
/**
29
 * Class JwtAuthenticator.
30
 *
31
 * @author Melech Mizrachi
32
 *
33
 * @template U of User
34
 *
35
 * @extends AbstractAuthenticator<U>
36
 */
37
class JwtAuthenticator extends AbstractAuthenticator
38
{
39
    /**
40
     * @param Store<U>        $store  The store
41
     * @param class-string<U> $entity The user entity
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<U> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<U>.
Loading history...
42
     */
43
    public function __construct(
44
        protected Jwt $jwt,
45
        protected ServerRequest $request,
46
        Store $store,
47
        PasswordHasher $hasher,
48
        string $entity,
49
        AuthenticatedUsers|null $authenticatedUsers = null,
50
        protected string $headerName = HeaderName::AUTHORIZATION,
51
    ) {
52
        parent::__construct(
53
            store: $store,
54
            hasher: $hasher,
55
            entity: $entity,
56
            authenticatedUsers: $authenticatedUsers ?? $this->getAuthenticatedUsersFromRequest() ?? new Data\AuthenticatedUsers(),
57
        );
58
    }
59
60
    /**
61
     * Attempt to get the authenticated users from the request.
62
     *
63
     * @return AuthenticatedUsers|null
64
     */
65
    protected function getAuthenticatedUsersFromRequest(): AuthenticatedUsers|null
66
    {
67
        $headerLine = $this->request->getHeaderLine(HeaderName::AUTHORIZATION);
68
69
        if ($headerLine === '') {
70
            return null;
71
        }
72
73
        [$bearer, $token] = explode(' ', $headerLine);
74
75
        if ($bearer !== HeaderValue::BEARER) {
76
            throw new InvalidAuthenticationException('Invalid authorization header');
77
        }
78
79
        return $this->getAuthenticatedUsersFromToken($token);
80
    }
81
82
    /**
83
     * Attempt to get the authenticated users from the token.
84
     *
85
     * @param string $token The token
86
     *
87
     * @return AuthenticatedUsers|null
88
     */
89
    protected function getAuthenticatedUsersFromToken(string $token): AuthenticatedUsers|null
90
    {
91
        $jwtPayload = $this->jwt->decode($token);
92
        $users      = $jwtPayload['users'] ?? null;
93
94
        if (! is_string($users)) {
95
            throw new InvalidAuthenticationException('Invalid token structure. Expecting users');
96
        }
97
98
        $unserializedUsers = unserialize(
99
            $users,
100
            ['allowed_classes' => true]
101
        );
102
103
        if (! $unserializedUsers instanceof AuthenticatedUsers) {
104
            throw new InvalidAuthenticationException('Invalid token structure. Expecting ' . AuthenticatedUsers::class);
105
        }
106
107
        return $unserializedUsers;
108
    }
109
}
110