Test Failed
Push — master ( 96ccb3...e36e05 )
by Justin
03:29
created

Policy::allowMethod()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 5
nc 3
nop 2
1
<?php
2
/**
3
 * Copyright (c) 2013-2016
4
 *
5
 * @category  Library
6
 * @package   Dwoo\Security
7
 * @author    Jordi Boggiano <[email protected]>
8
 * @author    David Sanchez <[email protected]>
9
 * @copyright 2008-2013 Jordi Boggiano
10
 * @copyright 2013-2016 David Sanchez
11
 * @license   http://dwoo.org/LICENSE Modified BSD License
12
 * @version   1.3.0
13
 * @date      2016-09-23
14
 * @link      http://dwoo.org/
15
 */
16
17
namespace Dwoo\Security;
18
19
use Dwoo\Core;
20
21
/**
22
 * Represents the security settings of a dwoo instance, it can be passed around to different dwoo instances.
23
 * This software is provided 'as-is', without any express or implied warranty.
24
 * In no event will the authors be held liable for any damages arising from the use of this software.
25
 */
26
class Policy
27
{
28
    /**
29
     * Php handling constants, defaults to PHP_REMOVE
30
     * PHP_ENCODE : run htmlentities over them
31
     * PHP_REMOVE : remove all <?php ?> (+ short tags if your short tags option is on) from the input template
32
     * PHP_ALLOW : leave them as they are
33
     *
34
     * @var int
35
     */
36
    const PHP_ENCODE = 1;
37
    const PHP_REMOVE = 2;
38
    const PHP_ALLOW  = 3;
39
40
    /**
41
     * Constant handling constants, defaults to CONST_DISALLOW
42
     * CONST_DISALLOW : throw an error if {$dwoo.const.*} is used in the template
43
     * CONST_ALLOW : allow {$dwoo.const.*} calls
44
     */
45
    const CONST_DISALLOW = false;
46
    const CONST_ALLOW    = true;
47
48
    /**
49
     * Php functions that are allowed to be used within the template.
50
     *
51
     * @var array
52
     */
53
    protected $allowedPhpFunctions = array(
54
        'str_repeat'       => true,
55
        'number_format'    => true,
56
        'htmlentities'     => true,
57
        'htmlspecialchars' => true,
58
        'long2ip'          => true,
59
        'strlen'           => true,
60
        'list'             => true,
61
        'empty'            => true,
62
        'count'            => true,
63
        'sizeof'           => true,
64
        'in_array'         => true,
65
        'is_array'         => true,
66
    );
67
68
    /**
69
     * Methods that are allowed to be used within the template.
70
     *
71
     * @var array
72
     */
73
    protected $allowedMethods = array();
74
75
    /**
76
     * Paths that are safe to use with include or other file-access plugins.
77
     *
78
     * @var array
79
     */
80
    protected $allowedDirectories = array();
81
82
    /**
83
     * Stores the php handling level.
84
     * defaults to self::PHP_REMOVE
85
     *
86
     * @var int
87
     */
88
    protected $phpHandling = self::PHP_REMOVE;
89
90
    /**
91
     * Stores the constant handling level.
92
     * defaults to self::CONST_DISALLOW
93
     *
94
     * @var bool
95
     */
96
    protected $constHandling = self::CONST_DISALLOW;
97
98
    /**
99
     * Adds a php function to the allowed list.
100
     *
101
     * @param mixed $func function name or array of function names
102
     */
103
    public function allowPhpFunction($func)
104
    {
105
        if (is_array($func)) {
106
            foreach ($func as $fname) {
107
                $this->allowedPhpFunctions[strtolower($fname)] = true;
108
            }
109
        } else {
110
            $this->allowedPhpFunctions[strtolower($func)] = true;
111
        }
112
    }
113
114
    /**
115
     * Removes a php function from the allowed list.
116
     *
117
     * @param mixed $func function name or array of function names
118
     */
119
    public function disallowPhpFunction($func)
120
    {
121
        if (is_array($func)) {
122
            foreach ($func as $fname) {
123
                unset($this->allowedPhpFunctions[strtolower($fname)]);
124
            }
125
        } else {
126
            unset($this->allowedPhpFunctions[strtolower($func)]);
127
        }
128
    }
129
130
    /**
131
     * Returns the list of php functions allowed to run, note that the function names
132
     * are stored in the array keys and not values.
133
     *
134
     * @return array
135
     */
136
    public function getAllowedPhpFunctions()
137
    {
138
        return $this->allowedPhpFunctions;
139
    }
140
141
    /**
142
     * Adds a class method to the allowed list, this must be used for
143
     * both static and non static method by providing the class name
144
     * and method name to use.
145
     *
146
     * @param mixed  $class  class name or array of array('class', 'method') couples
147
     * @param string $method method name
148
     */
149
    public function allowMethod($class, $method = null)
150
    {
151
        if (is_array($class)) {
152
            foreach ($class as $elem) {
153
                $this->allowedMethods[strtolower($elem[0])][strtolower($elem[1])] = true;
154
            }
155
        } else {
156
            $this->allowedMethods[strtolower($class)][strtolower($method)] = true;
157
        }
158
    }
159
160
    /**
161
     * Removes a class method from the allowed list.
162
     *
163
     * @param mixed  $class  class name or array of array('class', 'method') couples
164
     * @param string $method method name
165
     */
166
    public function disallowMethod($class, $method = null)
167
    {
168
        if (is_array($class)) {
169
            foreach ($class as $elem) {
170
                unset($this->allowedMethods[strtolower($elem[0])][strtolower($elem[1])]);
171
            }
172
        } else {
173
            unset($this->allowedMethods[strtolower($class)][strtolower($method)]);
174
        }
175
    }
176
177
    /**
178
     * Returns the list of class methods allowed to run, note that the class names
179
     * and method names are stored in the array keys and not values.
180
     *
181
     * @return array
182
     */
183
    public function getAllowedMethods()
184
    {
185
        return $this->allowedMethods;
186
    }
187
188
    /**
189
     * Adds a directory to the safelist for includes and other file-access plugins.
190
     * note that all the includePath directories you provide to the Dwoo_Template_File class
191
     * are automatically marked as safe
192
     *
193
     * @param mixed $path a path name or an array of paths
194
     */
195
    public function allowDirectory($path)
196
    {
197
        if (is_array($path)) {
198
            foreach ($path as $dir) {
199
                $this->allowedDirectories[realpath($dir)] = true;
200
            }
201
        } else {
202
            $this->allowedDirectories[realpath($path)] = true;
203
        }
204
    }
205
206
    /**
207
     * Removes a directory from the safe list.
208
     *
209
     * @param mixed $path a path name or an array of paths
210
     */
211
    public function disallowDirectory($path)
212
    {
213
        if (is_array($path)) {
214
            foreach ($path as $dir) {
215
                unset($this->allowedDirectories[realpath($dir)]);
216
            }
217
        } else {
218
            unset($this->allowedDirectories[realpath($path)]);
219
        }
220
    }
221
222
    /**
223
     * Returns the list of safe paths, note that the paths are stored in the array
224
     * keys and not values.
225
     *
226
     * @return array
227
     */
228
    public function getAllowedDirectories()
229
    {
230
        return $this->allowedDirectories;
231
    }
232
233
    /**
234
     * Sets the php handling level, defaults to REMOVE.
235
     *
236
     * @param int $level one of the Dwoo_Security_Policy::PHP_* constants
237
     */
238
    public function setPhpHandling($level = self::PHP_REMOVE)
239
    {
240
        $this->phpHandling = $level;
241
    }
242
243
    /**
244
     * Returns the php handling level.
245
     *
246
     * @return int the current level, one of the Dwoo_Security_Policy::PHP_* constants
247
     */
248
    public function getPhpHandling()
249
    {
250
        return $this->phpHandling;
251
    }
252
253
    /**
254
     * Sets the constant handling level, defaults to CONST_DISALLOW.
255
     *
256
     * @param bool $level one of the Dwoo_Security_Policy::CONST_* constants
257
     */
258
    public function setConstantHandling($level = self::CONST_DISALLOW)
259
    {
260
        $this->constHandling = $level;
261
    }
262
263
    /**
264
     * Returns the constant handling level.
265
     *
266
     * @return bool the current level, one of the Dwoo_Security_Policy::CONST_* constants
267
     */
268
    public function getConstantHandling()
269
    {
270
        return $this->constHandling;
271
    }
272
273
    /**
274
     * This is used at run time to check whether method calls are allowed or not.
275
     *
276
     * @param Core   $dwoo   dwoo instance that calls this
277
     * @param object $obj    any object on which the method must be called
278
     * @param string $method lowercased method name
279
     * @param array  $args   arguments array
280
     *
281
     * @return mixed result of method call or unll + E_USER_NOTICE if not allowed
282
     */
283
    public function callMethod(Core $dwoo, $obj, $method, $args)
284
    {
285
        foreach ($this->allowedMethods as $class => $methods) {
286
            if (!isset($methods[$method])) {
287
                continue;
288
            }
289
            if ($obj instanceof $class) {
290
                return call_user_func_array(array($obj, $method), $args);
291
            }
292
        }
293
        $dwoo->triggerError('The current security policy prevents you from calling ' . get_class($obj) . '::' . $method . '()');
294
295
        return null;
296
    }
297
298
    /**
299
     * This is used at compile time to check whether static method calls are allowed or not.
300
     *
301
     * @param mixed  $class  lowercased class name or array('class', 'method') couple
302
     * @param string $method lowercased method name
303
     *
304
     * @return bool
305
     */
306
    public function isMethodAllowed($class, $method = null)
307
    {
308
        if (is_array($class)) {
309
            list($class, $method) = $class;
310
        }
311
        foreach ($this->allowedMethods as $allowedClass => $methods) {
312
            if (!isset($methods[$method])) {
313
                continue;
314
            }
315
            if ($class === $allowedClass || is_subclass_of($class, $allowedClass)) {
316
                return true;
317
            }
318
        }
319
320
        return false;
321
    }
322
}
323