Skip to content

Commit 159c7e8

Browse files
committed
Fixed sandbox for methods
1 parent 7df0a55 commit 159c7e8

File tree

2 files changed

+56
-10
lines changed

2 files changed

+56
-10
lines changed

lib/Twig/Template.php

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -523,18 +523,21 @@ protected function getAttribute($object, $item, array $arguments = array(), $typ
523523
}
524524

525525
// object property
526-
if (self::METHOD_CALL !== $type && !$object instanceof self) { // Twig_Template does not have public properties, and we don't want to allow access to internal ones
527-
if (isset($object->$item) || array_key_exists((string) $item, $object)) {
528-
if ($isDefinedTest) {
529-
return true;
530-
}
526+
try {
527+
if (self::METHOD_CALL !== $type && !$object instanceof self) { // Twig_Template does not have public properties, and we don't want to allow access to internal ones
528+
if (isset($object->$item) || array_key_exists((string)$item, $object)) {
529+
if ($isDefinedTest) {
530+
return true;
531+
}
531532

532-
if ($this->env->hasExtension('sandbox')) {
533-
$this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
534-
}
533+
if ($this->env->hasExtension('sandbox')) {
534+
$this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
535+
}
535536

536-
return $object->$item;
537+
return $object->$item;
538+
}
537539
}
540+
} catch (Twig_Sandbox_SecurityError $propertySandboxException) {
538541
}
539542

540543
$class = get_class($object);
@@ -573,6 +576,10 @@ protected function getAttribute($object, $item, array $arguments = array(), $typ
573576
$method = (string) $item;
574577
$call = true;
575578
} else {
579+
if (isset($propertySandboxException)) {
580+
throw $propertySandboxException;
581+
}
582+
576583
if ($isDefinedTest) {
577584
return false;
578585
}
@@ -589,14 +596,18 @@ protected function getAttribute($object, $item, array $arguments = array(), $typ
589596
}
590597

591598
if ($this->env->hasExtension('sandbox')) {
592-
$this->env->getExtension('sandbox')->checkMethodAllowed($object, $method);
599+
$this->env->getExtension('sandbox')->checkMethodAllowed($object, $call ? '__call' : $method);
593600
}
594601

595602
// Some objects throw exceptions when they have __call, and the method we try
596603
// to call is not supported. If ignoreStrictCheck is true, we should return null.
597604
try {
598605
$ret = call_user_func_array(array($object, $method), $arguments);
599606
} catch (BadMethodCallException $e) {
607+
if ($call && isset($propertySandboxException)) {
608+
throw $propertySandboxException;
609+
}
610+
600611
if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) {
601612
return;
602613
}

test/Twig/Tests/Extension/SandboxTest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ protected function setUp()
3131
'1_basic7' => '{{ cycle(["foo","bar"], 1) }}',
3232
'1_basic8' => '{{ obj.getfoobar }}{{ obj.getFooBar }}',
3333
'1_basic9' => '{{ obj.foobar }}{{ obj.fooBar }}',
34+
'1_basic10' => '{{ obj.baz }}',
35+
'1_basic11' => '{{ obj.bac }}',
36+
'1_basic12' => '{{ obj.xyz }}',
3437
'1_basic' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
3538
'1_layout' => '{% block content %}{% endblock %}',
3639
'1_child' => "{% extends \"1_layout\" %}\n{% block content %}\n{{ \"a\"|json_encode }}\n{% endblock %}",
@@ -101,6 +104,14 @@ public function testSandboxGloballySet()
101104
} catch (Twig_Sandbox_SecurityError $e) {
102105
}
103106

107+
$twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => '__call'));
108+
try {
109+
$twig->loadTemplate('1_basic11')->render(self::$params);
110+
$this->fail('Sandbox throws a SecurityError exception if an unallowed property is called in the template through a method (__call)');
111+
} catch (Twig_Sandbox_SecurityError $e) {
112+
$this->assertEquals('Calling "bac" property on a "FooObject" object is not allowed.', $e->getRawMessage());
113+
}
114+
104115
$twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => 'foo'));
105116
FooObject::reset();
106117
$this->assertEquals('foo', $twig->loadTemplate('1_basic1')->render(self::$params), 'Sandbox allow some methods');
@@ -136,6 +147,12 @@ public function testSandboxGloballySet()
136147

137148
$this->assertEquals('foobarfoobar', $twig->loadTemplate('1_basic9')->render(self::$params), 'Sandbox allow methods via shortcut names (ie. without get/set)');
138149
}
150+
151+
$twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => 'getBaz'));
152+
$this->assertEquals('baz', $twig->loadTemplate('1_basic10')->render(self::$params), 'Sandbox allow some methods');
153+
154+
$twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => '__call'));
155+
$this->assertEquals('xyz', $twig->loadTemplate('1_basic12')->render(self::$params), 'Sandbox allow a method (__call())');
139156
}
140157

141158
public function testSandboxLocallySetForAnInclude()
@@ -192,6 +209,10 @@ class FooObject
192209

193210
public $bar = 'bar';
194211

212+
public $baz = 'baz';
213+
214+
public $bac = 'bac';
215+
195216
public static function reset()
196217
{
197218
self::$called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0);
@@ -217,4 +238,18 @@ public function getFooBar()
217238

218239
return 'foobar';
219240
}
241+
242+
public function getBaz()
243+
{
244+
return $this->baz;
245+
}
246+
247+
public function __call($name, $arguments)
248+
{
249+
if ('bac' === strtolower($name)) {
250+
throw new BadMethodCallException;
251+
}
252+
253+
return $name;
254+
}
220255
}

0 commit comments

Comments
 (0)