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) |
64
|
1 |
|
&& $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 |
|
|
|
|
157
|
|
|
{ |
158
|
|
|
// Check if element has @Secured\Privilege annotation & hasn't @Secured\Resource annotation |
159
|
1 |
|
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
|
1 |
|
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
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.