Passed
Push — master ( 5679ef...aad9e9 )
by Kirill
04:11
created

AuthMiddleware   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 110
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 9
eloc 40
c 1
b 0
f 0
dl 0
loc 110
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A closeContext() 0 23 3
A initContext() 0 19 4
A process() 0 12 1
1
<?php
2
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Spiral\Auth\Middleware;
13
14
use Psr\Http\Message\ResponseInterface;
15
use Psr\Http\Message\ResponseInterface as Response;
16
use Psr\Http\Message\ServerRequestInterface;
17
use Psr\Http\Message\ServerRequestInterface as Request;
18
use Psr\Http\Server\MiddlewareInterface;
19
use Psr\Http\Server\RequestHandlerInterface;
20
use Spiral\Auth\ActorProviderInterface;
21
use Spiral\Auth\AuthContext;
22
use Spiral\Auth\AuthContextInterface;
23
use Spiral\Auth\TokenStorageInterface;
24
use Spiral\Auth\TransportRegistry;
25
use Spiral\Core\ScopeInterface;
26
27
/**
28
 * Manages auth context scope.
29
 */
30
final class AuthMiddleware implements MiddlewareInterface
31
{
32
    public const ATTRIBUTE = 'authContext';
33
34
    /** @var ScopeInterface */
35
    private $scope;
36
37
    /** @var ActorProviderInterface */
38
    private $actorProvider;
39
40
    /** @var TokenStorageInterface */
41
    private $tokenStorage;
42
43
    /** @var TransportRegistry */
44
    private $transportRegistry;
45
46
    /**
47
     * @param ScopeInterface         $scope
48
     * @param ActorProviderInterface $actorProvider
49
     * @param TokenStorageInterface  $tokenStorage
50
     * @param TransportRegistry      $transportRegistry
51
     */
52
    public function __construct(
53
        ScopeInterface $scope,
54
        ActorProviderInterface $actorProvider,
55
        TokenStorageInterface $tokenStorage,
56
        TransportRegistry $transportRegistry
57
    ) {
58
        $this->scope = $scope;
59
        $this->actorProvider = $actorProvider;
60
        $this->tokenStorage = $tokenStorage;
61
        $this->transportRegistry = $transportRegistry;
62
    }
63
64
    /**
65
     * @param ServerRequestInterface  $request
66
     * @param RequestHandlerInterface $handler
67
     * @return ResponseInterface
68
     *
69
     * @throws \Throwable
70
     */
71
    public function process(Request $request, RequestHandlerInterface $handler): Response
72
    {
73
        $authContext = $this->initContext($request, new AuthContext($this->actorProvider));
74
75
        $response = $this->scope->runScope(
76
            [AuthContextInterface::class => $authContext],
77
            static function () use ($request, $handler, $authContext) {
78
                return $handler->handle($request->withAttribute(self::ATTRIBUTE, $authContext));
79
            }
80
        );
81
82
        return $this->closeContext($request, $response, $authContext);
83
    }
84
85
    /**
86
     * @param Request              $request
87
     * @param AuthContextInterface $authContext
88
     * @return AuthContextInterface
89
     */
90
    private function initContext(Request $request, AuthContextInterface $authContext): AuthContextInterface
91
    {
92
        foreach ($this->transportRegistry->getTransports() as $name => $transport) {
93
            $tokenID = $transport->fetchToken($request);
94
            if ($tokenID === null) {
95
                continue;
96
            }
97
98
            $token = $this->tokenStorage->load($tokenID);
99
            if ($token === null) {
100
                continue;
101
            }
102
103
            // found valid token
104
            $authContext->start($token, $name);
105
            return $authContext;
106
        }
107
108
        return $authContext;
109
    }
110
111
    /**
112
     * @param Request              $request
113
     * @param Response             $response
114
     * @param AuthContextInterface $authContext
115
     * @return Response
116
     */
117
    private function closeContext(Request $request, Response $response, AuthContextInterface $authContext): Response
118
    {
119
        if ($authContext->getToken() === null) {
120
            return $response;
121
        }
122
123
        $transport = $this->transportRegistry->getTransport($authContext->getTransport());
124
125
        if ($authContext->isClosed()) {
126
            $this->tokenStorage->delete($authContext->getToken());
127
128
            return $transport->removeToken(
129
                $request,
130
                $response,
131
                $authContext->getToken()->getID()
132
            );
133
        }
134
135
        return $transport->commitToken(
136
            $request,
137
            $response,
138
            $authContext->getToken()->getID(),
139
            $authContext->getToken()->getExpiresAt()
140
        );
141
    }
142
}
143