Bonjour,

Voila je rencontre un petit problème avec mon code.

Ce que je fais

Je suis la formation de Grafikart depuis quelques mois maintenant et en résumé, ce n’est pas la grande forme; je veux dire ce n’est pas évident avec les changements qui s'opèrent a un rythme vraiment trop mathématique. Bref je vais décrire ça avec ma situation actuelle.

Mon code CsrfMiddleware

<?php
/**
 * Created by IntelliJ IDEA.
 * User: maximux
 * Date: 27/06/18
 * Time: 22:29
 */

namespace App\Framework\Middleware;

use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class CsrfMiddleware implements MiddlewareInterface
{

    /**
     * @var string
     */
    private $formKey;

    /**
     * @var string
     */
    private $sessionKey;

    /**
     * @var \ArrayAccess
     */
    private $session;

    /**
     * @var int
     */
    private $limit;

    public function __construct(array &$session, int $limit = 50, string $formKey = '_csrf', string $sessionKey = 'csrf')
    {
        $this->session = &$session;
        $this->formKey = $formKey;
        $this->sessionKey = $sessionKey;
        $this->limit = $limit;
    }

    public function process(ServerRequestInterface $request, DelegateInterface $delegate): ResponseInterface
    {
        if (in_array($request->getMethod(), ['POST', 'PUT', 'DELETE'])) {
            $params = $request->getParsedBody() ?: [];
            if (!array_key_exists($this->formKey, $params)) {
                $this->reject();
            } else {
                $csrfList[] = $this->session[$this->sessionKey] ?? [];
                if (in_array($params[$this->formKey], $csrfList)) {
                    $this->useToken($params[$this->formKey]);
                    return $delegate->process($request);
                } else {
                    $this->reject();
                }
            }
        } else {
            return $delegate->process($request);
        }
    }

    public function generateToken(): string
    {
        $token = bin2hex(random_bytes(16));
        $csrfList = $this->session[$this->sessionKey] ?? [];
        $csrfList[] = $token;
        $this->session[$this->sessionKey] = $csrfList;
        $this->limitTokens();
        return $token;
    }

    private function reject(): void
    {
        throw new \Exception();
    }

    private function useToken($token): void
    {
        $tokens = array_filter($this->session[$this->sessionKey], function ($t) use ($token) {
            return $token !== $t;
        });
        $this->session[$this->sessionKey] = $tokens;
    }

    private function limitTokens(): void
    {
        $tokens = $this->session[$this->sessionKey] ?? [];
        if (count($tokens) > $this->limit) {
            array_shift($tokens);
        }
        $this->session[$this->sessionKey] = $tokens;
    }
}

Le CsrfMiddlewareTest

<?php
/**
 * Created by IntelliJ IDEA.
 * User: maximux
 * Date: 27/06/18
 * Time: 22:33
 */

namespace Tests\Framework\Middleware;

use App\Framework\Middleware\CsrfMiddleware;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\ServerRequest;
use Interop\Http\ServerMiddleware\DelegateInterface;
use PHPUnit\Framework\TestCase;

class CsrfMiddlewareTest extends TestCase
{

    /**
     * @var CsrfMiddleware
     */
    private $middleware;
    private $session;

    public function setUp()
    {
        $this->session = [];
        $this->middleware = new CsrfMiddleware($this->session);
    }

    public function testLetGetRequestPass()
    {
        $delegate = $this->getMockBuilder(DelegateInterface::class)
            ->setMethods(['process'])
            ->getMock();
        $delegate->expects($this->once())
            ->method('process')
            ->willReturn(new Response());
        $request = (new ServerRequest('GET', '/demo'));
        $this->middleware->process($request, $delegate);
    }

    public function testBlockPostRequestWithoutCsrf()
    {
        $delegate = $this->getMockBuilder(DelegateInterface::class)
            ->setMethods(['process'])
            ->getMock();
        $delegate->expects($this->never())->method('process');
        $this->middleware->generateToken();
        $request = (new ServerRequest('POST', '/demo'));
        $this->expectException(\Exception::class);
        $this->middleware->process($request, $delegate);
    }

    public function testBlockPostRequestWithInvalidCsrf()
    {
        $delegate = $this->getMockBuilder(DelegateInterface::class)
            ->setMethods(['process'])
            ->getMock();
        $delegate->expects($this->never())->method('process');
        $this->middleware->generateToken();
        $request = (new ServerRequest('POST', '/demo'));
        $request = $request->withParsedBody(['_csrf' => 'azeaze']);
        $this->expectException(\Exception::class);
        $this->middleware->process($request, $delegate);
    }

    public function testLetPostWithTokenPass()
    {
        $delegate = $this->getMockBuilder(DelegateInterface::class)
            ->setMethods(['process'])
            ->getMock();
        $delegate->expects($this->once())->method('process')
            ->willReturn(new Response());
        $request = (new ServerRequest('POST', '/demo'));
        $token = $this->middleware->generateToken();
        $request = $request->withParsedBody(['_csrf' => $token]);
        $this->middleware->process($request, $delegate);
    }

    public function testLetPostWithTokenPassOnce()
    {
        $delegate = $this->getMockBuilder(DelegateInterface::class)
            ->setMethods(['process'])
            ->getMock();
        $delegate->expects($this->once())->method('process')->willReturn(new Response());
        $request = (new ServerRequest('POST', '/demo'));
        $token = $this->middleware->generateToken();
        $request = $request->withParsedBody(['_csrf' => $token]);
        $this->middleware->process($request, $delegate);
        $this->expectException(\Exception::class);
        $this->middleware->process($request, $delegate);
    }

    public function testLimitTheTokenNumber()
    {
        for($i = 0; $i < 100; ++$i) {
            $token = $this->middleware->generateToken();
        }
        $this->assertCount(50, $this->session['csrf']);
        $this->assertEquals($token, $this->session['csrf'][49]);
    }
}

En fait, lorsque je survole le curseur sur $delegate dans le CsrfMiddlewareTest, j'obtiens ceci :
Expected \Interop\Http\ServerMiddleware\DelegateInterface, got \PHPUnit_Framework_MockObject_MockObject less... (Ctrl+F1)
Invocation parameter types are not compatible with declared.

Ce que je veux

Faire fonctionner mon test

Ce que j'obtiens

C:\www\MonFramework>.\vendor\bin\phpunit tests\Framework\Middleware\CsrfMiddlewareTest.php
PHPUnit 6.2.3 by Sebastian Bergmann and contributors.

...EE. 6 / 6 (100%)

Time: 538 ms, Memory: 4.00MB

There were 2 errors:

1) Tests\Framework\Middleware\CsrfMiddlewareTest::testLetPostWithTokenPass
Exception:

C:\www\MonFramework\src\Framework\Middleware\CsrfMiddleware.php:80
C:\www\MonFramework\src\Framework\Middleware\CsrfMiddleware.php:60
C:\www\MonFramework\tests\Framework\Middleware\CsrfMiddlewareTest.php:80

2) Tests\Framework\Middleware\CsrfMiddlewareTest::testLetPostWithTokenPassOnce
Exception:

C:\www\MonFramework\src\Framework\Middleware\CsrfMiddleware.php:80
C:\www\MonFramework\src\Framework\Middleware\CsrfMiddleware.php:60
C:\www\MonFramework\tests\Framework\Middleware\CsrfMiddlewareTest.php:92

ERRORS!
Tests: 6, Assertions: 7, Errors: 2.

A l'aide :(

Aucune réponse