1 <?php
2 
3 /*
4  * This file is part of Twig.
5  *
6  * (c) Fabien Potencier
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11 
12 namespace Twig\Sandbox;
13 
14 use Twig\Markup;
15 use Twig\Template;
16 
17 /**
18  * Represents a security policy which need to be enforced when sandbox mode is enabled.
19  *
20  * @author Fabien Potencier <fabien@symfony.com>
21  */
22 final class SecurityPolicy implements SecurityPolicyInterface
23 {
24     private $allowedTags;
25     private $allowedFilters;
26     private $allowedMethods;
27     private $allowedProperties;
28     private $allowedFunctions;
29 
30     public function __construct(array $allowedTags = [], array $allowedFilters = [], array $allowedMethods = [], array $allowedProperties = [], array $allowedFunctions = [])
31     {
32         $this->allowedTags = $allowedTags;
33         $this->allowedFilters = $allowedFilters;
34         $this->setAllowedMethods($allowedMethods);
35         $this->allowedProperties = $allowedProperties;
36         $this->allowedFunctions = $allowedFunctions;
37     }
38 
39     public function setAllowedTags(array $tags)
40     {
41         $this->allowedTags = $tags;
42     }
43 
44     public function setAllowedFilters(array $filters)
45     {
46         $this->allowedFilters = $filters;
47     }
48 
49     public function setAllowedMethods(array $methods)
50     {
51         $this->allowedMethods = [];
52         foreach ($methods as $class => $m) {
53             $this->allowedMethods[$class] = array_map(function ($value) { return strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); }, \is_array($m) ? $m : [$m]);
54         }
55     }
56 
57     public function setAllowedProperties(array $properties)
58     {
59         $this->allowedProperties = $properties;
60     }
61 
62     public function setAllowedFunctions(array $functions)
63     {
64         $this->allowedFunctions = $functions;
65     }
66 
67     public function checkSecurity($tags, $filters, $functions)
68     {
69         foreach ($tags as $tag) {
70             if (!\in_array($tag, $this->allowedTags)) {
71                 throw new SecurityNotAllowedTagError(sprintf('Tag "%s" is not allowed.', $tag), $tag);
72             }
73         }
74 
75         foreach ($filters as $filter) {
76             if (!\in_array($filter, $this->allowedFilters)) {
77                 throw new SecurityNotAllowedFilterError(sprintf('Filter "%s" is not allowed.', $filter), $filter);
78             }
79         }
80 
81         foreach ($functions as $function) {
82             if (!\in_array($function, $this->allowedFunctions)) {
83                 throw new SecurityNotAllowedFunctionError(sprintf('Function "%s" is not allowed.', $function), $function);
84             }
85         }
86     }
87 
88     public function checkMethodAllowed($obj, $method)
89     {
90         if ($obj instanceof Template || $obj instanceof Markup) {
91             return;
92         }
93 
94         $allowed = false;
95         $method = strtr($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
96         foreach ($this->allowedMethods as $class => $methods) {
97             if ($obj instanceof $class) {
98                 $allowed = \in_array($method, $methods);
99 
100                 break;
101             }
102         }
103 
104         if (!$allowed) {
105             $class = \get_class($obj);
106             throw new SecurityNotAllowedMethodError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, $class), $class, $method);
107         }
108     }
109 
110     public function checkPropertyAllowed($obj, $property)
111     {
112         $allowed = false;
113         foreach ($this->allowedProperties as $class => $properties) {
114             if ($obj instanceof $class) {
115                 $allowed = \in_array($property, \is_array($properties) ? $properties : [$properties]);
116 
117                 break;
118             }
119         }
120 
121         if (!$allowed) {
122             $class = \get_class($obj);
123             throw new SecurityNotAllowedPropertyError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, $class), $class, $property);
124         }
125     }
126 }
127 
128 class_alias('Twig\Sandbox\SecurityPolicy', 'Twig_Sandbox_SecurityPolicy');
129