Skip to content

Commit be700ae

Browse files
Merge branch '2.8' into 3.4
* 2.8: [VarDumper] Fix dumping ArrayObject and ArrayIterator instances Fix bad method call with guard authentication + session migration
2 parents 56f5d83 + 2627c16 commit be700ae

File tree

9 files changed

+143
-31
lines changed

9 files changed

+143
-31
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class SecurityExtension extends Extension
4545
private $userProviderFactories = array();
4646
private $expressionLanguage;
4747
private $logoutOnUserChangeByContextKey = array();
48+
private $statelessFirewallKeys = array();
4849

4950
public function __construct()
5051
{
@@ -115,6 +116,9 @@ public function load(array $configs, ContainerBuilder $container)
115116
$this->createAuthorization($config, $container);
116117
$this->createRoleHierarchy($config, $container);
117118

119+
$container->getDefinition('security.authentication.guard_handler')
120+
->replaceArgument(2, $this->statelessFirewallKeys);
121+
118122
if ($config['encoders']) {
119123
$this->createEncoders($config['encoders'], $container);
120124
}
@@ -379,6 +383,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a
379383
$listeners[] = new Reference($this->createContextListener($container, $contextKey, $logoutOnUserChange));
380384
$sessionStrategyId = 'security.authentication.session_strategy';
381385
} else {
386+
$this->statelessFirewallKeys[] = $id;
382387
$sessionStrategyId = 'security.authentication.session_strategy_noop';
383388
}
384389
$container->setAlias(new Alias('security.authentication.session_strategy.'.$id, false), $sessionStrategyId);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
>
1313
<argument type="service" id="security.token_storage" />
1414
<argument type="service" id="event_dispatcher" on-invalid="null" />
15+
<argument /> <!-- stateless firewall keys -->
16+
<call method="setSessionAuthenticationStrategy">
17+
<argument type="service" id="security.authentication.session_strategy" />
18+
</call>
1519
</service>
1620

1721
<service id="Symfony\Component\Security\Guard\GuardAuthenticatorHandler" alias="security.authentication.guard_handler" />

src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,35 @@ public function testDisableRoleHierarchyVoter()
123123
$this->assertFalse($container->hasDefinition('security.access.role_hierarchy_voter'));
124124
}
125125

126+
public function testGuardHandlerIsPassedStatelessFirewalls()
127+
{
128+
$container = $this->getRawContainer();
129+
130+
$container->loadFromExtension('security', array(
131+
'providers' => array(
132+
'default' => array('id' => 'foo'),
133+
),
134+
135+
'firewalls' => array(
136+
'some_firewall' => array(
137+
'pattern' => '^/admin',
138+
'http_basic' => null,
139+
'logout_on_user_change' => true,
140+
),
141+
'stateless_firewall' => array(
142+
'pattern' => '/.*',
143+
'stateless' => true,
144+
'http_basic' => null,
145+
'logout_on_user_change' => true,
146+
),
147+
),
148+
));
149+
150+
$container->compile();
151+
$definition = $container->getDefinition('security.authentication.guard_handler');
152+
$this->assertSame(array('stateless_firewall'), $definition->getArgument(2));
153+
}
154+
126155
/**
127156
* @group legacy
128157
* @expectedDeprecation Not setting "logout_on_user_change" to true on firewall "some_firewall" is deprecated as of 3.4, it will always be true in 4.0.

src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ private function executeGuardAuthenticator($uniqueGuardKey, GuardAuthenticatorIn
147147
}
148148

149149
// sets the token on the token storage, etc
150-
$this->guardHandler->authenticateWithToken($token, $request);
150+
$this->guardHandler->authenticateWithToken($token, $request, $this->providerKey);
151151
} catch (AuthenticationException $e) {
152152
// oh no! Authentication failed!
153153

src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,28 @@ class GuardAuthenticatorHandler
3737
private $tokenStorage;
3838
private $dispatcher;
3939
private $sessionStrategy;
40+
private $statelessProviderKeys;
4041

41-
public function __construct(TokenStorageInterface $tokenStorage, EventDispatcherInterface $eventDispatcher = null)
42+
/**
43+
* @param array $statelessProviderKeys An array of provider/firewall keys that are "stateless" and so do not need the session migrated on success
44+
*/
45+
public function __construct(TokenStorageInterface $tokenStorage, EventDispatcherInterface $eventDispatcher = null, array $statelessProviderKeys = array())
4246
{
4347
$this->tokenStorage = $tokenStorage;
4448
$this->dispatcher = $eventDispatcher;
49+
$this->statelessProviderKeys = $statelessProviderKeys;
4550
}
4651

4752
/**
4853
* Authenticates the given token in the system.
54+
*
55+
* @param string $providerKey The name of the provider/firewall being used for authentication
4956
*/
50-
public function authenticateWithToken(TokenInterface $token, Request $request)
57+
public function authenticateWithToken(TokenInterface $token, Request $request/*, string $providerKey */)
5158
{
52-
$this->migrateSession($request, $token);
59+
$providerKey = \func_num_args() > 2 ? func_get_arg(2) : null;
60+
61+
$this->migrateSession($request, $token, $providerKey);
5362
$this->tokenStorage->setToken($token);
5463

5564
if (null !== $this->dispatcher) {
@@ -100,7 +109,7 @@ public function authenticateUserAndHandleSuccess(UserInterface $user, Request $r
100109
// create an authenticated token for the User
101110
$token = $authenticator->createAuthenticatedToken($user, $providerKey);
102111
// authenticate this in the system
103-
$this->authenticateWithToken($token, $request);
112+
$this->authenticateWithToken($token, $request, $providerKey);
104113

105114
// return the success metric
106115
return $this->handleAuthenticationSuccess($token, $request, $authenticator, $providerKey);
@@ -142,9 +151,9 @@ public function setSessionAuthenticationStrategy(SessionAuthenticationStrategyIn
142151
$this->sessionStrategy = $sessionStrategy;
143152
}
144153

145-
private function migrateSession(Request $request, TokenInterface $token)
154+
private function migrateSession(Request $request, TokenInterface $token, $providerKey)
146155
{
147-
if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession()) {
156+
if (!$this->sessionStrategy || !$request->hasSession() || !$request->hasPreviousSession() || \in_array($providerKey, $this->statelessProviderKeys, true)) {
148157
return;
149158
}
150159

src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,18 @@ public function testSessionStrategyIsCalled()
144144
$handler->authenticateWithToken($this->token, $this->request);
145145
}
146146

147+
public function testSessionStrategyIsNotCalledWhenStateless()
148+
{
149+
$this->configurePreviousSession();
150+
151+
$this->sessionStrategy->expects($this->never())
152+
->method('onAuthentication');
153+
154+
$handler = new GuardAuthenticatorHandler($this->tokenStorage, $this->dispatcher, array('some_provider_key'));
155+
$handler->setSessionAuthenticationStrategy($this->sessionStrategy);
156+
$handler->authenticateWithToken($this->token, $this->request, 'some_provider_key');
157+
}
158+
147159
protected function setUp()
148160
{
149161
$this->tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock();

src/Symfony/Component/VarDumper/Caster/SplCaster.php

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,30 +29,12 @@ class SplCaster
2929

3030
public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, $isNested)
3131
{
32-
$prefix = Caster::PREFIX_VIRTUAL;
33-
$class = $stub->class;
34-
$flags = $c->getFlags();
35-
36-
$b = array(
37-
$prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST),
38-
$prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS),
39-
$prefix.'iteratorClass' => new ClassStub($c->getIteratorClass()),
40-
$prefix.'storage' => $c->getArrayCopy(),
41-
);
42-
43-
if ('ArrayObject' === $class) {
44-
$a = $b;
45-
} else {
46-
if (!($flags & \ArrayObject::STD_PROP_LIST)) {
47-
$c->setFlags(\ArrayObject::STD_PROP_LIST);
48-
$a = Caster::castObject($c, $class);
49-
$c->setFlags($flags);
50-
}
51-
52-
$a += $b;
53-
}
32+
return self::castSplArray($c, $a, $stub, $isNested);
33+
}
5434

55-
return $a;
35+
public static function castArrayIterator(\ArrayIterator $c, array $a, Stub $stub, $isNested)
36+
{
37+
return self::castSplArray($c, $a, $stub, $isNested);
5638
}
5739

5840
public static function castHeap(\Iterator $c, array $a, Stub $stub, $isNested)
@@ -186,7 +168,7 @@ public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $s
186168

187169
$clone = clone $c;
188170
foreach ($clone as $obj) {
189-
$storage[spl_object_hash($obj)] = array(
171+
$storage[] = array(
190172
'object' => $obj,
191173
'info' => $clone->getInfo(),
192174
);
@@ -205,4 +187,27 @@ public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub
205187

206188
return $a;
207189
}
190+
191+
private static function castSplArray($c, array $a, Stub $stub, $isNested)
192+
{
193+
$prefix = Caster::PREFIX_VIRTUAL;
194+
$class = $stub->class;
195+
$flags = $c->getFlags();
196+
197+
if (!($flags & \ArrayObject::STD_PROP_LIST)) {
198+
$c->setFlags(\ArrayObject::STD_PROP_LIST);
199+
$a = Caster::castObject($c, $class);
200+
$c->setFlags($flags);
201+
}
202+
$a += array(
203+
$prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST),
204+
$prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS),
205+
);
206+
if ($c instanceof \ArrayObject) {
207+
$a[$prefix.'iteratorClass'] = new ClassStub($c->getIteratorClass());
208+
}
209+
$a[$prefix.'storage'] = $c->getArrayCopy();
210+
211+
return $a;
212+
}
208213
}

src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ abstract class AbstractCloner implements ClonerInterface
9595
'AMQPEnvelope' => array('Symfony\Component\VarDumper\Caster\AmqpCaster', 'castEnvelope'),
9696

9797
'ArrayObject' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayObject'),
98+
'ArrayIterator' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayIterator'),
9899
'SplDoublyLinkedList' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castDoublyLinkedList'),
99100
'SplFileInfo' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castFileInfo'),
100101
'SplFileObject' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castFileObject'),

src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,51 @@ public function testCastObjectStorageDumpsInfo()
163163

164164
$this->assertDumpMatchesFormat('%ADateTime%A', $var);
165165
}
166+
167+
public function testCastArrayObject()
168+
{
169+
if (\defined('HHVM_VERSION')) {
170+
$this->markTestSkipped('HHVM as different internal details.');
171+
}
172+
$var = new \ArrayObject(array(123));
173+
$var->foo = 234;
174+
175+
$expected = <<<EOTXT
176+
ArrayObject {
177+
+"foo": 234
178+
flag::STD_PROP_LIST: false
179+
flag::ARRAY_AS_PROPS: false
180+
iteratorClass: "ArrayIterator"
181+
storage: array:1 [
182+
0 => 123
183+
]
184+
}
185+
EOTXT;
186+
$this->assertDumpEquals($expected, $var);
187+
}
188+
189+
public function testArrayIterator()
190+
{
191+
if (\defined('HHVM_VERSION')) {
192+
$this->markTestSkipped('HHVM as different internal details.');
193+
}
194+
$var = new MyArrayIterator(array(234));
195+
196+
$expected = <<<EOTXT
197+
Symfony\Component\VarDumper\Tests\Caster\MyArrayIterator {
198+
-foo: 123
199+
flag::STD_PROP_LIST: false
200+
flag::ARRAY_AS_PROPS: false
201+
storage: array:1 [
202+
0 => 234
203+
]
204+
}
205+
EOTXT;
206+
$this->assertDumpEquals($expected, $var);
207+
}
208+
}
209+
210+
class MyArrayIterator extends \ArrayIterator
211+
{
212+
private $foo = 123;
166213
}

0 commit comments

Comments
 (0)