[LON-CAPA-cvs] cvs: doc /loncapafiles loncapafiles.lpml loncom loncapa_apache.conf loncron lond loncom/interface domainprefs.pm lonconfigsettings.pm loncom/lonnet/perl lonnet.pm loncom/lti ltiauth.pm ltilogout.pm ltiutils.pm

raeburn raeburn at source.lon-capa.org
Thu Jul 18 14:29:05 EDT 2019


raeburn		Thu Jul 18 18:29:05 2019 EDT

  Added files:                 
    /loncom/lti	ltilogout.pm 

  Modified files:              
    /loncom	lond loncron loncapa_apache.conf 
    /loncom/lti	ltiutils.pm ltiauth.pm 
    /loncom/interface	domainprefs.pm lonconfigsettings.pm 
    /loncom/lonnet/perl	lonnet.pm 
    /doc/loncapafiles	loncapafiles.lpml 
  Log:
  - Bug 6754. LON-CAPA as LTI Provider. 
    Domain configuration to support session expiration in LON-CAPA,
    after user logs out of LTI Consumer which originally launched session,
    (if Consumer supports logoutServiceUrl; e.g. custom_logout_url in Canvas).  
  
  
-------------- next part --------------
Index: loncom/lond
diff -u loncom/lond:1.559 loncom/lond:1.560
--- loncom/lond:1.559	Tue Jul  2 19:40:18 2019
+++ loncom/lond	Thu Jul 18 18:28:40 2019
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
 #
-# $Id: lond,v 1.559 2019/07/02 19:40:18 raeburn Exp $
+# $Id: lond,v 1.560 2019/07/18 18:28:40 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -65,7 +65,7 @@
 my $status='';
 my $lastlog='';
 
-my $VERSION='$Revision: 1.559 $'; #' stupid emacs
+my $VERSION='$Revision: 1.560 $'; #' stupid emacs
 my $remoteVERSION;
 my $currenthostid="default";
 my $currentdomainid;
@@ -227,6 +227,7 @@
                dcmailput => {remote => 1, domroles => 1},
                del => {remote => 1, domroles => 1, enroll => 1, content => 1},
                delbalcookie => {institutiononly => 1},
+               delusersession => {institutiononly => 1},
                deldom => {remote => 1, domroles => 1}, # not currently used
                devalidatecache => {institutiononly => 1},
                domroleput => {remote => 1, enroll => 1},
@@ -3033,6 +3034,54 @@
 }
 &register_handler("userhassession", \&user_has_session_handler, 0,1,0);
 
+sub del_usersession_handler {
+    my ($cmd, $tail, $client) = @_;
+
+    my $result;
+    my ($udom, $uname) = map { &unescape($_) } (split(/:/, $tail));
+    if (($udom =~ /^$LONCAPA::match_domain$/) && ($uname =~ /^$LONCAPA::match_username$/)) {
+        my $lonidsdir = $perlvar{'lonIDsDir'};
+        if (-d $lonidsdir) {
+            if (opendir(DIR,$lonidsdir)) {
+                my $filename;
+                while ($filename=readdir(DIR)) {
+                    if ($filename=~/^\Q$uname\E_\d+_\Q$udom\E_/) {
+                        if (tie(my %oldenv,'GDBM_File',"$lonidsdir/$filename",
+                                &GDBM_READER(),0640)) {
+                            my $linkedfile;
+                            if (exists($oldenv{'user.linkedenv'})) {
+                                $linkedfile = $oldenv{'user.linkedenv'};
+                            }
+                            untie(%oldenv);
+                            $result = unlink("$lonidsdir/$filename");
+                            if ($result) {
+                                if ($linkedfile =~ /^[a-f0-9]+_linked$/) {
+                                    if (-l "$lonidsdir/$linkedfile.id") {
+                                        unlink("$lonidsdir/$linkedfile.id");
+                                    }
+                                }
+                            }
+                        } else {
+                            $result = unlink("$lonidsdir/$filename");
+                        }
+                        last;
+                    }
+                }
+            }
+        }
+        if ($result == 1) {
+            &Reply($client, "$result\n", "$cmd:$tail");
+        } else {
+            &Reply($client, "not_found\n", "$cmd:$tail");
+        }
+    } else {
+        &Failure($client, "invalid_user\n", "$cmd:$tail");
+    }
+    return 1;
+}
+
+&register_handler("delusersession", \&del_usersession_handler, 0,1,0);
+
 #
 #  Authenticate access to a user file by checking that the token the user's 
 #  passed also exists in their session file
Index: loncom/loncron
diff -u loncom/loncron:1.118 loncom/loncron:1.119
--- loncom/loncron:1.118	Mon Mar 18 00:37:37 2019
+++ loncom/loncron	Thu Jul 18 18:28:40 2019
@@ -2,7 +2,7 @@
 
 # Housekeeping program, started by cron, loncontrol and loncron.pl
 #
-# $Id: loncron,v 1.118 2019/03/18 00:37:37 raeburn Exp $
+# $Id: loncron,v 1.119 2019/07/18 18:28:40 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -567,6 +567,34 @@
     }
 }
 
+# ------------------------------------------------------------ clean out ltiIDs
+
+sub clean_ltiIDs {
+    my ($fh)=@_;
+    &log($fh,'<hr /><a name="ltisessions" /><h2>LTI Session Pointers</h2>');
+    my $cleaned=0;
+    my $active=0;
+    if (-d $perlvar{'ltiIDsDir'}) {
+        while (my $fname=<$perlvar{'ltiIDsDir'}/*>) {
+            my ($dev,$ino,$mode,$nlink,
+                $uid,$gid,$rdev,$size,
+                $atime,$mtime,$ctime,
+                $blksize,$blocks)=stat($fname);
+            my $now=time;
+            my $since=$now-$mtime;
+            if ($since>$perlvar{'lonExpire'}) {
+                $cleaned++;
+                &log($fh,"Unlinking $fname<br />");
+                unlink("$fname");
+            } else {
+                $active++;
+            }
+        }
+    }
+    &log($fh,"<p>Cleaned up ".$cleaned." old LTI session pointers.</p>");
+    &log($fh,"<h3>$active unexpired LTI session pointers</h3>");
+}
+
 # ----------------------------------------------------------- clean out sockets
 sub clean_sockets {
     my ($fh)=@_;
@@ -1595,6 +1623,7 @@
 	&clean_lonIDs($fh);
         &clean_balanceIDs($fh);
         &clean_webDAV_sessionIDs($fh);
+        &clean_ltiIDs($fh);
 	&check_httpd_logs($fh);
 	&rotate_lonnet_logs($fh);
 	&rotate_other_logs($fh);
Index: loncom/loncapa_apache.conf
diff -u loncom/loncapa_apache.conf:1.268 loncom/loncapa_apache.conf:1.269
--- loncom/loncapa_apache.conf:1.268	Thu May  2 02:18:10 2019
+++ loncom/loncapa_apache.conf	Thu Jul 18 18:28:40 2019
@@ -2,7 +2,7 @@
 ## loncapa_apache.conf -- Apache HTTP LON-CAPA configuration file
 ##
 
-# $Id: loncapa_apache.conf,v 1.268 2019/05/02 02:18:10 raeburn Exp $
+# $Id: loncapa_apache.conf,v 1.269 2019/07/18 18:28:40 raeburn Exp $
 
 #
 # LON-CAPA Section (extensions to httpd.conf daemon configuration)
@@ -780,6 +780,11 @@
 PerlHandler Apache::ltiroster
 </Location>
 
+<LocationMatch "^/adm/service/logout/\w+$">
+SetHandler perl-script
+PerlHandler Apache::ltilogout
+</LocationMatch>
+
 <Location /adm/restrictedaccess>
 PerlAccessHandler      Apache::publiccheck
 AuthType LONCAPA
@@ -1784,6 +1789,7 @@
 PerlSetVar       lonCaptchaDir     /home/httpd/captchaspool
 PerlSetVar       lonCaptchaDb     /home/httpd/captchadb 
 PerlSetVar       lonLTIDir    /home/httpd/lonLTItmp
+PerlSetVar       ltiIDsDir    /home/httpd/ltiIDs
 PerlSetVar       lonFontsDir     /home/httpd/html/adm/fonts
 # & separated list of % separated fields in order of
 # - internal name to call it, 
Index: loncom/lti/ltiutils.pm
diff -u loncom/lti/ltiutils.pm:1.16 loncom/lti/ltiutils.pm:1.17
--- loncom/lti/ltiutils.pm:1.16	Sun Mar 31 18:48:33 2019
+++ loncom/lti/ltiutils.pm	Thu Jul 18 18:28:46 2019
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Utility functions for managing LON-CAPA LTI interactions 
 #
-# $Id: ltiutils.pm,v 1.16 2019/03/31 18:48:33 raeburn Exp $
+# $Id: ltiutils.pm,v 1.17 2019/07/18 18:28:46 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -31,6 +31,7 @@
 use strict;
 use Net::OAuth;
 use Digest::SHA;
+use Digest::MD5 qw(md5_hex);
 use UUID::Tiny ':std';
 use Apache::lonnet;
 use Apache::loncommon;
@@ -339,14 +340,20 @@
 # 
 
 sub sign_params {
-    my ($url,$key,$secret,$sigmethod,$paramsref) = @_;
+    my ($url,$key,$secret,$paramsref,$sigmethod,$type,$callback,$post) = @_;
     return unless (ref($paramsref) eq 'HASH');
     if ($sigmethod eq '') {
         $sigmethod = 'HMAC-SHA1';
     }
+    if ($type eq '') {
+        $type = 'request token';
+    }
+    if ($callback eq '') {
+        $callback = 'about:blank',
+    }
     srand( time() ^ ($$ + ($$ << 15))  ); # Seed rand.
     my $nonce = Digest::SHA::sha1_hex(sprintf("%06x%06x",rand(0xfffff0),rand(0xfffff0)));
-    my $request = Net::OAuth->request("request token")->new(
+    my $request = Net::OAuth->request($type)->new(
             consumer_key => $key,
             consumer_secret => $secret,
             request_url => $url,
@@ -354,12 +361,16 @@
             signature_method => $sigmethod,
             timestamp => time,
             nonce => $nonce,
-            callback => 'about:blank',
+            callback => $callback,
             extra_params => $paramsref,
             version      => '1.0',
             );
     $request->sign();
-    return $request->to_hash();
+    if ($post) {
+        return $request->to_post_body();
+    } else {
+        return $request->to_hash();
+    }
 }
 
 #
@@ -647,7 +658,7 @@
         lti_message_type           => 'basic-lis-readmembershipsforcontext',
         ext_ims_lis_memberships_id => $id,
     );
-    my $hashref = &sign_params($url,$ckey,$secret,'',\%ltiparams);
+    my $hashref = &sign_params($url,$ckey,$secret,\%ltiparams);
     if (ref($hashref) eq 'HASH') {
         my $request=new HTTP::Request('POST',$url);
         $request->content(join('&',map {
@@ -735,7 +746,7 @@
             result_statusofresult         => 'final',
             result_date                   => $date,
         );
-        my $hashref = &sign_params($url,$ckey,$secret,$sigmethod,\%ltiparams);
+        my $hashref = &sign_params($url,$ckey,$secret,\%ltiparams,$sigmethod);
         if (ref($hashref) eq 'HASH') {
             $request=new HTTP::Request('POST',$url);
             $request->content(join('&',map {
@@ -807,6 +818,28 @@
 #FIXME Handle case where pass back of score to LTI Consumer failed.
 }
 
+sub setup_logout_callback {
+    my ($uname,$udom,$server,$ckey,$secret,$service_url,$idsdir,$protocol,$hostname) = @_;
+    if ($service_url =~ m{^https?://[^/]+/}) {
+        my $digest_user = &Encode::decode_utf8($uname.':'.$udom);
+        my $loginfile = &Digest::SHA::sha1_hex($digest_user).&md5_hex(&md5_hex(time.{}.rand().$$));
+        if ((-d $idsdir) && (open(my $fh,'>',"$idsdir/$loginfile"))) {
+            print $fh "$uname,$udom,$server\n";
+            close($fh);
+            my $callback = 'http://'.$hostname.'/adm/service/logout/'.$loginfile;
+            my %ltiparams = (
+                callback   => $callback,
+            );
+            my $post = &sign_params($service_url,$ckey,$secret,\%ltiparams,
+                                    '','','',1);
+            my $request=new HTTP::Request('POST',$service_url);
+            $request->content($post);
+            my $response = &LONCAPA::LWPReq::makerequest('',$request,'','',10);
+        }
+    }
+    return;
+}
+
 #
 # LON-CAPA as LTI Provider
 #
Index: loncom/lti/ltiauth.pm
diff -u loncom/lti/ltiauth.pm:1.18 loncom/lti/ltiauth.pm:1.19
--- loncom/lti/ltiauth.pm:1.18	Thu Jun 13 17:45:26 2019
+++ loncom/lti/ltiauth.pm	Thu Jul 18 18:28:46 2019
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Basic LTI Authentication Module
 #
-# $Id: ltiauth.pm,v 1.18 2019/06/13 17:45:26 raeburn Exp $
+# $Id: ltiauth.pm,v 1.19 2019/07/18 18:28:46 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -749,9 +749,21 @@
             }
         }
     }
+    my $protocol = 'http';
+    if ($ENV{'SERVER_PORT'} == 443) {
+        $protocol = 'https';
+    }
     if (($is_balancer) && (!$hosthere)) {
         # login but immediately go to switch server.
         &Apache::lonauth::success($r,$uname,$udom,$uhome,'noredirect');
+        if (($ltihash->{'callback'}) && ($params->{$ltihash->{'callback'}})) {
+            &LONCAPA::ltiutils::setup_logout_callback($uname,$udom,$otherserver,
+                                                      $ltihash->{'key'},
+                                                      $ltihash->{'secret'},
+                                                      $params->{$ltihash->{'callback'}},
+                                                      $r->dir_config('ltiIDsDir'),
+                                                      $protocol,$r->hostname);
+        }
         if ($symb) {
             $env{'form.symb'} = $symb;
             $env{'request.lti.uri'} = $tail;
@@ -818,6 +830,14 @@
         foreach my $key (%{$params}) {
             delete($env{'form.'.$key});
         }
+        if (($ltihash->{'callback'}) && ($params->{$ltihash->{'callback'}})) {
+            &LONCAPA::ltiutils::setup_logout_callback($uname,$udom,$lonhost,
+                                                      $ltihash->{'key'},
+                                                      $ltihash->{'secret'},
+                                                      $params->{$ltihash->{'callback'}},
+                                                      $r->dir_config('ltiIDsDir'),
+                                                      $protocol,$r->hostname);
+        }
         my $ip = $r->get_remote_host();
         my %info=('ip'        => $ip,
                   'domain'    => $udom,
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.362 loncom/interface/domainprefs.pm:1.363
--- loncom/interface/domainprefs.pm:1.362	Tue Jun  4 03:16:19 2019
+++ loncom/interface/domainprefs.pm	Thu Jul 18 18:28:52 2019
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: domainprefs.pm,v 1.362 2019/06/04 03:16:19 raeburn Exp $
+# $Id: domainprefs.pm,v 1.363 2019/07/18 18:28:52 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -2905,7 +2905,7 @@
                 }
             }
         }
-    } else if ((setting == 'user') || (setting == 'crs') || (setting == 'passback')) {
+    } else if ((setting == 'user') || (setting == 'crs') || (setting == 'passback') || (setting == 'callback')) {
         var radioname = '';
         var divid = '';
         if (setting == 'user') {
@@ -2914,6 +2914,9 @@
         } else if (setting == 'crs') {
             radioname = 'lti_mapcrs_'+item;
             divid = 'lti_crsfield_'+item;
+        } else if (setting == 'callback') {
+            radioname = 'lti_callback_'+item;
+            divid = 'lti_callbackfield_'+item;
         } else {
             radioname = 'lti_passback_'+item;
             divid =  'lti_passback_'+item;
@@ -2923,7 +2926,7 @@
             var setvis = '';
             for (var i=0; i<num; i++) {
                if (form.elements[radioname][i].checked) {
-                   if (setting == 'passback') {
+                   if ((setting == 'passback') || (setting == 'callback')) {
                        if (form.elements[radioname][i].value == '1') {
                            if (document.getElementById(divid)) {
                                document.getElementById(divid).style.display = 'inline-block';
@@ -4957,7 +4960,7 @@
 
 sub lti_options {
     my ($num,$current,$itemcount,%lt) = @_;
-    my (%checked,%rolemaps,$crssecsrc,$userfield,$cidfield);
+    my (%checked,%rolemaps,$crssecsrc,$userfield,$cidfield,$callback);
     $checked{'mapuser'}{'sourcedid'} = ' checked="checked"';
     $checked{'mapcrs'}{'course_offering_sourcedid'} = ' checked="checked"';
     $checked{'makecrs'}{'N'} = '  checked="checked"';
@@ -4975,6 +4978,7 @@
     my $crsfieldsty = 'none';
     my $crssecfieldsty = 'none';
     my $secsrcfieldsty = 'none';
+    my $callbacksty = 'none';
     my $passbacksty = 'none';
     my $optionsty = 'block';
     my $lcauthparm;
@@ -5054,6 +5058,13 @@
         } else {
             $checked{'crssec'}{'N'} = ' checked="checked"';
         }
+        if ($current->{'callback'} ne '') {
+            $callback = $current->{'callback'};
+            $checked{'callback'}{'Y'} = ' checked="checked"';
+            $callbacksty = 'inline-block';
+        } else {
+            $checked{'callback'}{'N'} = ' checked="checked"';
+        }
         if ($current->{'topmenu'}) {
             $checked{'topmenu'}{'Y'} = ' checked="checked"';
         } else {
@@ -5079,6 +5090,7 @@
     } else {
         $checked{'makecrs'}{'N'} = ' checked="checked"';
         $checked{'crssec'}{'N'} = ' checked="checked"';
+        $checked{'callback'}{'N'} = ' checked="checked"';
         $checked{'topmenu'}{'N'} = ' checked="checked"';
         $checked{'inlinemenu'}{'Y'} = ' checked="checked"'; 
         $checked{'menuitem'}{'grades'} = ' checked="checked"';
@@ -5107,6 +5119,7 @@
     my $onclickuser = ' onclick="toggleLTI(this.form,'."'user','$num'".');"';
     my $onclickcrs = ' onclick="toggleLTI(this.form,'."'crs','$num'".');"';
     my $onclicksec = ' onclick="toggleLTI(this.form,'."'sec','$num'".');"';
+    my $onclickcallback = ' onclick="toggleLTI(this.form,'."'callback','$num'".');"';
     my $onclicksecsrc = ' onclick="toggleLTI(this.form,'."'secsrc','$num'".')"';
     my $onclicklcauth = ' onclick="toggleLTI(this.form,'."'lcauth','$num'".')"';
     my $onclickmenu = ' onclick="toggleLTI(this.form,'."'lcmenu','$num'".');"';
@@ -5256,7 +5269,17 @@
                '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.1"'.$pb1p1chk.' />'.
                &mt('Outcomes Service (1.1)').'</label>'.(' 'x2).
                '<label><input type="radio" name="lti_passbackformat_'.$num.'" value="1.0"'.$pb1p0chk.'/>'.
-               &mt('Outcomes Extension (1.0)').'</label></span></div></fieldset>'.
+               &mt('Outcomes Extension (1.0)').'</label></span></div>'.
+               '<div style="padding:0;clear:both;margin:0;border:0"></div>'.
+               '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('Callback on logout').': '.
+               '<label><input type="radio" name="lti_callback_'.$num.'" value="0"'.
+               $checked{'callback'}{'N'}.$onclickcallback.' />'.&mt('No').'</label>'.(' 'x2).
+               '<label><input type="radio" name="lti_callback_'.$num.'" value="1"'.
+               $checked{'callback'}{'Y'}.$onclickcallback.' />'.&mt('Yes').'</label></span></div>'.
+               '<div class="LC_floatleft" style="display:'.$callbacksty.';" id="lti_callbackfield_'.$num.'">'.
+               '<span class="LC_nobreak">'.&mt('Parameter').': '.
+               '<input type="text" name="lti_callbackparam_'.$num.'" value="'.$callback.'" /></span>'.
+               '</div><div style="padding:0;clear:both;margin:0;border:0"></div></fieldset>'.
                '<fieldset class="ltioption_'.$num.'" style="display:'.$optionsty.'"><legend>'.&mt('Course defaults (Course Coordinator can override)').'</legend>'.
                '<div class="LC_floatleft"><span class="LC_nobreak">'.$lt{'topmenu'}.': '.
                '<label><input type="radio" name="lti_topmenu_'.$num.'" value="0"'.
@@ -12675,6 +12698,13 @@
                     }
                 }
             }
+            if ($env{'form.lti_callback_'.$idx}) {
+                if ($env{'form.lti_callbackparam_'.$idx}) {
+                    my $callback = $env{'form.lti_callbackparam_'.$idx};
+                    $callback =~ s/^\s+|\s+$//g;
+                    $confhash{$itemid}{'callback'} = $callback;
+                }
+            }
             foreach my $field ('passback','roster','topmenu','inlinemenu') {
                 if ($env{'form.lti_'.$field.'_'.$idx}) {
                     $confhash{$itemid}{$field} = 1;
@@ -12700,7 +12730,7 @@
                 }
             }
             unless (($idx eq 'add') || ($changes{$itemid})) {
-                foreach my $field ('mapuser','mapcrs','makecrs','section','passback','roster','lcauth','lcauthparm','topmenu','inlinemenu') {
+                foreach my $field ('mapuser','mapcrs','makecrs','section','passback','roster','lcauth','lcauthparm','topmenu','inlinemenu','callback') {
                     if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) {
                         $changes{$itemid} = 1;
                     }
@@ -12926,6 +12956,11 @@
                         } else {
                             $resulttext .= '<li>'.&mt('No section assignment').'</li>';
                         }
+                        if ($confhash{$itemid}{'callback'}) {
+                            $resulttext .= '<li>'.&mt('Callback setting').': '.$confhash{$itemid}{'callback'}.'</li>';
+                        } else {
+                            $resulttext .= '<li>'.&mt('No callback to logout LON-CAPA session when user logs out of Comsumer');
+                        }
                         foreach my $item ('passback','roster','topmenu','inlinemenu') {
                             $resulttext .= '<li>'.$lt{$item}.': ';
                             if ($confhash{$itemid}{$item}) {
Index: loncom/interface/lonconfigsettings.pm
diff -u loncom/interface/lonconfigsettings.pm:1.45 loncom/interface/lonconfigsettings.pm:1.46
--- loncom/interface/lonconfigsettings.pm:1.45	Sun Jan 27 14:39:48 2019
+++ loncom/interface/lonconfigsettings.pm	Thu Jul 18 18:28:52 2019
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: lonconfigsettings.pm,v 1.45 2019/01/27 14:39:48 raeburn Exp $
+# $Id: lonconfigsettings.pm,v 1.46 2019/07/18 18:28:52 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -221,7 +221,8 @@
                            "toggleLTI(document.display,'sec','add');".
                            "toggleLTI(document.display,'lcauth','add');".
                            "toggleLTI(document.display,'lcmenu','add');".
-                           "toggleLTI(document.display,'passback','add');";
+                           "toggleLTI(document.display,'passback','add');".
+                           "toggleLTI(document.display,'callback','add');";
                 if (ref($values) eq 'HASH') {
                     if (ref($values->{'lti'}) eq 'HASH') {
                         my $numlti = scalar(keys(%{$values->{'lti'}}));
@@ -231,7 +232,8 @@
                                        "toggleLTI(document.display,'sec','$i');".
                                        "toggleLTI(document.display,'lcauth','$i');".
                                        "toggleLTI(document.display,'lcmenu','$i');".
-                                       "toggleLTI(document.display,'passback','$i');";
+                                       "toggleLTI(document.display,'passback','$i');".
+                                       "toggleLTI(document.display,'callback','$i');";
                         }
                     }
                 }
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1410 loncom/lonnet/perl/lonnet.pm:1.1411
--- loncom/lonnet/perl/lonnet.pm:1.1410	Mon May  6 19:28:24 2019
+++ loncom/lonnet/perl/lonnet.pm	Thu Jul 18 18:28:58 2019
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1410 2019/05/06 19:28:24 raeburn Exp $
+# $Id: lonnet.pm,v 1.1411 2019/07/18 18:28:58 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1082,6 +1082,19 @@
     return;
 }
 
+sub delusersession {
+    my ($lonid,$udom,$uname) = @_;
+    my $uprimary_id = &domain($udom,'primary');
+    my $uintdom = &internet_dom($uprimary_id);
+    my $intdom = &internet_dom($lonid);
+    my $serverhomedom = &host_domain($lonid);
+    if (($uintdom ne '') && ($uintdom eq $intdom)) {
+        return &reply(join(':','delusersession',
+                            map {&escape($_)} ($udom,$uname)),$lonid);
+    }
+    return;
+}
+
 # check if user's browser sent load balancer cookie and server still has session
 # and is not overloaded.
 sub check_for_balancer_cookie {
Index: doc/loncapafiles/loncapafiles.lpml
diff -u doc/loncapafiles/loncapafiles.lpml:1.990 doc/loncapafiles/loncapafiles.lpml:1.991
--- doc/loncapafiles/loncapafiles.lpml:1.990	Sat Jul  6 19:20:31 2019
+++ doc/loncapafiles/loncapafiles.lpml	Thu Jul 18 18:29:04 2019
@@ -2,7 +2,7 @@
  "http://lpml.sourceforge.net/DTD/lpml.dtd">
 <!-- loncapafiles.lpml -->
 
-<!-- $Id: loncapafiles.lpml,v 1.990 2019/07/06 19:20:31 raeburn Exp $ -->
+<!-- $Id: loncapafiles.lpml,v 1.991 2019/07/18 18:29:04 raeburn Exp $ -->
 
 <!--
 
@@ -503,6 +503,12 @@
   <description>cookie jar</description>
 </directory>
 <directory dist='default'>
+  <protectionlevel>modest_delete</protectionlevel>
+  <targetdir dist='default'>home/httpd/ltiIDs</targetdir>
+  <categoryname>server standard</categoryname>
+  <description>stores LTI callback IDs for session logout</description>
+</directory>
+<directory dist='default'>
    <protectionlevel>modest_delete</protectionlevel>
  <targetdir dist='default'>home/httpd/balanceIDs</targetdir>
   <categoryname>server standard</categoryname>
@@ -2636,6 +2642,16 @@
 <status>works/unverified</status>
 </file>
 <file>
+<source>loncom/lti/ltilogout.pm</source>
+<target dist='default'>home/httpd/lib/perl/Apache/ltilogout.pm</target>
+<categoryname>handler</categoryname>
+<description>
+Handler to logout a LON-CAPA user session on callback from an LTI Consumer 
+which launched the session, when user logs out of session on Consumer.
+</description>
+<status>works/unverified</status>
+</file>
+<file>
 <source>loncom/lti/ltiutils.pm</source>
 <target dist='default'>home/httpd/lib/perl/LONCAPA/ltiutils.pm</target>
 <categoryname>system file</categoryname>

Index: loncom/lti/ltilogout.pm
+++ loncom/lti/ltilogout.pm
# The LearningOnline Network with CAPA
# LTI Provider Module to respond to a user session logout request.
#
# $Id: ltilogout.pm,v 1.1 2019/07/18 18:28:46 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#

package Apache::ltilogout;

use strict;
use Apache::Constants qw(:common :http);
use Apache::lonnet;
use Apache::loncommon;

sub handler {
    my $r = shift;
    my ($id) = ($r->uri =~ m{^/adm/service/logout/(\w+)$});
    if ($id) {
        my $dir = $r->dir_config('ltiIDsDir');
        my $lonhost = $r->dir_config('lonHostID');
        if (($dir ne '') && (-d $dir)) {
            if (-e "$dir/$id") {
                if (open(my $fh,'<',"$dir/$id")) {
                    my $contents = <$fh>;
                    chomp($contents);
                    close($fh);
                    my ($uname,$udom,$hostid) = split(/,/,$contents);
                    if (($uname ne '') && ($udom ne '')) {
                        my $uhome = &Apache::lonnet::homeserver($uname,$udom);
                        if ($uhome ne 'no_host') {
                            my $lonhost = $r->dir_config('lonHostID');
                            if ($hostid eq $lonhost) {
                                &delete_session($udom,$uname);
                            } else {
                                my ($is_balancer,$posshost,$setcookie) =
                                    &Apache::lonnet::check_loadbalancing($uname,$udom,'login');
                                if ($is_balancer) {
                                    if ($setcookie) {
                                        my $balancedir=$r->dir_config('lonBalanceDir');
                                        if (opendir(my $dirh,$balancedir)) {
                                            while (my $filename=readdir($dirh)) {
                                                if ($filename =~/^\Q$udom\E_\Q$uname\E_/) {
                                                    if (open(my $fh,'<',"$balancedir/$filename")) {
                                                        my $lonid = <$fh>;
                                                        close($fh);
                                                        if ($lonid eq $lonhost) {
                                                            &delete_session($r,$udom,$uname);
                                                        } elsif (&Apache::lonnet::hostname($lonid) ne '') {
                                                            &Apache::lonnet::delusersession($lonid,$udom,$uname);
                                                        }
                                                    }
                                                    last;
                                                }
                                            }
                                            closedir($dirh);
                                        }
                                    } else {
                                        my $lonid = &Apache::lonnet::find_existing_session($udom,$uname);
                                        if ($lonid eq $lonhost) {
                                            &delete_session($r,$udom,$uname);
                                        } elsif (&Apache::lonnet::hostname($lonid) ne '') {
                                            &Apache::lonnet::delusersession($lonid,$udom,$uname);
                                        }
                                    }
                                } else {
                                    &delete_session($r,$udom,$uname);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return OK;
}

sub delete_session {
    my ($r,$udom,$uname) = @_;
    my $lonidsdir = $r->dir_config('lonIDsDir');
    if (-d $lonidsdir) {
        if (opendir(my $dir,$lonidsdir)) {
            while (my $filename=readdir($dir)) {
                if ($filename=~/^\Q$uname\E_\d+_\Q$udom\E_/) {
                    unlink("$dir/$filename");
                    last;
                }
            }
        }
    }
}

1;


More information about the LON-CAPA-cvs mailing list