Merge branch '3.4'
* 3.4: Adding a shortcuts for the main security functionality [DI] Reference tagged services in config
This commit is contained in:
commit
3fde0f0644
@ -17,6 +17,8 @@ CHANGELOG
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
* Added new `security.helper` service that is an instance of `Symfony\Component\Security\Core\Security`
|
||||
and provides shortcuts for common security tasks.
|
||||
* Tagging voters with the `security.voter` tag without implementing the
|
||||
`VoterInterface` on the class is now deprecated and will be removed in 4.0.
|
||||
* [BC BREAK] `FirewallContext::getListeners()` now returns `\Traversable|array`
|
||||
|
@ -26,6 +26,19 @@
|
||||
</service>
|
||||
<service id="Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface" alias="security.token_storage" />
|
||||
|
||||
<service id="security.helper" class="Symfony\Component\Security\Core\Security">
|
||||
<argument type="service">
|
||||
<service class="Symfony\Component\DependencyInjection\ServiceLocator">
|
||||
<tag name="container.service_locator" />
|
||||
<argument type="collection">
|
||||
<argument key="security.token_storage" type="service" id="security.token_storage" />
|
||||
<argument key="security.authorization_checker" type="service" id="security.authorization_checker" />
|
||||
</argument>
|
||||
</service>
|
||||
</argument>
|
||||
</service>
|
||||
<service id="Symfony\Component\Security\Core\Security" alias="security.helper" />
|
||||
|
||||
<service id="security.user_value_resolver" class="Symfony\Bundle\SecurityBundle\SecurityUserValueResolver">
|
||||
<argument type="service" id="security.token_storage" />
|
||||
<tag name="controller.argument_value_resolver" priority="40" />
|
||||
|
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\SecurityBundle\Tests\Functional;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\User\User;
|
||||
|
||||
class SecurityTest extends WebTestCase
|
||||
{
|
||||
public function testServiceIsFunctional()
|
||||
{
|
||||
$kernel = self::createKernel(array('test_case' => 'SecurityHelper', 'root_config' => 'config.yml'));
|
||||
$kernel->boot();
|
||||
$container = $kernel->getContainer();
|
||||
|
||||
// put a token into the storage so the final calls can function
|
||||
$user = new User('foo', 'pass');
|
||||
$token = new UsernamePasswordToken($user, '', 'provider', array('ROLE_USER'));
|
||||
$container->get('security.token_storage')->setToken($token);
|
||||
|
||||
$security = $container->get('functional_test.security.helper');
|
||||
$this->assertTrue($security->isGranted('ROLE_USER'));
|
||||
$this->assertSame($token, $security->getToken());
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Bundle\TwigBundle\TwigBundle;
|
||||
use Symfony\Bundle\SecurityBundle\SecurityBundle;
|
||||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
||||
|
||||
return array(
|
||||
new FrameworkBundle(),
|
||||
new SecurityBundle(),
|
||||
new TwigBundle(),
|
||||
);
|
@ -0,0 +1,18 @@
|
||||
imports:
|
||||
- { resource: ./../config/default.yml }
|
||||
|
||||
services:
|
||||
# alias the service so we can access it in the tests
|
||||
functional_test.security.helper:
|
||||
alias: security.helper
|
||||
public: true
|
||||
|
||||
security:
|
||||
providers:
|
||||
in_memory:
|
||||
memory:
|
||||
users: []
|
||||
|
||||
firewalls:
|
||||
default:
|
||||
anonymous: ~
|
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Argument;
|
||||
|
||||
/**
|
||||
* Represents a collection of services found by tag name to lazily iterate over.
|
||||
*
|
||||
* @author Roland Franssen <franssen.roland@gmail.com>
|
||||
*/
|
||||
class TaggedIteratorArgument extends IteratorArgument
|
||||
{
|
||||
private $tag;
|
||||
|
||||
/**
|
||||
* @param string $tag
|
||||
*/
|
||||
public function __construct($tag)
|
||||
{
|
||||
parent::__construct(array());
|
||||
|
||||
$this->tag = (string) $tag;
|
||||
}
|
||||
|
||||
public function getTag()
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@ CHANGELOG
|
||||
* deprecated support for top-level anonymous services in XML
|
||||
* deprecated case insensitivity of parameter names
|
||||
* deprecated the `ResolveDefinitionTemplatesPass` class in favor of `ResolveChildDefinitionsPass`
|
||||
* added `TaggedIteratorArgument` with YAML (`!tagged foo`) and XML (`<service type="tagged"/>`) support
|
||||
|
||||
3.3.0
|
||||
-----
|
||||
|
@ -60,6 +60,7 @@ class PassConfig
|
||||
new AutowireRequiredMethodsPass(),
|
||||
new ResolveBindingsPass(),
|
||||
new AutowirePass(false),
|
||||
new ResolveTaggedIteratorArgumentPass(),
|
||||
new ResolveServiceSubscribersPass(),
|
||||
new ResolveReferencesToAliasesPass(),
|
||||
new ResolveInvalidReferencesPass(),
|
||||
|
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
|
||||
/**
|
||||
* Resolves all TaggedIteratorArgument arguments.
|
||||
*
|
||||
* @author Roland Franssen <franssen.roland@gmail.com>
|
||||
*/
|
||||
class ResolveTaggedIteratorArgumentPass extends AbstractRecursivePass
|
||||
{
|
||||
use PriorityTaggedServiceTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function processValue($value, $isRoot = false)
|
||||
{
|
||||
if (!$value instanceof TaggedIteratorArgument) {
|
||||
return parent::processValue($value, $isRoot);
|
||||
}
|
||||
|
||||
$value->setValues($this->findAndSortTaggedServices($value->getTag(), $this->container));
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection\Dumper;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
@ -291,6 +292,9 @@ class XmlDumper extends Dumper
|
||||
if (is_array($value)) {
|
||||
$element->setAttribute('type', 'collection');
|
||||
$this->convertParameters($value, $type, $element, 'key');
|
||||
} elseif ($value instanceof TaggedIteratorArgument) {
|
||||
$element->setAttribute('type', 'tagged');
|
||||
$element->setAttribute('tag', $value->getTag());
|
||||
} elseif ($value instanceof IteratorArgument) {
|
||||
$element->setAttribute('type', 'iterator');
|
||||
$this->convertParameters($value->getValues(), $type, $element, 'key');
|
||||
|
@ -19,6 +19,7 @@ use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Parameter;
|
||||
@ -255,6 +256,9 @@ class YamlDumper extends Dumper
|
||||
$value = $value->getValues()[0];
|
||||
}
|
||||
if ($value instanceof ArgumentInterface) {
|
||||
if ($value instanceof TaggedIteratorArgument) {
|
||||
return new TaggedValue('tagged', $value->getTag());
|
||||
}
|
||||
if ($value instanceof IteratorArgument) {
|
||||
$tag = 'iterator';
|
||||
} else {
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
@ -115,6 +116,18 @@ function iterator(array $values)
|
||||
return new IteratorArgument(AbstractConfigurator::processValue($values, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a lazy iterator by tag name.
|
||||
*
|
||||
* @param string $tag
|
||||
*
|
||||
* @return TaggedIteratorArgument
|
||||
*/
|
||||
function tagged($tag)
|
||||
{
|
||||
return new TaggedIteratorArgument($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an expression.
|
||||
*
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\DependencyInjection\Loader;
|
||||
|
||||
use Symfony\Component\Config\Util\XmlUtils;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
|
||||
@ -500,6 +501,12 @@ class XmlFileLoader extends FileLoader
|
||||
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="iterator" only accepts collections of type="service" references in "%s".', $name, $file));
|
||||
}
|
||||
break;
|
||||
case 'tagged':
|
||||
if (!$arg->getAttribute('tag')) {
|
||||
throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged" has no or empty "tag" attribute in "%s".', $name, $file));
|
||||
}
|
||||
$arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'));
|
||||
break;
|
||||
case 'string':
|
||||
$arguments[$key] = $arg->nodeValue;
|
||||
break;
|
||||
|
@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\Argument\BoundArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
@ -708,6 +709,13 @@ class YamlFileLoader extends FileLoader
|
||||
throw new InvalidArgumentException(sprintf('"!iterator" tag only accepts arrays of "@service" references in "%s".', $file));
|
||||
}
|
||||
}
|
||||
if ('tagged' === $value->getTag()) {
|
||||
if (!is_string($argument) || !$argument) {
|
||||
throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts non empty string in "%s".', $file));
|
||||
}
|
||||
|
||||
return new TaggedIteratorArgument($argument);
|
||||
}
|
||||
if ('service' === $value->getTag()) {
|
||||
if ($isParameter) {
|
||||
throw new InvalidArgumentException(sprintf('Using an anonymous service in a parameter is not allowed in "%s".', $file));
|
||||
|
@ -206,6 +206,7 @@
|
||||
<xsd:attribute name="key" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="on-invalid" type="invalid_sequence" />
|
||||
<xsd:attribute name="tag" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="bind" mixed="true">
|
||||
@ -230,6 +231,7 @@
|
||||
<xsd:attribute name="key" type="xsd:string" />
|
||||
<xsd:attribute name="index" type="xsd:integer" />
|
||||
<xsd:attribute name="on-invalid" type="invalid_sequence" />
|
||||
<xsd:attribute name="tag" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="call">
|
||||
@ -255,6 +257,7 @@
|
||||
<xsd:enumeration value="string" />
|
||||
<xsd:enumeration value="constant" />
|
||||
<xsd:enumeration value="iterator" />
|
||||
<xsd:enumeration value="tagged" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Compiler;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ResolveTaggedIteratorArgumentPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* @author Roland Franssen <franssen.roland@gmail.com>
|
||||
*/
|
||||
class ResolveTaggedIteratorArgumentPassTest extends TestCase
|
||||
{
|
||||
public function testProcess()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('a', 'stdClass')->addTag('foo');
|
||||
$container->register('b', 'stdClass')->addTag('foo', array('priority' => 20));
|
||||
$container->register('c', 'stdClass')->addTag('foo', array('priority' => 10));
|
||||
$container->register('d', 'stdClass')->setProperty('foos', new TaggedIteratorArgument('foo'));
|
||||
|
||||
(new ResolveTaggedIteratorArgumentPass())->process($container);
|
||||
|
||||
$properties = $container->getDefinition('d')->getProperties();
|
||||
$expected = new TaggedIteratorArgument('foo');
|
||||
$expected->setValues(array(new Reference('b'), new Reference('c'), new Reference('a')));
|
||||
$this->assertEquals($expected, $properties['foos']);
|
||||
}
|
||||
}
|
@ -5,9 +5,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
use App\BarService;
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$s = $c->services();
|
||||
$s->set(BarService::class)
|
||||
->args(array(inline('FooClass')));
|
||||
|
||||
};
|
||||
|
@ -5,7 +5,6 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
use App\BarService;
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$c->services()
|
||||
->set('bar', 'Class1')
|
||||
->set(BarService::class)
|
||||
@ -20,5 +19,4 @@ return function (ContainerConfigurator $c) {
|
||||
->parent('bar')
|
||||
->parent(BarService::class)
|
||||
;
|
||||
|
||||
};
|
||||
|
@ -5,7 +5,6 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo;
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$c->import('basic.php');
|
||||
|
||||
$s = $c->services()->defaults()
|
||||
@ -19,5 +18,4 @@ return function (ContainerConfigurator $c) {
|
||||
|
||||
$s->set(Foo::class)->args(array(ref('bar')))->public();
|
||||
$s->set('bar', Foo::class)->call('setFoo')->autoconfigure(false);
|
||||
|
||||
};
|
||||
|
@ -6,7 +6,6 @@ use App\FooService;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$s = $c->services();
|
||||
$s->instanceof(Prototype\Foo::class)
|
||||
->property('p', 0)
|
||||
@ -20,5 +19,4 @@ return function (ContainerConfigurator $c) {
|
||||
$s->load(Prototype::class.'\\', '../Prototype')->exclude('../Prototype/*/*');
|
||||
|
||||
$s->set('foo', FooService::class);
|
||||
|
||||
};
|
||||
|
@ -5,7 +5,6 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo;
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$c->parameters()
|
||||
('foo', 'Foo')
|
||||
('bar', 'Bar')
|
||||
@ -17,5 +16,4 @@ return function (ContainerConfigurator $c) {
|
||||
('bar', Foo::class)
|
||||
->call('setFoo')
|
||||
;
|
||||
|
||||
};
|
||||
|
@ -5,7 +5,6 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$di = $c->services()->defaults()
|
||||
->tag('baz');
|
||||
$di->load(Prototype::class.'\\', '../Prototype')
|
||||
@ -20,5 +19,4 @@ return function (ContainerConfigurator $c) {
|
||||
->parent('foo');
|
||||
$di->set('foo')->lazy()->abstract();
|
||||
$di->get(Prototype\Foo::class)->lazy(false);
|
||||
|
||||
};
|
||||
|
@ -9,7 +9,6 @@ require_once __DIR__.'/../includes/classes.php';
|
||||
require_once __DIR__.'/../includes/foo.php';
|
||||
|
||||
return function (ContainerConfigurator $c) {
|
||||
|
||||
$p = $c->parameters();
|
||||
$p->set('baz_class', 'BazClass');
|
||||
$p->set('foo_class', FooClass::class)
|
||||
@ -124,4 +123,11 @@ return function (ContainerConfigurator $c) {
|
||||
$s->set('bar2', 'stdClass');
|
||||
$s->set('BAR2', 'stdClass');
|
||||
|
||||
$s->set('tagged_iterator_foo', 'Bar')
|
||||
->private()
|
||||
->tag('foo');
|
||||
|
||||
$s->set('tagged_iterator', 'Bar')
|
||||
->public()
|
||||
->args(array(tagged('foo')));
|
||||
};
|
||||
|
@ -4,6 +4,7 @@ require_once __DIR__.'/../includes/classes.php';
|
||||
require_once __DIR__.'/../includes/foo.php';
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
@ -168,5 +169,15 @@ $container
|
||||
;
|
||||
$container->register('bar2', 'stdClass')->setPublic(true);
|
||||
$container->register('BAR2', 'stdClass')->setPublic(true);
|
||||
$container
|
||||
->register('tagged_iterator_foo', 'Bar')
|
||||
->addTag('foo')
|
||||
->setPublic(false)
|
||||
;
|
||||
$container
|
||||
->register('tagged_iterator', 'Bar')
|
||||
->addArgument(new TaggedIteratorArgument('foo'))
|
||||
->setPublic(true)
|
||||
;
|
||||
|
||||
return $container;
|
||||
|
@ -32,6 +32,8 @@ digraph sc {
|
||||
node_BAR [label="BAR\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
|
||||
node_bar2 [label="bar2\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
|
||||
node_BAR2 [label="BAR2\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"];
|
||||
node_tagged_iterator_foo [label="tagged_iterator_foo\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"];
|
||||
node_tagged_iterator [label="tagged_iterator\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"];
|
||||
node_foo2 [label="foo2\n\n", shape=record, fillcolor="#ff9999", style="filled"];
|
||||
node_foo3 [label="foo3\n\n", shape=record, fillcolor="#ff9999", style="filled"];
|
||||
node_foobaz [label="foobaz\n\n", shape=record, fillcolor="#ff9999", style="filled"];
|
||||
|
@ -266,6 +266,27 @@ use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
|
||||
|
||||
return $this->services['service_from_static_method'] = \Bar\FooClass::getInstance();
|
||||
|
||||
[Container%s/getTaggedIteratorService.php] => <?php
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
|
||||
|
||||
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
|
||||
// Returns the public 'tagged_iterator' shared service.
|
||||
|
||||
return $this->services['tagged_iterator'] = new \Bar(new RewindableGenerator(function () {
|
||||
yield 0 => ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->load(__DIR__.'/getFooService.php')) && false ?: '_'};
|
||||
yield 1 => ${($_ = isset($this->services['tagged_iterator_foo']) ? $this->services['tagged_iterator_foo'] : $this->services['tagged_iterator_foo'] = new \Bar()) && false ?: '_'};
|
||||
}, 2));
|
||||
|
||||
[Container%s/getTaggedIteratorFooService.php] => <?php
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
|
||||
|
||||
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
|
||||
// Returns the private 'tagged_iterator_foo' shared service.
|
||||
|
||||
return $this->services['tagged_iterator_foo'] = new \Bar();
|
||||
|
||||
[Container%s/Container.php] => <?php
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
|
||||
@ -326,6 +347,8 @@ class Container%s extends Container
|
||||
'method_call1' => __DIR__.'/getMethodCall1Service.php',
|
||||
'new_factory_service' => __DIR__.'/getNewFactoryServiceService.php',
|
||||
'service_from_static_method' => __DIR__.'/getServiceFromStaticMethodService.php',
|
||||
'tagged_iterator' => __DIR__.'/getTaggedIteratorService.php',
|
||||
'tagged_iterator_foo' => __DIR__.'/getTaggedIteratorFooService.php',
|
||||
);
|
||||
$this->aliases = array(
|
||||
'alias_for_alias' => 'foo',
|
||||
|
@ -52,6 +52,8 @@ class ProjectServiceContainer extends Container
|
||||
'method_call1' => 'getMethodCall1Service',
|
||||
'new_factory_service' => 'getNewFactoryServiceService',
|
||||
'service_from_static_method' => 'getServiceFromStaticMethodService',
|
||||
'tagged_iterator' => 'getTaggedIteratorService',
|
||||
'tagged_iterator_foo' => 'getTaggedIteratorFooService',
|
||||
);
|
||||
$this->aliases = array(
|
||||
'alias_for_alias' => 'foo',
|
||||
@ -372,6 +374,19 @@ class ProjectServiceContainer extends Container
|
||||
return $this->services['service_from_static_method'] = \Bar\FooClass::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the public 'tagged_iterator' shared service.
|
||||
*
|
||||
* @return \Bar
|
||||
*/
|
||||
protected function getTaggedIteratorService()
|
||||
{
|
||||
return $this->services['tagged_iterator'] = new \Bar(new RewindableGenerator(function () {
|
||||
yield 0 => ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'};
|
||||
yield 1 => ${($_ = isset($this->services['tagged_iterator_foo']) ? $this->services['tagged_iterator_foo'] : $this->services['tagged_iterator_foo'] = new \Bar()) && false ?: '_'};
|
||||
}, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the private 'factory_simple' shared service.
|
||||
*
|
||||
@ -386,6 +401,16 @@ class ProjectServiceContainer extends Container
|
||||
return $this->privates['factory_simple'] = new \SimpleFactoryClass('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the private 'tagged_iterator_foo' shared service.
|
||||
*
|
||||
* @return \Bar
|
||||
*/
|
||||
protected function getTaggedIteratorFooService()
|
||||
{
|
||||
return $this->services['tagged_iterator_foo'] = new \Bar();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -138,6 +138,12 @@
|
||||
</service>
|
||||
<service id="bar2" class="stdClass" public="true"/>
|
||||
<service id="BAR2" class="stdClass" public="true"/>
|
||||
<service id="tagged_iterator_foo" class="Bar" public="false">
|
||||
<tag name="foo"/>
|
||||
</service>
|
||||
<service id="tagged_iterator" class="Bar" public="true">
|
||||
<argument type="tagged" tag="foo"/>
|
||||
</service>
|
||||
<service id="Psr\Container\ContainerInterface" alias="service_container" public="false"/>
|
||||
<service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false"/>
|
||||
<service id="alias_for_foo" alias="foo" public="true"/>
|
||||
|
@ -155,6 +155,16 @@ services:
|
||||
alias_for_alias:
|
||||
alias: 'foo'
|
||||
public: true
|
||||
tagged_iterator_foo:
|
||||
class: Bar
|
||||
tags:
|
||||
- { name: foo }
|
||||
public: false
|
||||
tagged_iterator:
|
||||
class: Bar
|
||||
arguments:
|
||||
- !tagged foo
|
||||
public: true
|
||||
Psr\Container\ContainerInterface:
|
||||
alias: service_container
|
||||
public: false
|
||||
|
@ -15,6 +15,7 @@ CHANGELOG
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
* Added `getUser`, `getToken` and `isGranted` methods to `Security`.
|
||||
* added a `setToken()` method to the `SwitchUserEvent` class to allow to replace the created token while switching users
|
||||
when custom token generation is required by application.
|
||||
* Using voters that do not implement the `VoterInterface`is now deprecated in
|
||||
|
@ -11,10 +11,12 @@
|
||||
|
||||
namespace Symfony\Component\Security\Core;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* This class holds security information.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
* Helper class for commonly-needed security tasks.
|
||||
*/
|
||||
final class Security
|
||||
{
|
||||
@ -22,4 +24,50 @@ final class Security
|
||||
const AUTHENTICATION_ERROR = '_security.last_error';
|
||||
const LAST_USERNAME = '_security.last_username';
|
||||
const MAX_USERNAME_LENGTH = 4096;
|
||||
|
||||
private $container;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UserInterface|null
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
if (!$token = $this->getToken()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$user = $token->getUser();
|
||||
if (!is_object($user)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the attributes are granted against the current authentication token and optionally supplied subject.
|
||||
*
|
||||
* @param mixed $attributes
|
||||
* @param mixed $subject
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isGranted($attributes, $subject = null)
|
||||
{
|
||||
return $this->container->get('security.authorization_checker')
|
||||
->isGranted($attributes, $subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TokenInterface|null
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
return $this->container->get('security.token_storage')->getToken();
|
||||
}
|
||||
}
|
||||
|
97
src/Symfony/Component/Security/Core/Tests/SecurityTest.php
Normal file
97
src/Symfony/Component/Security/Core/Tests/SecurityTest.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Core\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Security\Core\User\User;
|
||||
|
||||
class SecurityTest extends TestCase
|
||||
{
|
||||
public function testGetToken()
|
||||
{
|
||||
$token = new UsernamePasswordToken('foo', 'bar', 'provider');
|
||||
$tokenStorage = $this->getMockBuilder(TokenStorageInterface::class)->getMock();
|
||||
|
||||
$tokenStorage->expects($this->once())
|
||||
->method('getToken')
|
||||
->will($this->returnValue($token));
|
||||
|
||||
$container = $this->createContainer('security.token_storage', $tokenStorage);
|
||||
|
||||
$security = new Security($container);
|
||||
$this->assertSame($token, $security->getToken());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getUserTests
|
||||
*/
|
||||
public function testGetUser($userInToken, $expectedUser)
|
||||
{
|
||||
$token = $this->getMockBuilder(TokenInterface::class)->getMock();
|
||||
$token->expects($this->any())
|
||||
->method('getUser')
|
||||
->will($this->returnValue($userInToken));
|
||||
$tokenStorage = $this->getMockBuilder(TokenStorageInterface::class)->getMock();
|
||||
|
||||
$tokenStorage->expects($this->once())
|
||||
->method('getToken')
|
||||
->will($this->returnValue($token));
|
||||
|
||||
$container = $this->createContainer('security.token_storage', $tokenStorage);
|
||||
|
||||
$security = new Security($container);
|
||||
$this->assertSame($expectedUser, $security->getUser());
|
||||
}
|
||||
|
||||
public function getUserTests()
|
||||
{
|
||||
yield array(null, null);
|
||||
|
||||
yield array('string_username', null);
|
||||
|
||||
$user = new User('nice_user', 'foo');
|
||||
yield array($user, $user);
|
||||
}
|
||||
|
||||
public function testIsGranted()
|
||||
{
|
||||
$authorizationChecker = $this->getMockBuilder(AuthorizationCheckerInterface::class)->getMock();
|
||||
|
||||
$authorizationChecker->expects($this->once())
|
||||
->method('isGranted')
|
||||
->with('SOME_ATTRIBUTE', 'SOME_SUBJECT')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$container = $this->createContainer('security.authorization_checker', $authorizationChecker);
|
||||
|
||||
$security = new Security($container);
|
||||
$this->assertTrue($security->isGranted('SOME_ATTRIBUTE', 'SOME_SUBJECT'));
|
||||
}
|
||||
|
||||
private function createContainer($serviceId, $serviceObject)
|
||||
{
|
||||
$container = $this->getMockBuilder(ContainerInterface::class)->getMock();
|
||||
|
||||
$container->expects($this->atLeastOnce())
|
||||
->method('get')
|
||||
->with($serviceId)
|
||||
->will($this->returnValue($serviceObject));
|
||||
|
||||
return $container;
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
"php": "^7.1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/container": "^1.0",
|
||||
"symfony/event-dispatcher": "~3.4|~4.0",
|
||||
"symfony/expression-language": "~3.4|~4.0",
|
||||
"symfony/http-foundation": "~3.4|~4.0",
|
||||
@ -27,6 +28,7 @@
|
||||
"psr/log": "~1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/container": "To instantiate the Security class",
|
||||
"symfony/event-dispatcher": "",
|
||||
"symfony/http-foundation": "",
|
||||
"symfony/validator": "For using the user password constraint",
|
||||
|
@ -29,6 +29,7 @@
|
||||
"symfony/security-http": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/container": "^1.0",
|
||||
"symfony/finder": "~3.4|~4.0",
|
||||
"symfony/polyfill-intl-icu": "~1.0",
|
||||
"symfony/routing": "~3.4|~4.0",
|
||||
@ -38,6 +39,7 @@
|
||||
"psr/log": "~1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/container": "To instantiate the Security class",
|
||||
"symfony/form": "",
|
||||
"symfony/validator": "For using the user password constraint",
|
||||
"symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs",
|
||||
|
Reference in New Issue
Block a user