JwtAuthMiddleware   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 100
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 9
lcom 1
cbo 8
dl 0
loc 100
c 0
b 0
f 0
ccs 32
cts 32
cp 1
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
B process() 0 53 8
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Soluble\Wallit\Middleware;
6
7
use Psr\Http\Message\ServerRequestInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use Psr\Http\Server\MiddlewareInterface;
10
use Psr\Http\Server\RequestHandlerInterface;
11
use Zend\Diactoros\Response\JsonResponse;
12
use Zend\Diactoros\Response\RedirectResponse;
13
use Soluble\Wallit\Service\JwtService;
14
use Soluble\Wallit\Token\Provider\ServerRequestLazyChainProvider;
15
16
class JwtAuthMiddleware implements MiddlewareInterface
17
{
18
    public const DEFAULT_OPTIONS = [
19
        self::OPTION_ALLOW_INSECURE_HTTP => false,
20
        self::OPTION_RELAXED_HOSTS       => [],
21
    ];
22
23
    public const OPTION_ALLOW_INSECURE_HTTP = 'allow_insecure_http';
24
    public const OPTION_RELAXED_HOSTS = 'relaxed_hosts';
25
26
    /**
27
     * @var array
28
     */
29
    protected $tokenProviders = [];
30
31
    /**
32
     * @var JwtService
33
     */
34
    protected $jwtService;
35
36
    /**
37
     * @var array
38
     */
39
    protected $options;
40
41
    /**
42
     * JwtAuthMiddleware constructor.
43
     *
44
     * @param mixed[] $tokenProviders lazy loaded token providers
45
     * @param mixed[] $options
46
     */
47 8
    public function __construct(
48
                    array $tokenProviders,
49
                    JwtService $jwtService,
50
                    array $options = []
51
    ) {
52 8
        $this->tokenProviders = $tokenProviders;
53 8
        $this->jwtService = $jwtService;
54 8
        $this->options = array_merge(self::DEFAULT_OPTIONS, $options);
55 8
    }
56
57
    /**
58
     * @throws Exception\InsecureSchemeException
59
     *
60
     * @return ResponseInterface|RedirectResponse
61
     */
62 8
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
63
    {
64
        // 1. Check for secure scheme (with exception of relaxed_hosts)
65 8
        $scheme = strtolower($request->getUri()->getScheme());
66
67 8
        if ($this->options['allow_insecure_http'] !== true && $scheme !== 'https') {
68 2
            $host = $request->getUri()->getHost();
69 2
            $relaxed_hosts = (array) $this->options['relaxed_hosts'];
70 2
            if (!in_array($host, $relaxed_hosts, true)) {
71 1
                throw new Exception\InsecureSchemeException(sprintf(
72 1
                    'Insecure scheme (%s) denied by configuration.',
73 1
                    $scheme
74
                ));
75
            }
76
        }
77
78
        // 2. Fetch token from server request
79
80 7
        $tokenProvider = new ServerRequestLazyChainProvider($request, $this->tokenProviders);
81
82 7
        $plainToken = $tokenProvider->getPlainToken();
83
84
        // 3. Validate the token
85 7
        if ($plainToken !== null) {
86
            try {
87 6
                $token = $this->jwtService->parsePlainToken($plainToken);
88
89 5
                if ($token->verify($this->jwtService->getSigner(), $this->jwtService->getPrivateKey())) {
90 4
                    if ($token->isExpired()) {
91 1
                        $message = 'Token has expired';
92
                    } else {
93
                        // Authenticated
94 4
                        return $handler->handle($request->withAttribute(self::class, $token));
95
                    }
96
                } else {
97 2
                    $message = 'Token is invalid';
98
                }
99 1
            } catch (\Throwable $e) {
100
                // log something ?
101 3
                $message = 'Token error while parsing plain text';
102
            }
103
        } else {
104 1
            $message = 'No token provided';
105
        }
106
107 4
        $error = new JsonResponse([
108 4
            'message' => 'Unauthorized.',
109 4
            'reason'  => $message,
110 4
            'code'    => 401
111 4
        ], 401, []);
112
113 4
        return $error;
114
    }
115
}
116