Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
45 / 45
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
AuthController
100.00% covered (success)
100.00%
45 / 45
100.00% covered (success)
100.00%
3 / 3
9
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 login
100.00% covered (success)
100.00%
35 / 35
100.00% covered (success)
100.00%
1 / 1
7
 logout
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace App\Web\Controller;
6
7use App\Domain\Auth\Form\LoginForm;
8use App\Domain\Auth\Service\Authenticator;
9use App\Domain\Auth\Service\AuthLogService;
10use App\Shared\Security\AuthMiddleware;
11use Psr\Http\Message\ResponseInterface;
12use Psr\Http\Message\ServerRequestInterface;
13use Yiisoft\DataResponse\DataResponseFactoryInterface;
14use Yiisoft\Http\Header;
15use Yiisoft\Http\Method;
16use Yiisoft\Session\SessionInterface;
17use Yiisoft\Yii\View\Renderer\WebViewRenderer;
18
19 class AuthController
20{
21    public function __construct(
22        private WebViewRenderer $viewRenderer,
23        private Authenticator $authenticator,
24        private AuthLogService $authLogService,
25        private SessionInterface $session
26    ) {
27        $this->viewRenderer = $viewRenderer->withControllerName('auth')->withLayout(null);
28    }
29
30    public function login(ServerRequestInterface $request, DataResponseFactoryInterface $responseFactory): ResponseInterface
31    {
32        if ($this->session->has('user_id')) {
33            return $responseFactory
34                ->createResponse('', 302)
35                ->withHeader(Header::LOCATION, '/dashboard');
36        }
37
38        $error = null;
39
40        if ($request->getMethod() === Method::POST) {
41            $form = (new LoginForm())->load((array) $request->getParsedBody());
42            $validationError = $form->validate();
43
44            if ($validationError !== null) {
45                $error = $validationError;
46            } else {
47                $ip = (string) ($request->getServerParams()['REMOTE_ADDR'] ?? '127.0.0.1');
48                $authResult = $this->authenticator->attemptAuthentication($form->getUsername(), $form->getPassword(), $ip);
49
50                if ($authResult->isSuccess() && $authResult->user !== null) {
51                    $user = $authResult->user;
52                    $this->session->regenerateID();
53                    $this->session->set('user_id', $user->id);
54                    $this->authLogService->logSuccess((int) $user->id, $ip);
55
56                    $response = $responseFactory
57                        ->createResponse('', 302)
58                        ->withHeader(Header::LOCATION, '/dashboard');
59
60                    if ($form->isRememberMe()) {
61                        $expires = gmdate('D, d M Y H:i:s \G\M\T', time() + (30 * 86400));
62                        $cookieValue = sprintf(
63                            '%s=%s; Expires=%s; Path=/; HttpOnly; SameSite=Strict',
64                            AuthMiddleware::REMEMBER_COOKIE_NAME,
65                            $user->authKey,
66                            $expires
67                        );
68                        $response = $response->withAddedHeader(Header::SET_COOKIE, $cookieValue);
69                    }
70
71                    return $response;
72                }
73
74                $this->authLogService->logFailure($ip, $authResult->attemptedUserId, $authResult->cause);
75                $error = 'Nieprawidłowy login lub hasło.';
76            }
77        }
78
79        return $this->viewRenderer->render('//auth/login.twig', [
80            'error' => $error,
81        ]);
82    }
83
84    public function logout(DataResponseFactoryInterface $responseFactory): ResponseInterface
85    {
86        $this->session->destroy();
87
88        $clearCookie = sprintf(
89            '%s=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; HttpOnly; SameSite=Strict',
90            AuthMiddleware::REMEMBER_COOKIE_NAME
91        );
92
93        return $responseFactory
94            ->createResponse('', 302)
95            ->withHeader(Header::LOCATION, '/login')
96            ->withHeader(Header::SET_COOKIE, $clearCookie);
97    }
98}