Skip to content

Commit

Permalink
Update CSRF feature
Browse files Browse the repository at this point in the history
  • Loading branch information
nguereza-tony committed Nov 2, 2023
1 parent 10831e4 commit a0535d8
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 11 deletions.
6 changes: 4 additions & 2 deletions src/Http/Middleware/CsrfMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
namespace Platine\Framework\Http\Middleware;

use Platine\Config\Config;
use Platine\Framework\Http\RequestData;
use Platine\Framework\Security\Csrf\CsrfManager;
use Platine\Http\Handler\MiddlewareInterface;
use Platine\Http\Handler\RequestHandlerInterface;
Expand Down Expand Up @@ -160,9 +159,12 @@ protected function shouldBeProcessed(ServerRequestInterface $request): bool
return false;
}

// Check for route attribute (useful for GET method)
$csrf = (bool) $route->getAttribute('csrf');

$methods = $this->config->get('security.csrf.http_methods', []);

if (!in_array($request->getMethod(), $methods)) {
if (!in_array($request->getMethod(), $methods) && $csrf === false) {
return false;
}

Expand Down
8 changes: 0 additions & 8 deletions src/Security/Csrf/CsrfManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,6 @@ public function getToken(?string $key = null): string
if ($key === null) {
$key = $this->getConfigValue('key');
}

if ($this->unique === false) {
$value = sha1(Str::randomToken(24));
$expire = $this->getConfigValue('expire') ?? 300;
$expireTime = time() + $expire;

$this->storage->set($key, $value, $expireTime);
}

$value = $this->storage->get($key);
if ($value === null) {
Expand Down
2 changes: 1 addition & 1 deletion src/Security/Csrf/Storage/CsrfSessionStorage.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public function clear(): void
* @param string $name
* @return string
*/
private function getKeyName(string $name): string
protected function getKeyName(string $name): string
{
return sprintf('%s.%s', self::CSRF_SESSION_KEY, $name);
}
Expand Down
75 changes: 75 additions & 0 deletions src/Security/Csrf/Storage/CsrfUserSessionStorage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

/**
* Platine Framework
*
* Platine Framework is a lightweight, high-performance, simple and elegant PHP
* Web framework
*
* This content is released under the MIT License (MIT)
*
* Copyright (c) 2020 Platine Framework
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

/**
* @file CsrfUserSessionStorage.php
*
* The CSRF storage based on user session
*
* @package Platine\Framework\Security\Csrf\Storage
* @author Platine Developers team
* @copyright Copyright (c) 2020
* @license http://opensource.org/licenses/MIT MIT License
* @link https://www.platine-php.com
* @version 1.0.0
* @filesource
*/

declare(strict_types=1);

namespace Platine\Framework\Security\Csrf\Storage;

/**
* @class CsrfUserSessionStorage
* @package Platine\Framework\Security\Csrf\Storage
*/
class CsrfUserSessionStorage extends CsrfSessionStorage
{
/**
* {@inheritdoc}
*/
public function get(string $name): ?string
{
$key = $this->getKeyName($name);
$token = $this->session->get($key, null);

return $token;
}

/**
* {@inheritdoc}
*/
public function set(string $name, string $token, int $expire): void
{
$key = $this->getKeyName($name);
$this->session->set($key, $token);
}
}
32 changes: 32 additions & 0 deletions tests/Http/Middleware/CsrfMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,36 @@ public function testProcessSuccess(): void

$this->assertEquals(0, $res->getStatusCode());
}

public function testProcessSuccessUsingGetMethod(): void
{
$route = $this->getMockInstance(Route::class, [
'getPattern' => '/bar/foo',
'getAttribute' => true,
]);
$request = $this->getMockInstance(ServerRequest::class, [
'getAttribute' => $route,
'getMethod' => 'GET',
'getQueryParams' => ['csrf_key' => 'foo'],
]);
$handler = $this->getMockInstance(HttpKernel::class);

$manager = $this->getMockInstance(CsrfManager::class, [
'validate' => true
]);
$lang = $this->getMockInstance(Lang::class);
$logger = $this->getMockInstance(Logger::class);
$config = $this->getMockInstanceMap(Config::class, [
'get' => [
['security.csrf.http_methods', [], ['POST']],
['security.csrf.url_whitelist', [], ['/api']],
['security.csrf.key', '', 'csrf_key'],
]
]);

$o = new CsrfMiddleware($logger, $lang, $config, $manager);
$res = $o->process($request, $handler);

$this->assertEquals(0, $res->getStatusCode());
}
}
81 changes: 81 additions & 0 deletions tests/Security/Csrf/Storage/CsrfUserSessionStorageTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

declare(strict_types=1);

namespace Platine\Test\Framework\Security\Csrf\Storage;

use Platine\Dev\PlatineTestCase;
use Platine\Framework\Security\Csrf\Storage\CsrfSessionStorage;
use Platine\Framework\Security\Csrf\Storage\CsrfUserSessionStorage;
use Platine\Session\Session;

/*
* @group core
* @group security
*/
class CsrfUserSessionStorageTest extends PlatineTestCase
{
public function testConstruct(): void
{
$session = new Session();

$o = new CsrfUserSessionStorage($session);

$this->assertInstanceOf(CsrfUserSessionStorage::class, $o);
}

public function testGetNull(): void
{
$session = new Session();

$o = new CsrfUserSessionStorage($session);

$this->assertNull($o->get('token'));
}

public function testGetDeleteClearSuccess(): void
{
$_SESSION[CsrfSessionStorage::CSRF_SESSION_KEY] = ['token' => 'foobar'];
$session = new Session();

$o = new CsrfUserSessionStorage($session);

$res = $o->get('token');
$this->assertEquals('foobar', $res);
$this->assertCount(1, $_SESSION[CsrfSessionStorage::CSRF_SESSION_KEY]);
$o->delete('token');

$this->assertNull($o->get('token'));
$this->assertIsArray($_SESSION[CsrfSessionStorage::CSRF_SESSION_KEY]);
$this->assertCount(0, $_SESSION[CsrfSessionStorage::CSRF_SESSION_KEY]);

$o->clear();
$this->assertNull($o->get('token'));
$this->assertArrayNotHasKey(CsrfSessionStorage::CSRF_SESSION_KEY, $_SESSION);
}

public function testSet(): void
{
$session = new Session();

$o = new CsrfUserSessionStorage($session);

$this->assertNull($o->get('token'));
$this->assertArrayNotHasKey(CsrfSessionStorage::CSRF_SESSION_KEY, $_SESSION);

$o->set('token', 'foobar', time() + 100);

$res = $o->get('token');
$this->assertEquals('foobar', $res);
$this->assertCount(1, $_SESSION[CsrfSessionStorage::CSRF_SESSION_KEY]);
$o->delete('token');

$this->assertNull($o->get('token'));
$this->assertIsArray($_SESSION[CsrfSessionStorage::CSRF_SESSION_KEY]);
$this->assertCount(0, $_SESSION[CsrfSessionStorage::CSRF_SESSION_KEY]);

$o->clear();
$this->assertNull($o->get('token'));
$this->assertArrayNotHasKey(CsrfSessionStorage::CSRF_SESSION_KEY, $_SESSION);
}
}

0 comments on commit a0535d8

Please sign in to comment.