[LON-CAPA-cvs] cvs: loncom / lond /auth lonauth.pm migrateuser.pm switchserver.pm /interface domainprefs.pm loncommon.pm lonconfigsettings.pm loncreateuser.pm lonmodifycourse.pm lonrequestcourse.pm lonuserutils.pm /lonnet/perl lonnet.pm /lti ltiauth.pm

raeburn raeburn at source.lon-capa.org
Thu Mar 22 21:02:23 EDT 2018


raeburn		Fri Mar 23 01:02:23 2018 EDT

  Modified files:              
    /loncom/interface	domainprefs.pm loncommon.pm lonconfigsettings.pm 
                     	loncreateuser.pm lonmodifycourse.pm 
                     	lonrequestcourse.pm lonuserutils.pm 
    /loncom/auth	lonauth.pm migrateuser.pm switchserver.pm 
    /loncom/lti	ltiauth.pm 
    /loncom/lonnet/perl	lonnet.pm 
    /loncom	lond 
  Log:
  - Bug 6754 LON-CAPA as LTI Provider
    - Creation of new LON-CAPA user account available from an LTI Consumer.
    - Creation of new LON-CAPA course available from an LTI Consumer.
    - Self-enrollment in a LON-CAPA course available from an LTI Consumer.
  
  
-------------- next part --------------
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.324 loncom/interface/domainprefs.pm:1.325
--- loncom/interface/domainprefs.pm:1.324	Mon Jan  1 01:29:38 2018
+++ loncom/interface/domainprefs.pm	Fri Mar 23 01:01:20 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: domainprefs.pm,v 1.324 2018/01/01 01:29:38 raeburn Exp $
+# $Id: domainprefs.pm,v 1.325 2018/03/23 01:01:20 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -104,7 +104,7 @@
 
 In the case of course requests, radio buttons are displayed for each institutional
 affiliate type (and also default, and _LC_adv) for each of the course types 
-(official, unofficial, community, textbook, and placement).  
+(official, unofficial, community, textbook, placement, and lti).  
 In each case the radio buttons allow the selection of one of four values:  
 
 0, approval, validate, autolimit=N (where N is blank, or a positive integer).
@@ -1893,7 +1893,7 @@
     my $typecount = 0;
     my ($css_class,%titles);
     if ($context eq 'requestcourses') {
-        @usertools = ('official','unofficial','community','textbook','placement');
+        @usertools = ('official','unofficial','community','textbook','placement','lti');
         @options =('norequest','approval','validate','autolimit');
         %validations = &Apache::lonnet::auto_courserequest_checks($dom);
         %titles = &courserequest_titles();
@@ -2357,7 +2357,7 @@
     my ($settings,$rowtotal) = @_;
     my $rownum = 0; 
     my ($output,%current);
-    my @crstypes = ('official','unofficial','community','textbook','placement');
+    my @crstypes = ('official','unofficial','community','textbook','placement','lti');
     if (ref($settings) eq 'HASH') {
         if (ref($settings->{'uniquecode'}) eq 'HASH') {
             foreach my $type (@crstypes) {
@@ -2806,6 +2806,10 @@
 }
 
 sub lti_toggle_js {
+    my %lcauthparmtext = &Apache::lonlocal::texthash (
+                            localauth => 'Local auth argument',
+                            krb       => 'Kerberos domain',
+                         );
     return <<"ENDSCRIPT";
 <script type="text/javascript">
 // <![CDATA[
@@ -2883,6 +2887,28 @@
                 }
             }
         }
+    } else if (setting == 'lcauth') {
+        var numauth = form.elements['lti_lcauth_'+item].length;
+        if (numauth) {
+            for (var i=0; i<numauth; i++) {
+                if (form.elements['lti_lcauth_'+item][i].checked) {
+                    if (document.getElementById('lti_'+setting+'_parmrow_'+item)) {
+                        if ((form.elements['lti_'+setting+'_'+item][i].value == 'internal') || (form.elements['lti_'+setting+'_'+item][i].value == 'lti')) {
+                            document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'none';
+                        } else {
+                            document.getElementById('lti_'+setting+'_parmrow_'+item).style.display = 'table-row';
+                            if (document.getElementById('lti_'+setting+'_parmtext_'+item)) {
+                                if (form.elements['lti_'+setting+'_'+item][i].value == 'localauth') {
+                                    document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'localauth'}";
+                                } else {
+                                    document.getElementById('lti_'+setting+'_parmtext_'+item).innerHTML = "$lcauthparmtext{'krb'}";
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
     }
     return;
 }
@@ -4614,7 +4640,7 @@
                 '<input type="password" size="20" name="lti_secret_'.$i.'" value="'.$secret.'" />'.
                 '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.lti_secret_'.$i.'.type='."'text'".' } else { this.form.lti_secret_'.$i.'.type='."'password'".' }" />'.&mt('Visible input').'</label>'.
                 '<input type="hidden" name="lti_id_'.$i.'" value="'.$item.'" /></span>'.
-                '</fieldset>'.&lti_options($i,$current,%lt).'</td></tr>';
+                '</fieldset>'.&lti_options($i,$current,$itemcount,%lt).'</td></tr>';
             $itemcount ++;
         }
     }
@@ -4647,7 +4673,7 @@
                   (' 'x2).
                   '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="lti_secret_add" value="" />'.
                   '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.lti_secret_add.type='."'text'".' } else { this.form.lti_secret_add.type='."'password'".' }" />'.&mt('Visible input').'</label></span> '."\n".
-                  '</fieldset>'.&lti_options('add',undef,%lt).
+                  '</fieldset>'.&lti_options('add',undef,$itemcount,%lt).
                   '</td>'."\n".
                   '</tr>'."\n";
     $$rowtotal ++;
@@ -4672,7 +4698,7 @@
 }
 
 sub lti_options {
-    my ($num,$current,%lt) = @_;
+    my ($num,$current,$itemcount,%lt) = @_;
     my (%checked,%rolemaps,$crssecsrc,$userfield,$cidfield);
     $checked{'mapuser'}{'sourcedid'} = ' checked="checked"';
     $checked{'mapcrs'}{'course_offering_sourcedid'} = ' checked="checked"';
@@ -4682,11 +4708,18 @@
     $checked{'selfenroll'} = {};
     $checked{'crssec'} = {};
     $checked{'crssecsrc'} = {};
-
+    $checked{'lcauth'} = {};
+    if ($num eq 'add') {
+        $checked{'lcauth'}{'lti'} = ' checked="checked"';
+    }
     my $userfieldsty = 'none';
     my $crsfieldsty = 'none';
     my $crssecfieldsty = 'none';
     my $secsrcfieldsty = 'none';
+    my $lcauthparm;
+    my $lcauthparmstyle = 'display:none';
+    my $lcauthparmtext;
+    my $numinrow = 4;
 
     if (ref($current) eq 'HASH') {
         if (($current->{'mapuser'} ne '') && ($current->{'mapuser'} ne 'lis_person_sourcedid')) {
@@ -4722,6 +4755,18 @@
                 $checked{'makeuser'}{$role} = ' checked="checked"';
             }
         }
+        if ($current->{'lcauth'} =~ /^(internal|localauth|krb4|krb5|lti)$/) {
+            $checked{'lcauth'}{$1} = ' checked="checked"';
+            unless (($current->{'lcauth'} eq 'lti') || ($current->{'lcauth'} eq 'internal')) {
+                $lcauthparm = $current->{'lcauthparm'};
+                $lcauthparmstyle = 'display:table-row'; 
+                if ($current->{'lcauth'} eq 'localauth') {
+                    $lcauthparmtext = &mt('Local auth argument');
+                } else {
+                    $lcauthparmtext = &mt('Kerberos domain');
+                }
+            }
+        }
         if (ref($current->{'selfenroll'}) eq 'ARRAY') {
             foreach my $role (@{$current->{'selfenroll'}}) {
                 $checked{'selfenroll'}{$role} = ' checked="checked"';
@@ -4746,15 +4791,25 @@
     } else {
         $checked{'makecrs'}{'N'} = ' checked="checked"';
         $checked{'crssec'}{'N'} = ' checked="checked"';
+#FIXME        
     }
-    my @coursetypes = ('official','unofficial','community','textbook','placement');
+    my @coursetypes = ('official','unofficial','community','textbook','placement','lti');
     my %coursetypetitles = &Apache::lonlocal::texthash (
                                official   => 'Official',
                                unofficial => 'Unofficial',
                                community  => 'Community',
                                textbook   => 'Textbook',
                                placement  => 'Placement Test',
+                               lti        => 'LTI Provider',
     );
+    my @authtypes = ('internal','krb4','krb5','localauth');
+    my %shortauth = (
+                     internal => 'int',
+                     krb4 => 'krb4',
+                     krb5 => 'krb5',
+                     localauth  => 'loc'
+                    );
+    my %authnames = &authtype_names();
     my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator);
     my @lticourseroles = qw(Learner Instructor TeachingAssistant Mentor);
     my @courseroles = ('cc','in','ta','ep','st');
@@ -4762,6 +4817,7 @@
     my $onclickcrs = ' onclick="toggleLTI(this.form,'."'crs','$num'".');"';
     my $onclicksec = ' onclick="toggleLTI(this.form,'."'sec','$num'".');"';
     my $onclicksecsrc = ' onclick="toggleLTI(this.form,'."'secsrc','$num'".')"';
+    my $onclicklcauth = ' onclick="toggleLTI(this.form,'."'lcauth','$num'".')"';
     my $output = '<fieldset><legend>'.&mt('Mapping users').'</legend>'.
                  '<div class="LC_floatleft"><span class="LC_nobreak">'.&mt('LON-CAPA username').': ';
     foreach my $option ('sourcedid','email','other') {
@@ -4803,6 +4859,29 @@
                    $checked{'makeuser'}{$ltirole}.' />'.$ltirole.'</label> </span> ';     
     }
     $output .= '</fieldset>'.
+               '<fieldset><legend>'.&mt('New user accounts created for LTI users').'</legend>'.
+               '<table>'.
+               &modifiable_userdata_row('lti','instdata_'.$num,$current,$numinrow,$itemcount).
+               '</table>'.
+               '<table class="LC_nested"><tr><td class="LC_left_item">LON-CAPA Authentication</td>'.
+               '<td class="LC_left_item">';
+    foreach my $auth ('lti', at authtypes) {
+        my $authtext;
+        if ($auth eq 'lti') {
+            $authtext = &mt('None');
+        } else {
+            $authtext = $authnames{$shortauth{$auth}};
+        }
+        $output .= '<span class="LC_nobreak"><label><input type="radio" name="lti_lcauth_'.$num.
+                   '" value="'.$auth.'"'.$checked{'lcauth'}{$auth}.$onclicklcauth.' />'.
+                   $authtext.'</label></span>  ';
+    }
+    $output .= '</td></tr>'.
+               '<tr id="lti_lcauth_parmrow_'.$num.'" style="'.$lcauthparmstyle.'">'.
+               '<td class="LC_right_item" colspan="2"><span class="LC_nobreak">'.
+               '<span id="lti_lcauth_parmtext_'.$num.'">'.$lcauthparmtext.'</span>'.
+               '<input type="text" name="lti_lcauthparm_'.$num.'" value="" /></span></td></tr>'.
+               '</table></fieldset>'.
                '<fieldset><legend>'.&mt('Mapping courses').'</legend>'.
                '<div class="LC_floatleft"><span class="LC_nobreak">'.
                &mt('Unique course identifier').': ';
@@ -6445,8 +6524,9 @@
                                    community  => 'Communities',
                                    textbook   => 'Textbook',
                                    placement  => 'Placement tests',
+                                   lti        => 'LTI Provider',
                                    norequest  => 'Not allowed',
-                                   approval   => 'Approval by Dom. Coord.',
+                                   approval   => 'Approval by DC',
                                    validate   => 'With validation',
                                    autolimit  => 'Numerical limit',
                                    unlimited  => '(blank for unlimited)',
@@ -6558,7 +6638,7 @@
         }
     } else {
         my @contexts = ('author','course','domain');
-        my @authtypes = ('int','krb4','krb5','loc');
+        my @authtypes = ('int','krb4','krb5','loc','lti');
         my %checked;
         if (ref($settings) eq 'HASH') {
             if (ref($settings->{'authtypes'}) eq 'HASH') {
@@ -7298,6 +7378,7 @@
                       krb4   => 'Kerberos 4',
                       krb5   => 'Kerberos 5',
                       loc    => 'Local',
+                      lti    => 'LTI',
                   );
     return %lt;
 }
@@ -7366,12 +7447,13 @@
                           '<td><span class="LC_nobreak">'.$titles->{$item}.
                           '</span></td><td class="LC_right_item" colspan="3">';
             if ($item eq 'auth_def') {
-                my @authtypes = ('internal','krb4','krb5','localauth');
+                my @authtypes = ('internal','krb4','krb5','localauth','lti');
                 my %shortauth = (
                                  internal => 'int',
                                  krb4 => 'krb4',
                                  krb5 => 'krb5',
-                                 localauth  => 'loc'
+                                 localauth  => 'loc',
+                                 lti => 'lti',
                                 );
                 my %authnames = &authtype_names();
                 foreach my $auth (@authtypes) {
@@ -8447,6 +8529,8 @@
         } else {
             $rolename = $role;
         }
+    } elsif ($context eq 'lti') {
+        $rolename = &mt('Institutional data used (if available)');
     } else {
         if ($role eq 'cr') {
             $rolename = &mt('Custom role');
@@ -8489,30 +8573,32 @@
               '<td class="LC_left_item" colspan="2"><table>';
     my $rem;
     my %checks;
+    my %current;
     if (ref($settings) eq 'HASH') {
-        if (ref($settings->{$context}) eq 'HASH') {
+        my $hashref;
+        if ($context eq 'lti') {
+            if (ref($settings) eq 'HASH') {
+                $hashref = $settings->{'instdata'};
+            }
+        } elsif (ref($settings->{$context}) eq 'HASH') {
             if (ref($settings->{$context}->{$role}) eq 'HASH') {
-                my $hashref = $settings->{$context}->{$role};
-                if ($role eq 'emailusername') {
-                    if ($statustype) {
-                        if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') {
-                            $hashref = $settings->{$context}->{$role}->{$statustype};
-                            if (ref($hashref) eq 'HASH') { 
-                                foreach my $field (@fields) {
-                                    if ($hashref->{$field}) {
-                                        $checks{$field} = $hashref->{$field};
-                                    }
-                                }
-                            }
-                        }
+                $hashref = $settings->{'lti_instdata'};
+            }
+            if ($role eq 'emailusername') {
+                if ($statustype) {
+                    if (ref($settings->{$context}->{$role}->{$statustype}) eq 'HASH') {
+                        $hashref = $settings->{$context}->{$role}->{$statustype};
                     }
-                } else {
-                    if (ref($hashref) eq 'HASH') {
-                        foreach my $field (@fields) {
-                            if ($hashref->{$field}) {
-                                $checks{$field} = ' checked="checked" ';
-                            }
-                        }
+                }
+            }
+        }
+        if (ref($hashref) eq 'HASH') { 
+            foreach my $field (@fields) {
+                if ($hashref->{$field}) {
+                    if ($role eq 'emailusername') {
+                        $checks{$field} = $hashref->{$field};
+                    } else {
+                        $checks{$field} = ' checked="checked" ';
                     }
                 }
             }
@@ -8532,7 +8618,7 @@
         unless ($role eq 'emailusername') {
             if (exists($checks{$fields[$i]})) {
                 $check = $checks{$fields[$i]}
-            } else {
+            } elsif ($context ne 'lti') {
                 if ($role eq 'st') {
                     if (ref($settings) ne 'HASH') {
                         $check = ' checked="checked" '; 
@@ -8542,6 +8628,7 @@
         }
         $output .= '<td class="LC_left_item">'.
                    '<span class="LC_nobreak">';
+        my $prefix = 'canmodify';
         if ($role eq 'emailusername') {
             unless ($checks{$fields[$i]} =~ /^(required|optional)$/) {
                 $checks{$fields[$i]} = 'omit';
@@ -8552,13 +8639,16 @@
                     $checked='checked="checked" ';
                 }
                 $output .= '<label>'.
-                           '<input type="radio" name="canmodify_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'.
+                           '<input type="radio" name="'.$prefix.'_'.$item.'_'.$fields[$i].'" value="'.$option.'" '.$checked.'/>'.
                            &mt($option).'</label>'.(' ' x2);
             }
             $output .= '<i>'.$fieldtitles{$fields[$i]}.'</i>';
         } else {
+            if ($context eq 'lti') {
+                $prefix = 'lti';
+            }
             $output .= '<label>'.
-                       '<input type="checkbox" name="canmodify_'.$role.'" '.
+                       '<input type="checkbox" name="'.$prefix.'_'.$role.'" '.
                        'value="'.$fields[$i].'"'.$check.'/>'.$fieldtitles{$fields[$i]}.
                        '</label>';
         }
@@ -9968,7 +10058,7 @@
         $context = $action;
     }
     if ($context eq 'requestcourses') {
-        @usertools = ('official','unofficial','community','textbook','placement');
+        @usertools = ('official','unofficial','community','textbook','placement','lti');
         @options =('norequest','approval','validate','autolimit');
         %validations = &Apache::lonnet::auto_courserequest_checks($dom);
         %titles = &courserequest_titles();
@@ -10017,7 +10107,7 @@
         my @approvalnotify = &Apache::loncommon::get_env_multiple('form.'.$context.'notifyapproval');
         @approvalnotify = sort(@approvalnotify);
         $confhash{'notify'}{'approval'} = join(',', at approvalnotify);
-        my @crstypes = ('official','unofficial','community','textbook','placement');
+        my @crstypes = ('official','unofficial','community','textbook','placement','lti');
         my @hasuniquecode = &Apache::loncommon::get_env_multiple('form.uniquecode');
         foreach my $type (@hasuniquecode) {
             if (grep(/^\Q$type\E$/, at crstypes)) {
@@ -11361,10 +11451,13 @@
                                textbook   => 'Textbook',
                                placement  => 'Placement Test',
     );
+    my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
     my %lt = &lti_names();
     map { $posslti{$_} = 1; } @ltiroles;
     map { $posslticrs{$_} = 1; } @lticourseroles;
     map { $posscrstype{$_} = 1; } @coursetypes;
+
+#FIXME
     
     my (@items,%deletions,%itemids);
     if ($env{'form.lti_add'}) {
@@ -11453,6 +11546,30 @@
             }
         }
         $confhash{$itemid}{'makeuser'} = \@makeuser;
+        if (@makeuser) {
+            my $lcauth = $env{'form.lti_lcauth_'.$idx};
+            if ($lcauth =~ /^(internal|krb4|krb5|localauth)$/) {
+                $confhash{$itemid}{'lcauth'} = $lcauth;
+                if ($lcauth ne 'internal') {
+                    my $lcauthparm = $env{'form.lti_lcauthparm_'.$idx};
+                    $lcauthparm =~ s/^(\s+|\s+)$//g;
+                    $lcauthparm =~ s/`//g;
+                    if ($lcauthparm ne '') {
+                        $confhash{$itemid}{'lcauthparm'} = $lcauthparm;
+                    }
+                }
+            } else {
+                $confhash{$itemid}{'lcauth'} = 'lti';
+            }
+        }
+        my @possinstdata =  &Apache::loncommon::get_env_multiple('form.lti_instdata_'.$idx);
+        if (@possinstdata) {
+            foreach my $field (@possinstdata) {
+                if (exists($fieldtitles{$field})) {
+                    push(@{$confhash{$itemid}{'instdata'}});
+                }
+            }
+        }
         if (($env{'form.lti_mapcrs_'.$idx} eq 'course_offering_sourcedid') ||
             ($env{'form.lti_mapcrs_'.$idx} eq 'context_id'))  {
             $confhash{$itemid}{'mapcrs'} = $env{'form.lti_mapcrs_'.$idx};
@@ -11499,12 +11616,12 @@
             }
         }
         unless (($idx eq 'add') || ($changes{$itemid})) {
-            foreach my $field ('mapuser','mapcrs','section','passback','roster') {
+            foreach my $field ('mapuser','mapcrs','makecrs','section','passback','roster','lcauth','lcauthparm') {
                 if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) {
                     $changes{$itemid} = 1;
                 }
             }
-            foreach my $field ('makeuser','mapcrstype','selfenroll') {
+            foreach my $field ('makeuser','mapcrstype','selfenroll','instdata') {
                 unless ($changes{$itemid}) {
                     if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') {
                         if (ref($confhash{$itemid}{$field}) eq 'ARRAY') {
@@ -11650,11 +11767,35 @@
                     if (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') {
                         if (@{$confhash{$itemid}{'makeuser'}} > 0) { 
                             $resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]',
-                                                      join(', ',@{$confhash{$itemid}{'makeuser'}})).'</li>';
+                                                      join(', ',@{$confhash{$itemid}{'makeuser'}})).'<br />';
+                            if ($confhash{$itemid}{'lcauth'} eq 'lti') {
+                                $resulttext .= &mt('New users will only be able to authenticate via LTI').'</li>';
+                            } else {
+                                $resulttext .= &mt('New users will be assigned LON-CAPA authentication: [_1]',
+                                                   $confhash{$itemid}{'lcauth'});
+                                if ($confhash{$itemid}{'lcauth'} eq 'internal') {
+                                    $resulttext .= '; '.&mt('a randomly generated password will be created');
+                                } elsif ($confhash{$itemid}{'lcauth'} eq 'localauth') {
+                                    if ($confhash{$itemid}{'lcauthparm'} ne '') {
+                                        $resulttext .= ' '.&mt('with argument: [_1]',$confhash{$itemid}{'lcauthparm'});
+                                    }
+                                } else {
+                                    $resulttext .= '; '.&mt('Kerberos domain: [_1]',$confhash{$itemid}{'lcauthparm'});
+                                }
+                            }
+                            $resulttext .= '</li>';
                         } else {
                             $resulttext .= '<li>'.&mt('User account creation not permitted.').'</li>';
                         }
                     }
+                    if (ref($confhash{$itemid}{'instdata'}) eq 'ARRAY') {
+                        if (@{$confhash{$itemid}{'instdata'}} > 0) {
+                            $resulttext .= '<li>'.&mt('Institutional data will be used when creating a new user for: [_1]',
+                                                      join(', ',map { $fieldtitles{$_}; } @{$confhash{$itemid}{'instdata'}})).'</li>';
+                        } else {
+                            $resulttext .= '<li>'.&mt('No institutional data used when creating a new user.').'</li>';
+                        }
+                    }
                     if ($confhash{$itemid}{'mapcrs'}) {
                         $resulttext .= '<li>'.&mt('Unique course identifier').': '.$confhash{$itemid}{'mapcrs'}.'</li>';
                     }
@@ -12838,7 +12979,7 @@
     }
 
     my @authen_contexts = ('author','course','domain');
-    my @authtypes = ('int','krb4','krb5','loc');
+    my @authtypes = ('int','krb4','krb5','loc','lti');
     my %authhash;
     foreach my $item (@authen_contexts) {
         my @authallowed =  &Apache::loncommon::get_env_multiple('form.'.$item.'_auth');
@@ -14020,7 +14161,7 @@
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
     my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def',
                  'portal_def','intauth_cost','intauth_check','intauth_switch');
-    my @authtypes = ('internal','krb4','krb5','localauth');
+    my @authtypes = ('internal','krb4','krb5','localauth','lti');
     foreach my $item (@items) {
         $newvalues{$item} = $env{'form.'.$item};
         if ($item eq 'auth_def') {
@@ -14212,6 +14353,7 @@
                                           krb4       => 'krb4',
                                           krb5       => 'krb5',
                                           localauth  => 'loc',
+                                          lti        => 'lti',
                         );
                         $value = $authnames{$shortauth{$value}};
                     } elsif ($item eq 'intauth_switch') {
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1309 loncom/interface/loncommon.pm:1.1310
--- loncom/interface/loncommon.pm:1.1309	Fri Jan 12 13:33:38 2018
+++ loncom/interface/loncommon.pm	Fri Mar 23 01:01:21 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1309 2018/01/12 13:33:38 raeburn Exp $
+# $Id: loncommon.pm,v 1.1310 2018/03/23 01:01:21 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -3027,6 +3027,8 @@
 
 =item * authform_filesystem
 
+=item * authform_lti
+
 =back
 
 See loncreateuser.pm for invocation and use examples.
@@ -3443,14 +3445,69 @@
                     $fsyscheck.' onchange="'.$jscall.'" onclick="'.
                     $jscall.'"'.$disabled.' />';
     }
-    $autharg = '<input type="text" size="10" name="fsysarg" value=""'.
+    $autharg = '<input type="password" size="10" name="fsysarg" value=""'.
                ' onchange="'.$jscall.'"'.$disabled.' />';
     $result = &mt
         ('[_1] Filesystem Authenticated (with initial password [_2])',
-         '<label><input type="radio" name="login" value="fsys" '.
-         $fsyscheck.'onchange="'.$jscall.'" onclick="'.$jscall.'"'.$disabled.' />',
-         '</label><input type="password" size="10" name="fsysarg" value="" '.
-                  'onchange="'.$jscall.'"'.$disabled.' />');
+         '<label>'.$authtype,'</label>'.$autharg);
+    return $result;
+}
+
+sub authform_lti {
+    my %in = (
+              formname => 'document.cu',
+              kerb_def_dom => 'MSU.EDU',
+              @_,
+              );
+    my ($lticheck,$result,$authtype,$autharg,$jscall,$disabled);
+    my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
+    if ($in{'readonly'}) {
+        $disabled = ' disabled="disabled"';
+    }
+    if (defined($in{'curr_authtype'})) {
+        if ($in{'curr_authtype'} eq 'lti') {
+            if ($can_assign{'lti'}) {
+                $lticheck = 'checked="checked" ';
+                if (defined($in{'mode'})) {
+                    if ($in{'mode'} eq 'modifyuser') {
+                        $lticheck = '';
+                    }
+                }
+            } else {
+                $result = &mt('Currently LTI Authenticated.');
+                return $result;
+            }
+        }
+    } else {
+        if ($authnum == 1) {
+            $authtype = '<input type="hidden" name="login" value="lti" />';
+        }
+    }
+    if (!$can_assign{'lti'}) {
+        return;
+    } elsif ($authtype eq '') {
+        if (defined($in{'mode'})) {
+            if ($in{'mode'} eq 'modifycourse') {
+                if ($authnum == 1) {
+                    $authtype = '<input type="radio" name="login" value="lti"'.$disabled.' />';
+                }
+            }
+        }
+    }
+    $jscall = "javascript:changed_radio('lti',$in{'formname'});";
+    if (($authtype eq '') && (($in{'mode'} eq 'modifycourse') || ($in{'curr_authtype'} ne 'lti'))) {
+        $authtype = '<input type="radio" name="login" value="lti" '.
+                    $lticheck.' onchange="'.$jscall.'" onclick="'.
+                    $jscall.'"'.$disabled.' />';
+    }
+    $autharg = '<input type="hidden" name="ltiarg" value="" />';
+    if ($authtype) {
+        $result = &mt('[_1] LTI Authenticated',
+                      '<label>'.$authtype.'</label>'.$autharg);
+    } else {
+        $result = '<b>'.&mt('LTI Authenticated').'</b>'.
+                  $autharg;
+    }
     return $result;
 }
 
@@ -3464,6 +3521,7 @@
                           krb5 => 1,
                           int  => 1,
                           loc  => 1,
+                          lti  => 1,
                      );
     my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
     if (ref($domconfig{'usercreation'}) eq 'HASH') {
@@ -16187,13 +16245,14 @@
 }
 
 sub course_types {
-    my @types = ('official','unofficial','community','textbook','placement');
+    my @types = ('official','unofficial','community','textbook','placement','lti');
     my %typename = (
                          official   => 'Official course',
                          unofficial => 'Unofficial course',
                          community  => 'Community',
                          textbook   => 'Textbook course',
                          placement  => 'Placement test',
+                         lti        => 'LTI provider',
                    );
     return (\@types,\%typename);
 }
Index: loncom/interface/lonconfigsettings.pm
diff -u loncom/interface/lonconfigsettings.pm:1.41 loncom/interface/lonconfigsettings.pm:1.42
--- loncom/interface/lonconfigsettings.pm:1.41	Mon Jan  1 01:29:38 2018
+++ loncom/interface/lonconfigsettings.pm	Fri Mar 23 01:01:21 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: lonconfigsettings.pm,v 1.41 2018/01/01 01:29:38 raeburn Exp $
+# $Id: lonconfigsettings.pm,v 1.42 2018/03/23 01:01:21 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -218,14 +218,16 @@
             if (grep(/^lti$/, at actions)) {
                 $onload .= "toggleLTI(document.display,'user','add');".
                            "toggleLTI(document.display,'crs','add');".
-                           "toggleLTI(document.display,'sec','add');";
+                           "toggleLTI(document.display,'sec','add');".
+                           "toggleLTI(document.display,'lcauth','add');";
                 if (ref($values) eq 'HASH') {
                     if (ref($values->{'lti'}) eq 'HASH') {
                         my $numlti = scalar(keys(%{$values->{'lti'}}));
                         for (my $i=0; $i<$numlti; $i++) {
                             $onload .= "toggleLTI(document.display,'user','$i');".
                                        "toggleLTI(document.display,'crs','$i');".
-                                       "toggleLTI(document.display,'sec','$i');";
+                                       "toggleLTI(document.display,'sec','$i');".
+                                       "toggleLTI(document.display,'lcauth','$i');";
                         }
                     }
                 }
Index: loncom/interface/loncreateuser.pm
diff -u loncom/interface/loncreateuser.pm:1.448 loncom/interface/loncreateuser.pm:1.449
--- loncom/interface/loncreateuser.pm:1.448	Sat Nov  4 20:59:38 2017
+++ loncom/interface/loncreateuser.pm	Fri Mar 23 01:01:21 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Create a user
 #
-# $Id: loncreateuser.pm,v 1.448 2017/11/04 20:59:38 raeburn Exp $
+# $Id: loncreateuser.pm,v 1.449 2018/03/23 01:01:21 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -78,6 +78,7 @@
 my $authformint;
 my $authformfsys;
 my $authformloc;
+my $authformlti;
 
 sub initialize_authen_forms {
     my ($dom,$formname,$curr_authtype,$mode) = @_;
@@ -88,7 +89,7 @@
                   domain => $dom,
                 );
     my %abv_auth = &auth_abbrev();
-    if ($curr_authtype =~ /^(krb4|krb5|internal|localauth|unix):(.*)$/) {
+    if ($curr_authtype =~ /^(krb4|krb5|internal|localauth|unix|lti):(.*)$/) {
         my $long_auth = $1;
         my $curr_autharg = $2;
         my %abv_auth = &auth_abbrev();
@@ -107,6 +108,7 @@
     $authformint  = &Apache::loncommon::authform_internal(%param);
     $authformfsys = &Apache::loncommon::authform_filesystem(%param);
     $authformloc  = &Apache::loncommon::authform_local(%param);
+    $authformlti  = &Apache::loncommon::authform_lti(%param);
 }
 
 sub auth_abbrev {
@@ -116,6 +118,7 @@
                      internal  => 'int',
                      localauth => 'loc',
                      unix      => 'fsys',
+                     lti       => 'lti',
                    );
     return %abv_auth;
 }
@@ -253,14 +256,15 @@
                    'community'  => 'Can request creation of communities',
                    'textbook'   => 'Can request creation of textbook courses',
                    'placement'  => 'Can request creation of placement tests',
+                   'lti'        => 'Can request creation of LTI courses',
                    'requestauthor'  => 'Can request author space',
     );
     if ($context eq 'requestcourses') {
         %userenv = &Apache::lonnet::userenvironment($ccdomain,$ccuname,
                       'requestcourses.official','requestcourses.unofficial',
                       'requestcourses.community','requestcourses.textbook',
-                      'requestcourses.placement');
-        @usertools = ('official','unofficial','community','textbook','placement');
+                      'requestcourses.placement','requestcourses.lti');
+        @usertools = ('official','unofficial','community','textbook','placement','lti');
         @options =('norequest','approval','autolimit','validate');
         %validations = &Apache::lonnet::auto_courserequest_checks($ccdomain);
         %reqtitles = &courserequest_titles();
@@ -543,6 +547,7 @@
                                    community  => 'Communities',
                                    textbook   => 'Textbook',
                                    placement  => 'Placement Tests',
+                                   lti        => 'LTI Provider',
                                    norequest  => 'Not allowed',
                                    approval   => 'Approval by Dom. Coord.',
                                    validate   => 'With validation',
@@ -2200,7 +2205,7 @@
                    'ld'    => "Login Data"
     );
     # Check for a bad authentication type
-    if ($currentauth !~ /^(krb4|krb5|unix|internal|localauth):/) {
+    if ($currentauth !~ /^(krb4|krb5|unix|internal|localauth|lti):/) {
         # bad authentication scheme
         if (&Apache::lonnet::allowed('mau',$ccdomain)) {
             &initialize_authen_forms($ccdomain,$formname);
@@ -2279,6 +2284,8 @@
                     $result = &mt('Currently using local (institutional) authentication.');
                 } elsif ($currentauth =~ /^unix:/) {
                     $result = &mt('Currently Filesystem Authenticated.');
+                } elsif ($currentauth =~ /^lti:/) {
+                    $result = &mt('Currently LTi authenticated.');
                 }
                 $outcome = '<h3>'.$lt{'ld'}.'</h3>'.
                            &Apache::loncommon::start_data_table().
@@ -2317,6 +2324,9 @@
         if ($can_assign{'loc'}) {
             push(@authform_others,$authformloc);
         }
+        if ($can_assign{'lti'}) {
+            push(@authform_others,$authformlti);
+        }
         if (($can_assign{'krb4'}) || ($can_assign{'krb5'})) {
             $show_override_msg = 1;
         }
@@ -2328,6 +2338,9 @@
         if ($can_assign{'loc'}) {
             push(@authform_others,$authformloc);
         }
+        if ($can_assign{'lti'}) {
+            push(@authform_others,$authformlti);
+        }
         if ($can_assign{'int'}) {
             $show_override_msg = 1;
         }
@@ -2342,6 +2355,9 @@
         if ($can_assign{'loc'}) {
             push(@authform_others,$authformloc);
         }
+        if ($can_assign{'lti'}) {
+            push(@authform_others,$authformlti);
+        }
         if ($can_assign{'fsys'}) {
             $show_override_msg = 1;
         }
@@ -2353,9 +2369,23 @@
         if ($can_assign{'int'}) {
             push(@authform_others,$authformint);
         }
+        if ($can_assign{'lti'}) {
+            push(@authform_others,$authformlti);
+        }
         if ($can_assign{'loc'}) {
             $show_override_msg = 1;
         }
+    } elsif ($currentauth=~/^lti:/) {
+        $authformcurrent=$authformlti;
+        if (($can_assign{'krb4'}) || ($can_assign{'krb5'})) {
+            push(@authform_others,$authformkrb);
+        }
+        if ($can_assign{'int'}) {
+            push(@authform_others,$authformint);
+        }
+        if ($can_assign{'loc'}) {
+            push(@authform_others,$authformloc);
+        }
     }
     if ($show_override_msg) {
         $authformcurrent = '<table><tr><td colspan="3">'.$authformcurrent.
@@ -2814,6 +2844,9 @@
 	$amode='localauth';
 	$genpwd=$env{'form.locarg'};
 	$genpwd=" " if (!$genpwd);
+    } elsif ($env{'form.login'} eq 'lti') {
+        $amode='lti';
+        $genpwd=" ";
     } elsif (($env{'form.login'} eq 'nochange') ||
              ($env{'form.login'} eq ''        )) { 
         # There is no need to tell the user we did not change what they
@@ -2833,7 +2866,7 @@
     my (%alerts,%rulematch,%inst_results,%curr_rules);
     my @userinfo = ('firstname','middlename','lastname','generation','permanentemail','id');
     my @usertools = ('aboutme','blog','webdav','portfolio');
-    my @requestcourses = ('official','unofficial','community','textbook','placement');
+    my @requestcourses = ('official','unofficial','community','textbook','placement','lti');
     my @requestauthor = ('requestauthor');
     my ($othertitle,$usertypes,$types) = 
         &Apache::loncommon::sorted_inst_types($env{'form.ccdomain'});
@@ -3299,7 +3332,7 @@
                         foreach my $key (keys(%changed)) {
                             if (($key eq 'official') || ($key eq 'unofficial') ||
                                 ($key eq 'community') || ($key eq 'textbook') ||
-                                ($key eq 'placement')) {
+                                ($key eq 'placement') || ($key eq 'lti')) {
                                 $newenvhash{'environment.requestcourses.'.$key} =
                                     $changeHash{'requestcourses.'.$key};
                                 if ($changeHash{'requestcourses.'.$key}) {
@@ -3509,6 +3542,7 @@
          'community'      => 'Can Request Communities',
          'textbook'       => 'Can Request Textbook Courses',
          'placement'      => 'Can Request Placement Tests',
+         'lti'            => 'Can Request LTI Courses',
          'requestauthor'  => 'Can Request Author Role',
          'inststatus'     => "Affiliation",
          'prvs'           => 'Previous Value:',
Index: loncom/interface/lonmodifycourse.pm
diff -u loncom/interface/lonmodifycourse.pm:1.92 loncom/interface/lonmodifycourse.pm:1.93
--- loncom/interface/lonmodifycourse.pm:1.92	Sat Apr  8 14:58:11 2017
+++ loncom/interface/lonmodifycourse.pm	Fri Mar 23 01:01:21 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # handler for DC-only modifiable course settings
 #
-# $Id: lonmodifycourse.pm,v 1.92 2017/04/08 14:58:11 raeburn Exp $
+# $Id: lonmodifycourse.pm,v 1.93 2018/03/23 01:01:21 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1277,6 +1277,8 @@
             $curr_authtype = 'int';
         } elsif ($enrollvar->{'authtype'} eq 'localauth' ) {
             $curr_authtype = 'loc';
+        } elsif ($enrollvar->{'authtype'} eq 'lti' ) {
+            $curr_authtype = 'lti';
         }
     }
     unless ($curr_authtype eq '') {
@@ -1297,7 +1299,8 @@
     $authform{'krb'} = &Apache::loncommon::authform_kerberos(%param);
     $authform{'int'} = &Apache::loncommon::authform_internal(%param);
     $authform{'loc'} = &Apache::loncommon::authform_local(%param);
-    foreach my $item ('krb','int','loc') {
+    $authform{'lti'} = &Apache::loncommon::authform_lti(%param);
+    foreach my $item ('krb','int','loc','lti') {
         if ($authform{$item} ne '') {
             $authenitems .= $authform{$item}.'<br />';
         }
@@ -1363,6 +1366,8 @@
             if ((defined($env{'form.locarg'})) && ($env{'form.locarg'})) {
                 $newattr{'autharg'} = $env{'form.locarg'};
             }
+        } elsif ($env{'form.login'} eq 'lti') {
+            $newattr{'authtype'} = 'lti';
         }
         if ( $newattr{'authtype'}=~ /^krb/) {
             if ($newattr{'autharg'}  eq '') {
Index: loncom/interface/lonrequestcourse.pm
diff -u loncom/interface/lonrequestcourse.pm:1.102 loncom/interface/lonrequestcourse.pm:1.103
--- loncom/interface/lonrequestcourse.pm:1.102	Fri Aug 11 15:26:38 2017
+++ loncom/interface/lonrequestcourse.pm	Fri Mar 23 01:01:21 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Request a course
 #
-# $Id: lonrequestcourse.pm,v 1.102 2017/08/11 15:26:38 raeburn Exp $
+# $Id: lonrequestcourse.pm,v 1.103 2018/03/23 01:01:21 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -155,6 +155,23 @@
     }
 
     if ($canreq) {
+        if (($env{'form.crstype'} eq 'lti') && ($env{'request.lti.login'}) &&
+            ($env{'form.lti.reqrole'} eq 'cc') && ($env{'form.lti.reqcrs'}) &&
+            ($env{'form.lti.sourcecrs'} ne '')) {
+            if ($action eq 'process') {
+                if ($can_request{'lti'}) {
+                    my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$dom);
+                    &process_textbook_request($r,$dom,$action,\%domdefs,\%domconfig,\%can_request,'lti');
+                } else {
+                    $r->print(&header('Course Request','','','',{ 'only_body' => 1}).
+                              '<div>'.
+                              '<p class="LC_info">'.&mt('You do not have privileges to request creation of LTI courses.').'</p>'.
+                              '</div>'.
+                              &Apache::loncommon::end_page());
+                }
+            }
+            return OK;
+        }
         if (($env{'form.crstype'} eq 'textbook') || 
             (scalar(keys(%can_request)) == 1) && ($can_request{'textbook'})) {
             my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$dom);
@@ -192,7 +209,8 @@
                 }
             } else {
                 if ($can_request{'textbook'}) {
-                    &print_textbook_form($r,$dom,\@incdoms,\%domdefs,$domconfig{'requestcourses'},\%can_request);
+                    &print_textbook_form($r,$dom,\@incdoms,\%domdefs,$domconfig{'requestcourses'},
+                                         \%can_request,'textbook');
                 } else {
                     &textbook_request_disabled($r,$dom,$action,\%can_request);
                 }
@@ -4541,9 +4559,11 @@
 }
 
 sub print_textbook_form {
-    my ($r,$dom,$incdoms,$domdefs,$settings,$can_request) = @_;
+    my ($r,$dom,$incdoms,$domdefs,$settings,$can_request,$crstype,$formhash) = @_;
     my (%prefab,%ordered,%numprefab);
-    my $crstype = 'textbook';
+    if ($crstype eq '') {
+        $crstype = 'textbook';
+    }
 #
 #  Retrieve list of prefabricated courses (textbook courses and templates) cloneable by user
 #
@@ -4660,31 +4680,37 @@
 
     my $jscript = &textbook_request_javascript(\%numprefab,$numcurrent,$numdomcourses,$customvalidationjs);
     $jscript .= $customjs;
-    my %loaditems;
+    my (%loaditems,$args);
     $loaditems{'onload'} = 'javascript:uncheckAllRadio();'.$customonload;
-    $r->print(&header('Course Request',$jscript,\%loaditems));
+    if ($crstype eq 'lti') {
+       $args = { 'only_body' => 1};
+    }
+    $r->print(&header('Course Request',$jscript,\%loaditems,undef,$args));
 
     if (ref($can_request) eq 'HASH') {
-        unless ((scalar(keys(%{$can_request})) == 1) && ($can_request->{'textbook'})) {
+        unless (((scalar(keys(%{$can_request})) == 1) && ($can_request->{'textbook'})) ||
+                ($crstype eq 'lti')) {
             &Apache::lonhtmlcommon::add_breadcrumb(
                 { href => '/adm/requestcourse',
                   text => 'Pick action',
                 });
         }
     }
-    &Apache::lonhtmlcommon::add_breadcrumb({text=>'Course Request'});
-    $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests'));
+    unless ($crstype eq 'lti') {
+        &Apache::lonhtmlcommon::add_breadcrumb({text=>'Course Request'});
+        $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests'));
 
-    &startContentScreen($r,'textbookrequests');
+        &startContentScreen($r,'textbookrequests');
 #
 # Show domain selector form, if required.
 #
-    if (@{$incdoms} > 1) {
-        my $onchange = 'this.form.submit()';
-        $r->print('<form name="domforcourse" method="post" action="/adm/requestcourse">'.
-                  '<div><fieldset><legend>'.&mt('Domain').'</legend>'.
-                  &Apache::loncommon::select_dom_form($dom,'showdom','',1,$onchange,$incdoms).
-                  '</fieldset></form>');
+        if (@{$incdoms} > 1) {
+            my $onchange = 'this.form.submit()';
+            $r->print('<form name="domforcourse" method="post" action="/adm/requestcourse">'.
+                      '<div><fieldset><legend>'.&mt('Domain').'</legend>'.
+                      &Apache::loncommon::select_dom_form($dom,'showdom','',1,$onchange,$incdoms).
+                      '</fieldset></form>');
+        }
     }
 
 #
@@ -4864,15 +4890,24 @@
 #
 # Submit button
 #
-    $r->print('<input type="hidden" name="crstype" value="textbook" />'.
+    $r->print('<input type="hidden" name="crstype" value="'.$crstype.'" />'.
               '<input type="hidden" name="action" value="process" />'.
               '<input type="submit" value="'.&mt('Create course').'" />');
 
 #
 # End request form
 #
+
+    if (($crstype eq 'lti') && (ref($formhash) eq 'HASH')) {
+        foreach my $item (keys(%{$formhash})) {
+            $r->print('<input type="hidden" name="'.$item.'" value="'.$formhash->{$item}.'" />'."\n");
+        }
+    }
+
     $r->print('</form>');
-    &endContentScreen($r).
+    unless ($crstype eq 'lti') {
+        &endContentScreen($r);
+    }
     $r->print(&Apache::loncommon::end_page());
     return;
 }
@@ -4959,9 +4994,11 @@
 }
 
 sub process_textbook_request {
-    my ($r,$dom,$action,$domdefs,$domconfig,$can_request) = @_;
+    my ($r,$dom,$action,$domdefs,$domconfig,$can_request,$crstype) = @_;
     my ($uniquecode,$req_notifylist);
-    my $crstype = 'textbook';
+    if ($crstype eq '') {
+        $crstype = 'textbook';
+    }
     if (ref($domconfig) eq 'HASH') {
         if (ref($domconfig->{'requestcourses'}) eq 'HASH') {
             if (ref($domconfig->{'requestcourses'}{'notify'}) eq 'HASH') {
@@ -5003,27 +5040,33 @@
         }
     }
     my $js = &processing_javascript();
-    my $loaditems = { 
-                      onload => 'javascript:hideProcessing();',
-                    };
-    $r->print(&header('Course Creation',$js,$loaditems));
-
-    if (ref($can_request) eq 'HASH') {
-        unless ((scalar(keys(%{$can_request})) == 1) && ($can_request->{'textbook'})) {
-            &Apache::lonhtmlcommon::add_breadcrumb(
-                { href => '/adm/requestcourse',
-                  text => 'Pick action',
-                });
+    my ($loaditems,$args);
+    $loaditems = {
+                   onload => 'javascript:hideProcessing();',
+                 };
+    if ($crstype eq 'lti') {
+       $args = { 'only_body' => 1};
+    }
+    $r->print(&header('Course Creation',$js,$loaditems,undef,$args));
+
+    unless ($crstype eq 'lti') {
+        if (ref($can_request) eq 'HASH') {
+            unless ((scalar(keys(%{$can_request})) == 1) && ($can_request->{'textbook'})) {
+                &Apache::lonhtmlcommon::add_breadcrumb(
+                    { href => '/adm/requestcourse',
+                      text => 'Pick action',
+                    });
+            }
         }
+        &Apache::lonhtmlcommon::add_breadcrumb(
+                                               { href => '/adm/requestcourse',
+                                                 text => "Create Course",
+                                               }
+                                              );
+        &Apache::lonhtmlcommon::add_breadcrumb({text=>'Request Processed'});
+        $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests'));
+        &startContentScreen($r,'textbookrequests');
     }
-    &Apache::lonhtmlcommon::add_breadcrumb(
-                                           { href => '/adm/requestcourse',
-                                             text => "Create Course",
-                                           }
-                                          );
-    &Apache::lonhtmlcommon::add_breadcrumb({text=>'Request Processed'});
-    $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests'));
-    &startContentScreen($r,'textbookrequests');
 
     my $details = {
                     owner          => $env{'user.name'},
@@ -5068,7 +5111,12 @@
     my ($result,$output,$customized) = &process_request($r,$lonhost,$dom,$cnum,$crstype,$now,$details,
                                                         '',$req_notifylist,[],$domconfig);
     $r->print($output);
-    if (&Apache::loncoursequeueadmin::author_prompt()) {
+    if ($crstype eq 'lti') {
+        my %consumers = &Apache::lonnet::get_dom('lticonsumers',[$env{'form.sourcecrs'}],$dom);
+        if (($env{'form.lti.sourcecrs'} ne '')  && ($consumers{$env{'form.lti.sourcecrs'}} eq '') && ($cnum ne '')) {
+            &Apache::lonnet::put_dom('lticonsumers',{ $env{'form.lti.sourcecrs'} => $cnum },$dom);
+        }
+    } elsif (&Apache::loncoursequeueadmin::author_prompt()) {
         unless ($customized) {
             &print_author_prompt($r,$action,$cnum,$dom,$crstype,$result);
         }
@@ -5077,7 +5125,9 @@
             $r->print('<p><a href="/adm/requestcourse">'.&mt('Create another course').'</a></p>');
         }
     }
-    &endContentScreen($r);
+    unless ($crstype eq 'lti') {
+        &endContentScreen($r);
+    }
     $r->print(&Apache::loncommon::end_page());
 }
 
Index: loncom/interface/lonuserutils.pm
diff -u loncom/interface/lonuserutils.pm:1.193 loncom/interface/lonuserutils.pm:1.194
--- loncom/interface/lonuserutils.pm:1.193	Sat Nov  4 20:59:39 2017
+++ loncom/interface/lonuserutils.pm	Fri Mar 23 01:01:21 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Utility functions for managing LON-CAPA user accounts
 #
-# $Id: lonuserutils.pm,v 1.193 2017/11/04 20:59:39 raeburn Exp $
+# $Id: lonuserutils.pm,v 1.194 2018/03/23 01:01:21 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -546,6 +546,7 @@
             case 'fsys':
                 alertmsg = '';
                 break;
+            case 'lti':
             default:
                 alertmsg = '';
         }
@@ -898,6 +899,7 @@
     my $krbform = &Apache::loncommon::authform_kerberos(%param);
     my $intform = &Apache::loncommon::authform_internal(%param);
     my $locform = &Apache::loncommon::authform_local(%param);
+    my $ltiform = &Apache::loncommon::authform_lti(%param);
     my $date_table = &date_setting_table(undef,undef,$context,undef,
                                          $formname,$permission,$crstype);
 
@@ -926,7 +928,7 @@
             &Apache::loncommon::help_open_topic('Auth_Options').
             "</p>\n";
     }
-    $Str .= &set_login($defdom,$krbform,$intform,$locform);
+    $Str .= &set_login($defdom,$krbform,$intform,$locform,$ltiform);
 
     my ($home_server_pick,$numlib) =
         &Apache::loncommon::home_server_form_item($defdom,'lcserver',
@@ -4251,6 +4253,8 @@
         if ((defined($env{'form.locarg'})) && ($env{'form.locarg'})) {
             $genpwd=$env{'form.locarg'};
         }
+    } elsif ($env{'form.login'} eq 'lti') {
+        $amode='lti';
     }
     if ($amode =~ /^krb/) {
         if (! defined($genpwd) || $genpwd eq '') {
@@ -4625,7 +4629,7 @@
                                 &mt('The user does not already exist, and you may not create a new user in a different domain.');
                             next;
                         } else {
-                            unless ($password || $env{'form.login'} eq 'loc') {
+                            unless (($password ne '') || ($env{'form.login'} eq 'loc') || ($env{'form.login'} eq 'lti')) {
                                 $disallow{$counter} =
                                     &mt('[_1]: This is a new user but no default password was provided, and the authentication type requires one.',
                                         '<b>'.$username.'</b>');
@@ -5491,7 +5495,7 @@
 }
 
 sub set_login {
-    my ($dom,$authformkrb,$authformint,$authformloc) = @_;
+    my ($dom,$authformkrb,$authformint,$authformloc,$authformlti) = @_;
     my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom);
     my $response;
     my ($authnum,%can_assign) =
@@ -5513,6 +5517,11 @@
                          '<td>'.$authformloc.'</td>'.
                          &Apache::loncommon::end_data_table_row()."\n";
         }
+        if ($can_assign{'lti'}) {
+            $response .= &Apache::loncommon::start_data_table_row().
+                         '<td>'.$authformlti.'</td>'.
+                         &Apache::loncommon::end_data_table_row()."\n";
+        }
         $response .= &Apache::loncommon::end_data_table();
     }
     return $response;
Index: loncom/auth/lonauth.pm
diff -u loncom/auth/lonauth.pm:1.148 loncom/auth/lonauth.pm:1.149
--- loncom/auth/lonauth.pm:1.148	Tue Aug  8 18:26:34 2017
+++ loncom/auth/lonauth.pm	Fri Mar 23 01:01:29 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # User Authentication Module
 #
-# $Id: lonauth.pm,v 1.148 2017/08/08 18:26:34 raeburn Exp $
+# $Id: lonauth.pm,v 1.149 2018/03/23 01:01:29 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -36,6 +36,7 @@
 use Apache::lonnet;
 use Apache::lonmenu();
 use Apache::createaccount;
+use Apache::ltiauth;
 use Fcntl qw(:flock);
 use Apache::lonlocal;
 use Apache::File();
@@ -45,7 +46,7 @@
 # ------------------------------------------------------------ Successful login
 sub success {
     my ($r, $username, $domain, $authhost, $lowerurl, $extra_env,
-	$form) = @_;
+	$form,$skipcritical) = @_;
 
 # ------------------------------------------------------------ Get cookie ready
     my $cookie =
@@ -64,10 +65,12 @@
 
 # ------------------------------------------------- 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';
+            }
         }
     }
 
@@ -93,7 +96,29 @@
     }
 # -------------------------------------------------------- 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;
+            &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;
@@ -161,11 +186,7 @@
             }
         }
     }
-    my $start_page=&Apache::loncommon::start_page('Successful Login',
-                                                  $header,$args);
-    my $end_page  =&Apache::loncommon::end_page();
 
-	my $continuelink='<a href="'.$destination.'">'.&mt('Continue').'</a>';
 # ------------------------------------------------- Output for successful login
 
     &Apache::loncommon::content_type($r,'text/html');
@@ -177,6 +198,12 @@
     }
     $r->send_http_header;
 
+    my $start_page=&Apache::loncommon::start_page('Successful Login',
+                                                  $header,$args);
+    my $end_page  =&Apache::loncommon::end_page();
+
+    my $continuelink='<a href="'.$destination.'">'.&mt('Continue').'</a>';
+
     my %lt=&Apache::lonlocal::texthash(
 				       'wel' => 'Welcome',
 				       'pro' => 'Login problems?',
@@ -407,7 +434,7 @@
     my $authhost=Apache::lonnet::authenticate($form{'uname'},$upass,
                                               $form{'udom'},$defaultauth,
                                               $clientcancheckhost);
-    
+
 # --------------------------------------------------------------------- Failed?
 
     if ($authhost eq 'no_host') {
Index: loncom/auth/migrateuser.pm
diff -u loncom/auth/migrateuser.pm:1.26 loncom/auth/migrateuser.pm:1.27
--- loncom/auth/migrateuser.pm:1.26	Thu Nov 30 15:14:51 2017
+++ loncom/auth/migrateuser.pm	Fri Mar 23 01:01:29 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Starts a user off based of an existing token.
 #
-# $Id: migrateuser.pm,v 1.26 2017/11/30 15:14:51 raeburn Exp $
+# $Id: migrateuser.pm,v 1.27 2018/03/23 01:01:29 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -35,25 +35,29 @@
 use Apache::lonnet;
 use Apache::lonlocal;
 use Apache::lonlogin();
+use Apache::ltiauth;
 
 sub goto_login {
-    my ($r,$domain) = @_;
-    &Apache::loncommon::content_type($r,'text/html');
-    $r->send_http_header;
-    my $url = '/adm/login';
-    if ($domain) {
-        $url .= '?domain='.$domain;
-    }
-    $r->print(&Apache::loncommon::start_page('Going to login',undef,
-					     {'redirect' => [0,$url],}).
-	      '<h1>'.&mt('One moment please...').'</h1>'.
-	      '<p>'.&mt('Transferring to login page.').'</p>'.
-	      &Apache::loncommon::end_page());
+    my ($r,$domain,$data) = @_;
+    if ((ref($data) eq 'HASH') && ($data->{'lti.login'})) {
+        &Apache::ltiauth::invalid_request($r,'22');
+    } else {
+        &Apache::loncommon::content_type($r,'text/html');
+        $r->send_http_header;
+        my $url = '/adm/login';
+        if ($domain) {
+            $url .= '?domain='.$domain;
+        }
+        $r->print(&Apache::loncommon::start_page('Going to login',undef,
+					         {'redirect' => [0,$url],}).
+	          '<h1>'.&mt('One moment please...').'</h1>'.
+	          '<p>'.&mt('Transferring to login page.').'</p>'.
+	          &Apache::loncommon::end_page());
+    }
     return OK;
 }
 
-
-sub sso_lti_check {
+sub sso_check {
     my ($data) = @_;
     my %extra_env;
     if (ref($data) eq 'HASH') {
@@ -64,23 +68,40 @@
             $extra_env{'request.sso.reloginserver'} = 
                 $data->{'sso.reloginserver'};
         }
+    }
+    return \%extra_env;
+}
+
+sub lti_check {
+    my ($data) = @_;
+    my %lti_env;
+    if (ref($data) eq 'HASH') {
         if ($data->{'lti.login'}) {
-            $extra_env{'request.lti.login'} = $data->{'lti.login'};
+            $lti_env{'request.lti.login'} = $data->{'lti.login'};
+            if ($data->{'lti.reqcrs'}) {
+                $lti_env{'request.lti.reqcrs'} = $data->{'lti.reqcrs'};
+            }
+            if ($data->{'lti.reqrole'}) {
+                $lti_env{'request.lti.reqrole'} = $data->{'lti.reqrole'};
+            }
+            if ($data->{'lti.selfenrollrole'}) {
+                $lti_env{'request.lti.selfenrollrole'} = $data->{'lti.selfenrollrole'};
+            }
         }
         if ($data->{'lti.passbackid'}) {
-            $extra_env{'request.lti.passbackid'} = $data->{'lti.passbackid'};
+            $lti_env{'request.lti.passbackid'} = $data->{'lti.passbackid'};
         }
         if ($data->{'lti.passbackurl'}) {
-            $extra_env{'request.lti.passbackurl'} = $data->{'lti.passbackurl'};
+            $lti_env{'request.lti.passbackurl'} = $data->{'lti.passbackurl'};
         }
         if ($data->{'lti.rosterid'}) {
-            $extra_env{'request.lti.rosterid'} = $data->{'lti.rosterid'};
+            $lti_env{'request.lti.rosterid'} = $data->{'lti.rosterid'};
         }
         if ($data->{'lti.rosterurl'}) {
-            $extra_env{'request.lti.rosterurl'} = $data->{'lti.rosterurl'};
+            $lti_env{'request.lti.rosterurl'} = $data->{'lti.rosterurl'};
         }
     }
-    return \%extra_env;
+    return \%lti_env;
 }
 
 sub ip_changed {
@@ -238,11 +259,11 @@
     &Apache::lonlocal::get_language_handle($r);
 
     if ($delete ne 'ok') {
-	return &goto_login($r);
+	return &goto_login($r,undef,\%data);
     }
 
     if (!defined($data{'username'}) || !defined($data{'domain'})) {
-        return &goto_login($r);
+        return &goto_login($r,undef,\%data);
     }
     if ($data{'ip'} ne $ENV{'REMOTE_ADDR'}) {
         &Apache::lonnet::logthis('IP change when session migration requested -- was: '.
@@ -256,9 +277,17 @@
     if (&Apache::lonnet::domain($data{'domain'})) {
         $udom=$data{'domain'};
     }
-    if ($home =~ /(con_lost|no_such_host)/) { return &goto_login($r,$udom); }
+    if ($home =~ /(con_lost|no_such_host)/) { return &goto_login($r,$udom,\%data); }
+
+    my $sso_env = &sso_check(\%data);
+    my $lti_env = &lti_check(\%data);
 
-    my $extra_env = &sso_lti_check(\%data);
+    my $extra_env;
+    if ((ref($sso_env) eq 'HASH') && (keys(%{$sso_env}))) {
+        $extra_env = $sso_env;
+    } elsif ((ref($lti_env) eq 'HASH') && (keys(%{$lti_env}))) {
+        $extra_env = $lti_env;
+    }
 
     my %form;
     if ($data{'symb'} ne '') {
@@ -276,7 +305,37 @@
 	if ($handle) {
 	    &Apache::lonnet::transfer_profile_to_env($r->dir_config('lonIDsDir'),
 						     $handle);
-            if ($data{'origurl'} ne '') {
+#FIXME if user is not currently logged in as an LTI log-in log them out.
+            if ($data{'lti.login'}) {
+                if (($data{'lti.reqcrs'}) && ($data{'lti.reqrole'} eq 'cc')) {
+                    $form{'lti.reqcrs'} = $data{'lti.reqcrs'};
+                    $form{'lti.reqrole'} = $data{'lti.reqrole'};
+                    $form{'lti.sourcecrs'} = $data{'lti.sourcecrs'};
+                    &Apache::loncommon::content_type($r,'text/html');
+                    $r->send_http_header;
+                    &Apache::ltiauth::lti_reqcrs($r,$data{'domain'},\%form,$data{'username'},$data{'domain'});
+                } elsif ($data{'lti.selfenrollrole'}) {
+                    if (&Apache::ltiauth::lti_enroll($data{'username'},data{'domain'},
+                                                 $data{'lti.selfenrollrole'}) eq 'ok') {
+                        my $url = '/adm/roles?selectrole=1&'.
+                                  &escape($data{'lti.selfenrollrole'}).'=1';
+                        if ($data{'origurl'} =~ m{/default_\d+\.sequence$}) {
+                            $url .= '&orgurl='.$data{'origurl'}.'&navmap=1';
+                        } elsif ($data{'origurl'} ne '') {
+                            $url .= '&orgurl='.$data{'origurl'};
+                        }
+                        $r->internal_redirect($url);
+                    } else {
+                        &Apache::ltiauth::invalid_request($r,23);
+                    }
+                } elsif ($data{'origurl'} ne '') {
+                    my $url = $data{'origurl'};
+                    if ($url =~ m{/default_\d+\.sequence$}) {
+                        $url .= (($url =~/\?/)?'&':'?').'navmap=1';
+                    }
+                    $r->internal_redirect($url);
+                }
+            } elsif ($data{'origurl'} ne '') {
                 $r->internal_redirect($data{'origurl'});
             } elsif ($env{'request.course.id'}) {
                 $r->internal_redirect('/adm/navmaps');
@@ -287,13 +346,22 @@
             my $desturl = '/adm/roles';
             if ($data{'origurl'} ne '') {
                 $desturl = $data{'origurl'};
+                if ($data{'lti.login'}) {
+                    $desturl = $data{'origurl'};
+                    if ($desturl =~ m{/default_\d+\.sequence$}) {
+                        $desturl .= (($desturl =~/\?/)?'&':'?').'navmap=1';
+                    }
+                }
+            }
+            my $skipcritical;
+            if (($data{'lti.login'}) && ($data{'lti.reqcrs'}) &&
+                ($data{'lti.reqrole'} eq 'cc')) {
+                $skipcritical = 1;
             }
 	    &Apache::lonauth::success($r,$data{'username'},$data{'domain'},
-				      $home,$desturl,$extra_env,\%form);
-
+				      $home,$desturl,$extra_env,\%form,$skipcritical);
 	}
 	return OK;
-
     }
 
     my $next_url='/adm/roles?selectrole=1&'.&escape($data{'role'}).'=1';
Index: loncom/auth/switchserver.pm
diff -u loncom/auth/switchserver.pm:1.38 loncom/auth/switchserver.pm:1.39
--- loncom/auth/switchserver.pm:1.38	Thu Nov 30 15:14:51 2017
+++ loncom/auth/switchserver.pm	Fri Mar 23 01:01:29 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Switch Servers Handler
 #
-# $Id: switchserver.pm,v 1.38 2017/11/30 15:14:51 raeburn Exp $
+# $Id: switchserver.pm,v 1.39 2018/03/23 01:01:29 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -180,6 +180,10 @@
     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,6 +235,18 @@
     if ($env{'request.lti.login'}) {
         $info{'lti.login'} = $env{'request.lti.login'};
     }
+    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'};
     }
Index: loncom/lti/ltiauth.pm
diff -u loncom/lti/ltiauth.pm:1.5 loncom/lti/ltiauth.pm:1.6
--- loncom/lti/ltiauth.pm:1.5	Fri Jan 12 20:42:38 2018
+++ loncom/lti/ltiauth.pm	Fri Mar 23 01:01:47 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Basic LTI Authentication Module
 #
-# $Id: ltiauth.pm,v 1.5 2018/01/12 20:42:38 raeburn Exp $
+# $Id: ltiauth.pm,v 1.6 2018/03/23 01:01:47 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -36,6 +36,7 @@
 use Apache::lonnet;
 use Apache::loncommon;
 use Apache::lonacc;
+use Apache::lonrequestcourse;
 use LONCAPA::ltiutils;
 
 sub handler {
@@ -181,7 +182,6 @@
                 $symb = $tail;
                 $symb =~ s{^/+}{};
             }
-#FIXME Need to handle encrypted URLs
         } elsif ($tail =~ m{^/($match_domain)/($match_courseid)$}) {
             ($urlcdom,$urlcnum) = ($1,$2);
             if (($cdom ne '') && ($cdom ne $urlcdom)) {
@@ -262,7 +262,7 @@
         $protocol = 'https';
     }
 
-    my ($itemid,$consumer_key,$secret, at ltiroles);
+    my ($itemid,$consumer_key,$secret);
     $consumer_key = $params->{'oauth_consumer_key'};
     if (ref($lti_by_key{$consumer_key}) eq 'ARRAY') {
         foreach my $id (@{$lti_by_key{$consumer_key}}) {
@@ -301,7 +301,7 @@
     }
 
 #
-# Determinine if source of username matches requirement from the 
+# Determine if source of username matches requirement from the 
 # domain configuration for the specific LTI Consumer.
 # 
 
@@ -387,39 +387,40 @@
     }
 
 #
-# Get LON-CAPA role to use from role-mapping of Consumer roles
+# Get LON-CAPA role(s) to use from role-mapping of Consumer roles
 # defined in domain configuration for the appropriate LTI
 # Consumer.
 #
-# If multiple LON-CAPA roles are indicated, choose based
-# on the order: cc, in, ta, ep, st
+# If multiple LON-CAPA roles are indicated for the current user,
+# ordering (from first to last) is: cc/co, in, ta, ep, st.
 #
 
-    my $reqrole;
+    my (@ltiroles, at lcroles);
 
-    my @roleorder = ('cc','in','ta','ep','st');
+    my @lcroleorder = ('cc','in','ta','ep','st');
+    my @ltiroleorder = ('Instructor','TeachingAssistant','Mentor','Learner');
     if ($params->{'roles'} =~ /,/) {
-        @ltiroles = split(/\s*,\s*/,$params->{'role'});
+        my @possltiroles = split(/\s*,\s*/,$params->{'role'});
+        foreach my $ltirole (@ltiroleorder) {
+            if (grep(/^\Q$ltirole\E$/, at possltiroles)) {
+                push(@ltiroles,$ltirole);
+            }
+        }
     } else {
         my $singlerole = $params->{'roles'};
         $singlerole =~ s/^\s|\s+$//g;
-        @ltiroles = ($singlerole);
+        if (grep(/^\Q$singlerole\E$/, at ltiroleorder)) {
+            @ltiroles = ($singlerole);
+        }
     }
     if (@ltiroles) {
         if (ref($lti{$itemid}{maproles}) eq 'HASH') {
             my %possroles;
             map { $possroles{$lti{$itemid}{maproles}{$_}} = 1; } @ltiroles;
-            my @possibles = keys(%possroles);
-            if (@possibles == 1) {
-                if (grep(/^\Q$possibles[0]\E$/, at roleorder)) {
-                    $reqrole = $possibles[0];
-
-                }
-            } elsif (@possibles > 1) {
-                foreach my $item (@roleorder) {
+            if (keys(%possroles) > 0) {
+                foreach my $item (@lcroleorder) {
                     if ($possroles{$item}) {
-                        $reqrole = $item;
-                        last;
+                        push(@lcroles,$item);
                     }
                 }
             }
@@ -440,38 +441,148 @@
                     foreach my $ltirole (@ltiroles) {
                         if (grep(/^\Q$ltirole\E$/,@{$lti{$itemid}{'makeuser'}})) {
                             $selfcreate = 1;
+                            last;
                         }
                     }
                 }
             }
             if ($selfcreate) {
-#FIXME Do user creation here.
-                return OK
+                my (%rulematch,%inst_results,%curr_rules,%got_rules,%alerts,%info);
+                my $checkhash = { "$uname:$udom" => { 'newuser' => 1, }, };
+                my $checks = { 'username' => 1, };
+                &Apache::loncommon::user_rule_check($checkhash,$checks,\%alerts,\%rulematch,
+                                                    \%inst_results,\%curr_rules,\%got_rules);
+                my ($userchkmsg,$lcauth,$lcauthparm);
+                my $allowed = 1;
+                if (ref($alerts{'username'}) eq 'HASH') {
+                    if (ref($alerts{'username'}{$udom}) eq 'HASH') {
+                        my $domdesc =
+                            &Apache::lonnet::domain($udom,'description');
+                        if ($alerts{'username'}{$udom}{$uname}) {
+                            if (ref($curr_rules{$udom}) eq 'HASH') {
+                                $userchkmsg =
+                                    &Apache::loncommon::instrule_disallow_msg('username',$domdesc,1).
+                                    &Apache::loncommon::user_rule_formats($udom,$domdesc,
+                                                                          $curr_rules{$udom}{'username'},
+                                                                           'username');
+                            }
+                            $allowed = 0;
+                        }
+                    }
+                }
+                if ($allowed) {
+                    if (ref($rulematch{$uname.':'.$udom}) eq 'HASH') {
+                        my $matchedrule = $rulematch{$uname.':'.$udom}{'username'};
+                        my ($rules,$ruleorder) =
+                            &Apache::lonnet::inst_userrules($udom,'username');
+                        if (ref($rules) eq 'HASH') {
+                            if (ref($rules->{$matchedrule}) eq 'HASH') {
+                                $lcauth = $rules->{$matchedrule}{'authtype'};
+                                $lcauthparm = $rules->{$matchedrule}{'authparm'};
+                            }
+                        }
+                    }
+                    if ($lcauth eq '') {
+                        $lcauth = $lti{$itemid}{'lcauth'};
+                        $lcauthparm = $lti{$itemid}{'lcauthparm'};
+                    }
+                } else {
+                    &invalid_request($r,12);
+                }
+                my @userinfo = ('firstname','middlename','lastname','generation',
+                                'permanentemail','id');
+                my %useinstdata;
+                if (ref($lti{$itemid}{'instdata'}) eq 'ARRAY') {
+                    map { $useinstdata{$_} = 1; } @{$lti{$itemid}{'instdata'}};
+                }
+                foreach my $item (@userinfo) {
+                    if (($useinstdata{$item}) && (ref($inst_results{$uname.':'.$udom}) eq 'HASH') &&
+                        ($inst_results{$uname.':'.$udom}{$item} ne '')) {
+                        $info{$item} = $inst_results{$uname.':'.$udom}{$item};
+                    } else {
+                        if ($item eq 'permanentemail') {
+                            if ($env{'form.lis_person_contact_email_primary'} =~/^[^\@]+\@[^@]+$/) {
+                                $info{$item} = $env{'form.lis_person_contact_email_primary'};
+                            }
+                        } elsif ($item eq 'firstname') {
+                            $info{$item} = $env{'form.lis_person_name_given'};
+                        } elsif ($item eq 'lastname') {
+                            $info{$item} = $env{'form.lis_person_name_family'};
+                        }
+                    }
+                }
+                if (($info{'middlename'} eq '') && ($env{'form.lis_person_name_full'} ne '')) {
+                    unless ($useinstdata{'middlename'}) {
+                        my $fullname = $env{'form.lis_person_name_full'};
+                        if ($info{'firstname'}) {
+                            $fullname =~ s/^\s*\Q$info{'firstname'}\E\s*//i;
+                        }
+                        if ($info{'lastname'}) {
+                            $fullname =~ s/\s*\Q$info{'lastname'}\E\s*$//i;
+                        }
+                        if ($fullname ne '') {
+                            $fullname =~ s/^\s+|\s+$//g;
+                            if ($fullname ne '') {
+                                $info{'middlename'} = $fullname;
+                            }
+                        }
+                    }
+                }
+                if (ref($inst_results{$uname.':'.$udom}{'inststatus'}) eq 'ARRAY') {
+                    my @inststatuses = @{$inst_results{$uname.':'.$udom}{'inststatus'}};
+                    $info{'inststatus'} = join(':',map { &escape($_); } @inststatuses);
+                }
+                my $result =
+                    &Apache::lonnet::modifyuser($udom,$uname,$info{'id'},
+                                                $lcauth,$lcauthparm,$info{'firstname'},
+                                                $info{'middlename'},$info{'lastname'},
+                                                $info{'generation'},undef,undef,
+                                                $info{'permanentemail'},$info{'inststatus'});
+                if ($result eq 'ok') {
+                    if (($ltiroles[0] eq 'Instructor') && ($lcroles[0] eq 'cc') && ($lti{$itemid}{'mapcrs'}) &&
+                        ($lti{$itemid}{'makecrs'})) {
+                        unless (&Apache::lonnet::usertools_access($uname,$udom,'lti','reload','requestcourses')) {
+                            &Apache::lonnet::put('environment',{ 'requestcourses.lti' => 1, },$udom,$uname);
+                        }
+                    }
+                } else {
+                    &invalid_request($r,13);
+                    return OK;
+                }
             } else {
-                &invalid_request($r,12);
+                &invalid_request($r,14);
                 return OK;
-            } 
-        } 
+            }
+        }
     } else {
-        &invalid_request($r,13);
+        &invalid_request($r,15);
         return OK;
     }
 
 #
 # If no LON-CAPA course available, check if domain's configuration
 # for the specific LTI Consumer allows a new course to be created 
-# (requires role in Consumer to be: Instructor).
+# (requires role in Consumer to be: Instructor and Instructor to map to CC)
 #
 
+    my $reqcrs;
     if ($cnum eq '') {
-        if ((@ltiroles) && (grep(/^Instructor$/, at ltiroles)) &&
-            ($lti{$itemid}{'mapcrs'})) {
-#FIXME Create a new LON-CAPA course here.
-            return OK;
+        if ((@ltiroles) && ($lti{$itemid}{'mapcrs'}) &&
+            ($ltiroles[0] eq 'Instructor') && ($lcroles[0] eq 'cc') && ($lti{$itemid}{'makecrs'})) {
+            my (%can_request,%request_domains);
+            &Apache::lonnet::check_can_request($cdom,\%can_request,\%request_domains,$uname,$udom);
+            if ($can_request{'lti'}) {
+                $reqcrs = 1;
+                &lti_session($r,$itemid,$uname,$udom,$uhome,$lonhost,undef,$mapurl,$tail,
+                             $symb,$cdom,$cnum,$params,\@ltiroles,$lti{$itemid},\@lcroles,
+                             $reqcrs,$sourcecrs);
+            } else {
+                &invalid_request($r,16);
+            }
         } else {
-            &invalid_request($r,14);
-            return OK; 
+            &invalid_request($r,17);
         }
+        return OK;
     }
 
 #
@@ -479,48 +590,204 @@
 # indicated is cc, change role indicated to co.
 # 
 
-    if ($reqrole eq 'cc') {
+    my %crsenv;
+    if ($lcroles[0] eq 'cc') {
         if (($cdom ne '') && ($cnum ne '')) {
-            my %crsenv = &Apache::lonnet::coursedescription($cnum.'_'.$cdom,{ 'one_time' => 1,});
+            %crsenv = &Apache::lonnet::coursedescription($cdom.'_'.$cnum,{ 'one_time' => 1,});
             if ($crsenv{'type'} eq 'Community') {
-                $reqrole = 'co'; 
+                $lcroles[0] = 'co';
+            }
+        }
+    }
+
+#
+# Determine if user has a LON-CAPA role in the mapped LON-CAPA course.
+# If multiple LON-CAPA roles are available for the user's assigned LTI roles,
+# choose the first available LON-CAPA role in the order: cc/co, in, ta, ep, st
+#
+
+    my ($role,$usec,$withsec);
+    unless ((($lcroles[0] eq 'cc') || ($lcroles[0] eq 'co')) && (@lcroles == 1)) {
+        if ($lti{$itemid}{'section'} ne '') {
+            if ($lti{$itemid}{'section'} eq 'course_section_sourcedid') {
+                if ($env{'form.course_section_sourcedid'} !~ /\W/) {
+                    $usec = $env{'form.course_section_sourcedid'};
+                }
+            } elsif ($env{'form.'.$lti{$itemid}{'section'}} !~ /\W/) {
+                $usec = $env{'form.'.$lti{$itemid}{'section'}};
+            }
+        }
+        if ($usec ne '') {
+            $withsec = 1;
+        }
+    }
+
+    if (@lcroles) {
+        my %crsroles = &Apache::lonnet::get_my_roles($uname,$udom,'userroles',undef,\@lcroles,
+                                                     [$cdom],$withsec);
+        foreach my $reqrole (@lcroles) {
+            if ($withsec) {
+                my $incsec;
+                if (($reqrole eq 'cc') || ($reqrole eq 'co')) {
+                    $incsec = '';
+                } else {
+                    $incsec = $usec;
+                }
+                if (exists($crsroles{$cnum.':'.$cdom.':'.$reqrole.':'.$incsec})) {
+                    $role = $reqrole.'./'.$cdom.'/'.$cnum;
+                    if ($incsec ne '') {
+                        $role .= '/'.$usec;
+                    }
+                    last;
+                }
+            } else {
+                if (exists($crsroles{$cnum.':'.$cdom.':'.$reqrole})) {
+                    $role = $reqrole.'./'.$cdom.'/'.$cnum;
+                    last;
+                }
             }
         }
     }
 
 #
-# Determine if user has required LON-CAPA role
-# in the mapped LON-CAPA course.
+# Determine if user can selfenroll
 #
 
-    my $role;
-    my %crsroles = &Apache::lonnet::get_my_roles($uname,$udom,'userroles',undef,[$reqrole],[$cdom]);
-    if (exists($crsroles{$cnum.':'.$cdom.':'.$reqrole})) {
-        $role = $reqrole.'./'.$cdom.'/'.$cnum;
-#FIXME Need to accommodate sections
-    } elsif (ref($lti{$itemid}{'selfenroll'}) eq 'ARRAY') {
-        if (grep(/^\Q$reqrole\E$/,@{$lti{$itemid}{'selfenroll'}})) {
-#FIXME Do self-enrollment here
+    my ($reqrole,$selfenrollrole);
+    if ($role eq '') {
+        if ((@ltiroles) && (ref($lti{$itemid}{'selfenroll'}) eq 'ARRAY')) {
+            foreach my $ltirole (@ltiroles) {
+                if (grep(/^\Q$ltirole\E$/,@{$lti{$itemid}{'selfenroll'}})) {
+                    if (ref($lti{$itemid}{maproles}) eq 'HASH') {
+                        $reqrole = $lti{$itemid}{maproles}{$ltirole};
+                        last;
+                    }
+                }
+            }
+        }
+        if ($reqrole eq '') {
+            &invalid_request($r,18);
             return OK;
         } else {
-            &invalid_request($r,15);
-            return OK;
+            unless (%crsenv) {
+                %crsenv = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
+            }
+            my $default_enrollment_start_date = $crsenv{'default_enrollment_start_date'};
+            my $default_enrollment_end_date   = $crsenv{'default_enrollment_end_date'};
+            my $now = time;
+            if ($default_enrollment_end_date && $default_enrollment_end_date <= $now) {
+                &invalid_request($r,19);
+                return OK;
+            } elsif ($default_enrollment_start_date && $default_enrollment_start_date >$now) {
+                &invalid_request($r,20);
+                return OK;
+            } else {
+                $selfenrollrole = $reqrole.'./'.$cdom.'/'.$cnum;
+                if (($withsec) && ($reqrole ne 'cc') && ($reqrole ne 'co')) {
+                    if ($usec ne '') {
+                        $selfenrollrole .= '/'.$usec;
+                    }
+                }
+            }
         }
     }
 
 #
 # Store consumer-to-LON-CAPA course mapping
 #
+
     if (($sourcecrs ne '')  && ($consumers{$sourcecrs} eq '') && ($cnum ne '')) {
         &Apache::lonnet::put_dom('lticonsumers',{ $sourcecrs => $cnum },$cdom);
     }
 
 #
-# Check if user should be hosted here or switched to another server.
+# Start user session
 #
 
-    &Apache::lonnet::logthis(" LTI authorized user: $uname:$udom role: $role course: $cdom\_$cnum");
+    &lti_session($r,$itemid,$uname,$udom,$uhome,$lonhost,$role,$mapurl,$tail,$symb,
+                 $cdom,$cnum,$params,\@ltiroles,$lti{$itemid},\@lcroles,undef,$sourcecrs,
+                 $selfenrollrole);
+    return OK;
+}
+
+sub lti_enroll {
+    my ($uname,$udom,$selfenrollrole) = @_;
+    my $enrollresult;
+    my ($role,$cdom,$cnum,$sec) =
+           ($selfenrollrole =~ m{^(\w+)\./($match_domain)/($match_courseid)(?:|/(\w*))$});
+    if (($cnum ne '') && ($cdom ne '')) {
+        my $chome = &Apache::lonnet::homeserver($cnum,$cdom);
+        if ($chome ne 'no_host') {
+            my %coursehash = &Apache::lonnet::coursedescription($cdom.'_'.$cnum);
+            my $start = $coursehash{'default_enrollment_start_date'};
+            my $end = $coursehash{'default_enrollment_end_date'};
+            my $area = "/$cdom/$cnum";
+            if (($role ne 'cc') && ($role ne 'co') && ($sec ne '')) {
+                $area .= '/'.$sec;
+            }
+            my $spec = $role.'.'.$area;
+            my $instcid;
+            if ($role eq 'st') {
+                $enrollresult =
+                    &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,
+                                                               undef,undef,$sec,$end,$start,
+                                                               'ltienroll',undef,$cdom.'_'.$cnum,1,
+                                                               'ltienroll','',$instcid);
+            } elsif ($role =~ /^(cc|in|ta|ep)$/) {
+                $enrollresult =
+                    &Apache::lonnet::assignrole($udom,$uname,$area,$role,$end,$start,
+                                                undef,1,'ltienroll');
+            }
+            if ($enrollresult eq 'ok') {
+                my (%userroles,%newrole,%newgroups);
+                &Apache::lonnet::standard_roleprivs(\%newrole,$role,$cdom,$spec,$cnum,
+                                                    $area);
+                &Apache::lonnet::set_userprivs(\%userroles,\%newrole,\%newgroups);
+                $userroles{'user.role.'.$spec} = $start.'.'.$end;
+                &Apache::lonnet::appenv(\%userroles,[$role,'cm']);
+            }
+        }
+    }
+    return $enrollresult;
+}
+
+sub lti_reqcrs {
+    my ($r,$cdom,$form,$uname,$udom) = @_;
+    my (%can_request,%request_domains);
+    &Apache::lonnet::check_can_request($cdom,\%can_request,\%request_domains,$uname,$udom);
+    if ($can_request{'lti'}) {
+        my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$cdom);
+        my %domdefs = &Apache::lonnet::get_domain_defaults($cdom);
+        &Apache::lonrequestcourse::print_textbook_form($r,$cdom,[$cdom],\%domdefs,
+                                                       $domconfig{'requestcourses'},
+                                                       \%can_request,'lti',$form);
+    } else {
+        $r->print(
+              &Apache::loncommon::start_page('Invalid LTI call',undef,{'only_body' => 1}).
+              &mt('Invalid LTI call').
+              &Apache::loncommon::end_page()
+        );
+    }
+}
+
+sub lti_session {
+    my ($r,$itemid,$uname,$udom,$uhome,$lonhost,$role,$mapurl,$tail,$symb,$cdom,$cnum,
+        $params,$ltiroles,$ltihash,$lcroles,$reqcrs,$sourcecrs,$selfenrollrole) = @_;
+    return unless ((ref($params) eq 'HASH') && (ref($ltiroles) eq 'ARRAY') &&
+                   (ref($ltihash) eq 'HASH') && (ref($lcroles) eq 'ARRAY'));
+#
+# Check if user should be hosted here or switched to another server.
+#
     $r->user($uname);
+    if ($cnum) {
+        if ($role) {
+            &Apache::lonnet::logthis(" LTI authorized user ($itemid): $uname:$udom, role: $role, course: $cdom\_$cnum");
+        } elsif ($selfenrollrole =~ m{^(\w+)\./$cdom/$cnum}) {
+            &Apache::lonnet::logthis(" LTI authorized user ($itemid): $uname:$udom, desired role: $1 course: $cdom\_$cnum");
+        }
+    } else {
+        &Apache::lonnet::logthis(" LTI authorized user ($itemid): $uname:$udom, course dom: $cdom");
+    }
     my ($is_balancer,$otherserver,$hosthere);
     ($is_balancer,$otherserver) =
         &Apache::lonnet::check_loadbalancing($uname,$udom,'login');
@@ -544,11 +811,30 @@
         &Apache::lonauth::success($r,$uname,$udom,$uhome,'noredirect');
         if ($symb) {
             $env{'form.symb'} = $symb;
+        } else {
+            if ($mapurl) {
+                $env{'form.origurl'} = $mapurl;
+            } elsif ($tail =~ m{^\Q/tiny/$cdom/\E\w+$}) {
+                $env{'form.origurl'} = $tail;
+            } else {
+                unless ($tail eq '/adm/roles') {
+                    $env{'form.origurl'} = '/adm/navmaps';
+                }
+            }
         }
         if ($role) {
             $env{'form.role'} = $role;
         }
-        if ($lti{$itemid}{'passback'}) {
+        if (($lcroles->[0] eq 'cc') && ($reqcrs)) {
+            $env{'request.lti.reqcrs'} = 1;
+            $env{'request.lti.reqrole'} = 'cc';
+            $env{'request.lti.sourcecrs'} = $sourcecrs;
+        }
+        if ($selfenrollrole) {
+            $env{'request.lti.selfenroll'} = $selfenrollrole;
+            $env{'request.lti.sourcecrs'} = $sourcecrs;
+        }
+        if ($ltihash->{'passback'}) {
             if ($params->{'lis_result_sourcedid'}) {
                 $env{'request.lti.passbackid'} = $params->{'lis_result_sourcedid'};
             }
@@ -556,9 +842,9 @@
                 $env{'request.lti.passbackurl'} = $params->{'lis_outcome_service_url'};
             }
         }
-        if (($lti{$itemid}{'roster'}) && (grep(/^Instructor$/, at ltiroles))) {
+        if (($ltihash->{'roster'}) && (grep(/^Instructor$/,@{$ltiroles}))) {
             if ($params->{'ext_ims_lis_memberships_id'}) {
-                $env{'request.lti.rosterid'} = $params->{'ext_ims_lis_memberships_id'}; 
+                $env{'request.lti.rosterid'} = $params->{'ext_ims_lis_memberships_id'};
             }
             if ($params->{'ext_ims_lis_memberships_url'}) {
                 $env{'request.lti.rosterurl'} = $params->{'ext_ims_lis_memberships_url'};
@@ -591,9 +877,17 @@
             $info{'role'} = $role;
         }
         if ($symb) {
-            $info{'symb'} = $symb; 
+            $info{'symb'} = $symb;
+        }
+        if (($lcroles->[0] eq 'cc') && ($reqcrs)) {
+            $info{'lti.reqcrs'} = 1;
+            $info{'lti.reqrole'} = 'cc';
+            $info{'lti.sourcecrs'} = $sourcecrs;
+        }
+        if ($selfenrollrole) {
+            $info{'lti.selfenrollrole'} = $selfenrollrole;
         }
-        if ($lti{$itemid}{'passback'}) {
+        if ($ltihash->{'passback'}) {
             if ($params->{'lis_result_sourcedid'}) {
                 $info{'lti.passbackid'} = $params->{'lis_result_sourcedid'}
             }
@@ -601,7 +895,7 @@
                 $info{'lti.passbackurl'} = $params->{'lis_outcome_service_url'}
             }
         }
-        if (($lti{$itemid}{'roster'}) && (grep(/^Instructor$/, at ltiroles))) {
+        if (($ltihash->{'roster'}) && (grep(/^Instructor$/,@{$ltiroles}))) {
             if ($params->{'ext_ims_lis_memberships_id'}) {
                 $info{'lti.rosterid'} = $params->{'ext_ims_lis_memberships_id'};
             }
@@ -612,9 +906,8 @@
         unless ($info{'symb'}) {
             if ($mapurl) {
                 $info{'origurl'} = $mapurl;
-                if ($mapurl =~ m{/default_\d+\.sequence$}) {
-                    $info{'origurl'} .=  (($mapurl =~/\?/)?'&':'?').'navmap=1';
-                }
+            } elsif ($tail =~ m{^\Q/tiny/$cdom/\E\w+$}) {
+                $info{'origurl'} = $tail;
             } else {
                 unless ($tail eq '/adm/roles') {
                     $info{'origurl'} = '/adm/navmaps';
@@ -629,7 +922,7 @@
         $r->internal_redirect('/adm/migrateuser');
         $r->set_handlers('PerlHandler'=> undef);
     }
-    return OK;
+    return;
 }
 
 sub invalid_request {
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1367 loncom/lonnet/perl/lonnet.pm:1.1368
--- loncom/lonnet/perl/lonnet.pm:1.1367	Thu Feb  1 04:51:13 2018
+++ loncom/lonnet/perl/lonnet.pm	Fri Mar 23 01:02:04 2018
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1367 2018/02/01 04:51:13 raeburn Exp $
+# $Id: lonnet.pm,v 1.1368 2018/03/23 01:02:04 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -7146,6 +7146,7 @@
                       community  => 1,
                       textbook   => 1,
                       placement  => 1,
+                      lti        => 1,
                  );
     } elsif ($context eq 'requestauthor') {
         %tools = (
@@ -7342,25 +7343,29 @@
 }
 
 sub check_can_request {
-    my ($dom,$can_request,$request_domains) = @_;
+    my ($dom,$can_request,$request_domains,$uname,$udom) = @_;
     my $canreq = 0;
+    if (($env{'user.name'} ne '') && ($env{'user.domain'} ne '')) {
+        $uname = $env{'user.name'};
+        $udom = $env{'user.domain'};
+    }
     my ($types,$typename) = &Apache::loncommon::course_types();
     my @options = ('approval','validate','autolimit');
     my $optregex = join('|', at options);
     if ((ref($can_request) eq 'HASH') && (ref($types) eq 'ARRAY')) {
         foreach my $type (@{$types}) {
-            if (&usertools_access($env{'user.name'},
-                                  $env{'user.domain'},
-                                  $type,undef,'requestcourses')) {
+            if (&usertools_access($uname,$udom,$type,undef,
+                                  'requestcourses')) {
                 $canreq ++;
                 if (ref($request_domains) eq 'HASH') {
-                    push(@{$request_domains->{$type}},$env{'user.domain'});
+                    push(@{$request_domains->{$type}},$udom);
                 }
-                if ($dom eq $env{'user.domain'}) {
+                if ($dom eq $udom) {
                     $can_request->{$type} = 1;
                 }
             }
-            if ($env{'environment.reqcrsotherdom.'.$type} ne '') {
+            if (($env{'user.name'} ne '') && ($env{'user.domain'} ne '') &&
+                ($env{'environment.reqcrsotherdom.'.$type} ne '')) {
                 my @curr = split(',',$env{'environment.reqcrsotherdom.'.$type});
                 if (@curr > 0) {
                     foreach my $item (@curr) {
@@ -7377,7 +7382,7 @@
                             }
                         }
                     }
-                    unless($dom eq $env{'user.domain'}) {
+                    unless ($dom eq $env{'user.domain'}) {
                         $canreq ++;
                         if (grep(/^\Q$dom\E:($optregex)(=?\d*)$/, at curr)) {
                             $can_request->{$type} = 1;
@@ -9298,8 +9303,12 @@
                             }
                         }
                     }
-                } elsif (($selfenroll == 1) && ($role eq 'st') && ($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'})) {
-                    $refused = '';
+                } elsif (($selfenroll == 1) && ($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'})) {
+                    if ($role eq 'st') {
+                        $refused = '';
+                    } elsif (($context eq 'ltienroll') && ($env{'request.lti'})) {
+                        $refused = '';
+                    }
                 } elsif ($context eq 'requestcourses') {
                     my @possroles = ('st','ta','ep','in','cc','co');
                     if ((grep(/^\Q$role\E$/, at possroles)) && ($env{'user.name'} ne '' && $env{'user.domain'} ne '')) {
@@ -9565,10 +9574,14 @@
     my $newuser;
     if ($uhome eq 'no_host') {
         $newuser = 1;
+        unless (($umode && ($upass ne '')) || ($umode eq 'localauth') ||
+                ($umode eq 'lti')) {
+            return 'error: more information needed to create new user';
+        }
     }
 # ----------------------------------------------------------------- Create User
     if (($uhome eq 'no_host') && 
-	(($umode && $upass) || ($umode eq 'localauth'))) {
+	(($umode && $upass) || ($umode eq 'localauth') || ($umode eq 'lti'))) {
         my $unhome='';
         if (defined($desiredhome) && &host_domain($desiredhome) eq $udom) { 
             $unhome = $desiredhome;
Index: loncom/lond
diff -u loncom/lond:1.542 loncom/lond:1.543
--- loncom/lond:1.542	Thu Feb  1 04:50:41 2018
+++ loncom/lond	Fri Mar 23 01:02:22 2018
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
 #
-# $Id: lond,v 1.542 2018/02/01 04:50:41 raeburn Exp $
+# $Id: lond,v 1.543 2018/03/23 01:02:22 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -65,7 +65,7 @@
 my $status='';
 my $lastlog='';
 
-my $VERSION='$Revision: 1.542 $'; #' stupid emacs
+my $VERSION='$Revision: 1.543 $'; #' stupid emacs
 my $remoteVERSION;
 my $currenthostid="default";
 my $currentdomainid;
@@ -8369,6 +8369,14 @@
 		$result = "pass_file_failed_error";
 	    }
 	}
+    } elsif ($umode eq 'lti') {
+        my $pf = IO::File->new(">$passfilename");
+        if($pf) {
+            print $pf "lti:\n";
+            &update_passwd_history($uname,$udom,$umode,$action);
+        } else {
+            $result = "pass_file_failed_error";
+        }
     } else {
 	$result="auth_mode_error";
     }


More information about the LON-CAPA-cvs mailing list