3 * FusionForge RBAC engine
5 * Copyright 2010, Roland Mas
7 * This file is part of FusionForge. FusionForge is free software;
8 * you can redistribute it and/or modify it under the terms of the
9 * GNU General Public License as published by the Free Software
10 * Foundation; either version 2 of the Licence, or (at your option)
13 * FusionForge 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.
18 * You should have received a copy of the GNU General Public License along
19 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 require_once $gfcommon.'include/RBAC.php' ;
26 * TODO: Enter description here ...
29 class RBACEngine extends Error implements PFO_RBACEngine {
30 private static $_instance ;
31 private $_cached_roles = array () ;
32 private $_cached_available_roles = NULL ;
33 private $_cached_global_roles = NULL ;
34 private $_cached_public_roles = NULL ;
36 // singleton constructor
37 public static function getInstance() {
38 if (!isset(self::$_instance)) {
40 self::$_instance = new $c;
43 return self::$_instance;
47 * @see PFO_RBACEngine::getAvailableRoles()
49 public function getAvailableRoles() {
50 if ($this->_cached_available_roles != NULL) {
51 return $this->_cached_available_roles ;
54 $this->_cached_available_roles = array () ;
56 $this->_cached_available_roles[] = RoleAnonymous::getInstance() ;
58 if (session_loggedin()) {
59 $this->_cached_available_roles[] = RoleLoggedIn::getInstance() ;
60 $user = session_get_user() ;
62 $res = db_query_params ('SELECT role_id FROM pfo_user_role WHERE user_id=$1',
63 array ($user->getID()));
64 while ($arr = db_fetch_array($res)) {
65 $this->_cached_available_roles[] = $this->getRoleById ($arr['role_id']) ;
70 $params['current_roles'] = $this->_cached_available_roles;
71 $params['new_roles'] = array();
72 plugin_hook_by_reference('get_extra_roles', $params);
73 foreach ($params['new_roles'] as $r) {
74 $this->addAvailableRole($r);
78 $params['current_roles'] = $this->_cached_available_roles;
79 $params['dropped_roles'] = array();
80 plugin_hook_by_reference('restrict_roles', $params);
81 foreach ($params['dropped_roles'] as $r) {
82 $this->dropAvailableRole($r);
85 return $this->_cached_available_roles ;
88 private function addAvailableRole($role) {
90 foreach ($this->_cached_available_roles as $r) {
91 if ($r->getID() == $role->getID()) {
96 $this->_cached_available_roles[] = $role;
100 private function dropAvailableRole($role) {
101 $new_roles = array();
102 foreach ($this->_cached_available_roles as $r) {
103 if ($r->getID() != $role->getID()) {
107 $this->_cached_available_roles = $new_roles;
110 public function getGlobalRoles() {
111 if ($this->_cached_global_roles != NULL) {
112 return $this->_cached_global_roles ;
115 $this->_cached_global_roles = array () ;
117 $res = db_query_params ('SELECT role_id FROM pfo_role WHERE home_group_id IS NULL',
119 while ($arr = db_fetch_array($res)) {
120 $this->_cached_global_roles[] = $this->getRoleById ($arr['role_id']) ;
123 return $this->_cached_global_roles ;
126 public function getPublicRoles() {
127 if ($this->_cached_public_roles != NULL) {
128 return $this->_cached_public_roles ;
131 $this->_cached_public_roles = array () ;
133 $res = db_query_params ('SELECT role_id FROM pfo_role WHERE is_public=$1',
135 while ($arr = db_fetch_array($res)) {
136 $this->_cached_public_roles[] = $this->getRoleById ($arr['role_id']) ;
139 return $this->_cached_public_roles ;
142 public function invalidateRoleCaches () {
143 $this->_cached_available_roles = NULL ;
144 $this->_cached_global_roles = NULL ;
145 $this->_cached_public_roles = NULL ;
148 public function getAvailableRolesForUser($user) {
151 $result[] = RoleAnonymous::getInstance() ;
152 $result[] = RoleLoggedIn::getInstance() ;
154 $uid = is_object($user) ? $user->getID() : $user;
156 $res = db_query_params ('SELECT role_id FROM pfo_user_role WHERE user_id=$1',
158 while ($arr = db_fetch_array($res)) {
159 $result[] = $this->getRoleById ($arr['role_id']) ;
166 * @see PFO_RBACEngine::isActionAllowed()
168 public function isActionAllowed ($section, $reference, $action = NULL) {
169 $rlist = $this->getAvailableRoles () ;
170 foreach ($rlist as $r) {
171 if ($r->hasPermission ($section, $reference, $action)) {
178 public function isGlobalActionAllowed ($section, $action = NULL) {
179 return $this->isActionAllowed ($section, -1, $action) ;
182 public function isActionAllowedForUser ($user, $section, $reference, $action = NULL) {
183 $rlist = $this->getAvailableRolesForUser ($user) ;
184 foreach ($rlist as $r) {
185 if ($r->hasPermission ($section, $reference, $action)) {
192 public function isGlobalActionAllowedForUser ($user, $section, $action = NULL) {
193 return $this->isActionAllowedForUser ($user, $section, -1, $action) ;
196 public function getRoleById ($role_id) {
197 if (array_key_exists ($role_id, $this->_cached_roles)) {
198 return $this->_cached_roles[$role_id] ;
200 $res = db_query_params ('SELECT c.class_name, r.home_group_id FROM pfo_role r, pfo_role_class c WHERE r.role_class = c.class_id AND r.role_id = $1',
202 if (!$res || !db_numrows($res)) {
206 $class_id = db_result ($res, 0, 'class_name') ;
208 case 'PFO_RoleExplicit':
209 $group_id = db_result ($res, 0, 'home_group_id') ;
210 $group = group_get_object ($group_id) ;
211 $this->_cached_roles[$role_id] = new Role ($group, $role_id) ;
212 return $this->_cached_roles[$role_id] ;
213 case 'PFO_RoleAnonymous':
214 $this->_cached_roles[$role_id] = RoleAnonymous::getInstance() ;
215 return $this->_cached_roles[$role_id] ;
216 case 'PFO_RoleLoggedIn':
217 $this->_cached_roles[$role_id] = RoleLoggedIn::getInstance() ;
218 return $this->_cached_roles[$role_id] ;
220 throw new Exception ("Not implemented") ;
224 public function getRolesByAllowedAction ($section, $reference, $action = NULL) {
225 $ids = $this->_getRolesIdByAllowedAction ($section, $reference, $action) ;
227 foreach ($ids as $role_id) {
228 $roles[] = $this->getRoleById ($role_id) ;
234 public function getUsersByAllowedAction ($section, $reference, $action = NULL) {
235 $roles = $this->getRolesByAllowedAction ($section, $reference, $action) ;
236 $user_ids = array () ;
237 foreach ($roles as $role) {
238 foreach ($role->getUsers() as $user) {
239 $user_ids[] = $user->getID() ;
243 $user_ids = array_unique ($user_ids) ;
245 return user_get_objects ($user_ids) ;
248 private function _getRolesIdByAllowedAction ($section, $reference, $action = NULL) {
250 $qpa = db_construct_qpa () ;
251 $qpa = db_construct_qpa ($qpa,
252 'SELECT role_id FROM pfo_role_setting WHERE section_name=$1 AND ref_id=$2 ',
256 // Look for roles that are directly allowed to perform action
261 case 'approve_projects':
263 case 'project_admin':
265 case 'tracker_admin':
268 $qpa = db_construct_qpa ($qpa, 'AND perm_val = 1') ;
273 $qpa = db_construct_qpa ($qpa, 'AND perm_val != 0') ;
276 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 1') ;
279 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 2') ;
286 $qpa = db_construct_qpa ($qpa, 'AND perm_val != 0') ;
289 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 1') ;
292 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 2') ;
299 $qpa = db_construct_qpa ($qpa, 'AND perm_val != 0') ;
302 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 1') ;
305 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 2') ;
308 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 3') ;
311 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 4') ;
318 $qpa = db_construct_qpa ($qpa, 'AND perm_val != 0') ;
321 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 1') ;
324 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 2') ;
327 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 3') ;
334 $qpa = db_construct_qpa ($qpa, 'AND perm_val != 0') ;
337 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 1') ;
340 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 2') ;
342 case 'unmoderated_post':
343 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 3') ;
346 $qpa = db_construct_qpa ($qpa, 'AND perm_val >= 4') ;
354 $qpa = db_construct_qpa ($qpa, 'AND perm_val != 0') ;
357 $qpa = db_construct_qpa ($qpa, 'AND (perm_val & 1) = 1') ;
360 $qpa = db_construct_qpa ($qpa, 'AND (perm_val & 2) = 2') ;
363 $qpa = db_construct_qpa ($qpa, 'AND (perm_val & 4) = 4') ;
368 $hook_params = array ();
369 $hook_params['section'] = $section ;
370 $hook_params['reference'] = $reference ;
371 $hook_params['action'] = $action ;
372 $hook_params['qpa'] = $qpa ;
373 $hook_params['result'] = $result ;
374 plugin_hook_by_reference ("list_roles_by_permission", $hook_params);
375 $qpa = $hook_params['qpa'] ;
379 $res = db_query_qpa ($qpa) ;
381 $this->setError('RBACEngine::getRolesByAllowedAction()::'.db_error());
384 while ($arr = db_fetch_array($res)) {
385 $result[] = $arr['role_id'] ;
388 // Also look for roles that can perform the action because they're more powerful
392 case 'approve_projects':
395 case 'project_admin':
396 $result = array_merge ($result, $this->_getRolesIdByAllowedAction ('forge_admin', -1)) ;
399 case 'tracker_admin':
405 $result = array_merge ($result, $this->_getRolesIdByAllowedAction ('project_admin', $reference)) ;
408 if ($action != 'tech') {
409 $t = artifactType_get_object ($reference) ;
410 $result = array_merge ($result, $this->_getRolesIdByAllowedAction ('tracker_admin', $t->Group->getID())) ;
414 if ($action != 'tech') {
415 $t = projectgroup_get_object ($reference) ;
416 $result = array_merge ($result, $this->_getRolesIdByAllowedAction ('pm_admin', $t->Group->getID())) ;
420 $t = forum_get_object ($reference) ;
421 $result = array_merge ($result, $this->_getRolesIdByAllowedAction ('forum_admin', $t->Group->getID())) ;
424 if ($action != 'tech') {
425 $result = array_merge ($result, $this->_getRolesIdByAllowedAction ('tracker_admin', $reference)) ;
429 if ($action != 'tech') {
430 $result = array_merge ($result, $this->_getRolesIdByAllowedAction ('pm_admin', $reference)) ;
434 $t = forum_get_object ($reference) ;
435 $result = array_merge ($result, $this->_getRolesIdByAllowedAction ('forum_admin', $reference)) ;
439 return array_unique ($result) ;
444 * Check if permission is allowed for an action on a reference in the context of a section
445 * @param string $section
446 * @param unknown_type $reference (group_id, ...)
447 * @param string $action
449 function forge_check_perm ($section, $reference, $action = NULL) {
450 $engine = RBACEngine::getInstance() ;
452 return $engine->isActionAllowed($section, $reference, $action) ;
456 * TODO: Enter description here ...
457 * @param unknown_type $section
458 * @param unknown_type $action
460 function forge_check_global_perm ($section, $action = NULL) {
461 $engine = RBACEngine::getInstance() ;
463 return $engine->isGlobalActionAllowed($section, $action) ;
466 function forge_check_perm_for_user ($user, $section, $reference, $action = NULL) {
467 $engine = RBACEngine::getInstance() ;
469 return $engine->isActionAllowedForUser($user, $section, $reference, $action) ;
472 function forge_check_global_perm_for_user ($user, $section, $action = NULL) {
473 $engine = RBACEngine::getInstance() ;
475 return $engine->isGlobalActionAllowedForUser($user, $section, $action) ;
480 // c-file-style: "bsd"