--- loncom/auth/lonacc.pm 2021/12/30 04:47:38 1.159.2.21.2.1 +++ loncom/auth/lonacc.pm 2022/07/08 15:36:32 1.159.2.21.2.2 @@ -1,7 +1,7 @@ # The LearningOnline Network # Cookie Based Access Handler # -# $Id: lonacc.pm,v 1.159.2.21.2.1 2021/12/30 04:47:38 raeburn Exp $ +# $Id: lonacc.pm,v 1.159.2.21.2.2 2022/07/08 15:36:32 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -273,10 +273,18 @@ sub upload_size_allowed { be identified by the third arg ($usename), except when lonacc is called in an internal redirect to /adm/switchserver (e.g., load-balancing following successful authentication) -- no cookie set yet. For that particular case - simply skip the call to sso_login(). + simply skip the call to sso_login(). returns OK if it was SSO and user was handled. returns undef if not SSO or no means to handle the user. + + In the case where the session was started from /adm/launch/tiny/$domain/$id, + i.e., for a protected link, with launch from another CMS, and user information + is accepted from the LTI payload, then, if the user has privileged roles, + authentication will be required. If SSO authentication is with a username + and/or domain that differ from the username in the LTI payload and domain + in the launch URL, then $r->user() will be unset and /adm/relaunch will be + called. =cut @@ -318,7 +326,7 @@ sub sso_login { } } - my ($linkprot,$linkkey); + my ($linkprot,$linkprotuser,$linkprotexit,$linkkey,$deeplinkurl); # # If Shibboleth auth is in use, and a dual SSO and non-SSO login page @@ -350,9 +358,14 @@ sub sso_login { &Apache::lonnet::tmpdel($form{'ttoken'}); if ($info{'origurl'}) { $form{'origurl'} = $info{'origurl'}; + if ($form{'origurl'} =~ m{^/tiny/$match_domain/\w+$}) { + $deeplinkurl = $form{'origurl'}; + } } if ($info{'linkprot'}) { $linkprot = $info{'linkprot'}; + $linkprotuser = $info{'linkprotuser'}; + $linkprotexit = $info{'linkprotexit'}; } elsif ($info{'linkkey'} ne '') { $linkkey = $info{'linkkey'}; } @@ -373,9 +386,12 @@ sub sso_login { } if ($firsturl =~ m{^/tiny/$match_domain/\w+$}) { $form{'origurl'} = $firsturl; + $deeplinkurl = $firsturl; } if ($form{'linkprot'}) { $linkprot = $form{'linkprot'}; + $linkprotuser = $form{'linkprotuser'}; + $linkprotexit = $form{'linkprotexit'}; } elsif ($form{'linkkey'} ne '') { $linkkey = $form{'linkkey'}; } @@ -393,6 +409,9 @@ sub sso_login { my ($firsturl,@rest)=split(/\&/,$info); if ($firsturl ne '') { $form{'origurl'} = &unescape($firsturl); + if ($form{'origurl'} =~ m{^/tiny/$match_domain/\w+$}) { + $deeplinkurl = $form{'origurl'}; + } } foreach my $item (@rest) { my ($key,$value) = split(/=/,$item); @@ -400,6 +419,8 @@ sub sso_login { } if ($form{'linkprot'}) { $linkprot = $form{'linkprot'}; + $linkprotuser = $form{'linkprotuser'}; + $linkprotexit = $form{'linkprotexit'}; } elsif ($form{'linkkey'} ne '') { $linkkey = $form{'linkkey'}; } @@ -407,8 +428,19 @@ sub sso_login { } elsif ($form{'ltoken'}) { my %link_info = &Apache::lonnet::tmpget($form{'ltoken'}); $linkprot = $link_info{'linkprot'}; + if ($linkprot) { + if ($link_info{'linkprotuser'} ne '') { + $linkprotuser = $link_info{'linkprotuser'}; + } + if ($link_info{'linkprotexit'} ne '') { + $linkprotexit = $link_info{'linkprotexit'}; + } + } my $delete = &Apache::lonnet::tmpdel($form{'ltoken'}); delete($form{'ltoken'}); + if ($form{'origurl'} =~ m{^/tiny/$match_domain/\w+$}) { + $deeplinkurl = $form{'origurl'}; + } } elsif ($form{'linkkey'} ne '') { $linkkey = $form{'linkkey'}; } @@ -417,6 +449,24 @@ sub sso_login { if ($domain eq '') { $domain = $r->dir_config('lonDefDomain'); } + if (($deeplinkurl) && ($linkprot) && ($linkprotuser ne '')) { + unless ($linkprotuser eq $user.':'.$domain) { + $r->user(); + my %data = ( + origurl => $deeplinkurl, + linkprot => $linkprot, + linkprotuser => $linkprotuser, + linkprotexit => $linkprotexit, + ); + my $token = &Apache::lonnet::tmpput(\%data,$r->dir_config('lonHostID'),'link'); + unless (($token eq 'con_lost') || ($token eq 'refused') || ($token =~ /^error:/) || + ($token eq 'unknown_cmd') || ($token eq 'no_such_host')) { + $r->internal_redirect('/adm/relaunch?rtoken='.$token); + $r->set_handlers('PerlHandler'=> undef); + return OK; + } + } + } my $home=&Apache::lonnet::homeserver($user,$domain); if ($home !~ /(con_lost|no_host|no_such_host)/) { &Apache::lonnet::logthis(" SSO authorized user $user "); @@ -470,6 +520,12 @@ sub sso_login { if ($env{'request.deeplink.login'}) { if ($linkprot) { $env{'request.linkprot'} = $linkprot; + if ($linkprotuser ne '') { + $env{'request.linkprotuser'} = $linkprotuser; + } + if ($linkprotexit ne '') { + $env{'request.linkprotexit'} = $linkprotexit; + } } elsif ($linkkey ne '') { $env{'request.linkkey'} = $linkkey; } @@ -515,6 +571,12 @@ sub sso_login { if ($info{'deeplink.login'}) { if ($linkprot) { $info{'linkprot'} = $linkprot; + if ($linkprotuser ne '') { + $info{'linkprotuser'} = $linkprotuser; + } + if ($linkprotexit ne '') { + $info{'linkprotexit'} = $linkprotexit; + } } elsif ($linkkey ne '') { $info{'linkkey'} = $linkkey; } @@ -529,9 +591,7 @@ sub sso_login { if (($is_balancer) && ($hosthere)) { $info{'noloadbalance'} = $hosthere; } - my $token = - &Apache::lonnet::tmpput(\%info, - $r->dir_config('lonHostID')); + my $token = &Apache::lonnet::tmpput(\%info,$r->dir_config('lonHostID'),'sso'); $env{'form.token'} = $token; $r->internal_redirect('/adm/migrateuser'); $r->set_handlers('PerlHandler'=> undef); @@ -722,13 +782,55 @@ sub handler { } } if ($requrl=~m{^/+tiny/+$match_domain/+\w+$}) { + if ($r->args) { + &Apache::loncommon::get_unprocessed_cgi($r->args,['ttoken']); + if (defined($env{'form.ttoken'})) { + my %info = &Apache::lonnet::tmpget($env{'form.ttoken'}); + if (($info{'origurl'} ne '') && ($info{'origurl'} eq $requrl)) { + my %data; + if (($info{'linkprotuser'} ne '') && ($info{'linkprot'}) && + ($info{'linkprotuser'} ne $env{'user.name'}.':'.$env{'user.domain'})) { + %data = ( + origurl => $requrl, + linkprot => $info{'linkprot'}, + linkprotuser => $info{'linkprotuser'}, + linkprotexit => $info{'linkprotexit'}, + ); + } elsif ($info{'ltoken'} ne '') { + my %ltoken_info = &Apache::lonnet::tmpget($info{'ltoken'}); + if (($ltoken_info{'linkprotuser'} ne '') && ($ltoken_info{'linkprot'}) && + ($ltoken_info{'linkprotuser'} ne $env{'user.name'}.':'.$env{'user.domain'})) { + %data = ( + origurl => $requrl, + linkprot => $ltoken_info{'linkprot'}, + linkprotuser => $ltoken_info{'linkprotuser'}, + linkprotexit => $ltoken_info{'linkprotexit'}, + ); + } + } + if (keys(%data)) { + my $delete = &Apache::lonnet::tmpdel($env{'form.ttoken'}); + if ($info{'ltoken'} ne '') { + my $delete = &Apache::lonnet::tmpdel($info{'ltoken'}); + } + my $token = + &Apache::lonnet::tmpput(\%data,$r->dir_config('lonHostID'),'retry'); + unless (($token eq 'con_lost') || ($token eq 'refused') || ($token =~ /^error:/) || + ($token eq 'unknown_cmd') || ($token eq 'no_such_host')) { + $r->internal_redirect('/adm/relaunch?rtoken='.$token); + $r->set_handlers('PerlHandler'=> undef); + return OK; + } + } + } + } + } if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') { $env{'request.firsturl'}=$requrl; return FORBIDDEN; - } else { - return OK; } + return OK; } # ---------------------------------------------------------------- Check access my $now = time;