import rt 3.6.6
[freeside.git] / rt / lib / RT / ACE_Overlay.pm
index 65e5a9c..54c6561 100644 (file)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# BEGIN BPS TAGGED BLOCK {{{
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # This work is made available to you under the terms of Version 2 of
 # the GNU General Public License. A copy of that license should have
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 # General Public License for more details.
 # 
-# Unless otherwise specified, all modifications, corrections or
-# extensions to this work which alter its source code become the
-# property of Best Practical Solutions, LLC when submitted for
-# inclusion in the work.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 or visit their web page on the internet at
+# http://www.gnu.org/copyleft/gpl.html.
+# 
 # 
+# CONTRIBUTION SUBMISSION POLICY:
 # 
-# END LICENSE BLOCK
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+# 
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+# 
+# END BPS TAGGED BLOCK }}}
 =head1 SYNOPSIS
 
   use RT::ACE;
@@ -41,6 +65,9 @@ ok(require RT::ACE);
 
 =cut
 
+
+package RT::ACE;
+
 use strict;
 no warnings qw(redefine);
 use RT::Principals;
@@ -107,8 +134,8 @@ Load an ACE by specifying a paramhash with the following fields:
 
             OR
 
-        ObjectType => undef,
-        ObjectId => undef
+             ObjectType => undef,
+             ObjectId => undef
 
 =cut
 
@@ -133,16 +160,9 @@ sub LoadByValues {
         );
     }
 
-    my ($object_type, $object_id);
-    
-    if ($args{'Object'} && UNIVERSAL::can($args{'Object'},'id')) {
-        $object_type = ref($args{'Object'});
-        $object_id = $args{'Object'}->id;
-    } elsif ($args{'ObjectId'} || $args{'ObjectType'}) {
-        $object_type = $args{'ObjectType'};
-        $object_id = $args{'ObjectId'};
-    } else {
-            return ( 0, $self->loc("System error. Right not granted.") );
+    my ($object, $object_type, $object_id) = $self->_ParseObjectArg( %args );
+    unless( $object ) {
+       return ( 0, $self->loc("System error. Right not granted.") );
     }
 
     $self->LoadByCols( PrincipalId   => $princ_obj->Id,
@@ -186,6 +206,12 @@ PARAMS is a parameter hash with the following elements:
    ObjectType => the type of the object in question (ref ($object))
    ObjectId => the id of the object in question $object->Id
 
+
+
+   Returns a tuple of (STATUS, MESSAGE);  If the call succeeded, STATUS is true. Otherwise it's false.
+
+
+
 =cut
 
 sub Create {
@@ -193,8 +219,16 @@ sub Create {
     my %args = ( PrincipalId   => undef,
                  PrincipalType => undef,
                  RightName     => undef,
-                 Object    => $RT::System,
+                 Object        => undef,
                  @_ );
+    #if we haven't specified any sort of right, we're talking about a global right
+    if (!defined $args{'Object'} && !defined $args{'ObjectId'} && !defined $args{'ObjectType'}) {
+        $args{'Object'} = $RT::System;
+    }
+    ($args{'Object'}, $args{'ObjectType'}, $args{'ObjectId'}) = $self->_ParseObjectArg( %args );
+    unless( $args{'Object'} ) {
+       return ( 0, $self->loc("System error. Right not granted.") );
+    }
 
     # {{{ Validate the principal
     my $princ_obj;
@@ -210,17 +244,6 @@ sub Create {
 
     # }}}
 
-
-    if ($args{'Object'} && ($args{'ObjectId'} || $args{'ObjectType'})) {
-        use Carp;
-        $RT::Logger->crit(Carp::cluck("ACE::Create called with an ObjectType or an ObjectId"));
-    }
-
-
-    
-    unless ($args{'Object'} && UNIVERSAL::can($args{'Object'},'id')) {
-            return ( 0, $self->loc("System error. Right not granted.") );
-    }
     # {{{ Check the ACL
 
     if (ref( $args{'Object'}) eq 'RT::Group' ) {
@@ -270,17 +293,14 @@ sub Create {
         }
     }
 
-    unless ( $args{'RightName'} ) {
-        return ( 0, $self->loc('Invalid right') );
-    }
     # }}}
 
     # Make sure the right doesn't already exist.
     $self->LoadByCols( PrincipalId   => $princ_obj->id,
                        PrincipalType => $args{'PrincipalType'},
                        RightName     => $args{'RightName'},
-                       ObjectType    => ref($args{'Object'}),
-                       ObjectId      => $args{'Object'}->id,
+                       ObjectType    => $args{'ObjectType'},
+                       ObjectId      => $args{'ObjectId'},
                        DelegatedBy   => 0,
                        DelegatedFrom => 0 );
     if ( $self->Id ) {
@@ -296,7 +316,7 @@ sub Create {
                                    DelegatedFrom => 0 );
 
     #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space. 
-    RT::Principal->_InvalidateACLCache();
+    RT::Principal->InvalidateACLCache();
 
     if ( $id > 0 ) {
         return ( $id, $self->loc('Right Granted') );
@@ -606,7 +626,7 @@ sub Delegate {
 
     #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space. 
     # TODO what about the groups key cache?
-    RT::Principal->_InvalidateACLCache();
+    RT::Principal->InvalidateACLCache();
 
     if ( $id > 0 ) {
         return ( $id, $self->loc('Right Delegated') );
@@ -669,7 +689,7 @@ sub _Delete {
     while ( my $delegated_ace = $delegated_from_this->Next ) {
         ( $delete_succeeded, $submsg ) =
           $delegated_ace->_Delete( InsideTransaction => 1 );
-        last if ($delete_succeeded);
+        last unless ($delete_succeeded);
     }
 
     unless ($delete_succeeded) {
@@ -679,18 +699,23 @@ sub _Delete {
 
     my ( $val, $msg ) = $self->SUPER::Delete(@_);
 
-    #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space. 
-    # TODO what about the groups key cache?
-    RT::Principal->_InvalidateACLCache();
+    # If we're revoking delegation rights (see above), we may need to
+    # revoke all rights delegated by the recipient.
+    if ($val and ($self->RightName() eq 'DelegateRights' or
+                 $self->RightName() eq 'SuperUser')) {
+       $val = $self->PrincipalObj->_CleanupInvalidDelegations( InsideTransaction => 1 );
+    }
 
     if ($val) {
+       #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space. 
+       # TODO what about the groups key cache?
+       RT::Principal->InvalidateACLCache();
         $RT::Handle->Commit() unless $InsideTransaction;
         return ( $val, $self->loc('Right revoked') );
     }
-    else {
-        $RT::Handle->Rollback() unless $InsideTransaction;
-        return ( 0, $self->loc('Right could not be revoked') );
-    }
+
+    $RT::Handle->Rollback() unless $InsideTransaction;
+    return ( 0, $self->loc('Right could not be revoked') );
 }
 
 # }}}
@@ -790,7 +815,7 @@ sub Object {
     else {
         $RT::Logger->warning( "$self -> Object called for an object "
                               . "of an unknown type:"
-                              . $self->ObjectType );
+                              . $self->__Value('ObjectType') );
         return (undef);
     }
 }
@@ -892,9 +917,8 @@ sub _CanonicalizePrincipal {
         my $equiv_group = RT::Group->new( $self->CurrentUser );
         $equiv_group->LoadACLEquivalenceGroup($princ_obj);
         unless ( $equiv_group->Id ) {
-            $RT::Logger->crit(
-                 "No ACL equiv group for princ " . $self->__Value('ObjectId') );
-            return ( 0, $self->loc('System error. Right not granted.') );
+            $RT::Logger->crit( "No ACL equiv group for princ " . $princ_obj->id );
+            return ( RT::Principal->new($RT::SystemUser), undef );
         }
         $princ_obj  = $equiv_group->PrincipalObj();
         $princ_type = 'Group';
@@ -903,5 +927,32 @@ sub _CanonicalizePrincipal {
     return ( $princ_obj, $princ_type );
 }
 
+sub _ParseObjectArg {
+    my $self = shift;
+    my %args = ( Object    => undef,
+                 ObjectId    => undef,
+                 ObjectType    => undef,
+                 @_ );
+
+    if( $args{'Object'} && ($args{'ObjectId'} || $args{'ObjectType'}) ) {
+       $RT::Logger->crit( "Method called with an ObjectType or an ObjectId and Object args" );
+       return ();
+    } elsif( $args{'Object'} && !UNIVERSAL::can($args{'Object'},'id') ) {
+       $RT::Logger->crit( "Method called called Object that has no id method" );
+       return ();
+    } elsif( $args{'Object'} ) {
+       my $obj = $args{'Object'};
+       return ($obj, ref $obj, $obj->id);
+    } elsif ( $args{'ObjectType'} ) {
+       my $obj =  $args{'ObjectType'}->new( $self->CurrentUser );
+       $obj->Load( $args{'ObjectId'} );
+       return ($obj, ref $obj, $obj->id);
+    } else {
+       $RT::Logger->crit( "Method called with wrong args" );
+       return ();
+    }
+}
+
+
 # }}}
 1;