PassportMiddleware::handle()   B
last analyzed

Complexity

Conditions 8
Paths 5

Size

Total Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 8

Importance

Changes 0
Metric Value
dl 0
loc 39
ccs 19
cts 19
cp 1
rs 8.0515
c 0
b 0
f 0
cc 8
nc 5
nop 3
crap 8
1
<?php declare(strict_types=1);
2
3
namespace Limoncello\Passport\Authentication;
4
5
/**
6
 * Copyright 2015-2019 [email protected]
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 * http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
use Closure;
22
use Limoncello\Contracts\Application\MiddlewareInterface;
23
use Limoncello\Contracts\Passport\PassportAccountManagerInterface;
24
use Limoncello\Contracts\Settings\SettingsProviderInterface;
25
use Limoncello\Passport\Exceptions\AuthenticationException;
26
use Limoncello\Passport\Package\PassportSettings as S;
27
use Psr\Container\ContainerInterface;
28
use Psr\Http\Message\ResponseInterface;
29
use Psr\Http\Message\ServerRequestInterface;
30
use Psr\Log\LoggerInterface;
31
use Zend\Diactoros\Response\EmptyResponse;
32
use function assert;
33
use function call_user_func;
34
use function is_callable;
35
use function is_string;
36
use function substr;
37
38
/**
39
 * @package Limoncello\Passport
40
 */
41
class PassportMiddleware implements MiddlewareInterface
42
{
43
    /** Middleware handler */
44
    const HANDLER = [self::class, self::MIDDLEWARE_METHOD_NAME];
45
46
    /**
47
     * @inheritdoc
48
     *
49
     * @SuppressWarnings(PHPMD.ElseExpression)
50
     */
51 3
    public static function handle(
52
        ServerRequestInterface $request,
53
        Closure $next,
54
        ContainerInterface $container
55
    ): ResponseInterface {
56 3
        $header = $request->getHeader('Authorization');
57
        // if value has Bearer token and it is a valid json with 2 required fields and they are strings
58 3
        if (empty($header) === false &&
59 3
            substr($value = $header[0], 0, 7) === 'Bearer ' &&
60 3
            is_string($tokenValue = substr($value, 7)) === true &&
61 3
            empty($tokenValue) === false
62
        ) {
63 2
            assert($container->has(PassportAccountManagerInterface::class));
64
65
            /** @var PassportAccountManagerInterface $accountManager */
66 2
            $accountManager = $container->get(PassportAccountManagerInterface::class);
67
            try {
68 2
                $accountManager->setAccountWithTokenValue($tokenValue);
69 1
            } catch (AuthenticationException $exception) {
70 1
                if (($logger = static::getLoggerIfEnabled($container)) !== null) {
71 1
                    $logger->info(
72 1
                        'Passport authentication failed for a given Bearer token value.',
73 1
                        ['token' => $tokenValue]
74
                    );
75
                }
76
77 2
                return static::createAuthenticationFailedResponse($container);
78
            }
79
        } else {
80 1
            if (($logger = static::getLoggerIfEnabled($container)) !== null) {
81 1
                $logger->debug(
82 1
                    'No Bearer token for Passport authentication. The request is not authenticated.'
83
                );
84
            }
85
        }
86
87
        // call next middleware handler
88 2
        return $next($request);
89
    }
90
91
    /**
92
     * @param ContainerInterface $container
93
     *
94
     * @return ResponseInterface
95
     */
96 1
    protected static function createAuthenticationFailedResponse(ContainerInterface $container): ResponseInterface
97
    {
98
        /** @var SettingsProviderInterface $provider */
99 1
        $provider = $container->get(SettingsProviderInterface::class);
100 1
        $settings = $provider->get(S::class);
101 1
        $factory  = $settings[S::KEY_FAILED_CUSTOM_UNAUTHENTICATED_FACTORY] ?? null;
102
103 1
        assert($factory === null || is_callable($factory) === true);
104
105 1
        $response = $factory === null ? new EmptyResponse(401) : call_user_func($factory);
106
107 1
        return $response;
108
    }
109
110
    /**
111
     * @param ContainerInterface $container
112
     *
113
     * @return null|LoggerInterface
114
     */
115 2
    protected static function getLoggerIfEnabled(ContainerInterface $container): ?LoggerInterface
116
    {
117 2
        $logger = null;
118 2
        if ($container->has(LoggerInterface::class) === true &&
119 2
            $container->get(SettingsProviderInterface::class)->get(S::class)[S::KEY_IS_LOG_ENABLED] === true
120
        ) {
121 2
            $logger = $container->get(LoggerInterface::class);
122
        }
123
124 2
        return $logger;
125
    }
126
}
127