%# BEGIN LICENSE BLOCK
%#
%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
%#
%# (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
%# 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.
%#
%# 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.
%#
%#
%# END LICENSE BLOCK
<%INIT>
# Roll back any dangling transactions from a previous failed connection
$RT::Handle->ForceRollback() if $RT::Handle->TransactionDepth;
local *session unless $m->is_subrequest; # avoid reentrancy, as suggested by masonbook
%ARGS = map {
# if they've passed multiple values, they'll be an array. if they've
# passed just one, a scalar whatever they are, mark them as utf8
my $type = ref($_);
(!$type)
? Encode::decode(utf8 => $_, Encode::FB_PERLQQ) :
($type eq 'ARRAY')
? [ map { ref($_) ? $_ : Encode::decode(utf8 => $_, Encode::FB_PERLQQ) } @$_ ] :
($type eq 'HASH')
? { map { ref($_) ? $_ : Encode::decode(utf8 => $_, Encode::FB_PERLQQ) } %$_ } : $_
} %ARGS;
if ($ARGS{'Debug'}) {
require Time::HiRes;
$m->{'rt_base_time'} = [Time::HiRes::gettimeofday()];
}
else {
$m->{'rt_base_time'} = time;
}
$m->comp('/Elements/SetupSessionCookie', %ARGS);
unless ($session{'CurrentUser'} && $session{'CurrentUser'}->Id) {
$session{'CurrentUser'} = RT::CurrentUser->new();
}
# Set the proper encoding for the current language handle
$r->content_type("text/html; charset=utf-8");
# If it's a noauth file, don't ask for auth.
if ($m->base_comp->path =~ '^/+NoAuth/' ||
$m->base_comp->path =~ '^/+REST/\d+\.\d+/NoAuth/')
{
$m->call_next(%ARGS);
$m->abort();
}
# If RT is configured for external auth, let's go through and get REMOTE_USER
elsif ( $RT::WebExternalAuth ) {
# do we actually have a REMOTE_USER equivlent?
if ( RT::Interface::Web::WebCanonicalizeInfo() ) {
my $orig_user = $user;
$user = RT::Interface::Web::WebCanonicalizeInfo();
$session{'CurrentUser'} = RT::CurrentUser->new();
my $load_method = $RT::WebExternalGecos ? 'LoadByGecos' : 'Load';
if ($^O eq 'MSWin32' and $RT::WebExternalGecos) {
my $NodeName = Win32::NodeName();
$user =~ s/^\Q$NodeName\E\\//i;
}
$session{'CurrentUser'}->$load_method($user);
if ($RT::WebExternalAuto and !$session{'CurrentUser'}->Id() ) {
# Create users on-the-fly
my $UserObj = RT::User->new(RT::CurrentUser->new('root'));
my ($val, $msg) = $UserObj->Create(
%{ref($RT::AutoCreate) ? $RT::AutoCreate : {}},
Name => $user,
Gecos => $user,
);
if ($val) {
# now get user specific information, to better create our user.
my $new_user_info = RT::Interface::Web::WebExternalAutoInfo($user);
# set the attributes that have been defined.
# FIXME: this is a horrible kludge. I'm sure there's something cleaner
foreach my $attribute ('Name', 'Comments', 'Signature', 'EmailAddress',
'PagerEmailAddress', 'FreeformContactInfo',
'Organization', 'Disabled', 'Privileged',
'RealName', 'NickName', 'Lang', 'EmailEncoding',
'WebEncoding', 'ExternalContactInfoId',
'ContactInfoSystem', 'ExternalAuthId', 'Gecos',
'HomePhone', 'WorkPhone', 'MobilePhone',
'PagerPhone', 'Address1', 'Address2', 'City',
'State', 'Zip', 'Country') {
my $method = "Set$attribute";
$UserObj->$method($new_user_info->{$attribute})
if( defined $new_user_info->{$attribute} );
}
$session{'CurrentUser'}->Load($user);
}
else {
# we failed to successfully create the user. abort abort abort.
delete $session{'CurrentUser'};
$m->abort() unless $RT::WebFallbackToInternalAuth;
$m->comp('/Elements/Login', %ARGS,
Error=> loc('Cannot create user: [_1]', $msg));
}
}
unless ( $session{'CurrentUser'}->Id() ) {
delete $session{'CurrentUser'};
$user = $orig_user;
if ( $RT::WebExternalOnly ) {
$m->comp('/Elements/Login', %ARGS,
Error=> loc('You are not an authorized user'));
$m->abort();
}
}
}
elsif ($RT::WebFallbackToInternalAuth) {
unless (defined($session{'CurrentUser'})) {
$m->comp('/Elements/Login', %ARGS,
Error=> loc('XXX CHANGEME You are not an authorized user'));
$m->abort();
}
} else {
# WebExternalAuth is set, but we don't have a REMOTE_USER. abort
delete $session{'CurrentUser'} if defined $session{'CurrentUser'};
}
}
delete $session{'CurrentUser'}
unless $session{'CurrentUser'} and defined $session{'CurrentUser'}->Id;
# Process per-page authentication callbacks
$m->comp('/Elements/Callback', %ARGS, _CallbackName => 'Auth');
# If the user is logging in, let's authenticate
if (!$session{'CurrentUser'} && defined ($user) && defined ($auth_digest || $pass) ){
$session{'CurrentUser'} = RT::CurrentUser->new();
$session{'CurrentUser'}->Load($user);
# check against reused nonces
my $nonce_cache;
if ($auth_nonce) {
require Cache::FileCache;
$nonce_cache = Cache::FileCache->new({
namespace => 'RT-Nonces',
default_expires_in => 7200,
auto_purge_interval => 1200,
});
$auth_nonce = substr($auth_nonce, 0, 32);
undef $auth_nonce if $nonce_cache->get( $auth_nonce );
}
if (!$session{'CurrentUser'}->id() ||
!$session{'CurrentUser'}->Authenticate( $auth_digest || $pass, $auth_created, $auth_nonce ))
{
delete $session{'CurrentUser'};
$m->comp('/Elements/Login', %ARGS,
Error => loc('Your username or password is incorrect'));
$m->abort();
}
# remember issued nonces
$nonce_cache->set( $auth_nonce, 1 ) if $auth_nonce;
}
# If we've got credentials, let's serve the file up.
if ( (defined $session{'CurrentUser'}) and
( $session{'CurrentUser'}->Id) ) {
# Process per-page global callbacks
$m->comp('/Elements/Callback', %ARGS);
# If the user isn't privileged, they can only see SelfService
if ((! $session{'CurrentUser'}->Privileged) and
($m->base_comp->path !~ '^(/+)SelfService/') ) {
$m->comp('/SelfService/index.html');
$m->abort();
}
else {
$m->call_next(%ARGS);
}
}
# If we have no credentials
else {
$m->comp('/Elements/Login', %ARGS);
$m->abort();
}
</%INIT>
<& /Elements/Footer, %ARGS &>
<%ARGS>
$user => undef
$pass => undef
$menu => undef
$auth_digest => undef
$auth_nonce => undef
$auth_created => undef
</%ARGS>