1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2005 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 }}}
50 my $ace = new RT::ACE($CurrentUser);
71 no warnings qw(redefine);
79 %TICKET_METAPRINCIPALS
83 # {{{ Descriptions of rights
87 # Queue rights are the sort of queue rights that can only be granted
88 # to real people or groups
93 my $Queue = RT::Queue->new($RT::SystemUser);
95 is ($Queue->AvailableRights->{'DeleteTicket'} , 'Delete tickets', "Found the delete ticket right");
96 is ($RT::System->AvailableRights->{'SuperUser'}, 'Do anything and everything', "Found the superuser right");
108 # {{{ Descriptions of principals
110 %TICKET_METAPRINCIPALS = (
111 Owner => 'The owner of a ticket', # loc_pair
112 Requestor => 'The requestor of a ticket', # loc_pair
113 Cc => 'The CC of a ticket', # loc_pair
114 AdminCc => 'The administrative CC of a ticket', # loc_pair
120 # {{{ sub LoadByValues
122 =head2 LoadByValues PARAMHASH
124 Load an ACE by specifying a paramhash with the following fields:
126 PrincipalId => undef,
127 PrincipalType => undef,
143 my %args = ( PrincipalId => undef,
144 PrincipalType => undef,
152 ( $princ_obj, $args{'PrincipalType'} ) =
153 $self->_CanonicalizePrincipal( $args{'PrincipalId'},
154 $args{'PrincipalType'} );
156 unless ( $princ_obj->id ) {
158 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
162 my ($object, $object_type, $object_id) = $self->_ParseObjectArg( %args );
164 return ( 0, $self->loc("System error. Right not granted.") );
167 $self->LoadByCols( PrincipalId => $princ_obj->Id,
168 PrincipalType => $args{'PrincipalType'},
169 RightName => $args{'RightName'},
170 ObjectType => $object_type,
171 ObjectId => $object_id);
173 #If we couldn't load it.
174 unless ( $self->Id ) {
175 return ( 0, $self->loc("ACE not found") );
179 return ( $self->Id, $self->loc("Right Loaded") );
187 =head2 Create <PARAMS>
189 PARAMS is a parameter hash with the following elements:
191 PrincipalId => The id of an RT::Principal object
192 PrincipalType => "User" "Group" or any Role type
193 RightName => the name of a right. in any case
194 DelegatedBy => The Principal->Id of the user delegating the right
195 DelegatedFrom => The id of the ACE which this new ACE is delegated from
200 Object => An object to create rights for. ususally, an RT::Queue or RT::Group
201 This should always be a DBIx::SearchBuilder::Record subclass
205 ObjectType => the type of the object in question (ref ($object))
206 ObjectId => the id of the object in question $object->Id
210 Returns a tuple of (STATUS, MESSAGE); If the call succeeded, STATUS is true. Otherwise it's false.
218 my %args = ( PrincipalId => undef,
219 PrincipalType => undef,
223 #if we haven't specified any sort of right, we're talking about a global right
224 if (!defined $args{'Object'} && !defined $args{'ObjectId'} && !defined $args{'ObjectType'}) {
225 $args{'Object'} = $RT::System;
227 ($args{'Object'}, $args{'ObjectType'}, $args{'ObjectId'}) = $self->_ParseObjectArg( %args );
228 unless( $args{'Object'} ) {
229 return ( 0, $self->loc("System error. Right not granted.") );
232 # {{{ Validate the principal
234 ( $princ_obj, $args{'PrincipalType'} ) =
235 $self->_CanonicalizePrincipal( $args{'PrincipalId'},
236 $args{'PrincipalType'} );
238 unless ( $princ_obj->id ) {
240 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
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') );
297 # Make sure the right doesn't already exist.
298 $self->LoadByCols( PrincipalId => $princ_obj->id,
299 PrincipalType => $args{'PrincipalType'},
300 RightName => $args{'RightName'},
301 ObjectType => $args{'ObjectType'},
302 ObjectId => $args{'ObjectId'},
304 DelegatedFrom => 0 );
306 return ( 0, $self->loc('That principal already has that right') );
309 my $id = $self->SUPER::Create( PrincipalId => $princ_obj->id,
310 PrincipalType => $args{'PrincipalType'},
311 RightName => $args{'RightName'},
312 ObjectType => ref( $args{'Object'} ),
313 ObjectId => $args{'Object'}->id,
315 DelegatedFrom => 0 );
317 #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space.
318 RT::Principal->InvalidateACLCache();
321 return ( $id, $self->loc('Right Granted') );
324 return ( 0, $self->loc('System error. Right not granted.') );
332 =head2 Delegate <PARAMS>
334 This routine delegates the current ACE to a principal specified by the
335 B<PrincipalId> parameter.
337 Returns an error if the current user doesn't have the right to be delegated
338 or doesn't have the right to delegate rights.
340 Always returns a tuple of (ReturnValue, Message)
345 my $user_a = RT::User->new($RT::SystemUser);
346 $user_a->Create( Name => 'DelegationA', Privileged => 1);
347 ok ($user_a->Id, "Created delegation user a");
349 my $user_b = RT::User->new($RT::SystemUser);
350 $user_b->Create( Name => 'DelegationB', Privileged => 1);
351 ok ($user_b->Id, "Created delegation user b");
355 my $q = RT::Queue->new($RT::SystemUser);
356 $q->Create(Name =>'DelegationTest');
357 ok ($q->Id, "Created a delegation test queue");
360 #------ First, we test whether a user can delegate a right that's been granted to him personally
361 my ($val, $msg) = $user_a->PrincipalObj->GrantRight(Object => $RT::System, Right => 'AdminOwnPersonalGroups');
364 ($val, $msg) = $user_a->PrincipalObj->GrantRight(Object =>$q, Right => 'OwnTicket');
367 ok($user_a->HasRight( Object => $RT::System, Right => 'AdminOwnPersonalGroups') ,"user a has the right 'AdminOwnPersonalGroups' directly");
369 my $a_delegates = RT::Group->new($user_a);
370 $a_delegates->CreatePersonalGroup(Name => 'Delegates');
371 ok( $a_delegates->Id ,"user a creates a personal group 'Delegates'");
372 ok( $a_delegates->AddMember($user_b->PrincipalId) ,"user a adds user b to personal group 'delegates'");
374 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to OwnTicket' in queue 'DelegationTest'");
375 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a has the right to 'OwnTicket' in queue 'DelegationTest'");
376 ok(!$user_a->HasRight( Object => $RT::System, Right => 'DelegateRights') ,"user a does not have the right 'delegate rights'");
379 my $own_ticket_ace = RT::ACE->new($user_a);
380 my $user_a_equiv_group = RT::Group->new($user_a);
381 $user_a_equiv_group->LoadACLEquivalenceGroup($user_a->PrincipalObj);
382 ok ($user_a_equiv_group->Id, "Loaded the user A acl equivalence group");
383 my $user_b_equiv_group = RT::Group->new($user_b);
384 $user_b_equiv_group->LoadACLEquivalenceGroup($user_b->PrincipalObj);
385 ok ($user_b_equiv_group->Id, "Loaded the user B acl equivalence group");
386 $own_ticket_ace->LoadByValues( PrincipalType => 'Group', PrincipalId => $user_a_equiv_group->PrincipalId, Object=>$q, RightName => 'OwnTicket');
388 ok ($own_ticket_ace->Id, "Found the ACE we want to test with for now");
391 ($val, $msg) = $own_ticket_ace->Delegate(PrincipalId => $a_delegates->PrincipalId) ;
392 ok( !$val ,"user a tries and fails to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
395 ($val, $msg) = $user_a->PrincipalObj->GrantRight( Right => 'DelegateRights');
396 ok($val, "user a is granted the right to 'delegate rights' - $msg");
398 ok($user_a->HasRight( Object => $RT::System, Right => 'DelegateRights') ,"user a has the right 'AdminOwnPersonalGroups' directly");
400 ($val, $msg) = $own_ticket_ace->Delegate(PrincipalId => $a_delegates->PrincipalId) ;
402 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
403 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
404 my $delegated_ace = RT::ACE->new($user_a);
405 $delegated_ace->LoadByValues ( Object => $q, RightName => 'OwnTicket', PrincipalType => 'Group',
406 PrincipalId => $a_delegates->PrincipalId, DelegatedBy => $user_a->PrincipalId, DelegatedFrom => $own_ticket_ace->Id);
407 ok ($delegated_ace->Id, "Found the delegated ACE");
409 ok( $a_delegates->DeleteMember($user_b->PrincipalId) ,"user a removes b from pg 'delegates'");
410 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
411 ok( $a_delegates->AddMember($user_b->PrincipalId) ,"user a adds user b to personal group 'delegates'");
412 ok( $user_b->HasRight(Right => 'OwnTicket', Object=> $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
413 ok( $delegated_ace->Delete ,"user a revokes pg 'delegates' right to 'OwnTickets' in queue 'DelegationTest'");
414 ok( ! $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
416 ($val, $msg) = $own_ticket_ace->Delegate(PrincipalId => $a_delegates->PrincipalId) ;
417 ok( $val ,"user a delegates pg 'delegates' right to 'OwnTickets' in queue 'DelegationTest' - $msg");
419 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest'");
421 ($val, $msg) = $user_a->PrincipalObj->RevokeRight(Object=>$q, Right => 'OwnTicket');
422 ok($val, "Revoked user a's right to own tickets in queue 'DelegationTest". $msg);
424 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest'");
426 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
428 ($val, $msg) = $user_a->PrincipalObj->GrantRight(Object=>$q, Right => 'OwnTicket');
431 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a has the right to own tickets in queue 'DelegationTest'");
433 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
435 # {{{ get back to a known clean state
436 ($val, $msg) = $user_a->PrincipalObj->RevokeRight( Object => $q, Right => 'OwnTicket');
437 ok($val, "Revoked user a's right to own tickets in queue 'DelegationTest -". $msg);
438 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"make sure that user a can't own tickets in queue 'DelegationTest'");
442 # {{{ Set up some groups and membership
443 my $del1 = RT::Group->new($RT::SystemUser);
444 ($val, $msg) = $del1->CreateUserDefinedGroup(Name => 'Del1');
445 ok( $val ,"create a group del1 - $msg");
447 my $del2 = RT::Group->new($RT::SystemUser);
448 ($val, $msg) = $del2->CreateUserDefinedGroup(Name => 'Del2');
449 ok( $val ,"create a group del2 - $msg");
450 ($val, $msg) = $del1->AddMember($del2->PrincipalId);
451 ok( $val,"make del2 a member of del1 - $msg");
453 my $del2a = RT::Group->new($RT::SystemUser);
454 ($val, $msg) = $del2a->CreateUserDefinedGroup(Name => 'Del2a');
455 ok( $val ,"create a group del2a - $msg");
456 ($val, $msg) = $del2->AddMember($del2a->PrincipalId);
457 ok($val ,"make del2a a member of del2 - $msg");
459 my $del2b = RT::Group->new($RT::SystemUser);
460 ($val, $msg) = $del2b->CreateUserDefinedGroup(Name => 'Del2b');
461 ok( $val ,"create a group del2b - $msg");
462 ($val, $msg) = $del2->AddMember($del2b->PrincipalId);
463 ok($val ,"make del2b a member of del2 - $msg");
465 ($val, $msg) = $del2->AddMember($user_a->PrincipalId) ;
466 ok($val,"make 'user a' a member of del2 - $msg");
468 ($val, $msg) = $del2b->AddMember($user_a->PrincipalId) ;
469 ok($val,"make 'user a' a member of del2b - $msg");
473 # {{{ Grant a right to a group and make sure that a submember can delegate the right and that it does not get yanked
474 # when a user is removed as a submember, when they're a sumember through another path
475 ($val, $msg) = $del1->PrincipalObj->GrantRight( Object=> $q, Right => 'OwnTicket');
476 ok( $val ,"grant del1 the right to 'OwnTicket' in queue 'DelegationTest' - $msg");
478 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"make sure that user a can own tickets in queue 'DelegationTest'");
480 my $group_ace= RT::ACE->new($user_a);
481 $group_ace->LoadByValues( PrincipalType => 'Group', PrincipalId => $del1->PrincipalId, Object => $q, RightName => 'OwnTicket');
483 ok ($group_ace->Id, "Found the ACE we want to test with for now");
485 ($val, $msg) = $group_ace->Delegate(PrincipalId => $a_delegates->PrincipalId);
487 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
488 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
491 ($val, $msg) = $del2b->DeleteMember($user_a->PrincipalId);
492 ok( $val ,"remove user a from group del2b - $msg");
493 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a has the right to own tickets in queue 'DelegationTest'");
494 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
498 # {{{ When a user is removed froom a group by the only path they're in there by, make sure the delegations go away
499 ($val, $msg) = $del2->DeleteMember($user_a->PrincipalId);
500 ok( $val ,"remove user a from group del2 - $msg");
501 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest' ");
502 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest' ");
505 ($val, $msg) = $del2->AddMember($user_a->PrincipalId);
506 ok( $val ,"make user a a member of group del2 - $msg");
508 ($val, $msg) = $del2->PrincipalObj->GrantRight(Object=>$q, Right => 'OwnTicket');
509 ok($val, "grant the right 'own tickets' in queue 'DelegationTest' to group del2 - $msg");
511 my $del2_right = RT::ACE->new($user_a);
512 $del2_right->LoadByValues( PrincipalId => $del2->PrincipalId, PrincipalType => 'Group', Object => $q, RightName => 'OwnTicket');
513 ok ($del2_right->Id, "Found the right");
515 ($val, $msg) = $del2_right->Delegate(PrincipalId => $a_delegates->PrincipalId);
516 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' gotten via del2 to personal group 'delegates' - $msg");
518 # They have it via del1 and del2
519 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
522 ($val, $msg) = $del2->PrincipalObj->RevokeRight(Object=>$q, Right => 'OwnTicket');
523 ok($val, "revoke the right 'own tickets' in queue 'DelegationTest' to group del2 - $msg");
524 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does has the right to own tickets in queue 'DelegationTest' via del1");
525 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
527 ($val, $msg) = $del2->PrincipalObj->GrantRight(Object=>$q, Right => 'OwnTicket');
528 ok($val, "grant the right 'own tickets' in queue 'DelegationTest' to group del2 - $msg");
531 $group_ace= RT::ACE->new($user_a);
532 $group_ace->LoadByValues( PrincipalType => 'Group', PrincipalId => $del1->PrincipalId, Object=>$q, RightName => 'OwnTicket');
534 ok ($group_ace->Id, "Found the ACE we want to test with for now");
536 ($val, $msg) = $group_ace->Delegate(PrincipalId => $a_delegates->PrincipalId);
538 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
540 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
542 ($val, $msg) = $del2->DeleteMember($user_a->PrincipalId);
543 ok( $val ,"remove user a from group del2 - $msg");
545 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest'");
547 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
557 my %args = ( PrincipalId => undef,
560 unless ( $self->Id ) {
561 return ( 0, $self->loc("Right not loaded.") );
564 ( $princ_obj, $args{'PrincipalType'} ) =
565 $self->_CanonicalizePrincipal( $args{'PrincipalId'},
566 $args{'PrincipalType'} );
568 unless ( $princ_obj->id ) {
570 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
578 # First, we check to se if the user is delegating rights and
579 # they have the permission to
580 unless ( $self->CurrentUser->HasRight(Right => 'DelegateRights', Object => $self->Object) ) {
581 return ( 0, $self->loc("Permission Denied") );
584 unless ( $self->PrincipalObj->IsGroup ) {
585 return ( 0, $self->loc("System Error") );
587 unless ( $self->PrincipalObj->Object->HasMemberRecursively(
588 $self->CurrentUser->PrincipalObj
591 return ( 0, $self->loc("Permission Denied") );
596 my $concurrency_check = RT::ACE->new($RT::SystemUser);
597 $concurrency_check->Load( $self->Id );
598 unless ( $concurrency_check->Id ) {
600 "Trying to delegate a right which had already been deleted");
601 return ( 0, $self->loc('Permission Denied') );
604 my $delegated_ace = RT::ACE->new( $self->CurrentUser );
606 # Make sure the right doesn't already exist.
607 $delegated_ace->LoadByCols( PrincipalId => $princ_obj->Id,
608 PrincipalType => 'Group',
609 RightName => $self->__Value('RightName'),
610 ObjectType => $self->__Value('ObjectType'),
611 ObjectId => $self->__Value('ObjectId'),
612 DelegatedBy => $self->CurrentUser->PrincipalId,
613 DelegatedFrom => $self->id );
614 if ( $delegated_ace->Id ) {
615 return ( 0, $self->loc('That principal already has that right') );
617 my $id = $delegated_ace->SUPER::Create(
618 PrincipalId => $princ_obj->Id,
619 PrincipalType => 'Group', # do we want to hardcode this?
620 RightName => $self->__Value('RightName'),
621 ObjectType => $self->__Value('ObjectType'),
622 ObjectId => $self->__Value('ObjectId'),
623 DelegatedBy => $self->CurrentUser->PrincipalId,
624 DelegatedFrom => $self->id );
626 #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space.
627 # TODO what about the groups key cache?
628 RT::Principal->InvalidateACLCache();
631 return ( $id, $self->loc('Right Delegated') );
634 return ( 0, $self->loc('System error. Right not delegated.') );
642 =head2 Delete { InsideTransaction => undef}
644 Delete this object. This method should ONLY ever be called from RT::User or RT::Group (or from itself)
645 If this is being called from within a transaction, specify a true value for the parameter InsideTransaction.
646 Really, DBIx::SearchBuilder should use and/or fake subtransactions
648 This routine will also recurse and delete any delegations of this right
655 unless ( $self->Id ) {
656 return ( 0, $self->loc('Right not loaded.') );
659 # A user can delete an ACE if the current user has the right to modify it and it's not a delegated ACE
660 # or if it's a delegated ACE and it was delegated by the current user
662 ( $self->CurrentUser->HasRight(Right => 'ModifyACL', Object => $self->Object)
663 && $self->__Value('DelegatedBy') == 0 )
664 || ( $self->__Value('DelegatedBy') == $self->CurrentUser->PrincipalId )
666 return ( 0, $self->loc('Permission Denied') );
671 # Helper for Delete with no ACL check
674 my %args = ( InsideTransaction => undef,
677 my $InsideTransaction = $args{'InsideTransaction'};
679 $RT::Handle->BeginTransaction() unless $InsideTransaction;
681 my $delegated_from_this = RT::ACL->new($RT::SystemUser);
682 $delegated_from_this->Limit( FIELD => 'DelegatedFrom',
684 VALUE => $self->Id );
686 my $delete_succeeded = 1;
688 while ( my $delegated_ace = $delegated_from_this->Next ) {
689 ( $delete_succeeded, $submsg ) =
690 $delegated_ace->_Delete( InsideTransaction => 1 );
691 last unless ($delete_succeeded);
694 unless ($delete_succeeded) {
695 $RT::Handle->Rollback() unless $InsideTransaction;
696 return ( 0, $self->loc('Right could not be revoked') );
699 my ( $val, $msg ) = $self->SUPER::Delete(@_);
701 # If we're revoking delegation rights (see above), we may need to
702 # revoke all rights delegated by the recipient.
703 if ($val and ($self->RightName() eq 'DelegateRights' or
704 $self->RightName() eq 'SuperUser')) {
705 $val = $self->PrincipalObj->_CleanupInvalidDelegations( InsideTransaction => 1 );
709 #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space.
710 # TODO what about the groups key cache?
711 RT::Principal->InvalidateACLCache();
712 $RT::Handle->Commit() unless $InsideTransaction;
713 return ( $val, $self->loc('Right revoked') );
716 $RT::Handle->Rollback() unless $InsideTransaction;
717 return ( 0, $self->loc('Right could not be revoked') );
722 # {{{ sub _BootstrapCreate
724 =head2 _BootstrapCreate
726 Grant a right with no error checking and no ACL. this is _only_ for
727 installation. If you use this routine without the author's explicit
728 written approval, he will hunt you down and make you spend eternity
729 translating mozilla's code into FORTRAN or intercal.
731 If you think you need this routine, you've mistaken.
735 sub _BootstrapCreate {
739 # When bootstrapping, make sure we get the _right_ users
740 if ( $args{'UserId'} ) {
741 my $user = RT::User->new( $self->CurrentUser );
742 $user->Load( $args{'UserId'} );
743 delete $args{'UserId'};
744 $args{'PrincipalId'} = $user->PrincipalId;
745 $args{'PrincipalType'} = 'User';
748 my $id = $self->SUPER::Create(%args);
754 $RT::Logger->err('System error. right not granted.');
762 # {{{ sub CanonicalizeRightName
764 =head2 CanonicalizeRightName <RIGHT>
766 Takes a queue or system right name in any case and returns it in
767 the correct case. If it's not found, will return undef.
771 sub CanonicalizeRightName {
775 if ( exists $LOWERCASERIGHTNAMES{"$right"} ) {
776 return ( $LOWERCASERIGHTNAMES{"$right"} );
790 If the object this ACE applies to is a queue, returns the queue object.
791 If the object this ACE applies to is a group, returns the group object.
792 If it's the system object, returns undef.
794 If the user has no rights, returns undef.
806 if ($self->__Value('ObjectType') && $OBJECT_TYPES{$self->__Value('ObjectType')} ) {
807 $appliesto_obj = $self->__Value('ObjectType')->new($self->CurrentUser);
808 unless (ref( $appliesto_obj) eq $self->__Value('ObjectType')) {
811 $appliesto_obj->Load( $self->__Value('ObjectId') );
812 return ($appliesto_obj);
815 $RT::Logger->warning( "$self -> Object called for an object "
816 . "of an unknown type:"
817 . $self->__Value('ObjectType') );
824 # {{{ sub PrincipalObj
828 Returns the RT::Principal object for this ACE.
835 my $princ_obj = RT::Principal->new( $self->CurrentUser );
836 $princ_obj->Load( $self->__Value('PrincipalId') );
838 unless ( $princ_obj->Id ) {
840 "ACE " . $self->Id . " couldn't load its principal object" );
848 # {{{ ACL related methods
854 return ( 0, $self->loc("ACEs can only be created and deleted.") );
864 if ( $self->__Value('DelegatedBy') eq $self->CurrentUser->PrincipalId ) {
865 return ( $self->__Value(@_) );
867 elsif ( $self->PrincipalObj->IsGroup
868 && $self->PrincipalObj->Object->HasMemberRecursively(
869 $self->CurrentUser->PrincipalObj
872 return ( $self->__Value(@_) );
874 elsif ( $self->CurrentUser->HasRight(Right => 'ShowACL', Object => $self->Object) ) {
875 return ( $self->__Value(@_) );
887 # {{{ _CanonicalizePrincipal
889 =head2 _CanonicalizePrincipal (PrincipalId, PrincipalType)
891 Takes a principal id and a principal type.
893 If the principal is a user, resolves it to the proper acl equivalence group.
894 Returns a tuple of (RT::Principal, PrincipalType) for the principal we really want to work with
898 sub _CanonicalizePrincipal {
900 my $princ_id = shift;
901 my $princ_type = shift;
903 my $princ_obj = RT::Principal->new($RT::SystemUser);
904 $princ_obj->Load($princ_id);
906 unless ( $princ_obj->Id ) {
908 $RT::Logger->crit(Carp::cluck);
909 $RT::Logger->crit("Can't load a principal for id $princ_id");
910 return ( $princ_obj, undef );
913 # Rights never get granted to users. they get granted to their
914 # ACL equivalence groups
915 if ( $princ_type eq 'User' ) {
916 my $equiv_group = RT::Group->new( $self->CurrentUser );
917 $equiv_group->LoadACLEquivalenceGroup($princ_obj);
918 unless ( $equiv_group->Id ) {
920 "No ACL equiv group for princ " . $self->__Value('ObjectId') );
921 return ( 0, $self->loc('System error. Right not granted.') );
923 $princ_obj = $equiv_group->PrincipalObj();
924 $princ_type = 'Group';
927 return ( $princ_obj, $princ_type );
930 sub _ParseObjectArg {
932 my %args = ( Object => undef,
937 if( $args{'Object'} && ($args{'ObjectId'} || $args{'ObjectType'}) ) {
938 $RT::Logger->crit( "Method called with an ObjectType or an ObjectId and Object args" );
940 } elsif( $args{'Object'} && !UNIVERSAL::can($args{'Object'},'id') ) {
941 $RT::Logger->crit( "Method called called Object that has no id method" );
943 } elsif( $args{'Object'} ) {
944 my $obj = $args{'Object'};
945 return ($obj, ref $obj, $obj->id);
946 } elsif ( $args{'ObjectType'} ) {
947 my $obj = $args{'ObjectType'}->new( $self->CurrentUser );
948 $obj->Load( $args{'ObjectId'} );
949 return ($obj, ref $obj, $obj->id);
951 $RT::Logger->crit( "Method called with wrong args" );