Skip to content

Commit 7209804

Browse files
[Form][FrameworkBundle] Use auto-configuration to make the default CSRF token id apply only to the app; not to bundles
1 parent 092a893 commit 7209804

File tree

3 files changed

+45
-4
lines changed

3 files changed

+45
-4
lines changed

DependencyInjection/FormPass.php

+13
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,18 @@ private function processFormTypes(ContainerBuilder $container): Reference
4747
// Get service locator argument
4848
$servicesMap = [];
4949
$namespaces = ['Symfony\Component\Form\Extension\Core\Type' => true];
50+
$csrfTokenIds = [];
5051

5152
// Builds an array with fully-qualified type class names as keys and service IDs as values
5253
foreach ($container->findTaggedServiceIds('form.type', true) as $serviceId => $tag) {
5354
// Add form type service to the service locator
5455
$serviceDefinition = $container->getDefinition($serviceId);
5556
$servicesMap[$formType = $serviceDefinition->getClass()] = new Reference($serviceId);
5657
$namespaces[substr($formType, 0, strrpos($formType, '\\'))] = true;
58+
59+
if (isset($tag[0]['csrf_token_id'])) {
60+
$csrfTokenIds[$formType] = $tag[0]['csrf_token_id'];
61+
}
5762
}
5863

5964
if ($container->hasDefinition('console.command.form_debug')) {
@@ -62,6 +67,14 @@ private function processFormTypes(ContainerBuilder $container): Reference
6267
$commandDefinition->setArgument(2, array_keys($servicesMap));
6368
}
6469

70+
if ($csrfTokenIds && $container->hasDefinition('form.type_extension.csrf')) {
71+
$csrfExtension = $container->getDefinition('form.type_extension.csrf');
72+
73+
if (8 <= \count($csrfExtension->getArguments())) {
74+
$csrfExtension->replaceArgument(7, $csrfTokenIds);
75+
}
76+
}
77+
6578
return ServiceLocatorTagPass::register($container, $servicesMap);
6679
}
6780

Extension/Csrf/Type/FormTypeCsrfExtension.php

+12-4
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public function __construct(
3737
private ?string $translationDomain = null,
3838
private ?ServerParams $serverParams = null,
3939
private array $fieldAttr = [],
40-
private ?string $defaultTokenId = null,
40+
private string|array|null $defaultTokenId = null,
4141
) {
4242
}
4343

@@ -50,11 +50,17 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
5050
return;
5151
}
5252

53+
$csrfTokenId = $options['csrf_token_id']
54+
?: $this->defaultTokenId[$builder->getType()->getInnerType()::class]
55+
?? $builder->getName()
56+
?: $builder->getType()->getInnerType()::class;
57+
$builder->setAttribute('csrf_token_id', $csrfTokenId);
58+
5359
$builder
5460
->addEventSubscriber(new CsrfValidationListener(
5561
$options['csrf_field_name'],
5662
$options['csrf_token_manager'],
57-
$options['csrf_token_id'] ?: ($builder->getName() ?: $builder->getType()->getInnerType()::class),
63+
$csrfTokenId,
5864
$options['csrf_message'],
5965
$this->translator,
6066
$this->translationDomain,
@@ -70,7 +76,7 @@ public function finishView(FormView $view, FormInterface $form, array $options):
7076
{
7177
if ($options['csrf_protection'] && !$view->parent && $options['compound']) {
7278
$factory = $form->getConfig()->getFormFactory();
73-
$tokenId = $options['csrf_token_id'] ?: ($form->getName() ?: $form->getConfig()->getType()->getInnerType()::class);
79+
$tokenId = $form->getConfig()->getAttribute('csrf_token_id');
7480
$data = (string) $options['csrf_token_manager']->getToken($tokenId);
7581

7682
$csrfForm = $factory->createNamed($options['csrf_field_name'], HiddenType::class, $data, [
@@ -85,9 +91,11 @@ public function finishView(FormView $view, FormInterface $form, array $options):
8591

8692
public function configureOptions(OptionsResolver $resolver): void
8793
{
88-
if ($defaultTokenId = $this->defaultTokenId) {
94+
if (\is_string($defaultTokenId = $this->defaultTokenId) && $defaultTokenId) {
8995
$defaultTokenManager = $this->defaultTokenManager;
9096
$defaultTokenId = static fn (Options $options) => $options['csrf_token_manager'] === $defaultTokenManager ? $defaultTokenId : null;
97+
} else {
98+
$defaultTokenId = null;
9199
}
92100

93101
$resolver->setDefaults([

Tests/DependencyInjection/FormPassTest.php

+20
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Symfony\Component\Form\AbstractTypeExtension;
2222
use Symfony\Component\Form\Command\DebugCommand;
2323
use Symfony\Component\Form\DependencyInjection\FormPass;
24+
use Symfony\Component\Form\Extension\Csrf\Type\FormTypeCsrfExtension;
2425
use Symfony\Component\Form\FormRegistry;
2526

2627
/**
@@ -95,6 +96,25 @@ public function testAddTaggedTypesToDebugCommand()
9596
);
9697
}
9798

99+
public function testAddTaggedTypesToCsrfTypeExtension()
100+
{
101+
$container = $this->createContainerBuilder();
102+
103+
$container->register('form.registry', FormRegistry::class);
104+
$container->register('form.type_extension.csrf', FormTypeCsrfExtension::class)
105+
->setArguments([null, true, '_token', null, 'validator.translation_domain', null, [], null])
106+
->setPublic(true);
107+
108+
$container->setDefinition('form.extension', $this->createExtensionDefinition());
109+
$container->register('my.type1', __CLASS__.'_Type1')->addTag('form.type', ['csrf_token_id' => 'the_token_id']);
110+
$container->register('my.type2', __CLASS__.'_Type2')->addTag('form.type');
111+
112+
$container->compile();
113+
114+
$csrfDefinition = $container->getDefinition('form.type_extension.csrf');
115+
$this->assertSame([__CLASS__.'_Type1' => 'the_token_id'], $csrfDefinition->getArgument(7));
116+
}
117+
98118
/**
99119
* @dataProvider addTaggedTypeExtensionsDataProvider
100120
*/

0 commit comments

Comments
 (0)