Passed
Branch master (372b2a)
by Filipe
01:32
created

HttpBasicAuthenticator::clear()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 0
c 0
b 0
f 0
dl 0
loc 2
rs 10
cc 1
nc 1
nop 0
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 Psr\Http\Message\ResponseInterface;
15
use Psr\Http\Message\ServerRequestInterface;
16
use Psr\Log\LoggerInterface;
17
use Slick\Http\Message\Response;
18
use Slick\WebStack\Domain\Security\Authentication\Token\UsernamePasswordToken;
19
use Slick\WebStack\Domain\Security\Authentication\TokenInterface;
20
use Slick\WebStack\Domain\Security\Exception\AuthenticationException;
21
use Slick\WebStack\Domain\Security\Http\AuthenticationEntryPointInterface;
22
use Slick\WebStack\Domain\Security\Http\Authenticator\Passport;
23
use Slick\WebStack\Domain\Security\Http\Authenticator\Passport\Badge\Credentials\PasswordCredentials;
24
use Slick\WebStack\Domain\Security\Http\Authenticator\Passport\Badge\UserBadge;
25
use Slick\WebStack\Domain\Security\Http\Authenticator\PassportInterface;
26
use Slick\WebStack\Domain\Security\Http\AuthenticatorInterface;
27
use Slick\WebStack\Domain\Security\SecurityException;
28
use Slick\WebStack\Domain\Security\User\UserProviderInterface;
29
use Slick\WebStack\Domain\Security\UserInterface;
30
31
/**
32
 * HttpBasicAuthenticator
33
 *
34
 * @package Slick\WebStack\Infrastructure\Http\Authenticator
35
 * @template TUser of UserInterface
36
 * @implements AuthenticatorInterface<TUser>
37
 */
38
final class HttpBasicAuthenticator implements AuthenticatorInterface, AuthenticationEntryPointInterface
39
{
40
41
    use AuthenticatorHandlerTrait;
42
43
    /**
44
     * Creates a HttpBasicAuthenticator
45
     *
46
     * @param string $realm
47
     * @param UserProviderInterface<TUser> $provider
48
     * @param LoggerInterface|null $logger
49
     */
50
    public function __construct(
51
        private readonly string                $realm,
52
        private readonly UserProviderInterface $provider,
53
        private readonly ?LoggerInterface      $logger = null
54
    ) {
55
    }
56
57
    /**
58
     * @inheritDoc
59
     */
60
    public function supports(ServerRequestInterface $request): ?bool
61
    {
62
        $serverParams = $request->getServerParams() ?? [];
63
        return array_key_exists('PHP_AUTH_USER', $serverParams);
64
    }
65
66
    /**
67
     * @inheritDoc
68
     * @return Passport<UserInterface>
69
     */
70
    public function authenticate(ServerRequestInterface $request): Passport
71
    {
72
        $serverParams = $request->getServerParams() ?? [];
73
        $username = $serverParams['PHP_AUTH_USER'] ?? null;
74
        $password = $serverParams['PHP_AUTH_PW'] ?? '';
75
76
        $userBadge = new UserBadge($username, $this->provider->loadUserByIdentifier(...));
0 ignored issues
show
Bug introduced by
It seems like $username can also be of type null; however, parameter $userIdentifier of Slick\WebStack\Domain\Se...serBadge::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

76
        $userBadge = new UserBadge(/** @scrutinizer ignore-type */ $username, $this->provider->loadUserByIdentifier(...));
Loading history...
77
        $credentials = new PasswordCredentials($password);
78
79
        return new Passport($userBadge, $credentials);
80
    }
81
82
    /**
83
     * @inheritDoc
84
     * @phpstan-return UsernamePasswordToken<UserInterface>
85
     * @throws SecurityException
86
     */
87
    public function createToken(PassportInterface $passport): UsernamePasswordToken
88
    {
89
        $authToken = new UsernamePasswordToken($passport->user(), $passport->user()->roles());
90
        $authToken->withAttributes([
91
        'IS_AUTHENTICATED_FULLY' => 'true',
92
        'IS_AUTHENTICATED_REMEMBERED' => 'false',
93
        'IS_AUTHENTICATED' => 'true'
94
        ]);
95
        return $authToken;
96
    }
97
98
    /**
99
     * @inheritDoc
100
     */
101
    public function onAuthenticationSuccess(ServerRequestInterface $request, TokenInterface $token): ?ResponseInterface
102
    {
103
        return null;
104
    }
105
106
    /**
107
     * @inheritDoc
108
     */
109
    public function onAuthenticationFailure(
110
        ServerRequestInterface $request,
111
        AuthenticationException $exception
112
    ): ?ResponseInterface {
113
        $serverParams = $request->getServerParams() ?? [];
114
        $this->logger?->info(
115
            'Basic authentication failed for user.',
116
            [
117
            'username' => $serverParams['PHP_AUTH_USER'] ?? '',
118
            'exception' => $exception,
119
            ]
120
        );
121
122
        return $this->start($request);
123
    }
124
125
    /**
126
     * @inheritDoc
127
     */
128
    public function start(
129
        ServerRequestInterface $request,
130
        ?AuthenticationException $authException = null
131
    ): ResponseInterface {
132
        return new Response(401, 'Unauthorized', ['WWW-Authenticate' => sprintf('Basic realm="%s"', $this->realm)]);
133
    }
134
135
    /**
136
     * @inheritDoc
137
     */
138
    public function clear(): void
139
    {
140
        // Do nothing here
141
    }
142
}
143