HCE Project DC service web UI  0.2
Hierarchical Cluster Engine DC service web UI
 All Classes Namespaces Files Functions Variables Pages
RAuthorizer.php
Go to the documentation of this file.
1 <?php
10 class RAuthorizer extends CApplicationComponent
11 {
19  private $_authManager;
20 
24  public function init()
25  {
26  parent::init();
27 
28  $this->_authManager = Yii::app()->getAuthManager();
29  }
30 
39  public function getRoles($includeSuperuser = true, $sort = true)
40  {
41  $exclude = $includeSuperuser === false ? array($this->superuserName) : array();
42  $roles = $this->getAuthItems(CAuthItem::TYPE_ROLE, null, null, $sort, $exclude);
43  $roles = $this->attachAuthItemBehavior($roles);
44 
45  return $roles;
46  }
47 
60  public function createAuthItem($name, $type, $description = '', $bizRule = null, $data = null)
61  {
62  $bizRule = $bizRule !== '' ? $bizRule : null;
63 
64  if ($data !== null) {
65  $data = $data !== '' ? $this->sanitizeExpression($data.';') : null;
66  }
67 
68  return $this->_authManager->createAuthItem($name, $type, $description, $bizRule, $data);
69  }
70 
81  public function updateAuthItem($oldName, $name, $description = '', $bizRule = null, $data = null)
82  {
83  $authItem = $this->_authManager->getAuthItem($oldName);
84  $authItem->name = $name;
85  $authItem->description = $description !== '' ? $description : null;
86  $authItem->bizRule = $bizRule !== '' ? $bizRule : null;
87 
88  // Make sure that data is not already serialized.
89  if (@unserialize($data) === false) {
90  $authItem->data = $data !== '' ? $this->sanitizeExpression($data.';') : null;
91  }
92 
93  $this->_authManager->saveAuthItem($authItem, $oldName);
94  }
95 
109  public function getAuthItems($types = null, $userId = null, CAuthItem $parent = null, $sort = true, $exclude = array())
110  {
111  // We have none or a single type.
112  if ($types !== (array) $types) {
113  $items = $this->_authManager->getAuthItems($types, $userId, $sort);
114  }
115  // We have multiple types.
116  else {
117  $typeItemList = array();
118  foreach ($types as $type) {
119  $typeItemList[ $type ] = $this->_authManager->getAuthItems($type, $userId, $sort);
120  }
121 
122  // Merge the authorization items preserving the keys.
123  $items = array();
124  foreach ($typeItemList as $typeItems) {
125  $items = $this->mergeAuthItems($items, $typeItems);
126  }
127  }
128 
129  $items = $this->excludeInvalidAuthItems($items, $parent, $exclude);
130  $items = $this->attachAuthItemBehavior($items, $userId, $parent);
131 
132  return $items;
133  }
134 
143  protected function mergeAuthItems($array1, $array2)
144  {
145  foreach ($array2 as $itemName => $item) {
146  if (isset($array1[ $itemName ]) === false) {
147  $array1[ $itemName ] = $item;
148  }
149  }
150 
151  return $array1;
152  }
153 
164  protected function excludeInvalidAuthItems($items, CAuthItem $parent = null, $exclude = array())
165  {
166  // We are getting authorization items valid for a certain item
167  // exclude its parents and children aswell.
168  if ($parent !== null) {
169  $exclude[] = $parent->name;
170  foreach ($parent->getChildren() as $childName => $child) {
171  $exclude[] = $childName;
172  }
173 
174  // Exclude the parents recursively to avoid inheritance loops.
175  $parentNames = array_keys($this->getAuthItemParents($parent->name));
176  $exclude = array_merge($parentNames, $exclude);
177  }
178 
179  // Unset the items that are supposed to be excluded.
180  foreach ($exclude as $itemName) {
181  if (isset($items[ $itemName ])) {
182  unset($items[ $itemName ]);
183  }
184  }
185 
186  return $items;
187  }
188 
200  public function getAuthItemParents($item, $type = null, $parentName = null, $direct = false)
201  {
202  if (($item instanceof CAuthItem) === false) {
203  $item = $this->_authManager->getAuthItem($item);
204  }
205 
206  $permissions = $this->getPermissions($parentName);
207  $parentNames = $this->getAuthItemParentsRecursive($item->name, $permissions, $direct);
208  $parents = $this->_authManager->getAuthItemsByNames($parentNames);
209  $parents = $this->attachAuthItemBehavior($parents, null, $item);
210 
211  if ($type !== null) {
212  foreach ($parents as $parentName => $parent) {
213  if ((int) $parent->type !== $type) {
214  unset($parents[ $parentName ]);
215  }
216  }
217  }
218 
219  return $parents;
220  }
221 
231  private function getAuthItemParentsRecursive($itemName, $items, $direct)
232  {
233  $parents = array();
234  foreach ($items as $childName => $children) {
235  if ($children !== array()) {
236  if (isset($children[ $itemName ])) {
237  if (isset($parents[ $childName ]) === false) {
238  $parents[ $childName ] = $childName;
239  }
240  } else {
241  if (($p = $this->getAuthItemParentsRecursive($itemName, $children, $direct)) !== array()) {
242  if ($direct === false && isset($parents[ $childName ]) === false) {
243  $parents[ $childName ] = $childName;
244  }
245 
246  $parents = array_merge($parents, $p);
247  }
248  }
249  }
250  }
251 
252  return $parents;
253  }
254 
264  public function getAuthItemChildren($item, $type = null)
265  {
266  if (($item instanceof CAuthItem) === false) {
267  $item = $this->_authManager->getAuthItem($item);
268  }
269 
270  $childrenNames = array();
271  foreach ($item->getChildren() as $childName => $child) {
272  if ($type === null || (int) $child->type === $type) {
273  $childrenNames[] = $childName;
274  }
275  }
276 
277  $children = $this->_authManager->getAuthItemsByNames($childrenNames);
278  $children = $this->attachAuthItemBehavior($children, null, $item);
279 
280  return $children;
281  }
282 
292  public function attachAuthItemBehavior($items, $userId = null, CAuthItem $parent = null)
293  {
294  // We have a single item.
295  if ($items instanceof CAuthItem) {
296  $items->attachBehavior('rights', new RAuthItemBehavior($userId, $parent));
297  }
298  // We have multiple items.
299  elseif ($items === (array) $items) {
300  foreach ($items as $item) {
301  $item->attachBehavior('rights', new RAuthItemBehavior($userId, $parent));
302  }
303  }
304 
305  return $items;
306  }
307 
313  public function getSuperusers()
314  {
315  $assignments = $this->_authManager->getAssignmentsByItemName(Rights::module()->superuserName);
316 
317  $userIdList = array();
318  foreach ($assignments as $userId => $assignment) {
319  $userIdList[] = $userId;
320  }
321 
322  $criteria = new CDbCriteria();
323  $criteria->addInCondition(Rights::module()->userIdColumn, $userIdList);
324 
325  $userClass = Rights::module()->userClass;
326  $users = CActiveRecord::model($userClass)->findAll($criteria);
327  $users = $this->attachUserBehavior($users);
328 
329  $superusers = array();
330  foreach ($users as $user) {
331  $superusers[] = $user->name;
332  }
333 
334  // Make sure that we have superusers, otherwise we would allow full access to Rights
335  // if there for some reason is not any superusers.
336  if ($superusers === array()) {
337  throw new CHttpException(403, Rights::t('core', 'There must be at least one superuser!'));
338  }
339 
340  return $superusers;
341  }
342 
350  public function attachUserBehavior($users)
351  {
352  $userClass = Rights::module()->userClass;
353 
354  // We have a single user.
355  if ($users instanceof $userClass) {
356  $users->attachBehavior('rights', new RUserBehavior());
357  }
358  // We have multiple user.
359  elseif ($users === (array) $users) {
360  foreach ($users as $user) {
361  $user->attachBehavior('rights', new RUserBehavior());
362  }
363  }
364 
365  return $users;
366  }
367 
375  public function isSuperuser($userId)
376  {
377  $assignments = $this->_authManager->getAuthAssignments($userId);
378 
379  return isset($assignments[ $this->superuserName ]);
380  }
381 
390  public function getPermissions($itemName = null)
391  {
392  $permissions = array();
393 
394  if ($itemName !== null) {
395  $item = $this->_authManager->getAuthItem($itemName);
396  $permissions = $this->getPermissionsRecursive($item);
397  } else {
398  foreach ($this->getRoles() as $roleName => $role) {
399  $permissions[ $roleName ] = $this->getPermissionsRecursive($role);
400  }
401  }
402 
403  return $permissions;
404  }
405 
413  private function getPermissionsRecursive(CAuthItem $item)
414  {
415  $permissions = array();
416  foreach ($item->getChildren() as $childName => $child) {
417  $permissions[ $childName ] = array();
418  if (($grandChildren = $this->getPermissionsRecursive($child)) !== array()) {
419  $permissions[ $childName ] = $grandChildren;
420  }
421  }
422 
423  return $permissions;
424  }
425 
435  public function hasPermission($itemName, $parentName = null, $permissions = array())
436  {
437  if ($parentName !== null) {
438  if ($parentName === $this->superuserName) {
439  return 1;
440  }
441 
442  $permissions = $this->getPermissions($parentName);
443  }
444 
445  if (isset($permissions[ $itemName ])) {
446  return 1;
447  }
448 
449  foreach ($permissions as $children) {
450  if ($children !== array()) {
451  if ($this->hasPermission($itemName, null, $children)>0) {
452  return 2;
453  }
454  }
455  }
456 
457  return 0;
458  }
459 
467  protected function sanitizeExpression($code)
468  {
469  // Language consturcts.
470  $languageConstructs = array(
471  'echo',
472  'empty',
473  'isset',
474  'unset',
475  'exit',
476  'die',
477  'include',
478  'include_once',
479  'require',
480  'require_once',
481  );
482 
483  // Loop through the language constructs.
484  foreach ($languageConstructs as $lc) {
485  if (preg_match('/'.$lc.'\ *\(?\ *[\"\']+/', $code)>0) {
486  return;
487  }
488  } // Language construct found, not safe for eval.
489 
490  // Get a list of all defined functions
491  $definedFunctions = get_defined_functions();
492  $functions = array_merge($definedFunctions['internal'], $definedFunctions['user']);
493 
494  // Loop through the functions and check the code for function calls.
495  // Append a '(' to the functions to avoid confusion between e.g. array() and array_merge().
496  foreach ($functions as $f) {
497  if (preg_match('/'.$f.'\ *\({1}/', $code)>0) {
498  return;
499  }
500  } // Function call found, not safe for eval.
501 
502  // Evaluate the safer code
503  $result = @eval($code);
504 
505  // Return the evaluated code or null if the result was false.
506  return $result !== false ? $result : null;
507  }
508 
512  public function getAuthManager()
513  {
514  return $this->_authManager;
515  }
516 }