Skip to content

[Security\Csrf] Split CsrfTokenGenerator into CsrfTokenManager and TokenGenerator #9216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 7, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion UPGRADE-3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ UPGRADE FROM 2.x to 3.0

* The interface `Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface`
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"
and "csrf_token_id".
Expand Down
15 changes: 12 additions & 3 deletions src/Symfony/Bridge/Twig/Form/TwigRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@

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\Security\Csrf\CsrfTokenGeneratorInterface;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;

/**
* @author Bernhard Schussek <bschussek@gmail.com>
Expand All @@ -24,9 +27,15 @@ class TwigRenderer extends FormRenderer implements TwigRendererInterface
*/
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');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should use FQCN in the message IMO

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about that, but then it becomes insanely long

}

parent::__construct($engine, $csrfTokenManager);

$this->engine = $engine;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<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">
<tag name="form.type_extension" alias="form" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,23 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<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_manager.class">Symfony\Component\Security\Csrf\CsrfTokenManager</parameter>
</parameters>

<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">
<argument type="service" id="session" />
</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.secure_random" />
</service>
</services>
</container>
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected function getExtensions()
));

return array_merge(parent::getExtensions(), array(
new TemplatingExtension($this->engine, $this->csrfTokenGenerator, array(
new TemplatingExtension($this->engine, $this->csrfTokenManager, array(
'FrameworkBundle:Form',
)),
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected function getExtensions()
));

return array_merge(parent::getExtensions(), array(
new TemplatingExtension($this->engine, $this->csrfTokenGenerator, array(
new TemplatingExtension($this->engine, $this->csrfTokenManager, array(
'FrameworkBundle:Form',
'FrameworkBundle:FormTable',
)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
namespace Symfony\Bundle\SecurityBundle\Templating\Helper;

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\Security\Csrf\CsrfTokenGeneratorInterface;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Templating\Helper\Helper;

/**
Expand Down Expand Up @@ -43,15 +45,21 @@ public function __construct(ContainerInterface $container, UrlGeneratorInterface
/**
* Registers a firewall's LogoutListener, allowing its URL to be generated.
*
* @param string $key The firewall key
* @param string $logoutPath The path that starts the logout process
* @param string $csrfTokenId The ID of the CSRF token
* @param string $csrfParameter The CSRF token parameter name
* @param CsrfTokenGeneratorInterface $csrfTokenGenerator A CsrfTokenGeneratorInterface instance
* @param string $key The firewall key
* @param string $logoutPath The path that starts the logout process
* @param string $csrfTokenId The ID of the CSRF token
* @param string $csrfParameter The CSRF token parameter name
* @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);
}

/**
Expand Down Expand Up @@ -94,9 +102,9 @@ private function generateLogoutUrl($key, $referenceType)
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]) {
$request = $this->container->get('request');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ security:
username_parameter: "user_login[username]"
password_parameter: "user_login[password]"
csrf_parameter: "user_login[_token]"
csrf_provider: security.csrf.token_generator
csrf_provider: security.csrf.token_manager
anonymous: ~
logout:
path: /logout_path
target: /
csrf_provider: security.csrf.token_generator
csrf_provider: security.csrf.token_manager

access_control:
- { path: .*, roles: IS_AUTHENTICATED_FULLY }
27 changes: 18 additions & 9 deletions src/Symfony/Component/Form/Extension/Csrf/CsrfExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@

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\AbstractExtension;
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Translation\TranslatorInterface;

/**
Expand All @@ -24,9 +27,9 @@
class CsrfExtension extends AbstractExtension
{
/**
* @var CsrfTokenGeneratorInterface
* @var CsrfTokenManagerInterface
*/
private $tokenGenerator;
private $tokenManager;

/**
* @var TranslatorInterface
Expand All @@ -41,13 +44,19 @@ class CsrfExtension extends AbstractExtension
/**
* Constructor.
*
* @param CsrfTokenGeneratorInterface $tokenGenerator The CSRF token generator
* @param TranslatorInterface $translator The translator for translating error messages
* @param null|string $translationDomain The translation domain for translating
* @param CsrfTokenManagerInterface $tokenManager The CSRF token manager
* @param TranslatorInterface $translator The translator for translating error messages
* @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->translationDomain = $translationDomain;
}
Expand All @@ -58,7 +67,7 @@ public function __construct(CsrfTokenGeneratorInterface $tokenGenerator, Transla
protected function loadTypeExtensions()
{
return array(
new Type\FormTypeCsrfExtension($this->tokenGenerator, true, '_token', $this->translator, $this->translationDomain),
new Type\FormTypeCsrfExtension($this->tokenManager, true, '_token', $this->translator, $this->translationDomain),
);
}
}
Original file line number Diff line number Diff line change
@@ -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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,45 @@

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>
*
* @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);
}

This file was deleted.

Loading