Skip to content
This repository was archived by the owner on May 31, 2024. It is now read-only.

Commit d4487cf

Browse files
committed
Merge branch '3.3' into 3.4
* 3.3: [Serializer] Fixed throwing exception with option JSON_PARTIAL_OUTPUT_ON_ERROR Tweaked some styles in the profiler tables Add type string to docblock for Process::setInput() [Security] Fail gracefully if the security token cannot be unserialized from the session [Form] AbstractLayoutTest - fix DOMDocument casing Run simple-phpunit with --no-suggest option [FrameworkBundle] Fix using "annotations.cached_reader" in after-removing passes bumped Symfony version to 3.3.16 updated VERSION for 3.3.15 updated CHANGELOG for 3.3.15 bumped Symfony version to 2.8.34 updated VERSION for 2.8.33 updated CHANGELOG for 2.8.33 bumped Symfony version to 2.7.41 updated VERSION for 2.7.40 update CONTRIBUTORS for 2.7.40 updated CHANGELOG for 2.7.40
2 parents ae1621e + 9e15cb9 commit d4487cf

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

Http/Firewall/ContextListener.php

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ class ContextListener implements ListenerInterface
4545
private $trustResolver;
4646
private $logoutOnUserChange = false;
4747

48+
private static $unserializeExceptionCode = 0x37313bc;
49+
4850
/**
4951
* @param TokenStorageInterface $tokenStorage
5052
* @param iterable|UserProviderInterface[] $userProviders
@@ -96,7 +98,7 @@ public function handle(GetResponseEvent $event)
9698
return;
9799
}
98100

99-
$token = unserialize($token);
101+
$token = $this->safelyUnserialize($token);
100102

101103
if (null !== $this->logger) {
102104
$this->logger->debug('Read existing security token from the session.', array(
@@ -219,4 +221,43 @@ protected function refreshUser(TokenInterface $token)
219221

220222
throw new \RuntimeException(sprintf('There is no user provider for user "%s".', get_class($user)));
221223
}
224+
225+
private function safelyUnserialize($serializedToken)
226+
{
227+
$e = $token = null;
228+
$prevUnserializeHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback');
229+
$prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = array()) use (&$prevErrorHandler) {
230+
if (__FILE__ === $file) {
231+
throw new \UnexpectedValueException($msg, self::$unserializeExceptionCode);
232+
}
233+
234+
return $prevErrorHandler ? $prevErrorHandler($type, $msg, $file, $line, $context) : false;
235+
});
236+
237+
try {
238+
$token = unserialize($serializedToken);
239+
} catch (\Error $e) {
240+
} catch (\Exception $e) {
241+
}
242+
restore_error_handler();
243+
ini_set('unserialize_callback_func', $prevUnserializeHandler);
244+
if ($e) {
245+
if (!$e instanceof \UnexpectedValueException || self::$unserializeExceptionCode !== $e->getCode()) {
246+
throw $e;
247+
}
248+
if ($this->logger) {
249+
$this->logger->warning('Failed to unserialize the security token from the session.', array('key' => $this->sessionKey, 'received' => $serializedToken, 'exception' => $e));
250+
}
251+
}
252+
253+
return $token;
254+
}
255+
256+
/**
257+
* @internal
258+
*/
259+
public static function handleUnserializeCallback($class)
260+
{
261+
throw new \UnexpectedValueException('Class not found: '.$class, self::$unserializeExceptionCode);
262+
}
222263
}

Http/Tests/Firewall/ContextListenerTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ public function testInvalidTokenInSession($token)
173173
public function provideInvalidToken()
174174
{
175175
return array(
176+
array('foo'),
177+
array('O:8:"NotFound":0:{}'),
176178
array(serialize(new \__PHP_Incomplete_Class())),
177179
array(serialize(null)),
178180
array(null),

0 commit comments

Comments
 (0)