Completed
Pull Request — master (#75)
by Marco
40:03 queued 36:09
created

SessionMiddlewareTest   C

Complexity

Total Complexity 34

Size/Duplication

Total Lines 643
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 18

Importance

Changes 0
Metric Value
wmc 34
lcom 1
cbo 18
dl 0
loc 643
rs 6.7466
c 0
b 0
f 0

33 Methods

Rating   Name   Duplication   Size   Complexity  
A testFromSymmetricKeyDefaultsUsesASecureCookie() 0 10 1
A testFromAsymmetricKeyDefaultsUsesASecureCookie() 0 15 1
A testSkipsInjectingSessionCookieOnEmptyContainer() 0 6 1
A testExtractsSessionContainerFromEmptyRequest() 0 4 1
A testInjectsSessionInResponseCookies() 0 9 1
A testWillIgnoreRequestsWithExpiredTokens() 0 13 1
A testWillIgnoreRequestsWithTokensFromFuture() 0 13 1
A testWillIgnoreUnSignedTokens() 0 13 1
A testWillNotRefreshSignedTokensWithoutIssuedAt() 0 13 1
A createToken() 0 9 1
B testSessionContainerCanBeReusedOverMultipleRequests() 0 33 1
B testWillRefreshTokenWithIssuedAtExactlyAtTokenRefreshTimeThreshold() 0 36 1
A testWillSkipInjectingSessionCookiesWhenSessionIsNotChanged() 0 22 1
A testWillSendExpirationCookieWhenSessionContentsAreCleared() 0 19 1
A testWillIgnoreMalformedTokens() 0 8 1
A testRejectsTokensWithInvalidSignature() 0 20 1
B testAllowsModifyingCookieDetails() 0 35 1
B testSessionTokenParsingIsDelayedWhenSessionIsNotBeingUsed() 0 32 1
B testShouldRegenerateTokenWhenRequestHasATokenThatIsAboutToExpire() 0 37 1
B testShouldNotRegenerateTokenWhenRequestHasATokenThatIsFarFromExpiration() 0 25 1
A validMiddlewaresProvider() 0 20 1
A testFromSymmetricKeyDefaultsWillHaveADefaultSessionPath() 0 12 1
A testFromAsymmetricKeyDefaultsWillHaveADefaultSessionPath() 0 17 1
B ensureSameResponse() 0 32 2
A ensureClearsSessionCookie() 0 14 1
A emptyValidationMiddleware() 0 14 1
A writingMiddleware() 0 12 1
A fakeDelegate() 0 12 1
A requestWithResponseCookies() 0 6 1
A getCookie() 0 4 1
A getSigner() 0 4 1
A getSignatureKey() 0 4 1
A getPropertyValue() 0 7 1
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license.
17
 */
18
19
declare(strict_types=1);
20
21
namespace PSR7SessionsTest\Storageless\Http;
22
23
use DateTimeImmutable;
24
use Dflydev\FigCookies\FigResponseCookies;
25
use Dflydev\FigCookies\SetCookie;
26
use Lcobucci\Clock\FrozenClock;
27
use Lcobucci\Clock\SystemClock;
28
use Lcobucci\JWT\Builder;
29
use Lcobucci\JWT\Parser;
30
use Lcobucci\JWT\Signer;
31
use Lcobucci\JWT\Signer\Hmac\Sha256;
32
use Lcobucci\JWT\Token;
33
use PHPUnit\Framework\TestCase;
34
use Psr\Http\Message\RequestInterface;
35
use Psr\Http\Message\ResponseInterface;
36
use Psr\Http\Message\ServerRequestInterface;
37
use Psr\Http\Server\RequestHandlerInterface;
38
use PSR7Sessions\Storageless\Http\SessionMiddleware;
39
use PSR7Sessions\Storageless\Session\DefaultSessionData;
40
use PSR7Sessions\Storageless\Session\SessionInterface;
41
use Zend\Diactoros\Response;
42
use Zend\Diactoros\ServerRequest;
43
44
final class SessionMiddlewareTest extends TestCase
45
{
46
    public function testFromSymmetricKeyDefaultsUsesASecureCookie() : void
47
    {
48
        $response = SessionMiddleware::fromSymmetricKeyDefaults('not relevant', 100)
49
            ->process(new ServerRequest(), $this->writingMiddleware());
50
51
        $cookie = $this->getCookie($response);
52
53
        self::assertTrue($cookie->getSecure());
54
        self::assertTrue($cookie->getHttpOnly());
55
    }
56
57
    public function testFromAsymmetricKeyDefaultsUsesASecureCookie() : void
58
    {
59
        $response = SessionMiddleware
60
            ::fromAsymmetricKeyDefaults(
61
                file_get_contents(__DIR__ . '/../../keys/private_key.pem'),
62
                file_get_contents(__DIR__ . '/../../keys/public_key.pem'),
63
                200
64
            )
65
            ->process(new ServerRequest(), $this->writingMiddleware());
66
67
        $cookie = $this->getCookie($response);
68
69
        self::assertTrue($cookie->getSecure());
70
        self::assertTrue($cookie->getHttpOnly());
71
    }
72
73
    /**
74
     * @dataProvider validMiddlewaresProvider
75
     */
76
    public function testSkipsInjectingSessionCookieOnEmptyContainer(SessionMiddleware $middleware) : void
77
    {
78
        $response = $this->ensureSameResponse($middleware, new ServerRequest(), $this->emptyValidationMiddleware());
79
80
        self::assertNull($this->getCookie($response)->getValue());
81
    }
82
83
    /**
84
     * @dataProvider validMiddlewaresProvider
85
     */
86
    public function testExtractsSessionContainerFromEmptyRequest(SessionMiddleware $middleware) : void
87
    {
88
        $this->ensureSameResponse($middleware, new ServerRequest(), $this->emptyValidationMiddleware());
89
    }
90
91
    /**
92
     * @dataProvider validMiddlewaresProvider
93
     */
94
    public function testInjectsSessionInResponseCookies(SessionMiddleware $middleware) : void
95
    {
96
        $initialResponse = new Response();
97
        $response = $middleware->process(new ServerRequest(), $this->writingMiddleware());
98
99
        self::assertNotSame($initialResponse, $response);
100
        self::assertEmpty($this->getCookie($response, 'non-existing')->getValue());
101
        self::assertInstanceOf(Token::class, (new Parser())->parse($this->getCookie($response)->getValue()));
102
    }
103
104
    /**
105
     * @dataProvider validMiddlewaresProvider
106
     */
107
    public function testSessionContainerCanBeReusedOverMultipleRequests(SessionMiddleware $middleware) : void
108
    {
109
        $sessionValue = uniqid('', true);
110
111
        $checkingMiddleware = $this->fakeDelegate(
112
            function (ServerRequestInterface $request) use ($sessionValue) {
113
                /* @var $session SessionInterface */
114
                $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
115
116
                self::assertSame($sessionValue, $session->get('foo'));
117
                self::assertFalse($session->hasChanged());
118
119
                $session->set('foo', $sessionValue . 'changed');
120
121
                self::assertTrue(
122
                    $session->hasChanged(),
123
                    'ensuring that the cookie is sent again: '
124
                    . 'non-modified session containers are not to be re-serialized into a token'
125
                );
126
127
                return new Response();
128
            }
129
        );
130
131
        $firstResponse = $middleware->process(new ServerRequest(), $this->writingMiddleware($sessionValue));
132
133
        $response = $middleware->process(
134
            $this->requestWithResponseCookies($firstResponse),
135
            $checkingMiddleware
136
        );
137
138
        self::assertNotSame($response, $firstResponse);
139
    }
140
141
    /**
142
     * @dataProvider validMiddlewaresProvider
143
     */
144
    public function testWillIgnoreRequestsWithExpiredTokens(SessionMiddleware $middleware) : void
145
    {
146
        $expiredToken = (new ServerRequest())
147
            ->withCookieParams([
148
                SessionMiddleware::DEFAULT_COOKIE => $this->createToken(
149
                    $middleware,
150
                    new \DateTime('-1 day'),
151
                    new \DateTime('-2 day')
152
                )
153
            ]);
154
155
        $this->ensureSameResponse($middleware, $expiredToken, $this->emptyValidationMiddleware());
156
    }
157
158
    /**
159
     * @dataProvider validMiddlewaresProvider
160
     */
161
    public function testWillIgnoreRequestsWithTokensFromFuture(SessionMiddleware $middleware) : void
162
    {
163
        $tokenInFuture = (new ServerRequest())
164
            ->withCookieParams([
165
                SessionMiddleware::DEFAULT_COOKIE => $this->createToken(
166
                    $middleware,
167
                    new \DateTime('+1 day'),
168
                    new \DateTime('-2 day')
169
                )
170
            ]);
171
172
        $this->ensureSameResponse($middleware, $tokenInFuture, $this->emptyValidationMiddleware());
173
    }
174
175
    /**
176
     * @dataProvider validMiddlewaresProvider
177
     */
178
    public function testWillIgnoreUnSignedTokens(SessionMiddleware $middleware) : void
179
    {
180
        $unsignedToken = (new ServerRequest())
181
            ->withCookieParams([
182
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
183
                    ->setIssuedAt((new \DateTime('-1 day'))->getTimestamp())
184
                    ->setExpiration((new \DateTime('+1 day'))->getTimestamp())
185
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
186
                    ->getToken()
187
            ]);
188
189
        $this->ensureSameResponse($middleware, $unsignedToken, $this->emptyValidationMiddleware());
190
    }
191
192
    /**
193
     * @dataProvider validMiddlewaresProvider
194
     */
195
    public function testWillNotRefreshSignedTokensWithoutIssuedAt(SessionMiddleware $middleware) : void
196
    {
197
        $unsignedToken = (new ServerRequest())
198
            ->withCookieParams([
199
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
200
                    ->setExpiration((new \DateTime('+1 day'))->getTimestamp())
201
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
202
                    ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
203
                    ->getToken()
204
            ]);
205
206
        $this->ensureSameResponse($middleware, $unsignedToken);
207
    }
208
209
    public function testWillRefreshTokenWithIssuedAtExactlyAtTokenRefreshTimeThreshold() : void
210
    {
211
        // forcing ourselves to think of time as a mutable value:
212
        $time = time() + random_int(-100, +100);
213
214
        $clock = new FrozenClock(new \DateTimeImmutable('@' . $time));
215
216
        $middleware = new SessionMiddleware(
217
            new Sha256(),
218
            'foo',
219
            'foo',
220
            SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
221
            new Parser(),
222
            1000,
223
            $clock,
224
            100
225
        );
226
227
        $requestWithTokenIssuedInThePast = (new ServerRequest())
228
            ->withCookieParams([
229
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
230
                    ->setExpiration($time + 10000)
231
                    ->setIssuedAt($time - 100)
232
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
233
                    ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
234
                    ->getToken()
235
            ]);
236
237
        $cookie = $this->getCookie($middleware->process($requestWithTokenIssuedInThePast, $this->fakeDelegate(function () {
238
            return new Response();
239
        })));
240
241
        $token = (new Parser())->parse($cookie->getValue());
242
243
        self::assertEquals($time, $token->getClaim(SessionMiddleware::ISSUED_AT_CLAIM), 'Token was refreshed');
244
    }
245
246
    /**
247
     * @dataProvider validMiddlewaresProvider
248
     */
249
    public function testWillSkipInjectingSessionCookiesWhenSessionIsNotChanged(SessionMiddleware $middleware) : void
250
    {
251
        $this->ensureSameResponse(
252
            $middleware,
253
            $this->requestWithResponseCookies(
254
                $middleware->process(new ServerRequest(), $this->writingMiddleware())
255
            ),
256
            $this->fakeDelegate(
257
                function (ServerRequestInterface $request) {
258
                    /* @var $session SessionInterface */
259
                    $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
260
261
                    // note: we set the same data just to make sure that we are indeed interacting with the session
262
                    $session->set('foo', 'bar');
263
264
                    self::assertFalse($session->hasChanged());
265
266
                    return new Response();
267
                }
268
            )
269
        );
270
    }
271
272
    /**
273
     * @dataProvider validMiddlewaresProvider
274
     */
275
    public function testWillSendExpirationCookieWhenSessionContentsAreCleared(SessionMiddleware $middleware) : void
276
    {
277
        $this->ensureClearsSessionCookie(
278
            $middleware,
279
            $this->requestWithResponseCookies(
280
                $middleware->process(new ServerRequest(), $this->writingMiddleware())
281
            ),
282
            $this->fakeDelegate(
283
                function (ServerRequestInterface $request) {
284
                    /* @var $session SessionInterface */
285
                    $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
286
287
                    $session->clear();
288
289
                    return new Response();
290
                }
291
            )
292
        );
293
    }
294
295
    /**
296
     * @dataProvider validMiddlewaresProvider
297
     */
298
    public function testWillIgnoreMalformedTokens(SessionMiddleware $middleware) : void
299
    {
300
        $this->ensureSameResponse(
301
            $middleware,
302
            (new ServerRequest())->withCookieParams([SessionMiddleware::DEFAULT_COOKIE => 'malformed content']),
303
            $this->emptyValidationMiddleware()
304
        );
305
    }
306
307
    public function testRejectsTokensWithInvalidSignature() : void
308
    {
309
        $middleware = new SessionMiddleware(
310
            new Sha256(),
311
            'foo',
312
            'bar', // wrong symmetric key (on purpose)
313
            SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
314
            new Parser(),
315
            100,
316
            new SystemClock()
317
        );
318
319
        $this->ensureSameResponse(
320
            $middleware,
321
            $this->requestWithResponseCookies(
322
                $middleware->process(new ServerRequest(), $this->writingMiddleware())
323
            ),
324
            $this->emptyValidationMiddleware()
325
        );
326
    }
327
328
    public function testAllowsModifyingCookieDetails() : void
329
    {
330
        $defaultCookie = SetCookie::create('a-different-cookie-name')
331
            ->withDomain('foo.bar')
332
            ->withPath('/yadda')
333
            ->withHttpOnly(false)
334
            ->withMaxAge('123123')
335
            ->withValue('a-random-value');
336
337
        $dateTime   = new DateTimeImmutable();
338
        $middleware = new SessionMiddleware(
339
            new Sha256(),
340
            'foo',
341
            'foo',
342
            $defaultCookie,
343
            new Parser(),
344
            123456,
345
            new FrozenClock($dateTime),
346
            123
347
        );
348
349
        $response = $middleware->process(new ServerRequest(), $this->writingMiddleware());
350
351
        self::assertNull($this->getCookie($response)->getValue());
352
353
        $tokenCookie = $this->getCookie($response, 'a-different-cookie-name');
354
355
        self::assertNotEmpty($tokenCookie->getValue());
356
        self::assertNotSame($defaultCookie->getValue(), $tokenCookie->getValue());
357
        self::assertSame($defaultCookie->getDomain(), $tokenCookie->getDomain());
358
        self::assertSame($defaultCookie->getPath(), $tokenCookie->getPath());
359
        self::assertSame($defaultCookie->getHttpOnly(), $tokenCookie->getHttpOnly());
360
        self::assertSame($defaultCookie->getMaxAge(), $tokenCookie->getMaxAge());
361
        self::assertEquals($dateTime->getTimestamp() + 123456, $tokenCookie->getExpires());
362
    }
363
364
    public function testSessionTokenParsingIsDelayedWhenSessionIsNotBeingUsed() : void
365
    {
366
        /* @var $signer Signer|\PHPUnit_Framework_MockObject_MockObject */
367
        $signer = $this->createMock(Signer::class);
368
369
        $signer->expects($this->never())->method('verify');
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in Lcobucci\JWT\Signer.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
370
        $signer->method('getAlgorithmId')->willReturn('HS256');
371
372
        $currentTimeProvider = new SystemClock();
373
        $setCookie  = SetCookie::create(SessionMiddleware::DEFAULT_COOKIE);
374
        $middleware = new SessionMiddleware($signer, 'foo', 'foo', $setCookie, new Parser(), 100, $currentTimeProvider);
0 ignored issues
show
Bug introduced by
It seems like $signer defined by $this->createMock(\Lcobucci\JWT\Signer::class) on line 367 can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, PSR7Sessions\Storageless...ddleware::__construct() does only seem to accept object<Lcobucci\JWT\Signer>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
375
        $request    = (new ServerRequest())
376
            ->withCookieParams([
377
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
378
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
379
                    ->setIssuedAt(time())
380
                    ->sign(new Sha256(), 'foo')
381
                    ->getToken()
382
            ]);
383
384
        $middleware->process(
385
            $request,
386
            $this->fakeDelegate(function (ServerRequestInterface $request) {
387
                self::assertInstanceOf(
388
                    SessionInterface::class,
389
                    $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE)
390
                );
391
392
                return new Response();
393
            })
394
        );
395
    }
396
397
    public function testShouldRegenerateTokenWhenRequestHasATokenThatIsAboutToExpire() : void
398
    {
399
        $dateTime   = new DateTimeImmutable();
400
        $middleware = new SessionMiddleware(
401
            new Sha256(),
402
            'foo',
403
            'foo',
404
            SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
405
            new Parser(),
406
            1000,
407
            new FrozenClock($dateTime),
408
            300
409
        );
410
411
        $expiringToken = (new ServerRequest())
412
            ->withCookieParams([
413
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
414
                    ->setIssuedAt((new \DateTime('-800 second'))->getTimestamp())
415
                    ->setExpiration((new \DateTime('+200 second'))->getTimestamp())
416
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
417
                    ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
418
                    ->getToken()
419
            ]);
420
421
        $initialResponse = new Response();
422
423
        $response = $middleware->process($expiringToken, $this->fakeDelegate(function () use ($initialResponse) {
424
            return $initialResponse;
425
        }));
426
427
        self::assertNotSame($initialResponse, $response);
428
429
        $tokenCookie = $this->getCookie($response);
430
431
        self::assertNotEmpty($tokenCookie->getValue());
432
        self::assertEquals($dateTime->getTimestamp() + 1000, $tokenCookie->getExpires());
433
    }
434
435
    public function testShouldNotRegenerateTokenWhenRequestHasATokenThatIsFarFromExpiration() : void
436
    {
437
        $middleware = new SessionMiddleware(
438
            new Sha256(),
439
            'foo',
440
            'foo',
441
            SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
442
            new Parser(),
443
            1000,
444
            new SystemClock(),
445
            300
446
        );
447
448
        $validToken = (new ServerRequest())
449
            ->withCookieParams([
450
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
451
                    ->setIssuedAt((new \DateTime('-100 second'))->getTimestamp())
452
                    ->setExpiration((new \DateTime('+900 second'))->getTimestamp())
453
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
454
                    ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
455
                    ->getToken()
456
            ]);
457
458
        $this->ensureSameResponse($middleware, $validToken);
459
    }
460
461
    /**
462
     * @return SessionMiddleware[][]
463
     */
464
    public function validMiddlewaresProvider() : array
465
    {
466
        return [
467
            [new SessionMiddleware(
468
                new Sha256(),
469
                'foo',
470
                'foo',
471
                SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
472
                new Parser(),
473
                100,
474
                new SystemClock()
475
            )],
476
            [SessionMiddleware::fromSymmetricKeyDefaults('not relevant', 100)],
477
            [SessionMiddleware::fromAsymmetricKeyDefaults(
478
                file_get_contents(__DIR__ . '/../../keys/private_key.pem'),
479
                file_get_contents(__DIR__ . '/../../keys/public_key.pem'),
480
                200
481
            )],
482
        ];
483
    }
484
485
    /**
486
     * @group #46
487
     */
488
    public function testFromSymmetricKeyDefaultsWillHaveADefaultSessionPath() : void
489
    {
490
        self::assertSame(
491
            '/',
492
            $this
493
                ->getCookie(
494
                    SessionMiddleware::fromSymmetricKeyDefaults('not relevant', 100)
495
                        ->process(new ServerRequest(), $this->writingMiddleware())
496
                )
497
                ->getPath()
498
        );
499
    }
500
501
    /**
502
     * @group #46
503
     *
504
     * @throws \InvalidArgumentException
505
     * @throws \OutOfBoundsException
506
     */
507
    public function testFromAsymmetricKeyDefaultsWillHaveADefaultSessionPath() : void
508
    {
509
        self::assertSame(
510
            '/',
511
            $this
512
                ->getCookie(
513
                    SessionMiddleware
514
                        ::fromAsymmetricKeyDefaults(
515
                            file_get_contents(__DIR__ . '/../../keys/private_key.pem'),
516
                            file_get_contents(__DIR__ . '/../../keys/public_key.pem'),
517
                            200
518
                        )
519
                        ->process(new ServerRequest(), $this->writingMiddleware())
520
                )
521
                ->getPath()
522
        );
523
    }
524
525
    private function ensureSameResponse(
526
        SessionMiddleware $middleware,
527
        ServerRequestInterface $request,
528
        RequestHandlerInterface $next = null
529
    ) : ResponseInterface {
530
        $initialResponse = new Response();
531
532
        $handleRequest = $this->createMock(RequestHandlerInterface::class);
533
534
        if ($next) {
535
            // capturing `$initialResponse` from the `$next` handler
536
            $handleRequest
537
                ->expects(self::once())
538
                ->method('handle')
539
                ->willReturnCallback(function (ServerRequestInterface $serverRequest) use ($next, & $initialResponse) {
540
                    $initialResponse = $next->handle($serverRequest);
541
542
                    return $initialResponse;
543
                });
544
        } else {
545
            $handleRequest
546
                ->expects(self::once())
547
                ->method('handle')
548
                ->willReturn($initialResponse);
549
        }
550
551
        $response = $middleware->process($request, $handleRequest);
0 ignored issues
show
Documentation introduced by
$handleRequest is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<Psr\Http\Server\RequestHandlerInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
552
553
        self::assertSame($initialResponse, $response);
554
555
        return $response;
556
    }
557
558
    private function ensureClearsSessionCookie(
559
        SessionMiddleware $middleware,
560
        ServerRequestInterface $request,
561
        RequestHandlerInterface $next
562
    ) : ResponseInterface {
563
        $response = $middleware->process($request, $next);
564
565
        $cookie = $this->getCookie($response);
566
567
        self::assertLessThan((new \DateTime('-29 day'))->getTimestamp(), $cookie->getExpires());
568
        self::assertEmpty($cookie->getValue());
569
570
        return $response;
571
    }
572
573
    /**
574
     * @param SessionMiddleware $middleware
575
     * @param \DateTime $issuedAt
576
     * @param \DateTime $expiration
577
     *
578
     * @return string
579
     */
580
    private function createToken(SessionMiddleware $middleware, \DateTime $issuedAt, \DateTime $expiration) : string
581
    {
582
        return (string) (new Builder())
583
            ->setIssuedAt($issuedAt->getTimestamp())
584
            ->setExpiration($expiration->getTimestamp())
585
            ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
586
            ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
587
            ->getToken();
588
    }
589
590
    private function emptyValidationMiddleware() : RequestHandlerInterface
591
    {
592
        return $this->fakeDelegate(
593
            function (ServerRequestInterface $request) {
594
                /* @var $session SessionInterface */
595
                $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
596
597
                self::assertInstanceOf(SessionInterface::class, $session);
598
                self::assertTrue($session->isEmpty());
599
600
                return new Response();
601
            }
602
        );
603
    }
604
605
    private function writingMiddleware(string $value = 'bar') : RequestHandlerInterface
606
    {
607
        return $this->fakeDelegate(
608
            function (ServerRequestInterface $request) use ($value) {
609
                /* @var $session SessionInterface */
610
                $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
611
                $session->set('foo', $value);
612
613
                return new Response();
614
            }
615
        );
616
    }
617
618
    private function fakeDelegate(callable $callback) : RequestHandlerInterface
619
    {
620
        $middleware = $this->createMock(RequestHandlerInterface::class);
621
622
        $middleware
623
            ->expects(self::once())
624
           ->method('handle')
625
           ->willReturnCallback($callback)
626
           ->with(self::isInstanceOf(RequestInterface::class));
627
628
        return $middleware;
629
    }
630
631
    /**
632
     * @param ResponseInterface $response
633
     *
634
     * @return \Zend\Diactoros\ServerRequest
635
     */
636
    private function requestWithResponseCookies(ResponseInterface $response) : ServerRequestInterface
637
    {
638
        return (new ServerRequest())->withCookieParams([
639
            SessionMiddleware::DEFAULT_COOKIE => $this->getCookie($response)->getValue()
640
        ]);
641
    }
642
643
    /**
644
     * @param ResponseInterface $response
645
     *
646
     * @return SetCookie
647
     */
648
    private function getCookie(ResponseInterface $response, string $name = SessionMiddleware::DEFAULT_COOKIE) : SetCookie
649
    {
650
        return FigResponseCookies::get($response, $name);
651
    }
652
653
    /**
654
     * @param SessionMiddleware $middleware
655
     *
656
     * @return Signer
657
     */
658
    private function getSigner(SessionMiddleware $middleware) : Signer
659
    {
660
        return $this->getPropertyValue($middleware, 'signer');
661
    }
662
663
    /**
664
     * @param SessionMiddleware $middleware
665
     *
666
     * @return string
667
     */
668
    private function getSignatureKey(SessionMiddleware $middleware) : string
669
    {
670
        return $this->getPropertyValue($middleware, 'signatureKey');
671
    }
672
673
    /**
674
     * @param object $object
675
     * @param string $name
676
     *
677
     * @return mixed
678
     */
679
    private function getPropertyValue($object, string $name)
680
    {
681
        $propertyReflection = new \ReflectionProperty($object, $name);
682
        $propertyReflection->setAccessible(true);
683
684
        return $propertyReflection->getValue($object);
685
    }
686
}
687