3 # Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
5 # (Except where explictly superceded by other copyright notices)
7 # This work is made available to you under the terms of Version 2 of
8 # the GNU General Public License. A copy of that license should have
9 # been provided with this software, but in any event can be snarfed
12 # This work is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # General Public License for more details.
17 # Unless otherwise specified, all modifications, corrections or
18 # extensions to this work which alter its source code become the
19 # property of Best Practical Solutions, LLC when submitted for
20 # inclusion in the work.
27 my $ace = new RT::ACE($CurrentUser);
45 no warnings qw(redefine);
53 %TICKET_METAPRINCIPALS
57 # {{{ Descriptions of rights
61 # Queue rights are the sort of queue rights that can only be granted
62 # to real people or groups
67 my $Queue = RT::Queue->new($RT::SystemUser);
69 is ($Queue->AvailableRights->{'DeleteTicket'} , 'Delete tickets', "Found the delete ticket right");
70 is ($RT::System->AvailableRights->{'SuperUser'}, 'Do anything and everything', "Found the superuser right");
82 # {{{ Descriptions of principals
84 %TICKET_METAPRINCIPALS = (
85 Owner => 'The owner of a ticket', # loc_pair
86 Requestor => 'The requestor of a ticket', # loc_pair
87 Cc => 'The CC of a ticket', # loc_pair
88 AdminCc => 'The administrative CC of a ticket', # loc_pair
94 # {{{ sub LoadByValues
96 =head2 LoadByValues PARAMHASH
98 Load an ACE by specifying a paramhash with the following fields:
100 PrincipalId => undef,
101 PrincipalType => undef,
117 my %args = ( PrincipalId => undef,
118 PrincipalType => undef,
126 ( $princ_obj, $args{'PrincipalType'} ) =
127 $self->_CanonicalizePrincipal( $args{'PrincipalId'},
128 $args{'PrincipalType'} );
130 unless ( $princ_obj->id ) {
132 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
136 my ($object_type, $object_id);
138 if ($args{'Object'} && UNIVERSAL::can($args{'Object'},'id')) {
139 $object_type = ref($args{'Object'});
140 $object_id = $args{'Object'}->id;
141 } elsif ($args{'ObjectId'} || $args{'ObjectType'}) {
142 $object_type = $args{'ObjectType'};
143 $object_id = $args{'ObjectId'};
145 return ( 0, $self->loc("System error. Right not granted.") );
148 $self->LoadByCols( PrincipalId => $princ_obj->Id,
149 PrincipalType => $args{'PrincipalType'},
150 RightName => $args{'RightName'},
151 ObjectType => $object_type,
152 ObjectId => $object_id);
154 #If we couldn't load it.
155 unless ( $self->Id ) {
156 return ( 0, $self->loc("ACE not found") );
160 return ( $self->Id, $self->loc("Right Loaded") );
168 =head2 Create <PARAMS>
170 PARAMS is a parameter hash with the following elements:
172 PrincipalId => The id of an RT::Principal object
173 PrincipalType => "User" "Group" or any Role type
174 RightName => the name of a right. in any case
175 DelegatedBy => The Principal->Id of the user delegating the right
176 DelegatedFrom => The id of the ACE which this new ACE is delegated from
181 Object => An object to create rights for. ususally, an RT::Queue or RT::Group
182 This should always be a DBIx::SearchBuilder::Record subclass
186 ObjectType => the type of the object in question (ref ($object))
187 ObjectId => the id of the object in question $object->Id
193 my %args = ( PrincipalId => undef,
194 PrincipalType => undef,
196 Object => $RT::System,
199 # {{{ Validate the principal
201 ( $princ_obj, $args{'PrincipalType'} ) =
202 $self->_CanonicalizePrincipal( $args{'PrincipalId'},
203 $args{'PrincipalType'} );
205 unless ( $princ_obj->id ) {
207 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
214 if ($args{'Object'} && ($args{'ObjectId'} || $args{'ObjectType'})) {
216 $RT::Logger->crit(Carp::cluck("ACE::Create called with an ObjectType or an ObjectId"));
221 unless ($args{'Object'} && UNIVERSAL::can($args{'Object'},'id')) {
222 return ( 0, $self->loc("System error. Right not granted.") );
226 if (ref( $args{'Object'}) eq 'RT::Group' ) {
227 unless ( $self->CurrentUser->HasRight( Object => $args{'Object'},
228 Right => 'AdminGroup' )
230 return ( 0, $self->loc('Permission Denied') );
235 unless ( $self->CurrentUser->HasRight( Object => $args{'Object'}, Right => 'ModifyACL' )) {
236 return ( 0, $self->loc('Permission Denied') );
241 # {{{ Canonicalize and check the right name
242 unless ( $args{'RightName'} ) {
243 return ( 0, $self->loc('Invalid right') );
246 $args{'RightName'} = $self->CanonicalizeRightName( $args{'RightName'} );
248 #check if it's a valid RightName
249 if ( ref ($args{'Object'} eq 'RT::Queue' )) {
250 unless ( exists $args{'Object'}->AvailableRights->{ $args{'RightName'} } ) {
251 $RT::Logger->warning("Couldn't validate right name". $args{'RightName'});
252 return ( 0, $self->loc('Invalid right') );
255 elsif ( ref ($args{'Object'} eq 'RT::Group' )) {
256 unless ( exists $args{'Object'}->AvailableRights->{ $args{'RightName'} } ) {
257 $RT::Logger->warning("Couldn't validate group right name". $args{'RightName'});
258 return ( 0, $self->loc('Invalid right') );
261 elsif ( ref ($args{'Object'} eq 'RT::System' )) {
262 my $q = RT::Queue->new($self->CurrentUser);
263 my $g = RT::Group->new($self->CurrentUser);
265 unless (( exists $g->AvailableRights->{ $args{'RightName'} } )
266 || ( exists $g->AvailableRights->{ $args{'RightName'} } )
267 || ( exists $RT::System->AvailableRights->{ $args{'RightName'} } ) ) {
268 $RT::Logger->warning("Couldn't validate system right name - ". $args{'RightName'});
269 return ( 0, $self->loc('Invalid right') );
273 unless ( $args{'RightName'} ) {
274 return ( 0, $self->loc('Invalid right') );
278 # Make sure the right doesn't already exist.
279 $self->LoadByCols( PrincipalId => $princ_obj->id,
280 PrincipalType => $args{'PrincipalType'},
281 RightName => $args{'RightName'},
282 ObjectType => ref($args{'Object'}),
283 ObjectId => $args{'Object'}->id,
285 DelegatedFrom => 0 );
287 return ( 0, $self->loc('That principal already has that right') );
290 my $id = $self->SUPER::Create( PrincipalId => $princ_obj->id,
291 PrincipalType => $args{'PrincipalType'},
292 RightName => $args{'RightName'},
293 ObjectType => ref( $args{'Object'} ),
294 ObjectId => $args{'Object'}->id,
296 DelegatedFrom => 0 );
298 #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space.
299 RT::Principal->_InvalidateACLCache();
302 return ( $id, $self->loc('Right Granted') );
305 return ( 0, $self->loc('System error. Right not granted.') );
313 =head2 Delegate <PARAMS>
315 This routine delegates the current ACE to a principal specified by the
316 B<PrincipalId> parameter.
318 Returns an error if the current user doesn't have the right to be delegated
319 or doesn't have the right to delegate rights.
321 Always returns a tuple of (ReturnValue, Message)
326 my $user_a = RT::User->new($RT::SystemUser);
327 $user_a->Create( Name => 'DelegationA', Privileged => 1);
328 ok ($user_a->Id, "Created delegation user a");
330 my $user_b = RT::User->new($RT::SystemUser);
331 $user_b->Create( Name => 'DelegationB', Privileged => 1);
332 ok ($user_b->Id, "Created delegation user b");
336 my $q = RT::Queue->new($RT::SystemUser);
337 $q->Create(Name =>'DelegationTest');
338 ok ($q->Id, "Created a delegation test queue");
341 #------ First, we test whether a user can delegate a right that's been granted to him personally
342 my ($val, $msg) = $user_a->PrincipalObj->GrantRight(Object => $RT::System, Right => 'AdminOwnPersonalGroups');
345 ($val, $msg) = $user_a->PrincipalObj->GrantRight(Object =>$q, Right => 'OwnTicket');
348 ok($user_a->HasRight( Object => $RT::System, Right => 'AdminOwnPersonalGroups') ,"user a has the right 'AdminOwnPersonalGroups' directly");
350 my $a_delegates = RT::Group->new($user_a);
351 $a_delegates->CreatePersonalGroup(Name => 'Delegates');
352 ok( $a_delegates->Id ,"user a creates a personal group 'Delegates'");
353 ok( $a_delegates->AddMember($user_b->PrincipalId) ,"user a adds user b to personal group 'delegates'");
355 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to OwnTicket' in queue 'DelegationTest'");
356 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a has the right to 'OwnTicket' in queue 'DelegationTest'");
357 ok(!$user_a->HasRight( Object => $RT::System, Right => 'DelegateRights') ,"user a does not have the right 'delegate rights'");
360 my $own_ticket_ace = RT::ACE->new($user_a);
361 my $user_a_equiv_group = RT::Group->new($user_a);
362 $user_a_equiv_group->LoadACLEquivalenceGroup($user_a->PrincipalObj);
363 ok ($user_a_equiv_group->Id, "Loaded the user A acl equivalence group");
364 my $user_b_equiv_group = RT::Group->new($user_b);
365 $user_b_equiv_group->LoadACLEquivalenceGroup($user_b->PrincipalObj);
366 ok ($user_b_equiv_group->Id, "Loaded the user B acl equivalence group");
367 $own_ticket_ace->LoadByValues( PrincipalType => 'Group', PrincipalId => $user_a_equiv_group->PrincipalId, Object=>$q, RightName => 'OwnTicket');
369 ok ($own_ticket_ace->Id, "Found the ACE we want to test with for now");
372 ($val, $msg) = $own_ticket_ace->Delegate(PrincipalId => $a_delegates->PrincipalId) ;
373 ok( !$val ,"user a tries and fails to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
376 ($val, $msg) = $user_a->PrincipalObj->GrantRight( Right => 'DelegateRights');
377 ok($val, "user a is granted the right to 'delegate rights' - $msg");
379 ok($user_a->HasRight( Object => $RT::System, Right => 'DelegateRights') ,"user a has the right 'AdminOwnPersonalGroups' directly");
381 ($val, $msg) = $own_ticket_ace->Delegate(PrincipalId => $a_delegates->PrincipalId) ;
383 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
384 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
385 my $delegated_ace = RT::ACE->new($user_a);
386 $delegated_ace->LoadByValues ( Object => $q, RightName => 'OwnTicket', PrincipalType => 'Group',
387 PrincipalId => $a_delegates->PrincipalId, DelegatedBy => $user_a->PrincipalId, DelegatedFrom => $own_ticket_ace->Id);
388 ok ($delegated_ace->Id, "Found the delegated ACE");
390 ok( $a_delegates->DeleteMember($user_b->PrincipalId) ,"user a removes b from pg 'delegates'");
391 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
392 ok( $a_delegates->AddMember($user_b->PrincipalId) ,"user a adds user b to personal group 'delegates'");
393 ok( $user_b->HasRight(Right => 'OwnTicket', Object=> $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
394 ok( $delegated_ace->Delete ,"user a revokes pg 'delegates' right to 'OwnTickets' in queue 'DelegationTest'");
395 ok( ! $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
397 ($val, $msg) = $own_ticket_ace->Delegate(PrincipalId => $a_delegates->PrincipalId) ;
398 ok( $val ,"user a delegates pg 'delegates' right to 'OwnTickets' in queue 'DelegationTest' - $msg");
400 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest'");
402 ($val, $msg) = $user_a->PrincipalObj->RevokeRight(Object=>$q, Right => 'OwnTicket');
403 ok($val, "Revoked user a's right to own tickets in queue 'DelegationTest". $msg);
405 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest'");
407 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
409 ($val, $msg) = $user_a->PrincipalObj->GrantRight(Object=>$q, Right => 'OwnTicket');
412 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a has the right to own tickets 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 # {{{ get back to a known clean state
417 ($val, $msg) = $user_a->PrincipalObj->RevokeRight( Object => $q, Right => 'OwnTicket');
418 ok($val, "Revoked user a's right to own tickets in queue 'DelegationTest -". $msg);
419 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"make sure that user a can't own tickets in queue 'DelegationTest'");
423 # {{{ Set up some groups and membership
424 my $del1 = RT::Group->new($RT::SystemUser);
425 ($val, $msg) = $del1->CreateUserDefinedGroup(Name => 'Del1');
426 ok( $val ,"create a group del1 - $msg");
428 my $del2 = RT::Group->new($RT::SystemUser);
429 ($val, $msg) = $del2->CreateUserDefinedGroup(Name => 'Del2');
430 ok( $val ,"create a group del2 - $msg");
431 ($val, $msg) = $del1->AddMember($del2->PrincipalId);
432 ok( $val,"make del2 a member of del1 - $msg");
434 my $del2a = RT::Group->new($RT::SystemUser);
435 ($val, $msg) = $del2a->CreateUserDefinedGroup(Name => 'Del2a');
436 ok( $val ,"create a group del2a - $msg");
437 ($val, $msg) = $del2->AddMember($del2a->PrincipalId);
438 ok($val ,"make del2a a member of del2 - $msg");
440 my $del2b = RT::Group->new($RT::SystemUser);
441 ($val, $msg) = $del2b->CreateUserDefinedGroup(Name => 'Del2b');
442 ok( $val ,"create a group del2b - $msg");
443 ($val, $msg) = $del2->AddMember($del2b->PrincipalId);
444 ok($val ,"make del2b a member of del2 - $msg");
446 ($val, $msg) = $del2->AddMember($user_a->PrincipalId) ;
447 ok($val,"make 'user a' a member of del2 - $msg");
449 ($val, $msg) = $del2b->AddMember($user_a->PrincipalId) ;
450 ok($val,"make 'user a' a member of del2b - $msg");
454 # {{{ Grant a right to a group and make sure that a submember can delegate the right and that it does not get yanked
455 # when a user is removed as a submember, when they're a sumember through another path
456 ($val, $msg) = $del1->PrincipalObj->GrantRight( Object=> $q, Right => 'OwnTicket');
457 ok( $val ,"grant del1 the right to 'OwnTicket' in queue 'DelegationTest' - $msg");
459 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"make sure that user a can own tickets in queue 'DelegationTest'");
461 my $group_ace= RT::ACE->new($user_a);
462 $group_ace->LoadByValues( PrincipalType => 'Group', PrincipalId => $del1->PrincipalId, Object => $q, RightName => 'OwnTicket');
464 ok ($group_ace->Id, "Found the ACE we want to test with for now");
466 ($val, $msg) = $group_ace->Delegate(PrincipalId => $a_delegates->PrincipalId);
468 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
469 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
472 ($val, $msg) = $del2b->DeleteMember($user_a->PrincipalId);
473 ok( $val ,"remove user a from group del2b - $msg");
474 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a has the right to own tickets in queue 'DelegationTest'");
475 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
479 # {{{ When a user is removed froom a group by the only path they're in there by, make sure the delegations go away
480 ($val, $msg) = $del2->DeleteMember($user_a->PrincipalId);
481 ok( $val ,"remove user a from group del2 - $msg");
482 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest' ");
483 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest' ");
486 ($val, $msg) = $del2->AddMember($user_a->PrincipalId);
487 ok( $val ,"make user a a member of group del2 - $msg");
489 ($val, $msg) = $del2->PrincipalObj->GrantRight(Object=>$q, Right => 'OwnTicket');
490 ok($val, "grant the right 'own tickets' in queue 'DelegationTest' to group del2 - $msg");
492 my $del2_right = RT::ACE->new($user_a);
493 $del2_right->LoadByValues( PrincipalId => $del2->PrincipalId, PrincipalType => 'Group', Object => $q, RightName => 'OwnTicket');
494 ok ($del2_right->Id, "Found the right");
496 ($val, $msg) = $del2_right->Delegate(PrincipalId => $a_delegates->PrincipalId);
497 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' gotten via del2 to personal group 'delegates' - $msg");
499 # They have it via del1 and del2
500 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
503 ($val, $msg) = $del2->PrincipalObj->RevokeRight(Object=>$q, Right => 'OwnTicket');
504 ok($val, "revoke the right 'own tickets' in queue 'DelegationTest' to group del2 - $msg");
505 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does has the right to own tickets in queue 'DelegationTest' via del1");
506 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->PrincipalObj->GrantRight(Object=>$q, Right => 'OwnTicket');
509 ok($val, "grant the right 'own tickets' in queue 'DelegationTest' to group del2 - $msg");
512 $group_ace= RT::ACE->new($user_a);
513 $group_ace->LoadByValues( PrincipalType => 'Group', PrincipalId => $del1->PrincipalId, Object=>$q, RightName => 'OwnTicket');
515 ok ($group_ace->Id, "Found the ACE we want to test with for now");
517 ($val, $msg) = $group_ace->Delegate(PrincipalId => $a_delegates->PrincipalId);
519 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
521 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
523 ($val, $msg) = $del2->DeleteMember($user_a->PrincipalId);
524 ok( $val ,"remove user a from group del2 - $msg");
526 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest'");
528 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
538 my %args = ( PrincipalId => undef,
541 unless ( $self->Id ) {
542 return ( 0, $self->loc("Right not loaded.") );
545 ( $princ_obj, $args{'PrincipalType'} ) =
546 $self->_CanonicalizePrincipal( $args{'PrincipalId'},
547 $args{'PrincipalType'} );
549 unless ( $princ_obj->id ) {
551 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
559 # First, we check to se if the user is delegating rights and
560 # they have the permission to
561 unless ( $self->CurrentUser->HasRight(Right => 'DelegateRights', Object => $self->Object) ) {
562 return ( 0, $self->loc("Permission Denied") );
565 unless ( $self->PrincipalObj->IsGroup ) {
566 return ( 0, $self->loc("System Error") );
568 unless ( $self->PrincipalObj->Object->HasMemberRecursively(
569 $self->CurrentUser->PrincipalObj
572 return ( 0, $self->loc("Permission Denied") );
577 my $concurrency_check = RT::ACE->new($RT::SystemUser);
578 $concurrency_check->Load( $self->Id );
579 unless ( $concurrency_check->Id ) {
581 "Trying to delegate a right which had already been deleted");
582 return ( 0, $self->loc('Permission Denied') );
585 my $delegated_ace = RT::ACE->new( $self->CurrentUser );
587 # Make sure the right doesn't already exist.
588 $delegated_ace->LoadByCols( PrincipalId => $princ_obj->Id,
589 PrincipalType => 'Group',
590 RightName => $self->__Value('RightName'),
591 ObjectType => $self->__Value('ObjectType'),
592 ObjectId => $self->__Value('ObjectId'),
593 DelegatedBy => $self->CurrentUser->PrincipalId,
594 DelegatedFrom => $self->id );
595 if ( $delegated_ace->Id ) {
596 return ( 0, $self->loc('That principal already has that right') );
598 my $id = $delegated_ace->SUPER::Create(
599 PrincipalId => $princ_obj->Id,
600 PrincipalType => 'Group', # do we want to hardcode this?
601 RightName => $self->__Value('RightName'),
602 ObjectType => $self->__Value('ObjectType'),
603 ObjectId => $self->__Value('ObjectId'),
604 DelegatedBy => $self->CurrentUser->PrincipalId,
605 DelegatedFrom => $self->id );
607 #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space.
608 # TODO what about the groups key cache?
609 RT::Principal->_InvalidateACLCache();
612 return ( $id, $self->loc('Right Delegated') );
615 return ( 0, $self->loc('System error. Right not delegated.') );
623 =head2 Delete { InsideTransaction => undef}
625 Delete this object. This method should ONLY ever be called from RT::User or RT::Group (or from itself)
626 If this is being called from within a transaction, specify a true value for the parameter InsideTransaction.
627 Really, DBIx::SearchBuilder should use and/or fake subtransactions
629 This routine will also recurse and delete any delegations of this right
636 unless ( $self->Id ) {
637 return ( 0, $self->loc('Right not loaded.') );
640 # A user can delete an ACE if the current user has the right to modify it and it's not a delegated ACE
641 # or if it's a delegated ACE and it was delegated by the current user
643 ( $self->CurrentUser->HasRight(Right => 'ModifyACL', Object => $self->Object)
644 && $self->__Value('DelegatedBy') == 0 )
645 || ( $self->__Value('DelegatedBy') == $self->CurrentUser->PrincipalId )
647 return ( 0, $self->loc('Permission Denied') );
652 # Helper for Delete with no ACL check
655 my %args = ( InsideTransaction => undef,
658 my $InsideTransaction = $args{'InsideTransaction'};
660 $RT::Handle->BeginTransaction() unless $InsideTransaction;
662 my $delegated_from_this = RT::ACL->new($RT::SystemUser);
663 $delegated_from_this->Limit( FIELD => 'DelegatedFrom',
665 VALUE => $self->Id );
667 my $delete_succeeded = 1;
669 while ( my $delegated_ace = $delegated_from_this->Next ) {
670 ( $delete_succeeded, $submsg ) =
671 $delegated_ace->_Delete( InsideTransaction => 1 );
672 last if ($delete_succeeded);
675 unless ($delete_succeeded) {
676 $RT::Handle->Rollback() unless $InsideTransaction;
677 return ( 0, $self->loc('Right could not be revoked') );
680 my ( $val, $msg ) = $self->SUPER::Delete(@_);
682 #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space.
683 # TODO what about the groups key cache?
684 RT::Principal->_InvalidateACLCache();
687 $RT::Handle->Commit() unless $InsideTransaction;
688 return ( $val, $self->loc('Right revoked') );
691 $RT::Handle->Rollback() unless $InsideTransaction;
692 return ( 0, $self->loc('Right could not be revoked') );
698 # {{{ sub _BootstrapCreate
700 =head2 _BootstrapCreate
702 Grant a right with no error checking and no ACL. this is _only_ for
703 installation. If you use this routine without the author's explicit
704 written approval, he will hunt you down and make you spend eternity
705 translating mozilla's code into FORTRAN or intercal.
707 If you think you need this routine, you've mistaken.
711 sub _BootstrapCreate {
715 # When bootstrapping, make sure we get the _right_ users
716 if ( $args{'UserId'} ) {
717 my $user = RT::User->new( $self->CurrentUser );
718 $user->Load( $args{'UserId'} );
719 delete $args{'UserId'};
720 $args{'PrincipalId'} = $user->PrincipalId;
721 $args{'PrincipalType'} = 'User';
724 my $id = $self->SUPER::Create(%args);
730 $RT::Logger->err('System error. right not granted.');
738 # {{{ sub CanonicalizeRightName
740 =head2 CanonicalizeRightName <RIGHT>
742 Takes a queue or system right name in any case and returns it in
743 the correct case. If it's not found, will return undef.
747 sub CanonicalizeRightName {
751 if ( exists $LOWERCASERIGHTNAMES{"$right"} ) {
752 return ( $LOWERCASERIGHTNAMES{"$right"} );
766 If the object this ACE applies to is a queue, returns the queue object.
767 If the object this ACE applies to is a group, returns the group object.
768 If it's the system object, returns undef.
770 If the user has no rights, returns undef.
782 if ($self->__Value('ObjectType') && $OBJECT_TYPES{$self->__Value('ObjectType')} ) {
783 $appliesto_obj = $self->__Value('ObjectType')->new($self->CurrentUser);
784 unless (ref( $appliesto_obj) eq $self->__Value('ObjectType')) {
787 $appliesto_obj->Load( $self->__Value('ObjectId') );
788 return ($appliesto_obj);
791 $RT::Logger->warning( "$self -> Object called for an object "
792 . "of an unknown type:"
793 . $self->ObjectType );
800 # {{{ sub PrincipalObj
804 Returns the RT::Principal object for this ACE.
811 my $princ_obj = RT::Principal->new( $self->CurrentUser );
812 $princ_obj->Load( $self->__Value('PrincipalId') );
814 unless ( $princ_obj->Id ) {
816 "ACE " . $self->Id . " couldn't load its principal object" );
824 # {{{ ACL related methods
830 return ( 0, $self->loc("ACEs can only be created and deleted.") );
840 if ( $self->__Value('DelegatedBy') eq $self->CurrentUser->PrincipalId ) {
841 return ( $self->__Value(@_) );
843 elsif ( $self->PrincipalObj->IsGroup
844 && $self->PrincipalObj->Object->HasMemberRecursively(
845 $self->CurrentUser->PrincipalObj
848 return ( $self->__Value(@_) );
850 elsif ( $self->CurrentUser->HasRight(Right => 'ShowACL', Object => $self->Object) ) {
851 return ( $self->__Value(@_) );
863 # {{{ _CanonicalizePrincipal
865 =head2 _CanonicalizePrincipal (PrincipalId, PrincipalType)
867 Takes a principal id and a principal type.
869 If the principal is a user, resolves it to the proper acl equivalence group.
870 Returns a tuple of (RT::Principal, PrincipalType) for the principal we really want to work with
874 sub _CanonicalizePrincipal {
876 my $princ_id = shift;
877 my $princ_type = shift;
879 my $princ_obj = RT::Principal->new($RT::SystemUser);
880 $princ_obj->Load($princ_id);
882 unless ( $princ_obj->Id ) {
884 $RT::Logger->crit(Carp::cluck);
885 $RT::Logger->crit("Can't load a principal for id $princ_id");
886 return ( $princ_obj, undef );
889 # Rights never get granted to users. they get granted to their
890 # ACL equivalence groups
891 if ( $princ_type eq 'User' ) {
892 my $equiv_group = RT::Group->new( $self->CurrentUser );
893 $equiv_group->LoadACLEquivalenceGroup($princ_obj);
894 unless ( $equiv_group->Id ) {
896 "No ACL equiv group for princ " . $self->__Value('ObjectId') );
897 return ( 0, $self->loc('System error. Right not granted.') );
899 $princ_obj = $equiv_group->PrincipalObj();
900 $princ_type = 'Group';
903 return ( $princ_obj, $princ_type );