summaryrefslogtreecommitdiff
path: root/rt/lib/RT/Principal_Overlay.pm
diff options
context:
space:
mode:
Diffstat (limited to 'rt/lib/RT/Principal_Overlay.pm')
-rw-r--r--rt/lib/RT/Principal_Overlay.pm587
1 files changed, 0 insertions, 587 deletions
diff --git a/rt/lib/RT/Principal_Overlay.pm b/rt/lib/RT/Principal_Overlay.pm
deleted file mode 100644
index 4783c5c..0000000
--- a/rt/lib/RT/Principal_Overlay.pm
+++ /dev/null
@@ -1,587 +0,0 @@
-# BEGIN BPS TAGGED BLOCK {{{
-#
-# COPYRIGHT:
-#
-# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC
-# <jesse@bestpractical.com>
-#
-# (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
-# been provided with this software, but in any event can be snarfed
-# from www.gnu.org.
-#
-# This work is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-#
-# CONTRIBUTION SUBMISSION POLICY:
-#
-# (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 }}}
-#
-
-package RT::Principal;
-
-use strict;
-use warnings;
-
-no warnings qw(redefine);
-
-use Cache::Simple::TimedExpiry;
-
-
-
-use RT::Group;
-use RT::User;
-
-# Set up the ACL cache on startup
-our $_ACL_CACHE;
-InvalidateACLCache();
-
-# {{{ IsGroup
-
-=head2 IsGroup
-
-Returns true if this principal is a group.
-Returns undef, otherwise
-
-=cut
-
-sub IsGroup {
- my $self = shift;
- if ($self->PrincipalType eq 'Group') {
- return(1);
- }
- else {
- return undef;
- }
-}
-
-# }}}
-
-# {{{ IsUser
-
-=head2 IsUser
-
-Returns true if this principal is a User.
-Returns undef, otherwise
-
-=cut
-
-sub IsUser {
- my $self = shift;
- if ($self->PrincipalType eq 'User') {
- return(1);
- }
- else {
- return undef;
- }
-}
-
-# }}}
-
-# {{{ Object
-
-=head2 Object
-
-Returns the user or group associated with this principal
-
-=cut
-
-sub Object {
- my $self = shift;
-
- unless ($self->{'object'}) {
- if ($self->IsUser) {
- $self->{'object'} = RT::User->new($self->CurrentUser);
- }
- elsif ($self->IsGroup) {
- $self->{'object'} = RT::Group->new($self->CurrentUser);
- }
- else {
- $RT::Logger->crit("Found a principal (".$self->Id.") that was neither a user nor a group");
- return(undef);
- }
- $self->{'object'}->Load($self->ObjectId());
- }
- return ($self->{'object'});
-
-
-}
-# }}}
-
-# {{{ ACL Related routines
-
-# {{{ GrantRight
-
-=head2 GrantRight { Right => RIGHTNAME, Object => undef }
-
-A helper function which calls RT::ACE->Create
-
-
-
- Returns a tuple of (STATUS, MESSAGE); If the call succeeded, STATUS is true. Otherwise it's
- false.
-
-=cut
-
-sub GrantRight {
- my $self = shift;
- my %args = ( Right => undef,
- Object => undef,
- @_);
-
-
- unless ($args{'Right'}) {
- return(0, $self->loc("Invalid Right"));
- }
-
-
- #ACL check handled in ACE.pm
- my $ace = RT::ACE->new( $self->CurrentUser );
-
-
- my $type = $self->_GetPrincipalTypeForACL();
-
- # If it's a user, we really want to grant the right to their
- # user equivalence group
- return ( $ace->Create(RightName => $args{'Right'},
- Object => $args{'Object'},
- PrincipalType => $type,
- PrincipalId => $self->Id
- ) );
-}
-# }}}
-
-# {{{ RevokeRight
-
-=head2 RevokeRight { Right => "RightName", Object => "object" }
-
-Delete a right that a user has
-
-
- Returns a tuple of (STATUS, MESSAGE); If the call succeeded, STATUS is true. Otherwise it's
- false.
-
-
-=cut
-
-sub RevokeRight {
-
- my $self = shift;
- my %args = (
- Right => undef,
- 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;
- }
- #ACL check handled in ACE.pm
- my $type = $self->_GetPrincipalTypeForACL();
-
- my $ace = RT::ACE->new( $self->CurrentUser );
- $ace->LoadByValues(
- RightName => $args{'Right'},
- Object => $args{'Object'},
- PrincipalType => $type,
- PrincipalId => $self->Id
- );
-
- unless ( $ace->Id ) {
- return ( 0, $self->loc("ACE not found") );
- }
- return ( $ace->Delete );
-}
-
-# }}}
-
-# {{{ sub _CleanupInvalidDelegations
-
-=head2 sub _CleanupInvalidDelegations { InsideTransaction => undef }
-
-Revokes all ACE entries delegated by this principal which are
-inconsistent with this principal's current delegation rights. Does
-not perform permission checks, but takes no action and returns success
-if this principal still retains DelegateRights. Should only ever be
-called from inside the RT library.
-
-If this principal is a group, recursively calls this method on each
-cached user member of itself.
-
-If called from inside a transaction, specify a true value for the
-InsideTransaction parameter.
-
-Returns a true value if the deletion succeeded; returns a false value
-and logs an internal error if the deletion fails (should not happen).
-
-=cut
-
-# This is currently just a stub for the methods of the same name in
-# RT::User and RT::Group.
-
-sub _CleanupInvalidDelegations {
- my $self = shift;
- unless ( $self->Id ) {
- $RT::Logger->warning("Principal not loaded.");
- return (undef);
- }
- return ($self->Object->_CleanupInvalidDelegations(@_));
-}
-
-# }}}
-
-# {{{ sub HasRight
-
-=head2 sub HasRight (Right => 'right' Object => undef)
-
-
-Checks to see whether this principal has the right "Right" for the Object
-specified. If the Object parameter is omitted, checks to see whether the
-user has the right globally.
-
-This still hard codes to check to see if a user has queue-level rights
-if we ask about a specific ticket.
-
-
-This takes the params:
-
- Right => name of a right
-
- And either:
-
- Object => an RT style object (->id will get its id)
-
-
-
-
-Returns 1 if a matching ACE was found.
-
-Returns undef if no ACE was found.
-
-=cut
-
-sub HasRight {
-
- my $self = shift;
- my %args = (
- Right => undef,
- Object => undef,
- EquivObjects => undef,
- @_
- );
-
- if ( $self->Disabled ) {
- $RT::Logger->err( "Disabled User: "
- . $self->id
- . " failed access check for "
- . $args{'Right'} );
- return (undef);
- }
-
- if ( !defined $args{'Right'} ) {
- $RT::Logger->crit("HasRight called without a right");
- return (undef);
- }
-
- if ( defined( $args{'Object'} )
- && UNIVERSAL::can( $args{'Object'}, 'id' )
- && $args{'Object'}->id )
- {
- push( @{ $args{'EquivObjects'} }, $args{Object} );
- }
- else {
- $RT::Logger->crit("$self HasRight called with no valid object");
- return (undef);
- }
-
- # If this object is a ticket, we care about ticket roles and queue roles
- if ( ( ref( $args{'Object'} ) eq 'RT::Ticket' ) && $args{'Object'}->Id ) {
-
-# this is a little bit hacky, but basically, now that we've done the ticket roles magic, we load the queue object
-# and ask all the rest of our questions about the queue.
- push( @{ $args{'EquivObjects'} }, $args{'Object'}->QueueObj );
-
- }
-
- # {{{ If we've cached a win or loss for this lookup say so
-
- # {{{ Construct a hashkey to cache decisions in
- my $hashkey = do {
- no warnings 'uninitialized';
-
- # We don't worry about the hash ordering, as this is only
- # temporarily used; also if the key changes it would be
- # invalidated anyway.
- join(
- ";:;",
- $self->Id,
- map {
- $_, # the key of each arguments
- ( $_ eq 'EquivObjects' ) # for object arrayref...
- ? map( _ReferenceId($_), @{ $args{$_} } ) # calculate each
- : _ReferenceId( $args{$_} ) # otherwise just the value
- } keys %args
- );
- };
-
- # }}}
-
- # {{{ if we've cached a positive result for this query, return 1
-
- my $cached_answer = $_ACL_CACHE->fetch($hashkey);
-
- # Returns undef on cache miss
- if ( defined $cached_answer ) {
- if ( $cached_answer == 1 ) {
- return (1);
- }
- elsif ( $cached_answer == -1 ) {
- return (0);
- }
- }
-
- my ( $or_look_at_object_rights, $or_check_roles );
- my $right = $args{'Right'};
-
- # {{{ Construct Right Match
-
- # If an object is defined, we want to look at rights for that object
-
- my @look_at_objects;
- push( @look_at_objects, "ACL.ObjectType = 'RT::System'" )
- unless $self->can('_IsOverrideGlobalACL')
- and $self->_IsOverrideGlobalACL( $args{Object} );
-
- foreach my $obj ( @{ $args{'EquivObjects'} } ) {
- next unless ( UNIVERSAL::can( $obj, 'id' ) );
- my $type = ref($obj);
- my $id = $obj->id;
-
- unless ($id) {
- use Carp;
- Carp::cluck(
- "Trying to check $type rights for an unspecified $type");
- $RT::Logger->crit(
- "Trying to check $type rights for an unspecified $type");
- }
- push @look_at_objects,
- "(ACL.ObjectType = '$type' AND ACL.ObjectId = '$id')";
- }
-
- # }}}
-
- # {{{ Build that honkin-big SQL query
-
- my $query_base =
- "SELECT ACL.id from ACL, Groups, Principals, CachedGroupMembers WHERE " .
-
- # Only find superuser or rights with the name $right
- "(ACL.RightName = 'SuperUser' OR ACL.RightName = '$right') " .
-
- # Never find disabled groups.
- "AND Principals.Disabled = 0 "
- . "AND CachedGroupMembers.Disabled = 0 "
- . "AND Principals.id = Groups.id "
- . # We always grant rights to Groups
-
-# See if the principal is a member of the group recursively or _is the rightholder_
-# never find recursively disabled group members
-# also, check to see if the right is being granted _directly_ to this principal,
-# as is the case when we want to look up group rights
-"AND Principals.id = CachedGroupMembers.GroupId AND CachedGroupMembers.MemberId = '"
- . $self->Id . "' "
- .
-
- # Make sure the rights apply to the entire system or to the object in question
- "AND ( " . join( ' OR ', @look_at_objects ) . ") ";
-
-# The groups query does the query based on group membership and individual user rights
-
- my $groups_query = $query_base .
-
-# limit the result set to groups of types ACLEquivalence (user) UserDefined, SystemInternal and Personal
-"AND ( ( ACL.PrincipalId = Principals.id AND ACL.PrincipalType = 'Group' AND "
- . "(Groups.Domain = 'SystemInternal' OR Groups.Domain = 'UserDefined' OR Groups.Domain = 'ACLEquivalence' OR Groups.Domain = 'Personal'))"
- .
-
- " ) ";
- $self->_Handle->ApplyLimits( \$groups_query, 1 ); #only return one result
-
- my @roles;
- foreach my $object ( @{ $args{'EquivObjects'} } ) {
- push( @roles, $self->_RolesForObject( ref($object), $object->id ) );
- }
-
- # The roles query does the query based on roles
- my $roles_query;
- if (@roles) {
- $roles_query =
- $query_base . "AND " . " ( ("
- . join( ' OR ', @roles ) . " ) "
- . " AND Groups.Type = ACL.PrincipalType AND Groups.Id = Principals.id AND Principals.PrincipalType = 'Group') ";
- $self->_Handle->ApplyLimits( \$roles_query, 1 ); #only return one result
-
- }
-
- # }}}
-
- # {{{ Actually check the ACL by performing an SQL query
- # $RT::Logger->debug("Now Trying $groups_query");
- my $hitcount = $self->_Handle->FetchResult($groups_query);
-
- # }}}
-
- # {{{ if there's a match, the right is granted
- if ($hitcount) {
- $_ACL_CACHE->set( $hashkey => 1 );
- return (1);
- }
-
- # Now check the roles query
- $hitcount = $self->_Handle->FetchResult($roles_query);
-
- if ($hitcount) {
- $_ACL_CACHE->set( $hashkey => 1 );
- return (1);
- }
-
- # We failed to find an acl hit
- $_ACL_CACHE->set( $hashkey => -1 );
- return (undef);
-}
-
-# }}}
-
-# {{{ _RolesForObject
-
-
-
-=head2 _RolesForObject( $object_type, $object_id)
-
-Returns an SQL clause finding role groups for Objects
-
-=cut
-
-
-sub _RolesForObject {
- my $self = shift;
- my $type = shift;
- my $id = shift;
-
- unless ($id) {
- $id = '0';
- }
-
- # This should never be true.
- unless ($id =~ /^\d+$/) {
- $RT::Logger->crit("RT::Prinicipal::_RolesForObject called with type $type and a non-integer id: '$id'");
- $id = "'$id'";
- }
-
- my $clause = "(Groups.Domain = '".$type."-Role' AND Groups.Instance = $id) ";
-
- return($clause);
-}
-
-# }}}
-
-# }}}
-
-# {{{ ACL caching
-
-
-# {{{ InvalidateACLCache
-
-=head2 InvalidateACLCache
-
-Cleans out and reinitializes the user rights cache
-
-=cut
-
-sub InvalidateACLCache {
- $_ACL_CACHE = Cache::Simple::TimedExpiry->new();
- $_ACL_CACHE->expire_after($RT::ACLCacheLifetime||60);
-
-}
-
-# }}}
-
-# }}}
-
-
-# {{{ _GetPrincipalTypeForACL
-
-=head2 _GetPrincipalTypeForACL
-
-Gets the principal type. if it's a user, it's a user. if it's a role group and it has a Type,
-return that. if it has no type, return group.
-
-=cut
-
-sub _GetPrincipalTypeForACL {
- my $self = shift;
- my $type;
- if ($self->PrincipalType eq 'Group' && $self->Object->Domain =~ /Role$/) {
- $type = $self->Object->Type;
- }
- else {
- $type = $self->PrincipalType;
- }
-
- return($type);
-}
-
-# }}}
-
-# {{{ _ReferenceId
-
-=head2 _ReferenceId
-
-Returns a list uniquely representing an object or normal scalar.
-
-For scalars, its string value is returned; for objects that has an
-id() method, its class name and Id are returned as a string separated by a "-".
-
-=cut
-
-sub _ReferenceId {
- my $scalar = shift;
-
- # just return the value for non-objects
- return $scalar unless UNIVERSAL::can($scalar, 'id');
-
- # an object -- return the class and id
- return(ref($scalar)."-". $scalar->id);
-}
-
-# }}}
-
-1;