Skip to content

Commit

Permalink
[Security\Csrf] Split CsrfTokenGenerator into CsrfTokenManager and To…
Browse files Browse the repository at this point in the history
…kenGenerator
  • Loading branch information
webmozart committed Oct 7, 2013
1 parent e18bd76 commit d4bb5f4
Show file tree
Hide file tree
Showing 46 changed files with 1,251 additions and 459 deletions.
2 changes: 1 addition & 1 deletion UPGRADE-3.0.md
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
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)

This comment has been minimized.

Copy link
@jjsaunier

jjsaunier Oct 14, 2013

Contributor

Why not CsrfTokenManagerInterface $crsfTokenManager = null ?

This comment has been minimized.

Copy link
@stof

stof Oct 15, 2013

Member

Because it would be a BC break as the class accepts a Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface in 2.3

This implementation accepts both a deprecated CsrfProviderInterface or a new CsrfTokenManagerInterface

This comment has been minimized.

Copy link
@jjsaunier

jjsaunier Oct 15, 2013

Contributor

Ok ty :)

{
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;
}
Expand Down
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
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>
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
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
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
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
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),
);
}
}
@@ -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());
}
}
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.

0 comments on commit d4bb5f4

Please sign in to comment.