--- loncom/auth/lonauth.pm 2017/08/08 16:43:54 1.144 +++ loncom/auth/lonauth.pm 2022/02/27 01:43:13 1.172 @@ -1,7 +1,7 @@ # The LearningOnline Network # User Authentication Module # -# $Id: lonauth.pm,v 1.144 2017/08/08 16:43:54 raeburn Exp $ +# $Id: lonauth.pm,v 1.172 2022/02/27 01:43:13 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -36,16 +36,18 @@ use Apache::loncommon(); use Apache::lonnet; use Apache::lonmenu(); use Apache::createaccount; +use Apache::ltiauth; use Fcntl qw(:flock); use Apache::lonlocal; use Apache::File(); use HTML::Entities; use Digest::MD5; +use CGI::Cookie(); # ------------------------------------------------------------ Successful login sub success { my ($r, $username, $domain, $authhost, $lowerurl, $extra_env, - $form) = @_; + $form,$skipcritical,$cid,$expirepub) = @_; # ------------------------------------------------------------ Get cookie ready my $cookie = @@ -59,22 +61,26 @@ sub success { # -------------------------------------------------------------------- Log this + my $ip = &Apache::lonnet::get_requestor_ip(); &Apache::lonnet::log($domain,$username,$authhost, - "Login $ENV{'REMOTE_ADDR'}"); + "Login $ip"); # ------------------------------------------------- Check for critical messages - my @what=&Apache::lonnet::dump('critical',$domain,$username); - if ($what[0]) { - if (($what[0] ne 'con_lost') && ($what[0]!~/^error\:/)) { - $lowerurl='/adm/email?critical=display'; + unless ($skipcritical) { + my @what=&Apache::lonnet::dump('critical',$domain,$username); + if ($what[0]) { + if (($what[0] ne 'con_lost') && ($what[0]!~/^error\:/)) { + $lowerurl='/adm/email?critical=display'; + } } } # ----------------------------------------------------------- Get cookies ready my ($securecookie,$defaultcookie); - if ($ENV{'SERVER_PORT'} == 443) { - $securecookie="lonID=$cookie; path=/; HttpOnly; secure"; + my $ssl = $r->subprocess_env('https'); + if ($ssl) { + $securecookie="lonSID=$cookie; path=/; HttpOnly; secure"; my $lonidsdir=$r->dir_config('lonIDsDir'); if (($lonidsdir) && (-e "$lonidsdir/$cookie.id")) { my $linkname=substr(Digest::MD5::md5_hex(Digest::MD5::md5_hex(time(). {}. rand(). $$)), 0, 32).'_linked'; @@ -85,7 +91,7 @@ sub success { "$lonidsdir/$linkname.id"); 1 }; if ($made_symlink) { $defaultcookie = "lonLinkID=$linkname; path=/; HttpOnly;"; - &Apache::lonnet::appenv({'user.linkedenv' => "$lonidsdir/$linkname.id"}); + &Apache::lonnet::appenv({'user.linkedenv' => $linkname}); } } } else { @@ -93,7 +99,35 @@ sub success { } # -------------------------------------------------------- Menu script and info my $destination = $lowerurl; - + if ($env{'request.lti.login'}) { + if (($env{'request.lti.reqcrs'}) && ($env{'request.lti.reqrole'} eq 'cc')) { + &Apache::loncommon::content_type($r,'text/html'); + if ($securecookie) { + $r->headers_out->add('Set-cookie' => $securecookie); + } + if ($defaultcookie) { + $r->headers_out->add('Set-cookie' => $defaultcookie); + } + $r->send_http_header; + if (ref($form) eq 'HASH') { + $form->{'lti.login'} = $env{'request.lti.login'}; + $form->{'lti.reqcrs'} = $env{'request.lti.reqcrs'}; + $form->{'lti.reqrole'} = $env{'request.lti.reqrole'}; + $form->{'lti.sourcecrs'} = $env{'request.lti.sourcecrs'}; + } + &Apache::ltiauth::lti_reqcrs($r,$domain,$form,$username,$domain); + return; + } + if ($env{'request.lti.selfenrollrole'}) { + if (&Apache::ltiauth::lti_enroll($username,$domain, + $env{'request.lti.selfenrollrole'}) eq 'ok') { + $form->{'role'} = $env{'request.lti.selfenrollrole'}; + &Apache::lonnet::delenv('request.lti.selfenrollrole'); + } else { + &Apache::ltiauth::invalid_request($r,24); + } + } + } if (defined($form->{role})) { my $envkey = 'user.role.'.$form->{role}; my $now=time; @@ -116,16 +150,26 @@ sub success { } if (defined($form->{symb})) { my $destsymb = $form->{symb}; + my $encrypted; + if ($destsymb =~ m{^/enc/}) { + $encrypted = 1; + if ($cid) { + $destsymb = &Apache::lonenc::unencrypted($destsymb,$cid); + } + } $destination .= ($destination =~ /\?/) ? '&' : '?'; if ($destsymb =~ /___/) { - # FIXME Need to deal with encrypted symbs and urls as needed. my ($map,$resid,$desturl)=split(/___/,$destsymb); $desturl = &Apache::lonnet::clutter($desturl); + if ($encrypted) { + $desturl = &Apache::lonenc::encrypted($desturl,1,$cid); + $destsymb = $form->{symb}; + } $desturl = &HTML::Entities::encode($desturl,'"<>&'); $destsymb = &HTML::Entities::encode($destsymb,'"<>&'); $destination .= 'destinationurl='.$desturl. '&destsymb='.$destsymb; - } else { + } elsif (!$encrypted) { $destsymb = &HTML::Entities::encode($destsymb,'"<>&'); $destination .= 'destinationurl='.$destsymb; } @@ -135,8 +179,27 @@ sub success { $destination .= 'source=login'; } - my $windowinfo = Apache::lonhtmlcommon::scripttag('self.name="loncapaclient";'); - my $header = ''; + if (($env{'request.deeplink.login'} eq $lowerurl) && + (($env{'request.linkprot'}) || ($env{'request.linkkey'} ne ''))) { + my %info; + if ($env{'request.linkprot'}) { + $info{'linkprot'} = $env{'request.linkprot'}; + } elsif ($env{'request.linkkey'} ne '') { + $info{'linkkey'} = $env{'request.linkkey'}; + } + $info{'origurl'} = $lowerurl; + my $token = &Apache::lonnet::tmpput(\%info,$r->dir_config('lonHostID'),'link'); + unless (($token eq 'con_lost') || ($token eq 'refused') || + ($token eq 'unknown_cmd') || ($token eq 'no_such_host')) { + $destination .= (($destination =~ /\?/) ? '&' : '?') . 'ttoken='.$token; + } + } + + my $windowname = 'loncapaclient'; + if ($env{'request.lti.login'}) { + $windowname .= 'lti'; + } + my $windowinfo = Apache::lonhtmlcommon::scripttag('self.name="'.$windowname.'";'); my $brcrum = [{'href' => '', 'text' => 'Successful Login'},]; my $args = {'bread_crumbs' => $brcrum,}; @@ -161,11 +224,7 @@ sub success { } } } - my $start_page=&Apache::loncommon::start_page('Successful Login', - $header,$args); - my $end_page =&Apache::loncommon::end_page(); - my $continuelink=''.&mt('Continue').''; # ------------------------------------------------- Output for successful login &Apache::loncommon::content_type($r,'text/html'); @@ -175,25 +234,64 @@ sub success { if ($defaultcookie) { $r->headers_out->add('Set-cookie' => $defaultcookie); } + if ($expirepub) { + my $c = new CGI::Cookie(-name => 'lonPubID', + -value => '', + -expires => '-10y',); + $r->headers_out->add('Set-cookie' => $c); + } $r->send_http_header; - my %lt=&Apache::lonlocal::texthash( - 'wel' => 'Welcome', - 'pro' => 'Login problems?', - ); - my $loginhelp = &loginhelpdisplay($domain); - if ($loginhelp) { - $loginhelp = '
'; + my ($start_page,$js,$pagebody,$end_page); + if ($env{'request.lti.login'}) { + $args = {'only_body' => 1}; + if ($env{'request.lti.target'} eq '') { + my $ltitarget = (($destination =~ /\?/) ? '&' : '?'). + 'ltitarget=iframe'; + $js = <<"ENDJS"; + + - my $welcome = &mt('Welcome to the Learning[_1]Online[_2] Network with CAPA. Please wait while your session is being set up.','',''); +ENDJS + $args->{'add_entries'} = {'onload' => "javascript:setLTItarget();"}; + $pagebody = ''; + } else { + $args->{'redirect'} = [0,$destination,1]; + } + $start_page=&Apache::loncommon::start_page('',$js,$args); + } else { + $args->{'redirect'} = [0,$destination]; + $start_page=&Apache::loncommon::start_page('Successful Login', + $js,$args); + + my %lt=&Apache::lonlocal::texthash( + 'wel' => 'Welcome', + 'pro' => 'Login problems?', + ); + $pagebody = "'.&mt('You are already logged in!').'
' + .''.&mt('Please [_1]log out[_2] first, and then try your access again', + '','') + .'
' + .$end_page); + } else { + if (($info{'linkprot'}) || ($info{'linkkey'} ne '')) { + my $token = &Apache::lonnet::tmpput(\%info,$r->dir_config('lonHostID'),'link'); + unless (($token eq 'con_lost') || ($token eq 'refused') || + ($token eq 'unknown_cmd') || ($token eq 'no_such_host')) { + $dest .= (($dest =~ /\?/) ? '&' : '?') . 'ttoken='.$token; + } + } + $r->print( + $start_page + .''.&mt('You are already logged in!').'
' + .''.&mt('Please either [_1]continue the current session[_2] or [_3]log out[_4] first, and then try your access again', + '','', + '','') + .'
' + .$end_page); + } + return OK; + } + } + } } $r->print( - $start_page - .''.&mt('You are already logged in!').'
' - .''.&mt('Please either [_1]continue the current session[_2] or [_3]log out[_4].' - ,'','','','') - .'
' - .$end_page + $start_page + .''.&mt('You are already logged in!').'
' + .''.&mt('Please either [_1]continue the current session[_2] or [_3]log out[_4].' + ,'','','','') + .'
' + .$end_page ); return OK; } @@ -313,19 +508,7 @@ sub handler { # ---------------------------------------------------- No valid token, continue - - my $buffer; - if ($r->header_in('Content-length') > 0) { - $r->read($buffer,$r->header_in('Content-length'),0); - } - my %form; - foreach my $pair (split(/&/,$buffer)) { - my ($name,$value) = split(/=/,$pair); - $value =~ tr/+/ /; - $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; - $form{$name}=$value; - } - + my %form = &get_form_items($r); if ((!$form{'uname'}) || (!$form{'upass0'}) || (!$form{'udom'})) { &failed($r,'Username, password and domain need to be specified.', \%form); @@ -334,10 +517,11 @@ sub handler { # split user logging in and "su"-user - ($form{'uname'},$form{'suname'})=split(/\:/,$form{'uname'}); + ($form{'uname'},$form{'suname'},$form{'sudom'})=split(/\:/,$form{'uname'}); $form{'uname'} = &LONCAPA::clean_username($form{'uname'}); $form{'suname'}= &LONCAPA::clean_username($form{'suname'}); - $form{'udom'} = &LONCAPA::clean_domain( $form{'udom'}); + $form{'udom'} = &LONCAPA::clean_domain($form{'udom'}); + $form{'sudom'} = &LONCAPA::clean_domain($form{'sudom'}); my $role = $r->dir_config('lonRole'); my $domain = $r->dir_config('lonDefDomain'); @@ -368,28 +552,17 @@ sub handler { return OK; } - my ($key,$firsturl,$rolestr,$symbstr,$iptokenstr)=split(/&/,$tmpinfo); - if ($rolestr) { - $rolestr = &unescape($rolestr); - } - if ($symbstr) { - $symbstr= &unescape($symbstr); - } - if ($iptokenstr) { - $iptokenstr = &unescape($iptokenstr); + my ($des_key,$firsturl,@rest)=split(/&/,$tmpinfo); + $firsturl = &unescape($firsturl); + foreach my $item (@rest) { + my ($key,$value) = split(/=/,$item); + $form{$key} = &unescape($value); } - if ($rolestr =~ /^role=/) { - (undef,$form{'role'}) = split('=',$rolestr); + if ($firsturl =~ m{^/tiny/$match_domain/\w+$}) { + $form{'firsturl'} = $firsturl; } - if ($symbstr =~ /^symb=/) { - (undef,$form{'symb'}) = split('=',$symbstr); - } - if ($iptokenstr =~ /^iptoken=/) { - (undef,$form{'iptoken'}) = split('=',$iptokenstr); - } - my $upass = $ENV{HTTPS} ? $form{'upass0'} - : &Apache::loncommon::des_decrypt($key,$form{'upass0'}); + : &Apache::loncommon::des_decrypt($des_key,$form{'upass0'}); # ---------------------------------------------------------------- Authenticate @@ -406,13 +579,37 @@ sub handler { my $authhost=Apache::lonnet::authenticate($form{'uname'},$upass, $form{'udom'},$defaultauth, $clientcancheckhost); - + # --------------------------------------------------------------------- Failed? if ($authhost eq 'no_host') { - &failed($r,'Username and/or password could not be authenticated.', - \%form); - return OK; + my $pwdverify; + if (&Apache::lonnet::homeserver($form{'uname'},$form{'udom'}) eq 'no_host') { + my %possunames = &alternate_unames_check($form{'uname'},$form{'udom'}); + if (keys(%possunames) > 0) { + foreach my $rulematch (keys(%possunames)) { + my $possuname = $possunames{$rulematch}; + if (($possuname ne '') && ($possuname =~ /^$match_username$/)) { + $authhost=Apache::lonnet::authenticate($possuname,$upass, + $form{'udom'},undef, + $clientcancheckhost); + if (($authhost eq 'no_host') || ($authhost eq 'no_account_on_host')) { + next; + } elsif (($authhost ne '') && (&Apache::lonnet::hostname($authhost) ne '')) { + $pwdverify = 1; + &Apache::lonnet::logthis("Authenticated user: $possuname was submitted as: $form{'uname'}"); + $form{'uname'} = $possuname; + last; + } + } + } + } + } + unless ($pwdverify) { + &failed($r,'Username and/or password could not be authenticated.', + \%form,$authhost); + return OK; + } } elsif ($authhost eq 'no_account_on_host') { if ($defaultauth) { my $domdesc = &Apache::lonnet::domain($form{'udom'},'description'); @@ -420,7 +617,8 @@ sub handler { return OK; } my $start_page = - &Apache::loncommon::start_page('Create a user account in LON-CAPA'); + &Apache::loncommon::start_page('Create a user account in LON-CAPA', + '',{'no_inline_link' => 1,}); my $lonhost = $r->dir_config('lonHostID'); my $origmail = $Apache::lonnet::perlvar{'lonSupportEMail'}; my $contacts = @@ -450,9 +648,9 @@ sub handler { $firsturl='/adm/roles'; } - my $hosthere; + my ($hosthere,%sessiondata); if ($form{'iptoken'}) { - my %sessiondata = &Apache::lonnet::tmpget($form{'iptoken'}); + %sessiondata = &Apache::lonnet::tmpget($form{'iptoken'}); my $delete = &Apache::lonnet::tmpdel($form{'iptoken'}); if (($sessiondata{'domain'} eq $form{'udom'}) && ($sessiondata{'username'} eq $form{'uname'})) { @@ -462,20 +660,68 @@ sub handler { # --------------------------------- Are we attempting to login as somebody else? if ($form{'suname'}) { + my ($suname,$sudom,$sudomref); + $suname = $form{'suname'}; + $sudom = $form{'udom'}; + if ($form{'sudom'}) { + unless ($sudom eq $form{'sudom'}) { + if (&Apache::lonnet::domain($form{'sudom'})) { + $sudomref = [$form{'sudom'}]; + $sudom = $form{'sudom'}; + } + } + } # ------------ see if the original user has enough privileges to pull this stunt - if (&Apache::lonnet::privileged($form{'uname'},$form{'udom'})) { + if (&Apache::lonnet::privileged($form{'uname'},$form{'udom'},$sudomref)) { # ---------------------------------------------------- see if the su-user exists - unless (&Apache::lonnet::homeserver($form{'suname'},$form{'udom'}) - eq 'no_host') { - &Apache::lonnet::logthis(&Apache::lonnet::homeserver($form{'suname'},$form{'udom'})); + unless (&Apache::lonnet::homeserver($suname,$sudom) eq 'no_host') { # ------------------------------ see if the su-user is not too highly privileged - unless (&Apache::lonnet::privileged($form{'suname'},$form{'udom'})) { + if (&Apache::lonnet::privileged($suname,$sudom)) { + &Apache::lonnet::logthis('Attempted switch user to privileged user'); + } else { + my $noprivswitch; +# +# su-user's home server and user's home server must have one of: +# (a) same domain +# (b) same primary library server for the two domains +# (c) same "internet domain" for primary library server(s) for home servers' domains +# + my $suprim = &Apache::lonnet::domain($sudom,'primary'); + my $suintdom = &Apache::lonnet::internet_dom($suprim); + unless ($sudom eq $form{'udom'}) { + my $uprim = &Apache::lonnet::domain($form{'udom'},'primary'); + my $uintdom = &Apache::lonnet::internet_dom($uprim); + unless ($suprim eq $uprim) { + unless ($suintdom eq $uintdom) { + &Apache::lonnet::logthis('Attempted switch user ' + .'to user with different "internet domain".'); + $noprivswitch = 1; + } + } + } + + unless ($noprivswitch) { +# +# server where log-in occurs must have same "internet domain" as su-user's home +# server +# + my $lonhost = $r->dir_config('lonHostID'); + my $hostintdom = &Apache::lonnet::internet_dom($lonhost); + if ($hostintdom ne $suintdom) { + &Apache::lonnet::logthis('Attempted switch user on a ' + .'server with a different "internet domain".'); + } else { + # -------------------------------------------------------- actually switch users - &Apache::lonnet::logperm('User '.$form{'uname'}.' at '.$form{'udom'}. - ' logging in as '.$form{'suname'}); - $form{'uname'}=$form{'suname'}; - } else { - &Apache::lonnet::logthis('Attempted switch user to privileged user'); + + &Apache::lonnet::logperm('User '.$form{'uname'}.' at '. + $form{'udom'}.' logging in as '.$suname.':'.$sudom); + $form{'uname'}=$suname; + if ($form{'udom'} ne $sudom) { + $form{'udom'}=$sudom; + } + } + } } } } else { @@ -489,11 +735,16 @@ sub handler { ($is_balancer,$otherserver) = &Apache::lonnet::check_loadbalancing($form{'uname'},$form{'udom'},'login'); if ($is_balancer) { + # 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); + if (($found_server) && ($balancer_cookie =~ /^\Q$env{'user.domain'}\E_\Q$env{'user.name'}\E_/)) { + $otherserver = $found_server; + } if ($otherserver eq '') { my $lowest_load; ($otherserver,undef,undef,undef,$lowest_load) = &Apache::lonnet::choose_server($form{'udom'}); if ($lowest_load > 100) { - $otherserver = &Apache::lonnet::spareserver($lowest_load,$lowest_load,1,$form{'udom'}); + $otherserver = &Apache::lonnet::spareserver($r,$lowest_load,$lowest_load,1,$form{'udom'}); } } if ($otherserver ne '') { @@ -519,8 +770,18 @@ sub handler { if ($form{'symb'}) { $switchto .= '&symb='.$form{'symb'}; } + if ($form{'linkprot'}) { + $env{'request.linkprot'} = $form{'linkprot'}; + } elsif ($form{'linkkey'} ne '') { + $env{'request.linkkey'} = $form{'linkkey'}; + } + if ($form{'firsturl'} =~ m{^/tiny/$match_domain/\w+$}) { + &set_deeplink_login(%form); + } $r->internal_redirect($switchto); } else { + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; $r->print(&noswitch()); } return OK; @@ -540,8 +801,18 @@ sub handler { if ($form{'symb'}) { $switchto .= '&symb='.$form{'symb'}; } + if ($form{'linkprot'}) { + $env{'request.linkprot'} = $form{'linkprot'}; + } elsif ($form{'linkkey'} ne '') { + $env{'request.linkkey'} = $form{'linkkey'}; + } + if ($form{'firsturl'} =~ m{^/tiny/$match_domain/\w+$}) { + &set_deeplink_login(%form); + } $r->internal_redirect($switchto); } else { + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; $r->print(&noswitch()); } return OK; @@ -562,13 +833,21 @@ sub handler { # ---------------------------------------------------------- Are we overloaded? if ((($userloadpercent>100.0)||($loadpercent>100.0))) { - my $unloaded=Apache::lonnet::spareserver($loadpercent,$userloadpercent,1,$form{'udom'}); + my $unloaded=Apache::lonnet::spareserver($r,$loadpercent,$userloadpercent,1,$form{'udom'}); if (!$unloaded) { ($unloaded) = &Apache::lonnet::choose_server($form{'udom'}); } if ($unloaded) { &success($r,$form{'uname'},$form{'udom'},$authhost,'noredirect', undef,\%form); + if ($form{'linkprot'}) { + $env{'request.linkprot'} = $form{'linkprot'}; + } elsif ($form{'linkkey'} ne '') { + $env{'request.linkkey'} = $form{'linkkey'}; + } + if ($form{'firsturl'} =~ m{^/tiny/$match_domain/\w+$}) { + &set_deeplink_login(%form); + } $r->internal_redirect('/adm/switchserver?otherserver='.$unloaded.'&origurl='.$firsturl); return OK; } @@ -576,12 +855,150 @@ sub handler { if (($is_balancer) && ($hosthere)) { $form{'noloadbalance'} = $hosthere; } - &success($r,$form{'uname'},$form{'udom'},$authhost,$firsturl,undef, + my $extra_env; + if (($hosthere) && ($sessiondata{'sessionserver'} ne '')) { + if ($sessiondata{'origurl'} ne '') { + $firsturl = $sessiondata{'origurl'}; + $form{'firsturl'} = $sessiondata{'origurl'}; + my @names = ('role','symb','linkprot','linkkey'); + foreach my $item (@names) { + if ($sessiondata{$item} ne '') { + $form{$item} = $sessiondata{$item}; + } + } + } + } + if ($form{'linkprot'}) { + my ($linkprotector,$uri) = split(/:/,$form{'linkprot'},2); + if ($linkprotector) { + $extra_env = {'user.linkprotector' => $linkprotector, + 'user.linkproturi' => $uri}; + } + } elsif ($form{'linkkey'} ne '') { + $extra_env = {'user.deeplinkkey' => $form{'linkkey'}, + 'user.keyedlinkuri' => $form{'firsturl'}}; + } + if ($form{'firsturl'} =~ m{^/tiny/$match_domain/\w+$}) { + &set_deeplink_login(%form); + if ($form{'linkprot'}) { + if (ref($extra_env) eq 'HASH') { + %{$extra_env} = ( %{$extra_env}, 'request.linkprot' => $form{'linkprot'} ); + } else { + $extra_env = {'request.linkprot' => $form{'linkprot'}}; + } + } elsif ($form{'linkkey'} ne '') { + if (ref($extra_env) eq 'HASH') { + %{$extra_env} = ( %{$extra_env}, 'request.linkkey' => $form{'linkkey'} ); + } else { + $extra_env = {'request.linkkey' => $form{'linkkey'}}; + } + } + if ($env{'request.deeplink.login'}) { + if (ref($extra_env) eq 'HASH') { + %{$extra_env} = ( %{$extra_env}, 'request.deeplink.login' => $form{'firsturl'} ); + } else { + $extra_env = {'request.deeplink.login' => $form{'firsturl'}}; + } + } + } + &success($r,$form{'uname'},$form{'udom'},$authhost,$firsturl,$extra_env, \%form); return OK; } } +sub get_form_items { + my ($r) = @_; + my $buffer; + if ($r->header_in('Content-length') > 0) { + $r->read($buffer,$r->header_in('Content-length'),0); + } + my %form; + foreach my $pair (split(/&/,$buffer)) { + my ($name,$value) = split(/=/,$pair); + $value =~ tr/+/ /; + $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; + $form{$name}=$value; + } + return %form; +} + +sub set_deeplink_login { + my (%form) = @_; + my $disallow; + if ($form{'firsturl'} =~ m{^/tiny/($match_domain)/\w+$}) { + my $cdom = $1; + my ($cnum,$symb) = &Apache::loncommon::symb_from_tinyurl($form{'firsturl'},'',$cdom); + if ($symb) { + if ($env{'request.course.id'} eq $cdom.'_'.$cnum) { + my $deeplink; + if ($symb =~ /\.(page|sequence)$/) { + my $mapname = &Apache::lonnet::deversion((&Apache::lonnet::decode_symb($symb))[2]); + my $navmap = Apache::lonnavmaps::navmap->new(); + if (ref($navmap)) { + $deeplink = $navmap->get_mapparam(undef,$mapname,'0.deeplink'); + } + } else { + $deeplink = &Apache::lonnet::EXT('resource.0.deeplink',$symb); + } + if ($deeplink ne '') { + my ($state,$others,$listed,$scope,$protect) = split(/,/,$deeplink); + if (($protect ne 'none') && ($protect ne '')) { + my ($acctype,$item) = split(/:/,$protect); + if ($acctype =~ /lti(c|d)$/) { + unless ($form{'linkprot'} eq $item.$1.':'.$env{'request.deeplink.login'}) { + $disallow = 1; + } + } elsif ($acctype eq 'key') { + unless ($form{'linkkey'} eq $item) { + $disallow = 1; + } + } + } + } + unless ($disallow) { + $env{'request.deeplink.login'} = $form{'firsturl'}; + } + } else { + $env{'request.deeplink.login'} = $form{'firsturl'}; + } + } + } + if ($disallow) { + return; + } + return 'ok'; +} + +sub set_retry_token { + my ($form,$lonhost,$querystr) = @_; + if (ref($form) eq 'HASH') { + my ($firsturl,$token,$extras,@names); + @names = ('role','symb','linkprot','linkkey','iptoken'); + foreach my $name (@names) { + if ($form->{$name} ne '') { + $extras .= '&'.$name.'='.&escape($form->{$name}); + last if ($name eq 'linkprot'); + } + } + my $firsturl = $form->{'firsturl'}; + if (($firsturl ne '') || ($extras ne '')) { + $extras .= ':retry'; + $token = &Apache::lonnet::reply('tmpput:'.&escape($firsturl). + $extras,$lonhost); + if (($token eq 'con_lost') || ($token eq 'no_such_host')) { + return 'fail'; + } else { + if (ref($querystr)) { + $$querystr = 'retry='.$token; + } + return 'ok'; + } + } + } + return; +} + sub check_can_host { my ($r,$form,$authhost,$domdesc) = @_; return unless (ref($form) eq 'HASH'); @@ -622,7 +1039,10 @@ sub check_can_host { if ($login_host ne '') { my $protocol = $Apache::lonnet::protocol{$login_host}; $protocol = 'http' if ($protocol ne 'https'); + my $alias = &Apache::lonnet::use_proxy_alias($r,$login_host); + $hostname = $alias if ($alias ne ''); my $newurl = $protocol.'://'.$hostname.'/adm/createaccount'; +#FIXME Should preserve where user was going and linkprot by setting ltoken at $login_host $r->print(&Apache::loncommon::start_page('Create a user account in LON-CAPA'). '