Passed
Push — master ( 2ca186...7f83bc )
by Alexander
05:08 queued 02:48
created

AutoLoginMiddleware::process()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 11
c 1
b 0
f 0
nc 6
nop 2
dl 0
loc 19
ccs 12
cts 12
cp 1
crap 7
rs 8.8333
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\User;
6
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Psr\Http\Server\MiddlewareInterface;
10
use Psr\Http\Server\RequestHandlerInterface;
11
use Psr\Log\LoggerInterface;
12
use Yiisoft\Auth\IdentityRepositoryInterface;
13
14
/**
15
 * AutoLoginMiddleware automatically logs user in based on cookie.
16
 */
17
final class AutoLoginMiddleware implements MiddlewareInterface
18
{
19
    private User $user;
20
    private IdentityRepositoryInterface $identityRepository;
21
    private LoggerInterface $logger;
22
    private AutoLogin $autoLogin;
23
    private bool $addCookie;
24
25 11
    public function __construct(
26
        User $user,
27
        IdentityRepositoryInterface $identityRepository,
28
        LoggerInterface $logger,
29
        AutoLogin $autoLogin,
30
        bool $addCookie = false
31
    ) {
32 11
        $this->user = $user;
33 11
        $this->identityRepository = $identityRepository;
34 11
        $this->logger = $logger;
35 11
        $this->autoLogin = $autoLogin;
36 11
        $this->addCookie = $addCookie;
37 11
    }
38
39 11
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
40
    {
41 11
        $this->authenticateUserByCookieFromRequest($request);
42 10
        $guestBeforeHandle = $this->user->isGuest();
43 10
        $response = $handler->handle($request);
44 10
        $guestAfterHandle = $this->user->isGuest();
45
46 10
        if ($this->addCookie && $guestBeforeHandle && !$guestAfterHandle) {
47 2
            $identity = $this->user->getIdentity(false);
48 2
            if ($identity instanceof AutoLoginIdentityInterface) {
49 2
                $response = $this->autoLogin->addCookie($identity, $response);
50
            }
51
        }
52
53 10
        if (!$guestBeforeHandle && $guestAfterHandle) {
54 1
            $response = $this->autoLogin->expireCookie($response);
55
        }
56
57 10
        return $response;
58
    }
59
60
    /**
61
     * Authenticate user by auto login cookie from request.
62
     *
63
     * @param ServerRequestInterface $request Request instance containing auto login cookie.
64
     */
65 11
    private function authenticateUserByCookieFromRequest(ServerRequestInterface $request): void
66
    {
67 11
        $cookieName = $this->autoLogin->getCookieName();
68 11
        $cookies = $request->getCookieParams();
69
70 11
        if (!array_key_exists($cookieName, $cookies)) {
71 1
            return;
72
        }
73
74
        try {
75 10
            $data = json_decode((string)$cookies[$cookieName], true, 512, JSON_THROW_ON_ERROR);
76 1
        } catch (\Exception $e) {
77 1
            $this->logger->warning('Unable to authenticate user by cookie. Invalid cookie.');
78 1
            return;
79
        }
80
81 9
        if (!is_array($data) || count($data) !== 2) {
82 1
            $this->logger->warning('Unable to authenticate user by cookie. Invalid cookie.');
83 1
            return;
84
        }
85
86 8
        [$id, $key] = $data;
87 8
        $id = (string)$id;
88 8
        $key = (string)$key;
89
90 8
        $identity = $this->identityRepository->findIdentity($id);
91
92 8
        if ($identity === null) {
93 1
            $this->logger->warning("Unable to authenticate user by cookie. Identity \"$id\" not found.");
94 1
            return;
95
        }
96
97 7
        if (!$identity instanceof AutoLoginIdentityInterface) {
98 1
            throw new \RuntimeException('Identity repository must return an instance of \Yiisoft\User\AutoLoginIdentityInterface in order for auto-login to function.');
99
        }
100
101 6
        if (!$identity->validateAutoLoginKey($key)) {
102 1
            $this->logger->warning('Unable to authenticate user by cookie. Invalid key.');
103 1
            return;
104
        }
105
106 5
        $this->user->login($identity);
107 5
    }
108
}
109