From: fabien Date: Thu, 5 Nov 2009 17:31:02 +0000 (+0000) Subject: added public properties support X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=452dc15ae1a6b9c02b08c351cacac3b50d29f300;p=konrad%2Ftwig.git added public properties support git-svn-id: http://svn.twig-project.org/trunk@113 93ef8e89-cb99-4229-a87c-7fa0fa45744b --- diff --git a/doc/03-Twig-for-Developers.markdown b/doc/03-Twig-for-Developers.markdown index b03c1fb..4ac9fd5 100644 --- a/doc/03-Twig-for-Developers.markdown +++ b/doc/03-Twig-for-Developers.markdown @@ -285,7 +285,7 @@ The `sandbox` extension can be used to evaluate untrusted code. Access to unsafe attributes and methods is prohibited. The sandbox security is managed by a policy instance. By default, Twig comes with one policy class: `Twig_Sandbox_SecurityPolicy`. This class allows you to white-list some tags, -filters, and methods: +filters, properties, and methods: [php] $tags = array('if'); @@ -293,13 +293,16 @@ filters, and methods: $methods = array( 'Article' => array('getTitle', 'getBody'), ); - $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods); + $properties = array( + 'Article' => array('title', 'body), + ); + $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties); With the previous configuration, the security policy will only allow usage of the `if` tag, and the `upper` filter. Moreover, the templates will only be -able to call the `getTitle()` and `getBody()` methods on `Article` objects. -Everything else won't be allowed and will generate a -`Twig_Sandbox_SecurityError` exception. +able to call the `getTitle()` and `getBody()` methods on `Article` objects, +and the `title` and `body` public properties. Everything else won't be allowed +and will generate a `Twig_Sandbox_SecurityError` exception. The policy object is the first argument of the sandbox constructor: diff --git a/lib/Twig/Extension/Sandbox.php b/lib/Twig/Extension/Sandbox.php index b900803..0baee4b 100644 --- a/lib/Twig/Extension/Sandbox.php +++ b/lib/Twig/Extension/Sandbox.php @@ -76,6 +76,14 @@ class Twig_Extension_Sandbox extends Twig_Extension } } + public function checkPropertyAllowed($obj, $method) + { + if ($this->isSandboxed()) + { + $this->policy->checkPropertyAllowed($obj, $method); + } + } + /** * Returns the name of the extension. * diff --git a/lib/Twig/Resource.php b/lib/Twig/Resource.php index 3173593..4fcd620 100644 --- a/lib/Twig/Resource.php +++ b/lib/Twig/Resource.php @@ -41,6 +41,16 @@ abstract class Twig_Resource return null; } + if (is_object($object) && isset($object->$item)) + { + if ($this->env->hasExtension('sandbox')) + { + $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item); + } + + return $object->$item; + } + if ( !is_object($object) || ( diff --git a/lib/Twig/Sandbox/SecurityPolicy.php b/lib/Twig/Sandbox/SecurityPolicy.php index 92b3756..fe6ac1d 100644 --- a/lib/Twig/Sandbox/SecurityPolicy.php +++ b/lib/Twig/Sandbox/SecurityPolicy.php @@ -21,12 +21,14 @@ class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterfac protected $allowedTags; protected $allowedFilters; protected $allowedMethods; + protected $allowedProperties; - public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array()) + public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array()) { $this->allowedTags = $allowedTags; $this->allowedFilters = $allowedFilters; $this->allowedMethods = $allowedMethods; + $this->allowedProperties = $allowedProperties; } public function setAllowedTags(array $tags) @@ -44,6 +46,11 @@ class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterfac $this->allowedMethods = $methods; } + public function setAllowedProperties(array $properties) + { + $this->allowedProperties = $properties; + } + public function checkSecurity($tags, $filters) { foreach ($tags as $tag) @@ -81,4 +88,23 @@ class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterfac throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj))); } } + + public function checkPropertyAllowed($obj, $property) + { + $allowed = false; + foreach ($this->allowedProperties as $class => $properties) + { + if ($obj instanceof $class) + { + $allowed = in_array($property, is_array($properties) ? $properties : array($properties)); + + break; + } + } + + if (!$allowed) + { + throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, get_class($obj))); + } + } } diff --git a/lib/Twig/Sandbox/SecurityPolicyInterface.php b/lib/Twig/Sandbox/SecurityPolicyInterface.php index afb7e61..bcb9f02 100644 --- a/lib/Twig/Sandbox/SecurityPolicyInterface.php +++ b/lib/Twig/Sandbox/SecurityPolicyInterface.php @@ -21,4 +21,6 @@ interface Twig_Sandbox_SecurityPolicyInterface public function checkSecurity($tags, $filters); public function checkMethodAllowed($obj, $method); + + public function checkPropertyAllowed($obj, $method); } diff --git a/test/unit/Twig/Extension/Sandbox.php b/test/unit/Twig/Extension/Sandbox.php index 64775d0..c929edd 100644 --- a/test/unit/Twig/Extension/Sandbox.php +++ b/test/unit/Twig/Extension/Sandbox.php @@ -19,6 +19,8 @@ require_once dirname(__FILE__).'/../../../lib/Twig_Loader_Var.php'; class Object { + public $bar = 'bar'; + public function foo() { return 'foo'; @@ -33,10 +35,11 @@ $templates = array( '1_basic1' => '{{ obj.foo }}', '1_basic2' => '{{ name|upper }}', '1_basic3' => '{% if name %}foo{% endif %}', + '1_basic4' => '{{ obj.bar }}', '1_basic' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}', ); -$t = new LimeTest(9); +$t = new LimeTest(11); $t->diag('Sandbox globally set'); $twig = get_environment(false, $templates); @@ -75,6 +78,17 @@ catch (Twig_Sandbox_SecurityError $e) $t->pass('Sandbox throws a SecurityError exception if an unallowed tag is used in the template'); } +$twig = get_environment(true, $templates); +try +{ + $twig->loadTemplate('1_basic4')->render($params); + $t->fail('Sandbox throws a SecurityError exception if an unallowed property is called in the template'); +} +catch (Twig_Sandbox_SecurityError $e) +{ + $t->pass('Sandbox throws a SecurityError exception if an unallowed property is called in the template'); +} + $twig = get_environment(true, $templates, array(), array(), array('Object' => 'foo')); $t->is($twig->loadTemplate('1_basic1')->render($params), 'foo', 'Sandbox allow some methods'); @@ -84,6 +98,9 @@ $t->is($twig->loadTemplate('1_basic2')->render($params), 'FABIEN', 'Sandbox allo $twig = get_environment(true, $templates, array('if')); $t->is($twig->loadTemplate('1_basic3')->render($params), 'foo', 'Sandbox allow some tags'); +$twig = get_environment(true, $templates, array(), array(), array(), array('Object' => 'bar')); +$t->is($twig->loadTemplate('1_basic4')->render($params), 'bar', 'Sandbox allow some properties'); + $t->diag('Sandbox locally set for an include'); $templates = array( @@ -112,7 +129,7 @@ catch (Twig_Sandbox_SecurityError $e) } -function get_environment($sandboxed, $templates, $tags = array(), $filters = array(), $methods = array()) +function get_environment($sandboxed, $templates, $tags = array(), $filters = array(), $methods = array(), $properties = array()) { static $prefix = 0; @@ -120,7 +137,7 @@ function get_environment($sandboxed, $templates, $tags = array(), $filters = arr $loader = new Twig_Loader_Var($templates, $prefix); $twig = new Twig_Environment($loader, array('trim_blocks' => true, 'debug' => true)); - $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods); + $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties); $twig->addExtension(new Twig_Extension_Sandbox($policy, $sandboxed)); return $twig;