From e1aced89fd0f036ee4fd448d17184c168f2c9ae0 Mon Sep 17 00:00:00 2001 From: Kris Wallsmith Date: Tue, 10 Jan 2012 04:55:48 -0800 Subject: [PATCH 1/2] [Twig] added {{ csrf_token() }} helper --- .../Bridge/Twig/Extension/FormExtension.php | 34 ++++++++++++++++++- .../TwigBundle/Resources/config/twig.xml | 1 + .../Extension/FormExtensionDivLayoutTest.php | 2 +- .../FormExtensionTableLayoutTest.php | 2 +- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/FormExtension.php b/src/Symfony/Bridge/Twig/Extension/FormExtension.php index 25004e90fd..b73212020a 100644 --- a/src/Symfony/Bridge/Twig/Extension/FormExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/FormExtension.php @@ -14,6 +14,7 @@ namespace Symfony\Bridge\Twig\Extension; use Symfony\Bridge\Twig\TokenParser\FormThemeTokenParser; use Symfony\Component\Form\FormView; use Symfony\Component\Form\Exception\FormException; +use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\Form\Util\FormUtil; /** @@ -24,6 +25,7 @@ use Symfony\Component\Form\Util\FormUtil; */ class FormExtension extends \Twig_Extension { + protected $csrfProvider; protected $resources; protected $blocks; protected $environment; @@ -31,8 +33,9 @@ class FormExtension extends \Twig_Extension protected $varStack; protected $template; - public function __construct(array $resources = array()) + public function __construct(CsrfProviderInterface $csrfProvider, array $resources = array()) { + $this->csrfProvider = $csrfProvider; $this->themes = new \SplObjectStorage(); $this->varStack = array(); $this->blocks = new \SplObjectStorage(); @@ -81,6 +84,7 @@ class FormExtension extends \Twig_Extension 'form_label' => new \Twig_Function_Method($this, 'renderLabel', array('is_safe' => array('html'))), 'form_row' => new \Twig_Function_Method($this, 'renderRow', array('is_safe' => array('html'))), 'form_rest' => new \Twig_Function_Method($this, 'renderRest', array('is_safe' => array('html'))), + 'csrf_token' => new \Twig_Function_Method($this, 'getCsrfToken'), '_form_is_choice_group' => new \Twig_Function_Method($this, 'isChoiceGroup', array('is_safe' => array('html'))), '_form_is_choice_selected' => new \Twig_Function_Method($this, 'isChoiceSelected', array('is_safe' => array('html'))), ); @@ -269,6 +273,34 @@ class FormExtension extends \Twig_Extension )); } + /** + * Returns a CSRF token. + * + * Use this helper for CSRF protection without the overhead of creating a + * form. + * + * + * + * + * + * Check the token in your action using the same intention. + * + * + * $csrfProvider = $this->get('form.csrf_provider'); + * if (!$csrfProvider->isCsrfTokenValid('rm_user_'.$user->getId(), $token)) { + * throw new \RuntimeException('CSRF attack detected.'); + * } + * + * + * @param string $intention The intention of the protected action + * + * @return string A CSRF token + */ + public function getCsrfToken($intention) + { + return $this->csrfProvider->generateCsrfToken($intention); + } + /** * Returns the name of the extension. * diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index 7c24db417d..36b4000ff8 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -75,6 +75,7 @@ + %twig.form.resources% diff --git a/tests/Symfony/Tests/Bridge/Twig/Extension/FormExtensionDivLayoutTest.php b/tests/Symfony/Tests/Bridge/Twig/Extension/FormExtensionDivLayoutTest.php index be935ccc96..4f4be0be54 100644 --- a/tests/Symfony/Tests/Bridge/Twig/Extension/FormExtensionDivLayoutTest.php +++ b/tests/Symfony/Tests/Bridge/Twig/Extension/FormExtensionDivLayoutTest.php @@ -38,7 +38,7 @@ class FormExtensionDivLayoutTest extends AbstractDivLayoutTest __DIR__, )); - $this->extension = new FormExtension(array( + $this->extension = new FormExtension($this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface'), array( 'form_div_layout.html.twig', 'custom_widgets.html.twig', )); diff --git a/tests/Symfony/Tests/Bridge/Twig/Extension/FormExtensionTableLayoutTest.php b/tests/Symfony/Tests/Bridge/Twig/Extension/FormExtensionTableLayoutTest.php index bb7e44743f..96cbf11612 100644 --- a/tests/Symfony/Tests/Bridge/Twig/Extension/FormExtensionTableLayoutTest.php +++ b/tests/Symfony/Tests/Bridge/Twig/Extension/FormExtensionTableLayoutTest.php @@ -38,7 +38,7 @@ class FormExtensionTableLayoutTest extends AbstractTableLayoutTest __DIR__, )); - $this->extension = new FormExtension(array( + $this->extension = new FormExtension($this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface'), array( 'form_table_layout.html.twig', 'custom_widgets.html.twig', )); From 753c06761a423c99e0aeba079bd7144e2650e500 Mon Sep 17 00:00:00 2001 From: Kris Wallsmith Date: Tue, 10 Jan 2012 04:56:30 -0800 Subject: [PATCH 2/2] [FrameworkBundle] added $view['form']->csrfToken() helper --- .../Resources/config/templating_php.xml | 1 + .../Templating/Helper/FormHelper.php | 41 +++++++++++++++++-- .../Helper/FormHelperDivLayoutTest.php | 2 +- .../Helper/FormHelperTableLayoutTest.php | 2 +- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml index 7c6f05a3af..9cc86bded2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating_php.xml @@ -97,6 +97,7 @@ + %templating.helper.form.resources% diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php index 3a66602498..084381aa1e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php @@ -15,6 +15,7 @@ use Symfony\Component\Templating\Helper\Helper; use Symfony\Component\Templating\EngineInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Form\Exception\FormException; +use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\Form\Util\FormUtil; /** @@ -27,6 +28,8 @@ class FormHelper extends Helper { protected $engine; + protected $csrfProvider; + protected $varStack; protected $context; @@ -38,14 +41,16 @@ class FormHelper extends Helper protected $templates; /** - * Constructor; + * Constructor. * - * @param EngineInterface $engine The templating engine - * @param array $resources An array of theme name + * @param EngineInterface $engine The templating engine + * @param CsrfProviderInterface $csrfProvider The CSRF provider + * @param array $resources An array of theme names */ - public function __construct(EngineInterface $engine, array $resources) + public function __construct(EngineInterface $engine, CsrfProviderInterface $csrfProvider, array $resources) { $this->engine = $engine; + $this->csrfProvider = $csrfProvider; $this->resources = $resources; $this->varStack = array(); $this->context = array(); @@ -172,6 +177,34 @@ class FormHelper extends Helper return $this->renderSection($view, 'rest', $variables); } + /** + * Returns a CSRF token. + * + * Use this helper for CSRF protection without the overhead of creating a + * form. + * + * + * echo $view['form']->csrfToken('rm_user_'.$user->getId()); + * + * + * Check the token in your action using the same intention. + * + * + * $csrfProvider = $this->get('form.csrf_provider'); + * if (!$csrfProvider->isCsrfTokenValid('rm_user_'.$user->getId(), $token)) { + * throw new \RuntimeException('CSRF attack detected.'); + * } + * + * + * @param string $intention The intention of the protected action + * + * @return string A CSRF token + */ + public function csrfToken($intention) + { + return $this->csrfProvider->generateCsrfToken($intention); + } + /** * Renders a template. * diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php index 01b0bc614e..7955f418ff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php @@ -37,7 +37,7 @@ class FormHelperDivLayoutTest extends AbstractDivLayoutTest $loader = new FilesystemLoader(array()); $engine = new PhpEngine($templateNameParser, $loader); - $this->helper = new FormHelper($engine, array('FrameworkBundle:Form')); + $this->helper = new FormHelper($engine, $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface'), array('FrameworkBundle:Form')); $engine->setHelpers(array( $this->helper, diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php index be209444ed..da2223135c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php @@ -37,7 +37,7 @@ class FormHelperTableLayoutTest extends AbstractTableLayoutTest $loader = new FilesystemLoader(array()); $engine = new PhpEngine($templateNameParser, $loader); - $this->helper = new FormHelper($engine, array( + $this->helper = new FormHelper($engine, $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface'), array( 'FrameworkBundle:Form', 'FrameworkBundle:FormTable' ));