10000 [Form] Skip CSRF validation on form when POST max size is exceeded · symfony/symfony@289531f · GitHub
[go: up one dir, main page]

Skip to content

Commit 289531f

Browse files
jameshalsallfabpot
authored andcommitted
[Form] Skip CSRF validation on form when POST max size is exceeded
1 parent 4590759 commit 289531f

File tree

7 files changed

+58
-12
lines changed

7 files changed

+58
-12
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/form_csrf.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<argument>%form.type_extension.csrf.field_name%</argument>
1717
<argument type="service" id="translator.default" />
1818
<argument>%validator.translation_domain%</argument>
19+
<argument type="service" id="form.server_params" />
1920
</service>
2021
</services>
2122
</container>

src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Symfony\Component\Form\FormEvents;
1919
use Symfony\Component\Form\FormError;
2020
use Symfony\Component\Form\FormEvent;
21+
use Symfony\Component\Form\Util\ServerParams;
2122
use Symfony\Component\Security\Csrf\CsrfToken;
2223
use Symfony\Compo 8000 nent\Security\Csrf\CsrfTokenManagerInterface;
2324
use Symfony\Component\Translation\TranslatorInterface;
@@ -68,14 +69,19 @@ class CsrfValidationListener implements EventSubscriberInterface
6869
*/
6970
private $translationDomain;
7071

72+
/**
73+
* @var ServerParams
74+
*/
75+
private $serverParams;
76+
7177
public static function getSubscribedEvents()
7278
{
7379
return array(
7480
FormEvents::PRE_SUBMIT => 'preSubmit',
7581
);
7682
}
7783

78-
public function __construct($fieldName, $tokenManager, $tokenId, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null)
84+
public function __construct($fieldName, $tokenManager, $tokenId, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null, ServerParams $serverParams = null)
7985
{
8086
if ($tokenManager instanceof CsrfProviderInterface) {
8187
$tokenManager = new CsrfProviderAdapter($tokenManager);
@@ -89,13 +95,15 @@ public function __construct($fieldName, $tokenManager, $tokenId, $errorMessage,
8995
$this->errorMessage = $errorMessage;
9096
$this->translator = $translator;
9197
$this->translationDomain = $translationDomain;
98+
$this->serverParams = $serverParams ?: new ServerParams();
9299
}
93100

94101
public function preSubmit(FormEvent $event)
95102
{
96103
$form = $event->getForm();
104+
$postRequestSizeExceeded = $form->getConfig()->getMethod() === 'POST' && $this->serverParams->hasPostMaxSizeBeenExceeded();
97105

98-
if ($form->isRoot() && $form->getConfig()->getOption('compound')) {
106+
if ($form->isRoot() && $form->getConfig()->getOption('compound') && !$postRequestSizeExceeded) {
99107
$data = $event->getData();
100108

101109
if (!isset($data[$this->fieldName]) || !$this->tokenManager->isTokenValid(new CsrfToken($this->tokenId, $data[$this->fieldName]))) {

src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\Form\FormBuilderInterface;
2121
use Symfony\Component\Form\FormView;
2222
use Symfony\Component\Form\FormInterface;
23+
use Symfony\Component\Form\Util\ServerParams;
2324
use Symfony\Component\OptionsResolver\Options;
2425
use Symfony\Component\OptionsResolver\OptionsResolver;
2526
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
@@ -55,7 +56,12 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
5556
*/
5657
private $translationDomain;
5758

58-
public function __construct($defaultTokenManager, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null)
59+
/**
60+
* @var ServerParams
61+
*/
62+
private $serverParams;
63+
64+
public function __construct($defaultTokenManager, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null, ServerParams $serverParams = null)
5965
{
6066
if ($defaultTokenManager instanceof CsrfProviderInterface) {
6167
$defaultTokenManager = new CsrfProviderAdapter($defaultTokenManager);
@@ -68,6 +74,7 @@ public function __construct($defaultTokenManager, $defaultEnabled = true, $defau
6874
$this->defaultFieldName = $defaultFieldName;
6975
$this->translator = $translator;
7076
$this->translationDomain = $translationDomain;
77+
$this->serverParams = $serverParams;
7178
}
7279

7380
/**
@@ -89,7 +96,8 @@ public function buildForm(FormBuilderInterface $builder, array $options)
8996
$options['csrf_token_id'] ?: ($builder->getName() ?: get_class($builder->getType()->getInnerType())),
9097
$options['csrf_message'],
9198
$this->translator,
92-
$this->translationDomain
99+
$this->translationDomain,
100+
$this->serverParams
93101
))
94102
;
95103
}

src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,7 @@ public function handleRequest(FormInterface $form, $request = null)
7373
// Mark the form with an error if the uploaded size was too large
7474
// This is done here and not in FormValidator because $_POST is
7575
// empty when that error occurs. Hence the form is never submitted.
76-
$contentLength = $this->serverParams->getContentLength();
77-
$maxContentLength = $this->serverParams->getPostMaxSize();
78-
79-
if (!empty($maxContentLength) && $contentLength > $maxContentLength) {
76+
if ($this->serverParams->hasPostMaxSizeBeenExceeded()) {
8077
// Submit the form, but don't clear the default values
8178
$form->submit(null, false);
8279

src/Symfony/Component/Form/NativeRequestHandler.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,7 @@ public function handleRequest(FormInterface $form, $request = null)
8181
// Mark the form with an error if the uploaded size was too large
8282
// This is done here and not in FormValidator because $_POST is
8383
// empty when that error occurs. Hence the form is never submitted.
84-
$contentLength = $this->serverParams->getContentLength();
85-
$maxContentLength = $this->serverParams->getPostMaxSize();
86-
87-
if (!empty($maxContentLength) && $contentLength > $maxContentLength) {
84+
if ($this->serverParams->hasPostMaxSizeBeenExceeded()) {
8885
// Submit the form, but don't clear the default values
8986
$form->submit(null, false);
9087

src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\Form\Tests\Extension\Csrf\EventListener;
1313

14+
use Symfony\Component\Form\Form;
1415
use Symfony\Component\Form\FormBuilder;
1516
use Symfony\Component\Form\FormEvent;
1617
use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener;
@@ -72,4 +73,25 @@ public function testStringFormData()
7273
// Validate accordingly
7374
$this->assertSame($data, $event->getData());
7475
}
76+
77+
public function testMaxPostSizeExceeded()
78+
{
79+
$serverParams = $this
80+
->getMockBuilder('\Symfony\Component\Form\Util\ServerParams')
81+
->disableOriginalConstructor()
82+
->getMock()
83+
;
84+
85+
$serverParams
86+
->expects($this->once())
87+
->method('hasPostMaxSizeBeenExceeded')
88+
->willReturn(true)
89+
;
90+
91+
$event = new FormEvent($this->form, array('csrf' => 'token'));
92+
$validation = new CsrfValidationListener('csrf', $this->tokenManager, 'unknown', 'Error message', null, null, $serverParams);
93+
94+
$validation->preSubmit($event);
95+
$this->assertEmpty($this->form->getErrors());
96+
}
7597
}

src/Symfony/Component/Form/Util/ServerParams.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ public function __construct(RequestStack $requestStack = null)
2525
$this->requestStack = $requestStack;
2626
}
2727

28+
/**
29+
* Returns true if the POST max size has been exceeded in the request.
30+
*
31+
* @return bool
32+
*/
33+
public function hasPostMaxSizeBeenExceeded()
34+
{
35+
$contentLength = $this->getContentLength();
36+
$maxContentLength = $this->getPostMaxSize();
37+
38+
return $maxContentLength && $contentLength > $maxContentLength;
39+
}
40+
2841
/**
2942
* Returns maximum post size in bytes.
3043
*

0 commit comments

Comments
 (0)
0