1 | <?php |
||||||||||
2 | /** |
||||||||||
3 | * This file is part of the O2System Framework package. |
||||||||||
4 | * |
||||||||||
5 | * For the full copyright and license information, please view the LICENSE |
||||||||||
6 | * file that was distributed with this source code. |
||||||||||
7 | * |
||||||||||
8 | * @author Steeve Andrian Salim |
||||||||||
9 | * @copyright Copyright (c) Steeve Andrian Salim |
||||||||||
10 | */ |
||||||||||
11 | |||||||||||
12 | // ------------------------------------------------------------------------ |
||||||||||
13 | |||||||||||
14 | namespace O2System\Framework\Services; |
||||||||||
15 | |||||||||||
16 | // ------------------------------------------------------------------------ |
||||||||||
17 | |||||||||||
18 | use O2System\Security\Authentication\User\Account; |
||||||||||
19 | use O2System\Security\Authentication\User\Role; |
||||||||||
20 | use O2System\Spl\Exceptions\RuntimeException; |
||||||||||
21 | |||||||||||
22 | /** |
||||||||||
23 | * Class AccessControl |
||||||||||
24 | * @package O2System\Framework\Services |
||||||||||
25 | */ |
||||||||||
26 | class AccessControl extends \O2System\Security\Authentication\User |
||||||||||
27 | { |
||||||||||
28 | /** |
||||||||||
29 | * User::$app |
||||||||||
30 | * |
||||||||||
31 | * @var string |
||||||||||
32 | */ |
||||||||||
33 | protected $app = 'app'; |
||||||||||
34 | |||||||||||
35 | /** |
||||||||||
36 | * User::__construct |
||||||||||
37 | * |
||||||||||
38 | * @throws \O2System\Spl\Exceptions\RuntimeException |
||||||||||
39 | */ |
||||||||||
40 | public function __construct() |
||||||||||
41 | { |
||||||||||
42 | parent::__construct(); |
||||||||||
43 | |||||||||||
44 | if ($config = config()->loadFile('AccessControl', true)) { |
||||||||||
0 ignored issues
–
show
|
|||||||||||
45 | $this->setConfig($config->getArrayCopy()); |
||||||||||
46 | } |
||||||||||
47 | |||||||||||
48 | if ( ! models('users')) { |
||||||||||
49 | throw new RuntimeException('ACL_E_UNDEFINED_USERS_MODEL'); |
||||||||||
50 | } |
||||||||||
51 | } |
||||||||||
52 | |||||||||||
53 | // ------------------------------------------------------------------------ |
||||||||||
54 | |||||||||||
55 | /** |
||||||||||
56 | * User::setApp |
||||||||||
57 | * |
||||||||||
58 | * @param string $app |
||||||||||
59 | * |
||||||||||
60 | * @return static |
||||||||||
61 | */ |
||||||||||
62 | public function setApp($app) |
||||||||||
63 | { |
||||||||||
64 | if ($app = modules()->getApp($app)) { |
||||||||||
0 ignored issues
–
show
The method
getApp() does not exist on O2System\Framework\Conta...s\DataStructures\Module .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||||||
65 | $this->app = $app; |
||||||||||
0 ignored issues
–
show
It seems like
$app can also be of type true . However, the property $app is declared as type string . Maybe add an additional type check?
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly. For example, imagine you have a variable Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||||||||||
66 | } |
||||||||||
67 | |||||||||||
68 | return $this; |
||||||||||
69 | } |
||||||||||
70 | |||||||||||
71 | // ------------------------------------------------------------------------ |
||||||||||
72 | |||||||||||
73 | /** |
||||||||||
74 | * User::authenticate |
||||||||||
75 | * |
||||||||||
76 | * @param string $username |
||||||||||
77 | * @param string $password |
||||||||||
78 | * |
||||||||||
79 | * @return bool |
||||||||||
80 | */ |
||||||||||
81 | public function authenticate($username, $password) |
||||||||||
82 | { |
||||||||||
83 | if ($user = $this->find($username)) { |
||||||||||
84 | if ($user->account) { |
||||||||||
85 | if ($this->passwordVerify($password, $user->account->password)) { |
||||||||||
86 | if ($this->passwordRehash($password)) { |
||||||||||
87 | $user->account->update([ |
||||||||||
88 | 'id' => $user->id, |
||||||||||
89 | 'password' => $this->passwordHash($password), |
||||||||||
90 | ]); |
||||||||||
91 | } |
||||||||||
92 | |||||||||||
93 | $account = $user->account->getArrayCopy(); |
||||||||||
94 | } |
||||||||||
95 | } elseif ($this->passwordVerify($password, $user->password)) { |
||||||||||
96 | $account = $user->getArrayCopy(); |
||||||||||
97 | } |
||||||||||
98 | |||||||||||
99 | if (isset($account)) { |
||||||||||
100 | foreach ($account as $key => $value) { |
||||||||||
101 | if (strpos($key, 'record') !== false) { |
||||||||||
102 | unset($account[ $key ]); |
||||||||||
103 | } elseif (in_array($key, |
||||||||||
104 | ['password', 'pin', 'token', 'sso', 'id_sys_user', 'id_sys_module', 'id_sys_module_role'])) { |
||||||||||
105 | unset($account[ $key ]); |
||||||||||
106 | } |
||||||||||
107 | } |
||||||||||
108 | |||||||||||
109 | $this->login($account); |
||||||||||
110 | |||||||||||
111 | return true; |
||||||||||
112 | } |
||||||||||
113 | } |
||||||||||
114 | |||||||||||
115 | return false; |
||||||||||
116 | } |
||||||||||
117 | |||||||||||
118 | // ------------------------------------------------------------------------ |
||||||||||
119 | |||||||||||
120 | /** |
||||||||||
121 | * User::find |
||||||||||
122 | * |
||||||||||
123 | * @param string $username |
||||||||||
124 | * |
||||||||||
125 | * @return bool|mixed|\O2System\Database\DataObjects\Result|\O2System\Framework\Models\Sql\DataObjects\Result |
||||||||||
126 | */ |
||||||||||
127 | public function find($username) |
||||||||||
128 | { |
||||||||||
129 | $column = 'username'; |
||||||||||
130 | if (is_numeric($username)) { |
||||||||||
131 | $column = 'id'; |
||||||||||
132 | } elseif (filter_var($username, FILTER_VALIDATE_EMAIL)) { |
||||||||||
133 | $column = 'email'; |
||||||||||
134 | } elseif (preg_match($this->config[ 'msisdnRegex' ], $username)) { |
||||||||||
135 | $column = 'msisdn'; |
||||||||||
136 | } |
||||||||||
137 | |||||||||||
138 | if ($user = models('users')->findWhere([ |
||||||||||
0 ignored issues
–
show
The method
findWhere() does not exist on O2System\Framework\Containers\Models .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||||||
139 | $column => $username, |
||||||||||
140 | ], 1)) { |
||||||||||
141 | return $user; |
||||||||||
142 | } |
||||||||||
143 | |||||||||||
144 | return false; |
||||||||||
145 | } |
||||||||||
146 | |||||||||||
147 | // ------------------------------------------------------------------------ |
||||||||||
148 | |||||||||||
149 | /** |
||||||||||
150 | * User::loggedIn |
||||||||||
151 | * |
||||||||||
152 | * @return bool |
||||||||||
153 | * @throws \Psr\Cache\InvalidArgumentException |
||||||||||
154 | */ |
||||||||||
155 | public function loggedIn() |
||||||||||
156 | { |
||||||||||
157 | if (parent::loggedIn()) { |
||||||||||
158 | if(is_object($_SESSION['account'])) { |
||||||||||
159 | $account = new Account($_SESSION['account']->getArrayCopy()); |
||||||||||
160 | $username = $account->user->username; |
||||||||||
161 | } else { |
||||||||||
162 | $account = new Account(); |
||||||||||
163 | $username = $_SESSION['account']['username']; |
||||||||||
164 | } |
||||||||||
165 | |||||||||||
166 | if ($user = models('users')->findWhere(['username' => $username], 1)) { |
||||||||||
167 | if ($profile = $user->profile) { |
||||||||||
168 | $account->store('profile', $profile); |
||||||||||
169 | } |
||||||||||
170 | |||||||||||
171 | if ($employee = $user->employee) { |
||||||||||
172 | $account->store('employee', $employee); |
||||||||||
173 | } |
||||||||||
174 | |||||||||||
175 | if ($member = $user->member) { |
||||||||||
176 | $account->store('member', $member); |
||||||||||
177 | } |
||||||||||
178 | |||||||||||
179 | if ($role = $user->role) { |
||||||||||
180 | $user->store('role', $role); |
||||||||||
0 ignored issues
–
show
The method
store() does not exist on O2System\Database\DataObjects\Result .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() The method
store() does not exist on O2System\Database\DataObjects\Result\Row .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||||||
181 | } |
||||||||||
182 | |||||||||||
183 | $account->store('user', $user); |
||||||||||
184 | |||||||||||
185 | session()->set('account', $account); |
||||||||||
186 | } |
||||||||||
187 | |||||||||||
188 | // Store Globals Account |
||||||||||
189 | globals()->store('account', $account); |
||||||||||
190 | |||||||||||
191 | // Store Presenter Account |
||||||||||
192 | if (services()->has('view')) { |
||||||||||
193 | presenter()->store('account', $account); |
||||||||||
194 | } |
||||||||||
195 | |||||||||||
196 | return true; |
||||||||||
197 | } |
||||||||||
198 | |||||||||||
199 | return false; |
||||||||||
200 | } |
||||||||||
201 | |||||||||||
202 | // ------------------------------------------------------------------------ |
||||||||||
203 | |||||||||||
204 | /** |
||||||||||
205 | * User::forceLogin |
||||||||||
206 | * |
||||||||||
207 | * @param string $username |
||||||||||
208 | * @param string $column |
||||||||||
209 | * |
||||||||||
210 | * @return bool |
||||||||||
211 | */ |
||||||||||
212 | public function forceLogin($username, $column = 'username') |
||||||||||
213 | { |
||||||||||
214 | if (is_numeric($username)) { |
||||||||||
215 | $column = 'id'; |
||||||||||
216 | } elseif (filter_var($username, FILTER_VALIDATE_EMAIL)) { |
||||||||||
217 | $column = 'email'; |
||||||||||
218 | } elseif (preg_match($this->config[ 'msisdnRegex' ], $username)) { |
||||||||||
219 | $column = 'msisdn'; |
||||||||||
220 | } elseif (strpos($username, 'token-') !== false) { |
||||||||||
221 | $username = str_replace('token-', '', $username); |
||||||||||
222 | $column = 'token'; |
||||||||||
223 | } elseif (strpos($username, 'sso-') !== false) { |
||||||||||
224 | $username = str_replace('sso-', '', $username); |
||||||||||
225 | $column = 'sso'; |
||||||||||
226 | } |
||||||||||
227 | |||||||||||
228 | if ($account = models('users')->findWhere([$column => $username], 1)) { |
||||||||||
229 | $account = $account->getArrayCopy(); |
||||||||||
230 | |||||||||||
231 | foreach ($account as $key => $value) { |
||||||||||
232 | if (strpos($key, 'record') !== false) { |
||||||||||
233 | unset($account[ $key ]); |
||||||||||
234 | } elseif (in_array($key, ['password', 'pin', 'token', 'sso'])) { |
||||||||||
235 | unset($account[ $key ]); |
||||||||||
236 | } |
||||||||||
237 | } |
||||||||||
238 | |||||||||||
239 | if ($column === 'token') { |
||||||||||
240 | models('users')->update([ |
||||||||||
0 ignored issues
–
show
The method
update() does not exist on O2System\Framework\Models\NoSql\Model .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() The method
update() does not exist on O2System\Framework\Containers\Models .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||||||
241 | 'id' => $account[ 'id' ], |
||||||||||
242 | 'token' => null, |
||||||||||
243 | ]); |
||||||||||
244 | } |
||||||||||
245 | |||||||||||
246 | $this->login($account); |
||||||||||
247 | |||||||||||
248 | return true; |
||||||||||
249 | } |
||||||||||
250 | |||||||||||
251 | return false; |
||||||||||
252 | } |
||||||||||
253 | |||||||||||
254 | // ------------------------------------------------------------------------ |
||||||||||
255 | |||||||||||
256 | /** |
||||||||||
257 | * User::hasAccess |
||||||||||
258 | * |
||||||||||
259 | * @param array $segments |
||||||||||
260 | * |
||||||||||
261 | * @return bool |
||||||||||
262 | */ |
||||||||||
263 | public function hasAccess(array $segments) |
||||||||||
264 | { |
||||||||||
265 | if ($this->loggedIn()) { |
||||||||||
266 | if ($account = globals()->offsetGet('account')) { |
||||||||||
267 | if (in_array($account->user->role->id, [1, 2])) { |
||||||||||
268 | return true; |
||||||||||
269 | } |
||||||||||
270 | |||||||||||
271 | if ($model = models('modules')) { |
||||||||||
272 | if ($segment = $model->segments->find(implode('/', $segments), 'segments')) { |
||||||||||
0 ignored issues
–
show
The method
find() does not exist on O2System\Framework\Model...\DataObjects\Result\Row . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() The method
find() does not exist on O2System\Framework\Models\Sql\DataObjects\Result .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() The property
segments does not exist on O2System\Framework\Models\NoSql\Model . Since you implemented __get , consider adding a @property annotation.
![]() The property
segments does not exist on O2System\Framework\Containers\Models . Since you implemented __get , consider adding a @property annotation.
![]() The property
segments does not exist on O2System\Framework\Models\Sql\Model . Since you implemented __get , consider adding a @property annotation.
![]() |
|||||||||||
273 | if ($authority = $model->segments->authorities->users->findWhere([ |
||||||||||
0 ignored issues
–
show
The property
authorities does not exist on O2System\Framework\Models\Sql\DataObjects\Result . Since you implemented __get , consider adding a @property annotation.
![]() The property
authorities does not exist on O2System\Framework\Model...\DataObjects\Result\Row . Since you implemented __get , consider adding a @property annotation.
![]() |
|||||||||||
274 | 'id_sys_module_segment' => $segment->id, |
||||||||||
0 ignored issues
–
show
The property
id does not exist on O2System\Framework\Model...\DataObjects\Result\Row . Since you implemented __get , consider adding a @property annotation.
![]() The property
id does not exist on O2System\Framework\Models\Sql\DataObjects\Result . Since you implemented __get , consider adding a @property annotation.
![]() |
|||||||||||
275 | 'id_sys_module_user' => $account->user->moduleUser->id, |
||||||||||
276 | ])) { |
||||||||||
277 | if ($authority->first()->permission === 'WRITE') { |
||||||||||
278 | return true; |
||||||||||
279 | } elseif ($authority->first()->permission === 'GRANTED') { |
||||||||||
280 | // Access only granted cannot do modifier access |
||||||||||
281 | foreach ([ |
||||||||||
282 | 'form', |
||||||||||
283 | 'add', |
||||||||||
284 | 'add-as-new', |
||||||||||
285 | 'edit', |
||||||||||
286 | 'update', |
||||||||||
287 | 'insert', |
||||||||||
288 | 'create', |
||||||||||
289 | 'delete', |
||||||||||
290 | ] as $segment |
||||||||||
291 | ) { |
||||||||||
292 | if (in_array($segment, $segments)) { |
||||||||||
293 | return false; |
||||||||||
294 | } |
||||||||||
295 | } |
||||||||||
296 | |||||||||||
297 | return true; |
||||||||||
298 | } |
||||||||||
299 | } |
||||||||||
300 | |||||||||||
301 | if ($authority = $model->segments->authorities->roles->findWhere([ |
||||||||||
302 | 'id_sys_module_segment' => $segment->id, |
||||||||||
303 | 'id_sys_module_role' => $account->user->role->id, |
||||||||||
304 | ])) { |
||||||||||
305 | if ($authority->first()->permission === 'WRITE') { |
||||||||||
306 | return true; |
||||||||||
307 | } elseif ($authority->first()->permission === 'GRANTED') { |
||||||||||
308 | // Access only granted cannot do modifier access |
||||||||||
309 | foreach ([ |
||||||||||
310 | 'form', |
||||||||||
311 | 'add', |
||||||||||
312 | 'add-as-new', |
||||||||||
313 | 'edit', |
||||||||||
314 | 'update', |
||||||||||
315 | 'insert', |
||||||||||
316 | 'create', |
||||||||||
317 | 'delete', |
||||||||||
318 | ] as $segment |
||||||||||
319 | ) { |
||||||||||
320 | if (in_array($segment, $segments)) { |
||||||||||
321 | return false; |
||||||||||
322 | } |
||||||||||
323 | } |
||||||||||
324 | |||||||||||
325 | return true; |
||||||||||
326 | } |
||||||||||
327 | } |
||||||||||
328 | } |
||||||||||
329 | } |
||||||||||
330 | } |
||||||||||
331 | } |
||||||||||
332 | |||||||||||
333 | return false; |
||||||||||
334 | } |
||||||||||
335 | |||||||||||
336 | // ------------------------------------------------------------------------ |
||||||||||
337 | |||||||||||
338 | /** |
||||||||||
339 | * User::hasWriteAccess |
||||||||||
340 | * |
||||||||||
341 | * @return bool |
||||||||||
342 | * @throws \Psr\Cache\InvalidArgumentException |
||||||||||
343 | */ |
||||||||||
344 | public function hasWriteAccess() |
||||||||||
345 | { |
||||||||||
346 | $segments = server_request()->getUri()->segments->getArrayCopy(); |
||||||||||
347 | |||||||||||
348 | if ($this->loggedIn()) { |
||||||||||
349 | if ($account = globals()->offsetGet('account')) { |
||||||||||
350 | if (in_array($account->user->role->id, [1, 2])) { |
||||||||||
351 | return true; |
||||||||||
352 | } |
||||||||||
353 | |||||||||||
354 | if ($model = models('modules')) { |
||||||||||
355 | |||||||||||
356 | if ($segment = $model->segments->find(implode('/', $segments), 'segments')) { |
||||||||||
0 ignored issues
–
show
The property
segments does not exist on O2System\Framework\Models\Sql\Model . Since you implemented __get , consider adding a @property annotation.
![]() The property
segments does not exist on O2System\Framework\Containers\Models . Since you implemented __get , consider adding a @property annotation.
![]() The property
segments does not exist on O2System\Framework\Models\NoSql\Model . Since you implemented __get , consider adding a @property annotation.
![]() |
|||||||||||
357 | if ($authority = $model->segments->authorities->users->findWhere([ |
||||||||||
0 ignored issues
–
show
The property
authorities does not exist on O2System\Framework\Models\Sql\DataObjects\Result . Since you implemented __get , consider adding a @property annotation.
![]() The property
authorities does not exist on O2System\Framework\Model...\DataObjects\Result\Row . Since you implemented __get , consider adding a @property annotation.
![]() |
|||||||||||
358 | 'id_sys_module_segment' => $segment->id, |
||||||||||
0 ignored issues
–
show
The property
id does not exist on O2System\Framework\Models\Sql\DataObjects\Result . Since you implemented __get , consider adding a @property annotation.
![]() The property
id does not exist on O2System\Framework\Model...\DataObjects\Result\Row . Since you implemented __get , consider adding a @property annotation.
![]() |
|||||||||||
359 | 'id_sys_module_user' => $account->user->moduleUser->id, |
||||||||||
360 | ])) { |
||||||||||
361 | if ($authority->first()->permission === 'WRITE') { |
||||||||||
362 | return true; |
||||||||||
363 | } |
||||||||||
364 | } |
||||||||||
365 | |||||||||||
366 | if ($authority = $model->segments->authorities->roles->findWhere([ |
||||||||||
367 | 'id_sys_module_segment' => $segment->id, |
||||||||||
368 | 'id_sys_module_role' => $account->user->role->id, |
||||||||||
369 | ])) { |
||||||||||
370 | if ($authority->first()->permission === 'WRITE') { |
||||||||||
371 | return true; |
||||||||||
372 | } |
||||||||||
373 | } |
||||||||||
374 | } |
||||||||||
375 | } |
||||||||||
376 | } |
||||||||||
377 | } |
||||||||||
378 | |||||||||||
379 | return false; |
||||||||||
380 | } |
||||||||||
381 | |||||||||||
382 | // ------------------------------------------------------------------------ |
||||||||||
383 | |||||||||||
384 | /** |
||||||||||
385 | * User::getIframeCode |
||||||||||
386 | * |
||||||||||
387 | * @return string |
||||||||||
388 | * @throws \Psr\Cache\InvalidArgumentException |
||||||||||
389 | */ |
||||||||||
390 | public function getIframeCode() |
||||||||||
391 | { |
||||||||||
392 | if ($this->signedOn() && $this->loggedIn() === false) { |
||||||||||
393 | return '<iframe id="sign-on-iframe" width="1" height="1" src="' . rtrim($this->config[ 'sso' ][ 'server' ], |
||||||||||
394 | '/') . '" style="display: none; visibility: hidden;"></iframe>'; |
||||||||||
395 | } |
||||||||||
396 | |||||||||||
397 | return ''; |
||||||||||
398 | } |
||||||||||
399 | } |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.