Skip to content

Commit bf1e312

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

File tree

5 files changed

+48
-9
lines changed

5 files changed

+48
-9
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ public function load(array $configs, ContainerBuilder $container): void
615615
$container->registerForAutoconfiguration(DataCollectorInterface::class)
616616
->addTag('data_collector');
617617
$container->registerForAutoconfiguration(FormTypeInterface::class)
618-
->addTag('form.type');
618+
->addTag('form.type', ['csrf_token_id' => '%.form.type_extension.csrf.token_id%']);
619619
$container->registerForAutoconfiguration(FormTypeGuesserInterface::class)
620620
->addTag('form.type_guesser');
621621
$container->registerForAutoconfiguration(FormTypeExtensionInterface::class)
@@ -777,9 +777,7 @@ private function registerFormConfiguration(array $config, ContainerBuilder $cont
777777
$container->setParameter('form.type_extension.csrf.enabled', true);
778778
$container->setParameter('form.type_extension.csrf.field_name', $config['form']['csrf_protection']['field_name']);
779779
$container->setParameter('form.type_extension.csrf.field_attr', $config['form']['csrf_protection']['field_attr']);
780-
781-
$container->getDefinition('form.type_extension.csrf')
782-
->replaceArgument(7, $config['form']['csrf_protection']['token_id']);
780+
$container->setParameter('.form.type_extension.csrf.token_id', $config['form']['csrf_protection']['token_id']);
783781
} else {
784782
$container->setParameter('form.type_extension.csrf.enabled', false);
785783
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
param('validator.translation_domain'),
2525
service('form.server_params'),
2626
param('form.type_extension.csrf.field_attr'),
27-
abstract_arg('framework.form.csrf_protection.token_id'),
27+
param('.form.type_extension.csrf.token_id'),
2828
])
2929
->tag('form.type_extension')
3030
;

src/Symfony/Component/Form/DependencyInjection/FormPass.php

Lines changed: 13 additions & 0 deletions
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

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

Lines changed: 12 additions & 4 deletions
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([

src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php

Lines changed: 20 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy