Skip to content

Commit 0851189

Browse files
weaverryanRobin Chalas
authored andcommitted
Adding a shortcuts for the main security functionality
1 parent 250d56b commit 0851189

File tree

10 files changed

+240
-3
lines changed

10 files changed

+240
-3
lines changed

src/Symfony/Bundle/SecurityBundle/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ CHANGELOG
44
3.4.0
55
-----
66

7+
* Added new `security.helper` service that is an instance of `Symfony\Component\Security\Core\Security`
8+
and provides shortcuts for common security tasks.
79
* Tagging voters with the `security.voter` tag without implementing the
810
`VoterInterface` on the class is now deprecated and will be removed in 4.0.
911
* [BC BREAK] `FirewallContext::getListeners()` now returns `\Traversable|array`

src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@
2626
</service>
2727
<service id="Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface" alias="security.token_storage" />
2828

29+
<service id="security.helper" class="Symfony\Component\Security\Core\Security">
30+
<argument type="service">
31+
<service class="Symfony\Component\DependencyInjection\ServiceLocator">
32+
<tag name="container.service_locator" />
33+
<argument type="collection">
34+
<argument key="security.token_storage" type="service" id="security.token_storage" />
35+
<argument key="security.authorization_checker" type="service" id="security.authorization_checker" />
36+
</argument>
37+
</service>
38+
</argument>
39+
</service>
40+
<service id="Symfony\Component\Security\Core\Security" alias="security.helper" />
41+
2942
<service id="security.user_value_resolver" class="Symfony\Bundle\SecurityBundle\SecurityUserValueResolver">
3043
<argument type="service" id="security.token_storage" />
3144
<tag name="controller.argument_value_resolver" priority="40" />
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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\SecurityBundle\Tests\Functional;
13+
14+
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
15+
use Symfony\Component\Security\Core\User\User;
16+
17+
class SecurityTest extends WebTestCase
18+
{
19+
public function testServiceIsFunctional()
20+
{
21+
$kernel = self::createKernel(array('test_case' => 'SecurityHelper', 'root_config' => 'config.yml'));
22+
$kernel->boot();
23+
$container = $kernel->getContainer();
24+
25+
// put a token into the storage so the final calls can function
26+
$user = new User('foo', 'pass');
27+
$token = new UsernamePasswordToken($user, '', 'provider', array('ROLE_USER'));
28+
$container->get('security.token_storage')->setToken($token);
29+
30+
$security = $container->get('functional_test.security.helper');
31+
$this->assertTrue($security->isGranted('ROLE_USER'));
32+
$this->assertSame($token, $security->getToken());
33+
}
34+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
use Symfony\Bundle\TwigBundle\TwigBundle;
13+
use Symfony\Bundle\SecurityBundle\SecurityBundle;
14+
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
15+
16+
return array(
17+
new FrameworkBundle(),
18+
new SecurityBundle(),
19+
new TwigBundle(),
20+
);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
imports:
2+
- { resource: ./../config/default.yml }
3+
4+
services:
5+
# alias the service so we can access it in the tests
6+
functional_test.security.helper:
7+
alias: security.helper
8+
public: true
9+
10+
security:
11+
providers:
12+
in_memory:
13+
memory:
14+
users: []
15+
16+
firewalls:
17+
default:
18+
anonymous: ~

src/Symfony/Component/Security/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
3.4.0
55
-----
66

7+
* Added `getUser`, `getToken` and `isGranted` methods to `Security`.
78
* added a `setToken()` method to the `SwitchUserEvent` class to allow to replace the created token while switching users
89
when custom token generation is required by application.
910
* Using voters that do not implement the `VoterInterface`is now deprecated in

src/Symfony/Component/Security/Core/Security.php

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,63 @@
1111

1212
namespace Symfony\Component\Security\Core;
1313

14+
use Psr\Container\ContainerInterface;
15+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
16+
use Symfony\Component\Security\Core\User\UserInterface;
17+
1418
/**
15-
* This class holds security information.
16-
*
17-
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
19+
* Helper class for commonly-needed security tasks.
1820
*/
1921
final class Security
2022
{
2123
const ACCESS_DENIED_ERROR = '_security.403_error';
2224
const AUTHENTICATION_ERROR = '_security.last_error';
2325
const LAST_USERNAME = '_security.last_username';
2426
const MAX_USERNAME_LENGTH = 4096;
27+
28+
private $container;
29+
30+
public function __construct(ContainerInterface $container)
31+
{
32+
$this->container = $container;
33+
}
34+
35+
/**
36+
* @return UserInterface|null
37+
*/
38+
public function getUser()
39+
{
40+
if (!$token = $this->getToken()) {
41+
return null;
42+
}
43+
44+
$user = $token->getUser();
45+
if (!is_object($user)) {
46+
return null;
47+
}
48+
49+
return $user;
50+
}
51+
52+
/**
53+
* Checks if the attributes are granted against the current authentication token and optionally supplied subject.
54+
*
55+
* @param mixed $attributes
56+
* @param mixed $subject
57+
*
58+
* @return bool
59+
*/
60+
public function isGranted($attributes, $subject = null)
61+
{
62+
return $this->container->get('security.authorization_checker')
63+
->isGranted($attributes, $subject);
64+
}
65+
66+
/**
67+
* @return TokenInterface|null
68+
*/
69+
public function getToken()
70+
{
71+
return $this->container->get('security.token_storage')->getToken();
72+
}
2573
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
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\Component\Security\Core\Tests;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Psr\Container\ContainerInterface;
16+
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
17+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
18+
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
19+
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
20+
use Symfony\Component\Security\Core\Security;
21+
use Symfony\Component\Security\Core\User\User;
22+
23+
class SecurityTest extends TestCase
24+
{
25+
public function testGetToken()
26+
{
27+
$token = new UsernamePasswordToken('foo', 'bar', 'provider');
28+
$tokenStorage = $this->getMockBuilder(TokenStorageInterface::class)->getMock();
29+
30+
$tokenStorage->expects($this->once())
31+
->method('getToken')
32+
->will($this->returnValue($token));
33+
34+
$container = $this->createContainer('security.token_storage', $tokenStorage);
35+
36+
$security = new Security($container);
37+
$this->assertSame($token, $security->getToken());
38+
}
39+
40+
/**
41+
* @dataProvider getUserTests
42+
*/
43+
public function testGetUser($userInToken, $expectedUser)
44+
{
45+
$token = $this->getMockBuilder(TokenInterface::class)->getMock();
46+
$token->expects($this->any())
47+
->method('getUser')
48+
->will($this->returnValue($userInToken));
49+
$tokenStorage = $this->getMockBuilder(TokenStorageInterface::class)->getMock();
50+
51+
$tokenStorage->expects($this->once())
52+
->method('getToken')
53+
->will($this->returnValue($token));
54+
55+
$container = $this->createContainer('security.token_storage', $tokenStorage);
56+
57+
$security = new Security($container);
58+
$this->assertSame($expectedUser, $security->getUser());
59+
}
60+
61+
public function getUserTests()
62+
{
63+
yield array(null, null);
64+
65+
yield array('string_username', null);
66+
67+
$user = new User('nice_user', 'foo');
68+
yield array($user, $user);
69+
}
70+
71+
public function testIsGranted()
72+
{
73+
$authorizationChecker = $this->getMockBuilder(AuthorizationCheckerInterface::class)->getMock();
74+
75+
$authorizationChecker->expects($this->once())
76+
->method('isGranted')
77+
->with('SOME_ATTRIBUTE', 'SOME_SUBJECT')
78+
->will($this->returnValue(true));
79+
80+
$container = $this->createContainer('security.authorization_checker', $authorizationChecker);
81+
82+
$security = new Security($container);
83+
$this->assertTrue($security->isGranted('SOME_ATTRIBUTE', 'SOME_SUBJECT'));
84+
}
85+
86+
private function createContainer($serviceId, $serviceObject)
87+
{
88+
$container = $this->getMockBuilder(ContainerInterface::class)->getMock();
89+
90+
$container->expects($this->atLeastOnce())
91+
->method('get')
92+
->with($serviceId)
93+
->will($this->returnValue($serviceObject));
94+
95+
return $container;
96+
}
97+
}

src/Symfony/Component/Security/Core/composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"symfony/polyfill-php56": "~1.0"
2121
},
2222
"require-dev": {
23+
"psr/container": "^1.0",
2324
"symfony/event-dispatcher": "~2.8|~3.0|~4.0",
2425
"symfony/expression-language": "~2.8|~3.0|~4.0",
2526
"symfony/http-foundation": "~2.8|~3.0|~4.0",
@@ -28,6 +29,7 @@
2829
"psr/log": "~1.0"
2930
},
3031
"suggest": {
32+
"psr/container": "To instantiate the Security class",
3133
"symfony/event-dispatcher": "",
3234
"symfony/http-foundation": "",
3335
"symfony/validator": "For using the user password constraint",

src/Symfony/Component/Security/composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"symfony/security-http": "self.version"
3333
},
3434
"require-dev": {
35+
"psr/container": "^1.0",
3536
"symfony/finder": "~2.8|~3.0|~4.0",
3637
"symfony/polyfill-intl-icu": "~1.0",
3738
"symfony/routing": "~2.8|~3.0|~4.0",
@@ -41,6 +42,7 @@
4142
"psr/log": "~1.0"
4243
},
4344
"suggest": {
45+
"psr/container": "To instantiate the Security class",
4446
"symfony/form": "",
4547
"symfony/validator": "For using the user password constraint",
4648
"symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs",

0 commit comments

Comments
 (0)