Actualización

This commit is contained in:
Xes
2025-04-10 12:24:57 +02:00
parent 8969cc929d
commit 45420b6f0d
39760 changed files with 4303286 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
vendor/
composer.lock
phpunit.xml

View File

@@ -0,0 +1,72 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf;
/**
* A CSRF token.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class CsrfToken
{
/**
* @var string
*/
private $id;
/**
* @var string
*/
private $value;
/**
* Constructor.
*
* @param string $id The token ID
* @param string $value The actual token value
*/
public function __construct($id, $value)
{
$this->id = (string) $id;
$this->value = (string) $value;
}
/**
* Returns the ID of the CSRF token.
*
* @return string The token ID
*/
public function getId()
{
return $this->id;
}
/**
* Returns the value of the CSRF token.
*
* @return string The token value
*/
public function getValue()
{
return $this->value;
}
/**
* Returns the value of the CSRF token.
*
* @return string The token value
*/
public function __toString()
{
return $this->value;
}
}

View File

@@ -0,0 +1,134 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
use Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator;
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
use Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage;
use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface;
/**
* Default implementation of {@link CsrfTokenManagerInterface}.
*
* @author Bernhard Schussek <bschussek@gmail.com>
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class CsrfTokenManager implements CsrfTokenManagerInterface
{
/**
* @var TokenGeneratorInterface
*/
private $generator;
/**
* @var TokenStorageInterface
*/
private $storage;
private $namespace;
/**
* Creates a new CSRF provider using PHP's native session storage.
*
* @param null|string|RequestStack|callable $namespace
* * null: generates a namespace using $_SERVER['HTTPS']
* * string: uses the given string
* * RequestStack: generates a namespace using the current master request
* * callable: uses the result of this callable (must return a string)
*
* @param TokenGeneratorInterface|null $generator The token generator
* @param TokenStorageInterface|null $storage The storage for storing
* generated CSRF tokens
*/
public function __construct(TokenGeneratorInterface $generator = null, TokenStorageInterface $storage = null, $namespace = null)
{
$this->generator = $generator ?: new UriSafeTokenGenerator();
$this->storage = $storage ?: new NativeSessionTokenStorage();
$superGlobalNamespaceGenerator = function () {
return !empty($_SERVER['HTTPS']) && 'off' !== strtolower($_SERVER['HTTPS']) ? 'https-' : '';
};
if (null === $namespace) {
$this->namespace = $superGlobalNamespaceGenerator;
} elseif ($namespace instanceof RequestStack) {
$this->namespace = function () use ($namespace, $superGlobalNamespaceGenerator) {
if ($request = $namespace->getMasterRequest()) {
return $request->isSecure() ? 'https-' : '';
}
return $superGlobalNamespaceGenerator();
};
} elseif (is_callable($namespace) || is_string($namespace)) {
$this->namespace = $namespace;
} else {
throw new InvalidArgumentException(sprintf('$namespace must be a string, a callable returning a string, null or an instance of "RequestStack". "%s" given.', gettype($namespace)));
}
}
/**
* {@inheritdoc}
*/
public function getToken($tokenId)
{
$namespacedId = $this->getNamespace().$tokenId;
if ($this->storage->hasToken($namespacedId)) {
$value = $this->storage->getToken($namespacedId);
} else {
$value = $this->generator->generateToken();
$this->storage->setToken($namespacedId, $value);
}
return new CsrfToken($tokenId, $value);
}
/**
* {@inheritdoc}
*/
public function refreshToken($tokenId)
{
$namespacedId = $this->getNamespace().$tokenId;
$value = $this->generator->generateToken();
$this->storage->setToken($namespacedId, $value);
return new CsrfToken($tokenId, $value);
}
/**
* {@inheritdoc}
*/
public function removeToken($tokenId)
{
return $this->storage->removeToken($this->getNamespace().$tokenId);
}
/**
* {@inheritdoc}
*/
public function isTokenValid(CsrfToken $token)
{
$namespacedId = $this->getNamespace().$token->getId();
if (!$this->storage->hasToken($namespacedId)) {
return false;
}
return hash_equals($this->storage->getToken($namespacedId), $token->getValue());
}
private function getNamespace()
{
return is_callable($ns = $this->namespace) ? $ns() : $ns;
}
}

View File

@@ -0,0 +1,67 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf;
/**
* Manages CSRF tokens.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface CsrfTokenManagerInterface
{
/**
* Returns a CSRF token for the given ID.
*
* If previously no token existed for the given ID, a new token is
* generated. Otherwise the existing token is returned (with the same value,
* not the same instance).
*
* @param string $tokenId The token ID. You may choose an arbitrary value
* for the ID
*
* @return CsrfToken The CSRF token
*/
public function getToken($tokenId);
/**
* Generates a new token value for the given ID.
*
* This method will generate a new token for the given token ID, independent
* of whether a token value previously existed or not. It can be used to
* enforce once-only tokens in environments with high security needs.
*
* @param string $tokenId The token ID. You may choose an arbitrary value
* for the ID
*
* @return CsrfToken The CSRF token
*/
public function refreshToken($tokenId);
/**
* Invalidates the CSRF token with the given ID, if one exists.
*
* @param string $tokenId The token ID
*
* @return string|null Returns the removed token value if one existed, NULL
* otherwise
*/
public function removeToken($tokenId);
/**
* Returns whether the given CSRF token is valid.
*
* @param CsrfToken $token A CSRF token
*
* @return bool Returns true if the token is valid, false otherwise
*/
public function isTokenValid(CsrfToken $token);
}

View File

@@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf\Exception;
use Symfony\Component\Security\Core\Exception\RuntimeException;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class TokenNotFoundException extends RuntimeException
{
}

19
vendor/symfony/security/Csrf/LICENSE vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2004-2017 Fabien Potencier
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.

14
vendor/symfony/security/Csrf/README.md vendored Normal file
View File

@@ -0,0 +1,14 @@
Security Component - CSRF
=========================
The Security CSRF (cross-site request forgery) component provides a class
`CsrfTokenManager` for generating and validating CSRF tokens.
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/security/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View File

@@ -0,0 +1,224 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManager;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class CsrfTokenManagerTest extends TestCase
{
/**
* @dataProvider getManagerGeneratorAndStorage
*/
public function testGetNonExistingToken($namespace, $manager, $storage, $generator)
{
$storage->expects($this->once())
->method('hasToken')
->with($namespace.'token_id')
->will($this->returnValue(false));
$generator->expects($this->once())
->method('generateToken')
->will($this->returnValue('TOKEN'));
$storage->expects($this->once())
->method('setToken')
->with($namespace.'token_id', 'TOKEN');
$token = $manager->getToken('token_id');
$this->assertInstanceOf('Symfony\Component\Security\Csrf\CsrfToken', $token);
$this->assertSame('token_id', $token->getId());
$this->assertSame('TOKEN', $token->getValue());
}
/**
* @dataProvider getManagerGeneratorAndStorage
*/
public function testUseExistingTokenIfAvailable($namespace, $manager, $storage)
{
$storage->expects($this->once())
->method('hasToken')
->with($namespace.'token_id')
->will($this->returnValue(true));
$storage->expects($this->once())
->method('getToken')
->with($namespace.'token_id')
->will($this->returnValue('TOKEN'));
$token = $manager->getToken('token_id');
$this->assertInstanceOf('Symfony\Component\Security\Csrf\CsrfToken', $token);
$this->assertSame('token_id', $token->getId());
$this->assertSame('TOKEN', $token->getValue());
}
/**
* @dataProvider getManagerGeneratorAndStorage
*/
public function testRefreshTokenAlwaysReturnsNewToken($namespace, $manager, $storage, $generator)
{
$storage->expects($this->never())
->method('hasToken');
$generator->expects($this->once())
->method('generateToken')
->will($this->returnValue('TOKEN'));
$storage->expects($this->once())
->method('setToken')
->with($namespace.'token_id', 'TOKEN');
$token = $manager->refreshToken('token_id');
$this->assertInstanceOf('Symfony\Component\Security\Csrf\CsrfToken', $token);
$this->assertSame('token_id', $token->getId());
$this->assertSame('TOKEN', $token->getValue());
}
/**
* @dataProvider getManagerGeneratorAndStorage
*/
public function testMatchingTokenIsValid($namespace, $manager, $storage)
{
$storage->expects($this->once())
->method('hasToken')
->with($namespace.'token_id')
->will($this->returnValue(true));
$storage->expects($this->once())
->method('getToken')
->with($namespace.'token_id')
->will($this->returnValue('TOKEN'));
$this->assertTrue($manager->isTokenValid(new CsrfToken('token_id', 'TOKEN')));
}
/**
* @dataProvider getManagerGeneratorAndStorage
*/
public function testNonMatchingTokenIsNotValid($namespace, $manager, $storage)
{
$storage->expects($this->once())
->method('hasToken')
->with($namespace.'token_id')
->will($this->returnValue(true));
$storage->expects($this->once())
->method('getToken')
->with($namespace.'token_id')
->will($this->returnValue('TOKEN'));
$this->assertFalse($manager->isTokenValid(new CsrfToken('token_id', 'FOOBAR')));
}
/**
* @dataProvider getManagerGeneratorAndStorage
*/
public function testNonExistingTokenIsNotValid($namespace, $manager, $storage)
{
$storage->expects($this->once())
->method('hasToken')
->with($namespace.'token_id')
->will($this->returnValue(false));
$storage->expects($this->never())
->method('getToken');
$this->assertFalse($manager->isTokenValid(new CsrfToken('token_id', 'FOOBAR')));
}
/**
* @dataProvider getManagerGeneratorAndStorage
*/
public function testRemoveToken($namespace, $manager, $storage)
{
$storage->expects($this->once())
->method('removeToken')
->with($namespace.'token_id')
->will($this->returnValue('REMOVED_TOKEN'));
$this->assertSame('REMOVED_TOKEN', $manager->removeToken('token_id'));
}
public function testNamespaced()
{
$generator = $this->getMockBuilder('Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface')->getMock();
$storage = $this->getMockBuilder('Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface')->getMock();
$requestStack = new RequestStack();
$requestStack->push(new Request(array(), array(), array(), array(), array(), array('HTTPS' => 'on')));
$manager = new CsrfTokenManager($generator, $storage, null, $requestStack);
$token = $manager->getToken('foo');
$this->assertSame('foo', $token->getId());
}
public function getManagerGeneratorAndStorage()
{
$data = array();
list($generator, $storage) = $this->getGeneratorAndStorage();
$data[] = array('', new CsrfTokenManager($generator, $storage, ''), $storage, $generator);
list($generator, $storage) = $this->getGeneratorAndStorage();
$data[] = array('https-', new CsrfTokenManager($generator, $storage), $storage, $generator);
list($generator, $storage) = $this->getGeneratorAndStorage();
$data[] = array('aNamespace-', new CsrfTokenManager($generator, $storage, 'aNamespace-'), $storage, $generator);
$requestStack = new RequestStack();
$requestStack->push(new Request(array(), array(), array(), array(), array(), array('HTTPS' => 'on')));
list($generator, $storage) = $this->getGeneratorAndStorage();
$data[] = array('https-', new CsrfTokenManager($generator, $storage, $requestStack), $storage, $generator);
list($generator, $storage) = $this->getGeneratorAndStorage();
$data[] = array('generated-', new CsrfTokenManager($generator, $storage, function () {
return 'generated-';
}), $storage, $generator);
$requestStack = new RequestStack();
$requestStack->push(new Request());
list($generator, $storage) = $this->getGeneratorAndStorage();
$data[] = array('', new CsrfTokenManager($generator, $storage, $requestStack), $storage, $generator);
return $data;
}
private function getGeneratorAndStorage()
{
return array(
$this->getMockBuilder('Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface')->getMock(),
$this->getMockBuilder('Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface')->getMock(),
);
}
public function setUp()
{
$_SERVER['HTTPS'] = 'on';
}
public function tearDown()
{
parent::tearDown();
unset($_SERVER['HTTPS']);
}
}

View File

@@ -0,0 +1,60 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf\Tests\TokenGenerator;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class UriSafeTokenGeneratorTest extends TestCase
{
const ENTROPY = 1000;
/**
* A non alpha-numeric byte string.
*
* @var string
*/
private static $bytes;
/**
* @var UriSafeTokenGenerator
*/
private $generator;
public static function setUpBeforeClass()
{
self::$bytes = base64_decode('aMf+Tct/RLn2WQ==');
}
protected function setUp()
{
$this->generator = new UriSafeTokenGenerator(self::ENTROPY);
}
protected function tearDown()
{
$this->generator = null;
}
public function testGenerateToken()
{
$token = $this->generator->generateToken();
$this->assertTrue(ctype_print($token), 'is printable');
$this->assertStringNotMatchesFormat('%S+%S', $token, 'is URI safe');
$this->assertStringNotMatchesFormat('%S/%S', $token, 'is URI safe');
$this->assertStringNotMatchesFormat('%S=%S', $token, 'is URI safe');
}
}

View File

@@ -0,0 +1,124 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf\Tests\TokenStorage;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
*/
class NativeSessionTokenStorageTest extends TestCase
{
const SESSION_NAMESPACE = 'foobar';
/**
* @var NativeSessionTokenStorage
*/
private $storage;
public static function setUpBeforeClass()
{
ini_set('session.save_handler', 'files');
ini_set('session.save_path', sys_get_temp_dir());
parent::setUpBeforeClass();
}
protected function setUp()
{
$_SESSION = array();
$this->storage = new NativeSessionTokenStorage(self::SESSION_NAMESPACE);
}
public function testStoreTokenInClosedSession()
{
$this->storage->setToken('token_id', 'TOKEN');
$this->assertSame(array(self::SESSION_NAMESPACE => array('token_id' => 'TOKEN')), $_SESSION);
}
public function testStoreTokenInClosedSessionWithExistingSessionId()
{
session_id('foobar');
$this->assertSame(PHP_SESSION_NONE, session_status());
$this->storage->setToken('token_id', 'TOKEN');
$this->assertSame(PHP_SESSION_ACTIVE, session_status());
$this->assertSame(array(self::SESSION_NAMESPACE => array('token_id' => 'TOKEN')), $_SESSION);
}
public function testStoreTokenInActiveSession()
{
session_start();
$this->storage->setToken('token_id', 'TOKEN');
$this->assertSame(array(self::SESSION_NAMESPACE => array('token_id' => 'TOKEN')), $_SESSION);
}
/**
* @depends testStoreTokenInClosedSession
*/
public function testCheckToken()
{
$this->assertFalse($this->storage->hasToken('token_id'));
$this->storage->setToken('token_id', 'TOKEN');
$this->assertTrue($this->storage->hasToken('token_id'));
}
/**
* @depends testStoreTokenInClosedSession
*/
public function testGetExistingToken()
{
$this->storage->setToken('token_id', 'TOKEN');
$this->assertSame('TOKEN', $this->storage->getToken('token_id'));
}
/**
* @expectedException \Symfony\Component\Security\Csrf\Exception\TokenNotFoundException
*/
public function testGetNonExistingToken()
{
$this->storage->getToken('token_id');
}
/**
* @depends testCheckToken
*/
public function testRemoveNonExistingToken()
{
$this->assertNull($this->storage->removeToken('token_id'));
$this->assertFalse($this->storage->hasToken('token_id'));
}
/**
* @depends testCheckToken
*/
public function testRemoveExistingToken()
{
$this->storage->setToken('token_id', 'TOKEN');
$this->assertSame('TOKEN', $this->storage->removeToken('token_id'));
$this->assertFalse($this->storage->hasToken('token_id'));
}
}

View File

@@ -0,0 +1,259 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf\Tests\TokenStorage;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class SessionTokenStorageTest extends TestCase
{
const SESSION_NAMESPACE = 'foobar';
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $session;
/**
* @var SessionTokenStorage
*/
private $storage;
protected function setUp()
{
$this->session = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface')
->disableOriginalConstructor()
->getMock();
$this->storage = new SessionTokenStorage($this->session, self::SESSION_NAMESPACE);
}
public function testStoreTokenInClosedSession()
{
$this->session->expects($this->any())
->method('isStarted')
->will($this->returnValue(false));
$this->session->expects($this->once())
->method('start');
$this->session->expects($this->once())
->method('set')
->with(self::SESSION_NAMESPACE.'/token_id', 'TOKEN');
$this->storage->setToken('token_id', 'TOKEN');
}
public function testStoreTokenInActiveSession()
{
$this->session->expects($this->any())
->method('isStarted')
->will($this->returnValue(true));
$this->session->expects($this->never())
->method('start');
$this->session->expects($this->once())
->method('set')
->with(self::SESSION_NAMESPACE.'/token_id', 'TOKEN');
$this->storage->setToken('token_id', 'TOKEN');
}
public function testCheckTokenInClosedSession()
{
$this->session->expects($this->any())
->method('isStarted')
->will($this->returnValue(false));
$this->session->expects($this->once())
->method('start');
$this->session->expects($this->once())
->method('has')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue('RESULT'));
$this->assertSame('RESULT', $this->storage->hasToken('token_id'));
}
public function testCheckTokenInActiveSession()
{
$this->session->expects($this->any())
->method('isStarted')
->will($this->returnValue(true));
$this->session->expects($this->never())
->method('start');
$this->session->expects($this->once())
->method('has')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue('RESULT'));
$this->assertSame('RESULT', $this->storage->hasToken('token_id'));
}
public function testGetExistingTokenFromClosedSession()
{
$this->session->expects($this->any())
->method('isStarted')
->will($this->returnValue(false));
$this->session->expects($this->once())
->method('start');
$this->session->expects($this->once())
->method('has')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue(true));
$this->session->expects($this->once())
->method('get')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue('RESULT'));
$this->assertSame('RESULT', $this->storage->getToken('token_id'));
}
public function testGetExistingTokenFromActiveSession()
{
$this->session->expects($this->any())
->method('isStarted')
->will($this->returnValue(true));
$this->session->expects($this->never())
->method('start');
$this->session->expects($this->once())
->method('has')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue(true));
$this->session->expects($this->once())
->method('get')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue('RESULT'));
$this->assertSame('RESULT', $this->storage->getToken('token_id'));
}
/**
* @expectedException \Symfony\Component\Security\Csrf\Exception\TokenNotFoundException
*/
public function testGetNonExistingTokenFromClosedSession()
{
$this->session->expects($this->any())
->method('isStarted')
->will($this->returnValue(false));
$this->session->expects($this->once())
->method('start');
$this->session->expects($this->once())
->method('has')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue(false));
$this->storage->getToken('token_id');
}
/**
* @expectedException \Symfony\Component\Security\Csrf\Exception\TokenNotFoundException
*/
public function testGetNonExistingTokenFromActiveSession()
{
$this->session->expects($this->any())
->method('isStarted')
->will($this->returnValue(true));
$this->session->expects($this->never())
->method('start');
$this->session->expects($this->once())
->method('has')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue(false));
$this->storage->getToken('token_id');
}
public function testRemoveNonExistingTokenFromClosedSession()
{
$this->session->expects($this->any())
->method('isStarted')
->will($this->returnValue(false));
$this->session->expects($this->once())
->method('start');
$this->session->expects($this->once())
->method('remove')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue(null));
$this->assertNull($this->storage->removeToken('token_id'));
}
public function testRemoveNonExistingTokenFromActiveSession()
{
$this->session->expects($this->any())
->method('isStarted')
->will($this->returnValue(true));
$this->session->expects($this->never())
->method('start');
$this->session->expects($this->once())
->method('remove')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue(null));
$this->assertNull($this->storage->removeToken('token_id'));
}
public function testRemoveExistingTokenFromClosedSession()
{
$this->session->expects($this->any())
->method('isStarted')
->will($this->returnValue(false));
$this->session->expects($this->once())
->method('start');
$this->session->expects($this->once())
->method('remove')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue('TOKEN'));
$this->assertSame('TOKEN', $this->storage->removeToken('token_id'));
}
public function testRemoveExistingTokenFromActiveSession()
{
$this->session->expects($this->any())
->method('isStarted')
->will($this->returnValue(true));
$this->session->expects($this->never())
->method('start');
$this->session->expects($this->once())
->method('remove')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue('TOKEN'));
$this->assertSame('TOKEN', $this->storage->removeToken('token_id'));
}
}

View File

@@ -0,0 +1,27 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf\TokenGenerator;
/**
* Generates CSRF tokens.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface TokenGeneratorInterface
{
/**
* Generates a CSRF token.
*
* @return string The generated CSRF token
*/
public function generateToken();
}

View File

@@ -0,0 +1,50 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf\TokenGenerator;
/**
* Generates CSRF tokens.
*
* @author Bernhard Schussek <bernhard.schussek@symfony.com>
*/
class UriSafeTokenGenerator implements TokenGeneratorInterface
{
/**
* The amount of entropy collected for each token (in bits).
*
* @var int
*/
private $entropy;
/**
* Generates URI-safe CSRF tokens.
*
* @param int $entropy The amount of entropy collected for each token (in bits)
*/
public function __construct($entropy = 256)
{
$this->entropy = $entropy;
}
/**
* {@inheritdoc}
*/
public function generateToken()
{
// Generate an URI safe base64 encoded string that does not contain "+",
// "/" or "=" which need to be URL encoded and make URLs unnecessarily
// longer.
$bytes = random_bytes($this->entropy / 8);
return rtrim(strtr(base64_encode($bytes), '+/', '-_'), '=');
}
}

View File

@@ -0,0 +1,117 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf\TokenStorage;
use Symfony\Component\Security\Csrf\Exception\TokenNotFoundException;
/**
* Token storage that uses PHP's native session handling.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class NativeSessionTokenStorage implements TokenStorageInterface
{
/**
* The namespace used to store values in the session.
*
* @var string
*/
const SESSION_NAMESPACE = '_csrf';
/**
* @var bool
*/
private $sessionStarted = false;
/**
* @var string
*/
private $namespace;
/**
* Initializes the storage with a session namespace.
*
* @param string $namespace The namespace under which the token is stored
* in the session
*/
public function __construct($namespace = self::SESSION_NAMESPACE)
{
$this->namespace = $namespace;
}
/**
* {@inheritdoc}
*/
public function getToken($tokenId)
{
if (!$this->sessionStarted) {
$this->startSession();
}
if (!isset($_SESSION[$this->namespace][$tokenId])) {
throw new TokenNotFoundException('The CSRF token with ID '.$tokenId.' does not exist.');
}
return (string) $_SESSION[$this->namespace][$tokenId];
}
/**
* {@inheritdoc}
*/
public function setToken($tokenId, $token)
{
if (!$this->sessionStarted) {
$this->startSession();
}
$_SESSION[$this->namespace][$tokenId] = (string) $token;
}
/**
* {@inheritdoc}
*/
public function hasToken($tokenId)
{
if (!$this->sessionStarted) {
$this->startSession();
}
return isset($_SESSION[$this->namespace][$tokenId]);
}
/**
* {@inheritdoc}
*/
public function removeToken($tokenId)
{
if (!$this->sessionStarted) {
$this->startSession();
}
$token = isset($_SESSION[$this->namespace][$tokenId])
? (string) $_SESSION[$this->namespace][$tokenId]
: null;
unset($_SESSION[$this->namespace][$tokenId]);
return $token;
}
private function startSession()
{
if (PHP_SESSION_NONE === session_status()) {
session_start();
}
$this->sessionStarted = true;
}
}

View File

@@ -0,0 +1,107 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf\TokenStorage;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Csrf\Exception\TokenNotFoundException;
/**
* Token storage that uses a Symfony Session object.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class SessionTokenStorage implements TokenStorageInterface
{
/**
* The namespace used to store values in the session.
*
* @var string
*/
const SESSION_NAMESPACE = '_csrf';
/**
* The user session from which the session ID is returned.
*
* @var SessionInterface
*/
private $session;
/**
* @var string
*/
private $namespace;
/**
* Initializes the storage with a Session object and a session namespace.
*
* @param SessionInterface $session The user session
* @param string $namespace The namespace under which the token
* is stored in the session
*/
public function __construct(SessionInterface $session, $namespace = self::SESSION_NAMESPACE)
{
$this->session = $session;
$this->namespace = $namespace;
}
/**
* {@inheritdoc}
*/
public function getToken($tokenId)
{
if (!$this->session->isStarted()) {
$this->session->start();
}
if (!$this->session->has($this->namespace.'/'.$tokenId)) {
throw new TokenNotFoundException('The CSRF token with ID '.$tokenId.' does not exist.');
}
return (string) $this->session->get($this->namespace.'/'.$tokenId);
}
/**
* {@inheritdoc}
*/
public function setToken($tokenId, $token)
{
if (!$this->session->isStarted()) {
$this->session->start();
}
$this->session->set($this->namespace.'/'.$tokenId, (string) $token);
}
/**
* {@inheritdoc}
*/
public function hasToken($tokenId)
{
if (!$this->session->isStarted()) {
$this->session->start();
}
return $this->session->has($this->namespace.'/'.$tokenId);
}
/**
* {@inheritdoc}
*/
public function removeToken($tokenId)
{
if (!$this->session->isStarted()) {
$this->session->start();
}
return $this->session->remove($this->namespace.'/'.$tokenId);
}
}

View File

@@ -0,0 +1,58 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Csrf\TokenStorage;
/**
* Stores CSRF tokens.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface TokenStorageInterface
{
/**
* Reads a stored CSRF token.
*
* @param string $tokenId The token ID
*
* @return string The stored token
*
* @throws \Symfony\Component\Security\Csrf\Exception\TokenNotFoundException If the token ID does not exist
*/
public function getToken($tokenId);
/**
* Stores a CSRF token.
*
* @param string $tokenId The token ID
* @param string $token The CSRF token
*/
public function setToken($tokenId, $token);
/**
* Removes a CSRF token.
*
* @param string $tokenId The token ID
*
* @return string|null Returns the removed token if one existed, NULL
* otherwise
*/
public function removeToken($tokenId);
/**
* Checks whether a token with the given token ID exists.
*
* @param string $tokenId The token ID
*
* @return bool Whether a token exists with the given ID
*/
public function hasToken($tokenId);
}

View File

@@ -0,0 +1,45 @@
{
"name": "symfony/security-csrf",
"type": "library",
"description": "Symfony Security Component - CSRF Library",
"keywords": [],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=5.5.9",
"symfony/polyfill-php56": "~1.0",
"symfony/polyfill-php70": "~1.0",
"symfony/security-core": "~2.8|~3.0"
},
"require-dev": {
"symfony/http-foundation": "~2.8.31|~3.2.14"
},
"conflict": {
"symfony/http-foundation": "<2.8.31|~3.2,<3.2.14"
},
"suggest": {
"symfony/http-foundation": "For using the class SessionTokenStorage."
},
"autoload": {
"psr-4": { "Symfony\\Component\\Security\\Csrf\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
}
}

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />
</php>
<testsuites>
<testsuite name="Symfony Security Component CSRF Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>