1 # {{{ BEGIN BPS TAGGED BLOCK
5 # This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC
6 # <jesse@bestpractical.com>
8 # (Except where explicitly superseded by other copyright notices)
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
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.
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.
28 # CONTRIBUTION SUBMISSION POLICY:
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.)
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.
45 # }}} END BPS TAGGED BLOCK
49 my $ace = new RT::ACE($CurrentUser);
67 no warnings qw(redefine);
75 %TICKET_METAPRINCIPALS
79 # {{{ Descriptions of rights
83 # Queue rights are the sort of queue rights that can only be granted
84 # to real people or groups
89 my $Queue = RT::Queue->new($RT::SystemUser);
91 is ($Queue->AvailableRights->{'DeleteTicket'} , 'Delete tickets', "Found the delete ticket right");
92 is ($RT::System->AvailableRights->{'SuperUser'}, 'Do anything and everything', "Found the superuser right");
104 # {{{ Descriptions of principals
106 %TICKET_METAPRINCIPALS = (
107 Owner => 'The owner of a ticket', # loc_pair
108 Requestor => 'The requestor of a ticket', # loc_pair
109 Cc => 'The CC of a ticket', # loc_pair
110 AdminCc => 'The administrative CC of a ticket', # loc_pair
116 # {{{ sub LoadByValues
118 =head2 LoadByValues PARAMHASH
120 Load an ACE by specifying a paramhash with the following fields:
122 PrincipalId => undef,
123 PrincipalType => undef,
139 my %args = ( PrincipalId => undef,
140 PrincipalType => undef,
148 ( $princ_obj, $args{'PrincipalType'} ) =
149 $self->_CanonicalizePrincipal( $args{'PrincipalId'},
150 $args{'PrincipalType'} );
152 unless ( $princ_obj->id ) {
154 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
158 my ($object_type, $object_id);
160 if ($args{'Object'} && UNIVERSAL::can($args{'Object'},'id')) {
161 $object_type = ref($args{'Object'});
162 $object_id = $args{'Object'}->id;
163 } elsif ($args{'ObjectId'} || $args{'ObjectType'}) {
164 $object_type = $args{'ObjectType'};
165 $object_id = $args{'ObjectId'};
167 return ( 0, $self->loc("System error. Right not granted.") );
170 $self->LoadByCols( PrincipalId => $princ_obj->Id,
171 PrincipalType => $args{'PrincipalType'},
172 RightName => $args{'RightName'},
173 ObjectType => $object_type,
174 ObjectId => $object_id);
176 #If we couldn't load it.
177 unless ( $self->Id ) {
178 return ( 0, $self->loc("ACE not found") );
182 return ( $self->Id, $self->loc("Right Loaded") );
190 =head2 Create <PARAMS>
192 PARAMS is a parameter hash with the following elements:
194 PrincipalId => The id of an RT::Principal object
195 PrincipalType => "User" "Group" or any Role type
196 RightName => the name of a right. in any case
197 DelegatedBy => The Principal->Id of the user delegating the right
198 DelegatedFrom => The id of the ACE which this new ACE is delegated from
203 Object => An object to create rights for. ususally, an RT::Queue or RT::Group
204 This should always be a DBIx::SearchBuilder::Record subclass
208 ObjectType => the type of the object in question (ref ($object))
209 ObjectId => the id of the object in question $object->Id
215 my %args = ( PrincipalId => undef,
216 PrincipalType => undef,
218 Object => $RT::System,
221 # {{{ Validate the principal
223 ( $princ_obj, $args{'PrincipalType'} ) =
224 $self->_CanonicalizePrincipal( $args{'PrincipalId'},
225 $args{'PrincipalType'} );
227 unless ( $princ_obj->id ) {
229 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
236 if ($args{'Object'} && ($args{'ObjectId'} || $args{'ObjectType'})) {
238 $RT::Logger->crit(Carp::cluck("ACE::Create called with an ObjectType or an ObjectId"));
243 unless ($args{'Object'} && UNIVERSAL::can($args{'Object'},'id')) {
244 return ( 0, $self->loc("System error. Right not granted.") );
248 if (ref( $args{'Object'}) eq 'RT::Group' ) {
249 unless ( $self->CurrentUser->HasRight( Object => $args{'Object'},
250 Right => 'AdminGroup' )
252 return ( 0, $self->loc('Permission Denied') );
257 unless ( $self->CurrentUser->HasRight( Object => $args{'Object'}, Right => 'ModifyACL' )) {
258 return ( 0, $self->loc('Permission Denied') );
263 # {{{ Canonicalize and check the right name
264 unless ( $args{'RightName'} ) {
265 return ( 0, $self->loc('Invalid right') );
268 $args{'RightName'} = $self->CanonicalizeRightName( $args{'RightName'} );
270 #check if it's a valid RightName
271 if ( ref ($args{'Object'} eq 'RT::Queue' )) {
272 unless ( exists $args{'Object'}->AvailableRights->{ $args{'RightName'} } ) {
273 $RT::Logger->warning("Couldn't validate right name". $args{'RightName'});
274 return ( 0, $self->loc('Invalid right') );
277 elsif ( ref ($args{'Object'} eq 'RT::Group' )) {
278 unless ( exists $args{'Object'}->AvailableRights->{ $args{'RightName'} } ) {
279 $RT::Logger->warning("Couldn't validate group right name". $args{'RightName'});
280 return ( 0, $self->loc('Invalid right') );
283 elsif ( ref ($args{'Object'} eq 'RT::System' )) {
284 my $q = RT::Queue->new($self->CurrentUser);
285 my $g = RT::Group->new($self->CurrentUser);
287 unless (( exists $g->AvailableRights->{ $args{'RightName'} } )
288 || ( exists $g->AvailableRights->{ $args{'RightName'} } )
289 || ( exists $RT::System->AvailableRights->{ $args{'RightName'} } ) ) {
290 $RT::Logger->warning("Couldn't validate system right name - ". $args{'RightName'});
291 return ( 0, $self->loc('Invalid right') );
295 unless ( $args{'RightName'} ) {
296 return ( 0, $self->loc('Invalid right') );
300 # Make sure the right doesn't already exist.
301 $self->LoadByCols( PrincipalId => $princ_obj->id,
302 PrincipalType => $args{'PrincipalType'},
303 RightName => $args{'RightName'},
304 ObjectType => ref($args{'Object'}),
305 ObjectId => $args{'Object'}->id,
307 DelegatedFrom => 0 );
309 return ( 0, $self->loc('That principal already has that right') );
312 my $id = $self->SUPER::Create( PrincipalId => $princ_obj->id,
313 PrincipalType => $args{'PrincipalType'},
314 RightName => $args{'RightName'},
315 ObjectType => ref( $args{'Object'} ),
316 ObjectId => $args{'Object'}->id,
318 DelegatedFrom => 0 );
320 #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space.
321 RT::Principal->_InvalidateACLCache();
324 return ( $id, $self->loc('Right Granted') );
327 return ( 0, $self->loc('System error. Right not granted.') );
335 =head2 Delegate <PARAMS>
337 This routine delegates the current ACE to a principal specified by the
338 B<PrincipalId> parameter.
340 Returns an error if the current user doesn't have the right to be delegated
341 or doesn't have the right to delegate rights.
343 Always returns a tuple of (ReturnValue, Message)
348 my $user_a = RT::User->new($RT::SystemUser);
349 $user_a->Create( Name => 'DelegationA', Privileged => 1);
350 ok ($user_a->Id, "Created delegation user a");
352 my $user_b = RT::User->new($RT::SystemUser);
353 $user_b->Create( Name => 'DelegationB', Privileged => 1);
354 ok ($user_b->Id, "Created delegation user b");
358 my $q = RT::Queue->new($RT::SystemUser);
359 $q->Create(Name =>'DelegationTest');
360 ok ($q->Id, "Created a delegation test queue");
363 #------ First, we test whether a user can delegate a right that's been granted to him personally
364 my ($val, $msg) = $user_a->PrincipalObj->GrantRight(Object => $RT::System, Right => 'AdminOwnPersonalGroups');
367 ($val, $msg) = $user_a->PrincipalObj->GrantRight(Object =>$q, Right => 'OwnTicket');
370 ok($user_a->HasRight( Object => $RT::System, Right => 'AdminOwnPersonalGroups') ,"user a has the right 'AdminOwnPersonalGroups' directly");
372 my $a_delegates = RT::Group->new($user_a);
373 $a_delegates->CreatePersonalGroup(Name => 'Delegates');
374 ok( $a_delegates->Id ,"user a creates a personal group 'Delegates'");
375 ok( $a_delegates->AddMember($user_b->PrincipalId) ,"user a adds user b to personal group 'delegates'");
377 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to OwnTicket' in queue 'DelegationTest'");
378 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a has the right to 'OwnTicket' in queue 'DelegationTest'");
379 ok(!$user_a->HasRight( Object => $RT::System, Right => 'DelegateRights') ,"user a does not have the right 'delegate rights'");
382 my $own_ticket_ace = RT::ACE->new($user_a);
383 my $user_a_equiv_group = RT::Group->new($user_a);
384 $user_a_equiv_group->LoadACLEquivalenceGroup($user_a->PrincipalObj);
385 ok ($user_a_equiv_group->Id, "Loaded the user A acl equivalence group");
386 my $user_b_equiv_group = RT::Group->new($user_b);
387 $user_b_equiv_group->LoadACLEquivalenceGroup($user_b->PrincipalObj);
388 ok ($user_b_equiv_group->Id, "Loaded the user B acl equivalence group");
389 $own_ticket_ace->LoadByValues( PrincipalType => 'Group', PrincipalId => $user_a_equiv_group->PrincipalId, Object=>$q, RightName => 'OwnTicket');
391 ok ($own_ticket_ace->Id, "Found the ACE we want to test with for now");
394 ($val, $msg) = $own_ticket_ace->Delegate(PrincipalId => $a_delegates->PrincipalId) ;
395 ok( !$val ,"user a tries and fails to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
398 ($val, $msg) = $user_a->PrincipalObj->GrantRight( Right => 'DelegateRights');
399 ok($val, "user a is granted the right to 'delegate rights' - $msg");
401 ok($user_a->HasRight( Object => $RT::System, Right => 'DelegateRights') ,"user a has the right 'AdminOwnPersonalGroups' directly");
403 ($val, $msg) = $own_ticket_ace->Delegate(PrincipalId => $a_delegates->PrincipalId) ;
405 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
406 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
407 my $delegated_ace = RT::ACE->new($user_a);
408 $delegated_ace->LoadByValues ( Object => $q, RightName => 'OwnTicket', PrincipalType => 'Group',
409 PrincipalId => $a_delegates->PrincipalId, DelegatedBy => $user_a->PrincipalId, DelegatedFrom => $own_ticket_ace->Id);
410 ok ($delegated_ace->Id, "Found the delegated ACE");
412 ok( $a_delegates->DeleteMember($user_b->PrincipalId) ,"user a removes b from pg 'delegates'");
413 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
414 ok( $a_delegates->AddMember($user_b->PrincipalId) ,"user a adds user b to personal group 'delegates'");
415 ok( $user_b->HasRight(Right => 'OwnTicket', Object=> $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
416 ok( $delegated_ace->Delete ,"user a revokes pg 'delegates' right to 'OwnTickets' in queue 'DelegationTest'");
417 ok( ! $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
419 ($val, $msg) = $own_ticket_ace->Delegate(PrincipalId => $a_delegates->PrincipalId) ;
420 ok( $val ,"user a delegates pg 'delegates' right to 'OwnTickets' in queue 'DelegationTest' - $msg");
422 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest'");
424 ($val, $msg) = $user_a->PrincipalObj->RevokeRight(Object=>$q, Right => 'OwnTicket');
425 ok($val, "Revoked user a's right to own tickets in queue 'DelegationTest". $msg);
427 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest'");
429 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
431 ($val, $msg) = $user_a->PrincipalObj->GrantRight(Object=>$q, Right => 'OwnTicket');
434 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a has the right to own tickets in queue 'DelegationTest'");
436 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
438 # {{{ get back to a known clean state
439 ($val, $msg) = $user_a->PrincipalObj->RevokeRight( Object => $q, Right => 'OwnTicket');
440 ok($val, "Revoked user a's right to own tickets in queue 'DelegationTest -". $msg);
441 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"make sure that user a can't own tickets in queue 'DelegationTest'");
445 # {{{ Set up some groups and membership
446 my $del1 = RT::Group->new($RT::SystemUser);
447 ($val, $msg) = $del1->CreateUserDefinedGroup(Name => 'Del1');
448 ok( $val ,"create a group del1 - $msg");
450 my $del2 = RT::Group->new($RT::SystemUser);
451 ($val, $msg) = $del2->CreateUserDefinedGroup(Name => 'Del2');
452 ok( $val ,"create a group del2 - $msg");
453 ($val, $msg) = $del1->AddMember($del2->PrincipalId);
454 ok( $val,"make del2 a member of del1 - $msg");
456 my $del2a = RT::Group->new($RT::SystemUser);
457 ($val, $msg) = $del2a->CreateUserDefinedGroup(Name => 'Del2a');
458 ok( $val ,"create a group del2a - $msg");
459 ($val, $msg) = $del2->AddMember($del2a->PrincipalId);
460 ok($val ,"make del2a a member of del2 - $msg");
462 my $del2b = RT::Group->new($RT::SystemUser);
463 ($val, $msg) = $del2b->CreateUserDefinedGroup(Name => 'Del2b');
464 ok( $val ,"create a group del2b - $msg");
465 ($val, $msg) = $del2->AddMember($del2b->PrincipalId);
466 ok($val ,"make del2b a member of del2 - $msg");
468 ($val, $msg) = $del2->AddMember($user_a->PrincipalId) ;
469 ok($val,"make 'user a' a member of del2 - $msg");
471 ($val, $msg) = $del2b->AddMember($user_a->PrincipalId) ;
472 ok($val,"make 'user a' a member of del2b - $msg");
476 # {{{ Grant a right to a group and make sure that a submember can delegate the right and that it does not get yanked
477 # when a user is removed as a submember, when they're a sumember through another path
478 ($val, $msg) = $del1->PrincipalObj->GrantRight( Object=> $q, Right => 'OwnTicket');
479 ok( $val ,"grant del1 the right to 'OwnTicket' in queue 'DelegationTest' - $msg");
481 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"make sure that user a can own tickets in queue 'DelegationTest'");
483 my $group_ace= RT::ACE->new($user_a);
484 $group_ace->LoadByValues( PrincipalType => 'Group', PrincipalId => $del1->PrincipalId, Object => $q, RightName => 'OwnTicket');
486 ok ($group_ace->Id, "Found the ACE we want to test with for now");
488 ($val, $msg) = $group_ace->Delegate(PrincipalId => $a_delegates->PrincipalId);
490 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
491 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
494 ($val, $msg) = $del2b->DeleteMember($user_a->PrincipalId);
495 ok( $val ,"remove user a from group del2b - $msg");
496 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a has the right to own tickets in queue 'DelegationTest'");
497 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
501 # {{{ When a user is removed froom a group by the only path they're in there by, make sure the delegations go away
502 ($val, $msg) = $del2->DeleteMember($user_a->PrincipalId);
503 ok( $val ,"remove user a from group del2 - $msg");
504 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest' ");
505 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest' ");
508 ($val, $msg) = $del2->AddMember($user_a->PrincipalId);
509 ok( $val ,"make user a a member of group del2 - $msg");
511 ($val, $msg) = $del2->PrincipalObj->GrantRight(Object=>$q, Right => 'OwnTicket');
512 ok($val, "grant the right 'own tickets' in queue 'DelegationTest' to group del2 - $msg");
514 my $del2_right = RT::ACE->new($user_a);
515 $del2_right->LoadByValues( PrincipalId => $del2->PrincipalId, PrincipalType => 'Group', Object => $q, RightName => 'OwnTicket');
516 ok ($del2_right->Id, "Found the right");
518 ($val, $msg) = $del2_right->Delegate(PrincipalId => $a_delegates->PrincipalId);
519 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' gotten via del2 to personal group 'delegates' - $msg");
521 # They have it via del1 and del2
522 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
525 ($val, $msg) = $del2->PrincipalObj->RevokeRight(Object=>$q, Right => 'OwnTicket');
526 ok($val, "revoke the right 'own tickets' in queue 'DelegationTest' to group del2 - $msg");
527 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does has the right to own tickets in queue 'DelegationTest' via del1");
528 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
530 ($val, $msg) = $del2->PrincipalObj->GrantRight(Object=>$q, Right => 'OwnTicket');
531 ok($val, "grant the right 'own tickets' in queue 'DelegationTest' to group del2 - $msg");
534 $group_ace= RT::ACE->new($user_a);
535 $group_ace->LoadByValues( PrincipalType => 'Group', PrincipalId => $del1->PrincipalId, Object=>$q, RightName => 'OwnTicket');
537 ok ($group_ace->Id, "Found the ACE we want to test with for now");
539 ($val, $msg) = $group_ace->Delegate(PrincipalId => $a_delegates->PrincipalId);
541 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
543 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
545 ($val, $msg) = $del2->DeleteMember($user_a->PrincipalId);
546 ok( $val ,"remove user a from group del2 - $msg");
548 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest'");
550 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
560 my %args = ( PrincipalId => undef,
563 unless ( $self->Id ) {
564 return ( 0, $self->loc("Right not loaded.") );
567 ( $princ_obj, $args{'PrincipalType'} ) =
568 $self->_CanonicalizePrincipal( $args{'PrincipalId'},
569 $args{'PrincipalType'} );
571 unless ( $princ_obj->id ) {
573 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
581 # First, we check to se if the user is delegating rights and
582 # they have the permission to
583 unless ( $self->CurrentUser->HasRight(Right => 'DelegateRights', Object => $self->Object) ) {
584 return ( 0, $self->loc("Permission Denied") );
587 unless ( $self->PrincipalObj->IsGroup ) {
588 return ( 0, $self->loc("System Error") );
590 unless ( $self->PrincipalObj->Object->HasMemberRecursively(
591 $self->CurrentUser->PrincipalObj
594 return ( 0, $self->loc("Permission Denied") );
599 my $concurrency_check = RT::ACE->new($RT::SystemUser);
600 $concurrency_check->Load( $self->Id );
601 unless ( $concurrency_check->Id ) {
603 "Trying to delegate a right which had already been deleted");
604 return ( 0, $self->loc('Permission Denied') );
607 my $delegated_ace = RT::ACE->new( $self->CurrentUser );
609 # Make sure the right doesn't already exist.
610 $delegated_ace->LoadByCols( PrincipalId => $princ_obj->Id,
611 PrincipalType => 'Group',
612 RightName => $self->__Value('RightName'),
613 ObjectType => $self->__Value('ObjectType'),
614 ObjectId => $self->__Value('ObjectId'),
615 DelegatedBy => $self->CurrentUser->PrincipalId,
616 DelegatedFrom => $self->id );
617 if ( $delegated_ace->Id ) {
618 return ( 0, $self->loc('That principal already has that right') );
620 my $id = $delegated_ace->SUPER::Create(
621 PrincipalId => $princ_obj->Id,
622 PrincipalType => 'Group', # do we want to hardcode this?
623 RightName => $self->__Value('RightName'),
624 ObjectType => $self->__Value('ObjectType'),
625 ObjectId => $self->__Value('ObjectId'),
626 DelegatedBy => $self->CurrentUser->PrincipalId,
627 DelegatedFrom => $self->id );
629 #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space.
630 # TODO what about the groups key cache?
631 RT::Principal->_InvalidateACLCache();
634 return ( $id, $self->loc('Right Delegated') );
637 return ( 0, $self->loc('System error. Right not delegated.') );
645 =head2 Delete { InsideTransaction => undef}
647 Delete this object. This method should ONLY ever be called from RT::User or RT::Group (or from itself)
648 If this is being called from within a transaction, specify a true value for the parameter InsideTransaction.
649 Really, DBIx::SearchBuilder should use and/or fake subtransactions
651 This routine will also recurse and delete any delegations of this right
658 unless ( $self->Id ) {
659 return ( 0, $self->loc('Right not loaded.') );
662 # A user can delete an ACE if the current user has the right to modify it and it's not a delegated ACE
663 # or if it's a delegated ACE and it was delegated by the current user
665 ( $self->CurrentUser->HasRight(Right => 'ModifyACL', Object => $self->Object)
666 && $self->__Value('DelegatedBy') == 0 )
667 || ( $self->__Value('DelegatedBy') == $self->CurrentUser->PrincipalId )
669 return ( 0, $self->loc('Permission Denied') );
674 # Helper for Delete with no ACL check
677 my %args = ( InsideTransaction => undef,
680 my $InsideTransaction = $args{'InsideTransaction'};
682 $RT::Handle->BeginTransaction() unless $InsideTransaction;
684 my $delegated_from_this = RT::ACL->new($RT::SystemUser);
685 $delegated_from_this->Limit( FIELD => 'DelegatedFrom',
687 VALUE => $self->Id );
689 my $delete_succeeded = 1;
691 while ( my $delegated_ace = $delegated_from_this->Next ) {
692 ( $delete_succeeded, $submsg ) =
693 $delegated_ace->_Delete( InsideTransaction => 1 );
694 last if ($delete_succeeded);
697 unless ($delete_succeeded) {
698 $RT::Handle->Rollback() unless $InsideTransaction;
699 return ( 0, $self->loc('Right could not be revoked') );
702 my ( $val, $msg ) = $self->SUPER::Delete(@_);
704 #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space.
705 # TODO what about the groups key cache?
706 RT::Principal->_InvalidateACLCache();
709 $RT::Handle->Commit() unless $InsideTransaction;
710 return ( $val, $self->loc('Right revoked') );
713 $RT::Handle->Rollback() unless $InsideTransaction;
714 return ( 0, $self->loc('Right could not be revoked') );
720 # {{{ sub _BootstrapCreate
722 =head2 _BootstrapCreate
724 Grant a right with no error checking and no ACL. this is _only_ for
725 installation. If you use this routine without the author's explicit
726 written approval, he will hunt you down and make you spend eternity
727 translating mozilla's code into FORTRAN or intercal.
729 If you think you need this routine, you've mistaken.
733 sub _BootstrapCreate {
737 # When bootstrapping, make sure we get the _right_ users
738 if ( $args{'UserId'} ) {
739 my $user = RT::User->new( $self->CurrentUser );
740 $user->Load( $args{'UserId'} );
741 delete $args{'UserId'};
742 $args{'PrincipalId'} = $user->PrincipalId;
743 $args{'PrincipalType'} = 'User';
746 my $id = $self->SUPER::Create(%args);
752 $RT::Logger->err('System error. right not granted.');
760 # {{{ sub CanonicalizeRightName
762 =head2 CanonicalizeRightName <RIGHT>
764 Takes a queue or system right name in any case and returns it in
765 the correct case. If it's not found, will return undef.
769 sub CanonicalizeRightName {
773 if ( exists $LOWERCASERIGHTNAMES{"$right"} ) {
774 return ( $LOWERCASERIGHTNAMES{"$right"} );
788 If the object this ACE applies to is a queue, returns the queue object.
789 If the object this ACE applies to is a group, returns the group object.
790 If it's the system object, returns undef.
792 If the user has no rights, returns undef.
804 if ($self->__Value('ObjectType') && $OBJECT_TYPES{$self->__Value('ObjectType')} ) {
805 $appliesto_obj = $self->__Value('ObjectType')->new($self->CurrentUser);
806 unless (ref( $appliesto_obj) eq $self->__Value('ObjectType')) {
809 $appliesto_obj->Load( $self->__Value('ObjectId') );
810 return ($appliesto_obj);
813 $RT::Logger->warning( "$self -> Object called for an object "
814 . "of an unknown type:"
815 . $self->ObjectType );
822 # {{{ sub PrincipalObj
826 Returns the RT::Principal object for this ACE.
833 my $princ_obj = RT::Principal->new( $self->CurrentUser );
834 $princ_obj->Load( $self->__Value('PrincipalId') );
836 unless ( $princ_obj->Id ) {
838 "ACE " . $self->Id . " couldn't load its principal object" );
846 # {{{ ACL related methods
852 return ( 0, $self->loc("ACEs can only be created and deleted.") );
862 if ( $self->__Value('DelegatedBy') eq $self->CurrentUser->PrincipalId ) {
863 return ( $self->__Value(@_) );
865 elsif ( $self->PrincipalObj->IsGroup
866 && $self->PrincipalObj->Object->HasMemberRecursively(
867 $self->CurrentUser->PrincipalObj
870 return ( $self->__Value(@_) );
872 elsif ( $self->CurrentUser->HasRight(Right => 'ShowACL', Object => $self->Object) ) {
873 return ( $self->__Value(@_) );
885 # {{{ _CanonicalizePrincipal
887 =head2 _CanonicalizePrincipal (PrincipalId, PrincipalType)
889 Takes a principal id and a principal type.
891 If the principal is a user, resolves it to the proper acl equivalence group.
892 Returns a tuple of (RT::Principal, PrincipalType) for the principal we really want to work with
896 sub _CanonicalizePrincipal {
898 my $princ_id = shift;
899 my $princ_type = shift;
901 my $princ_obj = RT::Principal->new($RT::SystemUser);
902 $princ_obj->Load($princ_id);
904 unless ( $princ_obj->Id ) {
906 $RT::Logger->crit(Carp::cluck);
907 $RT::Logger->crit("Can't load a principal for id $princ_id");
908 return ( $princ_obj, undef );
911 # Rights never get granted to users. they get granted to their
912 # ACL equivalence groups
913 if ( $princ_type eq 'User' ) {
914 my $equiv_group = RT::Group->new( $self->CurrentUser );
915 $equiv_group->LoadACLEquivalenceGroup($princ_obj);
916 unless ( $equiv_group->Id ) {
918 "No ACL equiv group for princ " . $self->__Value('ObjectId') );
919 return ( 0, $self->loc('System error. Right not granted.') );
921 $princ_obj = $equiv_group->PrincipalObj();
922 $princ_type = 'Group';
925 return ( $princ_obj, $princ_type );