JwtAuthenticator::process()   B
last analyzed

Complexity

Conditions 10
Paths 14

Size

Total Lines 45
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
eloc 27
c 2
b 0
f 0
nc 14
nop 2
dl 0
loc 45
ccs 0
cts 25
cp 0
crap 110
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
/**
3
 * This file is part of the daikon-cqrs/security-interop project.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace Daikon\Security\Middleware;
10
11
use Daikon\Boot\Middleware\RoutingHandler;
12
use Daikon\Config\ConfigProviderInterface;
13
use Daikon\Interop\Assertion;
14
use Daikon\Security\Authentication\AuthenticatorInterface;
15
use Daikon\Security\Authentication\JwtAuthenticationServiceInterface;
16
use Daikon\Security\Exception\AuthenticationException;
17
use Daikon\Security\Middleware\Action\SecureActionInterface;
18
use Fig\Http\Message\StatusCodeInterface;
19
use Middlewares\Utils\Factory;
20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
use Psr\Http\Server\MiddlewareInterface;
23
use Psr\Http\Server\RequestHandlerInterface;
24
25
final class JwtAuthenticator implements MiddlewareInterface, StatusCodeInterface
26
{
27
    public const AUTHENTICATOR = '_authenticator';
28
29
    private ConfigProviderInterface $config;
30
31
    private JwtAuthenticationServiceInterface $authenticationService;
32
33
    public function __construct(
34
        ConfigProviderInterface $config,
35
        JwtAuthenticationServiceInterface $authenticationService
36
    ) {
37
        $this->config = $config;
38
        $this->authenticationService = $authenticationService;
39
    }
40
41
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
42
    {
43
        $requestHandler = $request->getAttribute(RoutingHandler::REQUEST_HANDLER);
44
        if (!$requestHandler instanceof SecureActionInterface) {
45
            return $handler->handle($request);
46
        }
47
48
        $authConfig = $this->config->get('project.authentication', []);
49
        Assertion::true(
50
            is_a($authConfig['default_role'], AuthenticatorInterface::class, true),
51
            sprintf("Authentication default role must implement '%s'.", AuthenticatorInterface::class)
52
        );
53
        $jwtAttribute = $authConfig['cookies']['jwt']['attribute'] ?? JwtDecoder::DEFAULT_ATTR_JWT;
54
        $xsrfAttribute = $authConfig['cookies']['xsrf']['attribute'] ?? JwtDecoder::DEFAULT_ATTR_XSRF;
55
56
        $jwt = $request->getAttribute($jwtAttribute);
57
        $xsrfToken = $request->getAttribute($xsrfAttribute);
58
59
        try {
60
            if ($requestHandler->isSecure()) {
61
                if (!$jwt) {
62
                    throw new AuthenticationException('Missing JWT.');
63
                }
64
                if (!$xsrfToken) {
65
                    throw new AuthenticationException('Missing XSRF token.');
66
                }
67
            }
68
69
            if ($jwt) {
70
                if (!$jwt->uid || !$jwt->jti) {
71
                    throw new AuthenticationException('Invalid JWT.');
72
                }
73
                if ($jwt->xsrf !== $xsrfToken) {
74
                    throw new AuthenticationException('XSRF token does not match JWT.');
75
                }
76
                /** @var AuthenticatorInterface $authenticator */
77
                $authenticator = $this->authenticationService->authenticateJWT($jwt->uid, $jwt->jti, $jwt->xsrf);
78
            }
79
        } catch (AuthenticationException $error) {
80
            return Factory::createResponse(self::STATUS_UNAUTHORIZED);
81
        }
82
83
        /** @psalm-suppress UndefinedClass */
84
        return $handler->handle(
85
            $request->withAttribute(self::AUTHENTICATOR, $authenticator ?? new $authConfig['default_role'])
86
        );
87
    }
88
}
89