Bonjour,
Voila je rencontre un petit problème avec mon code.
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.
Faire fonctionner mon test
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 :(