These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Kunstmaan\AdminBundle\Helper\Security\Acl\Permission; |
||
4 | |||
5 | use Doctrine\ORM\EntityManager; |
||
6 | use Kunstmaan\AdminBundle\Entity\AbstractEntity; |
||
7 | use Kunstmaan\AdminBundle\Entity\AclChangeset; |
||
8 | use Kunstmaan\AdminBundle\Entity\Role; |
||
9 | use Kunstmaan\UtilitiesBundle\Helper\Shell\Shell; |
||
10 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; |
||
11 | use Symfony\Component\HttpFoundation\Request; |
||
12 | use Symfony\Component\HttpKernel\KernelInterface; |
||
13 | use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity; |
||
14 | use Symfony\Component\Security\Acl\Exception\AclNotFoundException; |
||
15 | use Symfony\Component\Security\Acl\Model\AclInterface; |
||
16 | use Symfony\Component\Security\Acl\Model\AclProviderInterface; |
||
17 | use Symfony\Component\Security\Acl\Model\AuditableEntryInterface; |
||
18 | use Symfony\Component\Security\Acl\Model\MutableAclInterface; |
||
19 | use Symfony\Component\Security\Acl\Model\MutableAclProviderInterface; |
||
20 | use Symfony\Component\Security\Acl\Model\ObjectIdentityRetrievalStrategyInterface; |
||
21 | use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; |
||
22 | use Symfony\Component\Security\Core\Role\RoleInterface; |
||
23 | use Symfony\Component\Security\Core\User\UserInterface; |
||
24 | |||
25 | /** |
||
26 | * Helper to manage the permissions on a certain entity |
||
27 | */ |
||
28 | class PermissionAdmin |
||
29 | { |
||
30 | const ADD = 'ADD'; |
||
31 | const DELETE = 'DEL'; |
||
32 | |||
33 | /** |
||
34 | * @var AbstractEntity |
||
35 | */ |
||
36 | protected $resource = null; |
||
37 | |||
38 | /** |
||
39 | * @var EntityManager |
||
40 | */ |
||
41 | protected $em = null; |
||
42 | |||
43 | /** |
||
44 | * @var TokenStorageInterface |
||
45 | */ |
||
46 | protected $tokenStorage = null; |
||
47 | |||
48 | /** |
||
49 | * @var MutableAclProviderInterface |
||
50 | */ |
||
51 | protected $aclProvider = null; |
||
52 | |||
53 | /** |
||
54 | * @var ObjectIdentityRetrievalStrategyInterface |
||
55 | */ |
||
56 | protected $oidRetrievalStrategy = null; |
||
57 | |||
58 | /** |
||
59 | * @var PermissionMap |
||
60 | */ |
||
61 | protected $permissionMap = null; |
||
62 | |||
63 | /** |
||
64 | * @var array |
||
65 | */ |
||
66 | protected $permissions = null; |
||
67 | |||
68 | /** |
||
69 | * @var EventDispatcherInterface |
||
70 | */ |
||
71 | protected $eventDispatcher = null; |
||
72 | |||
73 | /** |
||
74 | * @var KernelInterface |
||
75 | */ |
||
76 | protected $kernel; |
||
77 | |||
78 | /** |
||
79 | * @var Shell |
||
80 | */ |
||
81 | protected $shellHelper; |
||
82 | |||
83 | /** |
||
84 | * Constructor |
||
85 | * |
||
86 | * @param EntityManager $em The EntityManager |
||
87 | * @param TokenStorageInterface $tokenStorage The token storage |
||
88 | * @param AclProviderInterface $aclProvider The ACL provider |
||
89 | * @param ObjectIdentityRetrievalStrategyInterface $oidRetrievalStrategy The object retrieval strategy |
||
90 | * @param EventDispatcherInterface $eventDispatcher The event dispatcher |
||
91 | * @param Shell $shellHelper The shell helper |
||
92 | * @param KernelInterface $kernel The kernel |
||
93 | */ |
||
94 | 14 | public function __construct( |
|
95 | EntityManager $em, |
||
96 | TokenStorageInterface $tokenStorage, |
||
97 | AclProviderInterface $aclProvider, |
||
98 | ObjectIdentityRetrievalStrategyInterface $oidRetrievalStrategy, |
||
99 | EventDispatcherInterface $eventDispatcher, |
||
100 | Shell $shellHelper, |
||
101 | KernelInterface $kernel |
||
102 | ) { |
||
103 | 14 | $this->em = $em; |
|
104 | 14 | $this->tokenStorage = $tokenStorage; |
|
105 | 14 | $this->aclProvider = $aclProvider; |
|
106 | 14 | $this->oidRetrievalStrategy = $oidRetrievalStrategy; |
|
107 | 14 | $this->eventDispatcher = $eventDispatcher; |
|
108 | 14 | $this->shellHelper = $shellHelper; |
|
109 | 14 | $this->kernel = $kernel; |
|
110 | 14 | } |
|
111 | |||
112 | /** |
||
113 | * Initialize permission admin with specified entity. |
||
114 | * |
||
115 | * @param AbstractEntity $resource The object which has the permissions |
||
116 | * @param PermissionMapInterface $permissionMap The permission map to use |
||
117 | */ |
||
118 | 12 | public function initialize(AbstractEntity $resource, PermissionMapInterface $permissionMap) |
|
119 | { |
||
120 | 12 | $this->resource = $resource; |
|
121 | 12 | $this->permissionMap = $permissionMap; |
|
122 | 12 | $this->permissions = array(); |
|
123 | |||
124 | // Init permissions |
||
125 | try { |
||
126 | 12 | $objectIdentity = $this->oidRetrievalStrategy->getObjectIdentity($this->resource); |
|
127 | /* @var $acl AclInterface */ |
||
128 | 11 | $acl = $this->aclProvider->findAcl($objectIdentity); |
|
129 | 11 | $objectAces = $acl->getObjectAces(); |
|
130 | /* @var $ace AuditableEntryInterface */ |
||
131 | 11 | View Code Duplication | foreach ($objectAces as $ace) { |
132 | 11 | $securityIdentity = $ace->getSecurityIdentity(); |
|
133 | 11 | if ($securityIdentity instanceof RoleSecurityIdentity) { |
|
134 | 11 | $this->permissions[$securityIdentity->getRole()] = new MaskBuilder($ace->getMask()); |
|
135 | } |
||
136 | } |
||
137 | 1 | } catch (AclNotFoundException $e) { |
|
138 | // No Acl found - do nothing (or should we initialize with default values here?) |
||
139 | } |
||
140 | 12 | } |
|
141 | |||
142 | /** |
||
143 | * Get permissions. |
||
144 | * |
||
145 | * @return MaskBuilder[] |
||
146 | */ |
||
147 | 1 | public function getPermissions() |
|
148 | { |
||
149 | 1 | return $this->permissions; |
|
150 | } |
||
151 | |||
152 | /** |
||
153 | * Get permission for specified role. |
||
154 | * |
||
155 | * @param RoleInterface|string $role |
||
156 | * |
||
157 | * @return MaskBuilder|null |
||
158 | */ |
||
159 | 3 | public function getPermission($role) |
|
160 | { |
||
161 | 3 | if ($role instanceof RoleInterface || $role instanceof \Symfony\Component\Security\Core\Role\Role) { |
|
162 | 1 | $role = $role->getRole(); |
|
163 | } |
||
164 | 3 | if (isset($this->permissions[$role])) { |
|
165 | 2 | return $this->permissions[$role]; |
|
166 | } |
||
167 | |||
168 | 1 | return null; |
|
169 | } |
||
170 | |||
171 | /** |
||
172 | * Get all roles. |
||
173 | * |
||
174 | * @return Role[] |
||
175 | */ |
||
176 | 1 | public function getAllRoles() |
|
177 | { |
||
178 | 1 | return $this->em->getRepository('KunstmaanAdminBundle:Role')->findAll(); |
|
179 | } |
||
180 | |||
181 | /** |
||
182 | * Get all manageable roles for pages |
||
183 | * |
||
184 | * @return Role[] |
||
185 | */ |
||
186 | 1 | public function getManageableRolesForPages() |
|
187 | { |
||
188 | 1 | $roles = $this->em->getRepository('KunstmaanAdminBundle:Role')->findAll(); |
|
189 | |||
190 | 1 | if (($token = $this->tokenStorage->getToken()) && ($user = $token->getUser())) { |
|
191 | 1 | if ($user && !$user->isSuperAdmin() && ($superAdminRole = array_keys($roles, 'ROLE_SUPER_ADMIN'))) { |
|
192 | 1 | $superAdminRole = current($superAdminRole); |
|
193 | 1 | unset($roles[$superAdminRole]); |
|
194 | } |
||
195 | } |
||
196 | |||
197 | 1 | return $roles; |
|
198 | } |
||
199 | |||
200 | /** |
||
201 | * Get possible permissions. |
||
202 | * |
||
203 | * @return array |
||
204 | */ |
||
205 | 1 | public function getPossiblePermissions() |
|
206 | { |
||
207 | 1 | return $this->permissionMap->getPossiblePermissions(); |
|
208 | } |
||
209 | |||
210 | /** |
||
211 | * Handle form entry of permission changes. |
||
212 | * |
||
213 | * @param Request $request |
||
214 | * |
||
215 | * @return bool |
||
216 | */ |
||
217 | 2 | public function bindRequest(Request $request) |
|
218 | { |
||
219 | 2 | $changes = $request->request->get('permission-hidden-fields'); |
|
220 | |||
221 | 2 | if (empty($changes)) { |
|
222 | 1 | return true; |
|
223 | } |
||
224 | |||
225 | // Just apply the changes to the current node (non recursively) |
||
226 | 1 | $this->applyAclChangeset($this->resource, $changes, false); |
|
227 | |||
228 | // Apply recursively (on request) |
||
229 | 1 | $applyRecursive = $request->request->get('applyRecursive'); |
|
230 | 1 | if ($applyRecursive) { |
|
231 | // Serialize changes & store them in DB |
||
232 | 1 | $user = $this->tokenStorage->getToken()->getUser(); |
|
233 | 1 | $this->createAclChangeSet($this->resource, $changes, $user); |
|
234 | |||
235 | 1 | $cmd = 'php ' . $this->kernel->getRootDir() . '/../bin/console kuma:acl:apply'; |
|
236 | 1 | $cmd .= ' --env=' . $this->kernel->getEnvironment(); |
|
237 | |||
238 | 1 | $this->shellHelper->runInBackground($cmd); |
|
239 | } |
||
240 | |||
241 | 1 | return true; |
|
242 | } |
||
243 | |||
244 | /** |
||
245 | * Create a new ACL changeset. |
||
246 | * |
||
247 | * @param AbstractEntity $entity The entity |
||
248 | * @param array $changes The changes |
||
249 | * @param UserInterface $user The user |
||
250 | * |
||
251 | * @return AclChangeset |
||
252 | */ |
||
253 | 2 | public function createAclChangeSet(AbstractEntity $entity, $changes, UserInterface $user) |
|
254 | { |
||
255 | 2 | $aclChangeset = new AclChangeset(); |
|
256 | 2 | $aclChangeset->setRef($entity); |
|
257 | 2 | $aclChangeset->setChangeset($changes); |
|
258 | /* @var $user BaseUser */ |
||
259 | 2 | $aclChangeset->setUser($user); |
|
260 | 2 | $this->em->persist($aclChangeset); |
|
261 | 2 | $this->em->flush(); |
|
262 | |||
263 | 2 | return $aclChangeset; |
|
264 | } |
||
265 | |||
266 | /** |
||
267 | * Apply the specified ACL changeset. |
||
268 | * |
||
269 | * @param AbstractEntity $entity The entity |
||
270 | * @param array $changeset The changeset |
||
271 | * @param bool $recursive The recursive |
||
272 | */ |
||
273 | 4 | public function applyAclChangeset(AbstractEntity $entity, $changeset, $recursive = true) |
|
274 | { |
||
275 | 4 | if ($recursive) { |
|
276 | 2 | if (!method_exists($entity, 'getChildren')) { |
|
277 | 1 | return; |
|
278 | } |
||
279 | |||
280 | // Iterate over children and apply recursively |
||
281 | 1 | foreach ($entity->getChildren() as $child) { |
|
282 | 1 | $this->applyAclChangeset($child, $changeset); |
|
283 | } |
||
284 | } |
||
285 | |||
286 | // Apply ACL modifications to node |
||
287 | 3 | $objectIdentity = $this->oidRetrievalStrategy->getObjectIdentity($entity); |
|
288 | |||
289 | try { |
||
290 | /* @var $acl MutableAclInterface */ |
||
291 | 3 | $acl = $this->aclProvider->findAcl($objectIdentity); |
|
292 | 1 | } catch (AclNotFoundException $e) { |
|
293 | /* @var $acl MutableAclInterface */ |
||
294 | 1 | $acl = $this->aclProvider->createAcl($objectIdentity); |
|
295 | } |
||
296 | |||
297 | // Process permissions in changeset |
||
298 | 3 | foreach ($changeset as $role => $roleChanges) { |
|
299 | 2 | $index = $this->getObjectAceIndex($acl, $role); |
|
300 | 2 | $mask = 0; |
|
301 | 2 | if (false !== $index) { |
|
302 | 1 | $mask = $this->getMaskAtIndex($acl, $index); |
|
303 | } |
||
304 | 2 | foreach ($roleChanges as $type => $permissions) { |
|
305 | 2 | $maskChange = new MaskBuilder(); |
|
306 | 2 | foreach ($permissions as $permission) { |
|
307 | 2 | $maskChange->add($permission); |
|
308 | } |
||
309 | switch ($type) { |
||
310 | 2 | case self::ADD: |
|
311 | 1 | $mask |= $maskChange->get(); |
|
312 | |||
313 | 1 | break; |
|
314 | 1 | case self::DELETE: |
|
315 | 1 | $mask &= ~$maskChange->get(); |
|
316 | |||
317 | 1 | break; |
|
318 | } |
||
319 | } |
||
320 | 2 | if (false !== $index) { |
|
321 | 1 | $acl->updateObjectAce($index, $mask); |
|
0 ignored issues
–
show
|
|||
322 | } else { |
||
323 | 1 | $securityIdentity = new RoleSecurityIdentity($role); |
|
324 | 1 | $acl->insertObjectAce($securityIdentity, $mask); |
|
0 ignored issues
–
show
It seems like
$mask defined by $this->getMaskAtIndex($acl, $index) on line 302 can also be of type false ; however, Symfony\Component\Securi...face::insertObjectAce() does only seem to accept integer , did you maybe forget to handle an error condition?
This check looks for type mismatches where the missing type is Consider the follow example <?php
function getDate($date)
{
if ($date !== null) {
return new DateTime($date);
}
return false;
}
This function either returns a new
Loading history...
|
|||
325 | } |
||
326 | } |
||
327 | 3 | $this->aclProvider->updateAcl($acl); |
|
328 | 3 | } |
|
329 | |||
330 | /** |
||
331 | * Get current object ACE index for specified role. |
||
332 | * |
||
333 | * @param AclInterface $acl The AclInterface |
||
334 | * @param string $role The role |
||
335 | * |
||
336 | * @return bool|int |
||
337 | */ |
||
338 | 2 | View Code Duplication | private function getObjectAceIndex(AclInterface $acl, $role) |
339 | { |
||
340 | 2 | $objectAces = $acl->getObjectAces(); |
|
341 | /* @var $ace AuditableEntryInterface */ |
||
342 | 2 | foreach ($objectAces as $index => $ace) { |
|
343 | 2 | $securityIdentity = $ace->getSecurityIdentity(); |
|
344 | 2 | if (($securityIdentity instanceof RoleSecurityIdentity) && $securityIdentity->getRole() == $role) { |
|
345 | 1 | return $index; |
|
346 | } |
||
347 | } |
||
348 | |||
349 | 1 | return false; |
|
350 | } |
||
351 | |||
352 | /** |
||
353 | * Get object ACE mask at specified index. |
||
354 | * |
||
355 | * @param AclInterface $acl The acl interface |
||
356 | * @param int $index The index |
||
357 | * |
||
358 | * @return bool|int |
||
359 | */ |
||
360 | 2 | View Code Duplication | private function getMaskAtIndex(AclInterface $acl, $index) |
361 | { |
||
362 | 2 | $objectAces = $acl->getObjectAces(); |
|
363 | /* @var $ace AuditableEntryInterface */ |
||
364 | 2 | $ace = $objectAces[$index]; |
|
365 | 2 | $securityIdentity = $ace->getSecurityIdentity(); |
|
366 | 2 | if ($securityIdentity instanceof RoleSecurityIdentity) { |
|
367 | 2 | return $ace->getMask(); |
|
368 | } |
||
369 | |||
370 | 1 | return false; |
|
371 | } |
||
372 | } |
||
373 |
This check looks for type mismatches where the missing type is
false
. This is usually indicative of an error condtion.Consider the follow example
This function either returns a new
DateTime
object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returnedfalse
before passing on the value to another function or method that may not be able to handle afalse
.