summaryrefslogtreecommitdiff
path: root/rt/html/autohandler
diff options
context:
space:
mode:
Diffstat (limited to 'rt/html/autohandler')
-rw-r--r--rt/html/autohandler331
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>