8000 better errors when security deps are missing · symfony/symfony@56ee4aa · GitHub
[go: up one dir, main page]

Skip to content

Commit 56ee4aa

Browse files
committed
better errors when security deps are missing
1 parent 34d5f9e commit 56ee4aa

File tree

4 files changed

+185
-0
lines changed

4 files changed

+185
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
13+
14+
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
15+
use Symfony\Component\DependencyInjection\ContainerBuilder;
16+
use Symfony\Component\DependencyInjection\Exception\LogicException;
17+
18+
/**
19+
* @author Christian Flothmann <christian.flothmann@sensiolabs.de>
20+
*/
21+
class WorkflowGuardListenerPass implements CompilerPassInterface
22+
{
23+
/**
24+
* {@inheritdoc}
25+
*/
26+
public function process(ContainerBuilder $container)
27+
{
28+
if (!$container->hasParameter('workflow.has_guard_listeners')) {
29+
return;
30+
}
31+
32+
$container->getParameterBag()->remove('workflow.has_guard_listeners');
33+
34+
if (!$container->has('security.token_storage')) {
35+
throw new LogicException('The "security.token_storage" service is needed to be able to use the workflow guard listener.');
36+
}
37+
38+
if (!$container->has('security.authorization_checker')) {
39+
throw new LogicException('The "security.authorization_checker" service is needed to be able to use the workflow guard listener.');
40+
}
41+
42+
if (!$container->has('security.authentication.trust_resolver')) {
43+
throw new LogicException('The "security.authentication.trust_resolver" service is needed to be able to use the workflow guard listener.');
44+
}
45+
46+
if (!$container->has('security.role_hierarchy 8000 ')) {
47+
throw new LogicException('The "security.role_hierarchy" service is needed to be able to use the workflow guard listener.');
48+
}
49+
}
50+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface;
4747
use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
4848
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
49+
use Symfony\Component\Security\Core\Security;
4950
use Symfony\Component\Serializer\Encoder\CsvEncoder;
5051
use Symfony\Component\Serializer\Encoder\DecoderInterface;
5152
use Symfony\Component\Serializer\Encoder\EncoderInterface;
@@ -597,6 +598,10 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde
597598
throw new LogicException('Cannot guard workflows as the ExpressionLanguage component is not installed.');
598599
}
599600

601+
if (!class_exists(Security::class)) {
602+
throw new LogicException('Cannot guard workflows as the Security component is not installed.');
603+
}
604+
600605
$eventName = sprintf('workflow.%s.guard.%s', $name, $transitionName);
601606
$guard->addTag('kernel.event_listener', array('event' => $eventName, 'method' => 'onTransition'));
602607
$configuration[$eventName] = $config['guard'];
@@ -612,6 +617,7 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde
612617
));
613618

614619
$container->setDefinition(sprintf('%s.listener.guard', $workflowId), $guard);
620+
$container->setParameter('workflow.has_guard_listeners', true);
615621
}
616622
}
617623
}

src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationExtractorPass;
2929
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationDumperPass;
3030
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass;
31+
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\WorkflowGuardListenerPass;
3132
use Symfony\Component\Config\DependencyInjection\ConfigCachePass;
3233
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
3334
use Symfony\Component\HttpKernel\DependencyInjection\ControllerArgumentValueResolverPass;
@@ -109,6 +110,7 @@ public function build(ContainerBuilder $container)
109110
$this->addCompilerPassIfExists($container, ValidateWorkflowsPass::class);
110111
$container->addCompilerPass(new CachePoolClearerPass(), PassConfig::TYPE_AFTER_REMOVING);
111112
$this->addCompilerPassIfExists($container, FormPass::class);
113+
$container->addCompilerPass(new WorkflowGuardListenerPass());
112114

113115
if ($container->getParameter('kernel.debug')) {
114116
$container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\WorkflowGuardListenerPass;
16+
use Symfony\Component\DependencyInjection\ContainerBuilder;
17+
use Symfony\Component\DependencyInjection\Exception\LogicException;
18+
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
19+
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
20+
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
21+
use Symfony\Component\Security\Core\Role\RoleHierarchy;
22+
use Symfony\Component\Workflow\EventListener\GuardListener;
23+
24+
class WorkflowGuardListenerPassTest extends TestCase
25+
{
26+
private $container;
27+
private $compilerPass;
28+
29+
protected function setUp()
30+
{
31+
$this->container = new ContainerBuilder();
32+
$this->container->register('foo.listener.guard', GuardListener::class);
33+
$this->container->register('bar.listener.guard', GuardListener::class);
34+
$this->compilerPass = new WorkflowGuardListenerPass();
35+
}
36+
37+
public function testListenersAreNotRemovedIfParameterIsNotSet()
38+
{
39+
$this->compilerPass->process($this->container);
40+
41+
$this->assertTrue($this->container->hasDefinition('foo.listener.guard'));
42+
$this->assertTrue($this->container->hasDefinition('bar.listener.guard'));
43+
}
44+
45+
public function testParameterIsRemovedWhenThePassIsProcessed()
46+
{
47+
$this->container->setParameter('workflow.has_guard_listeners', array('foo.listener.guard', 'bar.listener.guard'));
48+
49+
try {
50+
$this->compilerPass->process($this->container);
51+
} catch (LogicException $e) {
52+
// Here, we are not interested in the exception handling. This is tested further down.
53+
}
54+
55+
$this->assertFalse($this->container->hasParameter('workflow.has_guard_listeners'));
56+
}
57+
58+
public function testListenersAreNotRemovedIfAllDependenciesArePresent()
59+
{
60+
$this->container->setParameter('workflow.has_guard_listeners', array('foo.listener.guard', 'bar.listener.guard'));
61+
$this->container->register('security.token_storage', TokenStorageInterface::class);
62+
$this->container->register('security.authorization_checker', AuthorizationCheckerInterface::class);
63+
$this->container->register('security.authentication.trust_resolver', AuthenticationTrustResolverInterface::class);
64+
$this->container->register('security.role_hierarchy', RoleHierarchy::class);
65+
66+
$this->compilerPass->process($this->container);
67+
68+
$this->assertTrue($this->container->hasDefinition('foo.listener.guard'));
69+
$this->assertTrue($this->container->hasDefinition('bar.listener.guard'));
70+
}
71+
72+
/**
73+
* @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException
74+
* @expectedExceptionMessage The "security.token_storage" service is needed to be able to use the workflow guard listener.
75+
*/
76+
public function testListenersAreRemovedIfTheTokenStorageServiceIsNotPresent()
77+
{
78+
$this->container->setParameter('workflow.has_guard_listeners', array('foo.listener.guard', 'bar.listener.guard'));
79+
$this->container->register('security.authorization_checker', AuthorizationCheckerInterface::class);
80+
$this->container->register('security.authentication.trust_resolver', AuthenticationTrustResolverInterface::class);
81+
$this->container->register('security.role_hierarchy', RoleHierarchy::class);
82+
83+
$this->compilerPass->process($this->container);
84+
}
85+
86+
/**
87+
* @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException
88+
* @expectedExceptionMessage The "security.authorization_checker" service is needed to be able to use the workflow guard listener.
89+
*/
90+
public function testListenersAreRemovedIfTheAuthorizationCheckerServiceIsNotPresent()
91+
{
92+
$this->container->setParameter('workflow.has_guard_listeners', array('foo.listener.guard', 'bar.listener.guard'));
93+
$this->container->register('security.token_storage', TokenStorageInterface::class);
94+
$this->container->register('security.authentication.trust_resolver', AuthenticationTrustResolverInterface::class);
95+
$this->container->register('security.role_hierarchy', RoleHierarchy::class);
96+
97+
$this->compilerPass->process($this->container);
98+
}
99+
100+
/**
101+
* @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException
102+
* @expectedExceptionMessage The "security.authentication.trust_resolver" service is needed to be able to use the workflow guard listener.
103+
*/
104+
public function testListenersAreRemovedIfTheAuthenticationTrustResolverServiceIsNotPresent()
105+
{
106+
$this->container->setParameter('workflow.has_guard_listeners', array('foo.listener.guard', 'bar.listener.guard'));
107+
$this->container->register('security.token_storage', TokenStorageInterface::class);
108+
$this->container->register('security.authorization_checker', AuthorizationCheckerInterface::class);
109+
$this->container->register('security.role_hierarchy', RoleHierarchy::class);
110+
111+
$this->compilerPass->process($this->container);
112+
}
113+
114+
/**
115+
* @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException
116+
* @expectedExceptionMessage The "security.role_hierarchy" service is needed to be able to use the workflow guard listener.
117+
*/
118+
public function testListenersAreRemovedIfTheRoleHierarchyServiceIsNotPresent()
119+
{
120+
$this->container->setParameter('workflow.has_guard_listeners', array('foo.listener.guard', 'bar.listener.guard'));
121+
$this->container->register('security.token_storage', TokenStorageInterface::class);
122+
$this->container->register('security.authorization_checker', AuthorizationCheckerInterface::class);
123+
$this->container->register('security.authentication.trust_resolver', AuthenticationTrustResolverInterface::class);
124+
125+
$this->compilerPass->process($this->container);
126+
}
127+
}

0 commit comments

Comments
 (0)
0