--- loncom/auth/lonlogin.pm 2021/09/27 02:49:36 1.185
+++ loncom/auth/lonlogin.pm 2021/11/03 01:04:02 1.193
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Login Screen
#
-# $Id: lonlogin.pm,v 1.185 2021/09/27 02:49:36 raeburn Exp $
+# $Id: lonlogin.pm,v 1.193 2021/11/03 01:04:02 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -38,6 +38,8 @@ use Apache::lonlocal;
use Apache::migrateuser();
use lib '/home/httpd/lib/perl/';
use LONCAPA qw(:DEFAULT :match);
+use URI::Escape;
+use HTML::Entities();
use CGI::Cookie();
sub handler {
@@ -47,23 +49,60 @@ sub handler {
(join('&',$ENV{'QUERY_STRING'},$env{'request.querystring'},
$ENV{'REDIRECT_QUERY_STRING'}),
['interface','username','domain','firsturl','localpath','localres',
- 'token','role','symb','iptoken','btoken','ltoken','linkkey','saml']);
- if (!defined($env{'form.firsturl'})) {
- &Apache::lonacc::get_posted_cgi($r,['firsturl']);
- }
- if (!defined($env{'form.firsturl'})) {
- if ($ENV{'REDIRECT_URL'} =~ m{^/+tiny/+$LONCAPA::match_domain/+\w+$}) {
- $env{'form.firsturl'} = $ENV{'REDIRECT_URL'};
- }
- }
- if (($env{'form.firsturl'} =~ m{^/+tiny/+$LONCAPA::match_domain/+\w+$}) &&
- (!$env{'form.ltoken'}) && (!$env{'form.linkkey'})) {
- &Apache::lonacc::get_posted_cgi($r,['linkkey']);
- }
+ 'token','role','symb','iptoken','btoken','ltoken','ttoken','linkkey',
+ 'saml','sso','retry']);
# -- check if they are a migrating user
if (defined($env{'form.token'})) {
- return &Apache::migrateuser::handler($r);
+ return &Apache::migrateuser::handler($r);
+ }
+
+ my $lonhost = $r->dir_config('lonHostID');
+ if ($env{'form.ttoken'}) {
+ my %info = &Apache::lonnet::tmpget($env{'form.ttoken'});
+ &Apache::lonnet::tmpdel($env{'form.ttoken'});
+ if ($info{'origurl'}) {
+ $env{'form.firsturl'} = $info{'origurl'};
+ }
+ if ($info{'ltoken'}) {
+ $env{'form.ltoken'} = $info{'ltoken'};
+ } elsif ($info{'linkprot'}) {
+ $env{'form.linkprot'} = $info{'linkprot'};
+ } elsif ($info{'linkkey'} ne '') {
+ $env{'form.linkkey'} = $info{'linkkey'};
+ }
+ } elsif (($env{'form.sso'}) || ($env{'form.retry'})) {
+ my $infotoken;
+ if ($env{'form.sso'}) {
+ $infotoken = $env{'form.sso'};
+ } else {
+ $infotoken = $env{'form.retry'};
+ }
+ my $data = &Apache::lonnet::reply('tmpget:'.$infotoken,$lonhost);
+ unless (($data=~/^error/) || ($data eq 'con_lost') ||
+ ($data eq 'no_such_host')) {
+ my %info = &decode_token($data);
+ foreach my $item (keys(%info)) {
+ $env{'form.'.$item} = $info{$item};
+ }
+ &Apache::lonnet::tmpdel($infotoken);
+ }
+ } else {
+ if (!defined($env{'form.firsturl'})) {
+ &Apache::lonacc::get_posted_cgi($r,['firsturl']);
+ }
+ if (!defined($env{'form.firsturl'})) {
+ if ($ENV{'REDIRECT_URL'} =~ m{^/+tiny/+$LONCAPA::match_domain/+\w+$}) {
+ $env{'form.firsturl'} = $ENV{'REDIRECT_URL'};
+ }
+ }
+ if (($env{'form.firsturl'} =~ m{^/+tiny/+$LONCAPA::match_domain/+\w+$}) &&
+ (!$env{'form.ltoken'}) && (!$env{'form.linkprot'}) && (!$env{'form.linkkey'})) {
+ &Apache::lonacc::get_posted_cgi($r,['linkkey']);
+ }
+ if ($env{'form.firsturl'} eq '/adm/logout') {
+ delete($env{'form.firsturl'});
+ }
}
# For "public user" - remove any exising "public" cookie, as user really wants to log-in
@@ -110,9 +149,6 @@ sub handler {
return OK;
}
- my $lonhost = $r->dir_config('lonHostID');
- $env{'form.firsturl'} =~ s/(`)/'/g;
-
# Check if browser sent a LON-CAPA load balancer cookie (and this is a balancer)
my ($found_server,$balancer_cookie) = &Apache::lonnet::check_for_balancer_cookie($r,1);
@@ -123,25 +159,39 @@ sub handler {
$protocol = 'http' if ($protocol ne 'https');
my $dest = '/adm/roles';
if ($env{'form.firsturl'} ne '') {
- $dest = $env{'form.firsturl'};
+ $dest = &HTML::Entities::encode($env{'form.firsturl'},'\'"<>&');
}
my %info = (
balcookie => $lonhost.':'.$balancer_cookie,
);
- if ($env{'form.ltoken'}) {
- my %link_info = &Apache::lonnet::tmpget($env{'form.ltoken'});
- if ($link_info{'linkprot'}) {
- $info{'linkprot'} = $link_info{'linkprot'};
- }
- &Apache::lonnet::tmpdel($env{'form.ltoken'});
- delete($env{'form.ltoken'});
- } elsif ($env{'form.linkkey'}) {
- $info{'linkkey'} = $env{'form.linkkey'};
- delete($env{'form.linkkey'});
+ if ($env{'form.role'}) {
+ $info{'role'} = $env{'form.role'};
+ }
+ if ($env{'form.symb'}) {
+ $info{'symb'} = $env{'form.symb'};
}
my $balancer_token = &Apache::lonnet::tmpput(\%info,$found_server);
- if ($balancer_token) {
- $dest .= (($dest=~/\?/)?'&;':'?') . 'btoken='.$balancer_token;
+ unless (($balancer_token eq 'con_lost') || ($balancer_token eq 'refused') ||
+ ($balancer_token eq 'unknown_cmd') || ($balancer_token eq 'no_such_host')) {
+ $dest .= (($dest=~/\?/)?'&':'?') . 'btoken='.$balancer_token;
+ }
+ if ($env{'form.firsturl'} =~ m{^/tiny/$match_domain/\w+$}) {
+ my %link_info;
+ if ($env{'form.ltoken'}) {
+ $link_info{'ltoken'} = $env{'form.ltoken'};
+ } elsif ($env{'form.linkprot'}) {
+ $link_info{'linkprot'} = $env{'form.linkprot'};
+ } elsif ($env{'form.linkkey'} ne '') {
+ $link_info{'linkkey'} = $env{'form.linkkey'};
+ }
+ if (keys(%link_info)) {
+ $link_info{'origurl'} = $env{'form.firsturl'};
+ my $token = &Apache::lonnet::tmpput(\%link_info,$found_server,'link');
+ unless (($token eq 'con_lost') || ($token eq 'refused') ||
+ ($token eq 'unknown_cmd') || ($token eq 'no_such_host')) {
+ $dest .= (($dest=~/\?/)?'&':'?') . 'ttoken='.$token;
+ }
+ }
}
unless ($found_server eq $lonhost) {
my $alias = &Apache::lonnet::use_proxy_alias($r,$found_server);
@@ -162,17 +212,10 @@ sub handler {
# it a balancer cookie for an active session on this server.
#
- my ($balcookie,$linkprot,$linkkey);
+ my $balcookie;
if ($env{'form.btoken'}) {
my %info = &Apache::lonnet::tmpget($env{'form.btoken'});
$balcookie = $info{'balcookie'};
- if ($balcookie) {
- if ($info{'linkprot'}) {
- $linkprot = $info{'linkprot'};
- } elsif ($info{'linkkey'}) {
- $linkkey = $info{'linkkey'};
- }
- }
&Apache::lonnet::tmpdel($env{'form.btoken'});
delete($env{'form.btoken'});
}
@@ -203,14 +246,16 @@ sub handler {
&Apache::loncommon::end_page();
my $dest = '/adm/roles';
if ($env{'form.firsturl'} ne '') {
- $dest = $env{'form.firsturl'};
+ $dest = &HTML::Entities::encode($env{'form.firsturl'},'\'"<>&');
}
- if (($env{'form.ltoken'}) || ($linkprot)) {
- unless ($linkprot) {
+ if (($env{'form.ltoken'}) || ($env{'form.linkprot'})) {
+ my $linkprot;
+ if ($env{'form.ltoken'}) {
my %info = &Apache::lonnet::tmpget($env{'form.ltoken'});
$linkprot = $info{'linkprot'};
my $delete = &Apache::lonnet::tmpdel($env{'form.ltoken'});
- delete($env{'form.ltoken'});
+ } else {
+ $linkprot = $env{'form.linkprot'};
}
if ($linkprot) {
my ($linkprotector,$deeplink) = split(/:/,$linkprot,2);
@@ -235,16 +280,14 @@ sub handler {
&Apache::lonnet::appenv({'user.linkproturi' => $deeplink});
}
}
- } elsif (($env{'form.linkkey'}) || ($linkkey)) {
+ } elsif ($env{'form.linkkey'} ne '') {
if ($env{'form.firsturl'} =~ m{^/tiny/$match_domain/\w+$}) {
- if ($linkkey eq '') {
- $linkkey = $env{'form.linkkey'};
- }
+ my $linkkey = $env{'form.linkkey'};
if ($env{'user.deeplinkkey'}) {
my @linkkeys = split(/,/,$env{'user.deeplinkkey'});
unless (grep(/^\Q$linkkey\E$/,@linkkeys)) {
push(@linkkeys,$linkkey);
- &Apache::lonnet::appenv({'user.deeplinkkey' => join(',',sort(@linkkeys))});
+ &Apache::lonnet::appenv({'user.deeplinkkey' => join(',',sort(@linkkeys))});
}
} else {
&Apache::lonnet::appenv({'user.deeplinkkey' => $linkkey});
@@ -292,7 +335,7 @@ sub handler {
$env{'form.interface'}=~s/\W//g;
(undef,undef,undef,undef,undef,undef,my $clientmobile) =
- &Apache::loncommon::decode_user_agent();
+ &Apache::loncommon::decode_user_agent($r);
my $iconpath=
&Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL'));
@@ -301,7 +344,7 @@ sub handler {
my $defdom = $domain;
if ($lonhost ne '') {
unless ($sessiondata{'sessionserver'}) {
- my $redirect = &check_loginvia($domain,$lonhost,$lonidsdir,$balcookie,$linkprot);
+ my $redirect = &check_loginvia($domain,$lonhost,$lonidsdir,$balcookie);
if ($redirect) {
$r->print($redirect);
return OK;
@@ -385,40 +428,30 @@ sub handler {
if ($uextkey>2147483647) { $uextkey-=4294967296; }
# -------------------------------------------------------- Store away log token
- my $tokenextras;
- if ($env{'form.role'}) {
- $tokenextras = '&role='.&escape($env{'form.role'});
- }
- if ($env{'form.symb'}) {
- if (!$tokenextras) {
- $tokenextras = '&';
- }
- $tokenextras .= '&symb='.&escape($env{'form.symb'});
- }
- if ($env{'form.iptoken'}) {
- if (!$tokenextras) {
- $tokenextras = '&&';
+ my ($tokenextras,$tokentype);
+ my @names = ('role','symb','iptoken','ltoken','linkprot','linkkey');
+ foreach my $name (@names) {
+ if ($env{'form.'.$name} ne '') {
+ if ($name eq 'ltoken') {
+ my %info = &Apache::lonnet::tmpget($env{'form.'.$name});
+ if ($info{'linkprot'}) {
+ $tokenextras .= '&linkprot='.&escape($info{'linkprot'});
+ $tokentype = 'link';
+ last;
+ }
+ } else {
+ $tokenextras .= '&'.$name.'='.&escape($env{'form.'.$name});
+ if (($name eq 'linkkey') || ($name eq 'linkprot')) {
+ $tokentype = 'link';
+ }
+ }
}
- $tokenextras .= '&iptoken='.&escape($env{'form.iptoken'});
}
- if ($env{'form.ltoken'}) {
- my %info = &Apache::lonnet::tmpget($env{'form.ltoken'});
- &Apache::lonnet::tmpdel($env{'form.ltoken'});
- delete($env{'form.ltoken'});
- if ($info{'linkprot'}) {
- if (!$tokenextras) {
- $tokenextras = '&&&';
- }
- $tokenextras .= '&linkprot='.&escape($info{'linkprot'});
- }
- } elsif ($env{'form.linkkey'}) {
- if (!$tokenextras) {
- $tokenextras = '&&&';
- }
- $tokenextras .= '&linkkey='.&escape($env{'form.linkkey'});
+ if ($tokentype) {
+ $tokenextras .= ":$tokentype";
}
my $logtoken=Apache::lonnet::reply(
- 'tmpput:'.$ukey.$lkey.'&'.$firsturl.$tokenextras,
+ 'tmpput:'.$ukey.$lkey.'&'.&escape($firsturl).$tokenextras,
$lonhost);
# -- If we cannot talk to ourselves, or hostID does not map to a hostname
@@ -428,6 +461,10 @@ sub handler {
if ($logtoken eq 'no_such_host') {
&Apache::lonnet::logthis('No valid logtoken for log-in page -- unable to determine hostname for hostID: '.$lonhost.'. Check entry in hosts.tab');
}
+ if ($env{'form.ltoken'}) {
+ &Apache::lonnet::tmpdel($env{'form.ltoken'});
+ delete($env{'form.ltoken'});
+ }
my $spares='';
my (@sparehosts,%spareservers);
my $sparesref = &Apache::lonnet::this_host_spares($defdom);
@@ -654,7 +691,7 @@ ENDSAMLJS
alink => "$alink",
onload => 'javascript:enableInput();',);
- my ($headextra,$headextra_exempt,%defaultdomconf);
+ my ($headextra,$headextra_exempt);
$headextra = $defaultdomconf{$defdom.'.login.headtag_'.$lonhost_in_use};
$headextra_exempt = $defaultdomconf{$domain.'.login.headtag_exempt_'.$lonhost_in_use};
if ($headextra) {
@@ -795,15 +832,36 @@ HEADER
if ($samlssourl ne '') {
$ssologin = $samlssourl;
}
+ if (($logtoken eq 'con_lost') || ($logtoken eq 'no_such_host')) {
+ my $querystring;
+ if ($env{'form.firsturl'} ne '') {
+ $querystring = 'origurl=';
+ if ($env{'form.firsturl'} =~ /[^\x00-\xFF]/) {
+ $querystring .= &uri_escape_utf8($env{'form.firsturl'});
+ } else {
+ $querystring .= &uri_escape($env{'form.firsturl'});
+ }
+ $querystring = &HTML::Entities::encode($querystring,"'");
+ }
+ if ($env{'form.ltoken'} ne '') {
+ $querystring .= (($querystring eq '')?'':'&') . 'ltoken='.
+ &HTML::Entities::encode(&uri_escape($env{'form.ltoken'}));
+ } elsif ($env{'form.linkkey'}) {
+ $querystring .= (($querystring eq '')?'':'&') . 'linkkey='.
+ &HTML::Entities::encode(&uri_escape($env{'form.linkkey'}));
+ }
+ if ($querystring ne '') {
+ $ssologin .= (($ssologin=~/\?/)?'&':'?') . $querystring;
+ }
+ } elsif ($logtoken ne '') {
+ $ssologin .= (($ssologin=~/\?/)?'&':'?') . 'logtoken='.$logtoken;
+ }
my $ssohref;
if ($samlssoimg ne '') {
$ssohref = '
';
} else {
$ssohref = ''.$samlssotext.'';
}
- if ($env{'form.firsturl'}) {
- $ssologin .= '?origurl='.&HTML::Entities::encode($env{'form.firsturl'},'<>&"');
- }
if (($env{'form.saml'} eq 'no') ||
(($env{'form.username'} ne '') && ($env{'form.domain'} ne ''))) {
$ssoauthstyle = 'none';
@@ -828,6 +886,11 @@ $coursecatalog
ENDSAML
+ } else {
+ if ($env{'form.ltoken'}) {
+ &Apache::lonnet::tmpdel($env{'form.ltoken'});
+ delete($env{'form.ltoken'});
+ }
}
$r->print(< $linkprot},$desthost);
- if ($ltoken) {
- $url .= (($url =~ /\?/) ? '&' : '?').'ltoken='.$ltoken;
+ if (($env{'form.ltoken'}) || ($env{'form.linkkey'} ne '')) {
+ my %link_info;
+ if ($env{'form.ltoken'}) {
+ $link_info{'ltoken'} = $env{'form.ltoken'};
+ } elsif ($env{'form.linkkey'} ne '') {
+ $link_info{'linkkey'} = $env{'form.linkkey'};
+ }
+ my $token = &Apache::lonnet::tmpput(\%link_info,$desthost,'link');
+ unless (($token eq 'con_lost') || ($token eq 'refused') ||
+ ($token eq 'unknown_cmd') || ($token eq 'no_such_host')) {
+ $url .= (($url=~/\?/)?'&':'?') . 'ttoken='.$token;
}
}
my $start_page = &Apache::loncommon::start_page('Switching Server ...',undef,
@@ -1103,5 +1180,19 @@ sub newuser_link {
return ''.$linkname.'';
}
+sub decode_token {
+ my ($info) = @_;
+ my ($firsturl,@rest)=split(/\&/,$info);
+ my %form;
+ if ($firsturl ne '') {
+ $form{'firsturl'} = &unescape($firsturl);
+ }
+ foreach my $item (@rest) {
+ my ($key,$value) = split(/=/,$item);
+ $form{$key} = &unescape($value);
+ }
+ return %form;
+}
+
1;
__END__