ILIAS  Release_3_10_x_branch Revision 61812
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilAccessHandler.php
Go to the documentation of this file.
1 <?php
2 /*
3  +-----------------------------------------------------------------------------+
4  | ILIAS open source |
5  +-----------------------------------------------------------------------------+
6  | Copyright (c) 1998-2001 ILIAS open source, University of Cologne |
7  | |
8  | This program is free software; you can redistribute it and/or |
9  | modify it under the terms of the GNU General Public License |
10  | as published by the Free Software Foundation; either version 2 |
11  | of the License, or (at your option) any later version. |
12  | |
13  | This program is distributed in the hope that it will be useful, |
14  | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16  | GNU General Public License for more details. |
17  | |
18  | You should have received a copy of the GNU General Public License |
19  | along with this program; if not, write to the Free Software |
20  | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21  +-----------------------------------------------------------------------------+
22 */
23 
24 require_once("Services/AccessControl/classes/class.ilAccessInfo.php");
25 
41 {
45  function ilAccessHandler()
46  {
47  global $rbacsystem;
48 
49  $this->rbacsystem =& $rbacsystem;
50  $this->results = array();
51  $this->current_info = new ilAccessInfo();
52 
53  // use function enable to switch on/off tests (only cache is used so far)
54  $this->cache = true;
55  $this->rbac = true;
56  $this->tree = true;
57  $this->condition = true;
58  $this->path = true;
59  $this->status = true;
60  $this->obj_id_cache = array();
61  $this->obj_type_cache = array();
62  $this->obj_tree_cache=array();
63  }
64 
75  function storeAccessResult($a_permission, $a_cmd, $a_ref_id, $a_access_granted, $a_user_id = "",$a_info = "")
76  {
77  global $ilUser;
78 
79  if ($a_user_id == "")
80  {
81  $a_user_id = $ilUser->getId();
82  }
83 
84  if ($a_info == "")
85  {
86  $a_info = $this->current_info;
87  }
88 
89  //var_dump("<pre>",$a_permission,"</pre>");
90 
91  if ($this->cache)
92  {
93  $this->results[$a_ref_id][$a_permission][$a_cmd][$a_user_id] =
94  array("granted" => $a_access_granted, "info" => $a_info);
95 //echo "<br>write-$a_ref_id-$a_permission-$a_cmd-$a_user_id-$a_access_granted-";
96  $this->current_result_element = array($a_access_granted,$a_ref_id,$a_permission,$a_cmd,$a_user_id);
97  $this->last_result = $this->results[$a_ref_id][$a_permission][$a_cmd][$a_user_id];
98  $this->last_info = $a_info;
99  }
100 
101  // get new info object
102  $this->current_info = new ilAccessInfo();
103 
104  }
105 
106 
119  function getStoredAccessResult($a_permission, $a_cmd, $a_ref_id, $a_user_id = "")
120  {
121  global $ilUser;
122 
123  if ($a_user_id == "")
124  {
125  $a_user_id = $ilUser->getId();
126  }
127 
128  /*if (is_object($this->results[$a_ref_id][$a_permission][$a_cmd][$a_user_id]['info']))
129  {
130  $this->current_info = $this->results[$a_ref_id][$a_permission][$a_cmd][$a_user_id]['info'];
131  }*/
132 
133  return $this->results[$a_ref_id][$a_permission][$a_cmd][$a_user_id];
134  }
135 
136  function storeCache()
137  {
138  global $ilDB, $ilUser;
139 
140  $q = "REPLACE INTO acc_cache (user_id, time, result) VALUES ".
141  "(".$ilDB->quote($ilUser->getId()).",".time().",".
142  $ilDB->quote(serialize($this->results)).")";
143  $ilDB->query($q);
144  }
145 
146  function readCache($a_secs = 0)
147  {
148  global $ilUser, $ilDB;
149 
150  if ($a_secs > 0)
151  {
152  $q = "SELECT * FROM acc_cache WHERE user_id = ".
153  $ilDB->quote($ilUser->getId());
154  $set = $ilDB->query($q);
155  $rec = $set->fetchRow(DB_FETCHMODE_ASSOC);
156  if ((time() - $rec["time"]) < $a_secs)
157  {
158  $this->results = unserialize($rec["result"]);
159 //var_dump($this->results);
160  return true;
161  }
162  }
163  return false;
164  }
165 
166  function getResults()
167  {
168  return $this->results;
169  }
170 
171  function setResults($a_results)
172  {
173  $this->results = $a_results;
174  }
175 
179  function addInfoItem($a_type, $a_text, $a_data = "")
180  {
181  $this->current_info->addInfoItem($a_type, $a_text, $a_data);
182  }
183 
196  function checkAccess($a_permission, $a_cmd, $a_ref_id, $a_type = "", $a_obj_id = "", $a_tree_id="")
197  {
198  global $ilUser;
199 
200  return $this->checkAccessOfUser($ilUser->getId(),$a_permission, $a_cmd, $a_ref_id, $a_type, $a_obj_id, $a_tree_id);
201  }
202 
216  function checkAccessOfUser($a_user_id,$a_permission, $a_cmd, $a_ref_id, $a_type = "", $a_obj_id = "", $a_tree_id="")
217  {
218  global $ilBench, $lng;
219 
220  $ilBench->start("AccessControl", "0400_clear_info");
221  $this->current_info->clear();
222  $ilBench->stop("AccessControl", "0400_clear_info");
223 
224  // get stored result
225  $cached = $this->doCacheCheck($a_permission, $a_cmd, $a_ref_id, $a_user_id);
226  if ($cached["hit"])
227  {
228  // Store access result
229  if (!$cached["granted"])
230  {
231  $this->current_info->addInfoItem(IL_NO_PERMISSION, $lng->txt("status_no_permission"));
232  }
233  return $cached["granted"];
234  }
235 
236  $ilBench->start("AccessControl", "0500_lookup_id_and_type");
237  // get object id if not provided
238  if ($a_obj_id == "")
239  {
240  if ($this->obj_id_cache[$a_ref_id] > 0)
241  {
242  $a_obj_id = $this->obj_id_cache[$a_ref_id];
243  }
244  else
245  {
246  $a_obj_id = ilObject::_lookupObjId($a_ref_id);
247  $this->obj_id_cache[$a_ref_id] = $a_obj_id;
248  }
249  }
250  if ($a_type == "")
251  {
252  if ($this->obj_type_cache[$a_ref_id] != "")
253  {
254  $a_type = $this->obj_type_cache[$a_ref_id];
255  }
256  else
257  {
258  $a_type = ilObject::_lookupType($a_ref_id, true);
259  $this->obj_type_cache[$a_ref_id] = $a_type;
260  }
261  }
262  $ilBench->stop("AccessControl", "0500_lookup_id_and_type");
263 
264  // to do: payment handling
265 
266  // if supplied tree id is not = 1 (= repository main tree),
267  // check if object is in tree and not deleted
268  if ($a_tree_id != 1 &&
269  !$this->doTreeCheck($a_permission, $a_cmd, $a_ref_id, $a_user_id))
270  {
271  $this->current_info->addInfoItem(IL_NO_PERMISSION, $lng->txt("status_no_permission"));
272  $this->storeAccessResult($a_permission, $a_cmd, $a_ref_id, false, $a_user_id);
273  return false;
274  }
275 
276  // rbac check for current object
277  if (!$this->doRBACCheck($a_permission, $a_cmd, $a_ref_id, $a_user_id))
278  {
279  $this->current_info->addInfoItem(IL_NO_PERMISSION, $lng->txt("status_no_permission"));
280  $this->storeAccessResult($a_permission, $a_cmd, $a_ref_id, false, $a_user_id);
281  return false;
282  }
283 
284  // check read permission for all parents
285  $par_check = $this->doPathCheck($a_permission, $a_cmd, $a_ref_id, $a_user_id);
286  if (!$par_check)
287  {
288  $this->current_info->addInfoItem(IL_NO_PARENT_ACCESS, $lng->txt("no_parent_access"));
289  $this->storeAccessResult($a_permission, $a_cmd, $a_ref_id, false, $a_user_id);
290  return false;
291  }
292 
293  // condition check (currently only implemented for read permission)
294  if (!$this->doConditionCheck($a_permission, $a_cmd, $a_ref_id, $a_user_id, $a_obj_id, $a_type))
295  {
296  $this->current_info->addInfoItem(IL_NO_PERMISSION, $lng->txt("status_no_permission"));
297  $this->storeAccessResult($a_permission, $a_cmd, $a_ref_id, false, $a_user_id);
298  return false;
299  }
300 
301  // object type specific check
302  if (!$this->doStatusCheck($a_permission, $a_cmd, $a_ref_id, $a_user_id, $a_obj_id, $a_type))
303  {
304  $this->current_info->addInfoItem(IL_NO_PERMISSION, $lng->txt("status_no_permission"));
305  $this->storeAccessResult($a_permission, $a_cmd, $a_ref_id, false, $a_user_id);
306  return false;
307  }
308 
309  // all checks passed
310  $this->storeAccessResult($a_permission, $a_cmd, $a_ref_id, true, $a_user_id);
311  return true;
312  }
313 
317  function getInfo()
318  {
319  //return $this->last_result;
320  //$this->last_info->setQueryData($this->current_result_element);
321  //var_dump("<pre>",$this->results,"</pre>");
322  return is_object($this->last_info) ? $this->last_info->getInfoItems() : array();
323  }
324 
328  function getResultLast()
329  {
330  return $this->last_result;
331  }
332 
333  function getResultAll($a_ref_id = "")
334  {
335  if ($a_ref_id == "")
336  {
337  return $this->results;
338  }
339 
340  return $this->results[$a_ref_id];
341  }
342 
347  function doCacheCheck($a_permission, $a_cmd, $a_ref_id,$a_user_id)
348  {
349  global $ilBench;
350  //echo "cacheCheck<br/>";
351 
352  $ilBench->start("AccessControl", "1000_checkAccess_get_cache_result");
353  $stored_access = $this->getStoredAccessResult($a_permission, $a_cmd, $a_ref_id,$a_user_id);
354  //var_dump($stored_access);
355  if (is_array($stored_access))
356  {
357 //echo "Hit";
358  $this->current_info = $stored_access["info"];
359  //var_dump("cache-treffer:");
360  $ilBench->stop("AccessControl", "1000_checkAccess_get_cache_result");
361  return array("hit" => true, "granted" => $stored_access["granted"]);
362  }
363 
364  // not in cache
365  $ilBench->stop("AccessControl", "1000_checkAccess_get_cache_result");
366  return array("hit" => false, "granted" => false);
367  }
368 
373  function doTreeCheck($a_permission, $a_cmd, $a_ref_id, $a_user_id)
374  {
375  global $tree, $lng, $ilBench;
376  //echo "treeCheck<br/>";
377 
378  // Get stored result
379  $tree_cache_key = $a_user_id.':'.$a_ref_id;
380  if (array_key_exists($tree_cache_key, $this->obj_tree_cache)) {
381  // Store access result
382  if (!$this->obj_tree_cache[$tree_cache_key])
383  {
384  $this->current_info->addInfoItem(IL_NO_PERMISSION, $lng->txt("status_no_permission"));
385  }
386  $this->storeAccessResult($a_permission, $a_cmd, $a_ref_id, $this->obj_tree_cache[$tree_cache_key], $a_user_id);
387 
388  return $this->obj_tree_cache[$tree_cache_key];
389  }
390 
391  $ilBench->start("AccessControl", "2000_checkAccess_in_tree");
392 
393  if(!$tree->isInTree($a_ref_id) or $tree->isDeleted($a_ref_id))
394  {
395  // Store negative access results
396 
397  // Store in tree cache
398  // Note, we only store up to 1000 results to avoid memory overflow.
399  if (count($this->obj_tree_cache) < 1000)
400  {
401  $this->obj_tree_cache[$tree_cache_key] = false;
402  }
403 
404  // Store in result cache
405  $this->current_info->addInfoItem(IL_DELETED, $lng->txt("object_deleted"));
406  $this->storeAccessResult($a_permission, $a_cmd, $a_ref_id, false, $a_user_id);
407 
408  $ilBench->stop("AccessControl", "2000_checkAccess_in_tree");
409 
410  return false;
411  }
412 
413  // Store positive access result.
414 
415  // Store in tree cache
416  // Note, we only store up to 1000 results to avoid memory overflow.
417  if (count($this->obj_tree_cache) < 1000)
418  {
419  $this->obj_tree_cache[$tree_cache_key] = true;
420  }
421 
422  // Store in result cache
423  $this->storeAccessResult($a_permission, $a_cmd, $a_ref_id, true, $a_user_id);
424 
425  $ilBench->stop("AccessControl", "2000_checkAccess_in_tree");
426  return true;
427  }
428 
433  function doRBACCheck($a_permission, $a_cmd, $a_ref_id, $a_user_id)
434  {
435  global $lng, $ilBench, $ilErr, $ilLog;
436 
437  $ilBench->start("AccessControl", "2500_checkAccess_rbac_check");
438 
439  if ($a_permission == "")
440  {
441  $message = sprintf('%s::doRBACCheck(): No operations given! $a_ref_id: %s',
442  get_class($this),
443  $a_ref_id);
444  $ilLog->write($message,$ilLog->FATAL);
445  $ilErr->raiseError($message,$ilErr->MESSAGE);
446  }
447 
448  $access = $this->rbacsystem->checkAccessOfUser($a_user_id, $a_permission, $a_ref_id);
449 
450  // Store in result cache
451  if (!$access)
452  {
453  $this->current_info->addInfoItem(IL_NO_PERMISSION, $lng->txt("status_no_permission"));
454  }
455  $this->storeAccessResult($a_permission, $a_cmd, $a_ref_id, true, $a_user_id);
456  $ilBench->stop("AccessControl", "2500_checkAccess_rbac_check");
457 
458  return $access;
459  }
460 
465  function doPathCheck($a_permission, $a_cmd, $a_ref_id, $a_user_id, $a_all = false)
466  {
467  global $tree, $lng, $ilBench,$ilObjDataCache;
468 //echo "<br>dopathcheck";
469  //echo "pathCheck<br/>";
470  $ilBench->start("AccessControl", "3100_checkAccess_check_parents_get_path");
471  $path = $tree->getPathId($a_ref_id);
472  $ilBench->stop("AccessControl", "3100_checkAccess_check_parents_get_path");
473 
474  $tmp_info = $this->current_info;
475  //var_dump($this->tmp_info);
476 
477  foreach ($path as $id)
478  {
479  if ($a_ref_id == $id)
480  {
481  continue;
482  }
483 
484  // Check course activation
485  if($ilObjDataCache->lookupType($ilObjDataCache->lookupObjId($id)) == 'crs')
486  {
487  if(!$this->doActivationCheck($a_permission,$a_cmd,$a_ref_id,$a_user_id,$a_all))
488  {
489  return false;
490  }
491  }
492 
493  $access = $this->checkAccessOfUser($a_user_id, "read", "info", $id);
494 
495  if ($access == false)
496  {
497 
498  //$this->doCacheCheck($a_permission, $a_cmd, $a_ref_id, $a_user_id);
499  $tmp_info->addInfoItem(IL_NO_PARENT_ACCESS, $lng->txt("no_parent_access"),$id);
500 
501  if ($a_all == false)
502  {
503  return false;
504  }
505  }
506  }
507 
508  return true;
509  }
510 
515  function doActivationCheck($a_permission, $a_cmd, $a_ref_id, $a_user_id, $a_all = false)
516  {
517  global $ilBench,$ilObjDataCache;
518 
519  $ilBench->start("AccessControl", "3150_checkAccess_check_course_activation");
520 
521  $cache_perm = ($a_permission == "visible")
522  ? "visible"
523  : "other";
524 
525 //echo "<br>doActivationCheck-$cache_perm-$a_ref_id-$a_user_id-".$ilObjDataCache->lookupType($ilObjDataCache->lookupObjId($a_ref_id));
526 
527  if (isset($this->ac_cache[$cache_perm][$a_ref_id][$a_user_id]))
528  {
529  $ilBench->stop("AccessControl", "3150_checkAccess_check_course_activation");
530  return $this->ac_cache[$cache_perm][$a_ref_id][$a_user_id];
531  }
532 
533  // nothings needs to be done if current permission is write permission
534  if($a_permission == 'write')
535  {
536  $ilBench->stop("AccessControl", "3150_checkAccess_check_course_activation");
537  return true;
538  }
539  include_once 'Modules/Course/classes/class.ilCourseItems.php';
540 
541  $this->preloadActivationTimes(array($a_ref_id));
542  if(isset($this->ac_times[$a_ref_id]))
543  {
544  // read preloaded
545  $item_data = $this->ac_times[$a_ref_id];
546  }
547  else
548  {
549  global $ilLog;
550  $ilLog->write(__METHOD__.': Error preloading activation times failed.');
551  $item_data = ilCourseItems::_readActivationTimes(array($a_ref_id));
552  $item_data = $item_data[$a_ref_id];
553  }
554 
555 
556  // if activation isn't enabled
557  if($item_data['timing_type'] != IL_CRS_TIMINGS_ACTIVATION)
558  {
559  $this->ac_cache[$cache_perm][$a_ref_id][$a_user_id] = true;
560  $ilBench->stop("AccessControl", "3150_checkAccess_check_course_activation");
561  return true;
562  }
563 
564  // if within activation time
565  if((time() >= $item_data['timing_start']) and
566  (time() <= $item_data['timing_end']))
567  {
568  $this->ac_cache[$cache_perm][$a_ref_id][$a_user_id] = true;
569  $ilBench->stop("AccessControl", "3150_checkAccess_check_course_activation");
570  return true;
571  }
572 
573  // if user has write permission
574  if($this->checkAccessOfUser($a_user_id, "write", "", $a_ref_id))
575  {
576  $this->ac_cache[$cache_perm][$a_ref_id][$a_user_id] = true;
577  $ilBench->stop("AccessControl", "3150_checkAccess_check_course_activation");
578  return true;
579  }
580  // if current permission is visible and visible is set in activation
581  if($a_permission == 'visible' and $item_data['visible'])
582  {
583  $this->ac_cache[$cache_perm][$a_ref_id][$a_user_id] = true;
584  $ilBench->stop("AccessControl", "3150_checkAccess_check_course_activation");
585  return true;
586  }
587  // no access
588  $this->ac_cache[$cache_perm][$a_ref_id][$a_user_id] = false;
589  $ilBench->stop("AccessControl", "3150_checkAccess_check_course_activation");
590  return false;
591  }
592 
601  public function preloadActivationTimes($a_ref_ids)
602  {
603  include_once('Modules/Course/classes/class.ilCourseItems.php');
604 
605  $read_arr = array();
606  foreach($a_ref_ids as $ref_id)
607  {
608  if(!isset($this->ac_times[$ref_id]))
609  {
610  $read_arr[] = $ref_id;
611  }
612  }
613  if(count($read_arr))
614  {
615  $this->ac_times = (array) $this->ac_times + ilCourseItems::_readActivationTimes($read_arr);
616  }
617  }
618 
623  function doConditionCheck($a_permission, $a_cmd, $a_ref_id,$a_user_id, $a_obj_id, $a_type)
624  {
625  //echo "conditionCheck<br/>";
626  global $lng, $ilBench;
627 
628  if (($a_permission == "read" or $a_permission == 'join') &&
629  !$this->checkAccessOfUser($a_user_id, "write", "", $a_ref_id, $a_type, $a_obj_id))
630  {
631  $ilBench->start("AccessControl", "4000_checkAccess_condition_check");
632  if(!ilConditionHandler::_checkAllConditionsOfTarget($a_ref_id,$a_obj_id,$a_type,$a_user_id))
633  {
634  $conditions = ilConditionHandler::_getConditionsOfTarget($a_ref_id,$a_obj_id, $a_type);
635  foreach ($conditions as $condition)
636  {
637  $this->current_info->addInfoItem(IL_MISSING_PRECONDITION,
638  $lng->txt("missing_precondition").": ".
639  ilObject::_lookupTitle($condition["trigger_obj_id"])." ".
640  $lng->txt("condition_".$condition["operator"])." ".
641  $condition["value"], $condition);
642  }
643  $ilBench->stop("AccessControl", "4000_checkAccess_condition_check");
644  return false;
645  }
646  $ilBench->stop("AccessControl", "4000_checkAccess_condition_check");
647  }
648 
649  return true;
650  }
651 
656  function doStatusCheck($a_permission, $a_cmd, $a_ref_id,$a_user_id, $a_obj_id, $a_type)
657  {
658  global $objDefinition, $ilBench;
659  //echo "statusCheck<br/>";
660  $ilBench->start("AccessControl", "5000_checkAccess_object_check");
661 
662  $class = $objDefinition->getClassName($a_type);
663  $location = $objDefinition->getLocation($a_type);
664  $full_class = "ilObj".$class."Access";
665  include_once($location."/class.".$full_class.".php");
666  // static call to ilObj..::_checkAccess($a_cmd, $a_permission, $a_ref_id, $a_obj_id)
667 
668  $ilBench->start("AccessControl", "5001_checkAccess_".$full_class."_check");
669  $obj_access = call_user_func(array($full_class, "_checkAccess"),
670  $a_cmd, $a_permission, $a_ref_id, $a_obj_id, $a_user_id);
671  $ilBench->stop("AccessControl", "5001_checkAccess_".$full_class."_check");
672  if (!($obj_access === true))
673  {
674  //Note: We must not add an info item here, because one is going
675  // to be added by the user function we just called a few
676  // lines above.
677  //$this->current_info->addInfoItem(IL_NO_OBJECT_ACCESS, $obj_access);
678 
679  $this->storeAccessResult($a_permission, $a_cmd, $a_ref_id, false, $a_user_id);
680  $ilBench->stop("AccessControl", "5000_checkAccess_object_check");
681  return false;
682  }
683 
684  $this->storeAccessResult($a_permission, $a_cmd, $a_ref_id, true, $a_user_id);
685  $ilBench->stop("AccessControl", "5000_checkAccess_object_check");
686  return true;
687  }
688 
689  function clear()
690  {
691  $this->results = array();
692  $this->last_result = "";
693  $this->current_info = new ilAccessInfo();
694  }
695 
696  function enable($a_str,$a_bool)
697  {
698  $this->$a_str = $a_bool;
699  }
700 }