Authentication::isOptional()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 4
b 0
f 0
nc 3
nop 1
dl 0
loc 11
ccs 7
cts 7
cp 1
crap 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Auth\Middleware;
6
7
use Psr\Http\Message\ResponseFactoryInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use Psr\Http\Message\ServerRequestInterface;
10
use Psr\Http\Server\MiddlewareInterface;
11
use Psr\Http\Server\RequestHandlerInterface;
12
use Yiisoft\Auth\AuthenticationMethodInterface;
13
use Yiisoft\Auth\Handler\AuthenticationFailureHandler;
14
use Yiisoft\Strings\WildcardPattern;
15
16
/**
17
 * Authentication middleware tries to authenticate and identity using request data.
18
 * If identity is found, it is set to request attribute allowing further middleware to obtain and use it.
19
 * If identity is not found failure handler is called. By default it is {@see AuthenticationFailureHandler}.
20
 */
21
final class Authentication implements MiddlewareInterface
22
{
23
    /**
24
     * @var RequestHandlerInterface A handler that is called when there is a failure authenticating an identity.
25
     */
26
    private RequestHandlerInterface $failureHandler;
27
28
    /**
29
     * @var array Patterns to match to consider the given request URI path optional.
30
     */
31
    private array $optionalPatterns = [];
32
    /**
33
     * @var WildcardPattern[]
34
     */
35
    private array $wildcards = [];
36
37 6
    public function __construct(
38
        private AuthenticationMethodInterface $authenticationMethod,
39
        ResponseFactoryInterface $responseFactory,
40
        RequestHandlerInterface $authenticationFailureHandler = null,
41
    ) {
42 6
        $this->failureHandler = $authenticationFailureHandler ?? new AuthenticationFailureHandler(
43 6
            $responseFactory
44 6
        );
45
    }
46
47 5
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
48
    {
49 5
        $identity = $this->authenticationMethod->authenticate($request);
50 5
        $request = $request->withAttribute(self::class, $identity);
51
52 5
        if ($identity === null && !$this->isOptional($request)) {
53 2
            return $this->authenticationMethod->challenge(
54 2
                $this->failureHandler->handle($request)
55 2
            );
56
        }
57
58 3
        return $handler->handle($request);
59
    }
60
61
    /**
62
     * @param array $optional Patterns to match to consider the given request URI path optional.
63
     *
64
     * @see WildcardPattern
65
     */
66 3
    public function withOptionalPatterns(array $optional): self
67
    {
68 3
        $new = clone $this;
69 3
        $new->optionalPatterns = $optional;
70 3
        return $new;
71
    }
72
73
    /**
74
     * Checks, whether authentication is optional for the given request URI path.
75
     */
76 4
    private function isOptional(ServerRequestInterface $request): bool
77
    {
78 4
        $path = $request->getUri()->getPath();
79 4
        $path = rawurldecode($path);
80
81 4
        foreach ($this->optionalPatterns as $pattern) {
82 2
            if ($this->getOptionalPattern($pattern)->match($path)) {
83 2
                return true;
84
            }
85
        }
86 2
        return false;
87
    }
88
89 2
    private function getOptionalPattern(string $pattern): WildcardPattern
90
    {
91 2
        if (!isset($this->wildcards[$pattern])) {
92 2
            $this->wildcards[$pattern] = new WildcardPattern($pattern);
93
        }
94
95 2
        return $this->wildcards[$pattern];
96
    }
97
}
98