X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=rt%2Flib%2FRT%2FCurrentUser.pm;h=9d406cc05bf4f766c3c9218ae5ac4fa0860864eb;hb=8103c1fc1b2c27a6855feadf26f91b980a54bc52;hp=6997ddbac9d1cbbe273a8d9fce44a7fdb8a7d0a6;hpb=3ef62a0570055da710328937e7f65dbb2c027c62;p=freeside.git diff --git a/rt/lib/RT/CurrentUser.pm b/rt/lib/RT/CurrentUser.pm index 6997ddbac..9d406cc05 100755 --- a/rt/lib/RT/CurrentUser.pm +++ b/rt/lib/RT/CurrentUser.pm @@ -1,7 +1,50 @@ -# $Header: /home/cvs/cvsroot/freeside/rt/lib/RT/CurrentUser.pm,v 1.1 2002-08-12 06:17:07 ivan Exp $ -# (c) 1996-1999 Jesse Vincent -# This software is redistributable under the terms of the GNU GPL - +# BEGIN BPS TAGGED BLOCK {{{ +# +# COPYRIGHT: +# +# This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC +# +# +# (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., 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: +# +# (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 NAME RT::CurrentUser - an RT object representing the current user @@ -19,7 +62,6 @@ =begin testing -ok (require RT::TestHarness); ok (require RT::CurrentUser); =end testing @@ -28,9 +70,12 @@ ok (require RT::CurrentUser); package RT::CurrentUser; + use RT::Record; -@ISA= qw(RT::Record); +use RT::I18N; +use strict; +use base qw/RT::Record/; # {{{ sub _Init @@ -38,17 +83,30 @@ use RT::Record; # 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 $Name = shift; +sub _Init { + my $self = shift; + my $User = shift; - $self->{'table'} = "Users"; + $self->{'table'} = "Users"; - if (defined($Name)) { - $self->Load($Name); - } - - $self->_MyCurrentUser($self); + if ( defined($User) ) { + + if ( UNIVERSAL::isa( $User, 'RT::User' ) + || UNIVERSAL::isa( $User, 'RT::CurrentUser' ) ) + { + $self->Load( $User->id ); + + } + elsif ( ref($User) ) { + $RT::Logger->crit( + "RT::CurrentUser->new() called with a bogus argument: $User"); + } + else { + $self->Load($User); + } + } + + $self->_BuildTableAttributes(); } # }}} @@ -56,7 +114,8 @@ sub _Init { # {{{ sub Create sub Create { - return (0, 'Permission Denied'); + my $self = shift; + return (0, $self->loc('Permission Denied')); } # }}} @@ -64,7 +123,8 @@ sub Create { # {{{ sub Delete sub Delete { - return (0, 'Permission Denied'); + my $self = shift; + return (0, $self->loc('Permission Denied')); } # }}} @@ -80,31 +140,65 @@ sub Delete { sub UserObj { my $self = shift; - unless ($self->{'UserObj'}) { use RT::User; - $self->{'UserObj'} = RT::User->new($self); - unless ($self->{'UserObj'}->Load($self->Id)) { - $RT::Logger->err("Couldn't load ".$self->Id. "from the users database.\n"); + my $user = RT::User->new($self); + + unless ($user->Load($self->Id)) { + $RT::Logger->err($self->loc("Couldn't load [_1] from the users database.\n", $self->Id)); } - - } - return ($self->{'UserObj'}); + return ($user); +} +# }}} + +# {{{ 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 _CoreAccessible { + { + Name => { 'read' => 1 }, + Gecos => { 'read' => 1 }, + RealName => { 'read' => 1 }, + Lang => { 'read' => 1 }, + Password => { 'read' => 0, 'write' => 0 }, + EmailAddress => { 'read' => 1, 'write' => 0 } + }; + } # }}} @@ -120,6 +214,8 @@ Takes the email address of the user to load. sub LoadByEmail { my $self = shift; my $identifier = shift; + + $identifier = RT::User::CanonicalizeEmailAddress(undef, $identifier); $self->LoadByCol("EmailAddress",$identifier); @@ -150,6 +246,7 @@ sub LoadByGecos { Loads a User into this CurrentUser object. Takes a Name. + =cut sub LoadByName { @@ -179,6 +276,11 @@ sub Load { if ($identifier !~ /\D/) { $self->SUPER::LoadById($identifier); } + + elsif (UNIVERSAL::isa($identifier,"RT::User")) { + # DWIM if they pass a user in + $self->SUPER::LoadById($identifier->Id); + } else { # This is a bit dangerous, we might get false authen if somebody # uses ambigous userids or real names: @@ -225,46 +327,155 @@ sub Privileged { # }}} -# {{{ Convenient ACL methods -=head2 HasQueueRight +# {{{ sub HasRight + +=head2 HasRight -calls $self->UserObj->HasQueueRight with the arguments passed in +calls $self->UserObj->HasRight with the arguments passed in =cut -sub HasQueueRight { - my $self = shift; - return ($self->UserObj->HasQueueRight(@_)); +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 + +=begin testing + +ok (my $cu = RT::CurrentUser->new('root')); +ok (my $lh = $cu->LanguageHandle('en-us')); +ok (defined $lh); +ok ($lh->isa('Locale::Maketext')); +is ($cu->loc('TEST_STRING'), "Concrete Mixer", "Localized TEST_STRING into English"); +ok ($lh = $cu->LanguageHandle('fr')); +SKIP: { + skip "fr locale is not loaded", 1 unless grep $_ eq 'fr', @RT::LexiconLanguages; + is ($cu->loc('Before'), "Avant", "Localized TEST_STRING into Frenc"); } -=head2 HasSystemRight +=end testing -calls $self->UserObj->HasSystemRight with the arguments passed in +=cut -=cut +sub LanguageHandle { + my $self = shift; + if ( ( !defined $self->{'LangHandle'} ) + || ( !UNIVERSAL::can( $self->{'LangHandle'}, 'maketext' ) ) + || (@_) ) { + if ( !$RT::SystemUser or ($self->id || 0) == $RT::SystemUser->id() ) { + @_ = qw(en-US); + } + + elsif ( $self->Lang ) { + push @_, $self->Lang; + } + $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'} ); +} + +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 }; + } -sub HasSystemRight { - my $self = shift; - return ($self->UserObj->HasSystemRight(@_)); + return $handle->maketext(@_); +} + +sub loc_fuzzy { + my $self = shift; + return '' if (!$_[0] || $_[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($result); } # }}} -# {{{ sub HasRight -=head2 HasSystemRight +=head2 CurrentUser -calls $self->UserObj->HasRight with the arguments passed in +Return the current currentuser object =cut -sub HasRight { - my $self = shift; - return ($self->UserObj->HasRight(@_)); +sub CurrentUser { + my $self = shift; + return($self); + +} + +=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: + + encode_base64(sha1( + $nonce . + $created . + sha1_hex( "$username:$realm:$server_pass" ) + )) + +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. + +=cut + +sub Authenticate { + my ($self, $password, $created, $nonce, $realm) = @_; + + require Digest::MD5; + require Digest::SHA1; + require MIME::Base64; + + 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") + )); + + chomp($password); + chomp($auth_digest); + + return ($password eq $auth_digest); } # }}} + +eval "require RT::CurrentUser_Vendor"; +die $@ if ($@ && $@ !~ qr{^Can't locate RT/CurrentUser_Vendor.pm}); +eval "require RT::CurrentUser_Local"; +die $@ if ($@ && $@ !~ qr{^Can't locate RT/CurrentUser_Local.pm}); + 1;