Completed
Push — develop ( 098751...1bc9e0 )
by Alejandro
16s queued 12s
created

AuthenticationMiddleware   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 41
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 9
eloc 19
dl 0
loc 41
ccs 15
cts 15
cp 1
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
B process() 0 23 7
A __construct() 0 4 1
A apiKeyFromRequest() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Shlinkio\Shlink\Rest\Middleware;
6
7
use Fig\Http\Message\RequestMethodInterface;
8
use Fig\Http\Message\StatusCodeInterface;
9
use Mezzio\Router\RouteResult;
10
use Psr\Http\Message\ResponseInterface as Response;
11
use Psr\Http\Message\ServerRequestInterface as Request;
12
use Psr\Http\Server\MiddlewareInterface;
13
use Psr\Http\Server\RequestHandlerInterface;
14
use Shlinkio\Shlink\Rest\Exception\MissingAuthenticationException;
15
use Shlinkio\Shlink\Rest\Exception\VerifyAuthenticationException;
16
use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface;
17
18
use function Functional\contains;
19
20
class AuthenticationMiddleware implements MiddlewareInterface, StatusCodeInterface, RequestMethodInterface
21
{
22
    public const API_KEY_HEADER = 'X-Api-Key';
23 6
24
    private ApiKeyServiceInterface $apiKeyService;
25 6
    private array $routesWhitelist;
26 6
27 6
    public function __construct(ApiKeyServiceInterface $apiKeyService, array $routesWhitelist)
28
    {
29 6
        $this->apiKeyService = $apiKeyService;
30
        $this->routesWhitelist = $routesWhitelist;
31
    }
32 6
33
    public function process(Request $request, RequestHandlerInterface $handler): Response
34 6
    {
35 6
        /** @var RouteResult|null $routeResult */
36 6
        $routeResult = $request->getAttribute(RouteResult::class);
37 6
        if (
38
            $routeResult === null
39 4
            || $routeResult->isFailure()
40
            || $request->getMethod() === self::METHOD_OPTIONS
41
            || contains($this->routesWhitelist, $routeResult->getMatchedRouteName())
42 2
        ) {
43 2
            return $handler->handle($request);
44 2
        }
45
46 2
        $apiKey = self::apiKeyFromRequest($request);
47
        if (empty($apiKey)) {
48
            throw MissingAuthenticationException::fromExpectedTypes([self::API_KEY_HEADER]);
49
        }
50
51
        if (! $this->apiKeyService->check($apiKey)) {
52
            throw VerifyAuthenticationException::forInvalidApiKey();
53
        }
54
55
        return $handler->handle($request);
56
    }
57
58
    public static function apiKeyFromRequest(Request $request): string
59
    {
60
        return $request->getHeaderLine(self::API_KEY_HEADER);
61
    }
62
}
63