Passed
Push — master ( 48c1a2...2aced3 )
by Alexpts
02:05
created

CheckJwtToken::setCookieNameWithIp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 3
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
crap 2
1
<?php
2
declare(strict_types=1);
3
4
namespace PTS\CheckJwtToken;
5
6
use Emarref\Jwt\Token;
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 PTS\JwtService\JwtService;
12
13
class CheckJwtToken implements MiddlewareInterface
14
{
15
16
    /** @var string */
17
    protected $tokenAttr = 'token';
18
    /** @var string */
19
    protected $ipAttr = 'client-ip';
20
    /** @var string */
21
    protected $cookieName = 'auth_token';
22
    /** @var JwtService */
23
    protected $jwtService;
24
    /** @var bool */
25
    protected $checkIp = true;
26
    /** @var bool */
27
    protected $cookieNameWithIp = true;
28
29
    /**
30
     * @param JwtService $jwtService
31
     */
32
    public function __construct(JwtService $jwtService)
33
    {
34
        $this->jwtService = $jwtService;
35
    }
36
37
    /**
38
     * @param bool $checkIp
39
     *
40
     * @return $this
41
     */
42
    public function setCheckIp(bool $checkIp): self
43
    {
44
        $this->checkIp = $checkIp;
45
        return $this;
46
    }
47
48
    /**
49
     * @param string $cookieName
50
     *
51
     * @return $this
52
     */
53
    public function setCookieName(string $cookieName): self
54
    {
55
        $this->cookieName = $cookieName;
56
        return $this;
57
    }
58
59
    /**
60
     * @param bool $cookieNameWithIp
61
     *
62
     * @return $this
63
     */
64
    public function setCookieNameWithIp(bool $cookieNameWithIp): self
65
    {
66
        $this->cookieNameWithIp = $cookieNameWithIp;
67
        return $this;
68
    }
69
70
    /**
71
     * @param string $attr
72
     *
73
     * @return $this
74
     */
75
    public function setIpAttr(string $attr): self
76
    {
77
        $this->ipAttr = $attr;
78
        return $this;
79
    }
80
81
    /**
82
     * @param string $attr
83
     *
84
     * @return $this
85
     */
86
    public function setTokenAttr(string $attr): self
87
    {
88
        $this->tokenAttr = $attr;
89
        return $this;
90
    }
91
92
    /**
93
     * @inheritdoc
94
     * @throws TokenException
95
     */
96
    public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
97
    {
98
        $jwtToken = $this->getTokenFromRequest($request);
99
100
        if (null === $jwtToken) {
101
            return $next->handle($request);
102
        }
103
104
        try {
105
            $token = $this->jwtService->decode($jwtToken);
106
            $this->jwtService->verify($token);
107
108
            $clientIp = $request->getAttribute($this->ipAttr);
109
            $this->checkTokenIp($token, $clientIp);
110
111
            $request = $request->withAttribute($this->tokenAttr, $token);
112
        } catch (\Exception $e) {
113
            throw new TokenException('Bad token', 401, $e);
114
        }
115
116
        return $next->handle($request);
117
    }
118
119
    /**
120
     * @param Token $token
121
     * @param string|null $clientIp
122
     *
123
     * @throws TokenException
124
     */
125
    protected function checkTokenIp(Token $token, string $clientIp = null): void
126
    {
127
        if ($this->checkIp) {
128
            $tokenIp = $this->getIpFromToken($token);
129
130
            if ($tokenIp && $clientIp !== $tokenIp) {
131
                throw new TokenException('Token not valid for this ip');
132
            }
133
        }
134
    }
135
136
    protected function getIpFromToken(Token $token): ?string
137
    {
138
        $tokenIp = $token->getPayload()->findClaimByName('ip');
139
        return $tokenIp !== null ? $tokenIp->getValue() : null;
140
    }
141
142
    /**
143
     * @param ServerRequestInterface $request
144
     *
145
     * @return null|string
146
     */
147
    protected function getTokenFromRequest(ServerRequestInterface $request): ?string
148
    {
149
        return $request->hasHeader('Authorization')
150
            ? $this->getTokenFromBearerHeader($request)
151
            : $this->getTokenFromCookie($request);
152
    }
153
154
    /**
155
     * @param ServerRequestInterface $request
156
     *
157
     * @return null|string
158
     */
159 3
    protected function getTokenFromBearerHeader(ServerRequestInterface $request): ?string
160
    {
161 3
        $header = $request->getHeader('Authorization');
162 3
        list($type, $value) = explode(' ', $header[0]);
163
164 3
        return $type === 'Bearer' ? $value : null;
165
    }
166
167
    /**
168
     * @param ServerRequestInterface $request
169
     *
170
     * @return null|string
171
     */
172 5
    protected function getTokenFromCookie(ServerRequestInterface $request): ?string
173
    {
174 5
        $cookiesData = $request->getCookieParams();
175 5
        $cookieName = $this->getCookieName($request);
176
177 5
        return $cookiesData[$cookieName] ??  null;
178
    }
179
180 5
    protected function getCookieName(ServerRequestInterface $request): string
181
    {
182 5
        if (!$this->cookieNameWithIp) {
183
            return $this->cookieName;
184
        }
185
186 5
        return $this->cookieName.'_'.$request->getAttribute($this->ipAttr);
187
    }
188
}
189