diff options
Diffstat (limited to 'rt/lib/RT/Users_Overlay.pm')
-rw-r--r-- | rt/lib/RT/Users_Overlay.pm | 211 |
1 files changed, 175 insertions, 36 deletions
diff --git a/rt/lib/RT/Users_Overlay.pm b/rt/lib/RT/Users_Overlay.pm index 49e4a99a6..4bb9f8f91 100644 --- a/rt/lib/RT/Users_Overlay.pm +++ b/rt/lib/RT/Users_Overlay.pm @@ -1,8 +1,8 @@ -# {{{ BEGIN BPS TAGGED BLOCK +# BEGIN BPS TAGGED BLOCK {{{ # # COPYRIGHT: # -# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC +# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC # <jesse@bestpractical.com> # # (Except where explicitly superseded by other copyright notices) @@ -42,7 +42,8 @@ # works based on those contributions, and sublicense and distribute # those contributions and any derivatives thereof. # -# }}} END BPS TAGGED BLOCK +# END BPS TAGGED BLOCK }}} + =head1 NAME RT::Users - Collection of RT::User objects @@ -65,6 +66,9 @@ ok(require RT::Users); =cut + +package RT::Users; + use strict; no warnings qw(redefine); @@ -219,7 +223,7 @@ sub LimitToPrivileged { # {{{ WhoHaveRight -=head2 WhoHaveRight { Right => 'name', Object => $rt_object , IncludeSuperusers => undef, IncludeSubgroupMembers => undef, IncludeSystemRights => undef } +=head2 WhoHaveRight { Right => 'name', Object => $rt_object , IncludeSuperusers => undef, IncludeSubgroupMembers => undef, IncludeSystemRights => undef, EquivObjects => [ ] } =begin testing @@ -228,6 +232,59 @@ $users->WhoHaveRight(Object =>$RT::System, Right =>'SuperUser'); ok($users->Count == 1, "There is one privileged superuser - Found ". $users->Count ); # TODO: this wants more testing +my $RTxUser = RT::User->new($RT::SystemUser); +($id, $msg) = $RTxUser->Create( Name => 'RTxUser', Comments => "RTx extension user", Privileged => 1); +ok ($id,$msg); + +my $group = RT::Group->new($RT::SystemUser); +$group->LoadACLEquivalenceGroup($RTxUser->PrincipalObj); + +my $RTxSysObj = {}; +bless $RTxSysObj, 'RTx::System'; +*RTx::System::Id = sub { 1; }; +*RTx::System::id = *RTx::System::Id; +my $ace = RT::Record->new($RT::SystemUser); +$ace->Table('ACL'); +$ace->_BuildTableAttributes unless ($_TABLE_ATTR->{ref($self)}); +($id, $msg) = $ace->Create( PrincipalId => $group->id, PrincipalType => 'Group', RightName => 'RTxUserRight', ObjectType => 'RTx::System', ObjectId => 1 ); +ok ($id, "ACL for RTxSysObj created"); + +my $RTxObj = {}; +bless $RTxObj, 'RTx::System::Record'; +*RTx::System::Record::Id = sub { 4; }; +*RTx::System::Record::id = *RTx::System::Record::Id; + +$users = RT::Users->new($RT::SystemUser); +$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxSysObj); +is($users->Count, 1, "RTxUserRight found for RTxSysObj"); + +$users = RT::Users->new($RT::SystemUser); +$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj); +is($users->Count, 0, "RTxUserRight not found for RTxObj"); + +$users = RT::Users->new($RT::SystemUser); +$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj, EquivObjects => [ $RTxSysObj ]); +is($users->Count, 1, "RTxUserRight found for RTxObj using EquivObjects"); + +$ace = RT::Record->new($RT::SystemUser); +$ace->Table('ACL'); +$ace->_BuildTableAttributes unless ($_TABLE_ATTR->{ref($self)}); +($id, $msg) = $ace->Create( PrincipalId => $group->id, PrincipalType => 'Group', RightName => 'RTxUserRight', ObjectType => 'RTx::System::Record', ObjectId => 5 ); +ok ($id, "ACL for RTxObj created"); + +my $RTxObj2 = {}; +bless $RTxObj2, 'RTx::System::Record'; +*RTx::System::Record::Id = sub { 5; }; +*RTx::System::Record::id = sub { 5; }; + +$users = RT::Users->new($RT::SystemUser); +$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj2); +is($users->Count, 1, "RTxUserRight found for RTxObj2"); + +$users = RT::Users->new($RT::SystemUser); +$users->WhoHaveRight(Right => 'RTxUserRight', Object => $RTxObj2, EquivObjects => [ $RTxSysObj ]); +is($users->Count, 1, "RTxUserRight found for RTxObj2"); + =end testing @@ -236,6 +293,7 @@ find all users who the right Right for this group, either individually or as members of groups +If passed a queue object, with no id, it will find users who have that right for _any_ queue @@ -243,38 +301,125 @@ or as members of groups sub WhoHaveRight { my $self = shift; - my %args = ( Right => undef, - Object => => undef, - IncludeSystemRights => undef, - IncludeSuperusers => undef, - IncludeSubgroupMembers => 1, - @_ ); - - if (defined $args{'ObjectType'} || defined $args{'ObjectId'}) { - $RT::Logger->crit("$self WhoHaveRight called with the Obsolete ObjectId/ObjectType API"); - return(undef); + my %args = ( + Right => undef, + Object => undef, + IncludeSystemRights => undef, + IncludeSuperusers => undef, + IncludeSubgroupMembers => 1, + EquivObjects => [ ], + @_ + ); + + if ( defined $args{'ObjectType'} || defined $args{'ObjectId'} ) { + $RT::Logger->crit( "$self WhoHaveRight called with the Obsolete ObjectId/ObjectType API"); + return (undef); } - my @privgroups; - my $Groups = RT::Groups->new($RT::SystemUser); - $Groups->WithRight(Right=> $args{'Right'}, - Object => $args{'Object'}, - IncludeSystemRights => $args{'IncludeSystemRights'}, - IncludeSuperusers => $args{'IncludeSuperusers'}); - while (my $Group = $Groups->Next()) { - push @privgroups, $Group->Id(); - } + + + # Find only members of groups that have the right. + my $acl = $self->NewAlias('ACL'); + my $groups = $self->NewAlias('Groups'); + my $userprinc = $self->{'princalias'}; + +# The cachedgroupmembers table is used for unrolling group memberships to allow fast lookups +# if we bind to CachedGroupMembers, we'll find all members of groups recursively. +# if we don't we'll find only 'direct' members of the group in question + my $cgm; - if (@privgroups) { - $self->WhoBelongToGroups(Groups => \@privgroups, - IncludeSubgroupMembers => $args{'IncludeSubgroupMembers'}); + if ( $args{'IncludeSubgroupMembers'} ) { + $cgm = $self->NewAlias('CachedGroupMembers'); } else { - # We don't have any group that matches -- make it impossible. - $self->Limit( FIELD => 'Id', VALUE => 'IS', OPERATOR => 'NULL' ); + $cgm = $self->NewAlias('GroupMembers'); } -} +#Tie the users we're returning ($userprinc) to the groups that have rights granted to them ($groupprinc) + $self->Join( + ALIAS1 => $cgm, + FIELD1 => 'MemberId', + ALIAS2 => $userprinc, + FIELD2 => 'id' + ); + + $self->Join( + ALIAS1 => $groups, + FIELD1 => 'id', + ALIAS2 => $cgm, + FIELD2 => 'GroupId' + ); + +# {{{ Find only rows where the right granted is the one we're looking up or _possibly_ superuser + $self->Limit( + ALIAS => $acl, + FIELD => 'RightName', + OPERATOR => ( $args{Right} ? '=' : 'IS NOT' ), + VALUE => $args{Right} || 'NULL', + ENTRYAGGREGATOR => 'OR' + ); + + if ( $args{'IncludeSuperusers'} and $args{'Right'} ) { + $self->Limit( + ALIAS => $acl, + FIELD => 'RightName', + OPERATOR => '=', + VALUE => 'SuperUser', + ENTRYAGGREGATOR => 'OR' + ); + } + + # }}} + + my ( $or_check_ticket_roles, $or_check_roles ); + my $which_object = "$acl.ObjectType = 'RT::System'"; + + if ( defined $args{'Object'} ) { + if ( ref( $args{'Object'} ) eq 'RT::Ticket' ) { + $or_check_ticket_roles = " OR ( $groups.Domain = 'RT::Ticket-Role' AND $groups.Instance = " . $args{'Object'}->Id . ") "; + +# If we're looking at ticket rights, we also want to look at the associated queue rights. +# 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. + $args{'Object'} = $args{'Object'}->QueueObj; + } + + # TODO XXX This really wants some refactoring + if ( ref( $args{'Object'} ) eq 'RT::Queue' ) { + $or_check_roles = " OR ( ( ($groups.Domain = 'RT::Queue-Role' "; + $or_check_roles .= "AND $groups.Instance = " . $args{'Object'}->id if ( $args{'Object'}->id ); + $or_check_roles .= ") $or_check_ticket_roles ) " . " AND $groups.Type = $acl.PrincipalType) "; + } + if ( $args{'IncludeSystemRights'} ) { + $which_object .= ' OR '; + } + else { + $which_object = ''; + } + foreach my $obj ( @{ $args{'EquivObjects'} } ) { + $which_object .= "($acl.ObjectType = '" . ref( $obj ) . "' AND $acl.ObjectId = " . $obj->id . ") OR "; + } + $which_object .= " ($acl.ObjectType = '" . ref( $args{'Object'} ) . "'"; + if ( $args{'Object'}->id ) { + $which_object .= " AND $acl.ObjectId = " . $args{'Object'}->id; + } + + $which_object .= ") "; + } + $self->_AddSubClause( "WhichObject", "($which_object)" ); + $self->_AddSubClause( + "WhichGroup", + qq{ ( ( $acl.PrincipalId = $groups.id AND $acl.PrincipalType = 'Group' + AND ( $groups.Domain = 'SystemInternal' OR $groups.Domain = 'UserDefined' OR $groups.Domain = 'ACLEquivalence')) + $or_check_roles) } + ); + # only include regular RT users + $self->LimitToEnabled; + + # no system user + $self->Limit( ALIAS => $userprinc, FIELD => 'id', OPERATOR => '!=', VALUE => $RT::SystemUser->id); + +} # }}} # {{{ WhoBelongToGroups @@ -307,20 +452,14 @@ sub WhoBelongToGroups { $cgm = $self->NewAlias('GroupMembers'); } - # {{{ Tie the users we're returning ($userprinc) to the groups that have rights granted to them ($groupprinc) + #Tie the users we're returning ($userprinc) to the groups that have rights granted to them ($groupprinc) $self->Join( ALIAS1 => $cgm, FIELD1 => 'MemberId', ALIAS2 => $userprinc, FIELD2 => 'id' ); - # }}} - # my $and_check_groups = "($cgm.GroupId = NULL"; foreach my $groupid (@{$args{'Groups'}}) { $self->Limit(ALIAS => $cgm, FIELD => 'GroupId', VALUE => $groupid, QUOTEVALUE => 0, ENTRYAGGREGATOR=> 'OR') - #$and_check_groups .= " OR $cgm.GroupId = $groupid"; } - #$and_check_groups .= ")"; - - #$self->_AddSubClause("WhichGroup", $and_check_groups); } # }}} |