1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Facile\OpenIDClient\Middleware; |
||
6 | |||
7 | use function class_exists; |
||
8 | use Dflydev\FigCookies\Cookies; |
||
9 | use Dflydev\FigCookies\FigResponseCookies; |
||
10 | use Dflydev\FigCookies\Modifier\SameSite; |
||
11 | use Dflydev\FigCookies\SetCookie; |
||
12 | use Facile\OpenIDClient\Exception\LogicException; |
||
13 | use Facile\OpenIDClient\Exception\RuntimeException; |
||
14 | use Facile\OpenIDClient\Session\AuthSession; |
||
15 | use Facile\OpenIDClient\Session\AuthSessionInterface; |
||
16 | use function is_array; |
||
17 | use function json_decode; |
||
18 | use function json_encode; |
||
19 | use Psr\Http\Message\ResponseInterface; |
||
20 | use Psr\Http\Message\ServerRequestInterface; |
||
21 | use Psr\Http\Server\MiddlewareInterface; |
||
22 | use Psr\Http\Server\RequestHandlerInterface; |
||
23 | use Psr\SimpleCache\CacheInterface; |
||
24 | |||
25 | /** |
||
26 | * @psalm-import-type AuthSessionType from AuthSessionInterface |
||
27 | */ |
||
28 | class SessionCookieMiddleware implements MiddlewareInterface |
||
29 | { |
||
30 | public const SESSION_ATTRIBUTE = AuthSessionInterface::class; |
||
31 | |||
32 | /** @var string */ |
||
33 | private $cookieName; |
||
34 | |||
35 | /** @var int */ |
||
36 | private $ttl; |
||
37 | |||
38 | /** @var CacheInterface */ |
||
39 | private $cache; |
||
40 | |||
41 | public function __construct(CacheInterface $cache, string $cookieName = 'openid', int $ttl = 300) |
||
42 | { |
||
43 | $this->cache = $cache; |
||
44 | $this->cookieName = $cookieName; |
||
45 | $this->ttl = $ttl; |
||
46 | } |
||
47 | |||
48 | public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface |
||
49 | { |
||
50 | if (! class_exists(Cookies::class)) { |
||
51 | throw new LogicException('To use the SessionCookieMiddleware you should install dflydev/fig-cookies package'); |
||
52 | } |
||
53 | |||
54 | $cookies = Cookies::fromRequest($request); |
||
55 | $sessionCookie = $cookies->get($this->cookieName); |
||
56 | |||
57 | $sessionId = null !== $sessionCookie ? $sessionCookie->getValue() : null; |
||
58 | /** @var string|null $sessionValue */ |
||
59 | $sessionValue = null !== $sessionId ? $this->cache->get($sessionId) : null; |
||
60 | /** @var false|AuthSessionType $data */ |
||
61 | $data = null !== $sessionValue ? json_decode($sessionValue, true) : []; |
||
62 | |||
63 | if (! is_array($data)) { |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
64 | $data = []; |
||
65 | } |
||
66 | |||
67 | $authSession = AuthSession::fromArray($data); |
||
68 | |||
69 | $response = $handler->handle($request->withAttribute(self::SESSION_ATTRIBUTE, $authSession)); |
||
70 | |||
71 | $sessionId = $sessionId ?? bin2hex(random_bytes(32)); |
||
72 | |||
73 | /** @var string $sessionValue */ |
||
74 | $sessionValue = json_encode($authSession); |
||
75 | |||
76 | if (false === $this->cache->set($sessionId, $sessionValue, $this->ttl)) { |
||
77 | throw new RuntimeException('Unable to save session'); |
||
78 | } |
||
79 | |||
80 | $sessionCookie = SetCookie::create($this->cookieName) |
||
81 | ->withValue($sessionId) |
||
82 | ->withMaxAge($this->ttl) |
||
83 | ->withHttpOnly() |
||
84 | ->withPath('/') |
||
85 | ->withSameSite(SameSite::strict()); |
||
86 | |||
87 | $response = FigResponseCookies::set($response, $sessionCookie); |
||
88 | |||
89 | return $response; |
||
90 | } |
||
91 | } |
||
92 |