Completed
Pull Request — master (#59)
by Geert
03:08
created

testFromAsymmetricKeyDefaultsUsesASecureCookie()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 10
nc 1
nop 0
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 Interop\Http\ServerMiddleware\DelegateInterface;
27
use Lcobucci\JWT\Builder;
28
use Lcobucci\JWT\Parser;
29
use Lcobucci\JWT\Signer;
30
use Lcobucci\JWT\Signer\Hmac\Sha256;
31
use Lcobucci\JWT\Token;
32
use PHPUnit_Framework_TestCase;
33
use Psr\Http\Message\ResponseInterface;
34
use Psr\Http\Message\ServerRequestInterface;
35
use PSR7Sessions\Storageless\Http\SessionMiddleware;
36
use PSR7Sessions\Storageless\Session\DefaultSessionData;
37
use PSR7Sessions\Storageless\Session\SessionInterface;
38
use PSR7Sessions\Storageless\Time\CurrentTimeProviderInterface;
39
use PSR7Sessions\Storageless\Time\SystemCurrentTime;
40
use PSR7SessionsTest\Storageless\Time\FakeCurrentTime;
41
use Zend\Diactoros\Response;
42
use Zend\Diactoros\ServerRequest;
43
44
final class SessionMiddlewareTest extends PHPUnit_Framework_TestCase
45
{
46
    public function testFromSymmetricKeyDefaultsUsesASecureCookie()
47
    {
48
        $response = SessionMiddleware::fromSymmetricKeyDefaults('not relevant', 100)
49
            ->process(new ServerRequest(), $this->writingDelegate());
50
51
        $cookie = $this->getCookie($response);
52
53
        self::assertTrue($cookie->getSecure());
54
        self::assertTrue($cookie->getHttpOnly());
55
    }
56
57
    public function testFromAsymmetricKeyDefaultsUsesASecureCookie()
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->writingDelegate());
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)
77
    {
78
        $response = $this->ensureSameResponse($middleware, new ServerRequest(), $this->emptyValidationDelegate());
79
80
        self::assertNull($this->getCookie($response)->getValue());
81
    }
82
83
    /**
84
     * @dataProvider validMiddlewaresProvider
85
     */
86
    public function testExtractsSessionContainerFromEmptyRequest(SessionMiddleware $middleware)
87
    {
88
        $this->ensureSameResponse($middleware, new ServerRequest(), $this->emptyValidationDelegate());
89
    }
90
91
    /**
92
     * @dataProvider validMiddlewaresProvider
93
     */
94
    public function testInjectsSessionInResponseCookies(SessionMiddleware $middleware)
95
    {
96
        $response = $this->ensureNotSameResponse($middleware, new ServerRequest(), $this->writingDelegate());
97
98
        self::assertEmpty($this->getCookie($response, 'non-existing')->getValue());
99
        self::assertInstanceOf(Token::class, (new Parser())->parse($this->getCookie($response)->getValue()));
100
    }
101
102
    /**
103
     * @dataProvider validMiddlewaresProvider
104
     */
105
    public function testSessionContainerCanBeReusedOverMultipleRequests(SessionMiddleware $middleware)
106
    {
107
        $sessionValue = uniqid('', true);
108
109
        $checkingDelegate = $this->fakeDelegate(
110
            function (ServerRequestInterface $request) use ($sessionValue) {
111
                /* @var $session SessionInterface */
112
                $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
113
114
                self::assertSame($sessionValue, $session->get('foo'));
115
                self::assertFalse($session->hasChanged());
116
117
                $session->set('foo', $sessionValue . 'changed');
118
119
                self::assertTrue(
120
                    $session->hasChanged(),
121
                    'ensuring that the cookie is sent again: '
122
                    . 'non-modified session containers are not to be re-serialized into a token'
123
                );
124
125
                return new Response();
126
            }
127
        );
128
129
        $firstResponse = $middleware->process(new ServerRequest(), $this->writingDelegate($sessionValue));
130
131
        $initialResponse = new Response();
132
133
        $response = $middleware->process(
134
            $this->requestWithResponseCookies($firstResponse),
135
            $checkingDelegate
136
        );
137
138
        self::assertNotSame($initialResponse, $response);
139
    }
140
141
    /**
142
     * @dataProvider validMiddlewaresProvider
143
     */
144
    public function testWillIgnoreRequestsWithExpiredTokens(SessionMiddleware $middleware)
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->emptyValidationDelegate());
156
    }
157
158
    /**
159
     * @dataProvider validMiddlewaresProvider
160
     */
161
    public function testWillIgnoreRequestsWithTokensFromFuture(SessionMiddleware $middleware)
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->emptyValidationDelegate());
173
    }
174
175
    /**
176
     * @dataProvider validMiddlewaresProvider
177
     */
178
    public function testWillIgnoreUnSignedTokens(SessionMiddleware $middleware)
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->emptyValidationDelegate());
190
    }
191
192
    /**
193
     * @dataProvider validMiddlewaresProvider
194
     */
195
    public function testWillNotRefreshSignedTokensWithoutIssuedAt(SessionMiddleware $middleware)
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, $this->defaultDelegate());
207
    }
208
209
    public function testWillRefreshTokenWithIssuedAtExactlyAtTokenRefreshTimeThreshold()
210
    {
211
        /* @var $currentTimeProvider CurrentTimeProviderInterface|\PHPUnit_Framework_MockObject_MockObject */
212
        $currentTimeProvider = $this->createMock(CurrentTimeProviderInterface::class);
213
214
        $middleware = new SessionMiddleware(
215
            new Sha256(),
216
            'foo',
217
            'foo',
218
            SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
219
            new Parser(),
220
            1000,
221
            $currentTimeProvider,
0 ignored issues
show
Bug introduced by
It seems like $currentTimeProvider defined by $this->createMock(\PSR7S...oviderInterface::class) on line 212 can also be of type object<PHPUnit_Framework_MockObject_MockObject>; however, PSR7Sessions\Storageless...ddleware::__construct() does only seem to accept object<PSR7Sessions\Stor...tTimeProviderInterface>, 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...
222
            100
223
        );
224
225
        // forcing ourselves to think of time as a mutable value:
226
        $time = time() + random_int(-100, +100);
227
228
        $currentTimeProvider->expects(self::any())->method('__invoke')->willReturn(new \DateTimeImmutable('@' . $time));
0 ignored issues
show
Bug introduced by
The method expects does only exist in PHPUnit_Framework_MockObject_MockObject, but not in PSR7Sessions\Storageless...ntTimeProviderInterface.

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...
229
230
        $requestWithTokenIssuedInThePast = (new ServerRequest())
231
            ->withCookieParams([
232
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
233
                    ->setExpiration($time + 10000)
234
                    ->setIssuedAt($time - 100)
235
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
236
                    ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
237
                    ->getToken()
238
            ]);
239
240
        $cookie = $this->getCookie($middleware->process($requestWithTokenIssuedInThePast, $this->defaultDelegate()));
241
242
        $token = (new Parser())->parse($cookie->getValue());
243
244
        self::assertEquals($time, $token->getClaim(SessionMiddleware::ISSUED_AT_CLAIM), 'Token was refreshed');
245
    }
246
247
    /**
248
     * @dataProvider validMiddlewaresProvider
249
     */
250
    public function testWillSkipInjectingSessionCookiesWhenSessionIsNotChanged(SessionMiddleware $middleware)
251
    {
252
        $this->ensureSameResponse(
253
            $middleware,
254
            $this->requestWithResponseCookies(
255
                $middleware->process(new ServerRequest(), $this->writingDelegate())
256
            ),
257
            $this->fakeDelegate(
258
                function (ServerRequestInterface $request) {
259
                    /* @var $session SessionInterface */
260
                    $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
261
262
                    // note: we set the same data just to make sure that we are indeed interacting with the session
263
                    $session->set('foo', 'bar');
264
265
                    self::assertFalse($session->hasChanged());
266
267
                    return new Response();
268
                }
269
            )
270
        );
271
    }
272
273
    /**
274
     * @dataProvider validMiddlewaresProvider
275
     */
276
    public function testWillSendExpirationCookieWhenSessionContentsAreCleared(SessionMiddleware $middleware)
277
    {
278
        $this->ensureClearsSessionCookie(
279
            $middleware,
280
            $this->requestWithResponseCookies(
281
                $middleware->process(new ServerRequest(), $this->writingDelegate())
282
            ),
283
            $this->fakeDelegate(
284
                function (ServerRequestInterface $request) {
285
                    /* @var $session SessionInterface */
286
                    $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
287
288
                    $session->clear();
289
290
                    return new Response();
291
                }
292
            )
293
        );
294
    }
295
296
    /**
297
     * @dataProvider validMiddlewaresProvider
298
     */
299
    public function testWillIgnoreMalformedTokens(SessionMiddleware $middleware)
300
    {
301
        $this->ensureSameResponse(
302
            $middleware,
303
            (new ServerRequest())->withCookieParams([SessionMiddleware::DEFAULT_COOKIE => 'malformed content']),
304
            $this->emptyValidationDelegate()
305
        );
306
    }
307
308
    public function testRejectsTokensWithInvalidSignature()
309
    {
310
        $middleware = new SessionMiddleware(
311
            new Sha256(),
312
            'foo',
313
            'bar', // wrong symmetric key (on purpose)
314
            SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
315
            new Parser(),
316
            100,
317
            new SystemCurrentTime()
318
        );
319
320
        $this->ensureSameResponse(
321
            $middleware,
322
            $this->requestWithResponseCookies(
323
                $middleware->process(new ServerRequest(), $this->writingDelegate())
324
            ),
325
            $this->emptyValidationDelegate()
326
        );
327
    }
328
329
    public function testAllowsModifyingCookieDetails()
330
    {
331
        $defaultCookie = SetCookie::create('a-different-cookie-name')
332
            ->withDomain('foo.bar')
333
            ->withPath('/yadda')
334
            ->withHttpOnly(false)
335
            ->withMaxAge('123123')
336
            ->withValue('a-random-value');
337
338
        $dateTime   = new DateTimeImmutable();
339
        $middleware = new SessionMiddleware(
340
            new Sha256(),
341
            'foo',
342
            'foo',
343
            $defaultCookie,
344
            new Parser(),
345
            123456,
346
            new FakeCurrentTime($dateTime),
347
            123
348
        );
349
350
        $response = $this->ensureNotSameResponse($middleware, new ServerRequest(), $this->writingDelegate());
351
352
        self::assertNull($this->getCookie($response)->getValue());
353
354
        $tokenCookie = $this->getCookie($response, 'a-different-cookie-name');
355
356
        self::assertNotEmpty($tokenCookie->getValue());
357
        self::assertNotSame($defaultCookie->getValue(), $tokenCookie->getValue());
358
        self::assertSame($defaultCookie->getDomain(), $tokenCookie->getDomain());
359
        self::assertSame($defaultCookie->getPath(), $tokenCookie->getPath());
360
        self::assertSame($defaultCookie->getHttpOnly(), $tokenCookie->getHttpOnly());
361
        self::assertSame($defaultCookie->getMaxAge(), $tokenCookie->getMaxAge());
362
        self::assertEquals($dateTime->getTimestamp() + 123456, $tokenCookie->getExpires());
363
    }
364
365
    public function testSessionTokenParsingIsDelayedWhenSessionIsNotBeingUsed()
366
    {
367
        /* @var $signer Signer|\PHPUnit_Framework_MockObject_MockObject */
368
        $signer = $this->createMock(Signer::class);
369
370
        $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...
371
372
        $currentTimeProvider = new SystemCurrentTime();
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 368 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
                    ->getToken()
380
            ]);
381
382
        $middleware->process(
383
            $request,
384
            $this->fakeDelegate(function (ServerRequestInterface $request) {
385
                self::assertInstanceOf(
386
                    SessionInterface::class,
387
                    $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE)
388
                );
389
390
                return new Response();
391
            })
392
        );
393
    }
394
395
    public function testShouldRegenerateTokenWhenRequestHasATokenThatIsAboutToExpire()
396
    {
397
        $dateTime   = new DateTimeImmutable();
398
        $middleware = new SessionMiddleware(
399
            new Sha256(),
400
            'foo',
401
            'foo',
402
            SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
403
            new Parser(),
404
            1000,
405
            new FakeCurrentTime($dateTime),
406
            300
407
        );
408
409
        $expiringToken = (new ServerRequest())
410
            ->withCookieParams([
411
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
412
                    ->setIssuedAt((new \DateTime('-800 second'))->getTimestamp())
413
                    ->setExpiration((new \DateTime('+200 second'))->getTimestamp())
414
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
415
                    ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
416
                    ->getToken()
417
            ]);
418
419
        $response = $this->ensureNotSameResponse($middleware, $expiringToken, $this->writingDelegate());
420
421
        $tokenCookie = $this->getCookie($response);
422
423
        self::assertNotEmpty($tokenCookie->getValue());
424
        self::assertEquals($dateTime->getTimestamp() + 1000, $tokenCookie->getExpires());
425
    }
426
427
    public function testShouldNotRegenerateTokenWhenRequestHasATokenThatIsFarFromExpiration()
428
    {
429
        $middleware = new SessionMiddleware(
430
            new Sha256(),
431
            'foo',
432
            'foo',
433
            SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
434
            new Parser(),
435
            1000,
436
            new SystemCurrentTime(),
437
            300
438
        );
439
440
        $validToken = (new ServerRequest())
441
            ->withCookieParams([
442
                SessionMiddleware::DEFAULT_COOKIE => (string) (new Builder())
443
                    ->setIssuedAt((new \DateTime('-100 second'))->getTimestamp())
444
                    ->setExpiration((new \DateTime('+900 second'))->getTimestamp())
445
                    ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
446
                    ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
447
                    ->getToken()
448
            ]);
449
450
        $this->ensureSameResponse($middleware, $validToken, $this->defaultDelegate());
451
    }
452
453
    /**
454
     * @return SessionMiddleware[][]
455
     */
456
    public function validMiddlewaresProvider()
457
    {
458
        return [
459
            [new SessionMiddleware(
460
                new Sha256(),
461
                'foo',
462
                'foo',
463
                SetCookie::create(SessionMiddleware::DEFAULT_COOKIE),
464
                new Parser(),
465
                100,
466
                new SystemCurrentTime()
467
            )],
468
            [SessionMiddleware::fromSymmetricKeyDefaults('not relevant', 100)],
469
            [SessionMiddleware::fromAsymmetricKeyDefaults(
470
                file_get_contents(__DIR__ . '/../../keys/private_key.pem'),
471
                file_get_contents(__DIR__ . '/../../keys/public_key.pem'),
472
                200
473
            )],
474
        ];
475
    }
476
477
    /**
478
     * @group #46
479
     */
480
    public function testFromSymmetricKeyDefaultsWillHaveADefaultSessionPath()
481
    {
482
        self::assertSame(
483
            '/',
484
            $this
485
                ->getCookie(
486
                    SessionMiddleware::fromSymmetricKeyDefaults('not relevant', 100)
487
                        ->process(new ServerRequest(), $this->writingDelegate())
488
                )
489
                ->getPath()
490
        );
491
    }
492
493
    /**
494
     * @group #46
495
     *
496
     * @throws \InvalidArgumentException
497
     * @throws \OutOfBoundsException
498
     */
499
    public function testFromAsymmetricKeyDefaultsWillHaveADefaultSessionPath()
500
    {
501
        self::assertSame(
502
            '/',
503
            $this
504
                ->getCookie(
505
                    SessionMiddleware
506
                        ::fromAsymmetricKeyDefaults(
507
                            file_get_contents(__DIR__ . '/../../keys/private_key.pem'),
508
                            file_get_contents(__DIR__ . '/../../keys/public_key.pem'),
509
                            200
510
                        )
511
                        ->process(new ServerRequest(), $this->writingDelegate())
512
                )
513
                ->getPath()
514
        );
515
    }
516
517
    /**
518
     * @param SessionMiddleware      $middleware
519
     * @param ServerRequestInterface $request
520
     * @param DelegateInterface      $delegate
521
     *
522
     * @return ResponseInterface
523
     */
524
    private function ensureSameResponse(
525
        SessionMiddleware $middleware,
526
        ServerRequestInterface $request,
527
        DelegateInterface $delegate
528
    ): ResponseInterface {
529
        $initialResponse = new Response();
530
        $response = $middleware->process($request, $delegate);
531
532
        self::assertSame($initialResponse->getHeaders(), $response->getHeaders());
533
534
        return $response;
535
    }
536
537
    private function ensureNotSameResponse(
538
        SessionMiddleware $middleware,
539
        ServerRequestInterface $request,
540
        DelegateInterface $delegate
541
    ): ResponseInterface {
542
        $initialResponse = new Response();
543
        $response = $middleware->process($request, $delegate);
544
545
        self::assertNotSame($initialResponse->getHeaders(), $response->getHeaders());
546
547
        return $response;
548
    }
549
550
    /**
551
     * @param SessionMiddleware      $middleware
552
     * @param ServerRequestInterface $request
553
     * @param DelegateInterface      $delegate
554
     *
555
     * @return ResponseInterface
556
     */
557
    private function ensureClearsSessionCookie(
558
        SessionMiddleware $middleware,
559
        ServerRequestInterface $request,
560
        DelegateInterface $delegate
561
    ): ResponseInterface {
562
        $initialResponse = new Response();
563
        $response = $middleware->process($request, $delegate);
564
565
        self::assertNotSame($initialResponse->getHeaders(), $response->getHeaders());
566
567
        $cookie = $this->getCookie($response);
568
569
        self::assertLessThan((new \DateTime('-29 day'))->getTimestamp(), $cookie->getExpires());
570
        self::assertEmpty($cookie->getValue());
571
572
        return $response;
573
    }
574
575
    /**
576
     * @param SessionMiddleware $middleware
577
     * @param \DateTime $issuedAt
578
     * @param \DateTime $expiration
579
     *
580
     * @return string
581
     */
582
    private function createToken(SessionMiddleware $middleware, \DateTime $issuedAt, \DateTime $expiration): string
583
    {
584
        return (string) (new Builder())
585
            ->setIssuedAt($issuedAt->getTimestamp())
586
            ->setExpiration($expiration->getTimestamp())
587
            ->set(SessionMiddleware::SESSION_CLAIM, DefaultSessionData::fromTokenData(['foo' => 'bar']))
588
            ->sign($this->getSigner($middleware), $this->getSignatureKey($middleware))
589
            ->getToken();
590
    }
591
592
    /**
593
     * @return DelegateInterface
594
     */
595
    private function emptyValidationDelegate(): DelegateInterface
596
    {
597
        return $this->fakeDelegate(
598
            function (ServerRequestInterface $request) {
599
                /* @var $session SessionInterface */
600
                $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
601
602
                self::assertInstanceOf(SessionInterface::class, $session);
603
                self::assertTrue($session->isEmpty());
604
605
                return new Response();
606
            }
607
        );
608
    }
609
610
    /**
611
     * @param string $value
612
     *
613
     * @return DelegateInterface
614
     */
615
    private function writingDelegate($value = 'bar'): DelegateInterface
616
    {
617
        return $this->fakeDelegate(
618
            function (ServerRequestInterface $request) use ($value) {
619
                /* @var $session SessionInterface */
620
                $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
621
                $session->set('foo', $value);
622
623
                return new Response();
624
            }
625
        );
626
    }
627
628
    /**
629
     * @return DelegateInterface
630
     */
631
    private function defaultDelegate(): DelegateInterface
632
    {
633
        return $this->fakeDelegate(
634
            function (ServerRequestInterface $request) {
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

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

Loading history...
635
                return new Response();
636
            }
637
        );
638
    }
639
640
    /**
641
     * @param callable $callback
642
     *
643
     * @return DelegateInterface
644
     */
645
    private function fakeDelegate(callable $callback): DelegateInterface
646
    {
647
        $delegate = $this->createMock(DelegateInterface::class);
648
649
        $delegate->expects($this->once())->method('process')->willReturnCallback($callback)->with(
650
            self::isInstanceOf(ServerRequestInterface::class)
651
        );
652
653
        return $delegate;
654
    }
655
656
    /**
657
     * @param ResponseInterface $response
658
     *
659
     * @return \Zend\Diactoros\ServerRequest
660
     */
661
    private function requestWithResponseCookies(ResponseInterface $response): ServerRequestInterface
662
    {
663
        return (new ServerRequest())->withCookieParams([
664
            SessionMiddleware::DEFAULT_COOKIE => $this->getCookie($response)->getValue()
665
        ]);
666
    }
667
668
    /**
669
     * @param ResponseInterface $response
670
     *
671
     * @return SetCookie
672
     */
673
    private function getCookie(ResponseInterface $response, string $name = SessionMiddleware::DEFAULT_COOKIE): SetCookie
674
    {
675
        return FigResponseCookies::get($response, $name);
676
    }
677
678
    /**
679
     * @param SessionMiddleware $middleware
680
     *
681
     * @return Signer
682
     */
683
    private function getSigner(SessionMiddleware $middleware): Signer
684
    {
685
        return $this->getPropertyValue($middleware, 'signer');
686
    }
687
688
    /**
689
     * @param SessionMiddleware $middleware
690
     *
691
     * @return string
692
     */
693
    private function getSignatureKey(SessionMiddleware $middleware): string
694
    {
695
        return $this->getPropertyValue($middleware, 'signatureKey');
696
    }
697
698
    /**
699
     * @param object $object
700
     * @param string $name
701
     *
702
     * @return mixed
703
     */
704
    private function getPropertyValue($object, string $name)
705
    {
706
        $propertyReflection = new \ReflectionProperty($object, $name);
707
        $propertyReflection->setAccessible(true);
708
709
        return $propertyReflection->getValue($object);
710
    }
711
}
712