@@ -41,6 +41,9 @@ protected function setUp(): void
4141 '1_basic7 ' => '{{ cycle(["foo","bar"], 1) }} ' ,
4242 '1_basic8 ' => '{{ obj.getfoobar }}{{ obj.getFooBar }} ' ,
4343 '1_basic9 ' => '{{ obj.foobar }}{{ obj.fooBar }} ' ,
44+ '1_basic10 ' => '{{ obj.baz }} ' ,
45+ '1_basic11 ' => '{{ obj.xyz }} ' ,
46+ '1_basic12 ' => '{{ obj.bac }} ' ,
4447 '1_basic ' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %} ' ,
4548 '1_layout ' => '{% block content %}{% endblock %} ' ,
4649 '1_child ' => "{% extends \"1_layout \" %} \n{% block content %} \n{{ \"a \"|json_encode }} \n{% endblock %} " ,
@@ -326,6 +329,35 @@ public function testSandboxAllowFunctionsCaseInsensitive()
326329 }
327330 }
328331
332+ public function testSandboxRunGetterInsteadOfUnallowedProperty ()
333+ {
334+ $ twig = $ this ->getEnvironment (true , array (), self ::$ templates , array (), array (), array (FooObject::class => 'getBaz ' ));
335+ FooObject::reset ();
336+ $ this ->assertEquals ('baz ' , $ twig ->load ('1_basic10 ' )->render (self ::$ params ), 'Sandbox allow some methods ' );
337+ $ this ->assertEquals (1 , FooObject::$ called ['getBaz ' ], 'Sandbox only calls method getBaz ' );
338+ }
339+
340+ public function testSandboxRunCallInsteadOfUnallowedProperty ()
341+ {
342+ $ twig = $ this ->getEnvironment (true , array (), self ::$ templates , array (), array (), array (FooObject::class => '__call ' ));
343+ FooObject::reset ();
344+ $ this ->assertEquals ('xyz ' , $ twig ->load ('1_basic11 ' )->render (self ::$ params ), 'Sandbox allow a method (__call()) ' );
345+ $ this ->assertEquals (1 , FooObject::$ called ['__call ' ], 'Sandbox only calls method __call ' );
346+ }
347+
348+ public function testSandboxRunCallInsteadOfUnallowedPropertyAndThrowException ()
349+ {
350+ $ twig = $ this ->getEnvironment (true , array (), self ::$ templates , [], [], [FooObject::class => '__call ' ]);
351+ FooObject::reset ();
352+ try {
353+ $ twig ->load ('1_basic12 ' )->render (self ::$ params );
354+ $ this ->fail ('Sandbox throws a SecurityError exception if an unallowed property is called in the template through a method (__call) ' );
355+ } catch (SecurityError $ e ) {
356+ $ this ->assertEquals (sprintf ('Calling "bac" property on a "%s" object is not allowed. ' , FooObject::class), $ e ->getRawMessage ());
357+ $ this ->assertEquals (1 , FooObject::$ called ['__call ' ], 'Sandbox only calls method __call ' );
358+ }
359+ }
360+
329361 public function testSandboxLocallySetForAnInclude ()
330362 {
331363 self ::$ templates = [
@@ -418,13 +450,17 @@ protected function getEnvironment($sandboxed, $options, $templates, $tags = [],
418450
419451class FooObject
420452{
421- public static $ called = ['__toString ' => 0 , 'foo ' => 0 , 'getFooBar ' => 0 ];
453+ public static $ called = ['__call ' => 0 , ' __toString ' => 0 , 'foo ' => 0 , ' getBaz ' => 0 , 'getFooBar ' => 0 ];
422454
423455 public $ bar = 'bar ' ;
424456
457+ public $ baz = 'baz ' ;
458+
459+ public $ bac = 'bac ' ;
460+
425461 public static function reset ()
426462 {
427- self ::$ called = ['__toString ' => 0 , 'foo ' => 0 , 'getFooBar ' => 0 ];
463+ self ::$ called = ['__call ' => 0 , ' __toString ' => 0 , 'foo ' => 0 , ' getBaz ' => 0 , 'getFooBar ' => 0 ];
428464 }
429465
430466 public function __toString ()
@@ -452,4 +488,20 @@ public function getAnotherFooObject()
452488 {
453489 return new self ();
454490 }
491+
492+ public function getBaz ()
493+ {
494+ ++self ::$ called ['getBaz ' ];
495+ return $ this ->baz ;
496+ }
497+
498+ public function __call ($ name , $ arguments )
499+ {
500+ ++self ::$ called ['__call ' ];
501+ if ('bac ' === strtolower ($ name )) {
502+ throw new \BadMethodCallException ('bac() method is not allowed ' );
503+ }
504+
505+ return $ name ;
506+ }
455507}
0 commit comments