[Security] Added CSRF sub-component
This commit is contained in:
parent
e24dbf7cba
commit
1bf16400fb
@ -52,6 +52,7 @@
|
||||
"symfony/security": "self.version",
|
||||
"symfony/security-acl": "self.version",
|
||||
"symfony/security-core": "self.version",
|
||||
"symfony/security-csrf": "self.version",
|
||||
"symfony/security-http": "self.version",
|
||||
"symfony/security-bundle": "self.version",
|
||||
"symfony/serializer": "self.version",
|
||||
|
3
src/Symfony/Component/Security/Csrf/.gitignore
vendored
Normal file
3
src/Symfony/Component/Security/Csrf/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
105
src/Symfony/Component/Security/Csrf/CsrfTokenGenerator.php
Normal file
105
src/Symfony/Component/Security/Csrf/CsrfTokenGenerator.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?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\Security\Core\Util\SecureRandomInterface;
|
||||
use Symfony\Component\Security\Core\Util\SecureRandom;
|
||||
use Symfony\Component\Security\Core\Util\StringUtils;
|
||||
use Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage;
|
||||
use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface;
|
||||
|
||||
/**
|
||||
* Generates and validates CSRF tokens.
|
||||
*
|
||||
* @since 2.4
|
||||
* @author Bernhard Schussek <bernhard.schussek@symfony.com>
|
||||
*/
|
||||
class CsrfTokenGenerator implements CsrfTokenGeneratorInterface
|
||||
{
|
||||
/**
|
||||
* The entropy of the token in bits.
|
||||
* @var integer
|
||||
*/
|
||||
const TOKEN_ENTROPY = 256;
|
||||
|
||||
/**
|
||||
* @var TokenStorageInterface
|
||||
*/
|
||||
private $storage;
|
||||
|
||||
/**
|
||||
* The generator for random values.
|
||||
* @var SecureRandomInterface
|
||||
*/
|
||||
private $random;
|
||||
|
||||
/**
|
||||
* Creates a new CSRF provider using PHP's native session storage.
|
||||
*
|
||||
* @param TokenStorageInterface $storage The storage for storing generated
|
||||
* CSRF tokens
|
||||
* @param SecureRandomInterface $random The used random value generator
|
||||
* @param integer $entropy The amount of entropy collected for
|
||||
* newly generated tokens (in bits)
|
||||
*
|
||||
*/
|
||||
public function __construct(TokenStorageInterface $storage = null, SecureRandomInterface $random = null, $entropy = self::TOKEN_ENTROPY)
|
||||
{
|
||||
if (null === $storage) {
|
||||
$storage = new NativeSessionTokenStorage();
|
||||
}
|
||||
|
||||
if (null === $random) {
|
||||
$random = new SecureRandom();
|
||||
}
|
||||
|
||||
$this->storage = $storage;
|
||||
$this->random = $random;
|
||||
$this->entropy = $entropy;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function generateCsrfToken($tokenId)
|
||||
{
|
||||
$currentToken = $this->storage->getToken($tokenId, false);
|
||||
|
||||
// Token exists and is still valid
|
||||
if (false !== $currentToken) {
|
||||
return $currentToken;
|
||||
}
|
||||
|
||||
// Token needs to be (re)generated
|
||||
// Generate an URI safe base64 encoded string that does not contain "+",
|
||||
// "/" or "=" which need to be URL encoded and make URLs unnecessarily
|
||||
// longer.
|
||||
$bytes = $this->random->nextBytes($this->entropy / 8);
|
||||
$token = rtrim(strtr(base64_encode($bytes), '+/', '-_'), '=');
|
||||
|
||||
$this->storage->setToken($tokenId, $token);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function isCsrfTokenValid($tokenId, $token)
|
||||
{
|
||||
if (!$this->storage->hasToken($tokenId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return StringUtils::equals((string) $this->storage->getToken($tokenId), $token);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
/**
|
||||
* Generates and validates CSRF tokens.
|
||||
*
|
||||
* You can generate a CSRF token by using the method {@link generateCsrfToken()}.
|
||||
* This method expects a unique token ID as argument. The token ID can later be
|
||||
* used to validate a token provided by the user.
|
||||
*
|
||||
* Token IDs do not necessarily have to be secret, but they should NEVER be
|
||||
* created from data provided by the client. A good practice is to hard-code the
|
||||
* token IDs for the various CSRF tokens used by your application.
|
||||
*
|
||||
* You should use the method {@link isCsrfTokenValid()} to check a CSRF token
|
||||
* submitted by the client. This method will return true if the CSRF token is
|
||||
* valid.
|
||||
*
|
||||
* @since 2.4
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface CsrfTokenGeneratorInterface
|
||||
{
|
||||
/**
|
||||
* Generates a CSRF token with the given token ID.
|
||||
*
|
||||
* @param string $tokenId An ID that identifies the token
|
||||
*/
|
||||
public function generateCsrfToken($tokenId);
|
||||
|
||||
/**
|
||||
* Validates a CSRF token.
|
||||
*
|
||||
* @param string $tokenId The token ID used when generating the token
|
||||
* @param string $token The token supplied by the client
|
||||
*
|
||||
* @return Boolean Whether the token supplied by the client is correct
|
||||
*/
|
||||
public function isCsrfTokenValid($tokenId, $token);
|
||||
}
|
19
src/Symfony/Component/Security/Csrf/LICENSE
Normal file
19
src/Symfony/Component/Security/Csrf/LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2004-2013 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.
|
21
src/Symfony/Component/Security/Csrf/README.md
Normal file
21
src/Symfony/Component/Security/Csrf/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
Security Component - CSRF
|
||||
=========================
|
||||
|
||||
The Security CSRF (cross-site request forgery) component provides a class
|
||||
`CsrfTokenGenerator` for generating and validating CSRF tokens.
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
Documentation:
|
||||
|
||||
http://symfony.com/doc/2.4/book/security.html
|
||||
|
||||
Tests
|
||||
-----
|
||||
|
||||
You can run the unit tests with the following command:
|
||||
|
||||
$ cd path/to/Symfony/Component/Security/Csrf/
|
||||
$ composer.phar install --dev
|
||||
$ phpunit
|
@ -0,0 +1,148 @@
|
||||
<?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\Form\Tests\Extension\Csrf\CsrfProvider;
|
||||
|
||||
use Symfony\Component\Security\Csrf\CsrfTokenGenerator;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class CsrfTokenGeneratorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* A non alpha-numeric byte string
|
||||
* @var string
|
||||
*/
|
||||
private static $bytes;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
private $random;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
private $storage;
|
||||
|
||||
/**
|
||||
* @var CsrfTokenGenerator
|
||||
*/
|
||||
private $generator;
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$bytes = base64_decode('aMf+Tct/RLn2WQ==');
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->random = $this->getMock('Symfony\Component\Security\Core\Util\SecureRandomInterface');
|
||||
$this->storage = $this->getMock('Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface');
|
||||
$this->generator = new CsrfTokenGenerator($this->storage, $this->random);
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
$this->random = null;
|
||||
$this->storage = null;
|
||||
$this->generator = null;
|
||||
}
|
||||
|
||||
public function testGenerateNewToken()
|
||||
{
|
||||
$this->storage->expects($this->once())
|
||||
->method('getToken')
|
||||
->with('token_id', false)
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$this->storage->expects($this->once())
|
||||
->method('setToken')
|
||||
->with('token_id', $this->anything())
|
||||
->will($this->returnCallback(function ($tokenId, $token) use (&$storedToken) {
|
||||
$storedToken = $token;
|
||||
}));
|
||||
|
||||
$this->random->expects($this->once())
|
||||
->method('nextBytes')
|
||||
->will($this->returnValue(self::$bytes));
|
||||
|
||||
$token = $this->generator->generateCsrfToken('token_id');
|
||||
|
||||
$this->assertSame($token, $storedToken);
|
||||
$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');
|
||||
}
|
||||
|
||||
public function testUseExistingTokenIfAvailable()
|
||||
{
|
||||
$this->storage->expects($this->once())
|
||||
->method('getToken')
|
||||
->with('token_id', false)
|
||||
->will($this->returnValue('TOKEN'));
|
||||
|
||||
$this->storage->expects($this->never())
|
||||
->method('setToken');
|
||||
|
||||
$this->random->expects($this->never())
|
||||
->method('nextBytes');
|
||||
|
||||
$token = $this->generator->generateCsrfToken('token_id');
|
||||
|
||||
$this->assertEquals('TOKEN', $token);
|
||||
}
|
||||
|
||||
public function testMatchingTokenIsValid()
|
||||
{
|
||||
$this->storage->expects($this->once())
|
||||
->method('hasToken')
|
||||
->with('token_id')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->storage->expects($this->once())
|
||||
->method('getToken')
|
||||
->with('token_id')
|
||||
->will($this->returnValue('TOKEN'));
|
||||
|
||||
$this->assertTrue($this->generator->isCsrfTokenValid('token_id', 'TOKEN'));
|
||||
}
|
||||
|
||||
public function testNonMatchingTokenIsNotValid()
|
||||
{
|
||||
$this->storage->expects($this->once())
|
||||
->method('hasToken')
|
||||
->with('token_id')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->storage->expects($this->once())
|
||||
->method('getToken')
|
||||
->with('token_id')
|
||||
->will($this->returnValue('TOKEN'));
|
||||
|
||||
$this->assertFalse($this->generator->isCsrfTokenValid('token_id', 'FOOBAR'));
|
||||
}
|
||||
|
||||
public function testNonExistingTokenIsNotValid()
|
||||
{
|
||||
$this->storage->expects($this->once())
|
||||
->method('hasToken')
|
||||
->with('token_id')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$this->storage->expects($this->never())
|
||||
->method('getToken');
|
||||
|
||||
$this->assertFalse($this->generator->isCsrfTokenValid('token_id', 'FOOBAR'));
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
<?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\Form\Tests\Extension\Csrf\CsrfProvider;
|
||||
|
||||
use Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
*/
|
||||
class NativeSessionTokenStorageTest extends \PHPUnit_Framework_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'));
|
||||
}
|
||||
|
||||
public function testGetNonExistingToken()
|
||||
{
|
||||
$this->assertSame('DEFAULT', $this->storage->getToken('token_id', 'DEFAULT'));
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
<?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\Form\Tests\Extension\Csrf\CsrfProvider;
|
||||
|
||||
use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class SessionTokenStorageTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
const SESSION_NAMESPACE = 'foobar';
|
||||
|
||||
/**
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
private $session;
|
||||
|
||||
/**
|
||||
* @var SessionTokenStorage
|
||||
*/
|
||||
private $storage;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
if (!class_exists('Symfony\Component\HttpFoundation\Session\SessionInterface')) {
|
||||
$this->markTestSkipped('The "HttpFoundation" component is not available');
|
||||
}
|
||||
|
||||
$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 testGetTokenFromClosedSession()
|
||||
{
|
||||
$this->session->expects($this->any())
|
||||
->method('isStarted')
|
||||
->will($this->returnValue(false));
|
||||
|
||||
$this->session->expects($this->once())
|
||||
->method('start');
|
||||
|
||||
$this->session->expects($this->once())
|
||||
->method('get')
|
||||
->with(self::SESSION_NAMESPACE.'/token_id', 'DEFAULT')
|
||||
->will($this->returnValue('RESULT'));
|
||||
|
||||
$this->assertSame('RESULT', $this->storage->getToken('token_id', 'DEFAULT'));
|
||||
}
|
||||
|
||||
public function testGetTokenFromActiveSession()
|
||||
{
|
||||
$this->session->expects($this->any())
|
||||
->method('isStarted')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$this->session->expects($this->never())
|
||||
->method('start');
|
||||
|
||||
$this->session->expects($this->once())
|
||||
->method('get')
|
||||
->with(self::SESSION_NAMESPACE.'/token_id', 'DEFAULT')
|
||||
->will($this->returnValue('RESULT'));
|
||||
|
||||
$this->assertSame('RESULT', $this->storage->getToken('token_id', 'DEFAULT'));
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Token storage that uses PHP's native session handling.
|
||||
*
|
||||
* @since 2.4
|
||||
* @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 Boolean
|
||||
*/
|
||||
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, $default = null)
|
||||
{
|
||||
if (!$this->sessionStarted) {
|
||||
$this->startSession();
|
||||
}
|
||||
|
||||
if (isset($_SESSION[$this->namespace][$tokenId])) {
|
||||
return $_SESSION[$this->namespace][$tokenId];
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setToken($tokenId, $token)
|
||||
{
|
||||
if (!$this->sessionStarted) {
|
||||
$this->startSession();
|
||||
}
|
||||
|
||||
$_SESSION[$this->namespace][$tokenId] = $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasToken($tokenId)
|
||||
{
|
||||
if (!$this->sessionStarted) {
|
||||
$this->startSession();
|
||||
}
|
||||
|
||||
return isset($_SESSION[$this->namespace][$tokenId]);
|
||||
}
|
||||
|
||||
private function startSession()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '5.4', '>=')) {
|
||||
if (PHP_SESSION_NONE === session_status()) {
|
||||
session_start();
|
||||
}
|
||||
} elseif (!session_id()) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
$this->sessionStarted = true;
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Token storage that uses a Symfony2 Session object.
|
||||
*
|
||||
* @since 2.4
|
||||
* @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, $default = null)
|
||||
{
|
||||
if (!$this->session->isStarted()) {
|
||||
$this->session->start();
|
||||
}
|
||||
|
||||
return $this->session->get($this->namespace . '/' . $tokenId, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setToken($tokenId, $token)
|
||||
{
|
||||
if (!$this->session->isStarted()) {
|
||||
$this->session->start();
|
||||
}
|
||||
|
||||
$this->session->set($this->namespace . '/' . $tokenId, $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasToken($tokenId)
|
||||
{
|
||||
if (!$this->session->isStarted()) {
|
||||
$this->session->start();
|
||||
}
|
||||
|
||||
return $this->session->has($this->namespace . '/' . $tokenId);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
<?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.
|
||||
*
|
||||
* @since 2.4
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface TokenStorageInterface
|
||||
{
|
||||
/**
|
||||
* Reads a stored CSRF token.
|
||||
*
|
||||
* @param string $tokenId The token ID
|
||||
* @param mixed $default The value to be returned if no token is set
|
||||
*
|
||||
* @return mixed The stored token or the default value, if no token is set
|
||||
*/
|
||||
public function getToken($tokenId, $default = null);
|
||||
|
||||
/**
|
||||
* Stores a CSRF token.
|
||||
*
|
||||
* @param string $tokenId The token ID
|
||||
* @param mixed $token The CSRF token
|
||||
*/
|
||||
public function setToken($tokenId, $token);
|
||||
|
||||
/**
|
||||
* Checks whether a token with the given token ID exists.
|
||||
*
|
||||
* @param string $tokenId The token ID
|
||||
*
|
||||
* @return Boolean Returns true if a token is stored for the given token ID,
|
||||
* false otherwise.
|
||||
*/
|
||||
public function hasToken($tokenId);
|
||||
}
|
34
src/Symfony/Component/Security/Csrf/composer.json
Normal file
34
src/Symfony/Component/Security/Csrf/composer.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "symfony/security-csrf",
|
||||
"type": "library",
|
||||
"description": "Symfony Security Component - CSRF Library",
|
||||
"keywords": [],
|
||||
"homepage": "http://symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/security-core": "~2.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": { "Symfony\\Component\\Security\\Csrf\\": "" }
|
||||
},
|
||||
"target-dir": "Symfony/Component/Security/Csrf",
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.4-dev"
|
||||
}
|
||||
}
|
||||
}
|
29
src/Symfony/Component/Security/Csrf/phpunit.xml.dist
Normal file
29
src/Symfony/Component/Security/Csrf/phpunit.xml.dist
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Symfony Security Component CSRF Test Suite">
|
||||
<directory>./Tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./</directory>
|
||||
<exclude>
|
||||
<directory>./vendor</directory>
|
||||
<directory>./Tests</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
@ -24,6 +24,7 @@
|
||||
"replace": {
|
||||
"symfony/security-acl": "self.version",
|
||||
"symfony/security-core": "self.version",
|
||||
"symfony/security-csrf": "self.version",
|
||||
"symfony/security-http": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
|
Reference in New Issue
Block a user