%# 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 }}} <%INIT> # Roll back any dangling transactions from a previous failed connection $RT::Handle->ForceRollback() if $RT::Handle->TransactionDepth; if ($RT::StatementLog) { $RT::Handle->ClearSQLStatementLog; $RT::Handle->LogSQLStatements(1); } local *session unless $m->is_subrequest; # avoid reentrancy, as suggested by masonbook # Disable AutoFlush using an attribute if ( $m->request_comp->attr_exists('AutoFlush') ) { $m->autoflush( $m->request_comp->attr('AutoFlush') ); } %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::is_utf8($_) ? $_ : Encode::decode( utf8 => $_, Encode::FB_PERLQQ ) : ( $type eq 'ARRAY' ) ? [ map { ( ref($_) or Encode::is_utf8($_) ) ? $_ : Encode::decode( utf8 => $_, Encode::FB_PERLQQ ) } @$_ ] : ( $type eq 'HASH' ) ? { map { ( ref($_) or Encode::is_utf8($_) ) ? $_ : Encode::decode( utf8 => $_, Encode::FB_PERLQQ ) } %$_ } : $_ } %ARGS; # Latter in the code we use # $m->comp( { base_comp => $m->request_comp }, $m->fetch_next, %ARGS ); # instead of $m->call_next to avoid problems with UTF8 keys in arguments. # The call_next method pass through original arguments and if you have # an argument with unicode key then in a next component you'll get two # records in the args hash: one with key without UTF8 flag and another # with the flag, which may result into errors. "{ base_comp => $m->request_comp }" # is copied from mason's source to get the same results as we get from # call_next method, this feature is not documented, so we just leave it # here to avoid possible side effects. # This code canonicalizes time inputs in hours into minutes foreach my $field ( keys %ARGS ) { next unless $field =~ /^(.*)-TimeUnits$/i && $ARGS{$1}; my $local = $1; $ARGS{$local} =~ s{\b (?: (\d+) \s+ )? (\d+)/(\d+) \b} {($1 || 0) + $3 ? $2 / $3 : 0}xe; if ( $ARGS{$field} && $ARGS{$field} =~ /hours/i ) { $ARGS{$local} *= 60; } delete $ARGS{$field}; } $m->{'rt_base_time'} = [ Time::HiRes::gettimeofday() ]; $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 =~ $RT::WebNoAuthRegex ) { $m->comp( { base_comp => $m->request_comp }, $m->fetch_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('RT_System') ); 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' ) { $m->comp( '/Elements/Callback', %ARGS, _CallbackName => 'NewUser' ); 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('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 $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 $pass ) { $session{'CurrentUser'} = RT::CurrentUser->new(); $session{'CurrentUser'}->Load($user); unless ( $session{'CurrentUser'}->id && $session{'CurrentUser'}->IsPassword($pass) ) { delete $session{'CurrentUser'}; $RT::Logger->error("FAILED LOGIN for $user from $ENV{'REMOTE_ADDR'}"); $m->comp( '/Elements/Login', %ARGS, Error => loc('Your username or password is incorrect') ); $m->comp( '/Elements/Callback', %ARGS, _CallbackName => 'FailedLogin' ); $m->abort; } else { $RT::Logger->info( "Successful login for $user from $ENV{'REMOTE_ADDR'}"); $m->comp( '/Elements/Callback', %ARGS, _CallbackName => 'SuccessfulLogin' ); } } # 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 ( not $session{'CurrentUser'}->Privileged ) { # if the user is trying to access a ticket, redirect them if ( $m->request_comp->path =~ '^(/+)Ticket/Display.html' and $ARGS{'id'} ) { RT::Interface::Web::Redirect($RT::WebURL."SelfService/Display.html?id=".$ARGS{'id'}); } # otherwise, drop the user at the SelfService default page elsif ( $m->base_comp->path !~ '^(/+)SelfService/' ) { RT::Interface::Web::Redirect($RT::WebURL."SelfService/"); } else { $m->comp( { base_comp => $m->request_comp }, $m->fetch_next, %ARGS); } } else { $m->comp( { base_comp => $m->request_comp }, $m->fetch_next, %ARGS); } } # If we have no credentials else { $m->comp( '/Elements/Login', %ARGS ); $m->abort(); } if ($RT::StatementLog) { my @log = $RT::Handle->SQLStatementLog; $RT::Handle->ClearSQLStatementLog; for my $stmt (@log) { my ( $time, $sql, $bind, $duration ) = @{$stmt}; my @bind; if ( ref $bind ) { @bind = @{$bind}; } else { # Older DBIx-SB $duration = $bind; } $RT::Logger->log( level => $RT::StatementLog, message => "SQL(" . sprintf( "%.2f", $duration ) . "s): $sql;" . ( @bind ? " [ bound values: @{[map{qq|'$_'|} @bind]} ]" : "" ) ); } } <& /Elements/Footer, %ARGS &> <%ARGS> $user => undef $pass => undef $menu => undef