--- loncom/auth/switchserver.pm	2021/12/12 21:07:21	1.35.2.6
+++ loncom/auth/switchserver.pm	2023/06/02 01:20:26	1.65
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Switch Servers Handler
 #
-# $Id: switchserver.pm,v 1.35.2.6 2021/12/12 21:07:21 raeburn Exp $
+# $Id: switchserver.pm,v 1.65 2023/06/02 01:20:26 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -54,7 +54,7 @@ sub init_env {
 }
 
 sub do_redirect {
-    my ($r,$url,$only_body,$extra_text) = @_;
+    my ($r,$url,$only_body,$extra_text,$write_to_opener) = @_;
     $r->send_http_header;
     my $delay = 0.5;
     if ($only_body && !$extra_text) {
@@ -62,7 +62,7 @@ sub do_redirect {
     }
     my $start_page = 
 	&Apache::loncommon::start_page('Switching Server ...',undef,
-				       {'redirect'       => [$delay,$url],
+				       {'redirect'       => [$delay,$url,'',$write_to_opener,1],
 					'only_body'      => $only_body,});
     my $end_page   = &Apache::loncommon::end_page();
     $r->print($start_page.$extra_text.$end_page);
@@ -97,12 +97,12 @@ sub flush_course_logs {
 
 sub handler {
     my ($r) = @_;
-    
+
     my $handle=&init_env($r);
     if (!defined($handle)) { return FORBIDDEN; }
 
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
-				['otherserver','role','origurl','symb']);
+				['otherserver','role','origurl','symb','lcssowin','edit']);
 
     my $switch_to=&Apache::lonnet::hostname($env{'form.otherserver'});
     if (! $env{'form.otherserver'}) {
@@ -155,34 +155,81 @@ sub handler {
                     $skip_canhost_check = 1;
                 }
             } elsif ($env{'form.role'} =~ m{^[ac]a\./($match_domain)/($match_username)$}) {
-                if (&Apache::lonnet::homeserver($2,$1) eq $env{'form.otherserver'}) {
-                    $skip_canhost_check = 1; 
+                my ($audom,$auname) = ($1,$2);
+                if (&Apache::lonnet::homeserver($auname,$audom) eq $env{'form.otherserver'}) {
+                    if ((&Apache::lonnet::will_trust('othcoau',$env{'user.domain'},$audom)) &&
+                        (&Apache::lonnet::will_trust('coaurem',$audom,$env{'user.domain'}))) {                             
+                        $skip_canhost_check = 1;
+                    }
                 }
             }
         }
     }
 
     unless ($skip_canhost_check) {
-        my $canhost = 1;
-        my $uprimary_id = &Apache::lonnet::domain($env{'user.domain'},'primary');
-        my $uint_dom = &Apache::lonnet::internet_dom($uprimary_id);
-        my @intdoms;
-        my $internet_names = &Apache::lonnet::get_internet_names($env{'form.otherserver'});
-        if (ref($internet_names) eq 'ARRAY') {
-            @intdoms = @{$internet_names};
-        }
-        unless ($uint_dom ne '' && grep(/^\Q$uint_dom\E$/,@intdoms)) {
-            my $serverhomeID = &Apache::lonnet::get_server_homeID($switch_to);
-            my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID);
-            my %defdomdefaults = &Apache::lonnet::get_domain_defaults($serverhomedom);
-            my %udomdefaults = &Apache::lonnet::get_domain_defaults($env{'user.domain'});
-            my $remoterev = &Apache::lonnet::get_server_loncaparev($env{'user.domain'},$env{'form.otherserver'});
-            $canhost = 
-                &Apache::lonnet::can_host_session($env{'user.domain'},
-                                                  $env{'form.otherserver'},
-                                                  $remoterev,
-                                                  $udomdefaults{'remotesessions'},
-                                                  $defdomdefaults{'hostedsessions'});
+        my $canhost = &Apache::lonnet::can_switchserver($env{'user.domain'},$env{'form.otherserver'});
+        unless ($canhost) {
+            if (($env{'request.course.id'}) && ($env{'form.symb'} ne '') &&
+                (&Apache::lonnet::allowed('mdc',$env{'request.course.id'}))) {
+                my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+                my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+                if (($cdom ne '') && ($cnum ne '') && ($env{'form.role'} =~ m{^([^.]+)\Q./$cdom/$cnum\E$})) {
+                    my $symb = &Apache::lonnet::symbclean($env{'form.symb'});
+                    my ($map,$idx,$url) = &Apache::lonnet::decode_symb($symb);
+                    if (&Apache::lonnet::symbverify($symb,$url)) {
+                        my $fileloc = &Apache::lonnet::declutter(&Apache::lonnet::filelocation("",$url));
+                        my $resurl = &Apache::lonnet::clutter($url);
+                        if ($resurl =~ m{^/res/($match_domain)/($match_username)/}) {
+                            my ($audom,$auname) = ($1,$2);
+                            if (&Apache::lonnet::homeserver($auname,$audom) eq $env{'form.otherserver'}) {
+                                my @possroles = ("user.role.au./$audom/","user.role.ca./$audom/$auname","user.role.aa./$audom/$auname");
+                                my $hasrole;
+                                foreach my $rolekey (@possroles) {
+                                    if (exists($env{$rolekey})) {
+                                        my ($start,$end) = split(/\./,$env{$rolekey});
+                                        unless (($start && $start > $now) || ($end && $end < $now)) {
+                                            if ($rolekey eq "user.role.au./$audom/") {
+                                                $hasrole = $rolekey;
+                                            } elsif ((&Apache::lonnet::will_trust('othcoau',$env{'user.domain'},$audom)) &&
+                                                     (&Apache::lonnet::will_trust('coaurem',$audom,$env{'user.domain'}))) {
+                                                $hasrole = $rolekey;
+                                            }
+                                        }
+                                        if ($hasrole) {
+                                            $hasrole =~ s/^\Quser.role.\E//;
+                                            last;
+                                        }
+                                    }
+                                }
+                                if ($hasrole) {
+                                    $env{'form.role'} = $hasrole;
+                                    $env{'form.origurl'} = &Apache::lonnet::deversion($resurl);
+                                    $env{'form.origurl'} =~ s{^/res/}{/priv/};
+                                    delete($env{'form.symb'});
+                                    $canhost = 1;
+                                    if ($env{'form.edit'}) {
+                                        my $ip = &Apache::lonnet::get_requestor_ip($r,REMOTE_NOLOOKUP);
+                                        my %info=('ip'            => $ip,
+                                                  'domain'        => $env{'user.domain'},
+                                                  'username'      => $env{'user.name'},
+                                                  'home'          => $env{'user.home'},
+                                                  'role'          => $env{'form.role'},
+                                                  'server'        => $r->dir_config('lonHostID'),
+                                                  'origurl'       => $env{'form.origurl'});
+                                        &Apache::loncommon::content_type($r,'text/html');
+                                        my $token = &Apache::lonnet::tmpput(\%info,$env{'form.otherserver'});
+                                        my $url = $protocol.'://'.$switch_to.'/adm/login?'.
+                                                                 'domain='.$env{'user.domain'}.
+                                                                 '&amp;username='.$env{'user.name'}.
+                                                                 '&amp;token='.$token;
+                                        return &do_redirect($r,$url,0);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
         }
         unless ($canhost) { return FORBIDDEN; }
     }
@@ -204,6 +251,10 @@ sub handler {
     my $logmsg = "Switch Server to $env{'form.otherserver'}";
     if ($env{'form.role'}) {
         $logmsg .= " with role: $env{'form.role'}";
+    } elsif (($env{'form.lti.reqcrs'}) && ($env{'form.lti.reqrole'} eq 'cc')) {
+        $logmsg .= " to create new LTI course";
+    } elsif ($env{'form.lti.selfenrollrole'}) {
+        $logmsg .= " to selfenroll with role: $env{'form.lti.selfenrollrole'}";
     } else {
         $logmsg .= " (no role)";
     }
@@ -231,9 +282,9 @@ sub handler {
 
 # ---------------------------------------------------------------- Get handover
 
-    my ($is_balancer,$setcookie,$newcookieid,$otherbalcookie);
+    my ($is_balancer,$setcookie,$newcookieid,$otherbalcookie,$offloadto,$dom_balancers);
     my $only_body = 0;
-    ($is_balancer,undef,$setcookie) =
+    ($is_balancer,undef,$setcookie,$offloadto,$dom_balancers) =
         &Apache::lonnet::check_loadbalancing($env{'user.name'},$env{'user.domain'},'switchserver');
     if ($is_balancer && $setcookie && $env{'form.otherserver'}) {
 
@@ -253,12 +304,25 @@ sub handler {
         $otherbalcookie = $env{'request.balancercookie'};
     }
 
-    my %info=('ip'       => $ip,
-	      'domain'   => $env{'user.domain'},
-	      'username' => $env{'user.name'},
-	      'role'     => $env{'form.role'},
-	      'server'   => $r->dir_config('lonHostID'),
-	      'balancer' => $is_balancer);
+    my %info=('ip'            => $ip,
+              'domain'        => $env{'user.domain'},
+              'username'      => $env{'user.name'},
+              'home'          => $env{'user.home'},
+              'role'          => $env{'form.role'},
+              'server'        => $r->dir_config('lonHostID'),
+              'balancer'      => $is_balancer,
+              'dom_balancers' => $dom_balancers,
+              'offloadto'     => '');
+    if (ref($offloadto) eq 'HASH') {
+        foreach my $key (keys(%{$offloadto})) {
+            if (ref($offloadto->{$key}) eq 'ARRAY') {
+                $info{'offloadto'} .= $key.'='.join(',',@{$offloadto->{$key}}).'&';
+            }
+        }
+        $info{'offloadto'} =~ s/\&$//;
+    } elsif (ref($offloadto) eq 'ARRAY') {
+        $info{'offloadto'} = join(',',@{$offloadto});
+    }
     if ($newcookieid) {
         $info{'balcookie'} = $newcookieid;
     } elsif ($otherbalcookie) {
@@ -266,17 +330,24 @@ sub handler {
     }
     if ($env{'form.origurl'}) {
         $info{'origurl'} = $env{'form.origurl'};
+        if ($env{'form.origurl'} eq '/adm/email') {
+            if ($env{'request.display'} && ($env{'request.mailrecip'} eq "$env{'user.name'}:$env{'user.domain'}")) {
+                $info{'display'} = &escape($env{'request.display'});
+                $info{'mailrecip'} = &escape($env{'request.mailrecip'});
+            }
+        }
     }
     if ($env{'form.symb'}) {
         $info{'symb'} = $env{'form.symb'};
     }
-    my $ssologoutscript = ''; 
+    my $ssologoutscript = '';
+    my $write_to_opener;
     if ($env{'request.sso.login'}) {
 	$info{'sso.login'} = $env{'request.sso.login'};
         if (defined($r->dir_config("lonSSOUserLogoutScriptFile_$info{domain}"))) {
             if (open(my $fh,'<',$r->dir_config("lonSSOUserLogoutScriptFile_$info{domain}"))) {
                 $ssologoutscript .= join('',<$fh>);
-                close($fh);
+                close($fh); 
             }
         }
         if (defined($r->dir_config('lonSSOUserLogoutScriptFile'))) {
@@ -289,13 +360,65 @@ sub handler {
     if ($env{'request.sso.reloginserver'}) {
         $info{'sso.reloginserver'} = $env{'request.sso.reloginserver'};
     }
+    if ($env{'request.linkprot'}) {
+        $info{'linkprot'} = $env{'request.linkprot'};
+        foreach my $item ('linkprotuser','linkprotexit','linkprotpbid','linkprotpburl') {
+            if ($env{'request.'.$item}) {
+                $info{$item} = $env{'request.'.$item};
+            }
+        }
+    } elsif ($env{'request.linkkey'} ne '') {
+        $info{'linkkey'} = $env{'request.linkkey'};
+    }
+    if ($env{'request.deeplink.login'}) {
+        $info{'deeplink.login'} = $env{'request.deeplink.login'};
+    }
+    if ($env{'request.lti.login'}) {
+        $info{'lti.login'} = $env{'request.lti.login'};
+    }
+    if ($env{'request.lti.uri'}) {
+        $info{'lti.uri'} = $env{'request.lti.uri'};
+    }
+    if ($env{'request.lti.reqcrs'}) {
+        $info{'lti.reqcrs'} = $env{'request.lti.reqcrs'};
+    }
+    if ($env{'request.lti.reqrole'}) {
+        $info{'lti.reqrole'} = $env{'request.lti.reqrole'};
+    }
+    if ($env{'request.lti.selfenrollrole'}) {
+        $info{'lti.selfenrollrole'} = $env{'request.lti.selfenrollrole'};
+    }
+    if ($env{'request.lti.sourcecrs'}) {
+        $info{'lti.sourcecrs'} = $env{'request.lti.sourcecrs'};
+    }
+    if ($env{'request.lti.passbackid'}) {
+        $info{'lti.passbackid'} = $env{'request.lti.passbackid'};
+    }
+    if ($env{'request.lti.passbackurl'}) {
+        $info{'lti.passbackurl'} = $env{'request.lti.passbackurl'};
+    }
+    if ($env{'request.lti.rosterid'}) {
+        $info{'lti.rosterid'} = $env{'request.lti.rosterid'};
+    }
+    if ($env{'request.lti.rosterurl'}) {
+        $info{'lti.rosterurl'} = $env{'request.lti.rosterurl'};
+    }
+    if ($env{'request.lti.target'}) {
+        $info{'lti.target'} = $env{'request.lti.target'};
+    }
     my $token = &Apache::lonnet::tmpput(\%info,$env{'form.otherserver'});
-    my $url =$protocol.'://'.$switch_to.'/adm/login?'.
-	'domain='.$env{'user.domain'}.
-	'&amp;username='.$env{'user.name'}.
-	'&amp;token='.$token;
+    my @args = ("domain=$env{'user.domain'}",
+                "username=$env{'user.name'}",
+                "token=$token");
+    my $url = $protocol.'://'.$switch_to.'/adm/login?';
+    if ($env{'form.lcssowin'}) {
+        $url .= join('&',@args);
+        $only_body = 1;
+    } else {
+        $url .= join('&amp;',@args);
+    }
 # --------------------------------------------------------------- Screen Output
-    return &do_redirect($r, $url, $only_body, $ssologoutscript);
+    return &do_redirect($r, $url, $only_body, $ssologoutscript, $env{'form.lcssowin'});
 }
 
 1;