Passed
Push — master ( 5679ef...aad9e9 )
by Kirill
04:11
created

CookieTransportTest   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 203
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 10
eloc 102
c 1
b 0
f 0
dl 0
loc 203
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A testDeleteToken() 0 26 1
A setUp() 0 3 1
A testCommitTokenLifetime() 0 29 1
A testCommitToken() 0 15 1
A getCore() 0 31 1
A testCommitTokenOtherParams() 0 19 1
A testCookieToken() 0 30 2
A testBadCookieToken() 0 30 2
1
<?php
2
3
/**
4
 * Spiral Framework.
5
 *
6
 * @license   MIT
7
 * @author    Anton Titov (Wolfy-J)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Spiral\Tests\Auth;
13
14
use PHPUnit\Framework\TestCase;
15
use Psr\Http\Message\ResponseInterface;
16
use Psr\Http\Message\ServerRequestInterface;
17
use Spiral\Auth\HttpTransportInterface;
18
use Spiral\Auth\Middleware\AuthMiddleware;
19
use Spiral\Auth\Transport\CookieTransport;
20
use Spiral\Auth\TransportRegistry;
21
use Spiral\Cookies\Cookie\SameSite;
22
use Spiral\Core\Container;
23
use Spiral\Http\Config\HttpConfig;
24
use Spiral\Http\Http;
25
use Spiral\Http\Pipeline;
26
use Spiral\Tests\Auth\Diactoros\ResponseFactory;
27
use Laminas\Diactoros\ServerRequest;
28
use Spiral\Tests\Auth\Stub\TestProvider;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Spiral\Tests\Auth\TestProvider. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
29
use Spiral\Tests\Auth\Stub\TestStorage;
30
use Spiral\Tests\Auth\Stub\TestToken;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Spiral\Tests\Auth\TestToken. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
31
32
class CookieTransportTest extends TestCase
33
{
34
    private $container;
35
36
    public function setUp(): void
37
    {
38
        $this->container = new Container();
39
    }
40
41
    public function testCookieToken(): void
42
    {
43
        $http = $this->getCore(new CookieTransport('auth-token'));
44
45
        $http->setHandler(
46
            static function (ServerRequestInterface $request, ResponseInterface $response): void {
0 ignored issues
show
Unused Code introduced by
The parameter $response is not used and could be removed. ( Ignorable by Annotation )

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

46
            static function (ServerRequestInterface $request, /** @scrutinizer ignore-unused */ ResponseInterface $response): void {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
47
                if ($request->getAttribute('authContext')->getToken() === null) {
48
                    echo 'no token';
49
                } else {
50
                    echo $request->getAttribute('authContext')->getToken()->getID();
51
                    echo ':';
52
                    echo json_encode($request->getAttribute('authContext')->getToken()->getPayload());
53
                }
54
            }
55
        );
56
57
        $response = $http->handle(
58
            new ServerRequest(
59
                [],
60
                [],
61
                null,
62
                'GET',
63
                'php://input',
64
                [],
65
                ['auth-token' => 'good-token']
66
            )
67
        );
68
69
        self::assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
70
        self::assertSame('good-token:{"id":"good-token"}', (string)$response->getBody());
71
    }
72
73
    public function testBadCookieToken(): void
74
    {
75
        $http = $this->getCore(new CookieTransport('auth-token'));
76
77
        $http->setHandler(
78
            static function (ServerRequestInterface $request, ResponseInterface $response): void {
0 ignored issues
show
Unused Code introduced by
The parameter $response is not used and could be removed. ( Ignorable by Annotation )

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

78
            static function (ServerRequestInterface $request, /** @scrutinizer ignore-unused */ ResponseInterface $response): void {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
79
                if ($request->getAttribute('authContext')->getToken() === null) {
80
                    echo 'no token';
81
                } else {
82
                    echo $request->getAttribute('authContext')->getToken()->getID();
83
                    echo ':';
84
                    echo json_encode($request->getAttribute('authContext')->getToken()->getPayload());
85
                }
86
            }
87
        );
88
89
        $response = $http->handle(
90
            new ServerRequest(
91
                [],
92
                [],
93
                null,
94
                'GET',
95
                'php://input',
96
                [],
97
                ['auth-token' => 'bad']
98
            )
99
        );
100
101
        self::assertSame(['text/html; charset=UTF-8'], $response->getHeader('Content-Type'));
102
        self::assertSame('no token', (string)$response->getBody());
103
    }
104
105
    public function testDeleteToken(): void
106
    {
107
        $http = $this->getCore(new CookieTransport('auth-token'));
108
109
        $http->setHandler(
110
            static function (ServerRequestInterface $request, ResponseInterface $response): void {
0 ignored issues
show
Unused Code introduced by
The parameter $response is not used and could be removed. ( Ignorable by Annotation )

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

110
            static function (ServerRequestInterface $request, /** @scrutinizer ignore-unused */ ResponseInterface $response): void {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
111
                $request->getAttribute('authContext')->close();
112
113
                echo 'closed';
114
            }
115
        );
116
117
        $response = $http->handle(
118
            new ServerRequest(
119
                [],
120
                [],
121
                null,
122
                'GET',
123
                'php://input',
124
                [],
125
                ['auth-token' => 'good-token']
126
            )
127
        );
128
129
        self::assertSame(['auth-token=; Path=/; HttpOnly'], $response->getHeader('Set-Cookie'));
130
        self::assertSame('closed', (string)$response->getBody());
131
    }
132
133
    public function testCommitToken(): void
134
    {
135
        $http = $this->getCore(new CookieTransport('auth-token'));
136
137
        $http->setHandler(
138
            static function (ServerRequestInterface $request, ResponseInterface $response): void {
0 ignored issues
show
Unused Code introduced by
The parameter $response is not used and could be removed. ( Ignorable by Annotation )

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

138
            static function (ServerRequestInterface $request, /** @scrutinizer ignore-unused */ ResponseInterface $response): void {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
139
                $request->getAttribute('authContext')->start(
140
                    new TestToken('new-token', ['ok' => 1])
141
                );
142
            }
143
        );
144
145
        $response = $http->handle(new ServerRequest([], [], null, 'GET', 'php://input', []));
146
147
        self::assertSame(['auth-token=new-token; Path=/; HttpOnly'], $response->getHeader('Set-Cookie'));
148
    }
149
150
    public function testCommitTokenOtherParams(): void
151
    {
152
        $http = $this->getCore(
153
            new CookieTransport('auth-token', '/', 'localhost', true, false, SameSite::NONE)
154
        );
155
156
        $http->setHandler(
157
            static function (ServerRequestInterface $request, ResponseInterface $response): void {
0 ignored issues
show
Unused Code introduced by
The parameter $response is not used and could be removed. ( Ignorable by Annotation )

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

157
            static function (ServerRequestInterface $request, /** @scrutinizer ignore-unused */ ResponseInterface $response): void {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
158
                $request->getAttribute('authContext')->start(
159
                    new TestToken('new-token', ['ok' => 1])
160
                );
161
            }
162
        );
163
164
        $response = $http->handle(new ServerRequest([], [], null, 'GET', 'php://input', []));
165
166
        self::assertSame(
167
            ['auth-token=new-token; Path=/; Domain=localhost; Secure; SameSite=None'],
168
            $response->getHeader('Set-Cookie')
169
        );
170
    }
171
172
    public function testCommitTokenLifetime(): void
173
    {
174
        $http = $this->getCore(new CookieTransport('auth-token'));
175
176
        $http->setHandler(
177
            static function (ServerRequestInterface $request, ResponseInterface $response): void {
0 ignored issues
show
Unused Code introduced by
The parameter $response is not used and could be removed. ( Ignorable by Annotation )

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

177
            static function (ServerRequestInterface $request, /** @scrutinizer ignore-unused */ ResponseInterface $response): void {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
178
                $request->getAttribute('authContext')->start(
179
                    new TestToken('new-token', ['ok' => 1], (new \DateTime('now'))->modify('+1 hour'))
180
                );
181
            }
182
        );
183
184
        $response = $http->handle(new ServerRequest([], [], null, 'GET', 'php://input', []));
185
186
        $cookie = explode('; ', $response->getHeader('Set-Cookie')[0]);
187
188
        self::assertSame(
189
            'auth-token=new-token',
190
            $cookie[0]
191
        );
192
193
        self::assertSame(
194
            'Expires=' . gmdate(DATE_COOKIE, time() + 3600),
195
            $cookie[1]
196
        );
197
198
        self::assertSame(
199
            'Max-Age=3600',
200
            $cookie[2]
201
        );
202
    }
203
204
    protected function getCore(HttpTransportInterface $transport): Http
205
    {
206
        $config = new HttpConfig(
207
            [
208
                'basePath'   => '/',
209
                'headers'    => [
210
                    'Content-Type' => 'text/html; charset=UTF-8'
211
                ],
212
                'middleware' => [],
213
            ]
214
        );
215
216
        $http = new Http(
217
            $config,
218
            new Pipeline($this->container),
219
            new ResponseFactory($config),
220
            $this->container
221
        );
222
223
        $http->getPipeline()->pushMiddleware(
224
            new AuthMiddleware(
225
                $this->container,
226
                new TestProvider(),
227
                new TestStorage(),
228
                $reg = new TransportRegistry()
229
            )
230
        );
231
        $reg->setDefaultTransport('transport');
232
        $reg->setTransport('transport', $transport);
233
234
        return $http;
235
    }
236
}
237