Passed
Push — master ( 0a6144...1acb0d )
by Mr
02:14
created

JwtAuthenticator::isSecure()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 6
ccs 0
cts 6
cp 0
crap 6
rs 10
c 0
b 0
f 0
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['jwt']['attribute'] ?? JwtDecoder::DEFAULT_ATTR_JWT;
54
        $xsrfAttribute = $authConfig['xsrf']['attribute'] ?? JwtDecoder::DEFAULT_ATTR_XSRF;
55
56
        $jwt = $request->getAttribute($jwtAttribute);
57
        $xsrfToken = $request->getAttribute($xsrfAttribute);
58
59
        try {
60
            if ($requestHandler->isSecure($request)) {
0 ignored issues
show
Unused Code introduced by
The call to Daikon\Security\Middlewa...onInterface::isSecure() has too many arguments starting with $request. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

60
            if ($requestHandler->/** @scrutinizer ignore-call */ isSecure($request)) {

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
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
        return $handler->handle(
84
            $request->withAttribute(self::AUTHENTICATOR, $authenticator ?? new $authConfig['default_role'])
85
        );
86
    }
87
}
88