192
192
SendSessionCookie();
193
193
$HTML::Mason::Commands::session{'CurrentUser'} = RT::CurrentUser->new() unless _UserLoggedIn();
195
# Process session-related callbacks before any auth attempts
196
$HTML::Mason::Commands::m->callback( %$ARGS, CallbackName => 'Session', CallbackPage => '/autohandler' );
198
MaybeRejectPrivateComponentRequest();
195
200
MaybeShowNoAuthPage($ARGS);
197
202
AttemptExternalAuth($ARGS) if RT->Config->Get('WebExternalAuthContinuous') or not _UserLoggedIn();
204
209
unless ( _UserLoggedIn() ) {
207
# If the user is logging in, let's authenticate
208
if ( defined $ARGS->{user} && defined $ARGS->{pass} ) {
209
AttemptPasswordAuthentication($ARGS);
211
# if no credentials then show him login page
212
$HTML::Mason::Commands::m->comp( '/Elements/Login', %$ARGS );
213
$HTML::Mason::Commands::m->abort;
212
# Authenticate if the user is trying to login via user/pass query args
213
my ($authed, $msg) = AttemptPasswordAuthentication($ARGS);
216
my $m = $HTML::Mason::Commands::m;
218
# REST urls get a special 401 response
219
if ($m->request_comp->path =~ '^/REST/\d+\.\d+/') {
220
$HTML::Mason::Commands::r->content_type("text/plain");
221
$m->error_format("text");
222
$m->out("RT/$RT::VERSION 401 Credentials required\n");
223
$m->out("\n$msg\n") if $msg;
226
# Specially handle /index.html so that we get a nicer URL
227
elsif ( $m->request_comp->path eq '/index.html' ) {
228
my $next = SetNextPage(RT->Config->Get('WebURL'));
229
$m->comp('/NoAuth/Login.html', next => $next, actions => [$msg]);
233
TangentForLogin(results => ($msg ? LoginError($msg) : undef));
266
=head2 LoginError ERROR
268
Pushes a login error into the Actions session store and returns the hash key.
274
my $key = Digest::MD5::md5_hex( rand(1024) );
275
push @{ $HTML::Mason::Commands::session{"Actions"}->{$key} ||= [] }, $new;
276
$HTML::Mason::Commands::session{'i'}++;
280
=head2 SetNextPage [PATH]
282
Intuits and stashes the next page in the sesssion hash. If PATH is
283
specified, uses that instead of the value of L<IntuitNextPage()>. Returns
289
my $next = shift || IntuitNextPage();
290
my $hash = Digest::MD5::md5_hex($next . $$ . rand(1024));
292
$HTML::Mason::Commands::session{'NextPage'}->{$hash} = $next;
293
$HTML::Mason::Commands::session{'i'}++;
300
=head2 TangentForLogin [HASH]
302
Redirects to C</NoAuth/Login.html>, setting the value of L<IntuitNextPage> as
303
the next page. Optionally takes a hash which is dumped into query params.
307
sub TangentForLogin {
308
my $hash = SetNextPage();
309
my %query = (@_, next => $hash);
310
my $login = RT->Config->Get('WebURL') . 'NoAuth/Login.html?';
311
$login .= $HTML::Mason::Commands::m->comp('/Elements/QueryString', %query);
315
=head2 TangentForLoginWithError ERROR
317
Localizes the passed error message, stashes it with L<LoginError> and then
318
calls L<TangentForLogin> with the appropriate results key.
322
sub TangentForLoginWithError {
323
my $key = LoginError(HTML::Mason::Commands::loc(@_));
324
TangentForLogin( results => $key );
327
=head2 IntuitNextPage
329
Attempt to figure out the path to which we should return the user after a
330
tangent. The current request URL is used, or failing that, the C<WebURL>
331
configuration variable.
338
# This includes any query parameters. Redirect will take care of making
339
# it an absolute URL.
340
if ($ENV{'REQUEST_URI'}) {
341
$req_uri = $ENV{'REQUEST_URI'};
343
# collapse multiple leading slashes so the first part doesn't look like
344
# a hostname of a schema-less URI
345
$req_uri =~ s{^/+}{/};
348
my $next = defined $req_uri ? $req_uri : RT->Config->Get('WebURL');
351
my $uri = URI->new($next);
353
# You get undef scheme with a relative uri like "/Search/Build.html"
354
unless (!defined($uri->scheme) || $uri->scheme eq 'http' || $uri->scheme eq 'https') {
355
$next = RT->Config->Get('WebURL');
358
# Make sure we're logging in to the same domain
359
# You can get an undef authority with a relative uri like "index.html"
360
my $uri_base_url = URI->new(RT->Config->Get('WebBaseURL'));
361
unless (!defined($uri->authority) || $uri->authority eq $uri_base_url->authority) {
362
$next = RT->Config->Get('WebURL');
242
368
=head2 MaybeShowInstallModePage
244
370
This function, called exclusively by RT's autohandler, dispatches
279
405
return unless $m->base_comp->path =~ RT->Config->Get('WebNoAuthRegex');
407
# Don't show the login page to logged in users
408
Redirect(RT->Config->Get('WebURL'))
409
if $m->base_comp->path eq '/NoAuth/Login.html' and _UserLoggedIn();
281
411
# If it's a noauth file, don't ask for auth.
282
412
SendSessionCookie();
283
413
$m->comp( { base_comp => $m->request_comp }, $m->fetch_next, %$ARGS );
417
=head2 MaybeRejectPrivateComponentRequest
419
This function will reject calls to private components, like those under
420
C</Elements>. If the requested path is a private component then we will
421
abort with a C<403> error.
425
sub MaybeRejectPrivateComponentRequest {
426
my $m = $HTML::Mason::Commands::m;
427
my $path = $m->request_comp->path;
429
# We do not check for dhandler here, because requesting our dhandlers
430
# directly is okay. Mason will invoke the dhandler with a dhandler_arg of
436
_elements | # mobile UI
438
autohandler | # requesting this directly is suspicious
440
( $ | / ) # trailing slash or end of path
287
448
=head2 ShowRequestedPage \%ARGS
289
450
This function, called exclusively by RT's autohandler, dispatches
381
542
# we failed to successfully create the user. abort abort abort.
382
543
delete $HTML::Mason::Commands::session{'CurrentUser'};
383
$m->comp( '/Elements/Login', %$ARGS, Error => HTML::Mason::Commands::loc( 'Cannot create user: [_1]', $msg ) )
384
if RT->Config->Get('WebFallbackToInternalAuth');;
545
if (RT->Config->Get('WebFallbackToInternalAuth')) {
546
TangentForLoginWithError('Cannot create user: [_1]', $msg);
393
557
$user = $orig_user;
395
559
if ( RT->Config->Get('WebExternalOnly') ) {
396
$m->comp( '/Elements/Login', %$ARGS, Error => HTML::Mason::Commands::loc('You are not an authorized user') );
560
TangentForLoginWithError('You are not an authorized user');
400
563
} elsif ( RT->Config->Get('WebFallbackToInternalAuth') ) {
401
564
unless ( defined $HTML::Mason::Commands::session{'CurrentUser'} ) {
402
565
# XXX unreachable due to prior defaulting in HandleRequest (check c34d108)
403
$m->comp( '/Elements/Login', %$ARGS, Error => HTML::Mason::Commands::loc('You are not an authorized user') );
566
TangentForLoginWithError('You are not an authorized user');
423
587
unless ( $user_obj->id && $user_obj->IsPassword( $ARGS->{pass} ) ) {
424
588
$RT::Logger->error("FAILED LOGIN for @{[$ARGS->{user}]} from $ENV{'REMOTE_ADDR'}");
425
$m->comp( '/Elements/Login', %$ARGS, Error => HTML::Mason::Commands::loc('Your username or password is incorrect'), );
426
589
$m->callback( %$ARGS, CallbackName => 'FailedLogin', CallbackPage => '/autohandler' );
430
$RT::Logger->info("Successful login for @{[$ARGS->{user}]} from $ENV{'REMOTE_ADDR'}");
431
InstantiateNewSession();
432
$HTML::Mason::Commands::session{'CurrentUser'} = $user_obj;
433
$m->callback( %$ARGS, CallbackName => 'SuccessfulLogin', CallbackPage => '/autohandler' );
590
return (0, HTML::Mason::Commands::loc('Your username or password is incorrect'));
593
$RT::Logger->info("Successful login for @{[$ARGS->{user}]} from $ENV{'REMOTE_ADDR'}");
595
# It's important to nab the next page from the session before we blow
597
my $next = delete $HTML::Mason::Commands::session{'NextPage'}->{$ARGS->{'next'} || ''};
599
InstantiateNewSession();
600
$HTML::Mason::Commands::session{'CurrentUser'} = $user_obj;
603
$m->callback( %$ARGS, CallbackName => 'SuccessfulLogin', CallbackPage => '/autohandler' );
605
# Really the only time we don't want to redirect here is if we were
606
# passed user and pass as query params in the URL.
610
elsif ($ARGS->{'next'}) {
611
# Invalid hash, but still wants to go somewhere, take them to /
612
Redirect(RT->Config->Get('WebURL'));
615
return (1, HTML::Mason::Commands::loc('Logged in'));
436
619
=head2 LoadSessionFromCookie
497
680
untie $HTML::Mason::Commands::session;
498
681
my $uri = URI->new($redir_to);
499
682
my $server_uri = URI->new( RT->Config->Get('WebURL') );
684
# Make relative URIs absolute from the server host and scheme
685
$uri->scheme($server_uri->scheme) if not defined $uri->scheme;
686
if (not defined $uri->host) {
687
$uri->host($server_uri->host);
688
$uri->port($server_uri->port);
501
691
# If the user is coming in via a non-canonical
502
692
# hostname, don't redirect them to the canonical host,
640
830
$type ||= "application/octet-stream";
833
# CGI.pm version 3.51 and 3.52 bang charset=iso-8859-1 onto our JS
834
# since we don't specify a charset
835
if ( $type =~ m{application/javascript} &&
836
$type !~ m{charset=([\w-]+)$} ) {
837
$type .= "; charset=utf-8";
642
839
$HTML::Mason::Commands::r->content_type($type);
643
open my $fh, "<$file" or die "couldn't open file: $!";
840
open( my $fh, '<', $file ) or die "couldn't open file: $!";
646
843
local $/ = \16384;
684
881
# Check for plaintext sig
685
882
return '' if not $html and $content =~ /^(--)?\Q$sig\E$/;
687
# Check for html-formatted sig
688
RT::Interface::Web::EscapeUTF8( \$sig );
884
# Check for html-formatted sig; we don't use EscapeUTF8 here
885
# because we want to precisely match the escaping that FCKEditor
886
# uses. see also 311223f5, which fixed this for 4.0
691
893
and $content =~ m{^(?:<p>)?(--)?\Q$sig\E(?:</p>)?$}s;
2097
2299
return ( _load_container_object( $obj_type, $obj_id ), $search_id );
2100
eval "require RT::Interface::Web_Vendor";
2101
die $@ if ( $@ && $@ !~ qr{^Can't locate RT/Interface/Web_Vendor.pm} );
2102
eval "require RT::Interface::Web_Local";
2103
die $@ if ( $@ && $@ !~ qr{^Can't locate RT/Interface/Web_Local.pm} );
2302
RT::Base->_ImportOverlays();