PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php

https://gitlab.com/gideonmarked/PLCPortal
PHP | 285 lines | 232 code | 41 blank | 12 comment | 0 complexity | a844adb32bcfbb32e03b2ebbf12e76e0 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of Twig.
  4. *
  5. * (c) Fabien Potencier
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. class Twig_Tests_Extension_SandboxTest extends PHPUnit_Framework_TestCase
  11. {
  12. protected static $params, $templates;
  13. protected function setUp()
  14. {
  15. self::$params = array(
  16. 'name' => 'Fabien',
  17. 'obj' => new FooObject(),
  18. 'arr' => array('obj' => new FooObject()),
  19. );
  20. self::$templates = array(
  21. '1_basic1' => '{{ obj.foo }}',
  22. '1_basic2' => '{{ name|upper }}',
  23. '1_basic3' => '{% if name %}foo{% endif %}',
  24. '1_basic4' => '{{ obj.bar }}',
  25. '1_basic5' => '{{ obj }}',
  26. '1_basic6' => '{{ arr.obj }}',
  27. '1_basic7' => '{{ cycle(["foo","bar"], 1) }}',
  28. '1_basic8' => '{{ obj.getfoobar }}{{ obj.getFooBar }}',
  29. '1_basic9' => '{{ obj.foobar }}{{ obj.fooBar }}',
  30. '1_basic' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
  31. '1_layout' => '{% block content %}{% endblock %}',
  32. '1_child' => "{% extends \"1_layout\" %}\n{% block content %}\n{{ \"a\"|json_encode }}\n{% endblock %}",
  33. );
  34. }
  35. /**
  36. * @expectedException Twig_Sandbox_SecurityError
  37. * @expectedExceptionMessage Filter "json_encode" is not allowed in "1_child" at line 3.
  38. */
  39. public function testSandboxWithInheritance()
  40. {
  41. $twig = $this->getEnvironment(true, array(), self::$templates, array('block'));
  42. $twig->loadTemplate('1_child')->render(array());
  43. }
  44. public function testSandboxGloballySet()
  45. {
  46. $twig = $this->getEnvironment(false, array(), self::$templates);
  47. $this->assertEquals('FOO', $twig->loadTemplate('1_basic')->render(self::$params), 'Sandbox does nothing if it is disabled globally');
  48. }
  49. public function testSandboxUnallowedMethodAccessor()
  50. {
  51. $twig = $this->getEnvironment(true, array(), self::$templates);
  52. try {
  53. $twig->loadTemplate('1_basic1')->render(self::$params);
  54. $this->fail('Sandbox throws a SecurityError exception if an unallowed method is called');
  55. } catch (Twig_Sandbox_SecurityError $e) {
  56. $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedMethodError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedMethodError');
  57. $this->assertEquals('FooObject', $e->getClassName(), 'Exception should be raised on the "FooObject" class');
  58. $this->assertEquals('foo', $e->getMethodName(), 'Exception should be raised on the "foo" method');
  59. }
  60. }
  61. public function testSandboxUnallowedFilter()
  62. {
  63. $twig = $this->getEnvironment(true, array(), self::$templates);
  64. try {
  65. $twig->loadTemplate('1_basic2')->render(self::$params);
  66. $this->fail('Sandbox throws a SecurityError exception if an unallowed filter is called');
  67. } catch (Twig_Sandbox_SecurityError $e) {
  68. $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedFilterError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedFilterError');
  69. $this->assertEquals('upper', $e->getFilterName(), 'Exception should be raised on the "upper" filter');
  70. }
  71. }
  72. public function testSandboxUnallowedTag()
  73. {
  74. $twig = $this->getEnvironment(true, array(), self::$templates);
  75. try {
  76. $twig->loadTemplate('1_basic3')->render(self::$params);
  77. $this->fail('Sandbox throws a SecurityError exception if an unallowed tag is used in the template');
  78. } catch (Twig_Sandbox_SecurityError $e) {
  79. $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedTagError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedTagError');
  80. $this->assertEquals('if', $e->getTagName(), 'Exception should be raised on the "if" tag');
  81. }
  82. }
  83. public function testSandboxUnallowedProperty()
  84. {
  85. $twig = $this->getEnvironment(true, array(), self::$templates);
  86. try {
  87. $twig->loadTemplate('1_basic4')->render(self::$params);
  88. $this->fail('Sandbox throws a SecurityError exception if an unallowed property is called in the template');
  89. } catch (Twig_Sandbox_SecurityError $e) {
  90. $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedPropertyError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedPropertyError');
  91. $this->assertEquals('FooObject', $e->getClassName(), 'Exception should be raised on the "FooObject" class');
  92. $this->assertEquals('bar', $e->getPropertyName(), 'Exception should be raised on the "bar" property');
  93. }
  94. }
  95. public function testSandboxUnallowedToString()
  96. {
  97. $twig = $this->getEnvironment(true, array(), self::$templates);
  98. try {
  99. $twig->loadTemplate('1_basic5')->render(self::$params);
  100. $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template');
  101. } catch (Twig_Sandbox_SecurityError $e) {
  102. $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedMethodError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedMethodError');
  103. $this->assertEquals('FooObject', $e->getClassName(), 'Exception should be raised on the "FooObject" class');
  104. $this->assertEquals('__tostring', $e->getMethodName(), 'Exception should be raised on the "__toString" method');
  105. }
  106. }
  107. public function testSandboxUnallowedToStringArray()
  108. {
  109. $twig = $this->getEnvironment(true, array(), self::$templates);
  110. try {
  111. $twig->loadTemplate('1_basic6')->render(self::$params);
  112. $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template');
  113. } catch (Twig_Sandbox_SecurityError $e) {
  114. $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedMethodError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedMethodError');
  115. $this->assertEquals('FooObject', $e->getClassName(), 'Exception should be raised on the "FooObject" class');
  116. $this->assertEquals('__tostring', $e->getMethodName(), 'Exception should be raised on the "__toString" method');
  117. }
  118. }
  119. public function testSandboxUnallowedFunction()
  120. {
  121. $twig = $this->getEnvironment(true, array(), self::$templates);
  122. try {
  123. $twig->loadTemplate('1_basic7')->render(self::$params);
  124. $this->fail('Sandbox throws a SecurityError exception if an unallowed function is called in the template');
  125. } catch (Twig_Sandbox_SecurityError $e) {
  126. $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedFunctionError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedFunctionError');
  127. $this->assertEquals('cycle', $e->getFunctionName(), 'Exception should be raised on the "cycle" function');
  128. }
  129. }
  130. public function testSandboxAllowMethodFoo()
  131. {
  132. $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => 'foo'));
  133. FooObject::reset();
  134. $this->assertEquals('foo', $twig->loadTemplate('1_basic1')->render(self::$params), 'Sandbox allow some methods');
  135. $this->assertEquals(1, FooObject::$called['foo'], 'Sandbox only calls method once');
  136. }
  137. public function testSandboxAllowMethodToString()
  138. {
  139. $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => '__toString'));
  140. FooObject::reset();
  141. $this->assertEquals('foo', $twig->loadTemplate('1_basic5')->render(self::$params), 'Sandbox allow some methods');
  142. $this->assertEquals(1, FooObject::$called['__toString'], 'Sandbox only calls method once');
  143. }
  144. public function testSandboxAllowMethodToStringDisabled()
  145. {
  146. $twig = $this->getEnvironment(false, array(), self::$templates);
  147. FooObject::reset();
  148. $this->assertEquals('foo', $twig->loadTemplate('1_basic5')->render(self::$params), 'Sandbox allows __toString when sandbox disabled');
  149. $this->assertEquals(1, FooObject::$called['__toString'], 'Sandbox only calls method once');
  150. }
  151. public function testSandboxAllowFilter()
  152. {
  153. $twig = $this->getEnvironment(true, array(), self::$templates, array(), array('upper'));
  154. $this->assertEquals('FABIEN', $twig->loadTemplate('1_basic2')->render(self::$params), 'Sandbox allow some filters');
  155. }
  156. public function testSandboxAllowTag()
  157. {
  158. $twig = $this->getEnvironment(true, array(), self::$templates, array('if'));
  159. $this->assertEquals('foo', $twig->loadTemplate('1_basic3')->render(self::$params), 'Sandbox allow some tags');
  160. }
  161. public function testSandboxAllowProperty()
  162. {
  163. $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array('FooObject' => 'bar'));
  164. $this->assertEquals('bar', $twig->loadTemplate('1_basic4')->render(self::$params), 'Sandbox allow some properties');
  165. }
  166. public function testSandboxAllowFunction()
  167. {
  168. $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array(), array('cycle'));
  169. $this->assertEquals('bar', $twig->loadTemplate('1_basic7')->render(self::$params), 'Sandbox allow some functions');
  170. }
  171. public function testSandboxAllowFunctionsCaseInsensitive()
  172. {
  173. foreach (array('getfoobar', 'getFoobar', 'getFooBar') as $name) {
  174. $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => $name));
  175. FooObject::reset();
  176. $this->assertEquals('foobarfoobar', $twig->loadTemplate('1_basic8')->render(self::$params), 'Sandbox allow methods in a case-insensitive way');
  177. $this->assertEquals(2, FooObject::$called['getFooBar'], 'Sandbox only calls method once');
  178. $this->assertEquals('foobarfoobar', $twig->loadTemplate('1_basic9')->render(self::$params), 'Sandbox allow methods via shortcut names (ie. without get/set)');
  179. }
  180. }
  181. public function testSandboxLocallySetForAnInclude()
  182. {
  183. self::$templates = array(
  184. '2_basic' => '{{ obj.foo }}{% include "2_included" %}{{ obj.foo }}',
  185. '2_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
  186. );
  187. $twig = $this->getEnvironment(false, array(), self::$templates);
  188. $this->assertEquals('fooFOOfoo', $twig->loadTemplate('2_basic')->render(self::$params), 'Sandbox does nothing if disabled globally and sandboxed not used for the include');
  189. self::$templates = array(
  190. '3_basic' => '{{ obj.foo }}{% sandbox %}{% include "3_included" %}{% endsandbox %}{{ obj.foo }}',
  191. '3_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
  192. );
  193. $twig = $this->getEnvironment(true, array(), self::$templates);
  194. try {
  195. $twig->loadTemplate('3_basic')->render(self::$params);
  196. $this->fail('Sandbox throws a SecurityError exception when the included file is sandboxed');
  197. } catch (Twig_Sandbox_SecurityError $e) {
  198. $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedTagError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedTagError');
  199. $this->assertEquals('sandbox', $e->getTagName());
  200. }
  201. }
  202. public function testMacrosInASandbox()
  203. {
  204. $twig = $this->getEnvironment(true, array('autoescape' => 'html'), array('index' => <<<EOF
  205. {%- import _self as macros %}
  206. {%- macro test(text) %}<p>{{ text }}</p>{% endmacro %}
  207. {{- macros.test('username') }}
  208. EOF
  209. ), array('macro', 'import'), array('escape'));
  210. $this->assertEquals('<p>username</p>', $twig->loadTemplate('index')->render(array()));
  211. }
  212. protected function getEnvironment($sandboxed, $options, $templates, $tags = array(), $filters = array(), $methods = array(), $properties = array(), $functions = array())
  213. {
  214. $loader = new Twig_Loader_Array($templates);
  215. $twig = new Twig_Environment($loader, array_merge(array('debug' => true, 'cache' => false, 'autoescape' => false), $options));
  216. $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
  217. $twig->addExtension(new Twig_Extension_Sandbox($policy, $sandboxed));
  218. return $twig;
  219. }
  220. }
  221. class FooObject
  222. {
  223. public static $called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0);
  224. public $bar = 'bar';
  225. public static function reset()
  226. {
  227. self::$called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0);
  228. }
  229. public function __toString()
  230. {
  231. ++self::$called['__toString'];
  232. return 'foo';
  233. }
  234. public function foo()
  235. {
  236. ++self::$called['foo'];
  237. return 'foo';
  238. }
  239. public function getFooBar()
  240. {
  241. ++self::$called['getFooBar'];
  242. return 'foobar';
  243. }
  244. }