diff options
Diffstat (limited to 'rt/html/autohandler')
-rw-r--r-- | rt/html/autohandler | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/rt/html/autohandler b/rt/html/autohandler new file mode 100644 index 000000000..909b922c8 --- /dev/null +++ b/rt/html/autohandler @@ -0,0 +1,331 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (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]} ]" : "" + ) + ); + } +} + +</%INIT> +<& /Elements/Footer, %ARGS &> +<%ARGS> +$user => undef +$pass => undef +$menu => undef +</%ARGS> |