Test Failed
Pull Request — master (#350)
by Raffael
26:39
created

Http::invalidAuthentication()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 33
ccs 0
cts 29
cp 0
rs 8.7697
c 0
b 0
f 0
cc 6
nc 5
nop 0
crap 42
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * balloon
7
 *
8
 * @copyright   Copryright (c) 2012-2019 gyselroth GmbH (https://gyselroth.com)
9
 * @license     GPL-3.0 https://opensource.org/licenses/GPL-3.0
10
 */
11
12
namespace Balloon\Bootstrap;
13
14
use Balloon\Hook;
15
use Balloon\Server;
16
use Micro\Auth\Adapter\None as AuthNone;
17
use Micro\Auth\Auth;
18
use Micro\Http\ExceptionInterface;
19
use Micro\Http\Response;
20
use Micro\Http\Router;
21
use MongoDB\BSON\Binary;
22
use Psr\Log\LoggerInterface;
23
24
class Http extends AbstractBootstrap
25
{
26
    /**
27
     * Auth.
28
     *
29
     * @var Auth
30
     */
31
    protected $auth;
32
33
    /**
34
     * Hook.
35
     *
36
     * @var Hook
37
     */
38
    protected $hook;
39
40
    /**
41
     * Router.
42
     *
43
     * @var Router
44
     */
45
    protected $router;
46
47
    /**
48
     * Server.
49
     *
50
     * @var Server
51
     */
52
    protected $server;
53
54
    /**
55
     * Http.
56
     */
57
    public function __construct(LoggerInterface $logger, Auth $auth, Hook $hook, Router $router, Server $server)
58
    {
59
        $this->setExceptionHandler();
60
        $this->setErrorHandler();
61
        $this->logger = $logger;
62
        $this->auth = $auth;
63
        $this->hook = $hook;
64
        $this->router = $router;
65
        $this->server = $server;
66
    }
67
68
    /**
69
     * Process.
70
     */
71
    public function process()
72
    {
73
        $this->logger->info('processing incoming http ['.$_SERVER['REQUEST_METHOD'].'] request to ['.$_SERVER['REQUEST_URI'].']', [
74
            'category' => get_class($this),
75
        ]);
76
77
        $this->hook->run('preAuthentication', [$this->auth]);
78
79
        if ($this->auth->requireOne()) {
80
            $this->hook->run('postAuthentication', [$this->auth, $this->auth->getIdentity()]);
81
82
            if (
83
                !($this->auth->getIdentity()->getAdapter() instanceof AuthNone)) {
84
                $this->auth->getIdentity()->getAttributeMap()->addMapper('binary', function ($value) {
85
                    return new Binary($value, Binary::TYPE_GENERIC);
86
                });
87
88
                $this->server->setIdentity($this->auth->getIdentity());
0 ignored issues
show
Compatibility introduced by
$this->auth->getIdentity() of type object<Micro\Auth\IdentityInterface> is not a sub-type of object<Micro\Auth\Identity>. It seems like you assume a concrete implementation of the interface Micro\Auth\IdentityInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
89
            }
90
91
            $this->router->run();
92
        } else {
93
            $this->invalidAuthentication();
94
        }
95
96
        return $this;
97
    }
98
99
    /**
100
     * Send invalid authentication response.
101
     */
102
    protected function invalidAuthentication(): void
103
    {
104
        $this->hook->run('postAuthentication', [$this->auth, null]);
105
106
        if (isset($_SERVER['PHP_AUTH_USER']) && '_logout' === $_SERVER['PHP_AUTH_USER']) {
107
            (new Response())
108
                ->setCode(401)
109
                ->setBody([
110
                    'error' => 'Unauthorized',
111
                    'message' => 'authentication failed',
112
                ])
113
                ->send();
114
        } else {
115
            if ('/api/auth' === $_SERVER['PATH_INFO']) {
116
                $code = 403;
117
            } else {
118
                $code = 401;
119
            }
120
121
            $response = (new Response())
122
                ->setCode($code)
123
                ->setBody([
124
                    'error' => 'Unauthorized',
125
                    'message' => 'authentication failed',
126
                ]);
127
128
            if (!isset($_SERVER['HTTP_AUTHORIZATION']) || substr($_SERVER['HTTP_AUTHORIZATION'], 0, 5) === 'Basic') {
129
                $response->setHeader('WWW-Authenticate', 'Basic realm="balloon"');
130
            }
131
132
            $response->send();
133
        }
134
    }
135
136
    /**
137
     * Set exception handler.
138
     */
139
    protected function setExceptionHandler(): self
140
    {
141
        set_exception_handler(function ($e) {
142
            $this->logger->emergency('uncaught exception: '.$e->getMessage(), [
143
                'category' => get_class($this),
144
                'exception' => $e,
145
            ]);
146
147
            $code = 500;
148
            if ($e instanceof ExceptionInterface) {
149
                $code = $e->getStatusCode();
150
            }
151
152
            (new Response())
153
                ->setCode($code)
154
                ->setBody([
155
                    'error' => get_class($e),
156
                    'message' => $e->getMessage(),
157
                ])
158
                ->send();
159
        });
160
161
        return $this;
162
    }
163
}
164