RememberMeAuthenticator   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 106
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 10
eloc 29
c 0
b 0
f 0
dl 0
loc 106
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A supports() 0 13 3
A __construct() 0 8 1
A onAuthenticationFailure() 0 12 2
A clear() 0 3 1
A createToken() 0 9 1
A onAuthenticationSuccess() 0 3 1
A authenticate() 0 10 1
1
<?php
2
3
/**
4
 * This file is part of php-scaffold
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Slick\WebStack\Infrastructure\Http\Authenticator;
13
14
use Slick\WebStack\Domain\Security\Authentication\Token\RememberMeToken;
15
use Slick\WebStack\Domain\Security\Authentication\Token\TokenStorageInterface;
16
use Slick\WebStack\Domain\Security\Authentication\TokenInterface;
17
use Slick\WebStack\Domain\Security\Exception\AuthenticationException;
18
use Slick\WebStack\Domain\Security\Exception\UserNotFoundException;
19
use Slick\WebStack\Domain\Security\Http\Authenticator\AuthenticatorHandlerInterface;
20
use Slick\WebStack\Domain\Security\Http\Authenticator\Passport;
21
use Slick\WebStack\Domain\Security\Http\Authenticator\PassportInterface;
22
use Slick\WebStack\Domain\Security\Http\Authenticator\SelfValidatingPassport;
23
use Slick\WebStack\Domain\Security\Http\AuthenticatorInterface;
24
use Slick\WebStack\Domain\Security\Http\RememberMe\RememberMeDetails;
25
use Slick\WebStack\Domain\Security\Http\RememberMe\RememberMeHandlerInterface;
26
use Slick\WebStack\Domain\Security\SecurityException;
27
use Slick\WebStack\Domain\Security\UserInterface;
28
use Psr\Http\Message\ResponseInterface;
29
use Psr\Http\Message\ServerRequestInterface;
30
use Psr\Log\LoggerInterface;
31
use SensitiveParameter;
0 ignored issues
show
Bug introduced by
The type SensitiveParameter 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...
32
33
/**
34
 * RememberMeAuthenticator
35
 *
36
 * @package Slick\WebStack\Domain\Security\Http
37
 *
38
 * @template-covariant TUser of UserInterface
39
 * @implements AuthenticatorInterface<TUser>
40
 */
41
final class RememberMeAuthenticator implements AuthenticatorInterface
42
{
43
    use AuthenticatorHandlerTrait;
44
45
    public const COOKIE_NAME = 'remember_me';
46
47
    /**
48
     * Creates a RememberMeAuthenticator
49
     *
50
     * @param RememberMeHandlerInterface $rememberMeHandler
51
     * @param string $secret
52
     * @param TokenStorageInterface<TUser> $tokenStorage
53
     * @param string|null $cookieName
54
     * @param LoggerInterface|null $logger
55
     */
56
    public function __construct(
57
        private readonly RememberMeHandlerInterface $rememberMeHandler,
58
        #[SensitiveParameter]
59
        private readonly string $secret,
60
        private readonly TokenStorageInterface $tokenStorage,
61
        private readonly ?string $cookieName = self::COOKIE_NAME,
62
        private readonly ?LoggerInterface $logger = null
63
    ) {
64
    }
65
66
    /**
67
     * @inheritDoc
68
     */
69
    public function supports(ServerRequestInterface $request): bool
70
    {
71
        if (null !== $this->tokenStorage->getToken()) {
72
            return false;
73
        }
74
75
        $cookies = $request->getCookieParams();
76
        if (!array_key_exists($this->cookieName ?? '', $cookies)) {
77
            return false;
78
        }
79
80
        $this->logger?->debug('Remember-me cookie detected.');
81
        return true;
82
    }
83
84
    /**
85
     * @inheritDoc
86
     * @return SelfValidatingPassport<UserInterface>
87
     */
88
    public function authenticate(ServerRequestInterface $request): SelfValidatingPassport
89
    {
90
        $cookies = $request->getCookieParams();
91
        $rememberMeCookie = RememberMeDetails::fromRawCookie($cookies[$this->cookieName] ?? '');
92
        $userBadge = new Passport\Badge\UserBadge(
93
            $rememberMeCookie->userIdentifier(),
94
            fn () => $this->rememberMeHandler->consumeRememberMeCookie($rememberMeCookie)
95
        );
96
97
        return new SelfValidatingPassport($userBadge);
98
    }
99
100
    /**
101
     * @inheritDoc
102
     * @return RememberMeToken
103
     * @throws SecurityException
104
     */
105
    public function createToken(PassportInterface $passport): TokenInterface
106
    {
107
        $rememberMeToken = new RememberMeToken($passport->user(), $this->secret);
108
        $rememberMeToken->withAttributes([
109
            'IS_AUTHENTICATED_FULLY' => 'false',
110
            'IS_AUTHENTICATED_REMEMBERED' => 'true',
111
            'IS_AUTHENTICATED' => 'true'
112
        ]);
113
        return $rememberMeToken;
114
    }
115
116
    /**
117
     * @inheritDoc
118
     */
119
    public function onAuthenticationSuccess(ServerRequestInterface $request, TokenInterface $token): ?ResponseInterface
120
    {
121
        return null;
122
    }
123
124
    /**
125
     * @inheritDoc
126
     */
127
    public function onAuthenticationFailure(
128
        ServerRequestInterface $request,
129
        AuthenticationException $exception
130
    ): ?ResponseInterface {
131
        if ($exception instanceof UserNotFoundException) {
132
            $this->logger?->info('User for remember-me cookie not found.', ['exception' => $exception]);
133
            return null;
134
        }
135
136
        $this->logger?->debug('Remember me authentication failed.', ['exception' => $exception]);
137
138
        return null;
139
    }
140
141
    /**
142
     * @inheritDoc
143
     */
144
    public function clear(): void
145
    {
146
        $this->rememberMeHandler->clearRememberMeCookie();
147
    }
148
}
149