[Security\Csrf] Split CsrfTokenGenerator into CsrfTokenManager and TokenGenerator

This commit is contained in:
Bernhard Schussek 2013-10-04 15:25:38 +02:00
parent e18bd76dd8
commit d4bb5f4e3c
46 changed files with 1251 additions and 459 deletions

View File

@ -170,7 +170,7 @@ UPGRADE FROM 2.x to 3.0
* The interface `Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface` * The interface `Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface`
and all of its implementations were removed. Use the new interface and all of its implementations were removed. Use the new interface
`Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface` instead. `Symfony\Component\Security\Csrf\CsrfTokenManagerInterface` instead.
* The options "csrf_provider" and "intention" were renamed to "csrf_token_generator" * The options "csrf_provider" and "intention" were renamed to "csrf_token_generator"
and "csrf_token_id". and "csrf_token_id".

View File

@ -11,8 +11,11 @@
namespace Symfony\Bridge\Twig\Form; namespace Symfony\Bridge\Twig\Form;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\Form\FormRenderer; use Symfony\Component\Form\FormRenderer;
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
/** /**
* @author Bernhard Schussek <bschussek@gmail.com> * @author Bernhard Schussek <bschussek@gmail.com>
@ -24,9 +27,15 @@ class TwigRenderer extends FormRenderer implements TwigRendererInterface
*/ */
private $engine; private $engine;
public function __construct(TwigRendererEngineInterface $engine, CsrfTokenGeneratorInterface $csrfTokenGenerator = null) public function __construct(TwigRendererEngineInterface $engine, $csrfTokenManager = null)
{ {
parent::__construct($engine, $csrfTokenGenerator); if ($csrfTokenManager instanceof CsrfProviderInterface) {
$csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager);
} elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) {
throw new UnexpectedTypeException($csrfTokenManager, 'CsrfProviderInterface or CsrfTokenManagerInterface');
}
parent::__construct($engine, $csrfTokenManager);
$this->engine = $engine; $this->engine = $engine;
} }

View File

@ -5,7 +5,9 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services> <services>
<service id="form.csrf_provider" class="Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfTokenGeneratorAdapter" parent="security.csrf.token_generator" /> <service id="form.csrf_provider" class="Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfTokenManagerAdapter">
<argument type="service" id="security.csrf.token_manager" />
</service>
<service id="form.type_extension.csrf" class="Symfony\Component\Form\Extension\Csrf\Type\FormTypeCsrfExtension"> <service id="form.type_extension.csrf" class="Symfony\Component\Form\Extension\Csrf\Type\FormTypeCsrfExtension">
<tag name="form.type_extension" alias="form" /> <tag name="form.type_extension" alias="form" />

View File

@ -5,18 +5,23 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters> <parameters>
<parameter key="security.csrf.token_generator.class">Symfony\Component\Security\Csrf\CsrfTokenGenerator</parameter> <parameter key="security.csrf.token_generator.class">Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator</parameter>
<parameter key="security.csrf.token_storage.class">Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage</parameter> <parameter key="security.csrf.token_storage.class">Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage</parameter>
<parameter key="security.csrf.token_manager.class">Symfony\Component\Security\Csrf\CsrfTokenManager</parameter>
</parameters> </parameters>
<services> <services>
<service id="security.csrf.token_generator" class="%security.csrf.token_generator.class%" public="false">
<argument type="service" id="security.secure_random" />
</service>
<service id="security.csrf.token_storage" class="%security.csrf.token_storage.class%" public="false"> <service id="security.csrf.token_storage" class="%security.csrf.token_storage.class%" public="false">
<argument type="service" id="session" /> <argument type="service" id="session" />
</service> </service>
<service id="security.csrf.token_generator" class="%security.csrf.token_generator.class%"> <service id="security.csrf.token_manager" class="%security.csrf.token_manager.class%">
<argument type="service" id="security.csrf.token_generator" />
<argument type="service" id="security.csrf.token_storage" /> <argument type="service" id="security.csrf.token_storage" />
<argument type="service" id="security.secure_random" />
</service> </service>
</services> </services>
</container> </container>

View File

@ -46,7 +46,7 @@ class FormHelperDivLayoutTest extends AbstractDivLayoutTest
)); ));
return array_merge(parent::getExtensions(), array( return array_merge(parent::getExtensions(), array(
new TemplatingExtension($this->engine, $this->csrfTokenGenerator, array( new TemplatingExtension($this->engine, $this->csrfTokenManager, array(
'FrameworkBundle:Form', 'FrameworkBundle:Form',
)), )),
)); ));

View File

@ -46,7 +46,7 @@ class FormHelperTableLayoutTest extends AbstractTableLayoutTest
)); ));
return array_merge(parent::getExtensions(), array( return array_merge(parent::getExtensions(), array(
new TemplatingExtension($this->engine, $this->csrfTokenGenerator, array( new TemplatingExtension($this->engine, $this->csrfTokenManager, array(
'FrameworkBundle:Form', 'FrameworkBundle:Form',
'FrameworkBundle:FormTable', 'FrameworkBundle:FormTable',
)), )),

View File

@ -12,8 +12,10 @@
namespace Symfony\Bundle\SecurityBundle\Templating\Helper; namespace Symfony\Bundle\SecurityBundle\Templating\Helper;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Templating\Helper\Helper; use Symfony\Component\Templating\Helper\Helper;
/** /**
@ -43,15 +45,21 @@ class LogoutUrlHelper extends Helper
/** /**
* Registers a firewall's LogoutListener, allowing its URL to be generated. * Registers a firewall's LogoutListener, allowing its URL to be generated.
* *
* @param string $key The firewall key * @param string $key The firewall key
* @param string $logoutPath The path that starts the logout process * @param string $logoutPath The path that starts the logout process
* @param string $csrfTokenId The ID of the CSRF token * @param string $csrfTokenId The ID of the CSRF token
* @param string $csrfParameter The CSRF token parameter name * @param string $csrfParameter The CSRF token parameter name
* @param CsrfTokenGeneratorInterface $csrfTokenGenerator A CsrfTokenGeneratorInterface instance * @param CsrfTokenManagerInterface $csrfTokenManager A CsrfTokenManagerInterface instance
*/ */
public function registerListener($key, $logoutPath, $csrfTokenId, $csrfParameter, CsrfTokenGeneratorInterface $csrfTokenGenerator = null) public function registerListener($key, $logoutPath, $csrfTokenId, $csrfParameter, $csrfTokenManager = null)
{ {
$this->listeners[$key] = array($logoutPath, $csrfTokenId, $csrfParameter, $csrfTokenGenerator); if ($csrfTokenManager instanceof CsrfProviderInterface) {
$csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager);
} elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) {
throw new \InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.');
}
$this->listeners[$key] = array($logoutPath, $csrfTokenId, $csrfParameter, $csrfTokenManager);
} }
/** /**
@ -94,9 +102,9 @@ class LogoutUrlHelper extends Helper
throw new \InvalidArgumentException(sprintf('No LogoutListener found for firewall key "%s".', $key)); throw new \InvalidArgumentException(sprintf('No LogoutListener found for firewall key "%s".', $key));
} }
list($logoutPath, $csrfTokenId, $csrfParameter, $csrfTokenGenerator) = $this->listeners[$key]; list($logoutPath, $csrfTokenId, $csrfParameter, $csrfTokenManager) = $this->listeners[$key];
$parameters = null !== $csrfTokenGenerator ? array($csrfParameter => $csrfTokenGenerator->generateCsrfToken($csrfTokenId)) : array(); $parameters = null !== $csrfTokenManager ? array($csrfParameter => (string) $csrfTokenManager->getToken($csrfTokenId)) : array();
if ('/' === $logoutPath[0]) { if ('/' === $logoutPath[0]) {
$request = $this->container->get('request'); $request = $this->container->get('request');

View File

@ -37,12 +37,12 @@ security:
username_parameter: "user_login[username]" username_parameter: "user_login[username]"
password_parameter: "user_login[password]" password_parameter: "user_login[password]"
csrf_parameter: "user_login[_token]" csrf_parameter: "user_login[_token]"
csrf_provider: security.csrf.token_generator csrf_provider: security.csrf.token_manager
anonymous: ~ anonymous: ~
logout: logout:
path: /logout_path path: /logout_path
target: / target: /
csrf_provider: security.csrf.token_generator csrf_provider: security.csrf.token_manager
access_control: access_control:
- { path: .*, roles: IS_AUTHENTICATED_FULLY } - { path: .*, roles: IS_AUTHENTICATED_FULLY }

View File

@ -11,9 +11,12 @@
namespace Symfony\Component\Form\Extension\Csrf; namespace Symfony\Component\Form\Extension\Csrf;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\Form\Extension\Csrf\Type; use Symfony\Component\Form\Extension\Csrf\Type;
use Symfony\Component\Form\AbstractExtension; use Symfony\Component\Form\AbstractExtension;
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
/** /**
@ -24,9 +27,9 @@ use Symfony\Component\Translation\TranslatorInterface;
class CsrfExtension extends AbstractExtension class CsrfExtension extends AbstractExtension
{ {
/** /**
* @var CsrfTokenGeneratorInterface * @var CsrfTokenManagerInterface
*/ */
private $tokenGenerator; private $tokenManager;
/** /**
* @var TranslatorInterface * @var TranslatorInterface
@ -41,13 +44,19 @@ class CsrfExtension extends AbstractExtension
/** /**
* Constructor. * Constructor.
* *
* @param CsrfTokenGeneratorInterface $tokenGenerator The CSRF token generator * @param CsrfTokenManagerInterface $tokenManager The CSRF token manager
* @param TranslatorInterface $translator The translator for translating error messages * @param TranslatorInterface $translator The translator for translating error messages
* @param null|string $translationDomain The translation domain for translating * @param null|string $translationDomain The translation domain for translating
*/ */
public function __construct(CsrfTokenGeneratorInterface $tokenGenerator, TranslatorInterface $translator = null, $translationDomain = null) public function __construct($tokenManager, TranslatorInterface $translator = null, $translationDomain = null)
{ {
$this->tokenGenerator = $tokenGenerator; if ($tokenManager instanceof CsrfProviderInterface) {
$tokenManager = new CsrfProviderAdapter($tokenManager);
} elseif (!$tokenManager instanceof CsrfTokenManagerInterface) {
throw new UnexpectedTypeException($tokenManager, 'CsrfProviderInterface or CsrfTokenManagerInterface');
}
$this->tokenManager = $tokenManager;
$this->translator = $translator; $this->translator = $translator;
$this->translationDomain = $translationDomain; $this->translationDomain = $translationDomain;
} }
@ -58,7 +67,7 @@ class CsrfExtension extends AbstractExtension
protected function loadTypeExtensions() protected function loadTypeExtensions()
{ {
return array( return array(
new Type\FormTypeCsrfExtension($this->tokenGenerator, true, '_token', $this->translator, $this->translationDomain), new Type\FormTypeCsrfExtension($this->tokenManager, true, '_token', $this->translator, $this->translationDomain),
); );
} }
} }

View File

@ -0,0 +1,75 @@
<?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\Extension\Csrf\CsrfProvider;
use Symfony\Component\Form\Exception\BadMethodCallException;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
/**
* Adapter for using old CSRF providers where the new {@link CsrfTokenManagerInterface}
* is expected.
*
* @since 2.4
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated Deprecated since version 2.4, to be removed in Symfony 3.0.
*/
class CsrfProviderAdapter implements CsrfTokenManagerInterface
{
/**
* @var CsrfProviderInterface
*/
private $csrfProvider;
public function __construct(CsrfProviderInterface $csrfProvider)
{
$this->csrfProvider = $csrfProvider;
}
public function getCsrfProvider()
{
return $this->csrfProvider;
}
/**
* {@inheritdoc}
*/
public function getToken($tokenId)
{
return $this->csrfProvider->generateCsrfToken($tokenId);
}
/**
* {@inheritdoc}
*/
public function refreshToken($tokenId)
{
throw new BadMethodCallException('Not supported');
}
/**
* {@inheritdoc}
*/
public function removeToken($tokenId)
{
throw new BadMethodCallException('Not supported');
}
/**
* {@inheritdoc}
*/
public function isTokenValid(CsrfToken $token)
{
return $this->csrfProvider->isCsrfTokenValid($token->getId(), $token->getValue());
}
}

View File

@ -11,16 +11,45 @@
namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider; namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface;
/** /**
* Alias interface of {@link CsrfTokenGeneratorInterface}. * Marks classes able to provide CSRF protection
*
* You can generate a CSRF token by using the method generateCsrfToken(). To
* this method you should pass a value that is unique to the page that should
* be secured against CSRF attacks. This value doesn't necessarily have to be
* secret. Implementations of this interface are responsible for adding more
* secret information.
*
* If you want to secure a form submission against CSRF attacks, you could
* supply an "intention" string. This way you make sure that the form can only
* be submitted to pages that are designed to handle the form, that is, that use
* the same intention string to validate the CSRF token with isCsrfTokenValid().
* *
* @author Bernhard Schussek <bschussek@gmail.com> * @author Bernhard Schussek <bschussek@gmail.com>
* *
* @deprecated Deprecated since version 2.4, to be removed in Symfony 3.0. Use * @deprecated Deprecated since version 2.4, to be removed in Symfony 3.0. Use
* {@link CsrfTokenGeneratorInterface} instead. * {@link \Symfony\Component\Security\Csrf\CsrfTokenManagerInterface}
* instead.
*/ */
interface CsrfProviderInterface extends CsrfTokenGeneratorInterface interface CsrfProviderInterface
{ {
/**
* Generates a CSRF token for a page of your application.
*
* @param string $intention Some value that identifies the action intention
* (i.e. "authenticate"). Doesn't have to be a secret value.
*
* @return string The generated token
*/
public function generateCsrfToken($intention);
/**
* Validates a CSRF token.
*
* @param string $intention The intention used when generating the CSRF token
* @param string $token The token supplied by the browser
*
* @return Boolean Whether the token supplied by the browser is correct
*/
public function isCsrfTokenValid($intention, $token);
} }

View File

@ -1,26 +0,0 @@
<?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\Extension\Csrf\CsrfProvider;
use Symfony\Component\Security\Csrf\CsrfTokenGenerator;
/**
* Adapter for using the new token generator with the old interface.
*
* @since 2.4
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated Deprecated since version 2.4, to be removed in Symfony 3.0.
*/
class CsrfTokenGeneratorAdapter extends CsrfTokenGenerator implements CsrfProviderInterface
{
}

View File

@ -0,0 +1,57 @@
<?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\Extension\Csrf\CsrfProvider;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
/**
* Adapter for using the new token generator with the old interface.
*
* @since 2.4
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated Deprecated since version 2.4, to be removed in Symfony 3.0.
*/
class CsrfTokenManagerAdapter implements CsrfProviderInterface
{
/**
* @var CsrfTokenManagerInterface
*/
private $tokenManager;
public function __construct(CsrfTokenManagerInterface $tokenManager)
{
$this->tokenManager = $tokenManager;
}
public function getTokenManager()
{
return $this->tokenManager;
}
/**
* {@inheritdoc}
*/
public function generateCsrfToken($intention)
{
return $this->tokenManager->getToken($intention)->getValue();
}
/**
* {@inheritdoc}
*/
public function isCsrfTokenValid($intention, $token)
{
return $this->tokenManager->isTokenValid(new CsrfToken($intention, $token));
}
}

View File

@ -20,7 +20,7 @@ namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
* @author Bernhard Schussek <bschussek@gmail.com> * @author Bernhard Schussek <bschussek@gmail.com>
* *
* @deprecated Deprecated since version 2.4, to be removed in Symfony 3.0. Use * @deprecated Deprecated since version 2.4, to be removed in Symfony 3.0. Use
* {@link \Symfony\Component\Security\Csrf\CsrfTokenGenerator} in * {@link \Symfony\Component\Security\Csrf\CsrfTokenManager} in
* combination with {@link \Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage} * combination with {@link \Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage}
* instead. * instead.
*/ */

View File

@ -22,7 +22,7 @@ use Symfony\Component\HttpFoundation\Session\Session;
* @author Bernhard Schussek <bschussek@gmail.com> * @author Bernhard Schussek <bschussek@gmail.com>
* *
* @deprecated Deprecated since version 2.4, to be removed in Symfony 3.0. Use * @deprecated Deprecated since version 2.4, to be removed in Symfony 3.0. Use
* {@link \Symfony\Component\Security\Csrf\CsrfTokenGenerator} in * {@link \Symfony\Component\Security\Csrf\CsrfTokenManager} in
* combination with {@link \Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage} * combination with {@link \Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage}
* instead. * instead.
*/ */

View File

@ -12,10 +12,14 @@
namespace Symfony\Component\Form\Extension\Csrf\EventListener; namespace Symfony\Component\Form\Extension\Csrf\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvent;
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface; use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
/** /**
@ -31,9 +35,9 @@ class CsrfValidationListener implements EventSubscriberInterface
/** /**
* The generator for CSRF tokens * The generator for CSRF tokens
* @var CsrfTokenGeneratorInterface * @var CsrfTokenManagerInterface
*/ */
private $tokenGenerator; private $tokenManager;
/** /**
* A text mentioning the tokenId of the CSRF token * A text mentioning the tokenId of the CSRF token
@ -68,10 +72,16 @@ class CsrfValidationListener implements EventSubscriberInterface
); );
} }
public function __construct($fieldName, CsrfTokenGeneratorInterface $tokenGenerator, $tokenId, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null) public function __construct($fieldName, $tokenManager, $tokenId, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null)
{ {
if ($tokenManager instanceof CsrfProviderInterface) {
$tokenManager = new CsrfProviderAdapter($tokenManager);
} elseif (!$tokenManager instanceof CsrfTokenManagerInterface) {
throw new UnexpectedTypeException($tokenManager, 'CsrfProviderInterface or CsrfTokenManagerInterface');
}
$this->fieldName = $fieldName; $this->fieldName = $fieldName;
$this->tokenGenerator = $tokenGenerator; $this->tokenManager = $tokenManager;
$this->tokenId = $tokenId; $this->tokenId = $tokenId;
$this->errorMessage = $errorMessage; $this->errorMessage = $errorMessage;
$this->translator = $translator; $this->translator = $translator;
@ -84,7 +94,7 @@ class CsrfValidationListener implements EventSubscriberInterface
$data = $event->getData(); $data = $event->getData();
if ($form->isRoot() && $form->getConfig()->getOption('compound')) { if ($form->isRoot() && $form->getConfig()->getOption('compound')) {
if (!isset($data[$this->fieldName]) || !$this->tokenGenerator->isCsrfTokenValid($this->tokenId, $data[$this->fieldName])) { if (!isset($data[$this->fieldName]) || !$this->tokenManager->isTokenValid(new CsrfToken($this->tokenId, $data[$this->fieldName]))) {
$errorMessage = $this->errorMessage; $errorMessage = $this->errorMessage;
if (null !== $this->translator) { if (null !== $this->translator) {

View File

@ -12,13 +12,17 @@
namespace Symfony\Component\Form\Extension\Csrf\Type; namespace Symfony\Component\Form\Extension\Csrf\Type;
use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfTokenManagerAdapter;
use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener; use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolverInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
/** /**
@ -27,9 +31,9 @@ use Symfony\Component\Translation\TranslatorInterface;
class FormTypeCsrfExtension extends AbstractTypeExtension class FormTypeCsrfExtension extends AbstractTypeExtension
{ {
/** /**
* @var CsrfTokenGeneratorInterface * @var CsrfTokenManagerInterface
*/ */
private $defaultTokenGenerator; private $defaultTokenManager;
/** /**
* @var Boolean * @var Boolean
@ -51,9 +55,15 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
*/ */
private $translationDomain; private $translationDomain;
public function __construct(CsrfTokenGeneratorInterface $defaultTokenGenerator, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null) public function __construct($defaultTokenManager, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null)
{ {
$this->defaultTokenGenerator = $defaultTokenGenerator; if ($defaultTokenManager instanceof CsrfProviderInterface) {
$defaultTokenManager = new CsrfProviderAdapter($defaultTokenManager);
} elseif (!$defaultTokenManager instanceof CsrfTokenManagerInterface) {
throw new UnexpectedTypeException($defaultTokenManager, 'CsrfProviderInterface or CsrfTokenManagerInterface');
}
$this->defaultTokenManager = $defaultTokenManager;
$this->defaultEnabled = $defaultEnabled; $this->defaultEnabled = $defaultEnabled;
$this->defaultFieldName = $defaultFieldName; $this->defaultFieldName = $defaultFieldName;
$this->translator = $translator; $this->translator = $translator;
@ -75,7 +85,7 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
$builder $builder
->addEventSubscriber(new CsrfValidationListener( ->addEventSubscriber(new CsrfValidationListener(
$options['csrf_field_name'], $options['csrf_field_name'],
$options['csrf_token_generator'], $options['csrf_token_manager'],
$options['csrf_token_id'], $options['csrf_token_id'],
$options['csrf_message'], $options['csrf_message'],
$this->translator, $this->translator,
@ -95,7 +105,7 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
{ {
if ($options['csrf_protection'] && !$view->parent && $options['compound']) { if ($options['csrf_protection'] && !$view->parent && $options['compound']) {
$factory = $form->getConfig()->getFormFactory(); $factory = $form->getConfig()->getFormFactory();
$data = $options['csrf_token_generator']->generateCsrfToken($options['csrf_token_id']); $data = (string) $options['csrf_token_manager']->getToken($options['csrf_token_id']);
$csrfForm = $factory->createNamed($options['csrf_field_name'], 'hidden', $data, array( $csrfForm = $factory->createNamed($options['csrf_field_name'], 'hidden', $data, array(
'mapped' => false, 'mapped' => false,
@ -116,18 +126,20 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
}; };
// BC clause for the "csrf_provider" option // BC clause for the "csrf_provider" option
$csrfTokenGenerator = function (Options $options) { $csrfTokenManager = function (Options $options) {
return $options['csrf_provider']; return $options['csrf_provider'] instanceof CsrfTokenManagerAdapter
? $options['csrf_provider']->getTokenManager()
: new CsrfProviderAdapter($options['csrf_provider']);
}; };
$resolver->setDefaults(array( $resolver->setDefaults(array(
'csrf_protection' => $this->defaultEnabled, 'csrf_protection' => $this->defaultEnabled,
'csrf_field_name' => $this->defaultFieldName, 'csrf_field_name' => $this->defaultFieldName,
'csrf_message' => 'The CSRF token is invalid. Please try to resubmit the form.', 'csrf_message' => 'The CSRF token is invalid. Please try to resubmit the form.',
'csrf_token_generator' => $csrfTokenGenerator, 'csrf_token_manager' => $csrfTokenManager,
'csrf_token_id' => $csrfTokenId, 'csrf_token_id' => $csrfTokenId,
'csrf_provider' => $this->defaultTokenGenerator, 'csrf_provider' => new CsrfTokenManagerAdapter($this->defaultTokenManager),
'intention' => 'unknown', 'intention' => 'unknown',
)); ));
} }

View File

@ -12,8 +12,11 @@
namespace Symfony\Component\Form\Extension\Templating; namespace Symfony\Component\Form\Extension\Templating;
use Symfony\Component\Form\AbstractExtension; use Symfony\Component\Form\AbstractExtension;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\Form\FormRenderer; use Symfony\Component\Form\FormRenderer;
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Templating\PhpEngine; use Symfony\Component\Templating\PhpEngine;
use Symfony\Bundle\FrameworkBundle\Templating\Helper\FormHelper; use Symfony\Bundle\FrameworkBundle\Templating\Helper\FormHelper;
@ -24,10 +27,16 @@ use Symfony\Bundle\FrameworkBundle\Templating\Helper\FormHelper;
*/ */
class TemplatingExtension extends AbstractExtension class TemplatingExtension extends AbstractExtension
{ {
public function __construct(PhpEngine $engine, CsrfTokenGeneratorInterface $csrfTokenGenerator = null, array $defaultThemes = array()) public function __construct(PhpEngine $engine, $csrfTokenManager = null, array $defaultThemes = array())
{ {
if ($csrfTokenManager instanceof CsrfProviderInterface) {
$csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager);
} elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) {
throw new UnexpectedTypeException($csrfTokenManager, 'CsrfProviderInterface or CsrfTokenManagerInterface');
}
$engine->addHelpers(array( $engine->addHelpers(array(
new FormHelper(new FormRenderer(new TemplatingRendererEngine($engine, $defaultThemes), $csrfTokenGenerator)) new FormHelper(new FormRenderer(new TemplatingRendererEngine($engine, $defaultThemes), $csrfTokenManager))
)); ));
} }
} }

View File

@ -13,7 +13,7 @@ namespace Symfony\Component\Form;
use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Exception\LogicException;
use Symfony\Component\Form\Exception\BadMethodCallException; use Symfony\Component\Form\Exception\BadMethodCallException;
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
/** /**
* Renders a form into HTML using a rendering engine. * Renders a form into HTML using a rendering engine.
@ -30,9 +30,9 @@ class FormRenderer implements FormRendererInterface
private $engine; private $engine;
/** /**
* @var CsrfTokenGeneratorInterface * @var CsrfTokenManagerInterface
*/ */
private $csrfTokenGenerator; private $csrfTokenManager;
/** /**
* @var array * @var array
@ -49,10 +49,16 @@ class FormRenderer implements FormRendererInterface
*/ */
private $variableStack = array(); private $variableStack = array();
public function __construct(FormRendererEngineInterface $engine, CsrfTokenGeneratorInterface $csrfTokenGenerator = null) public function __construct(FormRendererEngineInterface $engine, $csrfTokenManager = null)
{ {
if ($csrfTokenManager instanceof CsrfProviderInterface) {
$csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager);
} elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) {
throw new UnexpectedTypeException($csrfTokenManager, 'CsrfProviderInterface or CsrfTokenManagerInterface');
}
$this->engine = $engine; $this->engine = $engine;
$this->csrfTokenGenerator = $csrfTokenGenerator; $this->csrfTokenManager = $csrfTokenManager;
} }
/** /**
@ -76,11 +82,11 @@ class FormRenderer implements FormRendererInterface
*/ */
public function renderCsrfToken($tokenId) public function renderCsrfToken($tokenId)
{ {
if (null === $this->csrfTokenGenerator) { if (null === $this->csrfTokenManager) {
throw new BadMethodCallException('CSRF tokens can only be generated if a CsrfTokenGeneratorInterface is injected in FormRenderer::__construct().'); throw new BadMethodCallException('CSRF tokens can only be generated if a CsrfTokenManagerInterface is injected in FormRenderer::__construct().');
} }
return $this->csrfTokenGenerator->generateCsrfToken($tokenId); return $this->csrfTokenManager->getToken($tokenId)->getValue();
} }
/** /**

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Form\Tests;
use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormError;
use Symfony\Component\Form\Tests\Fixtures\AlternatingRowType; use Symfony\Component\Form\Tests\Fixtures\AlternatingRowType;
use Symfony\Component\Security\Csrf\CsrfToken;
abstract class AbstractDivLayoutTest extends AbstractLayoutTest abstract class AbstractDivLayoutTest extends AbstractLayoutTest
{ {
@ -471,9 +472,9 @@ abstract class AbstractDivLayoutTest extends AbstractLayoutTest
public function testCsrf() public function testCsrf()
{ {
$this->csrfTokenGenerator->expects($this->any()) $this->csrfTokenManager->expects($this->any())
->method('generateCsrfToken') ->method('getToken')
->will($this->returnValue('foo&bar')); ->will($this->returnValue(new CsrfToken('token_id', 'foo&bar')));
$form = $this->factory->createNamedBuilder('name', 'form') $form = $this->factory->createNamedBuilder('name', 'form')
->add($this->factory ->add($this->factory

View File

@ -17,7 +17,7 @@ use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormIntegrationTestCase abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormIntegrationTestCase
{ {
protected $csrfTokenGenerator; protected $csrfTokenManager;
protected function setUp() protected function setUp()
{ {
@ -27,7 +27,7 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
\Locale::setDefault('en'); \Locale::setDefault('en');
$this->csrfTokenGenerator = $this->getMock('Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface'); $this->csrfTokenManager = $this->getMock('Symfony\Component\Security\Csrf\CsrfTokenManagerInterface');
parent::setUp(); parent::setUp();
} }
@ -35,13 +35,13 @@ abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormInteg
protected function getExtensions() protected function getExtensions()
{ {
return array( return array(
new CsrfExtension($this->csrfTokenGenerator), new CsrfExtension($this->csrfTokenManager),
); );
} }
protected function tearDown() protected function tearDown()
{ {
$this->csrfTokenGenerator = null; $this->csrfTokenManager = null;
parent::tearDown(); parent::tearDown();
} }

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Tests; namespace Symfony\Component\Form\Tests;
use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormError;
use Symfony\Component\Security\Csrf\CsrfToken;
abstract class AbstractTableLayoutTest extends AbstractLayoutTest abstract class AbstractTableLayoutTest extends AbstractLayoutTest
{ {
@ -336,9 +337,9 @@ abstract class AbstractTableLayoutTest extends AbstractLayoutTest
public function testCsrf() public function testCsrf()
{ {
$this->csrfTokenGenerator->expects($this->any()) $this->csrfTokenManager->expects($this->any())
->method('generateCsrfToken') ->method('getToken')
->will($this->returnValue('foo&bar')); ->will($this->returnValue(new CsrfToken('token_id', 'foo&bar')));
$form = $this->factory->createNamedBuilder('name', 'form') $form = $this->factory->createNamedBuilder('name', 'form')
->add($this->factory ->add($this->factory

View File

@ -19,14 +19,14 @@ class CsrfValidationListenerTest extends \PHPUnit_Framework_TestCase
{ {
protected $dispatcher; protected $dispatcher;
protected $factory; protected $factory;
protected $tokenGenerator; protected $tokenManager;
protected $form; protected $form;
protected function setUp() protected function setUp()
{ {
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface'); $this->factory = $this->getMock('Symfony\Component\Form\FormFactoryInterface');
$this->tokenGenerator = $this->getMock('Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface'); $this->tokenManager = $this->getMock('Symfony\Component\Security\Csrf\CsrfTokenManagerInterface');
$this->form = $this->getBuilder('post') $this->form = $this->getBuilder('post')
->setDataMapper($this->getDataMapper()) ->setDataMapper($this->getDataMapper())
->getForm(); ->getForm();
@ -36,7 +36,7 @@ class CsrfValidationListenerTest extends \PHPUnit_Framework_TestCase
{ {
$this->dispatcher = null; $this->dispatcher = null;
$this->factory = null; $this->factory = null;
$this->tokenGenerator = null; $this->tokenManager = null;
$this->form = null; $this->form = null;
} }
@ -66,7 +66,7 @@ class CsrfValidationListenerTest extends \PHPUnit_Framework_TestCase
$data = "XP4HUzmHPi"; $data = "XP4HUzmHPi";
$event = new FormEvent($this->form, $data); $event = new FormEvent($this->form, $data);
$validation = new CsrfValidationListener('csrf', $this->tokenGenerator, 'unknown', 'Invalid.'); $validation = new CsrfValidationListener('csrf', $this->tokenManager, 'unknown', 'Invalid.');
$validation->preSubmit($event); $validation->preSubmit($event);
// Validate accordingly // Validate accordingly

View File

@ -16,6 +16,7 @@ use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormError;
use Symfony\Component\Form\Test\TypeTestCase; use Symfony\Component\Form\Test\TypeTestCase;
use Symfony\Component\Form\Extension\Csrf\CsrfExtension; use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
use Symfony\Component\Security\Csrf\CsrfToken;
class FormTypeCsrfExtensionTest_ChildType extends AbstractType class FormTypeCsrfExtensionTest_ChildType extends AbstractType
{ {
@ -37,7 +38,7 @@ class FormTypeCsrfExtensionTest extends TypeTestCase
/** /**
* @var \PHPUnit_Framework_MockObject_MockObject * @var \PHPUnit_Framework_MockObject_MockObject
*/ */
protected $tokenGenerator; protected $tokenManager;
/** /**
* @var \PHPUnit_Framework_MockObject_MockObject * @var \PHPUnit_Framework_MockObject_MockObject
@ -46,7 +47,7 @@ class FormTypeCsrfExtensionTest extends TypeTestCase
protected function setUp() protected function setUp()
{ {
$this->tokenGenerator = $this->getMock('Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface'); $this->tokenManager = $this->getMock('Symfony\Component\Security\Csrf\CsrfTokenManagerInterface');
$this->translator = $this->getMock('Symfony\Component\Translation\TranslatorInterface'); $this->translator = $this->getMock('Symfony\Component\Translation\TranslatorInterface');
parent::setUp(); parent::setUp();
@ -54,7 +55,7 @@ class FormTypeCsrfExtensionTest extends TypeTestCase
protected function tearDown() protected function tearDown()
{ {
$this->tokenGenerator = null; $this->tokenManager = null;
$this->translator = null; $this->translator = null;
parent::tearDown(); parent::tearDown();
@ -63,7 +64,7 @@ class FormTypeCsrfExtensionTest extends TypeTestCase
protected function getExtensions() protected function getExtensions()
{ {
return array_merge(parent::getExtensions(), array( return array_merge(parent::getExtensions(), array(
new CsrfExtension($this->tokenGenerator, $this->translator), new CsrfExtension($this->tokenManager, $this->translator),
)); ));
} }
@ -123,16 +124,16 @@ class FormTypeCsrfExtensionTest extends TypeTestCase
public function testGenerateCsrfToken() public function testGenerateCsrfToken()
{ {
$this->tokenGenerator->expects($this->once()) $this->tokenManager->expects($this->once())
->method('generateCsrfToken') ->method('getToken')
->with('%INTENTION%') ->with('TOKEN_ID')
->will($this->returnValue('token')); ->will($this->returnValue(new CsrfToken('TOKEN_ID', 'token')));
$view = $this->factory $view = $this->factory
->create('form', null, array( ->create('form', null, array(
'csrf_field_name' => 'csrf', 'csrf_field_name' => 'csrf',
'csrf_provider' => $this->tokenGenerator, 'csrf_token_manager' => $this->tokenManager,
'intention' => '%INTENTION%', 'csrf_token_id' => 'TOKEN_ID',
'compound' => true, 'compound' => true,
)) ))
->createView(); ->createView();
@ -153,16 +154,16 @@ class FormTypeCsrfExtensionTest extends TypeTestCase
*/ */
public function testValidateTokenOnSubmitIfRootAndCompound($valid) public function testValidateTokenOnSubmitIfRootAndCompound($valid)
{ {
$this->tokenGenerator->expects($this->once()) $this->tokenManager->expects($this->once())
->method('isCsrfTokenValid') ->method('isTokenValid')
->with('%INTENTION%', 'token') ->with(new CsrfToken('TOKEN_ID', 'token'))
->will($this->returnValue($valid)); ->will($this->returnValue($valid));
$form = $this->factory $form = $this->factory
->createBuilder('form', null, array( ->createBuilder('form', null, array(
'csrf_field_name' => 'csrf', 'csrf_field_name' => 'csrf',
'csrf_provider' => $this->tokenGenerator, 'csrf_token_manager' => $this->tokenManager,
'intention' => '%INTENTION%', 'csrf_token_id' => 'TOKEN_ID',
'compound' => true, 'compound' => true,
)) ))
->add('child', 'text') ->add('child', 'text')
@ -182,14 +183,14 @@ class FormTypeCsrfExtensionTest extends TypeTestCase
public function testFailIfRootAndCompoundAndTokenMissing() public function testFailIfRootAndCompoundAndTokenMissing()
{ {
$this->tokenGenerator->expects($this->never()) $this->tokenManager->expects($this->never())
->method('isCsrfTokenValid'); ->method('isTokenValid');
$form = $this->factory $form = $this->factory
->createBuilder('form', null, array( ->createBuilder('form', null, array(
'csrf_field_name' => 'csrf', 'csrf_field_name' => 'csrf',
'csrf_provider' => $this->tokenGenerator, 'csrf_token_manager' => $this->tokenManager,
'intention' => '%INTENTION%', 'csrf_token_id' => 'TOKEN_ID',
'compound' => true, 'compound' => true,
)) ))
->add('child', 'text') ->add('child', 'text')
@ -209,16 +210,16 @@ class FormTypeCsrfExtensionTest extends TypeTestCase
public function testDontValidateTokenIfCompoundButNoRoot() public function testDontValidateTokenIfCompoundButNoRoot()
{ {
$this->tokenGenerator->expects($this->never()) $this->tokenManager->expects($this->never())
->method('isCsrfTokenValid'); ->method('isTokenValid');
$form = $this->factory $form = $this->factory
->createNamedBuilder('root', 'form') ->createNamedBuilder('root', 'form')
->add($this->factory ->add($this->factory
->createNamedBuilder('form', 'form', null, array( ->createNamedBuilder('form', 'form', null, array(
'csrf_field_name' => 'csrf', 'csrf_field_name' => 'csrf',
'csrf_provider' => $this->tokenGenerator, 'csrf_token_manager' => $this->tokenManager,
'intention' => '%INTENTION%', 'csrf_token_id' => 'TOKEN_ID',
'compound' => true, 'compound' => true,
)) ))
) )
@ -233,14 +234,14 @@ class FormTypeCsrfExtensionTest extends TypeTestCase
public function testDontValidateTokenIfRootButNotCompound() public function testDontValidateTokenIfRootButNotCompound()
{ {
$this->tokenGenerator->expects($this->never()) $this->tokenManager->expects($this->never())
->method('isCsrfTokenValid'); ->method('isTokenValid');
$form = $this->factory $form = $this->factory
->create('form', null, array( ->create('form', null, array(
'csrf_field_name' => 'csrf', 'csrf_field_name' => 'csrf',
'csrf_provider' => $this->tokenGenerator, 'csrf_token_manager' => $this->tokenManager,
'intention' => '%INTENTION%', 'csrf_token_id' => 'TOKEN_ID',
'compound' => false, 'compound' => false,
)); ));
@ -269,9 +270,9 @@ class FormTypeCsrfExtensionTest extends TypeTestCase
public function testsTranslateCustomErrorMessage() public function testsTranslateCustomErrorMessage()
{ {
$this->tokenGenerator->expects($this->once()) $this->tokenManager->expects($this->once())
->method('isCsrfTokenValid') ->method('isTokenValid')
->with('%INTENTION%', 'token') ->with(new CsrfToken('TOKEN_ID', 'token'))
->will($this->returnValue(false)); ->will($this->returnValue(false));
$this->translator->expects($this->once()) $this->translator->expects($this->once())
@ -282,9 +283,9 @@ class FormTypeCsrfExtensionTest extends TypeTestCase
$form = $this->factory $form = $this->factory
->createBuilder('form', null, array( ->createBuilder('form', null, array(
'csrf_field_name' => 'csrf', 'csrf_field_name' => 'csrf',
'csrf_provider' => $this->tokenGenerator, 'csrf_token_manager' => $this->tokenManager,
'csrf_message' => 'Foobar', 'csrf_message' => 'Foobar',
'intention' => '%INTENTION%', 'csrf_token_id' => 'TOKEN_ID',
'compound' => true, 'compound' => true,
)) ))
->getForm(); ->getForm();

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\Core\Exception;
/**
* Base ExceptionInterface for the Security component.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
interface ExceptionInterface
{
}

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\Core\Exception;
/**
* Base InvalidArgumentException for the Security component.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}

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\Core\Exception;
/**
* Base RuntimeException for the Security component.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}

View File

@ -0,0 +1,66 @@
<?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;
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

@ -1,105 +0,0 @@
<?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);
}
}

View File

@ -0,0 +1,106 @@
<?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\StringUtils;
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>
*/
class CsrfTokenManager implements CsrfTokenManagerInterface
{
/**
* @var TokenGeneratorInterface
*/
private $generator;
/**
* @var TokenStorageInterface
*/
private $storage;
/**
* Creates a new CSRF provider using PHP's native session storage.
*
* @param TokenGeneratorInterface $generator The token generator
* @param TokenStorageInterface $storage The storage for storing
* generated CSRF tokens
*
*/
public function __construct(TokenGeneratorInterface $generator = null, TokenStorageInterface $storage = null)
{
if (null === $generator) {
$generator = new UriSafeTokenGenerator();
}
if (null === $storage) {
$storage = new NativeSessionTokenStorage();
}
$this->generator = $generator;
$this->storage = $storage;
}
/**
* {@inheritdoc}
*/
public function getToken($tokenId)
{
if ($this->storage->hasToken($tokenId)) {
$value = $this->storage->getToken($tokenId);
} else {
$value = $this->generator->generateToken();
$this->storage->setToken($tokenId, $value);
}
return new CsrfToken($tokenId, $value);
}
/**
* {@inheritdoc}
*/
public function refreshToken($tokenId)
{
$value = $this->generator->generateToken();
$this->storage->setToken($tokenId, $value);
return new CsrfToken($tokenId, $value);
}
/**
* {@inheritdoc}
*/
public function removeToken($tokenId)
{
return $this->storage->removeToken($tokenId);
}
/**
* {@inheritdoc}
*/
public function isTokenValid(CsrfToken $token)
{
if (!$this->storage->hasToken($token->getId())) {
return false;
}
return StringUtils::equals((string) $this->storage->getToken($token->getId()), $token->getValue());
}
}

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.
*
* @since 2.4
* @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.
*
* @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 Boolean Returns true if a token existed for this ID, false
* otherwise
*/
public function removeToken($tokenId);
/**
* Returns whether the given CSRF token is valid.
*
* @param CsrfToken $token A CSRF token
*
* @return Boolean 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
{
}

View File

@ -2,7 +2,7 @@ Security Component - CSRF
========================= =========================
The Security CSRF (cross-site request forgery) component provides a class The Security CSRF (cross-site request forgery) component provides a class
`CsrfTokenGenerator` for generating and validating CSRF tokens. `CsrfTokenManager` for generating and validating CSRF tokens.
Resources Resources
--------- ---------

View File

@ -1,148 +0,0 @@
<?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'));
}
}

View File

@ -0,0 +1,164 @@
<?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\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManager;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class CsrfTokenManagerTest extends \PHPUnit_Framework_TestCase
{
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $generator;
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $storage;
/**
* @var CsrfTokenManager
*/
private $manager;
protected function setUp()
{
$this->generator = $this->getMock('Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface');
$this->storage = $this->getMock('Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface');
$this->manager = new CsrfTokenManager($this->generator, $this->storage);
}
protected function tearDown()
{
$this->generator = null;
$this->storage = null;
$this->manager = null;
}
public function testGetNonExistingToken()
{
$this->storage->expects($this->once())
->method('hasToken')
->with('token_id')
->will($this->returnValue(false));
$this->generator->expects($this->once())
->method('generateToken')
->will($this->returnValue('TOKEN'));
$this->storage->expects($this->once())
->method('setToken')
->with('token_id', 'TOKEN');
$token = $this->manager->getToken('token_id');
$this->assertInstanceOf('Symfony\Component\Security\Csrf\CsrfToken', $token);
$this->assertSame('token_id', $token->getId());
$this->assertSame('TOKEN', $token->getValue());
}
public function testUseExistingTokenIfAvailable()
{
$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'));
$token = $this->manager->getToken('token_id');
$this->assertInstanceOf('Symfony\Component\Security\Csrf\CsrfToken', $token);
$this->assertSame('token_id', $token->getId());
$this->assertSame('TOKEN', $token->getValue());
}
public function testRefreshTokenAlwaysReturnsNewToken()
{
$this->storage->expects($this->never())
->method('hasToken');
$this->generator->expects($this->once())
->method('generateToken')
->will($this->returnValue('TOKEN'));
$this->storage->expects($this->once())
->method('setToken')
->with('token_id', 'TOKEN');
$token = $this->manager->refreshToken('token_id');
$this->assertInstanceOf('Symfony\Component\Security\Csrf\CsrfToken', $token);
$this->assertSame('token_id', $token->getId());
$this->assertSame('TOKEN', $token->getValue());
}
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->manager->isTokenValid(new CsrfToken('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->manager->isTokenValid(new CsrfToken('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->manager->isTokenValid(new CsrfToken('token_id', 'FOOBAR')));
}
public function testRemoveToken()
{
$this->storage->expects($this->once())
->method('removeToken')
->with('token_id')
->will($this->returnValue('REMOVED_TOKEN'));
$this->assertSame('REMOVED_TOKEN', $this->manager->removeToken('token_id'));
}
}

View File

@ -0,0 +1,71 @@
<?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\TokenGenerator;
use Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class UriSafeTokenGeneratorTest extends \PHPUnit_Framework_TestCase
{
const ENTROPY = 1000;
/**
* A non alpha-numeric byte string
* @var string
*/
private static $bytes;
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $random;
/**
* @var UriSafeTokenGenerator
*/
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->generator = new UriSafeTokenGenerator($this->random, self::ENTROPY);
}
protected function tearDown()
{
$this->random = null;
$this->generator = null;
}
public function testGenerateToken()
{
$this->random->expects($this->once())
->method('nextBytes')
->with(self::ENTROPY/8)
->will($this->returnValue(self::$bytes));
$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

@ -96,8 +96,31 @@ class NativeSessionTokenStorageTest extends \PHPUnit_Framework_TestCase
$this->assertSame('TOKEN', $this->storage->getToken('token_id')); $this->assertSame('TOKEN', $this->storage->getToken('token_id'));
} }
/**
* @expectedException \Symfony\Component\Security\Csrf\Exception\TokenNotFoundException
*/
public function testGetNonExistingToken() public function testGetNonExistingToken()
{ {
$this->assertSame('DEFAULT', $this->storage->getToken('token_id', 'DEFAULT')); $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

@ -108,7 +108,7 @@ class SessionTokenStorageTest extends \PHPUnit_Framework_TestCase
$this->assertSame('RESULT', $this->storage->hasToken('token_id')); $this->assertSame('RESULT', $this->storage->hasToken('token_id'));
} }
public function testGetTokenFromClosedSession() public function testGetExistingTokenFromClosedSession()
{ {
$this->session->expects($this->any()) $this->session->expects($this->any())
->method('isStarted') ->method('isStarted')
@ -117,15 +117,20 @@ class SessionTokenStorageTest extends \PHPUnit_Framework_TestCase
$this->session->expects($this->once()) $this->session->expects($this->once())
->method('start'); ->method('start');
$this->session->expects($this->once())
->method('has')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue(true));
$this->session->expects($this->once()) $this->session->expects($this->once())
->method('get') ->method('get')
->with(self::SESSION_NAMESPACE.'/token_id', 'DEFAULT') ->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue('RESULT')); ->will($this->returnValue('RESULT'));
$this->assertSame('RESULT', $this->storage->getToken('token_id', 'DEFAULT')); $this->assertSame('RESULT', $this->storage->getToken('token_id'));
} }
public function testGetTokenFromActiveSession() public function testGetExistingTokenFromActiveSession()
{ {
$this->session->expects($this->any()) $this->session->expects($this->any())
->method('isStarted') ->method('isStarted')
@ -134,11 +139,124 @@ class SessionTokenStorageTest extends \PHPUnit_Framework_TestCase
$this->session->expects($this->never()) $this->session->expects($this->never())
->method('start'); ->method('start');
$this->session->expects($this->once())
->method('has')
->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue(true));
$this->session->expects($this->once()) $this->session->expects($this->once())
->method('get') ->method('get')
->with(self::SESSION_NAMESPACE.'/token_id', 'DEFAULT') ->with(self::SESSION_NAMESPACE.'/token_id')
->will($this->returnValue('RESULT')); ->will($this->returnValue('RESULT'));
$this->assertSame('RESULT', $this->storage->getToken('token_id', 'DEFAULT')); $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

@ -9,7 +9,7 @@
* file that was distributed with this source code. * file that was distributed with this source code.
*/ */
namespace Symfony\Component\Security\Csrf; namespace Symfony\Component\Security\Csrf\TokenGenerator;
/** /**
* Generates and validates CSRF tokens. * Generates and validates CSRF tokens.
@ -29,24 +29,12 @@ namespace Symfony\Component\Security\Csrf;
* @since 2.4 * @since 2.4
* @author Bernhard Schussek <bschussek@gmail.com> * @author Bernhard Schussek <bschussek@gmail.com>
*/ */
interface CsrfTokenGeneratorInterface interface TokenGeneratorInterface
{ {
/** /**
* Generates a CSRF token with the given token ID. * Generates a CSRF token.
*
* @param string $tokenId An ID that identifies the token
* *
* @return string The generated CSRF token * @return string The generated CSRF token
*/ */
public function generateCsrfToken($tokenId); public function generateToken();
/**
* 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);
} }

View File

@ -0,0 +1,73 @@
<?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;
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 CSRF tokens.
*
* @since 2.4
* @author Bernhard Schussek <bernhard.schussek@symfony.com>
*/
class UriSafeTokenGenerator implements TokenGeneratorInterface
{
/**
* The generator for random values.
*
* @var SecureRandomInterface
*/
private $random;
/**
* The amount of entropy collected for each token (in bits).
*
* @var integer
*/
private $entropy;
/**
* Generates URI-safe CSRF tokens.
*
* @param SecureRandomInterface $random The random value generator used for
* generating entropy
* @param integer $entropy The amount of entropy collected for
* each token (in bits)
*
*/
public function __construct(SecureRandomInterface $random = null, $entropy = 256)
{
if (null === $random) {
$random = new SecureRandom();
}
$this->random = $random;
$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 = $this->random->nextBytes($this->entropy / 8);
return rtrim(strtr(base64_encode($bytes), '+/', '-_'), '=');
}
}

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Security\Csrf\TokenStorage; namespace Symfony\Component\Security\Csrf\TokenStorage;
use Symfony\Component\Security\Csrf\Exception\TokenNotFoundException;
/** /**
* Token storage that uses PHP's native session handling. * Token storage that uses PHP's native session handling.
* *
@ -49,17 +51,17 @@ class NativeSessionTokenStorage implements TokenStorageInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getToken($tokenId, $default = null) public function getToken($tokenId)
{ {
if (!$this->sessionStarted) { if (!$this->sessionStarted) {
$this->startSession(); $this->startSession();
} }
if (isset($_SESSION[$this->namespace][$tokenId])) { if (!isset($_SESSION[$this->namespace][$tokenId])) {
return $_SESSION[$this->namespace][$tokenId]; throw new TokenNotFoundException('The CSRF token with ID '.$tokenId.' does not exist.');
} }
return $default; return (string) $_SESSION[$this->namespace][$tokenId];
} }
/** /**
@ -71,7 +73,7 @@ class NativeSessionTokenStorage implements TokenStorageInterface
$this->startSession(); $this->startSession();
} }
$_SESSION[$this->namespace][$tokenId] = $token; $_SESSION[$this->namespace][$tokenId] = (string) $token;
} }
/** /**
@ -86,6 +88,24 @@ class NativeSessionTokenStorage implements TokenStorageInterface
return isset($_SESSION[$this->namespace][$tokenId]); return isset($_SESSION[$this->namespace][$tokenId]);
} }
/**
* {@inheritdoc}
*/
public function removeToken($tokenId)
{
if (!$this->sessionStarted) {
$this->startSession();
}
$token = isset($_SESSION[$this->namespace][$tokenId])
? $_SESSION[$this->namespace][$tokenId]
: null;
unset($_SESSION[$this->namespace][$tokenId]);
return $token;
}
private function startSession() private function startSession()
{ {
if (version_compare(PHP_VERSION, '5.4', '>=')) { if (version_compare(PHP_VERSION, '5.4', '>=')) {

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Security\Csrf\TokenStorage; namespace Symfony\Component\Security\Csrf\TokenStorage;
use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Csrf\Exception\TokenNotFoundException;
/** /**
* Token storage that uses a Symfony2 Session object. * Token storage that uses a Symfony2 Session object.
@ -54,13 +55,17 @@ class SessionTokenStorage implements TokenStorageInterface
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getToken($tokenId, $default = null) public function getToken($tokenId)
{ {
if (!$this->session->isStarted()) { if (!$this->session->isStarted()) {
$this->session->start(); $this->session->start();
} }
return $this->session->get($this->namespace . '/' . $tokenId, $default); 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);
} }
/** /**
@ -72,7 +77,7 @@ class SessionTokenStorage implements TokenStorageInterface
$this->session->start(); $this->session->start();
} }
$this->session->set($this->namespace . '/' . $tokenId, $token); $this->session->set($this->namespace.'/'.$tokenId, (string) $token);
} }
/** /**
@ -84,6 +89,18 @@ class SessionTokenStorage implements TokenStorageInterface
$this->session->start(); $this->session->start();
} }
return $this->session->has($this->namespace . '/' . $tokenId); 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

@ -23,27 +23,37 @@ interface TokenStorageInterface
* Reads a stored CSRF token. * Reads a stored CSRF token.
* *
* @param string $tokenId The token ID * @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 * @return string The stored token
*
* @throws \Symfony\Component\Security\Csrf\Exception\TokenNotFoundException If the token ID does not exist
*/ */
public function getToken($tokenId, $default = null); public function getToken($tokenId);
/** /**
* Stores a CSRF token. * Stores a CSRF token.
* *
* @param string $tokenId The token ID * @param string $tokenId The token ID
* @param mixed $token The CSRF token * @param string $token The CSRF token
*/ */
public function setToken($tokenId, $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. * Checks whether a token with the given token ID exists.
* *
* @param string $tokenId The token ID * @param string $tokenId The token ID
* *
* @return Boolean Returns true if a token is stored for the given token ID, * @return Boolean Whether a token exists with the given ID
* false otherwise.
*/ */
public function hasToken($tokenId); public function hasToken($tokenId);
} }

View File

@ -11,12 +11,16 @@
namespace Symfony\Component\Security\Http\Firewall; namespace Symfony\Component\Security\Http\Firewall;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Core\Exception\LogoutException; use Symfony\Component\Security\Core\Exception\LogoutException;
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface; use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface; use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface; use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
@ -34,19 +38,25 @@ class LogoutListener implements ListenerInterface
private $handlers; private $handlers;
private $successHandler; private $successHandler;
private $httpUtils; private $httpUtils;
private $csrfTokenGenerator; private $csrfTokenManager;
/** /**
* Constructor. * Constructor.
* *
* @param SecurityContextInterface $securityContext * @param SecurityContextInterface $securityContext
* @param HttpUtils $httpUtils An HttpUtilsInterface instance * @param HttpUtils $httpUtils An HttpUtilsInterface instance
* @param LogoutSuccessHandlerInterface $successHandler A LogoutSuccessHandlerInterface instance * @param LogoutSuccessHandlerInterface $successHandler A LogoutSuccessHandlerInterface instance
* @param array $options An array of options to process a logout attempt * @param array $options An array of options to process a logout attempt
* @param CsrfTokenGeneratorInterface $csrfTokenGenerator A CsrfTokenGeneratorInterface instance * @param CsrfTokenManagerInterface $csrfTokenManager A CsrfTokenManagerInterface instance
*/ */
public function __construct(SecurityContextInterface $securityContext, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), CsrfTokenGeneratorInterface $csrfTokenGenerator = null) public function __construct(SecurityContextInterface $securityContext, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), $csrfTokenManager = null)
{ {
if ($csrfTokenManager instanceof CsrfProviderInterface) {
$csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager);
} elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) {
throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.');
}
$this->securityContext = $securityContext; $this->securityContext = $securityContext;
$this->httpUtils = $httpUtils; $this->httpUtils = $httpUtils;
$this->options = array_merge(array( $this->options = array_merge(array(
@ -55,7 +65,7 @@ class LogoutListener implements ListenerInterface
'logout_path' => '/logout', 'logout_path' => '/logout',
), $options); ), $options);
$this->successHandler = $successHandler; $this->successHandler = $successHandler;
$this->csrfTokenGenerator = $csrfTokenGenerator; $this->csrfTokenManager = $csrfTokenManager;
$this->handlers = array(); $this->handlers = array();
} }
@ -72,7 +82,7 @@ class LogoutListener implements ListenerInterface
/** /**
* Performs the logout if requested * Performs the logout if requested
* *
* If a CsrfTokenGeneratorInterface instance is available, it will be used to * If a CsrfTokenManagerInterface instance is available, it will be used to
* validate the request. * validate the request.
* *
* @param GetResponseEvent $event A GetResponseEvent instance * @param GetResponseEvent $event A GetResponseEvent instance
@ -88,10 +98,10 @@ class LogoutListener implements ListenerInterface
return; return;
} }
if (null !== $this->csrfTokenGenerator) { if (null !== $this->csrfTokenManager) {
$csrfToken = $request->get($this->options['csrf_parameter'], null, true); $csrfToken = $request->get($this->options['csrf_parameter'], null, true);
if (false === $this->csrfTokenGenerator->isCsrfTokenValid($this->options['intention'], $csrfToken)) { if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) {
throw new LogoutException('Invalid CSRF token.'); throw new LogoutException('Invalid CSRF token.');
} }
} }

View File

@ -12,9 +12,13 @@
namespace Symfony\Component\Security\Http\Firewall; namespace Symfony\Component\Security\Http\Firewall;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface; use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
@ -30,7 +34,7 @@ use Psr\Log\LoggerInterface;
class SimpleFormAuthenticationListener extends AbstractAuthenticationListener class SimpleFormAuthenticationListener extends AbstractAuthenticationListener
{ {
private $simpleAuthenticator; private $simpleAuthenticator;
private $csrfTokenGenerator; private $csrfTokenManager;
/** /**
* Constructor. * Constructor.
@ -47,16 +51,22 @@ class SimpleFormAuthenticationListener extends AbstractAuthenticationListener
* @param LoggerInterface $logger A LoggerInterface instance * @param LoggerInterface $logger A LoggerInterface instance
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
* @param SimpleFormAuthenticatorInterface $simpleAuthenticator A SimpleFormAuthenticatorInterface instance * @param SimpleFormAuthenticatorInterface $simpleAuthenticator A SimpleFormAuthenticatorInterface instance
* @param CsrfTokenGeneratorInterface $csrfTokenGenerator A CsrfTokenGeneratorInterface instance * @param CsrfTokenManagerInterface $csrfTokenManager A CsrfTokenManagerInterface instance
*/ */
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenGeneratorInterface $csrfTokenGenerator = null, SimpleFormAuthenticatorInterface $simpleAuthenticator = null) public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenManagerInterface $csrfTokenManager = null, SimpleFormAuthenticatorInterface $simpleAuthenticator = null)
{ {
if (!$simpleAuthenticator) { if (!$simpleAuthenticator) {
throw new \InvalidArgumentException('Missing simple authenticator'); throw new \InvalidArgumentException('Missing simple authenticator');
} }
if ($csrfTokenManager instanceof CsrfProviderInterface) {
$csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager);
} elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) {
throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.');
}
$this->simpleAuthenticator = $simpleAuthenticator; $this->simpleAuthenticator = $simpleAuthenticator;
$this->csrfTokenGenerator = $csrfTokenGenerator; $this->csrfTokenManager = $csrfTokenManager;
$options = array_merge(array( $options = array_merge(array(
'username_parameter' => '_username', 'username_parameter' => '_username',
@ -85,10 +95,10 @@ class SimpleFormAuthenticationListener extends AbstractAuthenticationListener
*/ */
protected function attemptAuthentication(Request $request) protected function attemptAuthentication(Request $request)
{ {
if (null !== $this->csrfTokenGenerator) { if (null !== $this->csrfTokenManager) {
$csrfToken = $request->get($this->options['csrf_parameter'], null, true); $csrfToken = $request->get($this->options['csrf_parameter'], null, true);
if (false === $this->csrfTokenGenerator->isCsrfTokenValid($this->options['intention'], $csrfToken)) { if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) {
throw new InvalidCsrfTokenException('Invalid CSRF token.'); throw new InvalidCsrfTokenException('Invalid CSRF token.');
} }
} }

View File

@ -11,15 +11,19 @@
namespace Symfony\Component\Security\Http\Firewall; namespace Symfony\Component\Security\Http\Firewall;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface; use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@ -32,13 +36,19 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
*/ */
class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationListener class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationListener
{ {
private $csrfTokenGenerator; private $csrfTokenManager;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenGeneratorInterface $csrfTokenGenerator = null) public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, $csrfTokenManager = null)
{ {
if ($csrfTokenManager instanceof CsrfProviderInterface) {
$csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager);
} elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) {
throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.');
}
parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array( parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
'username_parameter' => '_username', 'username_parameter' => '_username',
'password_parameter' => '_password', 'password_parameter' => '_password',
@ -47,7 +57,7 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL
'post_only' => true, 'post_only' => true,
), $options), $logger, $dispatcher); ), $options), $logger, $dispatcher);
$this->csrfTokenGenerator = $csrfTokenGenerator; $this->csrfTokenManager = $csrfTokenManager;
} }
/** /**
@ -67,10 +77,10 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL
*/ */
protected function attemptAuthentication(Request $request) protected function attemptAuthentication(Request $request)
{ {
if (null !== $this->csrfTokenGenerator) { if (null !== $this->csrfTokenManager) {
$csrfToken = $request->get($this->options['csrf_parameter'], null, true); $csrfToken = $request->get($this->options['csrf_parameter'], null, true);
if (false === $this->csrfTokenGenerator->isCsrfTokenValid($this->options['intention'], $csrfToken)) { if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) {
throw new InvalidCsrfTokenException('Invalid CSRF token.'); throw new InvalidCsrfTokenException('Invalid CSRF token.');
} }
} }