1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA
26 # 02110-1301 or visit their web page on the internet at
27 # http://www.gnu.org/copyleft/gpl.html.
30 # CONTRIBUTION SUBMISSION POLICY:
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.)
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.
47 # END BPS TAGGED BLOCK }}}
51 my $ace = new RT::ACE($CurrentUser);
72 no warnings qw(redefine);
80 %TICKET_METAPRINCIPALS
84 # {{{ Descriptions of rights
88 # Queue rights are the sort of queue rights that can only be granted
89 # to real people or groups
94 my $Queue = RT::Queue->new($RT::SystemUser);
96 is ($Queue->AvailableRights->{'DeleteTicket'} , 'Delete tickets', "Found the delete ticket right");
97 is ($RT::System->AvailableRights->{'SuperUser'}, 'Do anything and everything', "Found the superuser right");
109 # {{{ Descriptions of principals
111 %TICKET_METAPRINCIPALS = (
112 Owner => 'The owner of a ticket', # loc_pair
113 Requestor => 'The requestor of a ticket', # loc_pair
114 Cc => 'The CC of a ticket', # loc_pair
115 AdminCc => 'The administrative CC of a ticket', # loc_pair
121 # {{{ sub LoadByValues
123 =head2 LoadByValues PARAMHASH
125 Load an ACE by specifying a paramhash with the following fields:
127 PrincipalId => undef,
128 PrincipalType => undef,
144 my %args = ( PrincipalId => undef,
145 PrincipalType => undef,
153 ( $princ_obj, $args{'PrincipalType'} ) =
154 $self->_CanonicalizePrincipal( $args{'PrincipalId'},
155 $args{'PrincipalType'} );
157 unless ( $princ_obj->id ) {
159 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
163 my ($object, $object_type, $object_id) = $self->_ParseObjectArg( %args );
165 return ( 0, $self->loc("System error. Right not granted.") );
168 $self->LoadByCols( PrincipalId => $princ_obj->Id,
169 PrincipalType => $args{'PrincipalType'},
170 RightName => $args{'RightName'},
171 ObjectType => $object_type,
172 ObjectId => $object_id);
174 #If we couldn't load it.
175 unless ( $self->Id ) {
176 return ( 0, $self->loc("ACE not found") );
180 return ( $self->Id, $self->loc("Right Loaded") );
188 =head2 Create <PARAMS>
190 PARAMS is a parameter hash with the following elements:
192 PrincipalId => The id of an RT::Principal object
193 PrincipalType => "User" "Group" or any Role type
194 RightName => the name of a right. in any case
195 DelegatedBy => The Principal->Id of the user delegating the right
196 DelegatedFrom => The id of the ACE which this new ACE is delegated from
201 Object => An object to create rights for. ususally, an RT::Queue or RT::Group
202 This should always be a DBIx::SearchBuilder::Record subclass
206 ObjectType => the type of the object in question (ref ($object))
207 ObjectId => the id of the object in question $object->Id
211 Returns a tuple of (STATUS, MESSAGE); If the call succeeded, STATUS is true. Otherwise it's false.
219 my %args = ( PrincipalId => undef,
220 PrincipalType => undef,
224 #if we haven't specified any sort of right, we're talking about a global right
225 if (!defined $args{'Object'} && !defined $args{'ObjectId'} && !defined $args{'ObjectType'}) {
226 $args{'Object'} = $RT::System;
228 ($args{'Object'}, $args{'ObjectType'}, $args{'ObjectId'}) = $self->_ParseObjectArg( %args );
229 unless( $args{'Object'} ) {
230 return ( 0, $self->loc("System error. Right not granted.") );
233 # {{{ Validate the principal
235 ( $princ_obj, $args{'PrincipalType'} ) =
236 $self->_CanonicalizePrincipal( $args{'PrincipalId'},
237 $args{'PrincipalType'} );
239 unless ( $princ_obj->id ) {
241 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
249 if (ref( $args{'Object'}) eq 'RT::Group' ) {
250 unless ( $self->CurrentUser->HasRight( Object => $args{'Object'},
251 Right => 'AdminGroup' )
253 return ( 0, $self->loc('Permission Denied') );
258 unless ( $self->CurrentUser->HasRight( Object => $args{'Object'}, Right => 'ModifyACL' )) {
259 return ( 0, $self->loc('Permission Denied') );
264 # {{{ Canonicalize and check the right name
265 unless ( $args{'RightName'} ) {
266 return ( 0, $self->loc('Invalid right') );
269 $args{'RightName'} = $self->CanonicalizeRightName( $args{'RightName'} );
271 #check if it's a valid RightName
272 if ( ref ($args{'Object'} eq 'RT::Queue' )) {
273 unless ( exists $args{'Object'}->AvailableRights->{ $args{'RightName'} } ) {
274 $RT::Logger->warning("Couldn't validate right name". $args{'RightName'});
275 return ( 0, $self->loc('Invalid right') );
278 elsif ( ref ($args{'Object'} eq 'RT::Group' )) {
279 unless ( exists $args{'Object'}->AvailableRights->{ $args{'RightName'} } ) {
280 $RT::Logger->warning("Couldn't validate group right name". $args{'RightName'});
281 return ( 0, $self->loc('Invalid right') );
284 elsif ( ref ($args{'Object'} eq 'RT::System' )) {
285 my $q = RT::Queue->new($self->CurrentUser);
286 my $g = RT::Group->new($self->CurrentUser);
288 unless (( exists $g->AvailableRights->{ $args{'RightName'} } )
289 || ( exists $g->AvailableRights->{ $args{'RightName'} } )
290 || ( exists $RT::System->AvailableRights->{ $args{'RightName'} } ) ) {
291 $RT::Logger->warning("Couldn't validate system right name - ". $args{'RightName'});
292 return ( 0, $self->loc('Invalid right') );
298 # Make sure the right doesn't already exist.
299 $self->LoadByCols( PrincipalId => $princ_obj->id,
300 PrincipalType => $args{'PrincipalType'},
301 RightName => $args{'RightName'},
302 ObjectType => $args{'ObjectType'},
303 ObjectId => $args{'ObjectId'},
305 DelegatedFrom => 0 );
307 return ( 0, $self->loc('That principal already has that right') );
310 my $id = $self->SUPER::Create( PrincipalId => $princ_obj->id,
311 PrincipalType => $args{'PrincipalType'},
312 RightName => $args{'RightName'},
313 ObjectType => ref( $args{'Object'} ),
314 ObjectId => $args{'Object'}->id,
316 DelegatedFrom => 0 );
318 #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space.
319 RT::Principal->InvalidateACLCache();
322 return ( $id, $self->loc('Right Granted') );
325 return ( 0, $self->loc('System error. Right not granted.') );
333 =head2 Delegate <PARAMS>
335 This routine delegates the current ACE to a principal specified by the
336 B<PrincipalId> parameter.
338 Returns an error if the current user doesn't have the right to be delegated
339 or doesn't have the right to delegate rights.
341 Always returns a tuple of (ReturnValue, Message)
346 my $user_a = RT::User->new($RT::SystemUser);
347 $user_a->Create( Name => 'DelegationA', Privileged => 1);
348 ok ($user_a->Id, "Created delegation user a");
350 my $user_b = RT::User->new($RT::SystemUser);
351 $user_b->Create( Name => 'DelegationB', Privileged => 1);
352 ok ($user_b->Id, "Created delegation user b");
356 my $q = RT::Queue->new($RT::SystemUser);
357 $q->Create(Name =>'DelegationTest');
358 ok ($q->Id, "Created a delegation test queue");
361 #------ First, we test whether a user can delegate a right that's been granted to him personally
362 my ($val, $msg) = $user_a->PrincipalObj->GrantRight(Object => $RT::System, Right => 'AdminOwnPersonalGroups');
365 ($val, $msg) = $user_a->PrincipalObj->GrantRight(Object =>$q, Right => 'OwnTicket');
368 ok($user_a->HasRight( Object => $RT::System, Right => 'AdminOwnPersonalGroups') ,"user a has the right 'AdminOwnPersonalGroups' directly");
370 my $a_delegates = RT::Group->new($user_a);
371 $a_delegates->CreatePersonalGroup(Name => 'Delegates');
372 ok( $a_delegates->Id ,"user a creates a personal group 'Delegates'");
373 ok( $a_delegates->AddMember($user_b->PrincipalId) ,"user a adds user b to personal group 'delegates'");
375 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to OwnTicket' in queue 'DelegationTest'");
376 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a has the right to 'OwnTicket' in queue 'DelegationTest'");
377 ok(!$user_a->HasRight( Object => $RT::System, Right => 'DelegateRights') ,"user a does not have the right 'delegate rights'");
380 my $own_ticket_ace = RT::ACE->new($user_a);
381 my $user_a_equiv_group = RT::Group->new($user_a);
382 $user_a_equiv_group->LoadACLEquivalenceGroup($user_a->PrincipalObj);
383 ok ($user_a_equiv_group->Id, "Loaded the user A acl equivalence group");
384 my $user_b_equiv_group = RT::Group->new($user_b);
385 $user_b_equiv_group->LoadACLEquivalenceGroup($user_b->PrincipalObj);
386 ok ($user_b_equiv_group->Id, "Loaded the user B acl equivalence group");
387 $own_ticket_ace->LoadByValues( PrincipalType => 'Group', PrincipalId => $user_a_equiv_group->PrincipalId, Object=>$q, RightName => 'OwnTicket');
389 ok ($own_ticket_ace->Id, "Found the ACE we want to test with for now");
392 ($val, $msg) = $own_ticket_ace->Delegate(PrincipalId => $a_delegates->PrincipalId) ;
393 ok( !$val ,"user a tries and fails to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
396 ($val, $msg) = $user_a->PrincipalObj->GrantRight( Right => 'DelegateRights');
397 ok($val, "user a is granted the right to 'delegate rights' - $msg");
399 ok($user_a->HasRight( Object => $RT::System, Right => 'DelegateRights') ,"user a has the right 'AdminOwnPersonalGroups' directly");
401 ($val, $msg) = $own_ticket_ace->Delegate(PrincipalId => $a_delegates->PrincipalId) ;
403 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
404 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
405 my $delegated_ace = RT::ACE->new($user_a);
406 $delegated_ace->LoadByValues ( Object => $q, RightName => 'OwnTicket', PrincipalType => 'Group',
407 PrincipalId => $a_delegates->PrincipalId, DelegatedBy => $user_a->PrincipalId, DelegatedFrom => $own_ticket_ace->Id);
408 ok ($delegated_ace->Id, "Found the delegated ACE");
410 ok( $a_delegates->DeleteMember($user_b->PrincipalId) ,"user a removes b from pg 'delegates'");
411 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
412 ok( $a_delegates->AddMember($user_b->PrincipalId) ,"user a adds user b to personal group 'delegates'");
413 ok( $user_b->HasRight(Right => 'OwnTicket', Object=> $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
414 ok( $delegated_ace->Delete ,"user a revokes pg 'delegates' right to 'OwnTickets' in queue 'DelegationTest'");
415 ok( ! $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
417 ($val, $msg) = $own_ticket_ace->Delegate(PrincipalId => $a_delegates->PrincipalId) ;
418 ok( $val ,"user a delegates pg 'delegates' right to 'OwnTickets' in queue 'DelegationTest' - $msg");
420 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest'");
422 ($val, $msg) = $user_a->PrincipalObj->RevokeRight(Object=>$q, Right => 'OwnTicket');
423 ok($val, "Revoked user a's right to own tickets in queue 'DelegationTest". $msg);
425 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest'");
427 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
429 ($val, $msg) = $user_a->PrincipalObj->GrantRight(Object=>$q, Right => 'OwnTicket');
432 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a has the right to own tickets in queue 'DelegationTest'");
434 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
436 # {{{ get back to a known clean state
437 ($val, $msg) = $user_a->PrincipalObj->RevokeRight( Object => $q, Right => 'OwnTicket');
438 ok($val, "Revoked user a's right to own tickets in queue 'DelegationTest -". $msg);
439 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"make sure that user a can't own tickets in queue 'DelegationTest'");
443 # {{{ Set up some groups and membership
444 my $del1 = RT::Group->new($RT::SystemUser);
445 ($val, $msg) = $del1->CreateUserDefinedGroup(Name => 'Del1');
446 ok( $val ,"create a group del1 - $msg");
448 my $del2 = RT::Group->new($RT::SystemUser);
449 ($val, $msg) = $del2->CreateUserDefinedGroup(Name => 'Del2');
450 ok( $val ,"create a group del2 - $msg");
451 ($val, $msg) = $del1->AddMember($del2->PrincipalId);
452 ok( $val,"make del2 a member of del1 - $msg");
454 my $del2a = RT::Group->new($RT::SystemUser);
455 ($val, $msg) = $del2a->CreateUserDefinedGroup(Name => 'Del2a');
456 ok( $val ,"create a group del2a - $msg");
457 ($val, $msg) = $del2->AddMember($del2a->PrincipalId);
458 ok($val ,"make del2a a member of del2 - $msg");
460 my $del2b = RT::Group->new($RT::SystemUser);
461 ($val, $msg) = $del2b->CreateUserDefinedGroup(Name => 'Del2b');
462 ok( $val ,"create a group del2b - $msg");
463 ($val, $msg) = $del2->AddMember($del2b->PrincipalId);
464 ok($val ,"make del2b a member of del2 - $msg");
466 ($val, $msg) = $del2->AddMember($user_a->PrincipalId) ;
467 ok($val,"make 'user a' a member of del2 - $msg");
469 ($val, $msg) = $del2b->AddMember($user_a->PrincipalId) ;
470 ok($val,"make 'user a' a member of del2b - $msg");
474 # {{{ Grant a right to a group and make sure that a submember can delegate the right and that it does not get yanked
475 # when a user is removed as a submember, when they're a sumember through another path
476 ($val, $msg) = $del1->PrincipalObj->GrantRight( Object=> $q, Right => 'OwnTicket');
477 ok( $val ,"grant del1 the right to 'OwnTicket' in queue 'DelegationTest' - $msg");
479 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"make sure that user a can own tickets in queue 'DelegationTest'");
481 my $group_ace= RT::ACE->new($user_a);
482 $group_ace->LoadByValues( PrincipalType => 'Group', PrincipalId => $del1->PrincipalId, Object => $q, RightName => 'OwnTicket');
484 ok ($group_ace->Id, "Found the ACE we want to test with for now");
486 ($val, $msg) = $group_ace->Delegate(PrincipalId => $a_delegates->PrincipalId);
488 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
489 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
492 ($val, $msg) = $del2b->DeleteMember($user_a->PrincipalId);
493 ok( $val ,"remove user a from group del2b - $msg");
494 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a has the right to own tickets in queue 'DelegationTest'");
495 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
499 # {{{ When a user is removed froom a group by the only path they're in there by, make sure the delegations go away
500 ($val, $msg) = $del2->DeleteMember($user_a->PrincipalId);
501 ok( $val ,"remove user a from group del2 - $msg");
502 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest' ");
503 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest' ");
506 ($val, $msg) = $del2->AddMember($user_a->PrincipalId);
507 ok( $val ,"make user a a member of group del2 - $msg");
509 ($val, $msg) = $del2->PrincipalObj->GrantRight(Object=>$q, Right => 'OwnTicket');
510 ok($val, "grant the right 'own tickets' in queue 'DelegationTest' to group del2 - $msg");
512 my $del2_right = RT::ACE->new($user_a);
513 $del2_right->LoadByValues( PrincipalId => $del2->PrincipalId, PrincipalType => 'Group', Object => $q, RightName => 'OwnTicket');
514 ok ($del2_right->Id, "Found the right");
516 ($val, $msg) = $del2_right->Delegate(PrincipalId => $a_delegates->PrincipalId);
517 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' gotten via del2 to personal group 'delegates' - $msg");
519 # They have it via del1 and del2
520 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
523 ($val, $msg) = $del2->PrincipalObj->RevokeRight(Object=>$q, Right => 'OwnTicket');
524 ok($val, "revoke the right 'own tickets' in queue 'DelegationTest' to group del2 - $msg");
525 ok( $user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does has the right to own tickets in queue 'DelegationTest' via del1");
526 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
528 ($val, $msg) = $del2->PrincipalObj->GrantRight(Object=>$q, Right => 'OwnTicket');
529 ok($val, "grant the right 'own tickets' in queue 'DelegationTest' to group del2 - $msg");
532 $group_ace= RT::ACE->new($user_a);
533 $group_ace->LoadByValues( PrincipalType => 'Group', PrincipalId => $del1->PrincipalId, Object=>$q, RightName => 'OwnTicket');
535 ok ($group_ace->Id, "Found the ACE we want to test with for now");
537 ($val, $msg) = $group_ace->Delegate(PrincipalId => $a_delegates->PrincipalId);
539 ok( $val ,"user a tries and succeeds to delegate the right 'ownticket' in queue 'DelegationTest' to personal group 'delegates' - $msg");
541 ok( $user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b has the right to own tickets in queue 'DelegationTest'");
543 ($val, $msg) = $del2->DeleteMember($user_a->PrincipalId);
544 ok( $val ,"remove user a from group del2 - $msg");
546 ok( !$user_a->HasRight(Right => 'OwnTicket', Object => $q) ,"user a does not have the right to own tickets in queue 'DelegationTest'");
548 ok( !$user_b->HasRight(Right => 'OwnTicket', Object => $q) ,"user b does not have the right to own tickets in queue 'DelegationTest'");
558 my %args = ( PrincipalId => undef,
561 unless ( $self->Id ) {
562 return ( 0, $self->loc("Right not loaded.") );
565 ( $princ_obj, $args{'PrincipalType'} ) =
566 $self->_CanonicalizePrincipal( $args{'PrincipalId'},
567 $args{'PrincipalType'} );
569 unless ( $princ_obj->id ) {
571 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
579 # First, we check to se if the user is delegating rights and
580 # they have the permission to
581 unless ( $self->CurrentUser->HasRight(Right => 'DelegateRights', Object => $self->Object) ) {
582 return ( 0, $self->loc("Permission Denied") );
585 unless ( $self->PrincipalObj->IsGroup ) {
586 return ( 0, $self->loc("System Error") );
588 unless ( $self->PrincipalObj->Object->HasMemberRecursively(
589 $self->CurrentUser->PrincipalObj
592 return ( 0, $self->loc("Permission Denied") );
597 my $concurrency_check = RT::ACE->new($RT::SystemUser);
598 $concurrency_check->Load( $self->Id );
599 unless ( $concurrency_check->Id ) {
601 "Trying to delegate a right which had already been deleted");
602 return ( 0, $self->loc('Permission Denied') );
605 my $delegated_ace = RT::ACE->new( $self->CurrentUser );
607 # Make sure the right doesn't already exist.
608 $delegated_ace->LoadByCols( PrincipalId => $princ_obj->Id,
609 PrincipalType => 'Group',
610 RightName => $self->__Value('RightName'),
611 ObjectType => $self->__Value('ObjectType'),
612 ObjectId => $self->__Value('ObjectId'),
613 DelegatedBy => $self->CurrentUser->PrincipalId,
614 DelegatedFrom => $self->id );
615 if ( $delegated_ace->Id ) {
616 return ( 0, $self->loc('That principal already has that right') );
618 my $id = $delegated_ace->SUPER::Create(
619 PrincipalId => $princ_obj->Id,
620 PrincipalType => 'Group', # do we want to hardcode this?
621 RightName => $self->__Value('RightName'),
622 ObjectType => $self->__Value('ObjectType'),
623 ObjectId => $self->__Value('ObjectId'),
624 DelegatedBy => $self->CurrentUser->PrincipalId,
625 DelegatedFrom => $self->id );
627 #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space.
628 # TODO what about the groups key cache?
629 RT::Principal->InvalidateACLCache();
632 return ( $id, $self->loc('Right Delegated') );
635 return ( 0, $self->loc('System error. Right not delegated.') );
643 =head2 Delete { InsideTransaction => undef}
645 Delete this object. This method should ONLY ever be called from RT::User or RT::Group (or from itself)
646 If this is being called from within a transaction, specify a true value for the parameter InsideTransaction.
647 Really, DBIx::SearchBuilder should use and/or fake subtransactions
649 This routine will also recurse and delete any delegations of this right
656 unless ( $self->Id ) {
657 return ( 0, $self->loc('Right not loaded.') );
660 # A user can delete an ACE if the current user has the right to modify it and it's not a delegated ACE
661 # or if it's a delegated ACE and it was delegated by the current user
663 ( $self->CurrentUser->HasRight(Right => 'ModifyACL', Object => $self->Object)
664 && $self->__Value('DelegatedBy') == 0 )
665 || ( $self->__Value('DelegatedBy') == $self->CurrentUser->PrincipalId )
667 return ( 0, $self->loc('Permission Denied') );
672 # Helper for Delete with no ACL check
675 my %args = ( InsideTransaction => undef,
678 my $InsideTransaction = $args{'InsideTransaction'};
680 $RT::Handle->BeginTransaction() unless $InsideTransaction;
682 my $delegated_from_this = RT::ACL->new($RT::SystemUser);
683 $delegated_from_this->Limit( FIELD => 'DelegatedFrom',
685 VALUE => $self->Id );
687 my $delete_succeeded = 1;
689 while ( my $delegated_ace = $delegated_from_this->Next ) {
690 ( $delete_succeeded, $submsg ) =
691 $delegated_ace->_Delete( InsideTransaction => 1 );
692 last unless ($delete_succeeded);
695 unless ($delete_succeeded) {
696 $RT::Handle->Rollback() unless $InsideTransaction;
697 return ( 0, $self->loc('Right could not be revoked') );
700 my ( $val, $msg ) = $self->SUPER::Delete(@_);
702 # If we're revoking delegation rights (see above), we may need to
703 # revoke all rights delegated by the recipient.
704 if ($val and ($self->RightName() eq 'DelegateRights' or
705 $self->RightName() eq 'SuperUser')) {
706 $val = $self->PrincipalObj->_CleanupInvalidDelegations( InsideTransaction => 1 );
710 #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space.
711 # TODO what about the groups key cache?
712 RT::Principal->InvalidateACLCache();
713 $RT::Handle->Commit() unless $InsideTransaction;
714 return ( $val, $self->loc('Right revoked') );
717 $RT::Handle->Rollback() unless $InsideTransaction;
718 return ( 0, $self->loc('Right could not be revoked') );
723 # {{{ sub _BootstrapCreate
725 =head2 _BootstrapCreate
727 Grant a right with no error checking and no ACL. this is _only_ for
728 installation. If you use this routine without the author's explicit
729 written approval, he will hunt you down and make you spend eternity
730 translating mozilla's code into FORTRAN or intercal.
732 If you think you need this routine, you've mistaken.
736 sub _BootstrapCreate {
740 # When bootstrapping, make sure we get the _right_ users
741 if ( $args{'UserId'} ) {
742 my $user = RT::User->new( $self->CurrentUser );
743 $user->Load( $args{'UserId'} );
744 delete $args{'UserId'};
745 $args{'PrincipalId'} = $user->PrincipalId;
746 $args{'PrincipalType'} = 'User';
749 my $id = $self->SUPER::Create(%args);
755 $RT::Logger->err('System error. right not granted.');
763 # {{{ sub CanonicalizeRightName
765 =head2 CanonicalizeRightName <RIGHT>
767 Takes a queue or system right name in any case and returns it in
768 the correct case. If it's not found, will return undef.
772 sub CanonicalizeRightName {
776 if ( exists $LOWERCASERIGHTNAMES{"$right"} ) {
777 return ( $LOWERCASERIGHTNAMES{"$right"} );
791 If the object this ACE applies to is a queue, returns the queue object.
792 If the object this ACE applies to is a group, returns the group object.
793 If it's the system object, returns undef.
795 If the user has no rights, returns undef.
807 if ($self->__Value('ObjectType') && $OBJECT_TYPES{$self->__Value('ObjectType')} ) {
808 $appliesto_obj = $self->__Value('ObjectType')->new($self->CurrentUser);
809 unless (ref( $appliesto_obj) eq $self->__Value('ObjectType')) {
812 $appliesto_obj->Load( $self->__Value('ObjectId') );
813 return ($appliesto_obj);
816 $RT::Logger->warning( "$self -> Object called for an object "
817 . "of an unknown type:"
818 . $self->__Value('ObjectType') );
825 # {{{ sub PrincipalObj
829 Returns the RT::Principal object for this ACE.
836 my $princ_obj = RT::Principal->new( $self->CurrentUser );
837 $princ_obj->Load( $self->__Value('PrincipalId') );
839 unless ( $princ_obj->Id ) {
841 "ACE " . $self->Id . " couldn't load its principal object" );
849 # {{{ ACL related methods
855 return ( 0, $self->loc("ACEs can only be created and deleted.") );
865 if ( $self->__Value('DelegatedBy') eq $self->CurrentUser->PrincipalId ) {
866 return ( $self->__Value(@_) );
868 elsif ( $self->PrincipalObj->IsGroup
869 && $self->PrincipalObj->Object->HasMemberRecursively(
870 $self->CurrentUser->PrincipalObj
873 return ( $self->__Value(@_) );
875 elsif ( $self->CurrentUser->HasRight(Right => 'ShowACL', Object => $self->Object) ) {
876 return ( $self->__Value(@_) );
888 # {{{ _CanonicalizePrincipal
890 =head2 _CanonicalizePrincipal (PrincipalId, PrincipalType)
892 Takes a principal id and a principal type.
894 If the principal is a user, resolves it to the proper acl equivalence group.
895 Returns a tuple of (RT::Principal, PrincipalType) for the principal we really want to work with
899 sub _CanonicalizePrincipal {
901 my $princ_id = shift;
902 my $princ_type = shift;
904 my $princ_obj = RT::Principal->new($RT::SystemUser);
905 $princ_obj->Load($princ_id);
907 unless ( $princ_obj->Id ) {
909 $RT::Logger->crit(Carp::cluck);
910 $RT::Logger->crit("Can't load a principal for id $princ_id");
911 return ( $princ_obj, undef );
914 # Rights never get granted to users. they get granted to their
915 # ACL equivalence groups
916 if ( $princ_type eq 'User' ) {
917 my $equiv_group = RT::Group->new( $self->CurrentUser );
918 $equiv_group->LoadACLEquivalenceGroup($princ_obj);
919 unless ( $equiv_group->Id ) {
920 $RT::Logger->crit( "No ACL equiv group for princ " . $princ_obj->id );
921 return ( RT::Principal->new($RT::SystemUser), undef );
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" );