--- loncom/auth/lonroles.pm 2021/01/04 03:50:53 1.269.2.38 +++ loncom/auth/lonroles.pm 2021/12/12 18:17:11 1.269.2.39 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # User Roles Screen # -# $Id: lonroles.pm,v 1.269.2.38 2021/01/04 03:50:53 raeburn Exp $ +# $Id: lonroles.pm,v 1.269.2.39 2021/12/12 18:17:11 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -144,6 +144,59 @@ use GDBM_File; use LONCAPA qw(:DEFAULT :match); use HTML::Entities; +sub start_loading_course { + my ($r,$title) = @_; + &Apache::loncommon::content_type($r,'text/html'); + &Apache::loncommon::no_cache($r); + $r->send_http_header; + my $swinfo=&Apache::lonmenu::rawconfig(); + # Breadcrumbs + my $brcrum = [{'href' => '', + 'text' => $title},]; + my $start_page = &Apache::loncommon::start_page($title,undef, + {'bread_crumbs' => $brcrum, + 'bread_crumbs_nomenu' => 1, + 'links_disabled' => 1}); + $r->print(< +// + +ENDREDIR + return; +} + +sub finish_loading_course { + my ($r,$msg,$url) = @_; + my $link = ''; + my $end_page = &Apache::loncommon::end_page(); + my $js_url = &js_escape($url); + $r->print(< +// a').removeAttr("aria-disabled"); + \$('.isDisabled').removeClass("isDisabled"); + var url = "$js_url"; + \$(location).attr('href',url); +}); + +$link +$end_page +END + return; +} sub redirect_user { my ($r,$title,$url,$msg) = @_; @@ -179,29 +232,22 @@ ENDREDIR sub error_page { my ($r,$error,$dest)=@_; - &Apache::loncommon::content_type($r,'text/html'); - &Apache::loncommon::no_cache($r); - $r->send_http_header; - return OK if $r->header_only; - # Breadcrumbs - my $brcrum = [{'href' => $dest, - 'text' => 'Problems during Course Initialization'},]; - $r->print(&Apache::loncommon::start_page('Problems during Course Initialization', - undef, - {'bread_crumbs' => $brcrum,}) - ); - $r->print( - ''. - '

'.&mt('The following problems occurred:'). - '
'. - $error. - '


'.&mt('Continue').'' + my %lt = &Apache::lonlocal::texthash( + pdc => 'Problems during Course Initialization', + tfp => 'The following problems occurred:', + con => 'Continue', ); - $r->print(&Apache::loncommon::end_page()); + my $end_page = &Apache::loncommon::end_page(); + $dest = &HTML::Entities::encode($dest,'"<>&'); + $r->print(<$lt{'pdc'} +

$lt{'tfp'} +
+$error +


$lt{'con'} +$end_page +END + return; } sub handler { @@ -227,6 +273,92 @@ sub handler { $update = $then; } + my ($blocked_by_ip,$blocked_type,$clientip); + $clientip = &Apache::lonnet::get_requestor_ip($r); + + if ($env{'form.selectrole'}) { + my ($role,$cdom,$cnum,$rest); + if ($env{'form.switchrole'} =~ m{^(co|cc|in|ta|ep|ad|st|cr).*?\./($match_domain)/($match_courseid)(/(\w+)|$)}) { + ($role,$cdom,$cnum,$rest) = ($1,$2,$3,$4); + } elsif ($env{'form.newrole'} =~ m{^(co|cc|in|ta|ep|ad|st|cr).*?\./($match_domain)/($match_courseid)(/(\w+)|$)}) { + ($role,$cdom,$cnum,$rest) = ($1,$2,$3,$4); + } + if ($cdom ne '') { + my ($has_evb,$check_ipaccess,$showrole); + $showrole = 1; + my $checkrole = "cm./$cdom/$cnum"; + if ($rest ne '') { + $checkrole .= "/$rest"; + } + if ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) && + ($role ne 'st')) { + $has_evb = 1; + } + unless ($has_evb) { + my @machinedoms = &Apache::lonnet::current_machine_domains(); + my $udom = $env{'user.domain'}; + if ($udom eq $cdom) { + $check_ipaccess = 1; + } elsif (($udom ne '') && (grep(/^\Q$udom\E$/,@machinedoms))) { + $check_ipaccess = 1; + } else { + my $lonhost = $Apache::lonnet::perlvar{'lonHostID'}; + my $internet_names = &Apache::lonnet::get_internet_names($lonhost); + my $cprim = &Apache::lonnet::domain($cdom,'primary'); + my $cintdom = &Apache::lonnet::internet_dom($cprim); + if (($cintdom ne '') && (ref($internet_names) eq 'ARRAY')) { + if (grep(/^\Q$cintdom\E$/,@{$internet_names})) { + $check_ipaccess = 1; + } + } + } + if ($check_ipaccess) { + my ($ipaccessref,$cached)=&Apache::lonnet::is_cached_new('ipaccess',$cdom); + unless (defined($cached)) { + my %domconfig = + &Apache::lonnet::get_dom('configuration',['ipaccess'],$cdom); + $ipaccessref = &Apache::lonnet::do_cache_new('ipaccess',$cdom,$domconfig{'ipaccess'},1800); + } + if (ref($ipaccessref) eq 'HASH') { + foreach my $id (keys(%{$ipaccessref})) { + if (ref($ipaccessref->{$id}) eq 'HASH') { + my $range = $ipaccessref->{$id}->{'ip'}; + if ($range) { + my $type = 'exclude'; + if (&Apache::lonnet::ip_match($clientip,$range)) { + $type = 'include'; + } + if (ref($ipaccessref->{$id}->{'courses'}) eq 'HASH') { + if ($ipaccessref->{$id}->{'courses'}{$cdom.'_'.$cnum}) { + if ($type eq 'include') { + $showrole = 1; + last; + } else { + $showrole = 0; + } + } else { + if ($type eq 'include') { + $showrole = 0; + } else { + $showrole = 1; + } + } + } + } + } + } + } + } + } + unless ($showrole) { + $blocked_by_ip = 1; + $blocked_type = &Apache::loncommon::course_type($cdom.'_'.$cnum); + delete($env{'form.selectrole'}); + delete($env{'form.newrole'}); + } + } + } + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}); # -------------------------------------------------- Check if setting hot list @@ -581,10 +713,37 @@ ENDENTERKEY } } } - my $msg; + my $crstype = &Apache::loncommon::course_type($cdom.'_'.$cnum); + $crstype = lc($crstype); + my $preamble = '
'. + '
'. + &mt("Please be patient while your $crstype loads"). + '
'. + '
'; + my $closure = < +// + +ENDCLOSE + my $title = &mt("Loading $crstype"); + &start_loading_course($r,$title); + my %prog_state = &Apache::lonhtmlcommon::Create_PrgWin($r,undef,$preamble); + &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Loading ...')); + $r->rflush(); + my ($msg,$critmsg_check); + $critmsg_check = 1; my ($furl,$ferr)= - &Apache::lonuserstate::readmap($cdom.'/'.$cnum); - unless ($ferr) { + &Apache::lonuserstate::readmap($cdom.'/'.$cnum,$critmsg_check); + &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Finished!')); + &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state); + $r->print($closure); + $r->rflush(); + if ($ferr) { + $furl = '/adm/roles?tryagain=1'; + } else { + &Apache::lonnet::appenv({'request.course.timechecked'=>$now}); unless (($env{'form.switchrole'}) || ($env{"environment.internal.$cdom.$cnum.$role.adhoc"})) { &Apache::lonnet::put('nohist_crslastlogin', @@ -639,9 +798,24 @@ ENDENTERKEY } if (&Apache::lonnet::allowed('adv') eq 'F') { $tadv=1; } &Apache::lonnet::appenv({'request.role.adv'=>$tadv}); + if ($ferr) { + if ($env{'form.orgurl'}) { + $furl .= '&orgurl='.&HTML::Entities::encode($env{'form.orgurl'},'<>&"'); + } + if ($env{'form.symb'}) { + $furl .= '&symb='.&HTML::Entities::encode($env{'form.symb'},'<>&"'); + } + } if (($ferr) && ($tadv)) { - &error_page($r,$ferr,$dest); + &error_page($r,$ferr,$furl); } else { + if ($env{'request.course.id'} eq $cdom.'_'.$cnum) { + if (($env{'form.orgurl'} ne '') && ($env{'form.symb'} ne '')) { + unless (&Apache::lonnet::symbverify($env{'form.symb'},$env{'form.orgurl'})) { + $dest=$env{'form.orgurl'}; + } + } + } if ($dest =~ m{^/adm/coursedocs\?folderpath}) { if ($env{'request.course.id'} eq $cdom.'_'.$cnum) { my $chome = &Apache::lonnet::homeserver($cnum,$cdom); @@ -649,26 +823,49 @@ ENDENTERKEY $cdom.'_'.$cnum); } } - $r->internal_redirect($dest); + if ($ferr) { + if (!$env{'request.course.id'}) { + &Apache::lonnet::appenv( + {"request.course.id" => $cdom.'_'.$cnum}); + $r->print('

'. + &mt('Could not initialize [_1] at this time.', + $env{'course.'.$cdom.'_'.$cnum.'.description'}). + '

'. + '

'. + &mt('Please try again.').'

'. + &Apache::loncommon::end_page()); + } + } else { + if (($env{'request.lti.login'}) && + ($env{'request.lti.rosterid'} || $env{'request.lti.passbackid'})) { + &process_lti($r,$cdom,$cnum); + } + $msg = '

'.&mt('Entering [_1] ...', + $env{'course.'.$cdom.'_'.$cnum.'.description'}). + '

'; + &finish_loading_course($r,$msg,$dest); + } } + $r->rflush(); return OK; } else { if (!$env{'request.course.id'}) { &Apache::lonnet::appenv( {"request.course.id" => $cdom.'_'.$cnum}); - $furl='/adm/roles?tryagain=1'; - $msg='

' - .&mt('Could not initialize [_1] at this time.', - $env{'course.'.$cdom.'_'.$cnum.'.description'}) - .'

' - .'

'.&mt('Please try again.').'

' - .'

'.$ferr.'

'; - } + } if (&Apache::lonnet::allowed('adv') eq 'F') { $tadv=1; } &Apache::lonnet::appenv({'request.role.adv'=>$tadv}); - - if (($ferr) && ($tadv)) { - &error_page($r,$ferr,$furl); + if ($ferr) { + if ($tadv) { + &error_page($r,$ferr,$furl); + } else { + $r->print('

'. + &mt('Could not initialize [_1] at this time.', + $env{'course.'.$cdom.'_'.$cnum.'.description'}). + '

'. + '

'.&mt('Please try again.').'

'. + &Apache::loncommon::end_page()); + } } else { # Check to see if the user is a CC entering a course # for the first time @@ -692,8 +889,9 @@ ENDENTERKEY if (($dest =~ m{^\Q/public/$cdom/$cnum/syllabus\E.*(\?|\&)usehttp=1}) || ($dest =~ m{^\Q/adm/wrapper/ext/\E(?!https:)})) { if ($ENV{'SERVER_PORT'} == 443) { - unless (&Apache::lonnet::uses_sts()) { - my $hostname = $r->hostname(); + my $hostname = $r->hostname(); + unless ((&Apache::lonnet::uses_sts()) || + (&Apache::lonnet::waf_allssl($hostname))) { if ($hostname ne '') { $dest = 'http://'.$hostname.$dest; } @@ -735,9 +933,11 @@ ENDENTERKEY $dest .= (($dest =~/\?/)? '&':'?').'symb='.$esc_symb; } } - &redirect_user($r, &mt('Entering [_1]', - $env{'course.'.$cdom.'_'.$cnum.'.description'}), - $dest, $msg); + $msg = '

'.&mt('Entering [_1] ...', + $env{'course.'.$cdom.'_'.$cnum.'.description'}). + '

'; + &finish_loading_course($r,$msg,$dest); + $r->rflush(); return OK; } if (&Apache::lonnet::allowed('whn', @@ -748,40 +948,62 @@ ENDENTERKEY ) { my $startpage = &courseloadpage($env{'request.course.id'}); unless ($startpage eq 'firstres') { - $msg = &mt('Entering [_1] ...', - $env{'course.'.$env{'request.course.id'}.'.description'}); - &redirect_user($r, &mt('New in course'), - '/adm/whatsnew?refpage=start', $msg); - return OK; + $msg = '

'.&mt('Entering [_1] ...', + $env{'course.'.$cdom.'_'.$cnum.'.description'}). + '

'; + &finish_loading_course($r,$msg,'/adm/whatsnew?refpage=start'); + $r->rflush(); + return OK; } } } # Are we allowed to look at the first resource? - my $access; - if ($furl =~ m{^(/adm/wrapper|)/ext/}) { - # If it's an external resource, - # strip off the symb argument and possible query - my ($exturl,$symb) = ($furl =~ m{^(.+)(?:\?|\&)symb=(.+)$}); - # Unencode $symb - $symb = &unescape($symb); - # Then check for permission - $access = &Apache::lonnet::allowed('bre',$exturl,$symb); - # For other resources just check for permission + # + # $furl returned by lonuserstate::readmap() has format: + # $url?symb=escaped($symb). If the resource has the + # encrypturl parameter in effect, the entire string + # $url?symb=escaped($symb) is encrypted as a string + # beginning /enc/. + # + my ($access,$unencfurl,$unencsymb); + if ($furl =~ m{^(.+)(?:\?|\&)symb=([^&]+)(?:$|&)}) { + my ($poss_url,$poss_symb) = ($1,$2); + $unencsymb = &unescape($poss_symb); + $unencfurl = $poss_url; + } elsif ($furl =~ m{^/enc/}) { + my $unenc = &Apache::lonenc::unencrypted($furl); + if ($unenc =~ m{^(.+)(?:\?|\&)symb=([^&]+)(?:$|&)}) { + ($unencfurl,$unencsymb) = ($1,$2); + $unencsymb = &unescape($unencsymb); + } else { + $unencfurl = $unenc; + } + } else { + $unencfurl = $furl; + } + if ($unencsymb) { + my $symb = &Apache::lonnet::symbclean($unencsymb); + if (($symb ne '') && (&Apache::lonnet::symbverify($symb,$unencfurl))) { + $access = &Apache::lonnet::allowed('bre',$unencfurl,$symb); + } else { + $access = &Apache::lonnet::allowed('bre',$unencfurl); + } } else { - $access = &Apache::lonnet::allowed('bre',$furl); + $access = &Apache::lonnet::allowed('bre',$unencfurl); } - if (!$access) { + if ((!$access) || ($access eq 'B')) { $furl = &Apache::lonpageflip::first_accessible_resource(); - } elsif ($access eq 'B') { - $furl = '/adm/navmaps?showOnlyHomework=1'; + if ($furl eq '') { + $furl = '/adm/navmaps?showOnlyHomework=1'; + } } - $msg = &mt('Entering [_1] ...', - $env{'course.'.$cdom.'_'.$cnum.'.description'}); - &redirect_user($r, &mt('Entering [_1]', - $env{'course.'.$cdom.'_'.$cnum.'.description'}), - $furl, $msg); + $msg = '

'.&mt('Entering [_1] ...', + $env{'course.'.$cdom.'_'.$cnum.'.description'}). + '

'; + &finish_loading_course($r,$msg,$furl); } - return OK; + $r->rflush(); + return OK; } } # @@ -857,8 +1079,8 @@ ENDENTERKEY if ($domdefs{'catauth'}) { $cattype = $domdefs{'catauth'}; } - my $funcs = &get_roles_functions($showcount,$cattype); - my $crumbsright; + my ($funcs,$crumbsright); + $funcs = &get_roles_functions($showcount,$cattype); if ($env{'browser.mobile'}) { $crumbsright = $funcs; undef($funcs); @@ -998,6 +1220,16 @@ ENDHEADER $r->print(''); $r->print(''); $r->print(''); + if ($blocked_by_ip) { + my $blocked_role = 'student'; + if ($blocked_type eq 'Community') { + $blocked_role = 'member'; + } + $r->print('

'. + &mt('The [_1] you selected is not available for access with a [_2] role from your current IP address: [_3].', + lc($blocked_type),$blocked_role,$clientip). + '

'); + } } $r->rflush(); @@ -1272,6 +1504,7 @@ sub gather_roles { $trole=Apache::lonnet::plaintext($role); my $ttype; my $twhere; + my $skipcal; my ($tdom,$trest,$tsection)= split(/\//,Apache::lonnet::declutter($where)); # First, Co-Authorship roles @@ -1386,6 +1619,7 @@ sub gather_roles { $env{'course.'.$tcourseid.'.description'}=$twhere; $sortkey=$role."\0".$tdom."\0".$twhere."\0".$envkey; $ttype = 'Unavailable'; + $skipcal = 1; } } if ($tsection) { @@ -1404,7 +1638,8 @@ sub gather_roles { ($role_text,$role_text_end) = &build_roletext($trolecode,$tdom,$trest,$tstatus,$tryagain, $advanced,$tremark,$tbg,$trole,$twhere,$tpstart, - $tpend,$nochoose,$button,$switchserver,$reinit,$switchwarning); + $tpend,$nochoose,$button,$switchserver,$reinit, + $switchwarning,$skipcal); $roletext->{$envkey}=[$role_text,$role_text_end]; if (!$sortkey) {$sortkey=$twhere."\0".$envkey;} $sortrole->{$sortkey}=$envkey; @@ -1707,7 +1942,7 @@ sub privileges_info { sub build_roletext { my ($trolecode,$tdom,$trest,$tstatus,$tryagain,$advanced,$tremark,$tbg,$trole,$twhere, - $tpstart,$tpend,$nochoose,$button,$switchserver,$reinit,$switchwarning) = @_; + $tpstart,$tpend,$nochoose,$button,$switchserver,$reinit,$switchwarning,$skipcal) = @_; my ($roletext,$roletext_end,$poss_adhoc); if ($trolecode =~ m/^d(c|h|a)\./) { $poss_adhoc = 1; @@ -1765,7 +2000,7 @@ sub build_roletext { $trolecode."','".$buttonname.'\');" />'; } } - if ($trolecode !~ m/^(dc|ca|au|aa)\./) { + if (($trolecode !~ m/^(dc|ca|au|aa)\./) && (!$skipcal)) { $tremark.=&Apache::lonannounce::showday(time,1, &Apache::lonannounce::readcalendar($tdom.'_'.$trest)); } @@ -2010,6 +2245,7 @@ sub display_cc_role { my $trolecode = $ccrole.'./'.$tdom.'/'.$trest; my $twhere; my $ttype; + my $skipcal; my $tbg='LC_roles_is'; my %newhash=&Apache::lonnet::coursedescription($tcourseid); if (%newhash) { @@ -2021,10 +2257,11 @@ sub display_cc_role { } else { $twhere=&mt('Currently not available'); $env{'course.'.$tcourseid.'.description'}=$twhere; + $skipcal = 1; } my $trole = &Apache::lonnet::plaintext($ccrole,$ttype,$tcourseid); $twhere.="
".&mt('Domain').":".$tdom; - ($roletext,$roletext_end) = &build_roletext($trolecode,$tdom,$trest,'is',$tryagain,$advanced,'',$tbg,$trole,$twhere,'','','',1,''); + ($roletext,$roletext_end) = &build_roletext($trolecode,$tdom,$trest,'is',$tryagain,$advanced,'',$tbg,$trole,$twhere,'','','',1,'','','',$skipcal); } } return ($roletext,$roletext_end);