Skip to content

Commit afd4983

Browse files
committed
[SecurityBundle] [FrameworkBundle] fix allow_if expression service generation
1 parent 4ebd60f commit afd4983

File tree

6 files changed

+107
-35
lines changed

6 files changed

+107
-35
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddExpressionLanguageProvidersPass.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ public function process(ContainerBuilder $container)
3636
}
3737

3838
// security
39-
if ($container->has('security.access.expression_voter')) {
40-
$definition = $container->findDefinition('security.access.expression_voter');
39+
if ($container->has('security.expression_language')) {
40+
$definition = $container->findDefinition('security.expression_language');
4141
foreach ($container->findTaggedServiceIds('security.expression_language_provider') as $id => $attributes) {
42-
$definition->addMethodCall('addExpressionLanguageProvider', array(new Reference($id)));
42+
$definition->addMethodCall('registerProvider', array(new Reference($id)));
4343
}
4444
}
4545
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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+
17+
/**
18+
* Parses expressions used in the security access_control configuration to make sure they are dumped as SerializedParsedExpression
19+
* This compiler pass must be registered after AddExpressionLanguageProvidersPass so custom functions can also be parsed.
20+
*
21+
* @author David Maicher <mail@dmaicher.de>
22+
*/
23+
class ParseSecurityExpressionsPass implements CompilerPassInterface
24+
{
25+
public function process(ContainerBuilder $container)
26+
{
27+
if (!$container->has('security.expression_language')) {
28+
return;
29+
}
30+
31+
$expressionLanguage = $container->get('security.expression_language');
32+
33+
foreach ($container->findTaggedServiceIds('security.expression.unparsed') as $id => $attributes) {
34+
$defition = $container->getDefinition($id);
35+
$defition
36+
->setClass('Symfony\Component\ExpressionLanguage\SerializedParsedExpression')
37+
->addArgument(serialize($expressionLanguage->parse($defition->getArgument(0), array('token', 'user', 'object', 'roles', 'request', 'trust_resolver'))->getNodes()))
38+
->setTags(array());
39+
}
40+
}
41+
}

src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass;
1717
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\FormPass;
1818
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\DataCollectorTranslatorPass;
19+
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ParseSecurityExpressionsPass;
1920
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingPass;
2021
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RoutingResolverPass;
2122
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass;
@@ -85,6 +86,7 @@ public function build(ContainerBuilder $container)
8586
$container->addCompilerPass(new AddCacheWarmerPass());
8687
$container->addCompilerPass(new AddCacheClearerPass());
8788
$container->addCompilerPass(new AddExpressionLanguageProvidersPass());
89+
$container->addCompilerPass(new ParseSecurityExpressionsPass()); // must be registered after AddExpressionLanguageProvidersPass
8890
$container->addCompilerPass(new TranslationExtractorPass());
8991
$container->addCompilerPass(new TranslationDumperPass());
9092
$container->addCompilerPass(new FragmentRendererPass(), PassConfig::TYPE_AFTER_REMOVING);

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddExpressionLanguageProvidersPassTest.php

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function testProcessForRouter()
2424
$container = new ContainerBuilder();
2525
$container->addCompilerPass(new AddExpressionLanguageProvidersPass());
2626

27-
$definition = new Definition('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\TestProvider');
27+
$definition = new Definition('\stdClass');
2828
$definition->addTag('routing.expression_language_provider');
2929
$container->setDefinition('some_routing_provider', $definition);
3030

@@ -43,7 +43,7 @@ public function testProcessForRouterAlias()
4343
$container = new ContainerBuilder();
4444
$container->addCompilerPass(new AddExpressionLanguageProvidersPass());
4545

46-
$definition = new Definition('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\TestProvider');
46+
$definition = new Definition('\stdClass');
4747
$definition->addTag('routing.expression_language_provider');
4848
$container->setDefinition('some_routing_provider', $definition);
4949

@@ -63,17 +63,16 @@ public function testProcessForSecurity()
6363
$container = new ContainerBuilder();
6464
$container->addCompilerPass(new AddExpressionLanguageProvidersPass());
6565

66-
$definition = new Definition('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\TestProvider');
66+
$definition = new Definition('\stdClass');
6767
$definition->addTag('security.expression_language_provider');
6868
$container->setDefinition('some_security_provider', $definition);
6969

70-
$container->register('security.access.expression_voter', '\stdClass');
70+
$container->register('security.expression_language', '\stdClass');
7171
$container->compile();
7272

73-
$router = $container->getDefinition('security.access.expression_voter');
74-
$calls = $router->getMethodCalls();
73+
$calls = $container->getDefinition('security.expression_language')->getMethodCalls();
7574
$this->assertCount(1, $calls);
76-
$this->assertEquals('addExpressionLanguageProvider', $calls[0][0]);
75+
$this->assertEquals('registerProvider', $calls[0][0]);
7776
$this->assertEquals(new Reference('some_security_provider'), $calls[0][1][0]);
7877
}
7978

@@ -82,22 +81,17 @@ public function testProcessForSecurityAlias()
8281
$container = new ContainerBuilder();
8382
$container->addCompilerPass(new AddExpressionLanguageProvidersPass());
8483

85-
$definition = new Definition('Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\TestProvider');
84+
$definition = new Definition('\stdClass');
8685
$definition->addTag('security.expression_language_provider');
8786
$container->setDefinition('some_security_provider', $definition);
8887

89-
$container->register('my_security.access.expression_voter', '\stdClass');
90-
$container->setAlias('security.access.expression_voter', 'my_security.access.expression_voter');
88+
$container->register('my.security.expression_language', '\stdClass');
89+
$container->setAlias('security.expression_language', 'my.security.expression_language');
9190
$container->compile();
9291

93-
$router = $container->getDefinition('my_security.access.expression_voter');
94-
$calls = $router->getMethodCalls();
92+
$calls = $container->getDefinition('my.security.expression_language')->getMethodCalls();
9593
$this->assertCount(1, $calls);
96-
$this->assertEquals('addExpressionLanguageProvider', $calls[0][0]);
94+
$this->assertEquals('registerProvider', $calls[0][0]);
9795
$this->assertEquals(new Reference('some_security_provider'), $calls[0][1][0]);
9896
}
9997
}
100-
101-
class TestProvider
102-
{
103-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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\ParseSecurityExpressionsPass;
16+
use Symfony\Component\DependencyInjection\ContainerBuilder;
17+
18+
class ParseSecurityExpressionsPassTest extends TestCase
19+
{
20+
public function testProcess()
21+
{
22+
$container = new ContainerBuilder();
23+
$container->addCompilerPass(new ParseSecurityExpressionsPass());
24+
$container->register('security.expression_language', 'Symfony\Component\Security\Core\Authorization\ExpressionLanguage');
25+
26+
$container->register('security.expression.one', 'Symfony\Component\ExpressionLanguage\Expression')
27+
->addArgument('true or false')
28+
->addTag('security.expression.unparsed');
29+
30+
$container->register('security.expression.two', 'Symfony\Component\ExpressionLanguage\Expression')
31+
->addArgument('false or true')
32+
->addTag('security.expression.unparsed');
33+
34+
$container->compile();
35+
36+
$expressionOne = $container->getDefinition('security.expression.one');
37+
$this->assertSame('Symfony\Component\ExpressionLanguage\SerializedParsedExpression', $expressionOne->getClass());
38+
$this->assertInstanceOf('Symfony\Component\ExpressionLanguage\Node\BinaryNode', unserialize($expressionOne->getArgument(1)));
39+
40+
$expressionTwo = $container->getDefinition('security.expression.one');
41+
$this->assertSame('Symfony\Component\ExpressionLanguage\SerializedParsedExpression', $expressionTwo->getClass());
42+
$this->assertInstanceOf('Symfony\Component\ExpressionLanguage\Node\BinaryNode', unserialize($expressionTwo->getArgument(1)));
43+
}
44+
}

src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ class SecurityExtension extends Extension
3838
private $listenerPositions = array('pre_auth', 'form', 'http', 'remember_me');
3939
private $factories = array();
4040
private $userProviderFactories = array();
41-
private $expressionLanguage;
4241

4342
public function __construct()
4443
{
@@ -589,11 +588,15 @@ private function createExpression($container, $expression)
589588
return $this->expressions[$id];
590589
}
591590

591+
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
592+
throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
593+
}
594+
592595
$container
593-
->register($id, 'Symfony\Component\ExpressionLanguage\SerializedParsedExpression')
596+
->register($id, 'Symfony\Component\ExpressionLanguage\Expression')
594597
->setPublic(false)
595598
->addArgument($expression)
596-
->addArgument(serialize($this->getExpressionLanguage()->parse($expression, array('token', 'user', 'object', 'roles', 'request', 'trust_resolver'))->getNodes()))
599+
->addTag('security.expression.unparsed')
597600
;
598601

599602
return $this->expressions[$id] = new Reference($id);
@@ -657,16 +660,4 @@ public function getConfiguration(array $config, ContainerBuilder $container)
657660
// first assemble the factories
658661
return new MainConfiguration($this->factories, $this->userProviderFactories);
659662
}
660-
661-
private function getExpressionLanguage()
662-
{
663-
if (null === $this->expressionLanguage) {
664-
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
665-
throw new \RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
666-
}
667-
$this->expressionLanguage = new ExpressionLanguage();
668-
}
669-
670-
return $this->expressionLanguage;
671-
}
672663
}

0 commit comments

Comments
 (0)