TAuthorizationRule::__construct()   F
last analyzed

Complexity

Conditions 25
Paths 1249

Size

Total Lines 63
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 650

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 25
eloc 42
c 2
b 0
f 0
nc 1249
nop 6
dl 0
loc 63
ccs 0
cts 55
cp 0
crap 650
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * TAuthorizationRule, TAuthorizationRuleCollection class file
5
 *
6
 * @author Qiang Xue <[email protected]>
7
 * @link https://github.com/pradosoft/prado
8
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
9
 */
10
11
namespace Prado\Security;
12
13
use Prado\Exceptions\TInvalidDataValueException;
14
15
/**
16
 * TAuthorizationRule class
17
 *
18
 * TAuthorizationRule represents a single authorization rule.
19
 * A rule is specified by an action (required), a list of users (optional),
20
 * a list of roles (optional), a verb (optional), and a list of IP rules (optional).
21
 * Action can be either 'allow' or 'deny'.
22
 * Guest (anonymous, unauthenticated) users are represented by question mark '?'.
23
 * All users (including guest users) are represented by asterisk '*'.
24
 * Authenticated users are represented by '@'.
25
 * Users/roles are case-insensitive.
26
 * Different users/roles are separated by comma ','.
27
 * Verb can be either 'get' or 'post'. If it is absent, it means both.
28
 * IP rules are separated by comma ',' and can contain wild card in the rules (e.g. '192.132.23.33, 192.122.*.*')
29
 *
30
 * @author Qiang Xue <[email protected]>
31
 * @since 3.0
32
 */
33
class TAuthorizationRule extends \Prado\TComponent implements \Prado\Collections\IPriorityItem
34
{
35
	/**
36
	 * @var string action, either 'allow' or 'deny'
37
	 */
38
	private $_action = 'allow';
39
	/**
40
	 * @var array list of user IDs
41
	 */
42
	private $_users = [];
43
	/**
44
	 * @var array list of roles
45
	 */
46
	private $_roles = ['*'];
47
	/**
48
	 * @var string verb, may be empty, 'get', or 'post'.
49
	 */
50
	private $_verb = '*';
51
	/**
52
	 * @var string IP patterns
53
	 */
54
	private $_ipRules = ['*'];
55
	/**
56
	 * @var numeric priority of the rule
0 ignored issues
show
Bug introduced by
The type Prado\Security\numeric was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
57
	 */
58
	private $_priority;
59
	/**
60
	 * @var bool if this rule applies to everyone
61
	 */
62
	private $_everyone = true;
63
	/**
64
	 * @var bool if this rule applies to guest user
65
	 */
66
	private $_guest = false;
67
	/**
68
	 * @var bool if this rule applies to authenticated users
69
	 */
70
	private $_authenticated = false;
71
72
	/**
73
	 * Constructor.
74
	 * @param string $action action, either 'deny' or 'allow'
75
	 * @param string $users a comma separated user list
76
	 * @param string $roles a comma separated role list
77
	 * @param string $verb verb, can be empty, 'get', or 'post'
78
	 * @param string $ipRules IP rules (separated by comma, can contain wild card *)
79
	 * @param null|numeric $priority
80
	 */
81
	public function __construct($action = 'allow', $users = '', $roles = '', $verb = '', $ipRules = '', $priority = null)
82
	{
83
		$action = strtolower(trim($action));
84
		if ($action === 'allow' || $action === 'deny') {
85
			$this->_action = $action;
86
		} else {
87
			throw new TInvalidDataValueException('authorizationrule_action_invalid', $action);
88
		}
89
90
		$this->_users = [];
91
		$this->_everyone = false;
92
		$this->_guest = false;
93
		$this->_authenticated = false;
94
		if ($users === null || trim($users) === '') {
95
			$users = '*';
96
		}
97
		foreach (explode(',', $users) as $user) {
98
			if (($user = trim(strtolower($user))) !== '') {
99
				if ($user === '*') {
100
					$this->_everyone = true;
101
					break;
102
				} elseif ($user === '?') {
103
					$this->_guest = true;
104
				} elseif ($user === '@') {
105
					$this->_authenticated = true;
106
				} else {
107
					$this->_users[] = $user;
108
				}
109
			}
110
		}
111
112
		$this->_roles = [];
113
		if ($roles === null || trim($roles) === '') {
114
			$roles = '*';
115
		}
116
		foreach (explode(',', $roles) as $role) {
117
			if (($role = trim(strtolower($role))) !== '') {
118
				$this->_roles[] = $role;
119
			}
120
		}
121
122
		if ($verb === null || ($verb = trim(strtolower($verb))) === '') {
123
			$verb = '*';
124
		}
125
		if ($verb === '*' || $verb === 'get' || $verb === 'post') {
126
			$this->_verb = $verb;
127
		} else {
128
			throw new TInvalidDataValueException('authorizationrule_verb_invalid', $verb);
129
		}
130
131
		$this->_ipRules = [];
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type string of property $_ipRules.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
132
		if ($ipRules === null || trim($ipRules) === '') {
133
			$ipRules = '*';
134
		}
135
		foreach (explode(',', $ipRules) as $ipRule) {
136
			if ($ipRule !== null && ($ipRule = trim($ipRule)) !== '') {
137
				$this->_ipRules[] = $ipRule;
138
			}
139
		}
140
141
		$this->_priority = is_numeric($priority) ? $priority : null;
0 ignored issues
show
introduced by
The condition is_numeric($priority) is always false.
Loading history...
142
143
		parent::__construct();
144
	}
145
146
	/**
147
	 * @return string action, either 'allow' or 'deny'
148
	 */
149
	public function getAction()
150
	{
151
		return $this->_action;
152
	}
153
154
	/**
155
	 * @return string[] list of user IDs
156
	 */
157
	public function getUsers()
158
	{
159
		return $this->_users;
160
	}
161
162
	/**
163
	 * @return string[] list of roles
164
	 */
165
	public function getRoles()
166
	{
167
		return $this->_roles;
168
	}
169
170
	/**
171
	 * @return string verb, may be '*', 'get', or 'post'.
172
	 */
173
	public function getVerb()
174
	{
175
		return $this->_verb;
176
	}
177
178
	/**
179
	 * @return array list of IP rules.
180
	 * @since 3.1.1
181
	 */
182
	public function getIPRules()
183
	{
184
		return $this->_ipRules;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_ipRules returns the type string which is incompatible with the documented return type array.
Loading history...
185
	}
186
187
	/**
188
	 * @return numeric priority of the rule.
189
	 * @since 4.2.0
190
	 */
191
	public function getPriority()
192
	{
193
		return $this->_priority;
194
	}
195
196
	/**
197
	 * @return bool if this rule applies to everyone
198
	 */
199
	public function getGuestApplied()
200
	{
201
		return $this->_guest || $this->_everyone;
202
	}
203
204
	/**
205
	 * @return bool if this rule applies to everyone
206
	 */
207
	public function getEveryoneApplied()
208
	{
209
		return $this->_everyone;
210
	}
211
212
	/**
213
	 * @return bool if this rule applies to authenticated users
214
	 */
215
	public function getAuthenticatedApplied()
216
	{
217
		return $this->_authenticated || $this->_everyone;
218
	}
219
220
	/**
221
	 * @param IUser $user the user object
222
	 * @param string $verb the request verb (GET, PUT)
223
	 * @param string $ip the request IP address
224
	 * @param null|mixed $extra
225
	 * @return int 1 if the user is allowed, -1 if the user is denied, 0 if the rule does not apply to the user
226
	 */
227
	public function isUserAllowed(IUser $user, $verb, $ip, $extra = null)
0 ignored issues
show
Unused Code introduced by
The parameter $extra is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

227
	public function isUserAllowed(IUser $user, $verb, $ip, /** @scrutinizer ignore-unused */ $extra = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
228
	{
229
		if ($this->isVerbMatched($verb) && $this->isIpMatched($ip) && $this->isUserMatched($user) && $this->isRoleMatched($user)) {
230
			return ($this->_action === 'allow') ? 1 : -1;
231
		} else {
232
			return 0;
233
		}
234
	}
235
236
	private function isIpMatched($ip)
237
	{
238
		if (empty($this->_ipRules)) {
239
			return 1;
240
		}
241
		foreach ($this->_ipRules as $rule) {
0 ignored issues
show
Bug introduced by
The expression $this->_ipRules of type string is not traversable.
Loading history...
242
			if ($rule === '*' || $rule === $ip || (($pos = strpos($rule, '*')) !== false && strncmp($ip, $rule, $pos) === 0)) {
243
				return 1;
244
			}
245
		}
246
		return 0;
247
	}
248
249
	private function isUserMatched($user)
250
	{
251
		return ($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest()) || in_array(strtolower($user->getName()), $this->_users));
252
	}
253
254
	private function isRoleMatched($user)
255
	{
256
		foreach ($this->_roles as $role) {
257
			if ($role === '*' || $user->isInRole($role)) {
258
				return true;
259
			}
260
		}
261
		return false;
262
	}
263
264
	private function isVerbMatched($verb)
265
	{
266
		return ($this->_verb === '*' || strcasecmp($verb, $this->_verb) === 0);
267
	}
268
269
	/**
270
	 * Returns an array with the names of all variables of this object that should NOT be serialized
271
	 * because their value is the default one or useless to be cached for the next load.
272
	 * Reimplement in derived classes to add new variables, but remember to also to call the parent
273
	 * implementation first.
274
	 * @param array $exprops by reference
275
	 */
276
	protected function _getZappableSleepProps(&$exprops)
277
	{
278
		parent::_getZappableSleepProps($exprops);
279
280
		if ($this->_action === 'allow') {
281
			$exprops[] = "\0Prado\Security\TAuthorizationRule\0_action";
282
		}
283
		if ($this->_users === []) {
284
			$exprops[] = "\0Prado\Security\TAuthorizationRule\0_users";
285
		}
286
		if (count($this->_roles) === 1 && $this->_roles[0] === '*') {
287
			$exprops[] = "\0Prado\Security\TAuthorizationRule\0_roles";
288
		}
289
		if ($this->_verb === '*') {
290
			$exprops[] = "\0Prado\Security\TAuthorizationRule\0_verb";
291
		}
292
		if (count($this->_ipRules) === 1 && $this->_ipRules[0] === '*') {
0 ignored issues
show
Bug introduced by
$this->_ipRules of type string is incompatible with the type Countable|array expected by parameter $value of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

292
		if (count(/** @scrutinizer ignore-type */ $this->_ipRules) === 1 && $this->_ipRules[0] === '*') {
Loading history...
293
			$exprops[] = "\0Prado\Security\TAuthorizationRule\0_ipRules";
294
		}
295
		if ($this->_everyone == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
296
			$exprops[] = "\0Prado\Security\TAuthorizationRule\0_everyone";
297
		}
298
		if ($this->_guest == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
299
			$exprops[] = "\0Prado\Security\TAuthorizationRule\0_guest";
300
		}
301
		if ($this->_authenticated == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
302
			$exprops[] = "\0Prado\Security\TAuthorizationRule\0_authenticated";
303
		}
304
		if ($this->_priority === null) {
305
			$exprops[] = "\0Prado\Security\TAuthorizationRule\0_priority";
306
		}
307
	}
308
}
309