Upgrade to 4.2.8
[usit-rt.git] / lib / RT / ACL.pm
1 # BEGIN BPS TAGGED BLOCK {{{
2 #
3 # COPYRIGHT:
4 #
5 # This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
6 #                                          <sales@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., 51 Franklin Street, Fifth Floor, Boston, MA
26 # 02110-1301 or visit their web page on the internet at
27 # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28 #
29 #
30 # CONTRIBUTION SUBMISSION POLICY:
31 #
32 # (The following paragraph is not intended to limit the rights granted
33 # to you to modify and distribute this software under the terms of
34 # the GNU General Public License and is only of importance to you if
35 # you choose to contribute your changes and enhancements to the
36 # community by submitting them to Best Practical Solutions, LLC.)
37 #
38 # By intentionally submitting any modifications, corrections or
39 # derivatives to this work, or any other work intended for use with
40 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 # you are the copyright holder for those contributions and you grant
42 # Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
43 # royalty-free, perpetual, license to use, copy, create derivative
44 # works based on those contributions, and sublicense and distribute
45 # those contributions and any derivatives thereof.
46 #
47 # END BPS TAGGED BLOCK }}}
48
49 =head1 NAME
50
51   RT::ACL - collection of RT ACE objects
52
53 =head1 SYNOPSIS
54
55   use RT::ACL;
56 my $ACL = RT::ACL->new($CurrentUser);
57
58 =head1 DESCRIPTION
59
60
61 =head1 METHODS
62
63
64 =cut
65
66
67 package RT::ACL;
68 use base 'RT::SearchBuilder';
69
70 use RT::ACE;
71
72 sub Table { 'ACL'}
73
74 use strict;
75 use warnings;
76
77
78
79 =head2 Next
80
81 Hand out the next ACE that was found
82
83 =cut
84
85
86
87 =head2 LimitToObject $object
88
89 Limit the ACL to rights for the object $object. It needs to be an RT::Record class.
90
91 =cut
92
93 sub LimitToObject {
94     my $self = shift;
95     my $obj  = shift;
96
97     my $obj_type = ref($obj)||$obj;
98     my $obj_id = eval { $obj->id};
99
100     my $object_clause = 'possible_objects';
101     $self->_OpenParen($object_clause);
102     $self->Limit(
103         SUBCLAUSE       => $object_clause,
104         FIELD           => 'ObjectType',
105         OPERATOR        => '=',
106         VALUE           => (ref($obj)||$obj),
107         ENTRYAGGREGATOR => 'OR' # That "OR" applies to the separate objects we're searching on, not "Type Or ID"
108     );
109     if ($obj_id) {
110     $self->Limit(
111         SUBCLAUSE       => $object_clause,
112         FIELD           => 'ObjectId',
113         OPERATOR        => '=',
114         VALUE           => $obj_id,
115         ENTRYAGGREGATOR => 'AND',
116         QUOTEVALUE      => 0
117     );
118     }
119     $self->_CloseParen($object_clause);
120
121 }
122
123
124
125 =head2 LimitToPrincipal { Type => undef, Id => undef, IncludeGroupMembership => undef }
126
127 Limit the ACL to the principal with PrincipalId Id and PrincipalType Type
128
129 Id is not optional.
130 Type is.
131
132 if IncludeGroupMembership => 1 is specified, ACEs which apply to the principal due to group membership will be included in the resultset.
133
134
135 =cut
136
137 sub LimitToPrincipal {
138     my $self = shift;
139     my %args = ( Type                   => undef,
140                  Id                     => undef,
141                  IncludeGroupMembership => undef,
142                  @_
143                );
144     if ( $args{'IncludeGroupMembership'} ) {
145         my $cgm = $self->NewAlias('CachedGroupMembers');
146         $self->Join( ALIAS1 => 'main',
147                      FIELD1 => 'PrincipalId',
148                      ALIAS2 => $cgm,
149                      FIELD2 => 'GroupId'
150                    );
151         $self->Limit( ALIAS => $cgm,
152                       FIELD => 'Disabled',
153                       VALUE => 0 );
154         $self->Limit( ALIAS           => $cgm,
155                       FIELD           => 'MemberId',
156                       OPERATOR        => '=',
157                       VALUE           => $args{'Id'},
158                       ENTRYAGGREGATOR => 'OR'
159                     );
160     } else {
161         if ( defined $args{'Type'} ) {
162             $self->Limit( FIELD           => 'PrincipalType',
163                           OPERATOR        => '=',
164                           VALUE           => $args{'Type'},
165                           ENTRYAGGREGATOR => 'OR'
166                         );
167         }
168
169         # if the principal id points to a user, we really want to point
170         # to their ACL equivalence group. The machinations we're going through
171         # lead me to start to suspect that we really want users and groups
172         # to just be the same table. or _maybe_ that we want an object db.
173         my $princ = RT::Principal->new( RT->SystemUser );
174         $princ->Load( $args{'Id'} );
175         if ( $princ->PrincipalType eq 'User' ) {
176             my $group = RT::Group->new( RT->SystemUser );
177             $group->LoadACLEquivalenceGroup($princ);
178             $args{'Id'} = $group->PrincipalId;
179         }
180         $self->Limit( FIELD           => 'PrincipalId',
181                       OPERATOR        => '=',
182                       VALUE           => $args{'Id'},
183                       ENTRYAGGREGATOR => 'OR'
184                     );
185     }
186 }
187
188
189
190
191 sub Next {
192     my $self = shift;
193
194     my $ACE = $self->SUPER::Next();
195     # Short-circuit having to load up the ->Object
196     return $ACE
197         if $self->CurrentUser->PrincipalObj->Id == RT->SystemUser->Id;
198     if ( ( defined($ACE) ) and ( ref($ACE) ) ) {
199
200         if ( $self->CurrentUser->HasRight( Right  => 'ShowACL',
201                                            Object => $ACE->Object )
202              or $self->CurrentUser->HasRight( Right  => 'ModifyACL',
203                                               Object => $ACE->Object )
204           ) {
205             return ($ACE);
206         }
207
208         #If the user doesn't have the right to show this ACE
209         else {
210             return ( $self->Next() );
211         }
212     }
213
214     #if there never was any ACE
215     else {
216         return (undef);
217     }
218
219 }
220
221 # The singular of ACL is ACE.
222 sub _SingularClass { "RT::ACE" }
223
224 RT::Base->_ImportOverlays();
225
226 1;