X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=rt%2Flib%2FRT%2FCurrentUser.pm;h=4ca2f98919f79b206787753d052ab30d6ee29fb0;hb=bcce4879b66b40c9c0a370305f7dab4e48224866;hp=b674d4e60e47059c6bf30eb0c451c6a6a950e2c4;hpb=b4b0c7e72d7eaee2fbfc7022022c9698323203dd;p=freeside.git diff --git a/rt/lib/RT/CurrentUser.pm b/rt/lib/RT/CurrentUser.pm index b674d4e60..4ca2f9891 100755 --- a/rt/lib/RT/CurrentUser.pm +++ b/rt/lib/RT/CurrentUser.pm @@ -1,14 +1,8 @@ -# BEGIN BPS TAGGED BLOCK {{{ +# BEGIN LICENSE BLOCK # -# COPYRIGHT: +# Copyright (c) 1996-2003 Jesse Vincent # -# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC -# -# -# (Except where explicitly superseded by other copyright notices) -# -# -# LICENSE: +# (Except where explictly superceded by other copyright notices) # # 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 @@ -20,165 +14,182 @@ # 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., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301 or visit their web page on the internet at -# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. -# +# 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. # -# 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 }}} - +# END LICENSE BLOCK =head1 NAME RT::CurrentUser - an RT object representing the current user =head1 SYNOPSIS - use RT::CurrentUser; - - # laod - my $current_user = new RT::CurrentUser; - $current_user->Load(...); - # or - my $current_user = RT::CurrentUser->new( $user_obj ); - # or - my $current_user = RT::CurrentUser->new( $address || $name || $id ); - - # manipulation - $current_user->UserObj->SetName('new_name'); + use RT::CurrentUser =head1 DESCRIPTION -B subclass of L class. Used to define the current -user. You should pass an instance of this class to constructors of -many RT classes, then the instance used to check ACLs and localize -strings. =head1 METHODS -See also L for a list of methods this class has. -=head2 new +=begin testing + +ok (require RT::CurrentUser); -Returns new CurrentUser object. Unlike all other classes of RT it takes -either subclass of C class object or scalar value that is -passed to Load method. +=end testing =cut package RT::CurrentUser; +use RT::Record; use RT::I18N; use strict; -use warnings; +use vars qw/@ISA/; +@ISA= qw(RT::Record); -use base qw/RT::User/; +# {{{ sub _Init #The basic idea here is that $self->CurrentUser is always supposed # to be a CurrentUser object. but that's hard to do when we're trying to load # the CurrentUser object -sub _Init { - my $self = shift; - my $User = shift; - - $self->{'table'} = "Users"; - - if ( defined $User ) { - - if ( UNIVERSAL::isa( $User, 'RT::User' ) ) { - $self->LoadById( $User->id ); - } - elsif ( ref $User ) { - $RT::Logger->crit( - "RT::CurrentUser->new() called with a bogus argument: $User"); - } - else { - $self->Load( $User ); - } - } +sub _Init { + my $self = shift; + my $Name = shift; - $self->_BuildTableAttributes; + $self->{'table'} = "Users"; -} + if (defined($Name)) { + $self->Load($Name); + } + + $self->CurrentUser($self); -=head2 Create, Delete and Set* +} +# }}} -As stated above it's a subclass of L, but this class is read-only -and calls to these methods are illegal. Return 'permission denied' message -and log an error. - -=cut +# {{{ sub Create sub Create { my $self = shift; - $RT::Logger->error('RT::CurrentUser is read-only, RT::User for manipulation'); return (0, $self->loc('Permission Denied')); } +# }}} + +# {{{ sub Delete + sub Delete { my $self = shift; - $RT::Logger->error('RT::CurrentUser is read-only, RT::User for manipulation'); return (0, $self->loc('Permission Denied')); } -sub _Set { - my $self = shift; - $RT::Logger->error('RT::CurrentUser is read-only, RT::User for manipulation'); - return (0, $self->loc('Permission Denied')); -} +# }}} + +# {{{ sub UserObj =head2 UserObj -Returns the L object associated with this CurrentUser object. + Returns the RT::User object associated with this CurrentUser object. =cut sub UserObj { my $self = shift; - - my $user = RT::User->new( $self ); - unless ( $user->LoadById( $self->Id ) ) { - $RT::Logger->error( - $self->loc("Couldn't load [_1] from the users database.\n", $self->Id) - ); + + unless ($self->{'UserObj'}) { + use RT::User; + $self->{'UserObj'} = RT::User->new($self); + unless ($self->{'UserObj'}->Load($self->Id)) { + $RT::Logger->err($self->loc("Couldn't load [_1] from the users database.\n", $self->Id)); + } + } - return $user; + return ($self->{'UserObj'}); } +# }}} -sub _CoreAccessible { - { - Name => { 'read' => 1 }, - Gecos => { 'read' => 1 }, - RealName => { 'read' => 1 }, - Lang => { 'read' => 1 }, - Password => { 'read' => 0, 'write' => 0 }, - EmailAddress => { 'read' => 1, 'write' => 0 } - }; - +# {{{ sub PrincipalObj + +=head2 PrincipalObj + + Returns this user's principal object. this is just a helper routine for + $self->UserObj->PrincipalObj + +=cut + +sub PrincipalObj { + my $self = shift; + return($self->UserObj->PrincipalObj); } + +# }}} + + +# {{{ sub PrincipalId + +=head2 PrincipalId + + Returns this user's principal Id. this is just a helper routine for + $self->UserObj->PrincipalId + +=cut + +sub PrincipalId { + my $self = shift; + return($self->UserObj->PrincipalId); +} + + +# }}} + + +# {{{ sub _Accessible +sub _Accessible { + my $self = shift; + my %Cols = ( + Name => 'read', + Gecos => 'read', + RealName => 'read', + Password => 'neither', + EmailAddress => 'read', + Privileged => 'read', + IsAdministrator => 'read' + ); + return($self->SUPER::_Accessible(@_, %Cols)); +} +# }}} + +# {{{ sub LoadByEmail + +=head2 LoadByEmail + +Loads a User into this CurrentUser object. +Takes the email address of the user to load. + +=cut + +sub LoadByEmail { + my $self = shift; + my $identifier = shift; + + $identifier = RT::User::CanonicalizeEmailAddress(undef, $identifier); + + $self->LoadByCol("EmailAddress",$identifier); + +} +# }}} + +# {{{ sub LoadByGecos + =head2 LoadByGecos Loads a User into this CurrentUser object. @@ -188,128 +199,171 @@ Takes a unix username as its only argument. sub LoadByGecos { my $self = shift; - return $self->LoadByCol( "Gecos", shift ); + my $identifier = shift; + + $self->LoadByCol("Gecos",$identifier); + } +# }}} + +# {{{ sub LoadByName =head2 LoadByName Loads a User into this CurrentUser object. Takes a Name. - =cut sub LoadByName { my $self = shift; - return $self->LoadByCol( "Name", shift ); + my $identifier = shift; + $self->LoadByCol("Name",$identifier); + } +# }}} -=head2 LanguageHandle - -Returns this current user's langauge handle. Should take a language -specification. but currently doesn't +# {{{ sub Load -=cut +=head2 Load -sub LanguageHandle { - my $self = shift; - if ( !defined $self->{'LangHandle'} - || !UNIVERSAL::can( $self->{'LangHandle'}, 'maketext' ) - || @_ ) - { - if ( my $lang = $self->Lang ) { - push @_, $lang; - } - elsif ( $self->id && ($self->id == ($RT::SystemUser->id||0) || $self->id == ($RT::Nobody->id||0)) ) { - # don't use ENV magic for system users - push @_, 'en'; - } +Loads a User into this CurrentUser object. +Takes either an integer (users id column reference) or a Name +The latter is deprecated. Instead, you should use LoadByName. +Formerly, this routine also took email addresses. - $self->{'LangHandle'} = RT::I18N->get_handle(@_); - } +=cut - # Fall back to english. - unless ( $self->{'LangHandle'} ) { - die "We couldn't get a dictionary. Ne mogu naidti slovar. No puedo encontrar dictionario."; - } - return $self->{'LangHandle'}; +sub Load { + my $self = shift; + my $identifier = shift; + + #if it's an int, load by id. otherwise, load by name. + if ($identifier !~ /\D/) { + $self->SUPER::LoadById($identifier); + } + else { + # This is a bit dangerous, we might get false authen if somebody + # uses ambigous userids or real names: + $self->LoadByCol("Name",$identifier); + } } -sub loc { - my $self = shift; - return '' if !defined $_[0] || $_[0] eq ''; +# }}} - my $handle = $self->LanguageHandle; +# {{{ sub IsPassword - if (@_ == 1) { - # pre-scan the lexicon hashes to return _AUTO keys verbatim, - # to keep locstrings containing '[' and '~' from tripping over Maketext - return $_[0] unless grep exists $_->{$_[0]}, @{ $handle->_lex_refs }; - } +=head2 IsPassword - return $handle->maketext(@_); -} +Takes a password as a string. Passes it off to IsPassword in this +user's UserObj. If it is the user's password and the user isn't +disabled, returns 1. -sub loc_fuzzy { - my $self = shift; - return '' if !defined $_[0] || $_[0] eq ''; +Otherwise, returns undef. - # XXX: work around perl's deficiency when matching utf8 data - return $_[0] if Encode::is_utf8($_[0]); +=cut - return $self->LanguageHandle->maketext_fuzzy( @_ ); +sub IsPassword { + my $self = shift; + my $value = shift; + + return ($self->UserObj->IsPassword($value)); } -=head2 CurrentUser +# }}} -Return the current currentuser object +# {{{ sub Privileged + +=head2 Privileged + +Returns true if the current user can be granted rights and be +a member of groups. =cut -sub CurrentUser { +sub Privileged { my $self = shift; - return($self); - + return ($self->UserObj->Privileged()); } -=head2 Authenticate +# }}} -Takes $password, $created and $nonce, and returns a boolean value -representing whether the authentication succeeded. -If both $nonce and $created are specified, validate $password against: +# {{{ sub HasRight - encode_base64(sha1( - $nonce . - $created . - sha1_hex( "$username:$realm:$server_pass" ) - )) +=head2 HasRight -where $server_pass is the md5_hex(password) digest stored in the -database, $created is in ISO time format, and $nonce is a random -string no longer than 32 bytes. +calls $self->UserObj->HasRight with the arguments passed in =cut -sub Authenticate { - my ($self, $password, $created, $nonce, $realm) = @_; +sub HasRight { + my $self = shift; + return ($self->UserObj->HasRight(@_)); +} + +# }}} + +# {{{ Localization + +=head2 LanguageHandle + +Returns this current user's langauge handle. Should take a language +specification. but currently doesn't - require Digest::MD5; - require Digest::SHA1; - require MIME::Base64; +=begin testing + +ok (my $cu = RT::CurrentUser->new('root')); +ok (my $lh = $cu->LanguageHandle); +ok ($lh != undef); +ok ($lh->isa('Locale::Maketext')); +ok ($cu->loc('TEST_STRING') eq "Concrete Mixer", "Localized TEST_STRING into English"); +ok ($lh = $cu->LanguageHandle('fr')); +ok ($cu->loc('Before') eq "Avant", "Localized TEST_STRING into Frenc"); + +=end testing + +=cut - my $username = $self->UserObj->Name or return; - my $server_pass = $self->UserObj->__Value('Password') or return; - my $auth_digest = MIME::Base64::encode_base64(Digest::SHA1::sha1( - $nonce . - $created . - Digest::MD5::md5_hex("$username:$realm:$server_pass") - )); +sub LanguageHandle { + my $self = shift; + if ((!defined $self->{'LangHandle'}) || + (!UNIVERSAL::can($self->{'LangHandle'}, 'maketext')) || + (@_)) { + $self->{'LangHandle'} = RT::I18N->get_handle(@_); + } + # Fall back to english. + unless ($self->{'LangHandle'}) { + die "We couldn't get a dictionary. Nye mogu naidti slovar. No puedo encontrar dictionario."; + } + return ($self->{'LangHandle'}); +} - chomp($password); - chomp($auth_digest); +sub loc { + my $self = shift; + return '' if $_[0] eq ''; + + my $handle = $self->LanguageHandle; + + if (@_ == 1) { + # pre-scan the lexicon hashes to return _AUTO keys verbatim, + # to keep locstrings containing '[' and '~' from tripping over Maketext + return $_[0] unless grep { exists $_->{$_[0]} } @{ $handle->_lex_refs }; + } + + return $handle->maketext(@_); +} + +sub loc_fuzzy { + my $self = shift; + return '' if $_[0] eq ''; + + # XXX: work around perl's deficiency when matching utf8 data + return $_[0] if Encode::is_utf8($_[0]); + my $result = $self->LanguageHandle->maketext_fuzzy(@_); - return ($password eq $auth_digest); + return($result); } +# }}} eval "require RT::CurrentUser_Vendor"; die $@ if ($@ && $@ !~ qr{^Can't locate RT/CurrentUser_Vendor.pm}); @@ -317,3 +371,4 @@ eval "require RT::CurrentUser_Local"; die $@ if ($@ && $@ !~ qr{^Can't locate RT/CurrentUser_Local.pm}); 1; +