[ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
1 <?php 2 /**************************************************************************\ 3 * eGroupWare API - Access Control List * 4 * This file written by Dan Kuykendall <seek3r@phpgroupware.org> * 5 * Security scheme based on ACL design * 6 * Copyright (C) 2000, 2001 Dan Kuykendall * 7 * -------------------------------------------------------------------------* 8 * This library is part of the eGroupWare API * 9 * http://www.egroupware.org/api * 10 * ------------------------------------------------------------------------ * 11 * This library is free software; you can redistribute it and/or modify it * 12 * under the terms of the GNU Lesser General Public License as published by * 13 * the Free Software Foundation; either version 2.1 of the License, * 14 * or any later version. * 15 * This library is distributed in the hope that it will be useful, but * 16 * WITHOUT ANY WARRANTY; without even the implied warranty of * 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * 18 * See the GNU Lesser General Public License for more details. * 19 * You should have received a copy of the GNU Lesser General Public License * 20 * along with this library; if not, write to the Free Software Foundation, * 21 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 22 \**************************************************************************/ 23 24 /* $Id: class.acl.inc.php 20295 2006-02-15 12:31:25Z $ */ 25 26 /** 27 * Access Control List System 28 * 29 * This class provides an ACL security scheme. 30 * This can manage rights to 'run' applications, and limit certain features within an application. 31 * It is also used for granting a user "membership" to a group, or making a user have the security equivilance of another user. 32 * It is also used for granting a user or group rights to various records, such as todo or calendar items of another user. 33 * $acl =& CreateObject('phpgwapi.acl',5); // 5 is the user id 34 * 35 * @author Seek3r and others 36 * @copyright LGPL 37 * @package api 38 * @subpackage accounts 39 * @access public 40 */ 41 class acl 42 { 43 /** 44 * @var int $account_id the account-id this class is instanciated for 45 */ 46 var $account_id = 0; 47 /** 48 * @var $account_type 49 */ 50 var $account_type; 51 /** 52 * @var array $data internal repository with acl rows for the given app and account-id (incl. memberships) 53 */ 54 var $data = Array(); 55 /** 56 * @var object/db $db internal copy of the db-object 57 */ 58 var $db; 59 /** 60 * @var string $table_name name of the acl_table 61 */ 62 var $table_name = 'egw_acl'; 63 64 /** 65 * ACL constructor for setting account id 66 * 67 * Sets the ID for $acl->account_id. Can be used to change a current instances id as well. 68 * Some functions are specific to this account, and others are generic. 69 * 70 * @example acl->acl(5); // 5 is the user id 71 * @param int $account_id int-the user id 72 */ 73 function acl($account_id = '') 74 { 75 if (is_object($GLOBALS['egw_setup']->db)) 76 { 77 $this->db = clone($GLOBALS['egw_setup']->db); 78 } 79 else 80 { 81 $this->db = clone($GLOBALS['egw']->db); 82 } 83 $this->db->set_app('phpgwapi'); 84 85 if ((int)$this->account_id != (int)$account_id) 86 { 87 $this->account_id = get_account_id((int)$account_id,@$GLOBALS['egw_info']['user']['account_id']); 88 } 89 } 90 91 function DONTlist_methods($_type='xmlrpc') 92 { 93 /* 94 This handles introspection or discovery by the logged in client, 95 in which case the input might be an array. The server always calls 96 this function to fill the server dispatch map using a string. 97 */ 98 99 if (is_array($_type)) 100 { 101 $_type = $_type['type'] ? $_type['type'] : $_type[0]; 102 } 103 104 switch($_type) 105 { 106 case 'xmlrpc': 107 $xml_functions = array( 108 'read_repository' => array( 109 'function' => 'read_repository', 110 'signature' => array(array(xmlrpcStruct)), 111 'docstring' => lang('FIXME!') 112 ), 113 'get_rights' => array( 114 'function' => 'get_rights', 115 'signature' => array(array(xmlrpcStruct,xmlrpcStruct)), 116 'docstring' => lang('FIXME!') 117 118 ), 119 'list_methods' => array( 120 'function' => 'list_methods', 121 'signature' => array(array(xmlrpcStruct,xmlrpcString)), 122 'docstring' => lang('Read this list of methods.') 123 ) 124 ); 125 return $xml_functions; 126 break; 127 case 'soap': 128 return $this->soap_functions; 129 break; 130 default: 131 return array(); 132 break; 133 } 134 } 135 136 /**************************************************************************\ 137 * These are the standard $this->account_id specific functions * 138 \**************************************************************************/ 139 140 /** 141 * Read acl records for $acl->account_id from reposity 142 * 143 * @internal 144 * @return array along with storing it in $acl->data. <br> 145 */ 146 function read_repository() 147 { 148 // For some reason, calling this via XML-RPC doesn't call the constructor. 149 // Here is yet another work around(tm) (jengo) 150 if (!$this->account_id) 151 { 152 $this->acl(); 153 } 154 $acl_acc_list = array_values((array)$this->get_location_list_for_id('phpgw_group', 1, $this->account_id)); 155 array_unshift($acl_acc_list,$this->account_id,0); 156 $this->db->select($this->table_name,'*',array('acl_account' => $acl_acc_list ),__LINE__,__FILE__); 157 158 $this->data = Array(); 159 while(($row = $this->db->row(true))) 160 { 161 $this->data[] = array( 162 'appname' => $row['acl_appname'], 163 'location' => $row['acl_location'], 164 'account' => $row['acl_account'], 165 'rights' => $row['acl_rights'], 166 ); 167 } 168 return $this->data; 169 } 170 171 /** 172 * Read acl records from $acl->data 173 * 174 * @return array all ACL records from $this->data. 175 */ 176 function read() 177 { 178 if (!count($this->data)) 179 { 180 $this->read_repository(); 181 } 182 return $this->data; 183 } 184 185 /** 186 * Adds ACL record to the repository of the class 187 * 188 * Adds ACL record to $this->data. 189 * 190 * @param string $appname default False derives value from $GLOBALS['egw_info']['flags']['currentapp'] 191 * @param string $location location 192 * @param int $rights rights 193 * @return array all ACL records from $this->data. 194 */ 195 function add($appname,$location,$rights) 196 { 197 if (!$appname) $appname = $GLOBALS['egw_info']['flags']['currentapp']; 198 199 $this->data[] = array( 200 'appname' => $appname, 201 'location' => $location, 202 'account' => (int) $this->account_id, 203 'rights' => (int) $rights 204 ); 205 206 return $this->data; 207 } 208 209 /** 210 * Delete ACL record in the repository of the class 211 * 212 * @param string $appname appname or '' for $GLOBALS['egw_info']['flags']['currentapp'] 213 * @param string $location location 214 * @return array all ACL records from $this->data. 215 */ 216 function delete($appname,$location) 217 { 218 if (!$appname) $appname = $GLOBALS['egw_info']['flags']['currentapp']; 219 220 foreach($this->data as $idx => $value) 221 { 222 if ($this->data[$idx]['appname'] == $appname && $this->data[$idx]['location'] == $location && $this->data[$idx]['account'] == $this->account_id) 223 { 224 unset($this->data[$idx]); 225 } 226 } 227 return $this->data; 228 } 229 230 /** 231 * save the internal repository or the class 232 * 233 * @return array all ACL records from $this->data. 234 */ 235 function save_repository() 236 { 237 $this->db->delete($this->table_name,array( 238 'acl_account' => $this->account_id, 239 ),__LINE__,__FILE__); 240 241 foreach($this->data as $value) 242 { 243 if ($value['account'] == $this->account_id) 244 { 245 $this->db->insert($this->table_name,array( 246 'acl_appname' => $value['appname'], 247 'acl_location' => $value['location'], 248 'acl_account' => $this->account_id, 249 'acl_rights' => $value['rights'], 250 ),false,__LINE__,__FILE__); 251 } 252 } 253 if ($this->account_id == $GLOBALS['egw_info']['user']['account_id'] && 254 method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited 255 { 256 $GLOBALS['egw']->invalidate_session_cache(); 257 } 258 return $this->data; 259 } 260 261 /**************************************************************************\ 262 * These are the non-standard $this->account_id specific functions * 263 \**************************************************************************/ 264 265 /** 266 * get rights from the class repository (included rights of $this->account_id and all it's memberships) 267 * 268 * @param string $location app location to get rights from 269 * @param string $appname optional defaults to $GLOBALS['egw_info']['flags']['currentapp']; 270 * @return int all rights or'ed together 271 */ 272 function get_rights($location,$appname = '') 273 { 274 // For XML-RPC, change this once its working correctly for passing parameters (jengo) 275 if (is_array($location)) 276 { 277 $appname = $location['appname']; 278 $location = $location['location']; 279 } 280 281 if (!count($this->data)) 282 { 283 $this->read_repository(); 284 } 285 if (!$appname) $appname = $GLOBALS['egw_info']['flags']['currentapp']; 286 287 if (!count($this->data) && $GLOBALS['egw_info']['server']['acl_default'] != 'deny') 288 { 289 return True; 290 } 291 $rights = 0; 292 foreach($this->data as $idx => $value) 293 { 294 if ($value['appname'] == $appname) 295 { 296 if ($value['location'] == $location || $value['location'] == 'everywhere') 297 { 298 if ($value['rights'] == 0) 299 { 300 return False; 301 } 302 $rights |= $value['rights']; 303 } 304 } 305 } 306 return $rights; 307 } 308 309 /** 310 * check required rights agains the internal repository (included rights of $this->account_id and all it's memberships) 311 * 312 * @param $location app location 313 * @param $required required right to check against 314 * @param $appname optional defaults to currentapp 315 * @return boolean 316 */ 317 function check($location, $required, $appname = False) 318 { 319 $rights = $this->get_rights($location,$appname); 320 321 return !!($rights & $required); 322 } 323 324 /** 325 * get specific rights for this->account_id for an app location 326 * 327 * @param string $location app location 328 * @param string $appname='' optional defaults to currentapp 329 * @param int $account_id=0 optional defaults to $this->account_id 330 * @return int $rights 331 */ 332 function get_specific_rights($location, $appname = '') 333 { 334 if (!$appname) $appname = $GLOBALS['egw_info']['flags']['currentapp']; 335 336 if (!count($this->data) && $GLOBALS['egw_info']['server']['acl_default'] != 'deny') 337 { 338 return True; 339 } 340 $rights = 0; 341 342 foreach($this->data as $idx => $value) 343 { 344 if ($value['appname'] == $appname && 345 ($value['location'] == $location || $value['location'] == 'everywhere') && 346 $value['account'] == $this->account_id) 347 { 348 if ($value['rights'] == 0) 349 { 350 return False; 351 } 352 $rights |= $value['rights']; 353 } 354 } 355 return $rights; 356 } 357 358 /** 359 * check specific rights 360 * 361 * @param string $location app location 362 * @param int $required required rights 363 * @param string $appname optional defaults to currentapp 364 * @return boolean 365 */ 366 function check_specific($location, $required, $appname = '') 367 { 368 $rights = $this->get_specific_rights($location,$appname); 369 370 return !!($rights & $required); 371 } 372 373 /**************************************************************************\ 374 * These are the generic functions. Not specific to $this->account_id * 375 \**************************************************************************/ 376 377 /** 378 * add repository information / rights for app/location/account_id to the database 379 * 380 * @param string $app appname 381 * @param string $location location 382 * @param int $account_id account id 383 * @param int $rights rights 384 * @return boolean allways true 385 */ 386 function add_repository($app, $location, $account_id, $rights) 387 { 388 //echo "<p>acl::add_repository('$app','$location',$account_id,$rights);</p>\n"; 389 $this->db->insert($this->table_name,array( 390 'acl_rights' => $rights, 391 ),array( 392 'acl_appname' => $app, 393 'acl_location' => $location, 394 'acl_account' => $account_id, 395 ),__LINE__,__FILE__); 396 397 if ($account_id == $GLOBALS['egw_info']['user']['account_id'] && 398 method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited 399 { 400 $GLOBALS['egw']->invalidate_session_cache(); 401 } 402 return True; 403 } 404 405 /** 406 * delete repository information / rights for app/location[/account_id] from the DB 407 * 408 * @param string $app appname 409 * @param string $location location 410 * @param int/boolean $account_id account id, default 0=$this->account_id, or false to delete all entries for $app/$location 411 * @return int number of rows deleted 412 */ 413 function delete_repository($app, $location, $accountid='') 414 { 415 static $cache_accountid; 416 417 $where = array( 418 'acl_appname' => $app, 419 'acl_location' => $location, 420 ); 421 if ($accountid !== false) 422 { 423 if(isset($cache_accountid[$accountid]) && $cache_accountid[$accountid]) 424 { 425 $where['acl_account'] = $cache_accountid[$accountid]; 426 } 427 else 428 { 429 $where['acl_account'] = $cache_accountid[$accountid] = get_account_id($accountid,$this->account_id); 430 } 431 } 432 if (method_exists($GLOBALS['egw'],'invalidate_session_cache')) // egw object in setup is limited 433 { 434 $GLOBALS['egw']->invalidate_session_cache(); 435 } 436 if ($app == '%' || $app == '%%') unset($where['acl_appname']); 437 438 $this->db->delete($this->table_name,$where,__LINE__,__FILE__); 439 440 return $this->db->affected_rows(); 441 } 442 443 /** 444 * Get rights for a given account, location and application 445 * 446 * @param int $account_id 447 * @param string $location 448 * @param string $appname='' defaults to current app 449 * @return int/boolean rights or false if none exist 450 */ 451 function get_specific_rights_for_account($account_id,$location,$appname='') 452 { 453 if (!$appname) $appname = $GLOBALS['egw_info']['flags']['currentapp']; 454 455 $this->db->select($this->table_name,'acl_rights',array( 456 'acl_location' => $location, 457 'acl_account' => $account_id, 458 'acl_appname' => $appname, 459 ),__LINE__,__FILE__); 460 461 return $this->db->next_record() ? $this->db->f('acl_rights') : false; 462 } 463 464 /** 465 * Get all rights for a given location and application 466 * 467 * @param string $location 468 * @param string $appname='' defaults to current app 469 * @return array with account => rights pairs 470 */ 471 function get_all_rights($location,$appname='') 472 { 473 if (!$appname) $appname = $GLOBALS['egw_info']['flags']['currentapp']; 474 475 $this->db->select($this->table_name,'acl_account,acl_rights',array( 476 'acl_location' => $location, 477 'acl_appname' => $appname, 478 ),__LINE__,__FILE__); 479 480 $rights = array(); 481 while($this->db->next_record()) 482 { 483 $rights[$this->db->f('acl_account')] = $this->db->f('acl_rights'); 484 } 485 return $rights; 486 } 487 488 /** 489 * Get the rights for all locations 490 * 491 * @param int $account_id 492 * @param string $appname='' defaults to current app 493 * @param boolean $use_memberships=true 494 * @return array with location => rights pairs 495 */ 496 function get_all_location_rights($account_id,$appname='',$use_memberships=true) 497 { 498 if (!$appname) $appname = $GLOBALS['egw_info']['flags']['currentapp']; 499 500 $accounts = array($account_id); 501 if ($use_memberships) 502 { 503 foreach((array)$GLOBALS['egw']->accounts->membership($account_id) as $group) 504 { 505 $accounts[] = $group['account_id']; 506 } 507 } 508 $this->db->select($this->table_name,'acl_location,acl_rights',array( 509 'acl_account' => $accounts, 510 'acl_appname' => $appname, 511 ),__LINE__,__FILE__); 512 513 $rights = array(); 514 while($this->db->next_record()) 515 { 516 $rights[$this->db->f('acl_location')] |= $this->db->f('acl_rights'); 517 } 518 return $rights; 519 } 520 521 /** 522 * get application list for an account id 523 * 524 * @param string $location location 525 * @param int $required required rights 526 * @param int $account_id account id defaults to $GLOBALS['egw_info']['user']['account_id']; 527 * @return array/boolean false if there are no matching row in the db, else array with app-names 528 */ 529 function get_app_list_for_id($location, $required, $accountid = '') 530 { 531 static $cache_accountid; 532 533 if($cache_accountid[$accountid]) 534 { 535 $account_id = $cache_accountid[$accountid]; 536 } 537 else 538 { 539 $account_id = get_account_id($accountid,$this->account_id); 540 $cache_accountid[$accountid] = $account_id; 541 } 542 $this->db->select($this->table_name,array('acl_appname','acl_rights'),array( 543 'acl_location' => $location, 544 'acl_account' => $account_id, 545 ),__LINE__,__FILE__); 546 547 $rights = 0; 548 $apps = false; 549 while ($this->db->next_record()) 550 { 551 if ($this->db->f('acl_rights') == 0) 552 { 553 return False; 554 } 555 $rights |= $this->db->f('acl_rights'); 556 if (!!($rights & $required)) 557 { 558 $apps[] = $this->db->f('acl_appname'); 559 } 560 } 561 return $apps; 562 } 563 564 /** 565 * get location list for id 566 * 567 * @param string $app app 568 * @param int $required required rights 569 * @param int $accountid optional defaults to $GLOBALS['egw_info']['user']['account_id']; 570 * @return array/boolean false if there are no matching rows in the db or array with location-strings 571 */ 572 function get_location_list_for_id($app, $required, $accountid = '') 573 { 574 static $cache_accountid; 575 576 if($cache_accountid[$accountid]) 577 { 578 $accountid = $cache_accountid[$accountid]; 579 } 580 else 581 { 582 $accountid = $cache_accountid[$accountid] = get_account_id($accountid,$this->account_id); 583 } 584 $this->db->select($this->table_name,'acl_location,acl_rights',array( 585 'acl_appname' => $app, 586 'acl_account' => $accountid, 587 ),__LINE__,__FILE__); 588 589 $locations = false; 590 while ($this->db->next_record()) 591 { 592 if ($this->db->f('acl_rights') & $required) 593 { 594 $locations[] = $this->db->f('acl_location'); 595 } 596 } 597 return $locations; 598 } 599 600 /** 601 * get ids for location 602 * 603 * @param string $location location 604 * @param int $required required rights 605 * @param string $app app optional defaults to $GLOBALS['egw_info']['flags']['currentapp']; 606 * @return boolean/array false if there are no matching rows in the db or array of account-ids 607 */ 608 function get_ids_for_location($location, $required, $app = '') 609 { 610 if (!$app) $app = $GLOBALS['egw_info']['flags']['currentapp']; 611 612 $this->db->select($this->table_name,array('acl_account','acl_rights'),array( 613 'acl_appname' => $app, 614 'acl_location' => $location, 615 ),__LINE__,__FILE__); 616 617 $accounts = false; 618 while ($this->db->next_record()) 619 { 620 if (!!($this->db->f('acl_rights') & $required)) 621 { 622 $accounts[] = (int) $this->db->f('acl_account'); 623 } 624 } 625 return $accounts; 626 } 627 628 /** 629 * get the locations for an app (excluding the run location !!!) 630 * 631 * @param string $app app optional defaults to $GLOBALS['egw_info']['flags']['currentapp']; 632 * @return boolean/array false if there are no matching location in the db or array of locations 633 */ 634 function get_locations_for_app($app='') 635 { 636 if (!$app) $app = $GLOBALS['egw_info']['flags']['currentapp']; 637 638 $this->db->select($this->table_name,'DISTINCT '.'acl_location',array( 639 'acl_appname' => $app, 640 ),__LINE__,__FILE__); 641 642 $locations = false; 643 while ($this->db->next_record()) 644 { 645 if (($location = $this->db->f(0)) != 'run') 646 { 647 $locations[] = $location; 648 } 649 } 650 return $locations; 651 } 652 653 /** 654 * get a list of applications a user has rights to 655 * 656 * @param int $account_id optional defaults to $GLOBALS['egw_info']['user']['account_id']; 657 * @return boolean/array containing list of apps or false if there are none 658 */ 659 function get_user_applications($accountid = '') 660 { 661 static $cache_accountid; 662 663 if($cache_accountid[$accountid]) 664 { 665 $account_id = $cache_accountid[$accountid]; 666 } 667 else 668 { 669 $account_id = get_account_id($accountid,$this->account_id); 670 $cache_accountid[$accountid] = $account_id; 671 } 672 $memberships = array($account_id); 673 foreach((array)$GLOBALS['egw']->accounts->membership($account_id) as $group) 674 { 675 $memberships[] = $group['account_id']; 676 } 677 $db2 = clone($this->db); 678 $db2->select($this->table_name,array('acl_appname','acl_rights'),array( 679 'acl_location' => 'run', 680 'acl_account' => $memberships, 681 ),__LINE__,__FILE__); 682 683 $apps = false; 684 while ($db2->next_record()) 685 { 686 $app = $db2->f('acl_appname'); 687 if(!isset($apps[$app])) 688 { 689 $apps[$app] = 0; 690 } 691 $apps[$app] |= (int) $db2->f('acl_rights'); 692 } 693 return $apps; 694 } 695 696 /** 697 * Read the grants other users gave $this->account_id for $app, group ACL is taken into account 698 * 699 * @param string $app optional defaults to $GLOBALS['egw_info']['flags']['currentapp']; 700 * @return array with account-ids (of owners) and granted rights as values 701 */ 702 function get_grants($app='') 703 { 704 if (!$app) $app = $GLOBALS['egw_info']['flags']['currentapp']; 705 706 $memberships = array($this->account_id); 707 foreach((array)$GLOBALS['egw']->accounts->membership($this->account_id) as $group) 708 { 709 $memberships[] = $group['account_id']; 710 } 711 $db2 = clone($this->db); 712 $db2->select($this->table_name,array('acl_account','acl_rights'),array( 713 'acl_appname' => $app, 714 'acl_location' => $memberships, 715 ),__LINE__,__FILE__); 716 717 $grants = $accounts = Array(); 718 while ($db2->next_record()) 719 { 720 $grantor = $db2->f('acl_account'); 721 $rights = $db2->f('acl_rights'); 722 723 if(!isset($accounts[$grantor])) 724 // cache the group-members for performance 725 { 726 // if $grantor is a group, get its members 727 $members = $this->get_ids_for_location($grantor,1,'phpgw_group'); 728 if(!$members) 729 { 730 $accounts[$grantor] = Array($grantor); 731 $is_group[$grantor] = False; 732 } 733 else 734 { 735 $accounts[$grantor] = $members; 736 $is_group[$grantor] = True; 737 } 738 } 739 if(@$is_group[$grantor]) 740 { 741 // Don't allow to override private! 742 $rights &= (~ EGW_ACL_PRIVATE); 743 if(!isset($grants[$grantor])) 744 { 745 $grants[$grantor] = 0; 746 } 747 $grants[$grantor] |= $rights; 748 if(!!($rights & EGW_ACL_READ)) 749 { 750 $grants[$grantor] |= EGW_ACL_READ; 751 } 752 } 753 foreach($accounts[$grantor] as $grantors) 754 { 755 if(!isset($grants[$grantors])) 756 { 757 $grants[$grantors] = 0; 758 } 759 $grants[$grantors] |= $rights; 760 } 761 } 762 $grants[$GLOBALS['egw_info']['user']['account_id']] = ~0; 763 764 return $grants; 765 } 766 767 /** 768 * Deletes all ACL entries for an account (user or group) 769 * 770 * @param int $account_id acount-id 771 */ 772 function delete_account($account_id) 773 { 774 if ((int) $account_id) 775 { 776 $this->db->delete($this->table_name,array( 777 'acl_account' => $account_id 778 ),__LINE__,__FILE__); 779 // delete all memberships in account_id (if it is a group) 780 $this->db->delete($this->table_name,array( 781 'acl_appname' => 'phpgw_group', 782 'acl_location' => $account_id, 783 ),__LINE__,__FILE__); 784 } 785 } 786 } //end of acl class
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |