Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added sandbox support for functions

  • Loading branch information...
commit 7794463706680fa13108e196fe554def94c08203 1 parent 3615e9a
@arnaud-lb arnaud-lb authored committed
View
4 lib/Twig/Extension/Sandbox.php
@@ -70,10 +70,10 @@ public function getSecurityPolicy()
return $this->policy;
}
- public function checkSecurity($tags, $filters)
+ public function checkSecurity($tags, $filters, $functions)
{
if ($this->isSandboxed()) {
- $this->policy->checkSecurity($tags, $filters);
+ $this->policy->checkSecurity($tags, $filters, $functions);
}
}
View
7 lib/Twig/Node/SandboxedModule.php
@@ -20,13 +20,15 @@ class Twig_Node_SandboxedModule extends Twig_Node_Module
{
protected $usedFilters;
protected $usedTags;
+ protected $usedFunctions;
- public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags)
+ public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions)
{
parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getAttribute('filename'), $node->getLine(), $node->getNodeTag());
$this->usedFilters = $usedFilters;
$this->usedTags = $usedTags;
+ $this->usedFunctions = $usedFunctions;
}
protected function compileDisplayBody($compiler)
@@ -48,7 +50,8 @@ protected function compileDisplayFooter($compiler)
->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
->indent()
->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n")
- ->write(!$this->usedFilters ? "array()\n" : "array('".implode('\', \'', $this->usedFilters)."')\n")
+ ->write(!$this->usedFilters ? "array(),\n" : "array('".implode('\', \'', $this->usedFilters)."'),\n")
+ ->write(!$this->usedFunctions ? "array()\n" : "array('".implode('\', \'', $this->usedFunctions)."')\n")
->outdent()
->write(");\n")
;
View
9 lib/Twig/NodeVisitor/Sandbox.php
@@ -20,6 +20,7 @@ class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
protected $inAModule = false;
protected $tags;
protected $filters;
+ protected $functions;
/**
* Called before child nodes are visited.
@@ -35,6 +36,7 @@ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
$this->inAModule = true;
$this->tags = array();
$this->filters = array();
+ $this->functions = array();
return $node;
} elseif ($this->inAModule) {
@@ -48,6 +50,11 @@ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
$this->filters[] = $node->getNode('filter')->getAttribute('value');
}
+ // look for functions
+ if ($node instanceof Twig_Node_Expression_Function) {
+ $this->functions[] = $node->getNode('name')->getAttribute('name');
+ }
+
// wrap print to check __toString() calls
if ($node instanceof Twig_Node_Print) {
return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getLine(), $node->getNodeTag());
@@ -70,7 +77,7 @@ public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
if ($node instanceof Twig_Node_Module) {
$this->inAModule = false;
- return new Twig_Node_SandboxedModule($node, array_unique($this->filters), array_unique($this->tags));
+ return new Twig_Node_SandboxedModule($node, array_unique($this->filters), array_unique($this->tags), array_unique($this->functions));
}
return $node;
View
17 lib/Twig/Sandbox/SecurityPolicy.php
@@ -21,13 +21,15 @@ class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterfac
protected $allowedFilters;
protected $allowedMethods;
protected $allowedProperties;
+ protected $allowedFunctions;
- public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array())
+ public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array(), array $allowedFunctions = array())
{
$this->allowedTags = $allowedTags;
$this->allowedFilters = $allowedFilters;
$this->allowedMethods = $allowedMethods;
$this->allowedProperties = $allowedProperties;
+ $this->allowedFunctions = $allowedFunctions;
}
public function setAllowedTags(array $tags)
@@ -50,7 +52,12 @@ public function setAllowedProperties(array $properties)
$this->allowedProperties = $properties;
}
- public function checkSecurity($tags, $filters)
+ public function setAllowedFunctions(array $functions)
+ {
+ $this->allowedFunctions = $functions;
+ }
+
+ public function checkSecurity($tags, $filters, $functions)
{
foreach ($tags as $tag) {
if (!in_array($tag, $this->allowedTags)) {
@@ -63,6 +70,12 @@ public function checkSecurity($tags, $filters)
throw new Twig_Sandbox_SecurityError(sprintf('Filter "%s" is not allowed.', $filter));
}
}
+
+ foreach ($functions as $function) {
+ if (!in_array($function, $this->allowedFunctions)) {
+ throw new Twig_Sandbox_SecurityError(sprintf('Function "%s" is not allowed.', $function));
+ }
+ }
}
public function checkMethodAllowed($obj, $method)
View
2  lib/Twig/Sandbox/SecurityPolicyInterface.php
@@ -17,7 +17,7 @@
*/
interface Twig_Sandbox_SecurityPolicyInterface
{
- public function checkSecurity($tags, $filters);
+ public function checkSecurity($tags, $filters, $functions);
public function checkMethodAllowed($obj, $method);
View
16 test/Twig/Tests/Extension/SandboxTest.php
@@ -28,6 +28,7 @@ public function setUp()
'1_basic4' => '{{ obj.bar }}',
'1_basic5' => '{{ obj }}',
'1_basic6' => '{{ arr.obj }}',
+ '1_basic7' => '{{ cycle(["foo","bar"], 1) }}',
'1_basic' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
);
}
@@ -79,6 +80,13 @@ public function testSandboxGloballySet()
} catch (Twig_Sandbox_SecurityError $e) {
}
+ $twig = $this->getEnvironment(true, array(), self::$templates);
+ try {
+ $twig->loadTemplate('1_basic7')->render(self::$params);
+ $this->fail('Sandbox throws a SecurityError exception if an unallowed function is called in the template');
+ } catch (Twig_Sandbox_SecurityError $e) {
+ }
+
$twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('Object' => 'foo'));
$this->assertEquals('foo', $twig->loadTemplate('1_basic1')->render(self::$params), 'Sandbox allow some methods');
@@ -93,6 +101,10 @@ public function testSandboxGloballySet()
$twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array('Object' => 'bar'));
$this->assertEquals('bar', $twig->loadTemplate('1_basic4')->render(self::$params), 'Sandbox allow some properties');
+
+ $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array(), array('cycle'));
+ $this->assertEquals('bar', $twig->loadTemplate('1_basic7')->render(self::$params), 'Sandbox allow some functions');
+
}
public function testSandboxLocallySetForAnInclude()
@@ -129,11 +141,11 @@ public function testMacrosInASandbox()
$this->assertEquals('<p>username</p>', $twig->loadTemplate('index')->render(array()));
}
- protected function getEnvironment($sandboxed, $options, $templates, $tags = array(), $filters = array(), $methods = array(), $properties = array())
+ protected function getEnvironment($sandboxed, $options, $templates, $tags = array(), $filters = array(), $methods = array(), $properties = array(), $functions = array())
{
$loader = new Twig_Loader_Array($templates);
$twig = new Twig_Environment($loader, array_merge(array('debug' => true, 'cache' => false, 'autoescape' => false), $options));
- $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties);
+ $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
$twig->addExtension(new Twig_Extension_Sandbox($policy, $sandboxed));
return $twig;
View
12 test/Twig/Tests/Node/SandboxedModuleTest.php
@@ -24,7 +24,7 @@ public function testConstructor()
$macros = new Twig_Node();
$filename = 'foo.twig';
$node = new Twig_Node_Module($body, $parent, $blocks, $macros, $filename);
- $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'));
+ $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'), array('cycle'));
$this->assertEquals($body, $node->getNode('body'));
$this->assertEquals($blocks, $node->getNode('blocks'));
@@ -57,7 +57,7 @@ public function getTests()
$filename = 'foo.twig';
$node = new Twig_Node_Module($body, $extends, $blocks, $macros, $filename);
- $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'));
+ $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'), array('cycle'));
$tests[] = array($node, <<<EOF
<?php
@@ -76,7 +76,8 @@ public function display(array \$context, array \$blocks = array())
protected function checkSecurity() {
\$this->env->getExtension('sandbox')->checkSecurity(
array('upper'),
- array('for')
+ array('for'),
+ array('cycle')
);
}
@@ -95,7 +96,7 @@ public function getTemplateName()
$filename = 'foo.twig';
$node = new Twig_Node_Module($body, $extends, $blocks, $macros, $filename);
- $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'));
+ $node = new Twig_Node_SandboxedModule($node, array('for'), array('upper'), array('cycle'));
$tests[] = array($node, <<<EOF
<?php
@@ -124,7 +125,8 @@ public function display(array \$context, array \$blocks = array())
protected function checkSecurity() {
\$this->env->getExtension('sandbox')->checkSecurity(
array('upper'),
- array('for')
+ array('for'),
+ array('cycle')
);
\$this->parent->checkSecurity();
Please sign in to comment.
Something went wrong with that request. Please try again.