--- loncom/interface/lonuserutils.pm	2024/08/24 23:49:48	1.184.4.10.2.8
+++ loncom/interface/lonuserutils.pm	2020/02/10 17:12:54	1.205
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Utility functions for managing LON-CAPA user accounts
 #
-# $Id: lonuserutils.pm,v 1.184.4.10.2.8 2024/08/24 23:49:48 raeburn Exp $
+# $Id: lonuserutils.pm,v 1.205 2020/02/10 17:12:54 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -103,7 +103,7 @@ sub modifystudent {
 sub modifyuserrole {
     my ($context,$setting,$changeauth,$cid,$udom,$uname,$uid,$umode,$upass,
         $first,$middle,$last,$gene,$sec,$forceid,$desiredhome,$email,$role,
-        $end,$start,$checkid,$inststatus,$emptyok) = @_;
+        $end,$start,$checkid,$inststatus) = @_;
     my ($scope,$userresult,$authresult,$roleresult,$idresult);
     if ($setting eq 'course' || $context eq 'course') {
         $scope = '/'.$cid;
@@ -114,11 +114,7 @@ sub modifyuserrole {
     } elsif ($context eq 'domain') {
         $scope = '/'.$env{'request.role.domain'}.'/';
     } elsif ($context eq 'author') {
-        if ($env{'request.role'} =~ m{^ca\.(/$match_domain/$match_username)$}) {
-            $scope = $1;
-        } else {
-            $scope =  '/'.$env{'user.domain'}.'/'.$env{'user.name'};
-        }
+        $scope =  '/'.$env{'user.domain'}.'/'.$env{'user.name'};
     }
     if ($context eq 'domain') {
         my $uhome = &Apache::lonnet::homeserver($uname,$udom);
@@ -138,25 +134,6 @@ sub modifyuserrole {
                                   generation => $gene,
                                   id         => $uid,
                                  );
-
-                # When "Update ID in user's course(s)" and "Force change of existing ID"
-                # checkboxes both checked, prevent replacement of name information
-                # in classlist.db file(s) for the user's course(s) with blank(s),
-                # in the case where the uploaded csv file was without column(s) for
-                # the particular field. Fields are: First Name, Middle Names/Initials,
-                # Last Name (or the composite: Last Name, First Names), and Generation.
-
-                my %emptyallowed;
-                if ((ref($emptyok) eq 'HASH') && (keys(%{$emptyok}) > 0)) {
-                    %emptyallowed = %{$emptyok};
-                }
-                foreach my $field (keys(%userupdate)) {
-                    if ($userupdate{$field} eq '') {
-                        unless ($emptyallowed{$field}) {
-                            delete($userupdate{$field});
-                        }
-                    }
-                }
                 $idresult = &propagate_id_change($uname,$udom,\%userupdate);
             }
         }
@@ -533,7 +510,7 @@ END
 ";
     } elsif ($mode eq 'modifycourse') {
         $auth_checks .= "
-    if ((current.argfield !== null) && (current.argfield !== undefined) && (current.argfield !== '') && (vf.elements[current.argfield].value == null || vf.elements[current.argfield].value == '')) {
+    if (vf.elements[current.argfield].value == null || vf.elements[current.argfield].value == '') {
 ";
     }
     if ( ($mode eq 'createcourse') || ($mode eq 'modifycourse') ) {
@@ -555,7 +532,7 @@ END
 END
     } else {
         my ($numrules,$intargjs) =
-            &Apache::loncommon::passwd_validation_js('vf.elements[current.argfield].value',$domain);
+            &passwd_validation_js('vf.elements[current.argfield].value',$domain);
         $auth_checks .= (<<END);
     foundatype=1;
     if (current.argfield == null || current.argfield == '') {
@@ -566,15 +543,14 @@ END
             case 'krb':
                 alertmsg = '$alert{'krb'}';
                 break;
+            case 'loc':
             case 'int':
                 alertmsg = '$alert{'ipass'}';
                 break;
             case 'fsys':
                 alertmsg = '$alert{'ipass'}';
                 break;
-            case 'loc':
-                alertmsg = '';
-                break;
+            case 'lti':
             default:
                 alertmsg = '';
         }
@@ -675,6 +651,137 @@ END
     return $result;
 }
 
+sub passwd_validation_js {
+    my ($currpasswdval,$domain) = @_;
+    my %passwdconf = &Apache::lonnet::get_passwdconf($domain);
+    my ($min,$max,@chars,$numrules,$intargjs,%alert);
+    $numrules = 0;
+    $min = $Apache::lonnet::passwdmin;
+    if (ref($passwdconf{'chars'}) eq 'ARRAY') {
+        if ($passwdconf{'min'} =~ /^\d+$/) {
+            if ($passwdconf{'min'} > $min) {
+                $min = $passwdconf{'min'};
+            }
+        }
+        if ($passwdconf{'max'} =~ /^\d+$/) {
+            $max = $passwdconf{'max'};
+            $numrules ++;
+        }
+        @chars = @{$passwdconf{'chars'}};
+        if (@chars) {
+            $numrules ++;
+        }
+    }
+    if ($min > 0) {
+        $numrules ++;
+    }
+    if (($min > 0) || ($max ne '') || (@chars > 0)) {
+        my $alertmsg = &mt('Initial password did not satisfy requirement(s):').'\n\n';
+        if ($min) {
+            $alert{'min'} = &mt('minimum [quant,_1,character]',$min).'\n';
+        }
+        if ($max) {
+            $alert{'max'} = &mt('maximum [quant,_1,character]',$max).'\n';
+        }
+        my (@charalerts,@charrules);
+        if (@chars) {
+            if (grep(/^uc$/,@chars)) {
+                push(@charalerts,&mt('contain at least one upper case letter'));
+                push(@charrules,'uc');
+            }
+            if (grep(/^lc$/,@chars)) {
+                push(@charalerts,&mt('contain at least one lower case letter'));
+                push(@charrules,'lc');
+            }
+            if (grep(/^num$/,@chars)) {
+                push(@charalerts,&mt('contain at least one number'));
+                push(@charrules,'num');
+            }
+            if (grep(/^spec$/,@chars)) {
+                push(@charalerts,&mt('contain at least one non-alphanumeric'));
+                push(@charrules,'spec');
+            }
+        }
+        $intargjs = qq|            var rulesmsg = '';\n|.
+                    qq|            var currpwval = $currpasswdval;\n|;
+            if ($min) {
+                $intargjs .= qq|
+            if (currpwval.length < $min) {
+                rulesmsg += ' - $alert{min}';
+            }
+|;
+            }
+            if ($max) {
+                $intargjs .= qq|
+            if (currpwval.length > $max) {
+                rulesmsg += ' - $alert{max}';
+            }
+|;
+            }
+            if (@chars > 0) {
+                my $charrulestr = '"'.join('","',@charrules).'"';
+                my $charalertstr = '"'.join('","',@charalerts).'"';
+                $intargjs .= qq|            var brokerules = new Array();\n|.
+                             qq|            var charrules = new Array($charrulestr);\n|.
+                             qq|            var charalerts = new Array($charalertstr);\n|;
+                my %rules;
+                map { $rules{$_} = 1; } @chars;
+                if ($rules{'uc'}) {
+                    $intargjs .= qq|
+            var ucRegExp = /[A-Z]/;
+            if (!ucRegExp.test(currpwval)) {
+                brokerules.push('uc');
+            }
+|;
+                }
+                if ($rules{'lc'}) {
+                    $intargjs .= qq|
+            var lcRegExp = /[a-z]/;
+            if (!lcRegExp.test(currpwval)) {
+                brokerules.push('lc');
+            }
+|;
+                }
+                if ($rules{'num'}) {
+                     $intargjs .= qq|
+            var numRegExp = /[0-9]/;
+            if (!numRegExp.test(currpwval)) {
+                brokerules.push('num');
+            }
+|;
+                }
+                if ($rules{'spec'}) {
+                     $intargjs .= q|
+            var specRegExp = /[!"#$%&'()*+,\-.\/:;<=>?@[\\^\]_`{\|}~]/;
+            if (!specRegExp.test(currpwval)) {
+                brokerules.push('spec');
+            }
+|;
+                }
+                $intargjs .= qq|
+            if (brokerules.length > 0) {
+                for (var i=0; i<brokerules.length; i++) {
+                    for (var j=0; j<charrules.length; j++) {
+                        if (brokerules[i] == charrules[j]) {
+                            rulesmsg += ' - '+charalerts[j]+'\\n';
+                            break;
+                        }
+                    }
+                }
+            }
+|;
+            }
+            $intargjs .= qq|
+            if (rulesmsg != '') {
+                rulesmsg = '$alertmsg'+rulesmsg;
+                alert(rulesmsg);
+                return false;
+            }
+|;
+    }
+    return ($numrules,$intargjs);
+}
+
 ###############################################################
 ###############################################################
 sub upload_manager_javascript_forward_associate {
@@ -932,6 +1039,7 @@ sub print_upload_manager_footer {
     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);
 
@@ -960,7 +1068,7 @@ sub print_upload_manager_footer {
             &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',
@@ -977,8 +1085,14 @@ sub print_upload_manager_footer {
                 &Apache::lonhtmlcommon::row_closure();
     }
 
+    my ($trusted,$untrusted);
+    if ($context eq 'course') {
+        ($trusted,$untrusted) = &Apache::lonnet::trusted_domains('enroll',$defdom);
+    } elsif ($context eq 'author') {
+        ($trusted,$untrusted) = &Apache::lonnet::trusted_domains('othcoau',$defdom);
+    }
     $Str .= &Apache::lonhtmlcommon::row_title(&mt('Default domain'))
-           .&Apache::loncommon::select_dom_form($defdom,'defaultdomain',undef,1)
+           .&Apache::loncommon::select_dom_form($defdom,'defaultdomain',undef,1,undef,$trusted,$untrusted)
            .&Apache::lonhtmlcommon::row_closure();
 
     $Str .= &Apache::lonhtmlcommon::row_title(&mt('Starting and Ending Dates'))
@@ -1508,14 +1622,6 @@ sub construction_space_roles {
         foreach my $role (@allroles) {
             if (&Apache::lonnet::allowed('c'.$role,$env{'user.domain'}.'/'.$env{'user.name'})) { 
                 push(@roles,$role); 
-            } elsif ($env{'request.role'} =~ m{^ca\./($match_domain)/($match_username)$}) {
-                my ($audom,$auname) = ($1,$2);
-                if (($role eq 'ca') || ($role eq 'aa')) {
-                    if ((&Apache::lonnet::allowed('v'.$role,,$audom.'/'.$auname)) &&
-                        ($env{"environment.internal.manager./$audom/$auname"})) {
-                        push(@roles,$role);
-                    }
-                }
             }
         }
         return @roles;
@@ -1619,24 +1725,6 @@ sub print_userlist {
     if (! exists($env{'form.sortby'})) {
         $env{'form.sortby'} = 'username';
     }
-    my ($showstart,$showend);
-    if (($env{'form.Status'} eq '') && ($env{'form.phase'} eq '') &&
-        ($env{'form.showrole'} eq '') && ($context eq 'course') &&
-        ($env{'request.course.id'} ne '') &&
-        ($env{'course.'.$env{'request.course.id'}.'.internal.coursecode'} ne '')) {
-        my $now = time;
-        my $startaccess = $env{'course.'.$env{'request.course.id'}.'.default_enrollment_start_date'};
-        my $endaccess = $env{'course.'.$env{'request.course.id'}.'.default_enrollment_end_date'};
-        if (($startaccess) && ($startaccess > $now)) {
-            $env{'form.Status'} = 'Future';
-            $showstart = 1;
-        }
-        if (($endaccess ne '') && ($endaccess != 0) && ($endaccess < $now)) {
-            $env{'form.Status'} = 'Expired';
-            undef($showstart);
-            $showend = 1;
-        }
-    }
     if ($env{'form.Status'} !~ /^(Any|Expired|Active|Future)$/) {
         $env{'form.Status'} = 'Active';
     }
@@ -1704,7 +1792,7 @@ sub print_userlist {
         $r->print(&section_group_filter($cnum,$cdom));
     }
     $r->print('</div><div class="LC_left_float">'.
-              &column_checkboxes($context,$mode,$formname,$showcredits,$showstart,$showend).
+              &column_checkboxes($context,$mode,$formname,$showcredits).
               '</div>');
     if ($env{'form.phase'} eq '') {
         $r->print('<br clear="all" />'.
@@ -1790,31 +1878,12 @@ sub print_userlist {
     } else {
         my (%cstr_roles,%dom_roles);
         if ($context eq 'author') {
-            my @possroles = &roles_by_context($context);
-            my @allowedroles;
             # List co-authors and assistant co-authors
-            my ($auname,$audom);
-            if ($env{'request.role'} =~ m{^ca\./($match_domain)/($match_username)$}) {
-                ($audom,$auname) = ($1,$2);
-                foreach my $role (@possroles) {
-                    if ((&Apache::lonnet::allowed('v'.$role,"$audom/$auname")) ||
-                        (&Apache::lonnet::allowed('c'.$role,"$audom/$auname"))) {
-                        push(@allowedroles,$role);
-                    }
-                }
-            } elsif ($env{'request.role'} =~ m{^au\./($match_domain)/}) {
-                if ($1 eq $env{'user.domain'}) {
-                    $auname = $env{'user.name'};
-                    $audom = $env{'user.domain'};
-                }
-                @allowedroles = @possroles;
-            }
-            if (($auname ne '') && ($audom ne '')) {
-                %cstr_roles = &Apache::lonnet::get_my_roles($auname,$audom,undef,
-                                                            \@statuses,\@allowedroles);
-                &gather_userinfo($context,$format,\%userlist,$indexhash,\%userinfo,
-                                 \%cstr_roles,$permission);
-            }
+            my @possroles = &roles_by_context($context);
+            %cstr_roles = &Apache::lonnet::get_my_roles(undef,undef,undef,
+                                              \@statuses,\@possroles);
+            &gather_userinfo($context,$format,\%userlist,$indexhash,\%userinfo,
+                             \%cstr_roles,$permission);
         } elsif ($context eq 'domain') {
             if ($env{'form.roletype'} eq 'domain') {
                 if (grep(/^authorusage$/,@cols)) {
@@ -2105,17 +2174,14 @@ sub get_cols_array {
             push(@cols,'photo');
         }
         if ($context eq 'domain') {
-            push(@cols,('authorusage','authorquota','extent'));
-        }
-        if ($context eq 'author') {
-            push(@cols,'manager');
+            push (@cols,('authorusage','authorquota','extent'));
         }
     }
     return @cols;
 }
 
 sub column_checkboxes {
-    my ($context,$mode,$formname,$showcredits,$showstart,$showend) = @_;
+    my ($context,$mode,$formname,$showcredits) = @_;
     my @cols = &get_cols_array($context,$mode,$showcredits);
     my @showncols = &Apache::loncommon::get_env_multiple('form.showcol');
     my (%disabledchk,%unchecked);
@@ -2128,21 +2194,11 @@ sub column_checkboxes {
             if ($showcredits) {
                 $unchecked{'credits'} = 1;
             }
-            my %curr_groups = &Apache::longroup::coursegroups();
-            unless (keys(%curr_groups)) {
-                $unchecked{'groups'} = 1;
-            }
-        } elsif ($context eq 'domain') {
+        } elsif ($context eq 'domain') { 
             $unchecked{'extent'} = 1; 
         }
-        if ($showstart) {
-            $unchecked{'lastlogin'} = 1;
-        } else {
-            $unchecked{'start'} = 1;
-        }
-        unless ($showend) {
-            $unchecked{'end'} = 1;
-        }
+        $unchecked{'start'} = 1;
+        $unchecked{'end'} = 1;
     } else {
         if ($env{'form.Status'} ne 'Any') {
             $disabledchk{'status'} = 1;
@@ -2159,11 +2215,6 @@ sub column_checkboxes {
             } elsif ($env{'form.roletype'} eq 'domain') {
                 $disabledchk{'extent'} = 1; 
             }
-        } elsif ($context eq 'author') {
-            if (($env{'form.Status'} eq 'Expired') ||
-                ($env{'form.showrole'} eq 'aa')) {
-                $disabledchk{'manager'} = 1;
-            }
         }
     }
     my $numposs = scalar(@cols);
@@ -2255,7 +2306,6 @@ sub get_column_names {
         'ca'         => "check all",
         'ua'         => "uncheck all",
         'clicker'    => "clicker-ID",
-        'manager'    => "co-author manager",
     );
     if ($context eq 'domain' && $env{'form.roletype'} eq 'course') {
         $lt{'extent'} = &mt('course(s): description, section(s), status');
@@ -2540,7 +2590,6 @@ sub make_keylist_array {
     $index->{'instsec'} = &Apache::loncoursedata::CL_INSTSEC();
     $index->{'authorquota'} = &Apache::loncoursedata::CL_AUTHORQUOTA();
     $index->{'authorusage'} = &Apache::loncoursedata::CL_AUTHORUSAGE();
-    $index->{'manager'} = &Apache::loncoursedata::CL_CAMANAGER();
     foreach my $key (keys(%{$index})) {
         $keylist->[$index->{$key}] = $key;
     }
@@ -2615,9 +2664,6 @@ sub show_users_list {
             (($env{'form.showrole'} eq 'Any') || ($env{'form.showrole'} eq 'au'))) {
             push(@sortable,('authorusage','authorquota'));
         }
-        if ($context eq 'author') {
-            push(@sortable,'manager');
-        }
     }
     if ($mode eq 'pickauthor') {
         @sortable = ('username','fullname','email','status');
@@ -2935,7 +2981,6 @@ END
     foreach my $idx (@$keylist) {
         $index{$idx} = $i++;
     }
-    my $now = time;
     my $usercount = 0;
     my ($secfilter,$grpfilter);
     if ($context eq 'course') {
@@ -2953,12 +2998,10 @@ END
                                                 Future  => 'Future',
                                                 Expired => 'Expired',
                                                );
-    my (%crslogins,%camanagers);
+    # If this is for a single course get last course "log-in".
+    my %crslogins;
     if ($context eq 'course') {
-        # If this is for a single course get last course "log-in".
         %crslogins=&Apache::lonnet::dump('nohist_crslastlogin',$cdom,$cnum);
-    } elsif ($context eq 'author') {
-        map { $camanagers{$_.':ca'} = 1; } split(/,/,$env{'environment.authormanagers'});
     }
     # Get groups, role, permanent e-mail so we can sort on them if
     # necessary.
@@ -3058,16 +3101,6 @@ END
                 }
             }
         }
-        if ($context eq 'author') {
-            if (($camanagers{$user}) &&
-                ((!defined($userlist->{$user}->[$index{'end'}])) ||
-                 ($userlist->{$user}->[$index{'end'}] == 0) ||
-                 ($userlist->{$user}->[$index{'end'}] > $now))) {
-                $userlist->{$user}->[$index{'manager'}] = &mt('Yes');
-            } else {
-                $userlist->{$user}->[$index{'manager'}] = &mt('No');
-            }
-        }
         my %emails   = &Apache::loncommon::getemails($uname,$udom);
         if ($emails{'permanentemail'} =~ /\S/) {
             $userlist->{$user}->[$index{'email'}] = $emails{'permanentemail'};
@@ -4263,42 +4296,19 @@ sub upfile_drop_add {
         $fieldstype{$field.'_choice'} = 'scalar';
     }
     &Apache::loncommon::store_course_settings('enrollment_upload',\%fieldstype);
-    my ($cid,$crstype,$setting,$crsdom,$crsnum,$oldcrsuserdoms,%emptyok);
+    my ($cid,$crstype,$setting,$crsdom);
     if ($context eq 'domain') {
         $setting = $env{'form.roleaction'};
-        if (exists($fields{'names'})) {
-            map { $emptyok{$_} = 1; } ('lastname','firstname','middlename');
-        } else {
-            if (exists($fields{'lname'})) {
-                $emptyok{'lastname'} = 1;
-            }
-            if (exists($fields{'fname'})) {
-                $emptyok{'firstname'} = 1;
-            }
-            if (exists($fields{'mname'})) {
-                $emptyok{'middlename'} = 1;
-            }
-        }
-        if (exists($fields{'gen'})) {
-            $emptyok{'generation'} = 1;
-        }
     }
     if ($env{'request.course.id'} ne '') {
         $cid = $env{'request.course.id'};
         $crstype = &Apache::loncommon::course_type();
         $crsdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
-        $crsnum = $env{'course.'.$env{'request.course.id'}.'.num'};
     } elsif ($setting eq 'course') {
         if (&Apache::lonnet::is_course($env{'form.dcdomain'},$env{'form.dccourse'})) {
             $cid = $env{'form.dcdomain'}.'_'.$env{'form.dccourse'};
             $crstype = &Apache::loncommon::course_type($cid);
             $crsdom = $env{'form.dcdomain'};
-            $crsnum = $env{'form.dccourse'};
-            if (exists($env{'course.'.$cid.'.internal.userdomains'})) {
-                $oldcrsuserdoms = 1;
-            }
-            my %coursedesc = &Apache::lonnet::coursedescription($cid,{ one_time => 1 });
-            $env{'course.'.$cid.'.internal.userdomains'} = $coursedesc{'internal.userdomains'};
         }
     }
     my ($startdate,$enddate) = &get_dates_from_form();
@@ -4309,7 +4319,47 @@ sub upfile_drop_add {
     my $defdom=$env{'request.role.domain'};
     my $domain;
     if ($env{'form.defaultdomain'} ne '') {
-        $domain = $env{'form.defaultdomain'};
+        if (($context eq 'course') || ($setting eq 'course')) {
+            if ($env{'form.defaultdomain'} eq $crsdom) {
+                $domain = $env{'form.defaultdomain'};
+            } else {
+                if (&Apache::lonnet::will_trust('enroll',$crsdom,$env{'form.defaultdomain'})) {
+                    $domain = $env{'form.defaultdomain'};
+                } else {
+                    $r->print('<span class="LC_error">'.&mt('Error').': '.
+                              &mt('Enrollment of users not permitted for specified default domain: [_1].',
+                                  &Apache::lonnet::domain($env{'form.defaultdomain'},'description')).'</span>');
+                    return 'untrusted';
+                }
+            }
+        } elsif ($context eq 'author') {
+            if ($env{'form.defaultdomain'} eq $defdom) {
+                $domain = $env{'form.defaultdomain'}; 
+            } else {
+                if ((&Apache::lonnet::will_trust('othcoau',$defdom,$env{'form.defaultdomain'})) &&
+                    (&Apache::lonnet::will_trust('coaurem',$env{'form.defaultdomain'},$defdom))) {
+                    $domain = $env{'form.defaultdomain'};
+                } else {
+                    $r->print('<span class="LC_error">'.&mt('Error').': '.
+                              &mt('Addition of users not permitted for specified default domain: [_1].',
+                                  &Apache::lonnet::domain($env{'form.defaultdomain'},'description')).'</span>');
+                    return 'untrusted';
+                }
+            }
+        } elsif (($context eq 'domain') && ($setting eq 'domain')) {
+            if ($env{'form.defaultdomain'} eq $defdom) {
+                $domain = $env{'form.defaultdomain'};
+            } else {
+                if (&Apache::lonnet::will_trust('domroles',$defdom,$env{'form.defaultdomain'})) {
+                    $domain = $env{'form.defaultdomain'};
+                } else {
+                    $r->print('<span class="LC_error">'.&mt('Error').': '.
+                              &mt('Addition of users not permitted for specified default domain: [_1].',
+                                  &Apache::lonnet::domain($env{'form.defaultdomain'},'description')).'</span>');
+                    return 'untrusted';
+                }
+            }
+        }
     } else {
         $domain = $defdom;
     }
@@ -4321,7 +4371,6 @@ sub upfile_drop_add {
         if (! exists($home_servers{$desiredhost})) {
             $r->print('<p class="LC_error">'.&mt('Error').': '.
                       &mt('Invalid home server specified').'</p>');
-            $r->print(&Apache::loncommon::end_page());
             return 'invalidhome';
         }
     }
@@ -4349,6 +4398,8 @@ sub upfile_drop_add {
         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 '') {
@@ -4501,6 +4552,7 @@ sub upfile_drop_add {
         my (%existinguser,%userinfo,%disallow,%rulematch,%inst_results,%alerts,%checkuname,
             %showpasswdrules,$haspasswdmap);
         my $counter = -1;
+        my (%willtrust,%trustchecked);
         foreach my $line (@userdata) {
             $counter ++;
             my @secs;
@@ -4548,6 +4600,28 @@ sub upfile_drop_add {
                                 '"<b>'.$entries{$fields{'domain'}}.'</b>"',
                                 $fname,$mname,$lname,$gen);
                         next;
+                    } elsif ($entries{$fields{'domain'}} ne $domain) {
+                        my $possdom = $entries{$fields{'domain'}};
+                        if ($context eq 'course' || $setting eq 'course') {
+                            unless ($trustchecked{$possdom}) {
+                                $willtrust{$possdom} = &Apache::lonnet::will_trust('enroll',$domain,$possdom);
+                                $trustchecked{$possdom} = 1;
+                            }
+                        } elsif ($context eq 'author') {
+                            unless ($trustchecked{$possdom}) {
+                                $willtrust{$possdom} = &Apache::lonnet::will_trust('othcoau',$domain,$possdom);
+                            }
+                            if ($willtrust{$possdom}) {
+                                $willtrust{$possdom} = &Apache::lonnet::will_trust('coaurem',$possdom,$domain); 
+                            }
+                        }
+                        unless ($willtrust{$possdom}) {
+                            $disallow{$counter} =
+                                &mt('Unacceptable domain [_1] for user [_2] [_3] [_4] [_5]',
+                                    '"<b>'.$possdom.'</b>"',
+                                    $fname,$mname,$lname,$gen);
+                            next;
+                        }
                     }
                     my $username = $entries{$fields{'username'}};
                     my $userdomain = $entries{$fields{'domain'}};
@@ -4732,7 +4806,7 @@ sub upfile_drop_add {
                                 &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>');
@@ -4935,16 +5009,6 @@ sub upfile_drop_add {
                     my (%userres,%authres,%roleres,%idres);
                     my $singlesec = '';
                     if ($role eq 'st') {
-                        if (($context eq 'domain') && ($changeauth eq 'Yes') && (!$newuser)) {
-                            if ((&Apache::lonnet::allowed('mau',$userdomain)) &&
-                                (&Apache::lonnet::homeserver($username,$userdomain) ne 'no_host')) {
-                                if ((($amode =~ /^krb4|krb5|internal$/) && $password ne '') ||
-                                     ($amode eq 'localauth')) {
-                                    $authresult =
-                                        &Apache::lonnet::modifyuserauth($userdomain,$username,$amode,$password);
-                                }
-                            }
-                        }
                         my $sec;
                         if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') {
                             if (@secs > 0) {
@@ -4995,7 +5059,7 @@ sub upfile_drop_add {
                                                 $mname,$lname,$gen,$singlesec,
                                                 $env{'form.forceid'},$desiredhost,
                                                 $email,$role,$enddate,$startdate,
-                                                $checkid,$inststatus,\%emptyok);
+                                                $checkid,$inststatus);
                         }
                     }
                     if ($multiple) {
@@ -5017,13 +5081,6 @@ sub upfile_drop_add {
             } # end of loop
             $r->print('</ul>');
             &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
-            if (($context eq 'domain') && ($setting eq 'course')) {
-                unless ($oldcrsuserdoms) {
-                    if (exists($env{'course.'.$cid.'.internal.userdomains'})) {
-                        delete($env{'course.'.$cid.'.internal.userdomains'});
-                    }
-                }
-            }
         }
         # Flush the course logs so reverse user roles immediately updated
         $r->register_cleanup(\&Apache::lonnet::flushcourselogs);
@@ -5122,11 +5179,7 @@ sub passwdrule_alerts {
             my %passwdconf = &Apache::lonnet::get_passwdconf($domain);
             $warning = '<b>'.&mt('Password requirement(s) unmet for one or more users:').'</b><ul>';
             if ($showrules{'min'}) {
-                my $min = $passwdconf{'min'};
-                if ($min eq '') {
-                    $min = $Apache::lonnet::passwdmin;
-                }
-                $warning .= '<li>'.&mt('minimum [quant,_1,character]',$min).'</li>';
+                $warning .= '<li>'.&mt('minimum [quant,_1,character]',$passwdconf{'min'}).'</li>';
             }
             if ($showrules{'max'}) {
                 $warning .= '<li>'.&mt('maximum [quant,_1,character]',$passwdconf{'max'}).'</li>';
@@ -5652,7 +5705,7 @@ END
 }
 
 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) =
@@ -5674,6 +5727,11 @@ sub set_login {
                          '<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;
@@ -6202,9 +6260,6 @@ sub get_permission {
                     $permission{'selfenrolladmin'} = 1;
                 }
             }
-            unless ($permission{'selfenrolladmin'}) {
-                $permission{'selfenrollview'} = 1;
-            }
         }
         if ($env{'request.course.id'}) {
             my $user;
@@ -6224,23 +6279,8 @@ sub get_permission {
             }
         }
     } elsif ($context eq 'author') {
-        my $audom = $env{'request.role.domain'};
-        my $auname = $env{'user.name'};
-        if ((&Apache::lonnet::allowed('cca',"$audom/$auname")) ||
-            (&Apache::lonnet::allowed('caa',"$audom/$auname"))) {
-            $permission{'author'} = 1;
-            $permission{'cusr'} = 1;
-            $permission{'view'} = 1;
-        }
-    } elsif ($context eq 'coauthor') {
-        my ($audom,$auname) = ($env{'request.role'} =~ m{^ca\./($match_domain)/($match_username)$});
-        if ((&Apache::lonnet::allowed('vca',"$audom/$auname")) ||
-            (&Apache::lonnet::allowed('vaa',"$audom/$auname"))) {
-            if ($env{"environment.internal.manager./$audom/$auname"}) {
-                $permission{'cusr'} = 1;
-                $permission{'view'} = 1;
-            }
-        }
+        $permission{'cusr'} = &authorpriv($env{'user.name'},$env{'request.role.domain'});
+        $permission{'view'} = $permission{'cusr'};
     } else {
         my @allroles = &roles_by_context($context);
         foreach my $role (@allroles) {
@@ -6268,9 +6308,8 @@ sub get_permission {
         }
     }
     my $allowed = 0;
-    foreach my $key (keys(%permission)) {
-        next if (($key eq 'owner') || ($key eq 'co-owner') || ($key eq 'author'));
-        if ($permission{$key}) { $allowed=1; last; }
+    foreach my $perm (values(%permission)) {
+        if ($perm) { $allowed=1; last; }
     }
     return (\%permission,$allowed);
 }
@@ -6283,18 +6322,6 @@ sub authorpriv {
          || (&Apache::lonnet::allowed('caa',$audom.'/'.$auname))) { return ''; }    return 1;
 }
 
-sub coauthorpriv {
-    my ($auname,$audom)=@_;
-    my $uname = $env{'user.name'};
-    my $udom = $env{'user.domain'};
-    if (((&Apache::lonnet::allowed('vca',"$udom/$uname")) ||
-         (&Apache::lonnet::allowed('vaa',"$udom/$uname"))) &&
-         ($env{"environment.internal.manager./$audom/$auname"})) {
-        return 1;
-    }
-    return '';
-}
-
 sub roles_on_upload {
     my ($context,$setting,$crstype,%customroles) = @_;
     my (@possible_roles,@permitted_roles);
@@ -6491,7 +6518,7 @@ sub verify_authen {
         $finish = "document.$formname.submit();";
     }
     my ($numrules,$intargjs) =
-        &Apache::loncommon::passwd_validation_js('argpicked',$domain);
+        &passwd_validation_js('argpicked',$domain);
     my $outcome = <<"ENDSCRIPT";
 
 function auth_check() {
@@ -6695,7 +6722,7 @@ sub selfenrollment_administration {
         }
     }
     if ($settings{'internal.selfenrollmgrdc'} ne '') {
-        @in_domain = split(/,/,$settings{'internal.selfenrollmgrdc'});
+        my @in_domain = split(/,/,$settings{'internal.selfenrollmgrdc'});
         my @diffs = &Apache::loncommon::compare_arrays(\@in_domain,$possconfigs);
         unless (@diffs) {
             return (\@in_course,\@in_domain);