Completed
Push — master ( 7e98b2...89d085 )
by Adam
02:18
created

src/IPub/Permissions/Access/AnnotationChecker.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * AnnotationChecker.php
4
 *
5
 * @copyright      More in license.md
6
 * @license        http://www.ipublikuj.eu
7
 * @author         Adam Kadlec http://www.ipublikuj.eu
8
 * @package        iPublikuj:Permissions!
9
 * @subpackage     Access
10
 * @since          1.0.0
11
 *
12
 * @date           13.10.14
13
 */
14
15
declare(strict_types = 1);
16
17
namespace IPub\Permissions\Access;
18
19
use Nette;
20
use Nette\Application\UI;
21
use Nette\Utils;
22
use Nette\Security as NS;
23
24
use IPub;
25
use IPub\Permissions\Entities;
26
use IPub\Permissions\Exceptions;
27
use IPub\Permissions\Security;
28
29
/**
30
 * Presenter & component annotation access checker
31
 *
32
 * @package        iPublikuj:Permissions!
33
 * @subpackage     Access
34
 *
35
 * @author         Adam Kadlec <[email protected]>
36
 */
37 1
final class AnnotationChecker extends Nette\Object implements IChecker, ICheckRequirements
38
{
39
	/**
40
	 * @var NS\User
41
	 */
42
	private $user;
43
44
	/**
45
	 * @param NS\User $user
46
	 */
47
	public function __construct(NS\User $user)
48
	{
49 1
		$this->user = $user;
50 1
	}
51
52
	/**
53
	 * {@inheritdoc}
54
	 */
55
	public function isAllowed($element) : bool
56
	{
57
		// Check annotations only if element have to be secured
58
		if (
59 1
			($element instanceof UI\ComponentReflection || $element instanceof UI\MethodReflection)
60 1
			&& $element->hasAnnotation('Secured')
61
		) {
62 1
			return $this->checkUser($element)
63 1
			&& $this->checkResources($element)/*
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
64
			&& $this->checkPrivileges($element)*/
65 1
			&& $this->checkPermission($element)
66 1
			&& $this->checkRoles($element);
67
68
		} else {
69 1
			return TRUE;
70
		}
71
	}
72
73
	/**
74
	 * @param UI\ComponentReflection|UI\MethodReflection $element
75
	 *
76
	 * @return bool
77
	 *
78
	 * @throws Exceptions\InvalidArgumentException
79
	 */
80 View Code Duplication
	private function checkUser($element) : bool
81
	{
82
		// Check if element has @Secured\User annotation
83 1
		if ($element->hasAnnotation('Secured\User')) {
84
			// Get user annotation
85 1
			$user = $element->getAnnotation('Secured\User');
86
87
			// Annotation is single string
88 1
			if (is_string($user) && in_array($user, ['loggedIn', 'guest'], TRUE)) {
89
				// User have to be logged in and is not
90 1
				if ($user === 'loggedIn' && $this->user->isLoggedIn() === FALSE) {
91
					return FALSE;
92
93
				// User have to be logged out and is logged in
94 1
				} elseif ($user === 'guest' && $this->user->isLoggedIn() === TRUE) {
95 1
					return FALSE;
96
				}
97
98
			// Annotation have wrong definition
99
			} else {
100
				throw new Exceptions\InvalidArgumentException('In @Security\User annotation is allowed only one from two strings: \'loggedIn\' & \'guest\'');
101
			}
102
103 1
			return TRUE;
104
		}
105
106 1
		return TRUE;
107
	}
108
109
	/**
110
	 * @param UI\ComponentReflection|UI\MethodReflection $element
111
	 *
112
	 * @return bool
113
	 *
114
	 * @throws Exceptions\InvalidStateException
115
	 */
116
	private function checkResources($element) : bool
117
	{
118
		// Check if element has @Security\Resource annotation & @Secured\Privilege annotation
119 1
		if ($element->hasAnnotation('Secured\Resource')) {
120 1
			$resources = UI\ComponentReflection::parseAnnotation($element, 'Secured\Resource');
121
122 1
			if (count($resources) != 1) {
123
				throw new Exceptions\InvalidStateException('Invalid resources count in @Security\Resource annotation!');
124
			}
125
126 1
			$privileges = UI\ComponentReflection::parseAnnotation($element, 'Secured\Privilege');
127
128 1 View Code Duplication
			foreach ($resources as $resource) {
129 1
				if ($privileges !== FALSE) {
130 1
					foreach ($privileges as $privilege) {
131 1
						if ($this->user->isAllowed($resource, $privilege)) {
132 1
							return TRUE;
133
						}
134
					}
135
136
				} else {
137
					if ($this->user->isAllowed($resource)) {
138
						return TRUE;
139
					}
140
				}
141
			}
142
143
			return FALSE;
144
		}
145
146 1
		return TRUE;
147
	}
148
149
	/**
150
	 * @param UI\ComponentReflection|UI\MethodReflection $element
151
	 *
152
	 * @return bool
153
	 *
154
	 * @throws Exceptions\InvalidStateException
155
	 */
156 View Code Duplication
	private function checkPrivileges($element) : bool
0 ignored issues
show
This method is not used, and could be removed.
Loading history...
157
	{
158
		// Check if element has @Secured\Privilege annotation & hasn't @Secured\Resource annotation
159
		if (!$element->hasAnnotation('Secured\Resource') && $element->hasAnnotation('Secured\Privilege')) {
160
			$privileges = UI\ComponentReflection::parseAnnotation($element, 'Secured\Privilege');
161
162
			if (count($privileges) != 1) {
163
				throw new Exceptions\InvalidStateException('Invalid privileges count in @Security\Privilege annotation!');
164
			}
165
166
			foreach ($privileges as $privilege) {
167
				// Check if privilege name is defined
168
				if ($privilege === TRUE) {
169
					continue;
170
				}
171
172
				if ($this->user->isAllowed(NS\IAuthorizator::ALL, $privilege)) {
173
					return TRUE;
174
				}
175
			}
176
177
			return FALSE;
178
		}
179
180
		return TRUE;
181
	}
182
183
	/**
184
	 * @param UI\ComponentReflection|UI\MethodReflection $element
185
	 *
186
	 * @return bool
187
	 */
188 View Code Duplication
	private function checkPermission($element) : bool
189
	{
190
		// Check if element has @Secured\Permission annotation
191 1
		if ($element->hasAnnotation('Secured\Permission')) {
192 1
			$permissions = UI\ComponentReflection::parseAnnotation($element, 'Secured\Permission');
193
194 1
			foreach ($permissions as $permission) {
195
				// Check if parameters are defined
196 1
				if ($permission === TRUE) {
197
					continue;
198
				}
199
200
				// Parse resource & privilege from permission
201 1
				list($resource, $privilege) = explode(Entities\IPermission::DELIMITER, $permission);
202
203
				// Remove white spaces
204 1
				$resource = Utils\Strings::trim($resource);
205 1
				$privilege = Utils\Strings::trim($privilege);
206
207 1
				if ($this->user->isAllowed($resource, $privilege)) {
208 1
					return TRUE;
209
				}
210
			}
211
212
			return FALSE;
213
		}
214
215 1
		return TRUE;
216
	}
217
218
	/**
219
	 * @param UI\ComponentReflection|UI\MethodReflection $element
220
	 *
221
	 * @return bool
222
	 */
223
	private function checkRoles($element) : bool
224
	{
225
		// Check if element has @Secured\Role annotation
226 1
		if ($element->hasAnnotation('Secured\Role')) {
227 1
			$roles = UI\ComponentReflection::parseAnnotation($element, 'Secured\Role');
228
229 1
			foreach ($roles as $role) {
230
				// Check if role name is defined
231 1
				if ($role === TRUE) {
232
					continue;
233
				}
234
235 1
				if ($this->user->isInRole($role)) {
236 1
					return TRUE;
237
				}
238
			}
239
240 1
			return FALSE;
241
		}
242
243 1
		return TRUE;
244
	}
245
}
246