This commit was generated by cvs2svn to compensate for changes in r4407,
[freeside.git] / rt / lib / RT / ACL_Overlay.pm
1 # BEGIN BPS TAGGED BLOCK {{{
2
3 # COPYRIGHT:
4 #  
5 # This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC 
6 #                                          <jesse@bestpractical.com>
7
8 # (Except where explicitly superseded by other copyright notices)
9
10
11 # LICENSE:
12
13 # This work is made available to you under the terms of Version 2 of
14 # the GNU General Public License. A copy of that license should have
15 # been provided with this software, but in any event can be snarfed
16 # from www.gnu.org.
17
18 # This work is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 # General Public License for more details.
22
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
27
28 # CONTRIBUTION SUBMISSION POLICY:
29
30 # (The following paragraph is not intended to limit the rights granted
31 # to you to modify and distribute this software under the terms of
32 # the GNU General Public License and is only of importance to you if
33 # you choose to contribute your changes and enhancements to the
34 # community by submitting them to Best Practical Solutions, LLC.)
35
36 # By intentionally submitting any modifications, corrections or
37 # derivatives to this work, or any other work intended for use with
38 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
39 # you are the copyright holder for those contributions and you grant
40 # Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
41 # royalty-free, perpetual, license to use, copy, create derivative
42 # works based on those contributions, and sublicense and distribute
43 # those contributions and any derivatives thereof.
44
45 # END BPS TAGGED BLOCK }}}
46
47 =head1 NAME
48
49   RT::ACL - collection of RT ACE objects
50
51 =head1 SYNOPSIS
52
53   use RT::ACL;
54 my $ACL = new RT::ACL($CurrentUser);
55
56 =head1 DESCRIPTION
57
58
59 =head1 METHODS
60
61 =begin testing
62
63 ok(require RT::ACL);
64
65 =end testing
66
67 =cut
68
69
70 package RT::ACL;
71
72 use strict;
73 no warnings qw(redefine);
74
75
76 =head2 Next
77
78 Hand out the next ACE that was found
79
80 =cut
81
82
83 # {{{ LimitToObject 
84
85 =head2 LimitToObject $object
86
87 Limit the ACL to rights for the object $object. It needs to be an RT::Record class.
88
89 =cut
90
91 sub LimitToObject {
92     my $self = shift;
93     my $obj  = shift;
94     unless ( defined($obj)
95         && ref($obj)
96         && UNIVERSAL::can( $obj, 'id' )
97         && $obj->id )
98     {
99         return undef;
100     }
101     $self->Limit(
102         FIELD           => 'ObjectType',
103         OPERATOR        => '=',
104         VALUE           => ref($obj),
105         ENTRYAGGREGATOR => 'OR'
106     );
107     $self->Limit(
108         FIELD           => 'ObjectId',
109         OPERATOR        => '=',
110         VALUE           => $obj->id,
111         ENTRYAGGREGATOR => 'OR',
112         QUOTEVALUE      => 0
113     );
114
115 }
116
117 # }}}
118
119 # {{{ LimitNotObject
120
121 =head2 LimitNotObject $object
122
123 Limit the ACL to rights NOT on the object $object.  $object needs to be
124 an RT::Record class.
125
126 =cut
127
128 sub LimitNotObject {
129     my $self = shift;
130     my $obj  = shift;
131     unless ( defined($obj)
132         && ref($obj)
133         && UNIVERSAL::can( $obj, 'id' )
134         && $obj->id )
135     {
136         return undef;
137     }
138     $self->Limit( FIELD => 'ObjectType',
139                   OPERATOR => '!=',
140                   VALUE => ref($obj),
141                   ENTRYAGGREGATOR => 'OR',
142                   SUBCLAUSE => $obj->id
143                 );
144     $self->Limit( FIELD => 'ObjectId',
145                   OPERATOR => '!=',
146                   VALUE => $obj->id,
147                   ENTRYAGGREGATOR => 'OR',
148                   QUOTEVALUE => 0,
149                   SUBCLAUSE => $obj->id
150                 );
151 }
152
153 # }}}
154
155 # {{{ LimitToPrincipal 
156
157 =head2 LimitToPrincipal { Type => undef, Id => undef, IncludeGroupMembership => undef }
158
159 Limit the ACL to the principal with PrincipalId Id and PrincipalType Type
160
161 Id is not optional.
162 Type is.
163
164 if IncludeGroupMembership => 1 is specified, ACEs which apply to the principal due to group membership will be included in the resultset.
165
166
167 =cut
168
169 sub LimitToPrincipal {
170     my $self = shift;
171     my %args = ( Type                               => undef,
172                  Id                                 => undef,
173                  IncludeGroupMembership => undef,
174                  @_ );
175     if ( $args{'IncludeGroupMembership'} ) {
176         my $cgm = $self->NewAlias('CachedGroupMembers');
177         $self->Join( ALIAS1 => 'main',
178                      FIELD1 => 'PrincipalId',
179                      ALIAS2 => $cgm,
180                      FIELD2 => 'GroupId' );
181         $self->Limit( ALIAS           => $cgm,
182                       FIELD           => 'MemberId',
183                       OPERATOR        => '=',
184                       VALUE           => $args{'Id'},
185                       ENTRYAGGREGATOR => 'OR' );
186     }
187     else {
188         if ( defined $args{'Type'} ) {
189             $self->Limit( FIELD           => 'PrincipalType',
190                           OPERATOR        => '=',
191                           VALUE           => $args{'Type'},
192                           ENTRYAGGREGATOR => 'OR' );
193         }
194     # if the principal id points to a user, we really want to point
195     # to their ACL equivalence group. The machinations we're going through
196     # lead me to start to suspect that we really want users and groups
197     # to just be the same table. or _maybe_ that we want an object db.
198     my $princ = RT::Principal->new($RT::SystemUser);
199     $princ->Load($args{'Id'});
200     if ($princ->PrincipalType eq 'User') {
201     my $group = RT::Group->new($RT::SystemUser);
202         $group->LoadACLEquivalenceGroup($princ);
203         $args{'Id'} = $group->PrincipalId;
204     }
205         $self->Limit( FIELD           => 'PrincipalId',
206                       OPERATOR        => '=',
207                       VALUE           => $args{'Id'},
208                       ENTRYAGGREGATOR => 'OR' );
209     }
210 }
211
212 # }}}
213
214
215
216 # {{{ ExcludeDelegatedRights
217
218 =head2 ExcludeDelegatedRights 
219
220 Don't list rights which have been delegated.
221
222 =cut
223
224 sub ExcludeDelegatedRights {
225     my $self = shift;
226     $self->DelegatedBy(Id => 0);
227     $self->DelegatedFrom(Id => 0);
228 }
229 # }}}
230
231 # {{{ DelegatedBy 
232
233 =head2 DelegatedBy { Id => undef }
234
235 Limit the ACL to rights delegated by the principal whose Principal Id is
236 B<Id>
237
238 Id is not optional.
239
240 =cut
241
242 sub DelegatedBy {
243     my $self = shift;
244     my %args = (
245         Id => undef,
246         @_
247     );
248     $self->Limit(
249         FIELD           => 'DelegatedBy',
250         OPERATOR        => '=',
251         VALUE           => $args{'Id'},
252         ENTRYAGGREGATOR => 'OR'
253     );
254
255 }
256
257 # }}}
258
259 # {{{ DelegatedFrom 
260
261 =head2 DelegatedFrom { Id => undef }
262
263 Limit the ACL to rights delegate from the ACE which has the Id specified 
264 by the Id parameter.
265
266 Id is not optional.
267
268 =cut
269
270 sub DelegatedFrom {
271     my $self = shift;
272     my %args = (
273                  Id => undef,
274                  @_);
275     $self->Limit(FIELD => 'DelegatedFrom', OPERATOR=> '=', VALUE => $args{'Id'}, ENTRYAGGREGATOR => 'OR');
276
277 }
278
279 # }}}
280
281
282 # {{{ sub Next 
283 sub Next {
284     my $self = shift;
285
286     my $ACE = $self->SUPER::Next();
287     if ( ( defined($ACE) ) and ( ref($ACE) ) ) {
288
289         if ( $self->CurrentUser->HasRight( Right  => 'ShowACL',
290                                            Object => $ACE->Object )
291              or $self->CurrentUser->HasRight( Right  => 'ModifyACL',
292                                               Object => $ACE->Object )
293           ) {
294             return ($ACE);
295         }
296
297         #If the user doesn't have the right to show this ACE
298         else {
299             return ( $self->Next() );
300         }
301     }
302
303     #if there never was any ACE
304     else {
305         return (undef);
306     }
307
308 }
309
310 # }}}
311
312
313
314 #wrap around _DoSearch  so that we can build the hash of returned
315 #values 
316 sub _DoSearch {
317     my $self = shift;
318    # $RT::Logger->debug("Now in ".$self."->_DoSearch");
319     my $return = $self->SUPER::_DoSearch(@_);
320   #  $RT::Logger->debug("In $self ->_DoSearch. return from SUPER::_DoSearch was $return\n");
321     $self->_BuildHash();
322     return ($return);
323 }
324
325
326 #Build a hash of this ACL's entries.
327 sub _BuildHash {
328     my $self = shift;
329
330     while (my $entry = $self->Next) {
331        my $hashkey = $entry->ObjectType . "-" .  $entry->ObjectId . "-" .  $entry->RightName . "-" .  $entry->PrincipalId . "-" .  $entry->PrincipalType;
332
333         $self->{'as_hash'}->{"$hashkey"} =1;
334
335     }
336 }
337
338
339 # {{{ HasEntry
340
341 =head2 HasEntry
342
343 =cut
344
345 sub HasEntry {
346
347     my $self = shift;
348     my %args = ( RightScope => undef,
349                  RightAppliesTo => undef,
350                  RightName => undef,
351                  PrincipalId => undef,
352                  PrincipalType => undef,
353                  @_ );
354
355     #if we haven't done the search yet, do it now.
356     $self->_DoSearch();
357
358     if ($self->{'as_hash'}->{ $args{'RightScope'} . "-" .
359                               $args{'RightAppliesTo'} . "-" . 
360                               $args{'RightName'} . "-" .
361                               $args{'PrincipalId'} . "-" .
362                               $args{'PrincipalType'}
363                             } == 1) {
364         return(1);
365     }
366     else {
367         return(undef);
368     }
369 }
370
371 # }}}
372 1;