source: trunk/phpgwapi/inc/class.acl.inc.php @ 1280

Revision 1280, 18.7 KB checked in by eduardoalex, 15 years ago (diff)

Ticket #453 - Edição de grupos compartilhados.

  • Property svn:eol-style set to native
  • Property svn:executable set to *
Line 
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
25        /*!
26                @class acl
27                @abstract Access Control List Security System
28                @discussion This class provides an ACL security scheme.
29                This can manage rights to 'run' applications, and limit certain features within an application.
30                It is also used for granting a user "membership" to a group, or making a user have the security equivilance of another user.
31                It is also used for granting a user or group rights to various records, such as todo or calendar items of another user.
32                @syntax CreateObject('phpgwapi.acl',int account_id);
33                @example $acl = CreateObject('phpgwapi.acl',5);  // 5 is the user id
34                @example $acl = CreateObject('phpgwapi.acl',10);  // 10 is the user id
35                @author Seek3r
36                @copyright LGPL
37                @package phpgwapi
38                @access public
39        */
40        class acl
41        {
42                /*! @var $account_id */
43                var $account_id;
44                /*! @var $account_type */
45                var $account_type;
46                /*! @var $data  */
47                var $data = Array();
48                /*! @var $db */
49                var $db;
50                var $table_name = 'phpgw_acl';
51
52                /*!
53                @function acl
54                @abstract ACL constructor for setting account id
55                @discussion Author: Seek3r <br>
56                Sets the ID for $acl->account_id. Can be used to change a current instances id as well. <br>
57                Some functions are specific to this account, and others are generic. <br>
58                @syntax int acl(int account_id) <br>
59                @example1 acl->acl(5); // 5 is the user id  <br>
60                @param account_id int-the user id
61                */
62                function acl($account_id = '')
63                {
64                        $this->db = clone($GLOBALS['phpgw']->db);
65                        $this->db->set_app('phpgwapi');
66
67                        if ((int)$this->account_id != (int)$account_id)
68                        {
69                                $this->account_id = get_account_id((int)$account_id,@$GLOBALS['phpgw_info']['user']['account_id']);
70                        }
71                }
72
73                function DONTlist_methods($_type='xmlrpc')
74                {
75                        /*
76                          This handles introspection or discovery by the logged in client,
77                          in which case the input might be an array.  The server always calls
78                          this function to fill the server dispatch map using a string.
79                        */
80
81                        if (is_array($_type))
82                        {
83                                $_type = $_type['type'] ? $_type['type'] : $_type[0];
84                        }
85
86                        switch($_type)
87                        {
88                                case 'xmlrpc':
89                                $xml_functions = array(
90                                                'read_repository' => array(
91                                                        'function'  => 'read_repository',
92                                                        'signature' => array(array(xmlrpcStruct)),
93                                                        'docstring' => lang('FIXME!')
94                                                ),
95                                                'get_rights' => array(
96                                                        'function'  => 'get_rights',
97                                                        'signature' => array(array(xmlrpcStruct,xmlrpcStruct)),
98                                                        'docstring' => lang('FIXME!')
99
100                                                ),
101                                                'list_methods' => array(
102                                                        'function'  => 'list_methods',
103                                                        'signature' => array(array(xmlrpcStruct,xmlrpcString)),
104                                                        'docstring' => lang('Read this list of methods.')
105                                                )
106                                        );
107                                        return $xml_functions;
108                                        break;
109                                case 'soap':
110                                        return $this->soap_functions;
111                                        break;
112                                default:
113                                        return array();
114                                        break;
115                        }
116                }
117
118                /**************************************************************************\
119                * These are the standard $this->account_id specific functions              *
120                \**************************************************************************/
121
122                /*!
123                @function read_repository
124                @abstract Read acl records from reposity
125                @discussion Author: Seek3r <br>
126                Reads ACL records for $acl->account_id and returns array along with storing it in $acl->data.  <br>
127                Syntax: array read_repository() <br>
128                Example1: acl->read_repository(); <br>
129                Should only be called within this class
130                */
131                function read_repository()
132                {
133                        // For some reason, calling this via XML-RPC doesn't call the constructor.
134                        // Here is yet another work around(tm) (jengo)
135                        if (!$this->account_id)
136                        {
137                                $this->acl();
138                        }
139                        $acl_acc_list = array_values((array)$this->get_location_list_for_id('phpgw_group', 1, $this->account_id));
140                        array_unshift($acl_acc_list,$this->account_id,0);
141                        $this->db->select($this->table_name,'*',array('acl_account' => $acl_acc_list ),__LINE__,__FILE__);
142                       
143                        $this->data = Array();
144                        while($this->db->next_record())
145                        {
146                                $this->data[] = array(
147                                        'appname'  => $this->db->f('acl_appname'),
148                                        'location' => $this->db->f('acl_location'),
149                                        'account'  => $this->db->f('acl_account'),
150                                        'rights'   => $this->db->f('acl_rights')
151                                );
152                        }
153                        return $this->data;
154                }
155
156                /*!
157                @function read
158                @abstract Read acl records from $acl->data
159                @discussion Author: Seek3r <br>
160                Returns ACL records from $acl->data. <br>
161                Syntax: array read() <br>
162                Example1: acl->read(); <br>
163                */
164                function read()
165                {
166                        if (!count($this->data))
167                        {
168                                $this->read_repository();
169                        }
170                        return $this->data;
171                }
172
173                /*!
174                @function add
175                @abstract Adds ACL record to $acl->data
176                @discussion Adds ACL record to $acl->data. <br>
177                Syntax: array add() <br>
178                Example1: acl->add();
179                @param $appname default False derives value from $phpgw_info['flags']['currentapp']
180                @param $location location
181                @param $rights rights
182                */
183                function add($appname,$location,$rights)
184                {
185                        if (!$appname) $appname = $GLOBALS['phpgw_info']['flags']['currentapp'];
186
187                        $this->data[] = array(
188                                'appname'  => $appname,
189                                'location' => $location,
190                                'account'  => (int) $this->account_id,
191                                'rights'   => (int) $rights
192                        );
193
194                        return $this->data;
195                }
196               
197                function persist_shared_groups($location)
198                {
199                        $this->db->persist_shared_groups($location,$this->account_id);
200                }
201               
202                /*!
203                @function delete
204                @abstract Delete ACL record
205                @discussion
206                Syntax <br>
207                Example: <br>
208                @param $appname optional defaults to $phpgw_info['flags']['currentapp']
209                @param $location app location
210                */
211                function delete($appname, $location)
212                {
213                        if (!$appname) $appname = $GLOBALS['phpgw_info']['flags']['currentapp'];
214
215                        foreach($this->data as $idx => $value)
216                        {
217                                if ($this->data[$idx]['appname'] == $appname && $this->data[$idx]['location'] == $location && $this->data[$idx]['account'] == $this->account_id)
218                                {
219                                        unset($this->data[$idx]);
220                                }
221                        }
222                        return $this->data;
223                }
224
225                /*!
226                @function save_repostiory
227                @abstract save repository
228                @discussion save the repository <br>
229                Syntax: save_repository() <br>
230                example: acl->save_repository()
231                */
232               
233                function save_repository()
234                {
235                        $this->db->delete($this->table_name,array(
236                                'acl_account' => $this->account_id,
237                        ),__LINE__,__FILE__);
238
239                        foreach($this->data as $value)
240                        {
241                                if ($value['account'] == $this->account_id)
242                                {
243                                        $this->db->insert($this->table_name,array(
244                                                'acl_appname'  => $value['appname'],
245                                                'acl_location' => $value['location'],
246                                                'acl_account'  => $this->account_id,
247                                                'acl_rights'   => $value['rights'],
248                                        ),false,__LINE__,__FILE__);
249                                }
250                        }
251                        return $this->data;
252                }
253
254                /**************************************************************************\
255                * These are the non-standard $this->account_id specific functions          *
256                \**************************************************************************/
257
258                /*!
259                @function get_rights
260                @abstract get rights from the repository not specific to this->account_id (?)
261                @discussion
262                @param $location app location to get rights from
263                @param $appname optional defaults to $phpgw_info['flags']['currentapp'];
264                */
265                function get_rights($location,$appname = False)
266                {
267                        // For XML-RPC, change this once its working correctly for passing parameters (jengo)
268                        if (is_array($location))
269                        {
270                                $appname  = $location['appname'];
271                                $location = $location['location'];
272                        }
273
274                        if (!count($this->data))
275                        {
276                                $this->read_repository();
277                        }
278                        if (!$appname) $appname = $GLOBALS['phpgw_info']['flags']['currentapp'];
279
280                        if (!count($this->data) && $GLOBALS['phpgw_info']['server']['acl_default'] != 'deny')
281                        {
282                                return True;
283                        }
284                        $rights = 0;
285                        foreach($this->data as $idx => $value)
286                        {
287                                if ($value['appname'] == $appname)
288                                {
289                                        if ($value['location'] == $location || $value['location'] == 'everywhere')
290                                        {
291                                                if ($value['rights'] == 0)
292                                                {
293                                                        return False;
294                                                }
295                                                $rights |= $value['rights'];
296                                        }
297                                }
298                        }
299                        return $rights;
300                }
301                /*!
302                @function check
303                @abstract check required rights (not specific to this->account_id?)
304                @param $location app location
305                @param $required required right to check against
306                @param $appname optional defaults to currentapp
307                */
308                function check($location, $required, $appname = False)
309                {
310                        $rights = $this->get_rights($location,$appname);
311
312                        return !!($rights & $required);
313                }
314                /*!
315                @function get_specific_rights
316                @abstract get specific rights for this->account_id for an app location
317                @param $location app location
318                @param $appname optional defaults to currentapp
319                @result $rights ?
320                */
321                function get_specific_rights($location, $appname = False)
322                {
323                        if (!$appname) $appname = $GLOBALS['phpgw_info']['flags']['currentapp'];
324
325                        if (!count($this->data) && $GLOBALS['phpgw_info']['server']['acl_default'] != 'deny')
326                        {
327                                return True;
328                        }
329                        $rights = 0;
330
331                        foreach($this->data as $idx => $value)
332                        {
333                                if ($value['appname'] == $appname &&
334                                        ($value['location'] == $location ||     $value['location'] == 'everywhere') &&
335                                        $value['account'] == $this->account_id)
336                                {
337                                        if ($value['rights'] == 0)
338                                        {
339                                                return False;
340                                        }
341                                        $rights |= $value['rights'];
342                                }
343                        }
344                        return $rights;
345                }
346                /*!
347                @function check_specific
348                @abstract check specific
349                @param $location app location
350                @param $required required rights
351                @param $appname optional defaults to currentapp
352                @result boolean
353                */
354                function check_specific($location, $required, $appname = False)
355                {
356                        $rights = $this->get_specific_rights($location,$appname);
357
358                        return !!($rights & $required);
359                }
360
361                /**************************************************************************\
362                * These are the generic functions. Not specific to $this->account_id       *
363                \**************************************************************************/
364
365                /**
366                 * add repository information / rights for app/location/account_id
367                 *
368                 * @param $app appname
369                 * @param $location location
370                 * @param $account_id account id
371                 * @param $rights rights
372                 */
373                function add_repository($app, $location, $account_id, $rights)
374                {
375                        //echo "<p>acl::add_repository('$app','$location',$account_id,$rights);</p>\n";
376                        $this->db->insert($this->table_name,array(
377                                'acl_rights' => $rights,
378                        ),array(
379                                'acl_appname' => $app,
380                                'acl_location' => $location,
381                                'acl_account'  => $account_id,
382                        ),__LINE__,__FILE__);
383
384                        return True;
385                }
386
387                /**
388                 * delete repository information / rights for app/location[/account_id]
389                 * @param string $app appname
390                 * @param string $location location
391                 * @param int/boolean $account_id account id, default 0=$this->account_id, or false to delete all entries for $app/$location
392                 * @return int number of rows deleted
393                 */
394                function delete_repository($app, $location, $accountid='')
395                {
396                        static $cache_accountid;
397
398                        $where = array(
399                                'acl_appname'  => $app,
400                                'acl_location' => $location,
401                        );
402                        if ($accountid !== false)
403                        {
404                                if(isset($cache_accountid[$accountid]) && $cache_accountid[$accountid])
405                                {
406                                        $where['acl_account'] = $cache_accountid[$accountid];
407                                }
408                                else
409                                {
410                                        $where['acl_account'] = $cache_accountid[$accountid] = get_account_id($accountid,$this->account_id);
411                                }
412                        }
413                        if ($app == '%' || $app == '%%') unset($where['acl_appname']);
414
415                        $this->db->delete($this->table_name,$where,__LINE__,__FILE__);
416
417                        return $this->db->affected_rows();
418                }
419
420                /*!
421                @function get_app_list_for_id
422                @abstract get application list for an account id
423                @param $location location
424                @param $required ?
425                @param $account_id account id defaults to $phpgw_info['user']['account_id'];
426                */
427                function get_app_list_for_id($location, $required, $accountid = '')
428                {
429                        static $cache_accountid;
430
431                        if($cache_accountid[$accountid])
432                        {
433                                $account_id = $cache_accountid[$accountid];
434                        }
435                        else
436                        {
437                                $account_id = get_account_id($accountid,$this->account_id);
438                                $cache_accountid[$accountid] = $account_id;
439                        }
440                        $this->db->select($this->table_name,array('acl_appname','acl_rights'),array(
441                                'acl_location' => $location,
442                                'acl_account'  => $account_id,
443                        ),__LINE__,__FILE__);
444
445                        $rights = 0;
446                        $apps = false;
447                        while ($this->db->next_record())
448                        {
449                                if ($this->db->f('acl_rights') == 0)
450                                {
451                                        return False;
452                                }
453                                $rights |= $this->db->f('acl_rights');
454                                if (!!($rights & $required))
455                                {
456                                        $apps[] = $this->db->f('acl_appname');
457                                }
458                        }
459                        return $apps;
460                }
461
462                /*!
463                @function get_location_list_for_id
464                @abstract get location list for id
465                @discussion ?
466                @param $app app
467                @param $required required
468                @param $account_id optional defaults to $phpgw_info['user']['account_id'];
469                */
470                function get_location_list_for_id($app, $required, $accountid = '')
471                {
472                        static $cache_accountid;
473
474                        if($cache_accountid[$accountid])
475                        {
476                                $accountid = $cache_accountid[$accountid];
477                        }
478                        else
479                        {
480                                $accountid = $cache_accountid[$accountid] = get_account_id($accountid,$this->account_id);
481                        }
482                        $this->db->select($this->table_name,'acl_location,acl_rights',array(
483                                'acl_appname' => $app,
484                                'acl_account' => $accountid,
485                        ),__LINE__,__FILE__);
486
487                        $locations = false;
488                        while ($this->db->next_record())
489                        {
490                                if ($this->db->f('acl_rights') & $required)
491                                {
492                                        $locations[] = $this->db->f('acl_location');
493                                }
494                        }
495                        return $locations;
496                }
497                /*!
498                @function get_ids_for_location
499                @abstract get ids for location
500                @param $location location
501                @param $required required
502                @param $app app optional defaults to $phpgw_info['flags']['currentapp'];
503                */
504                function get_ids_for_location($location, $required, $app = False)
505                {
506                        if (!$app) $app = $GLOBALS['phpgw_info']['flags']['currentapp'];
507
508                        $this->db->select($this->table_name,array('acl_account','acl_rights'),array(
509                                'acl_appname'  => $app,
510                                'acl_location' => $location,
511                        ),__LINE__,__FILE__);
512
513                        $accounts = false;
514                        while ($this->db->next_record())
515                        {
516                                if (!!($this->db->f('acl_rights') & $required))
517                                {
518                                        $accounts[] = (int) $this->db->f('acl_account');
519                                }
520                        }
521                        return $accounts;
522                }
523
524                /*!
525                @function get_user_applications
526                @abstract get a list of applications a user has rights to
527                @param $account_id optional defaults to $phpgw_info['user']['account_id'];
528                @result $apps array containing list of apps
529                */
530                function get_user_applications($accountid = '')
531                {
532                        static $cache_accountid;
533
534                        if($cache_accountid[$accountid])
535                        {
536                                $account_id = $cache_accountid[$accountid];
537                        }
538                        else
539                        {
540                                $account_id = get_account_id($accountid,$this->account_id);
541                                $cache_accountid[$accountid] = $account_id;
542                        }
543                        $memberships = array($account_id);
544                        foreach((array)$GLOBALS['phpgw']->accounts->membership($account_id) as $group)
545                        {
546                                $memberships[] = $group['account_id'];
547                        }
548                        $db2 = clone($this->db);
549                        $db2->select($this->table_name,array('acl_appname','acl_rights'),array(
550                                'acl_location' => 'run',
551                                'acl_account'  => $memberships,
552                        ),__LINE__,__FILE__);
553
554                        $apps = false;
555                        while ($db2->next_record())
556                        {
557                                $app = $db2->f('acl_appname');
558                                if(!isset($apps[$app]))
559                                {
560                                        $apps[$app] = 0;
561                                }
562                                $apps[$app] |= (int) $db2->f('acl_rights');
563                        }
564                        return $apps;
565                }
566                /*!
567                @function get_grants
568                @abstract ?
569                @param $app optional defaults to $phpgw_info['flags']['currentapp'];
570                */
571                function get_grants($app='')
572                {
573                        if (!$app) $app = $GLOBALS['phpgw_info']['flags']['currentapp'];
574
575                        $memberships = array($this->account_id);
576                        foreach((array)$GLOBALS['phpgw']->accounts->membership($this->account_id) as $group)
577                        {
578                                $memberships[] = $group['account_id'];
579                        }
580                        $db2 = clone($this->db);
581                        $db2->select($this->table_name,array('acl_account','acl_rights'),array(
582                                'acl_appname'  => $app,
583                                'acl_location' => $memberships,
584                        ),__LINE__,__FILE__);
585                       
586                        $grants = $accounts = Array();
587                        while ($db2->next_record())
588                        {
589                                $grantor = $db2->f('acl_account');
590                                $rights = $db2->f('acl_rights');
591
592                                if(!isset($accounts[$grantor]))
593                                // cache the group-members for performance
594                                {
595                                        // if $grantor is a group, get its members
596                                        $members = $this->get_ids_for_location($grantor,1,'phpgw_group');
597                                        if(!$members)
598                                        {
599                                                $accounts[$grantor] = Array($grantor);
600                                                $is_group[$grantor] = False;
601                                        }
602                                        else
603                                        {
604                                                $accounts[$grantor] = $members;
605                                                $is_group[$grantor] = True;
606                                        }
607                                }
608                                if(@$is_group[$grantor])
609                                {
610                                        // Don't allow to override private!
611                                        $rights &= (~ PHPGW_ACL_PRIVATE);
612                                        if(!isset($grants[$grantor]))
613                                        {
614                                                $grants[$grantor] = 0;
615                                        }
616                                        $grants[$grantor] |= $rights;
617                                        if(!!($rights & PHPGW_ACL_READ))
618                                        {
619                                                $grants[$grantor] |= PHPGW_ACL_READ;
620                                        }
621                                }
622                                foreach($accounts[$grantor] as $grantors)
623                                {
624                                        if(!isset($grants[$grantors]))
625                                        {
626                                                $grants[$grantors] = 0;
627                                        }
628                                        $grants[$grantors] |= $rights;
629                                }
630                        }
631                        $grants[$GLOBALS['phpgw_info']['user']['account_id']] = ~0;
632
633                        return $grants;
634                }
635               
636                /**
637                 * Deletes all ACL entries for an account (user or group)
638                 *
639                 * @param int $account_id acount-id
640                 */
641                function delete_account($account_id)
642                {
643                        if ((int) $account_id)
644                        {
645                                $this->db->delete($this->table_name,array(
646                                        'acl_account' => $account_id
647                                ),__LINE__,__FILE__);
648                                // delete all memberships in account_id (if it is a group)
649                                $this->db->delete($this->table_name,array(
650                                        'acl_appname' => 'phpgw_group',
651                                        'acl_location' => $account_id,
652                                ),__LINE__,__FILE__);
653                        }
654                }
655        } //end of acl class
Note: See TracBrowser for help on using the repository browser.