Procházet zdrojové kódy

merged kriswallsmith/form/csrf-intention

Fabien Potencier před 14 roky
rodič
revize
eb202bb7b7

+ 3 - 0
UPDATE.md

@@ -23,6 +23,9 @@ beta1 to beta2
     Symfony\Component\Routing\Exception\NotFoundException
     Symfony\Component\Routing\Exception\MethodNotAllowedException
 
+* The form component's ``csrf_page_id`` option has been renamed to
+  ``csrf_intention``.
+
 * The ``error_handler`` setting has been removed. The ``ErrorHandler`` class
   is now managed directly by Symfony SE in ``AppKernel``.
 

+ 1 - 1
src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php

@@ -30,7 +30,7 @@ class FormLoginFactory extends AbstractFactory
         $this->addOption('username_parameter', '_username');
         $this->addOption('password_parameter', '_password');
         $this->addOption('csrf_parameter', '_csrf_token');
-        $this->addOption('csrf_page_id', 'form_login');
+        $this->addOption('intention', 'authenticate');
         $this->addOption('post_only', true);
     }
 

+ 13 - 15
src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderInterface.php

@@ -21,31 +21,29 @@ namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
  * secret information.
  *
  * If you want to secure a form submission against CSRF attacks, you could
- * use the class name of the form as page ID. This way you make sure that the
- * form can only be bound to pages that are designed to handle the form,
- * that is, that use the same class name to validate the CSRF token with
- * isCsrfTokenValid().
+ * supply an "intention" string. This way you make sure that the form can only
+ * be bound 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 <bernhard.schussek@symfony.com>
  */
 interface CsrfProviderInterface
 {
     /**
-     * Generates a CSRF token for a page of your application
+     * Generates a CSRF token for a page of your application.
      *
-     * @param string $pageId  Some value that identifies the page (for example,
-     *                        the class name of the form). Doesn't have to be
-     *                        a secret value.
+     * @param string $intention Some value that identifies the action intention
+     *                          (i.e. "authenticate"). Doesn't have to be a secret value.
      */
-    public function generateCsrfToken($pageId);
+    public function generateCsrfToken($intention);
 
     /**
-     * Validates a CSRF token
+     * Validates a CSRF token.
      *
-     * @param  string $pageId  The page ID 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
+     * @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($pageId, $token);
+    public function isCsrfTokenValid($intention, $token);
 }

+ 4 - 4
src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php

@@ -43,17 +43,17 @@ class DefaultCsrfProvider implements CsrfProviderInterface
     /**
      * {@inheritDoc}
      */
-    public function generateCsrfToken($pageId)
+    public function generateCsrfToken($intention)
     {
-        return sha1($this->secret.$pageId.$this->getSessionId());
+        return sha1($this->secret.$intention.$this->getSessionId());
     }
 
     /**
      * {@inheritDoc}
      */
-    public function isCsrfTokenValid($pageId, $token)
+    public function isCsrfTokenValid($intention, $token)
     {
-        return $token === $this->generateCsrfToken($pageId);
+        return $token === $this->generateCsrfToken($intention);
     }
 
     /**

+ 12 - 10
src/Symfony/Component/Form/Extension/Csrf/Type/CsrfType.php

@@ -30,26 +30,28 @@ class CsrfType extends AbstractType
     public function buildForm(FormBuilder $builder, array $options)
     {
         $csrfProvider = $options['csrf_provider'];
-        $pageId = $options['page_id'];
+        $intention = $options['intention'];
 
-        $builder
-        ->setData($csrfProvider->generateCsrfToken($pageId))
-        ->addValidator(new CallbackValidator(
-        function (FormInterface $form) use ($csrfProvider, $pageId) {
+        $validator = function (FormInterface $form) use ($csrfProvider, $intention)
+        {
             if ((!$form->hasParent() || $form->getParent()->isRoot())
-            && !$csrfProvider->isCsrfTokenValid($pageId, $form->getData())) {
+                && !$csrfProvider->isCsrfTokenValid($intention, $form->getData())) {
                 $form->addError(new FormError('The CSRF token is invalid. Please try to resubmit the form'));
-                $form->setData($csrfProvider->generateCsrfToken($pageId));
+                $form->setData($csrfProvider->generateCsrfToken($intention));
             }
-        }
-        ));
+        };
+
+        $builder
+            ->setData($csrfProvider->generateCsrfToken($intention))
+            ->addValidator(new CallbackValidator($validator))
+        ;
     }
 
     public function getDefaultOptions(array $options)
     {
         return array(
             'csrf_provider' => $this->csrfProvider,
-            'page_id' => null,
+            'intention' => null,
             'property_path' => false,
         );
     }

+ 2 - 2
src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php

@@ -30,7 +30,7 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
     public function buildForm(FormBuilder $builder, array $options)
     {
         if ($options['csrf_protection']) {
-            $csrfOptions = array('page_id' => $options['csrf_page_id']);
+            $csrfOptions = array('intention' => $options['intention']);
 
             if ($options['csrf_provider']) {
                 $csrfOptions['csrf_provider'] = $options['csrf_provider'];
@@ -58,7 +58,7 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
             'csrf_protection' => $this->enabled,
             'csrf_field_name' => $this->fieldName,
             'csrf_provider'   => null,
-            'csrf_page_id'    => get_class($this),
+            'intention'  => 'unknown',
         );
     }
 

+ 2 - 2
src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php

@@ -42,7 +42,7 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL
             'username_parameter' => '_username',
             'password_parameter' => '_password',
             'csrf_parameter'     => '_csrf_token',
-            'csrf_page_id'       => 'form_login',
+            'intention'          => 'authenticate',
             'post_only'          => true,
         ), $options), $successHandler, $failureHandler, $logger, $dispatcher);
 
@@ -65,7 +65,7 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL
         if (null !== $this->csrfProvider) {
             $csrfToken = $request->get($this->options['csrf_parameter']);
 
-            if (false === $this->csrfProvider->isCsrfTokenValid($this->options['csrf_page_id'], $csrfToken)) {
+            if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
                 throw new InvalidCsrfTokenException('Invalid CSRF token.');
             }
         }

+ 9 - 9
tests/Symfony/Tests/Component/Form/Extension/Csrf/Type/CsrfTypeTest.php

@@ -36,12 +36,12 @@ class CsrfTypeTest extends TypeTestCase
     {
         $this->provider->expects($this->once())
             ->method('generateCsrfToken')
-            ->with('%PAGE_ID%')
+            ->with('%INTENTION%')
             ->will($this->returnValue('token'));
 
         $form = $this->factory->create('csrf', null, array(
             'csrf_provider' => $this->provider,
-            'page_id' => '%PAGE_ID%'
+            'intention' => '%INTENTION%'
         ));
 
         $this->assertEquals('token', $form->getData());
@@ -51,12 +51,12 @@ class CsrfTypeTest extends TypeTestCase
     {
         $this->provider->expects($this->once())
             ->method('isCsrfTokenValid')
-            ->with('%PAGE_ID%', 'token')
+            ->with('%INTENTION%', 'token')
             ->will($this->returnValue(true));
 
         $form = $this->factory->create('csrf', null, array(
             'csrf_provider' => $this->provider,
-            'page_id' => '%PAGE_ID%'
+            'intention' => '%INTENTION%'
         ));
         $form->bind('token');
 
@@ -70,7 +70,7 @@ class CsrfTypeTest extends TypeTestCase
 
         $form = $this->factory->create('csrf', null, array(
             'csrf_provider' => $this->provider,
-            'page_id' => '%PAGE_ID%'
+            'intention' => '%INTENTION%'
         ));
         $form->setParent($this->getNonRootForm());
         $form->bind('token');
@@ -80,23 +80,23 @@ class CsrfTypeTest extends TypeTestCase
     {
         $this->provider->expects($this->at(0))
             ->method('generateCsrfToken')
-            ->with('%PAGE_ID%')
+            ->with('%INTENTION%')
             ->will($this->returnValue('token1'));
         $this->provider->expects($this->at(1))
             ->method('isCsrfTokenValid')
-            ->with('%PAGE_ID%', 'invalid')
+            ->with('%INTENTION%', 'invalid')
             ->will($this->returnValue(false));
 
         // The token is regenerated to avoid stalled tokens, for example when
         // the session ID changed
         $this->provider->expects($this->at(2))
             ->method('generateCsrfToken')
-            ->with('%PAGE_ID%')
+            ->with('%INTENTION%')
             ->will($this->returnValue('token2'));
 
         $form = $this->factory->create('csrf', null, array(
             'csrf_provider' => $this->provider,
-            'page_id' => '%PAGE_ID%'
+            'intention' => '%INTENTION%'
         ));
         $form->bind('invalid');