Passed
Push — master ( ce8c92...7c0481 )
by Alexander
01:29
created

Authentication::withOptionalPatterns()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
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\StringHelper;
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
    private AuthenticationMethodInterface $authenticationMethod;
24
25
    /**
26
     * @var RequestHandlerInterface A handler that is called when there is a failure authenticating an identity.
27
     */
28
    private RequestHandlerInterface $failureHandler;
29
30
    /**
31
     * @var array Patterns to match to consider the given request URI path optional.
32
     */
33
    private array $optionalPatterns = [];
34
35 5
    public function __construct(
36
        AuthenticationMethodInterface $authenticationMethod,
37
        ResponseFactoryInterface $responseFactory,
38
        RequestHandlerInterface $authenticationFailureHandler = null
39
    ) {
40 5
        $this->authenticationMethod = $authenticationMethod;
41 5
        $this->failureHandler = $authenticationFailureHandler ?? new AuthenticationFailureHandler(
42 4
            $responseFactory
43
        );
44 5
    }
45
46 4
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
47
    {
48 4
        $identity = $this->authenticationMethod->authenticate($request);
49 4
        $request = $request->withAttribute(self::class, $identity);
50
51 4
        if ($identity === null && !$this->isOptional($request)) {
52 2
            return $this->authenticationMethod->challenge(
53 2
                $this->failureHandler->handle($request)
54
            );
55
        }
56
57 2
        return $handler->handle($request);
58
    }
59
60
    /**
61
     * @param array $optional Patterns to match to consider the given request URI path optional.
62
     * @return self
63
     */
64 2
    public function withOptionalPatterns(array $optional): self
65
    {
66 2
        $new = clone $this;
67 2
        $new->optionalPatterns = $optional;
68 2
        return $new;
69
    }
70
71
    /**
72
     * Checks, whether authentication is optional for the given request URI path.
73
     */
74 3
    private function isOptional(ServerRequestInterface $request): bool
75
    {
76 3
        $path = $request->getUri()->getPath();
77 3
        foreach ($this->optionalPatterns as $pattern) {
78 1
            if (StringHelper::matchWildcard($pattern, $path)) {
79 1
                return true;
80
            }
81
        }
82 2
        return false;
83
    }
84
}
85