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 = []; |
|
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(Role::class)->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(Role::class)->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 | * @return bool |
||
214 | */ |
||
215 | 2 | public function bindRequest(Request $request) |
|
216 | { |
||
217 | 2 | $changes = $request->request->get('permission-hidden-fields'); |
|
218 | |||
219 | 2 | if (empty($changes)) { |
|
220 | 1 | return true; |
|
221 | } |
||
222 | |||
223 | // Just apply the changes to the current node (non recursively) |
||
224 | 1 | $this->applyAclChangeset($this->resource, $changes, false); |
|
225 | |||
226 | // Apply recursively (on request) |
||
227 | 1 | $applyRecursive = $request->request->get('applyRecursive'); |
|
228 | 1 | if ($applyRecursive) { |
|
229 | // Serialize changes & store them in DB |
||
230 | 1 | $user = $this->tokenStorage->getToken()->getUser(); |
|
231 | 1 | $this->createAclChangeSet($this->resource, $changes, $user); |
|
232 | |||
233 | 1 | $cmd = 'php ' . $this->kernel->getRootDir() . '/../bin/console kuma:acl:apply'; |
|
0 ignored issues
–
show
|
|||
234 | 1 | $cmd .= ' --env=' . $this->kernel->getEnvironment(); |
|
235 | |||
236 | 1 | $this->shellHelper->runInBackground($cmd); |
|
237 | } |
||
238 | |||
239 | 1 | return true; |
|
240 | } |
||
241 | |||
242 | /** |
||
243 | * Create a new ACL changeset. |
||
244 | * |
||
245 | * @param AbstractEntity $entity The entity |
||
246 | * @param array $changes The changes |
||
247 | * @param UserInterface $user The user |
||
248 | * |
||
249 | * @return AclChangeset |
||
250 | */ |
||
251 | 2 | public function createAclChangeSet(AbstractEntity $entity, $changes, UserInterface $user) |
|
252 | { |
||
253 | 2 | $aclChangeset = new AclChangeset(); |
|
254 | 2 | $aclChangeset->setRef($entity); |
|
255 | 2 | $aclChangeset->setChangeset($changes); |
|
256 | /* @var $user BaseUser */ |
||
257 | 2 | $aclChangeset->setUser($user); |
|
258 | 2 | $this->em->persist($aclChangeset); |
|
259 | 2 | $this->em->flush(); |
|
260 | |||
261 | 2 | return $aclChangeset; |
|
262 | } |
||
263 | |||
264 | /** |
||
265 | * Apply the specified ACL changeset. |
||
266 | * |
||
267 | * @param AbstractEntity $entity The entity |
||
268 | * @param array $changeset The changeset |
||
269 | * @param bool $recursive The recursive |
||
270 | */ |
||
271 | 4 | public function applyAclChangeset(AbstractEntity $entity, $changeset, $recursive = true) |
|
272 | { |
||
273 | 4 | if ($recursive) { |
|
274 | 2 | if (!method_exists($entity, 'getChildren')) { |
|
275 | 1 | return; |
|
276 | } |
||
277 | |||
278 | // Iterate over children and apply recursively |
||
279 | 1 | foreach ($entity->getChildren() as $child) { |
|
280 | 1 | $this->applyAclChangeset($child, $changeset); |
|
281 | } |
||
282 | } |
||
283 | |||
284 | // Apply ACL modifications to node |
||
285 | 3 | $objectIdentity = $this->oidRetrievalStrategy->getObjectIdentity($entity); |
|
286 | |||
287 | try { |
||
288 | /* @var $acl MutableAclInterface */ |
||
289 | 3 | $acl = $this->aclProvider->findAcl($objectIdentity); |
|
290 | 1 | } catch (AclNotFoundException $e) { |
|
291 | /* @var $acl MutableAclInterface */ |
||
292 | 1 | $acl = $this->aclProvider->createAcl($objectIdentity); |
|
293 | } |
||
294 | |||
295 | // Process permissions in changeset |
||
296 | 3 | foreach ($changeset as $role => $roleChanges) { |
|
297 | 2 | $index = $this->getObjectAceIndex($acl, $role); |
|
298 | 2 | $mask = 0; |
|
299 | 2 | if (false !== $index) { |
|
300 | 1 | $mask = $this->getMaskAtIndex($acl, $index); |
|
301 | } |
||
302 | 2 | foreach ($roleChanges as $type => $permissions) { |
|
303 | 2 | $maskChange = new MaskBuilder(); |
|
304 | 2 | foreach ($permissions as $permission) { |
|
305 | 2 | $maskChange->add($permission); |
|
306 | } |
||
307 | switch ($type) { |
||
308 | 2 | case self::ADD: |
|
309 | 1 | $mask |= $maskChange->get(); |
|
310 | |||
311 | 1 | break; |
|
312 | 1 | case self::DELETE: |
|
313 | 1 | $mask &= ~$maskChange->get(); |
|
314 | |||
315 | 1 | break; |
|
316 | } |
||
317 | } |
||
318 | 2 | if (false !== $index) { |
|
319 | 1 | $acl->updateObjectAce($index, $mask); |
|
320 | } else { |
||
321 | 1 | $securityIdentity = new RoleSecurityIdentity($role); |
|
322 | 1 | $acl->insertObjectAce($securityIdentity, $mask); |
|
323 | } |
||
324 | } |
||
325 | 3 | $this->aclProvider->updateAcl($acl); |
|
326 | 3 | } |
|
327 | |||
328 | /** |
||
329 | * Get current object ACE index for specified role. |
||
330 | * |
||
331 | * @param AclInterface $acl The AclInterface |
||
332 | * @param string $role The role |
||
333 | * |
||
334 | * @return bool|int |
||
335 | */ |
||
336 | 2 | View Code Duplication | private function getObjectAceIndex(AclInterface $acl, $role) |
337 | { |
||
338 | 2 | $objectAces = $acl->getObjectAces(); |
|
339 | /* @var $ace AuditableEntryInterface */ |
||
340 | 2 | foreach ($objectAces as $index => $ace) { |
|
341 | 2 | $securityIdentity = $ace->getSecurityIdentity(); |
|
342 | 2 | if (($securityIdentity instanceof RoleSecurityIdentity) && $securityIdentity->getRole() == $role) { |
|
343 | 1 | return $index; |
|
344 | } |
||
345 | } |
||
346 | |||
347 | 1 | return false; |
|
348 | } |
||
349 | |||
350 | /** |
||
351 | * Get object ACE mask at specified index. |
||
352 | * |
||
353 | * @param AclInterface $acl The acl interface |
||
354 | * @param int $index The index |
||
355 | * |
||
356 | * @return bool|int |
||
357 | */ |
||
358 | 2 | View Code Duplication | private function getMaskAtIndex(AclInterface $acl, $index) |
359 | { |
||
360 | 2 | $objectAces = $acl->getObjectAces(); |
|
361 | /* @var $ace AuditableEntryInterface */ |
||
362 | 2 | $ace = $objectAces[$index]; |
|
363 | 2 | $securityIdentity = $ace->getSecurityIdentity(); |
|
364 | 2 | if ($securityIdentity instanceof RoleSecurityIdentity) { |
|
365 | 2 | return $ace->getMask(); |
|
366 | } |
||
367 | |||
368 | 1 | return false; |
|
369 | } |
||
370 | } |
||
371 |
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.