| [ Index ] |
PHP Cross Reference of MantisBT |
[Summary view] [Print] [Text view]
1 <?php 2 # MantisBT - A PHP based bugtracking system 3 4 # MantisBT is free software: you can redistribute it and/or modify 5 # it under the terms of the GNU General Public License as published by 6 # the Free Software Foundation, either version 2 of the License, or 7 # (at your option) any later version. 8 # 9 # MantisBT is distributed in the hope that it will be useful, 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # GNU General Public License for more details. 13 # 14 # You should have received a copy of the GNU General Public License 15 # along with MantisBT. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Access API 19 * 20 * @package CoreAPI 21 * @subpackage AccessAPI 22 * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org 23 * @copyright Copyright (C) 2002 - 2011 MantisBT Team - mantisbt-dev@lists.sourceforge.net 24 * @link http://www.mantisbt.org 25 * 26 * @uses authentication_api.php 27 * @uses bug_api.php 28 * @uses bugnote_api.php 29 * @uses config_api.php 30 * @uses constant_inc.php 31 * @uses current_user_api.php 32 * @uses database_api.php 33 * @uses error_api.php 34 * @uses helper_api.php 35 * @uses lang_api.php 36 * @uses print_api.php 37 * @uses project_api.php 38 * @uses string_api.php 39 * @uses user_api.php 40 */ 41 42 require_api( 'authentication_api.php' ); 43 require_api( 'bug_api.php' ); 44 require_api( 'bugnote_api.php' ); 45 require_api( 'config_api.php' ); 46 require_api( 'constant_inc.php' ); 47 require_api( 'current_user_api.php' ); 48 require_api( 'database_api.php' ); 49 require_api( 'error_api.php' ); 50 require_api( 'helper_api.php' ); 51 require_api( 'lang_api.php' ); 52 require_api( 'print_api.php' ); 53 require_api( 'project_api.php' ); 54 require_api( 'string_api.php' ); 55 require_api( 'user_api.php' ); 56 57 /** 58 * 59 * @global array $g_cache_access_matrix 60 */ 61 $g_cache_access_matrix = array(); 62 63 /** 64 * 65 * @global array $g_cache_access_matrix_project_ids 66 */ 67 $g_cache_access_matrix_project_ids = array(); 68 69 /** 70 * 71 * @global array $g_cache_access_matrix_user_ids 72 */ 73 $g_cache_access_matrix_user_ids = array(); 74 75 /** 76 * Function to be called when a user is attempting to access a page that 77 * he/she is not authorised to. This outputs an access denied message then 78 * re-directs to the mainpage. 79 */ 80 function access_denied() { 81 if( !auth_is_user_authenticated() ) { 82 if( basename( $_SERVER['SCRIPT_NAME'] ) != 'login_page.php' ) { 83 $t_return_page = $_SERVER['SCRIPT_NAME']; 84 if( isset( $_SERVER['QUERY_STRING'] ) ) { 85 $t_return_page .= '?' . $_SERVER['QUERY_STRING']; 86 } 87 $t_return_page = string_url( string_sanitize_url( $t_return_page ) ); 88 print_header_redirect( 'login_page.php' . '?return=' . $t_return_page ); 89 } 90 } else { 91 if( current_user_is_anonymous() ) { 92 if( basename( $_SERVER['SCRIPT_NAME'] ) != 'login_page.php' ) { 93 $t_return_page = $_SERVER['SCRIPT_NAME']; 94 if( isset( $_SERVER['QUERY_STRING'] ) ) { 95 $t_return_page .= '?' . $_SERVER['QUERY_STRING']; 96 } 97 $t_return_page = string_url( string_sanitize_url( $t_return_page ) ); 98 echo '<p class="center">' . error_string( ERROR_ACCESS_DENIED ) . '</p><p class="center">'; 99 print_bracket_link( helper_mantis_url( 'login_page.php' ) . '?return=' . $t_return_page, lang_get( 'click_to_login' ) ); 100 echo '</p><p class="center">'; 101 print_bracket_link( helper_mantis_url( 'main_page.php' ), lang_get( 'proceed' ) ); 102 echo '</p>'; 103 } 104 } else { 105 echo '<p class="center">' . error_string( ERROR_ACCESS_DENIED ) . '</p>'; 106 echo '<p class="center">'; 107 print_bracket_link( helper_mantis_url( 'main_page.php' ), lang_get( 'proceed' ) ); 108 echo '</p>'; 109 } 110 } 111 exit; 112 } 113 114 /** 115 * retrieves and returns access matrix for a project from cache or caching if required. 116 * @param int $p_project_id integer representing project id 117 * @return array returns an array of users->accesslevel for the given user 118 * @access private 119 */ 120 function access_cache_matrix_project( $p_project_id ) { 121 global $g_cache_access_matrix, $g_cache_access_matrix_project_ids; 122 123 if( ALL_PROJECTS == (int)$p_project_id ) { 124 return array(); 125 } 126 127 if( !in_array( (int) $p_project_id, $g_cache_access_matrix_project_ids ) ) { 128 $t_project_user_list_table = db_get_table( 'project_user_list' ); 129 130 $query = "SELECT user_id, access_level 131 FROM $t_project_user_list_table 132 WHERE project_id=" . db_param(); 133 $result = db_query_bound( $query, Array( (int)$p_project_id ) ); 134 $count = db_num_rows( $result ); 135 for( $i = 0;$i < $count;$i++ ) { 136 $row = db_fetch_array( $result ); 137 138 $g_cache_access_matrix[(int) $row['user_id']][(int) $p_project_id] = (int) $row['access_level']; 139 } 140 141 $g_cache_access_matrix_project_ids[] = (int) $p_project_id; 142 } 143 144 $t_results = array(); 145 146 foreach( $g_cache_access_matrix as $t_user ) { 147 if( isset( $t_user[(int) $p_project_id] ) ) { 148 $t_results[(int) $p_project_id] = $t_user[(int) $p_project_id]; 149 } 150 } 151 152 return $t_results; 153 } 154 155 /** 156 * retrieves and returns access matrix for a user from cache or caching if required. 157 * @param int $p_user_id integer representing user id 158 * @return array returns an array of projects->accesslevel for the given user 159 * @access private 160 */ 161 function access_cache_matrix_user( $p_user_id ) { 162 global $g_cache_access_matrix, $g_cache_access_matrix_user_ids; 163 164 if( !in_array( (int) $p_user_id, $g_cache_access_matrix_user_ids ) ) { 165 $t_project_user_list_table = db_get_table( 'project_user_list' ); 166 167 $query = "SELECT project_id, access_level 168 FROM $t_project_user_list_table 169 WHERE user_id=" . db_param(); 170 $result = db_query_bound( $query, Array( (int)$p_user_id ) ); 171 172 $count = db_num_rows( $result ); 173 174 # make sure we always have an array to return 175 $g_cache_access_matrix[(int) $p_user_id] = array(); 176 177 for( $i = 0;$i < $count;$i++ ) { 178 $row = db_fetch_array( $result ); 179 $g_cache_access_matrix[(int) $p_user_id][(int) $row['project_id']] = (int) $row['access_level']; 180 } 181 182 $g_cache_access_matrix_user_ids[] = (int) $p_user_id; 183 } 184 185 return $g_cache_access_matrix[(int) $p_user_id]; 186 } 187 188 /** 189 * Check the a user's access against the given "threshold" and return true 190 * if the user can access, false otherwise. 191 * $p_access_level may be a single value, or an array. If it is a single 192 * value, treat it as a threshold so return true if user is >= threshold. 193 * If it is an array, look for exact matches to one of the values 194 * @param int $p_user_access_level user access level 195 * @param int|array $p_threshold access threshold, defaults to NOBODY 196 * @return bool true or false depending on whether given access level matches the threshold 197 * @access public 198 */ 199 function access_compare_level( $p_user_access_level, $p_threshold = NOBODY ) { 200 if( is_array( $p_threshold ) ) { 201 return( in_array( $p_user_access_level, $p_threshold ) ); 202 } else { 203 return( $p_user_access_level >= $p_threshold ); 204 } 205 } 206 207 /** 208 * This function only checks the user's global access level, ignoring any 209 * overrides they might have at a project level 210 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 211 * @return int global access level 212 * @access public 213 */ 214 function access_get_global_level( $p_user_id = null ) { 215 if( $p_user_id === null ) { 216 $p_user_id = auth_get_current_user_id(); 217 } 218 219 # Deal with not logged in silently in this case 220 # @@@ we may be able to remove this and just error 221 # and once we default to anon login, we can remove it for sure 222 if( !auth_is_user_authenticated() ) { 223 return false; 224 } 225 226 return user_get_field( $p_user_id, 'access_level' ); 227 } 228 229 /** 230 * Check the current user's access against the given value and return true 231 * if the user's access is equal to or higher, false otherwise. 232 * @param int $p_access_level integer representing access level 233 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 234 * @return bool whether user has access level specified 235 * @access public 236 */ 237 function access_has_global_level( $p_access_level, $p_user_id = null ) { 238 # Short circuit the check in this case 239 if( NOBODY == $p_access_level ) { 240 return false; 241 } 242 243 if( $p_user_id === null ) { 244 $p_user_id = auth_get_current_user_id(); 245 } 246 247 $t_access_level = access_get_global_level( $p_user_id ); 248 249 return access_compare_level( $t_access_level, $p_access_level ); 250 } 251 252 /** 253 * Check if the user has the specified global access level 254 * and deny access to the page if not 255 * @see access_has_global_level 256 * @param int $p_access_level integer representing access level 257 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 258 * @access public 259 */ 260 function access_ensure_global_level( $p_access_level, $p_user_id = null ) { 261 if( !access_has_global_level( $p_access_level, $p_user_id ) ) { 262 access_denied(); 263 } 264 } 265 266 /** 267 * This function checks the project access level first (for the current project 268 * if none is specified) and if the user is not listed, it falls back on the 269 * user's global access level. 270 * @param int $p_project_id integer representing project id to check access against 271 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 272 * @return int access level user has to given project 273 * @access public 274 */ 275 function access_get_project_level( $p_project_id = null, $p_user_id = null ) { 276 # Deal with not logged in silently in this case 277 /** @todo we may be able to remove this and just error and once we default to anon login, we can remove it for sure */ 278 if( !auth_is_user_authenticated() ) { 279 return ANYBODY; 280 } 281 282 if( null === $p_user_id ) { 283 $p_user_id = auth_get_current_user_id(); 284 } 285 286 if( null === $p_project_id ) { 287 $p_project_id = helper_get_current_project(); 288 } 289 290 $t_global_access_level = access_get_global_level( $p_user_id ); 291 292 if( ALL_PROJECTS == $p_project_id || user_is_administrator( $p_user_id ) ) { 293 return $t_global_access_level; 294 } else { 295 $t_project_access_level = access_get_local_level( $p_user_id, $p_project_id ); 296 $t_project_view_state = project_get_field( $p_project_id, 'view_state' ); 297 298 # Try to use the project access level. 299 # If the user is not listed in the project, then try to fall back 300 # to the global access level 301 if( false === $t_project_access_level ) { 302 # If the project is private and the user isn't listed, then they 303 # must have the private_project_threshold access level to get in. 304 if( VS_PRIVATE == $t_project_view_state ) { 305 if( access_compare_level( $t_global_access_level, config_get( 'private_project_threshold', null, null, ALL_PROJECTS ) ) ) { 306 return $t_global_access_level; 307 } else { 308 return ANYBODY; 309 } 310 } else { 311 # project access not set, but the project is public 312 return $t_global_access_level; 313 } 314 } else { 315 # project specific access was set 316 return $t_project_access_level; 317 } 318 } 319 } 320 321 /** 322 * Check the current user's access against the given value and return true 323 * if the user's access is equal to or higher, false otherwise. 324 * @param int $p_access_level integer representing access level 325 * @param int $p_project_id integer representing project id to check access against 326 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 327 * @return bool whether user has access level specified 328 * @access public 329 */ 330 function access_has_project_level( $p_access_level, $p_project_id = null, $p_user_id = null ) { 331 # Short circuit the check in this case 332 if( NOBODY == $p_access_level ) { 333 return false; 334 } 335 336 if( null === $p_user_id ) { 337 $p_user_id = auth_get_current_user_id(); 338 } 339 if( null === $p_project_id ) { 340 $p_project_id = helper_get_current_project(); 341 } 342 343 $t_access_level = access_get_project_level( $p_project_id, $p_user_id ); 344 345 return access_compare_level( $t_access_level, $p_access_level ); 346 } 347 348 /** 349 * Check if the user has the specified access level for the given project 350 * and deny access to the page if not 351 * @see access_has_project_level 352 * @param int $p_access_level integer representing access level 353 * @param int|null $p_project_id integer representing project id to check access against, defaults to null to use current project 354 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 355 * @access public 356 */ 357 function access_ensure_project_level( $p_access_level, $p_project_id = null, $p_user_id = null ) { 358 if( !access_has_project_level( $p_access_level, $p_project_id, $p_user_id ) ) { 359 access_denied(); 360 } 361 } 362 363 /** 364 * Check whether the user has the specified access level for any project project 365 * @param int $p_access_level integer representing access level 366 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 367 * @return bool whether user has access level specified 368 * @access public 369 */ 370 function access_has_any_project( $p_access_level, $p_user_id = null ) { 371 # Short circuit the check in this case 372 373 if( NOBODY == $p_access_level ) { 374 return false; 375 } 376 377 if( null === $p_user_id ) { 378 $p_user_id = auth_get_current_user_id(); 379 } 380 381 $t_projects = project_get_all_rows(); 382 foreach( $t_projects as $t_project ) { 383 if ( access_has_project_level( $p_access_level, $t_project['id'], $p_user_id ) ) { 384 return true; 385 } 386 } 387 388 return false; 389 } 390 391 /** 392 * Check the current user's access against the given value and return true 393 * if the user's access is equal to or higher, false otherwise. 394 * This function looks up the bug's project and performs an access check 395 * against that project 396 * @param int $p_access_level integer representing access level 397 * @param int $p_bug_id integer representing bug id to check access against 398 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 399 * @return bool whether user has access level specified 400 * @access public 401 */ 402 function access_has_bug_level( $p_access_level, $p_bug_id, $p_user_id = null ) { 403 # Deal with not logged in silently in this case 404 # @@@ we may be able to remove this and just error 405 # and once we default to anon login, we can remove it for sure 406 if( !auth_is_user_authenticated() ) { 407 return false; 408 } 409 410 if( $p_user_id === null ) { 411 $p_user_id = auth_get_current_user_id(); 412 } 413 414 $t_project_id = bug_get_field( $p_bug_id, 'project_id' ); 415 416 # check limit_Reporter (Issue #4769) 417 # reporters can view just issues they reported 418 $t_limit_reporters = config_get( 'limit_reporters' ); 419 if(( ON === $t_limit_reporters ) && ( !bug_is_user_reporter( $p_bug_id, $p_user_id ) ) && ( !access_has_project_level( REPORTER + 1, $t_project_id, $p_user_id ) ) ) { 420 return false; 421 } 422 423 # If the bug is private and the user is not the reporter, then the 424 # the user must also have higher access than private_bug_threshold 425 if( VS_PRIVATE == bug_get_field( $p_bug_id, 'view_state' ) && !bug_is_user_reporter( $p_bug_id, $p_user_id ) ) { 426 $p_access_level = max( $p_access_level, config_get( 'private_bug_threshold' ) ); 427 } 428 429 return access_has_project_level( $p_access_level, $t_project_id, $p_user_id ); 430 } 431 432 /** 433 * Check if the user has the specified access level for the given bug 434 * and deny access to the page if not 435 * @see access_has_bug_level 436 * @param int $p_access_level integer representing access level 437 * @param int $p_bug_id integer representing bug id to check access against 438 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 439 * @return bool whether user has access level specified 440 * @access public 441 */ 442 function access_ensure_bug_level( $p_access_level, $p_bug_id, $p_user_id = null ) { 443 if( !access_has_bug_level( $p_access_level, $p_bug_id, $p_user_id ) ) { 444 access_denied(); 445 } 446 } 447 448 /** 449 * Check the current user's access against the given value and return true 450 * if the user's access is equal to or higher, false otherwise. 451 * This function looks up the bugnote's bug and performs an access check 452 * against that bug 453 * @param int $p_access_level integer representing access level 454 * @param int $p_bugnote_id integer representing bugnote id to check access against 455 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 456 * @return bool whether user has access level specified 457 * @access public 458 */ 459 function access_has_bugnote_level( $p_access_level, $p_bugnote_id, $p_user_id = null ) { 460 if( null === $p_user_id ) { 461 $p_user_id = auth_get_current_user_id(); 462 } 463 464 # If the bug is private and the user is not the reporter, then the 465 # the user must also have higher access than private_bug_threshold 466 if( VS_PRIVATE == bugnote_get_field( $p_bugnote_id, 'view_state' ) && !bugnote_is_user_reporter( $p_bugnote_id, $p_user_id ) ) { 467 $p_access_level = max( $p_access_level, config_get( 'private_bugnote_threshold' ) ); 468 } 469 470 $t_bug_id = bugnote_get_field( $p_bugnote_id, 'bug_id' ); 471 472 return access_has_bug_level( $p_access_level, $t_bug_id, $p_user_id ); 473 } 474 475 /** 476 * Check if the user has the specified access level for the given bugnote 477 * and deny access to the page if not 478 * @see access_has_bugnote_level 479 * @param int $p_access_level integer representing access level 480 * @param int $p_bugnote_id integer representing bugnote id to check access against 481 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 482 * @access public 483 */ 484 function access_ensure_bugnote_level( $p_access_level, $p_bugnote_id, $p_user_id = null ) { 485 if( !access_has_bugnote_level( $p_access_level, $p_bugnote_id, $p_user_id ) ) { 486 access_denied(); 487 } 488 } 489 490 /** 491 * Check if the current user can close the specified bug 492 * @param int $p_bug_id integer representing bug id to check access against 493 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 494 * @return bool whether user has access to close bugs 495 * @access public 496 */ 497 function access_can_close_bug( $p_bug_id, $p_user_id = null ) { 498 if( null === $p_user_id ) { 499 $p_user_id = auth_get_current_user_id(); 500 } 501 502 # If allow_reporter_close is enabled, then reporters can always close their own bugs 503 if( ON == config_get( 'allow_reporter_close' ) && bug_is_user_reporter( $p_bug_id, $p_user_id ) ) { 504 return true; 505 } 506 507 $t_bug = bug_get( $p_bug_id ); 508 509 $t_closed_status_threshold = access_get_status_threshold( config_get( 'bug_closed_status_threshold' ), $t_bug->project_id ); 510 511 return access_has_bug_level( $t_closed_status_threshold, $p_bug_id, $p_user_id ); 512 } 513 514 /** 515 * Make sure that the current user can close the specified bug 516 * @see access_can_close_bug 517 * @param int $p_bug_id integer representing bug id to check access against 518 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 519 * @access public 520 */ 521 function access_ensure_can_close_bug( $p_bug_id, $p_user_id = null ) { 522 if( !access_can_close_bug( $p_bug_id, $p_user_id ) ) { 523 access_denied(); 524 } 525 } 526 527 /** 528 * Check if the current user can reopen the specified bug 529 * @param int $p_bug_id integer representing bug id to check access against 530 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 531 * @return bool whether user has access to reopen bugs 532 * @access public 533 */ 534 function access_can_reopen_bug( $p_bug_id, $p_user_id = null ) { 535 if( $p_user_id === null ) { 536 $p_user_id = auth_get_current_user_id(); 537 } 538 539 # If allow_reporter_reopen is enabled, then reporters can always reopen their own bugs 540 if( ON == config_get( 'allow_reporter_reopen' ) && bug_is_user_reporter( $p_bug_id, $p_user_id ) ) { 541 return true; 542 } 543 544 return access_has_bug_level( config_get( 'reopen_bug_threshold' ), $p_bug_id, $p_user_id ); 545 } 546 547 /** 548 * Make sure that the current user can reopen the specified bug. 549 * Calls access_denied if user has no access to terminate script 550 * @see access_can_reopen_bug 551 * @param int $p_bug_id integer representing bug id to check access against 552 * @param int|null $p_user_id integer representing user id, defaults to null to use current user 553 * @access public 554 */ 555 function access_ensure_can_reopen_bug( $p_bug_id, $p_user_id = null ) { 556 if( !access_can_reopen_bug( $p_bug_id, $p_user_id ) ) { 557 access_denied(); 558 } 559 } 560 561 /** 562 * get the user's access level specific to this project. 563 * return false (0) if the user has no access override here 564 * @param int $p_user_id Integer representing user id 565 * @param int $p_project_id integer representing project id 566 * @return bool|int returns false (if no access) or an integer representing level of access 567 * @access public 568 */ 569 function access_get_local_level( $p_user_id, $p_project_id ) { 570 global $g_cache_access_matrix, $g_cache_access_matrix_project_ids; 571 572 $p_project_id = (int) $p_project_id; 573 $p_user_id = (int) $p_user_id; 574 575 if( in_array( $p_project_id, $g_cache_access_matrix_project_ids ) ) { 576 if( isset( $g_cache_access_matrix[$p_user_id][$p_project_id] ) ) { 577 return $g_cache_access_matrix[$p_user_id][$p_project_id]; 578 } else { 579 return false; 580 } 581 } 582 583 $t_project_level = access_cache_matrix_user( $p_user_id ); 584 585 if( isset( $t_project_level[$p_project_id] ) ) { 586 return $t_project_level[$p_project_id]; 587 } else { 588 return false; 589 } 590 } 591 592 /** 593 * get the access level required to change the issue to the new status 594 * If there is no specific differentiated access level, use the 595 * generic update_bug_status_threshold. 596 * @param int $p_status 597 * @param int $p_project_id Default value ALL_PROJECTS 598 * @return int integer representing user level e.g. DEVELOPER 599 * @access public 600 */ 601 function access_get_status_threshold( $p_status, $p_project_id = ALL_PROJECTS ) { 602 $t_thresh_array = config_get( 'set_status_threshold', null, null, $p_project_id ); 603 if( isset( $t_thresh_array[(int)$p_status] ) ) { 604 return (int)$t_thresh_array[(int)$p_status]; 605 } else { 606 return config_get( 'update_bug_status_threshold', null, null, $p_project_id ); 607 } 608 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Jul 28 15:48:31 2011 | Cross-referenced by PHPXref 0.7 |