Passed
Push — master ( 11e3a6...398838 )
by Fabio
06:26
created

TPermissionsAction::getPermissionsManager()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 7
c 1
b 0
f 0
nc 4
nop 0
dl 0
loc 12
rs 10
1
<?php
2
/**
3
 * TPermissionsAction class file
4
 *
5
 * @author Brad Anderson <[email protected]>
6
 * @link https://github.com/pradosoft/prado
7
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
8
 * @package Prado\Security\Permissions
9
 */
10
11
namespace Prado\Security\Permissions;
12
13
use Prado\Prado;
14
use Prado\Security\TAuthorizationRule;
15
use Prado\Shell\TShellAction;
16
use Prado\Shell\TShellWriter;
17
use Prado\TPropertyValue;
18
19
/**
20
 * TPermissionsAction class.
21
 *
22
 * The indexes, displays rolls with children and permissions rules, and can edit
23
 * Db roles, children and rules.
24
 *
25
 * @author Brad Anderson <belisoful[at]icloud[dot]com>
26
 * @package Prado\Security\Permissions
27
 * @since 4.2.0
28
 */
29
class TPermissionsAction extends TShellAction
30
{
31
	protected $action = 'perm';
32
	protected $methods = ['index', 'role', 'add-rule', 'remove-rule'];
33
	protected $parameters = [null, 'role-name', ['permission-name', 'action'], ['permission-name', 'db-rule-index']];
34
	protected $optional = [null, ['[+-]child', '...'], ['users', 'roles', 'verb', 'ips', 'priority', 'class'], null];
35
	protected $description = [
36
		'Provides information about Permissions.',
37
		'Displays DB permission information. \'-a\' for all.',
38
		'Add and remove children from roles in the DB.',
39
		'Add a rule to the DB for a specific permission.',
40
		'Remove a rule from the DB for a specific permission.'];
41
	
42
	private $_allPerms = false;
43
	
44
	private $_manager = false;
45
	
46
	/**
47
	 *
48
	 */
49
	public function getAll()
50
	{
51
		return $this->_allPerms;
52
	}
53
	
54
	/**
55
	 * @param bool $value If this is called, set the property to true
56
	 */
57
	public function setAll($value)
58
	{
59
		$this->_allPerms = TPropertyValue::ensureBoolean($value === '' ? true : $value);
0 ignored issues
show
introduced by
The condition $value === '' is always false.
Loading history...
60
	}
61
	
62
	/**
63
	 * Properties for the action set by parameter
64
	 * @param string $actionID the action being executed
65
	 * @return array properties for the $actionID
66
	 */
67
	public function options($actionID): array
68
	{
69
		if ($actionID === 'index') {
70
			return ['all'];
71
		}
72
		return [];
73
	}
74
	
75
	/**
76
	 * Aliases for the properties to be set by parameter
77
	 * @param string $actionID the action being executed
78
	 * @return array<alias, property> properties for the $actionID
79
	 */
80
	public function optionAliases(): array
81
	{
82
		return ['a' => 'all'];
0 ignored issues
show
Bug Best Practice introduced by
The expression return array('a' => 'all') returns the type array<string,string> which is incompatible with the documented return type Prado\Security\Permissions\property[].
Loading history...
83
	}
84
	
85
	/**
86
	 *
87
	 * @param mixed $rule
88
	 * @param null|mixed $writer
89
	 */
90
	protected function ruleToString($rule, $writer = null)
91
	{
92
		if (!$writer) {
93
			$writer = $this->getWriter();
94
		}
95
		$users = $rule->getUsers();
96
		if ($rule->getEveryoneApplied()) {
97
			$users[] = '*';
98
		} else {
99
			if ($rule->getAuthenticatedApplied()) {
100
				$users[] = '@';
101
			}
102
			if ($rule->getGuestApplied()) {
103
				$users[] = '?';
104
			}
105
		}
106
		
107
		return ($writer->format($a = $rule->getAction(), [TShellWriter::BOLD, $a === 'allow' ? TShellWriter::GREEN : TShellWriter::RED]) . ': ') .
108
			(get_class($rule) === 'Prado\\Security\\Permissions\\TUserOwnerRule' ? 'User Owner- ' : '') .
109
			(($p = $rule->getPriority()) ? '∆' . $p . ' ' : '') .
110
			(($users[0] !== '*') ? 'users="' . implode(', ', $users) . '" ' : '') .
111
			((($r = $rule->getRoles()) && (count($r) !== 1 || $r[0] !== '*')) ? 'roles="' . implode(', ', $r) . '" ' : '') .
112
			((($v = $rule->getVerb()) && $v !== '*') ? 'verb="' . $v . '" ' : '') .
113
			((($ip = $rule->getIPRules()) && (count($ip) !== 1 || $ip[0] !== '*')) ? 'ip="' . implode(', ', $ip) . '"' : '');
114
	}
115
	
116
	/**
117
	 * display the database parameter key values.
118
	 * @param array $args parameters
119
	 * @return bool is the action handled
120
	 */
121
	public function actionIndex($args)
0 ignored issues
show
Unused Code introduced by
The parameter $args 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

121
	public function actionIndex(/** @scrutinizer ignore-unused */ $args)

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...
122
	{
123
		$writer = $this->getWriter();
124
		if (!($manager = $this->getPermissionsManager())) {
125
			$writer->writeError('No TPermissionsManager found to report');
126
			return true;
127
		}
128
		
129
		$writer->writeLine();
130
		$writer->writeLine('Permissions Manager Information', TShellWriter::UNDERLINE);
131
		$writer->writeLine();
132
		$writer->writeLine('Super Roles: ' . implode(', ', $manager->getSuperRoles() ?? ['(none)']));
133
		$writer->writeLine('Default Roles: ' . implode(', ', $manager->getDefaultRoles() ?? ['(none)']));
134
		
135
		$dbConfigRoles = $manager->getDbConfigRoles();
136
		$dbConfigRules = $manager->getDbConfigPermissionRules();
137
		$roles = $this->getAll() ? $manager->getHierarchyRoleChildren(null) : $dbConfigRoles;
138
		$rules = $this->getAll() ? $manager->getPermissionRules(null) : $dbConfigRules;
139
		$len = 0;
140
		foreach ($roles as $role => $children) {
141
			if (($l = strlen($role)) > $len) {
142
				$len = $l;
143
			}
144
		}
145
		$writer->writeLine();
146
		$writer->write("    ");
147
		$writer->writeLine('Roles:', TShellWriter::UNDERLINE);
148
		foreach ($roles as $role => $children) {
149
			$writer->write($writer->pad($role, $len + 1));
150
			$writer->writeLine($writer->wrapText(implode(', ', $children), $len + 1));
151
		}
152
		
153
		$len = 0;
154
		foreach ($rules as $permName => $permRules) {
155
			if (($l = strlen($permName)) > $len) {
156
				$len = $l;
157
			}
158
		}
159
		$writer->writeLine();
160
		$writer->write("    ");
161
		$writer->writeLine('Permission Rules:', TShellWriter::UNDERLINE);
162
		foreach ($rules as $name => $collection) {
163
			$writer->write($writer->pad($name, $len + 1));
164
			$rules[$name] = [];
165
			$i = 0;
166
			foreach ($collection as $key => $rule) {
167
				$rules[$name][] = '#' . ($i++) . ' ' . $this->ruleToString($rule, $writer);
168
			}
169
			$writer->writeLine($writer->wrapText(implode("\n", $rules[$name]), $len + 1));
170
			$writer->writeLine();
171
		}
172
		$writer->writeLine();
173
		return true;
174
	}
175
	
176
	/**
177
	 * get children of a role, and adds to and removes children from a db configuration.
178
	 * @param array $args parameters
179
	 * @return bool is the action handled
180
	 */
181
	public function actionRole($args)
182
	{
183
		$writer = $this->getWriter();
184
		
185
		if (!($manager = $this->getPermissionsManager())) {
186
			$writer->writeError('No TPermissionsManager found to view and edit permissions');
187
			return true;
188
		}
189
		
190
		if (!$manager->getDbParameter()) {
191
			$writer->writeError('TPermissionsManager has no DbParameter to store db permissions configurations');
192
			return true;
193
		}
194
		
195
		$writer->writeLine();
196
		
197
		if (!($role = ($args[1] ?? null))) {
198
			$writer->writeError('Action requires <role-name> to view and edit');
199
			return true;
200
		}
201
		$role = strtolower($role);
202
		$diff_children = [];
203
		$merge_children = [];
204
		for ($i = 2; $i < count($args); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
205
			if ($args[$i][0] === '-') {
206
				$diff_children[] = substr($args[$i], 1);
207
			} else {
208
				$merge_children[] = substr($args[$i], $args[$i][0] === '+' ? 1 : 0);
209
			}
210
		}
211
		if ($merge_children) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $merge_children of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
introduced by
$merge_children is an empty array, thus is always false.
Loading history...
212
			if (!$manager->addRoleChildren($role, $merge_children)) {
213
				$writer->writeError('Could not add role children');
214
				return true;
215
			}
216
		}
217
		if ($diff_children) {
218
			if (!$manager->removeRoleChildren($role, $diff_children)) {
219
				$writer->writeError('Could not remove role children');
220
				return true;
221
			}
222
		}
223
		if ($merge_children || $diff_children) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $merge_children of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
224
			$writer->writeLine("   Role Children Change Successful", [TShellWriter::GREEN, TShellWriter::BOLD]);
225
			$writer->writeLine();
226
		}
227
		$roles = $manager->getDbConfigRoles();
228
		$writer->write("    ");
229
		$writer->writeLine('Current Db Role and Children', TShellWriter::UNDERLINE);
230
		
231
		$writer->write($role, [TShellWriter::BOLD, TShellWriter::BLUE]);
232
		$writer->write(' ');
233
		if (!($roles[$role] ?? null)) {
234
			$writer->write('(no children)', TShellWriter::DARK_GRAY);
235
		} else {
236
			$writer->writeLine($writer->wrapText(implode(", ", $roles[$role] ?? []), strlen($role) + 1));
237
		}
238
		$writer->writeLine();
239
		$writer->writeLine();
240
		return true;
241
	}
242
	
243
	/**
244
	 * adds a DB Configuration Permission Rule.  Here is the format of the function
245
	 * arguments.
246
	 * 'perm/add-rule' permission_name action users roles verb ips priority
247
	 * and can be use like this:
248
	 * <code>
249
	 * 	prado-cli perm/add-rule '*' deny '*' 'Default' '*' '192.168.*' 1000
250
	 * </code>
251
	 * @param array $args parameters
252
	 * @return bool is the action handled
253
	 */
254
	public function actionAddRule($args)
255
	{
256
		$writer = $this->getWriter();
257
		
258
		if (!($manager = $this->getPermissionsManager())) {
259
			$writer->writeError('No TPermissionsManager found to view and edit permissions');
260
			return true;
261
		}
262
		if (!$manager->getDbParameter()) {
263
			$writer->writeError('TPermissionsManager has no DbParameter to store db permissions configurations');
264
			return true;
265
		}
266
		
267
		if (!($name = ($args[1] ?? null))) {
268
			$writer->writeError('Permissions needs a name to add a rule');
269
			return true;
270
		}
271
		$name = strtolower($name);
272
		if (!($action = strtolower($args[2] ?? ''))) {
273
			$writer->writeError('Permissions needs an action [allow, deny] to add the rule');
274
			return true;
275
		}
276
		if (!in_array($action, ['allow', 'deny'])) {
277
			$writer->writeError("Permissions action '{$action}' is not [allow, deny]");
278
			return true;
279
		}
280
		$users = $args[3] ?? null;
281
		$roles = $args[4] ?? null;
282
		$verb = $args[5] ?? null;
283
		$ips = $args[6] ?? null;
284
		$priority = (!is_numeric($args[7] ?? null)) ? null : $args[7];
285
		$class = $args[8] ?? 'Prado\\Security\\TAuthorizationRule';
286
		
287
		if (!$users) {
288
			$users = '*';
289
		}
290
		if (!$roles) {
291
			$roles = '*';
292
		}
293
		if (!$verb) {
294
			$verb = '*';
295
		}
296
		if (!in_array($verb, ['*', 'get', 'post'])) {
297
			$writer->writeError("Permissions verb '{$verb}' is not [*, get, post]");
298
			return true;
299
		}
300
		if (!$ips) {
301
			$ips = '*';
302
		}
303
		
304
		$rule = Prado::createComponent($class, $action, $users, $roles, $verb, $ips, $priority);
305
		
306
		if (!$manager->addPermissionRule($name, $rule)) {
307
			$writer->writeError('Could not add permission rule');
308
			return true;
309
		}
310
		$writer->writeLine();
311
		$writer->writeLine("   Added Permission Rule Successful", [TShellWriter::GREEN, TShellWriter::BOLD]);
312
		
313
		$dbConfigRules = $manager->getDbConfigPermissionRules();
314
		
315
		$writer->writeLine();
316
		$writer->write("    ");
317
		$writer->writeLine("Permission Rules for '{$name}':", TShellWriter::UNDERLINE);
318
		foreach ($dbConfigRules[$name] as $key => $rule) {
319
			$writer->writeLine($writer->wrapText('#' . ($key) . ' ' . $this->ruleToString($rule, $writer), 10));
320
		}
321
		$writer->writeLine();
322
		
323
		return true;
324
	}
325
	
326
	/**
327
	 * removes a DB Configuration Permission Rule
328
	 * @param array $args parameters
329
	 * @return bool is the action handled
330
	 */
331
	public function actionRemoveRule($args)
332
	{
333
		$writer = $this->getWriter();
334
		
335
		if (!($manager = $this->getPermissionsManager())) {
336
			$writer->writeError('No TPermissionsManager found to view and edit permissions');
337
			return true;
338
		}
339
		
340
		if (!$manager->getDbParameter()) {
341
			$writer->writeError('TPermissionsManager has no DbParameter to store db permissions configurations');
342
			return true;
343
		}
344
		
345
		if (!($name = ($args[1] ?? null))) {
346
			$writer->writeError('Permissions needs a name to remove a rule');
347
			return true;
348
		}
349
		$name = strtolower($name);
350
		if (!is_numeric($index = ($args[2] ?? null))) {
351
			$writer->writeError("Permission rule index '{$index}' is not valid");
352
			return true;
353
		}
354
		
355
		$dbConfigRules = $manager->getDbConfigPermissionRules();
356
		
357
		if (!isset($dbConfigRules[$name])) {
358
			$writer->writeError('No rules for specified permission');
359
			return true;
360
		}
361
		if (!isset($dbConfigRules[$name][$index])) {
362
			$writer->writeError("No rule at index '{$index}' for specified permission '{$name}'");
363
			return true;
364
		}
365
		
366
		if (!$manager->removePermissionRule($name, $dbConfigRules[$name][$index])) {
367
			$writer->writeError('Could not add permission rule');
368
			return true;
369
		}
370
		$writer->writeLine();
371
		$writer->writeLine("Remove Permission Rule Successful", [TShellWriter::GREEN, TShellWriter::BOLD]);
372
373
		$dbConfigRules = $manager->getDbConfigPermissionRules();
374
		
375
		$writer->writeLine();
376
		$writer->write("    ");
377
		$writer->writeLine("Permission Rules for '{$name}':", TShellWriter::UNDERLINE);
378
		if (isset($dbConfigRules[$name])) {
379
			foreach ($dbConfigRules[$name] as $key => $rule) {
380
				$writer->writeLine($writer->wrapText('#' . ($key) . ' ' . $this->ruleToString($rule, $writer), 10));
381
			}
382
		} else {
383
			$writer->writeLine("(No Rules for Permission)", TShellWriter::DARK_GRAY);
384
		}
385
386
		$writer->writeLine();
387
		
388
		return true;
389
	}
390
	
391
	/**
392
	 * get the TPermissionsManager
393
	 * @return Prado\Security\Permissions\TPermissionsManager
0 ignored issues
show
Bug introduced by
The type Prado\Prado\Security\Per...ons\TPermissionsManager 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...
394
	 */
395
	public function getPermissionsManager()
396
	{
397
		if ($this->_manager === false) {
398
			$this->_manager = null;
399
			$app = Prado::getApplication();
400
			foreach ($app->getModulesByType('Prado\\Security\\Permissions\\TPermissionsManager') as $id => $module) {
401
				if ($this->_manager = $app->getModule($id)) {
402
					break;
403
				}
404
			}
405
		}
406
		return $this->_manager;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_manager also could return the type Prado\TModule|true which is incompatible with the documented return type Prado\Prado\Security\Per...ons\TPermissionsManager.
Loading history...
407
	}
408
	
409
	/**
410
	 * get the TPermissionsManager from the Application
411
	 * @param Prado\Security\Permissions\TPermissionsManager $manager
412
	 */
413
	public function setPermissionsManager($manager)
414
	{
415
		$this->_manager = $manager;
416
	}
417
}
418